use poise::{ serenity_prelude::{ CreateActionRow, CreateEmbed, CreateEmbedFooter, CreateSelectMenu, CreateSelectMenuKind, CreateSelectMenuOption, }, CreateReply, }; use crate::{ component_models::{ pager::{Pager, TodoPager}, ComponentDataModel, TodoSelector, }, consts::{EMBED_DESCRIPTION_MAX_LENGTH, SELECT_MAX_ENTRIES, THEME_COLOR}, Context, Error, }; pub mod channel; pub mod guild; pub mod user; /// Manage todo lists #[poise::command(slash_command, default_member_permissions = "MANAGE_GUILD")] pub async fn todo(_ctx: Context<'_>) -> Result<(), Error> { Ok(()) } pub fn max_todo_page(todo_values: &[(usize, String)]) -> usize { let mut rows = 0; let mut char_count = 0; todo_values.iter().enumerate().map(|(c, (_, v))| format!("{}: {}", c, v)).fold( 1, |mut pages, text| { rows += 1; char_count += text.len(); if char_count > EMBED_DESCRIPTION_MAX_LENGTH || rows > SELECT_MAX_ENTRIES { rows = 1; char_count = text.len(); pages += 1; } pages }, ) } pub fn show_todo_page( todo_values: &[(usize, String)], page: usize, user_id: Option, channel_id: Option, guild_id: Option, ) -> CreateReply { let pager = TodoPager::new(page, user_id, channel_id, guild_id); let pages = max_todo_page(todo_values); let mut page = page; if page >= pages { page = pages - 1; } let mut char_count = 0; let mut rows = 0; let mut skipped_rows = 0; let mut skipped_char_count = 0; let mut first_num = 0; let mut skipped_pages = 0; let (todo_ids, display_vec): (Vec, Vec) = todo_values .iter() .enumerate() .map(|(c, (i, v))| (i, format!("`{}`: {}", c + 1, v))) .skip_while(|(_, p)| { first_num += 1; skipped_rows += 1; skipped_char_count += p.len(); if skipped_char_count > EMBED_DESCRIPTION_MAX_LENGTH || skipped_rows > SELECT_MAX_ENTRIES { skipped_rows = 1; skipped_char_count = p.len(); skipped_pages += 1; } skipped_pages < page }) .take_while(|(_, p)| { rows += 1; char_count += p.len(); char_count < EMBED_DESCRIPTION_MAX_LENGTH && rows <= SELECT_MAX_ENTRIES }) .unzip(); let display = display_vec.join("\n"); let title = if user_id.is_some() { "Your" } else if channel_id.is_some() { "Channel" } else { "Server" }; if todo_ids.is_empty() { CreateReply::default().embed( CreateEmbed::new() .title(format!("{} Todo List", title)) .description("Todo List Empty!") .color(*THEME_COLOR) .footer(CreateEmbedFooter::new(format!("Page {} of {}", page + 1, pages))), ) } else { let todo_selector = ComponentDataModel::TodoSelector(TodoSelector { page, user_id, channel_id, guild_id }); CreateReply::default() .embed( CreateEmbed::new() .title(format!("{} Todo List", title)) .description(display) .color(*THEME_COLOR) .footer(CreateEmbedFooter::new(format!("Page {} of {}", page + 1, pages))), ) .components(vec![ pager.create_button_row(pages), CreateActionRow::SelectMenu(CreateSelectMenu::new( todo_selector.to_custom_id(), CreateSelectMenuKind::String { options: todo_ids .iter() .zip(&display_vec) .enumerate() .map(|(count, (id, disp))| { let c = disp.split_once(' ').unwrap_or(("", "")).1; let description = if c.len() > 100 { format!("{}...", c.chars().take(97).collect::()) } else { c.to_string() }; CreateSelectMenuOption::new( format!("Mark {} complete", count + first_num), id.to_string(), ) .description(description) }) .collect(), }, )), ]) } }