Finish refactoring
This commit is contained in:
@@ -1,221 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use twilight_model::channel::message::Embed;
|
||||
use twilight_util::builder::embed::{
|
||||
EmbedAuthorBuilder, EmbedBuilder, EmbedFieldBuilder, EmbedFooterBuilder, ImageSource,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
commands::{COMMANDS, PREFIX, get_command_by_name},
|
||||
constants::{BOT_AVATAR, BOT_NAME, COLOR_RED, COLOR_WHITE},
|
||||
framework::{
|
||||
commands::{
|
||||
Command, CommandError,
|
||||
arguments::{Argument, NeedyString, ParseArguments},
|
||||
context::CommandContext,
|
||||
},
|
||||
interactions::{InteractionError, components::Button, context::InteractionContext},
|
||||
utils::EscapeDiscordMarkdown,
|
||||
},
|
||||
utils::ToTitleCase,
|
||||
};
|
||||
|
||||
pub struct HelpCommand;
|
||||
|
||||
#[async_trait]
|
||||
impl Command for HelpCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"help"
|
||||
}
|
||||
|
||||
fn arguments(&self) -> &'static [Argument] {
|
||||
&[Argument {
|
||||
name: "command",
|
||||
is_optional: true,
|
||||
is_greedy: false,
|
||||
}]
|
||||
}
|
||||
|
||||
fn description(&self) -> &'static str {
|
||||
"Lists all commands and shows information about them individually."
|
||||
}
|
||||
|
||||
async fn execute(&self, ctx: &CommandContext, args: &str) -> Result<(), CommandError> {
|
||||
let command_name: Option<NeedyString> = ParseArguments::parse(args).unwrap();
|
||||
|
||||
if let Some(command_name) = command_name {
|
||||
if let Some(command) = get_command_by_name(&command_name) {
|
||||
ctx.send()
|
||||
.embed(get_command_help_embed(&command))
|
||||
.component(HelpGoBackButton, 1)
|
||||
.component(HelpSupportLinkButton, 1)
|
||||
.await
|
||||
.inspect_err(|e| log::error!("Failed to send message! {e}"))
|
||||
.map_err(|_| CommandError::MessageSendingFailed)?;
|
||||
} else {
|
||||
ctx.send()
|
||||
.embed(get_command_not_found_embed(command_name.0))
|
||||
.component(HelpGoBackButton, 1)
|
||||
.component(HelpSupportLinkButton, 1)
|
||||
.await
|
||||
.map_err(|_| CommandError::MessageSendingFailed)?;
|
||||
}
|
||||
} else {
|
||||
ctx.send()
|
||||
.embed(get_all_command_help_embed())
|
||||
.component(HelpWebsiteLinkButton, 1)
|
||||
.component(HelpSupportLinkButton, 1)
|
||||
.component(HelpDonateLinkButton, 1)
|
||||
.await
|
||||
.map_err(|_| CommandError::MessageSendingFailed)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_command_help_embed(command: &Arc<dyn Command>) -> Embed {
|
||||
let name = format!("{PREFIX}{}", command.name());
|
||||
let arguments = command
|
||||
.arguments()
|
||||
.iter()
|
||||
.map(|arg| arg.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
let usage = if !arguments.is_empty() {
|
||||
format!("{name} {arguments}")
|
||||
} else {
|
||||
name
|
||||
};
|
||||
|
||||
EmbedBuilder::new()
|
||||
.author(
|
||||
EmbedAuthorBuilder::new(BOT_NAME)
|
||||
.icon_url(ImageSource::url(BOT_AVATAR).unwrap())
|
||||
.build(),
|
||||
)
|
||||
.thumbnail(ImageSource::url(BOT_AVATAR).unwrap())
|
||||
.color(COLOR_WHITE)
|
||||
.title(format!("{} Command", command.name().to_title_case()))
|
||||
.description(command.description())
|
||||
.field(EmbedFieldBuilder::new("Usage", format!("`{usage}`")).build())
|
||||
.field(EmbedFieldBuilder::new(
|
||||
"Aliases",
|
||||
if !command.aliases().is_empty() {
|
||||
command
|
||||
.aliases()
|
||||
.iter()
|
||||
.map(|alias| format!("`{PREFIX}{alias}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
} else {
|
||||
String::from("*This command doesn't have aliases.*")
|
||||
},
|
||||
))
|
||||
.footer(EmbedFooterBuilder::new(format!(
|
||||
"Use {PREFIX}help <command> to get help about a specific command."
|
||||
)))
|
||||
.build()
|
||||
}
|
||||
|
||||
fn get_all_command_help_embed() -> Embed {
|
||||
EmbedBuilder::new()
|
||||
.author(EmbedAuthorBuilder::new(BOT_NAME).icon_url(ImageSource::url(BOT_AVATAR).unwrap()))
|
||||
.title("Pick up the phone and start making friends!")
|
||||
.description(format!("Here is the list of all available commands. You can see more details about a specific command with `{PREFIX}help <command>`."))
|
||||
.thumbnail(ImageSource::url(BOT_AVATAR).unwrap())
|
||||
.color(COLOR_WHITE)
|
||||
.field(EmbedFieldBuilder::new("Commands", get_commands_table()).build())
|
||||
.footer(EmbedFooterBuilder::new(format!("v{} - Use {PREFIX}help <command> to get more information about a specific command.", env!("CARGO_PKG_VERSION"))))
|
||||
.build()
|
||||
}
|
||||
|
||||
fn get_commands_table() -> String {
|
||||
let mut table = String::new();
|
||||
|
||||
for command in COMMANDS.iter() {
|
||||
table.push_str(&format!("{:<12}", command.name()));
|
||||
}
|
||||
|
||||
format!("```\n{table}\n```")
|
||||
}
|
||||
|
||||
fn get_command_not_found_embed(name: String) -> Embed {
|
||||
EmbedBuilder::new()
|
||||
.color(COLOR_RED)
|
||||
.author(EmbedAuthorBuilder::new(BOT_NAME).icon_url(ImageSource::url(BOT_AVATAR).unwrap()))
|
||||
.title("That's not a command")
|
||||
.description(format!("`{}` is not a valid command name (nor alias). If you put it with the prefix on, take the prefix off before trying again. For example, if you did `p.help p.call`, do `p.help call` instead.\n\nIf you still can't figure it out, press the button below to go back to the full list. Everything's there!", name.escape()))
|
||||
.thumbnail(ImageSource::url(BOT_AVATAR).unwrap())
|
||||
.build()
|
||||
}
|
||||
|
||||
pub struct HelpGoBackButton;
|
||||
|
||||
#[async_trait]
|
||||
impl Button for HelpGoBackButton {
|
||||
fn label(&self) -> Option<&'static str> {
|
||||
Some("← Go back to commands list")
|
||||
}
|
||||
|
||||
async fn on_press(&self, ctx: InteractionContext) -> Result<(), InteractionError> {
|
||||
ctx
|
||||
.original_message()
|
||||
.expect(
|
||||
"Buttons always have the original message in the interaction context, this one didn't (got None)"
|
||||
)
|
||||
.edit()
|
||||
.embed(get_all_command_help_embed())
|
||||
.component(HelpWebsiteLinkButton, 1)
|
||||
.component(HelpSupportLinkButton, 1)
|
||||
.component(HelpDonateLinkButton, 1)
|
||||
.await
|
||||
.inspect_err(|e| log::error!("An error occurred while attempting to edit the original message of an interaction. {e:?}"))
|
||||
.map_err(
|
||||
|_| InteractionError::OriginalMessageEditingFailed
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HelpSupportLinkButton;
|
||||
|
||||
#[async_trait]
|
||||
impl Button for HelpSupportLinkButton {
|
||||
fn label(&self) -> Option<&'static str> {
|
||||
Some("Get help")
|
||||
}
|
||||
|
||||
fn url(&self) -> Option<&'static str> {
|
||||
Some("https://discord.gg/9daSsrfTmE")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HelpWebsiteLinkButton;
|
||||
|
||||
#[async_trait]
|
||||
impl Button for HelpWebsiteLinkButton {
|
||||
fn label(&self) -> Option<&'static str> {
|
||||
Some("Website")
|
||||
}
|
||||
|
||||
fn url(&self) -> Option<&'static str> {
|
||||
Some("https://payphone.lat/")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HelpDonateLinkButton;
|
||||
|
||||
#[async_trait]
|
||||
impl Button for HelpDonateLinkButton {
|
||||
fn label(&self) -> Option<&'static str> {
|
||||
Some("Donate")
|
||||
}
|
||||
|
||||
fn url(&self) -> Option<&'static str> {
|
||||
Some("https://ko-fi.com/payphonedev")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user