use poise::{ serenity_prelude::{model::id::ChannelId, CreateEmbed, CreateEmbedFooter, PartialChannel}, CreateReply, }; use serde::{Deserialize, Serialize}; use serde_repr::*; use crate::{ component_models::pager::{LookPager, Pager}, consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR}, models::{reminder::Reminder, CtxData}, utils::{Extract, Recordable}, Context, Error, }; #[derive(Serialize_repr, Deserialize_repr, Copy, Clone)] #[repr(u8)] pub enum TimeDisplayType { Absolute = 0, Relative = 1, } #[derive(Serialize, Deserialize, Copy, Clone)] pub struct LookFlags { pub show_disabled: bool, pub channel_id: Option, pub time_display: TimeDisplayType, } impl Default for LookFlags { fn default() -> Self { Self { show_disabled: true, channel_id: None, time_display: TimeDisplayType::Relative } } } #[derive(Serialize, Deserialize, Extract)] pub struct Options { channel: Option, disabled: Option, relative: Option, } impl Recordable for Options { async fn run(self, ctx: Context<'_>) -> Result<(), Error> { let timezone = ctx.timezone().await; let flags = LookFlags { show_disabled: self.disabled.unwrap_or(true), channel_id: self.channel.map(|c| c.id), time_display: self.relative.map_or(TimeDisplayType::Relative, |b| { if b { TimeDisplayType::Relative } else { TimeDisplayType::Absolute } }), }; let channel_id = if let Some(channel) = ctx.channel_id().to_channel_cached(&ctx.cache()) { if Some(channel.guild_id) == ctx.guild_id() { flags.channel_id.unwrap_or_else(|| ctx.channel_id()) } else { ctx.channel_id() } } else { ctx.channel_id() }; let channel_name = channel_id.to_channel_cached(&ctx.cache()).map(|channel| channel.name.clone()); let reminders = Reminder::from_channel(&ctx.data().database, channel_id, &flags).await; if reminders.is_empty() { let _ = ctx.say("No reminders on specified channel").await; } else { let mut char_count = 0; let display = reminders .iter() .map(|reminder| reminder.display(&flags, &timezone)) .take_while(|p| { char_count += p.len(); char_count < EMBED_DESCRIPTION_MAX_LENGTH }) .collect::>() .join(""); let pages = reminders .iter() .map(|reminder| reminder.display(&flags, &timezone)) .fold(0, |t, r| t + r.len()) .div_ceil(EMBED_DESCRIPTION_MAX_LENGTH); let pager = LookPager::new(flags, timezone); ctx.send( CreateReply::default() .ephemeral(true) .embed( CreateEmbed::new() .title(format!( "Reminders{}", channel_name.map_or(String::new(), |n| format!(" on #{}", n)) )) .description(display) .footer(CreateEmbedFooter::new(format!("Page {} of {}", 1, pages))) .color(*THEME_COLOR), ) .components(vec![pager.create_button_row(pages)]), ) .await?; } Ok(()) } } /// View reminders on a specific channel #[poise::command( slash_command, rename = "look", identifying_name = "look", default_member_permissions = "MANAGE_GUILD" )] pub async fn command( ctx: Context<'_>, #[description = "Channel to view reminders on"] channel: Option, #[description = "Whether to show disabled reminders or not"] disabled: Option, #[description = "Whether to display times as relative or exact times"] relative: Option, ) -> Result<(), Error> { (Options { channel, disabled, relative }).run(ctx).await }