121 lines
3.0 KiB
Rust
121 lines
3.0 KiB
Rust
use std::fmt::Debug;
|
|
use std::sync::Arc;
|
|
|
|
use async_trait::async_trait;
|
|
use twilight_model::channel::message::Component as TwilightComponent;
|
|
use twilight_model::channel::message::component::{
|
|
ActionRow as TwilightActionRow, Button as TwilightButton, ButtonStyle,
|
|
};
|
|
|
|
use crate::framework::interactions::InteractionError;
|
|
use crate::framework::interactions::context::InteractionContext;
|
|
|
|
type ComponentWithID<T, E> = (Option<String>, Arc<dyn Component<T, E>>);
|
|
|
|
pub struct ActionRow<T, E> {
|
|
components: Vec<ComponentWithID<T, E>>,
|
|
}
|
|
|
|
impl<T, E> ActionRow<T, E> {
|
|
pub fn new(components: &[ComponentWithID<T, E>]) -> Self {
|
|
Self {
|
|
components: components.to_vec(),
|
|
}
|
|
}
|
|
|
|
pub fn add(&mut self, id: Option<String>, component: Arc<dyn Component<T, E>>) {
|
|
self.components.push((id, component));
|
|
}
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
self.components.is_empty()
|
|
}
|
|
|
|
pub fn build(self) -> TwilightComponent {
|
|
TwilightComponent::ActionRow(TwilightActionRow {
|
|
components: self
|
|
.components
|
|
.into_iter()
|
|
.map(|(id, c)| c.build(id))
|
|
.collect(),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
pub trait Component<T, E>: Send + Sync + Debug {
|
|
fn custom_id(&self) -> Option<String> {
|
|
Some(String::from("component"))
|
|
}
|
|
fn build(&self, id: Option<String>) -> TwilightComponent;
|
|
|
|
async fn execute(&self, ctx: InteractionContext<T, E>) -> Result<(), InteractionError>;
|
|
}
|
|
|
|
#[async_trait]
|
|
impl<T, S, E> Component<S, E> for T
|
|
where
|
|
T: Button<S, E>,
|
|
S: Send + Sync + 'static,
|
|
E: Send + Sync + 'static,
|
|
{
|
|
fn custom_id(&self) -> Option<String> {
|
|
Button::id(self)
|
|
}
|
|
|
|
fn build(&self, id: Option<String>) -> TwilightComponent {
|
|
TwilightComponent::Button(TwilightButton {
|
|
custom_id: id,
|
|
disabled: self.disabled(),
|
|
emoji: None,
|
|
label: self.label().map(|i| i.to_string()),
|
|
style: if self.url().is_none() {
|
|
self.style()
|
|
} else {
|
|
ButtonStyle::Link
|
|
},
|
|
url: self.url().map(|i| i.to_string()),
|
|
sku_id: None,
|
|
})
|
|
}
|
|
|
|
async fn execute(&self, ctx: InteractionContext<S, E>) -> Result<(), InteractionError> {
|
|
self.on_press(ctx).await
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
pub trait Button<S, E>: Send + Sync + Debug
|
|
where
|
|
S: Send + Sync + 'static,
|
|
E: Send + Sync + 'static,
|
|
{
|
|
fn id(&self) -> Option<String> {
|
|
if self.url().is_none() {
|
|
Some(String::from("Button"))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn style(&self) -> ButtonStyle {
|
|
ButtonStyle::Secondary
|
|
}
|
|
|
|
fn label(&self) -> Option<String> {
|
|
None
|
|
}
|
|
|
|
fn url(&self) -> Option<String> {
|
|
None
|
|
}
|
|
|
|
fn disabled(&self) -> bool {
|
|
false
|
|
}
|
|
|
|
async fn on_press(&self, ctx: InteractionContext<S, E>) -> Result<(), InteractionError> {
|
|
ctx.defer().await
|
|
}
|
|
}
|