todo stuff
This commit is contained in:
parent
6b5d6ae288
commit
ebabe0e85a
@ -81,21 +81,28 @@ pub fn command(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
options.subcommand_groups.push(new_group);
|
options.subcommand_groups.push(new_group);
|
||||||
}
|
}
|
||||||
"arg" => {
|
"arg" => {
|
||||||
if let Some(subcommand_group) = options.subcommand_groups.last_mut() {
|
let arg = propagate_err!(attributes::parse(values));
|
||||||
if let Some(subcommand) = subcommand_group.subcommands.last_mut() {
|
|
||||||
subcommand.cmd_args.push(propagate_err!(attributes::parse(values)));
|
match last_desc {
|
||||||
} else {
|
LastItem::Fun => {
|
||||||
if let Some(subcommand) = options.subcommands.last_mut() {
|
options.cmd_args.push(arg);
|
||||||
subcommand.cmd_args.push(propagate_err!(attributes::parse(values)));
|
|
||||||
} else {
|
|
||||||
options.cmd_args.push(propagate_err!(attributes::parse(values)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
LastItem::SubFun => {
|
||||||
if let Some(subcommand) = options.subcommands.last_mut() {
|
options.subcommands.last_mut().unwrap().cmd_args.push(arg);
|
||||||
subcommand.cmd_args.push(propagate_err!(attributes::parse(values)));
|
}
|
||||||
} else {
|
LastItem::SubGroup => {
|
||||||
options.cmd_args.push(propagate_err!(attributes::parse(values)));
|
panic!("Argument not expected under subcommand group");
|
||||||
|
}
|
||||||
|
LastItem::SubGroupFun => {
|
||||||
|
options
|
||||||
|
.subcommand_groups
|
||||||
|
.last_mut()
|
||||||
|
.unwrap()
|
||||||
|
.subcommands
|
||||||
|
.last_mut()
|
||||||
|
.unwrap()
|
||||||
|
.cmd_args
|
||||||
|
.push(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -369,7 +369,7 @@ async fn delete(ctx: &Context, invoke: CommandInvoke, _args: CommandOptions) {
|
|||||||
|
|
||||||
let reminders = Reminder::from_guild(ctx, interaction.guild_id, interaction.user.id).await;
|
let reminders = Reminder::from_guild(ctx, interaction.guild_id, interaction.user.id).await;
|
||||||
|
|
||||||
let resp = show_delete_page(&reminders, 0, timezone).await;
|
let resp = show_delete_page(&reminders, 0, timezone);
|
||||||
|
|
||||||
let _ = interaction
|
let _ = interaction
|
||||||
.create_interaction_response(&ctx, |r| {
|
.create_interaction_response(&ctx, |r| {
|
||||||
@ -402,7 +402,7 @@ pub fn max_delete_page(reminders: &[Reminder], timezone: &Tz) -> usize {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn show_delete_page(
|
pub fn show_delete_page(
|
||||||
reminders: &[Reminder],
|
reminders: &[Reminder],
|
||||||
page: usize,
|
page: usize,
|
||||||
timezone: Tz,
|
timezone: Tz,
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
use regex_command_attr::command;
|
use regex_command_attr::command;
|
||||||
use serenity::client::Context;
|
use serenity::{
|
||||||
|
builder::{CreateEmbed, CreateInteractionResponse},
|
||||||
|
client::Context,
|
||||||
|
model::interactions::InteractionResponseType,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
component_models::pager::TodoPager,
|
||||||
|
consts::{EMBED_DESCRIPTION_MAX_LENGTH, SELECT_MAX_ENTRIES, THEME_COLOR},
|
||||||
framework::{CommandInvoke, CommandOptions, CreateGenericResponse},
|
framework::{CommandInvoke, CommandOptions, CreateGenericResponse},
|
||||||
SQLPool,
|
SQLPool,
|
||||||
};
|
};
|
||||||
@ -61,6 +67,8 @@ async fn todo(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
_ => (Some(invoke.author_id().0), None, None),
|
_ => (Some(invoke.author_id().0), None, None),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
println!("{:?}", keys);
|
||||||
|
|
||||||
match args.get("task") {
|
match args.get("task") {
|
||||||
Some(task) => {
|
Some(task) => {
|
||||||
let task = task.to_string();
|
let task = task.to_string();
|
||||||
@ -82,7 +90,8 @@ async fn todo(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let values = sqlx::query!(
|
let values = sqlx::query!(
|
||||||
"SELECT value FROM todos WHERE user_id = ? AND channel_id = ? AND guild_id = ?",
|
// fucking braindead mysql use <=> instead of = for null comparison
|
||||||
|
"SELECT value FROM todos WHERE user_id <=> ? AND channel_id <=> ? AND guild_id <=> ?",
|
||||||
keys.0,
|
keys.0,
|
||||||
keys.1,
|
keys.1,
|
||||||
keys.2,
|
keys.2,
|
||||||
@ -91,8 +100,115 @@ async fn todo(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|row| &row.value);
|
.map(|row| row.value.clone())
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let resp = show_todo_page(&values, 0, keys.0, keys.1, keys.2);
|
||||||
|
|
||||||
|
let interaction = invoke.interaction().unwrap();
|
||||||
|
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
*r = resp;
|
||||||
|
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn max_todo_page(todo_values: &[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: &[String],
|
||||||
|
page: usize,
|
||||||
|
user_id: Option<u64>,
|
||||||
|
channel_id: Option<u64>,
|
||||||
|
guild_id: Option<u64>,
|
||||||
|
) -> CreateInteractionResponse {
|
||||||
|
// 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 display_vec: Vec<String> = todo_values
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(c, v)| 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
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let display = display_vec.join("\n");
|
||||||
|
|
||||||
|
let title = if user_id.is_some() {
|
||||||
|
"Your"
|
||||||
|
} else if channel_id.is_some() {
|
||||||
|
"Channel"
|
||||||
|
} else {
|
||||||
|
"Server"
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut embed = CreateEmbed::default();
|
||||||
|
embed
|
||||||
|
.title(format!("{} Todo List", title))
|
||||||
|
.description(display)
|
||||||
|
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
|
||||||
|
.color(*THEME_COLOR);
|
||||||
|
|
||||||
|
let mut response = CreateInteractionResponse::default();
|
||||||
|
response.interaction_response_data(|d| d.embeds(vec![embed]));
|
||||||
|
|
||||||
|
response
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ use serenity::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::reminder_cmds::{max_delete_page, show_delete_page},
|
commands::reminder_cmds::{max_delete_page, show_delete_page},
|
||||||
component_models::pager::{DelPager, LookPager, Pager},
|
component_models::pager::{DelPager, LookPager, Pager, TodoPager},
|
||||||
consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
|
consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
|
||||||
models::reminder::Reminder,
|
models::reminder::Reminder,
|
||||||
SQLPool,
|
SQLPool,
|
||||||
@ -31,6 +31,7 @@ pub enum ComponentDataModel {
|
|||||||
Restrict(Restrict),
|
Restrict(Restrict),
|
||||||
LookPager(LookPager),
|
LookPager(LookPager),
|
||||||
DelPager(DelPager),
|
DelPager(DelPager),
|
||||||
|
TodoPager(TodoPager),
|
||||||
DelSelector(DelSelector),
|
DelSelector(DelSelector),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,8 +169,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
|
|||||||
|
|
||||||
let max_pages = max_delete_page(&reminders, &pager.timezone);
|
let max_pages = max_delete_page(&reminders, &pager.timezone);
|
||||||
|
|
||||||
let resp =
|
let resp = show_delete_page(&reminders, pager.next_page(max_pages), pager.timezone);
|
||||||
show_delete_page(&reminders, pager.next_page(max_pages), pager.timezone).await;
|
|
||||||
|
|
||||||
let _ = component
|
let _ = component
|
||||||
.create_interaction_response(&ctx, move |r| {
|
.create_interaction_response(&ctx, move |r| {
|
||||||
@ -190,7 +190,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
|
|||||||
let reminders =
|
let reminders =
|
||||||
Reminder::from_guild(ctx, component.guild_id, component.user.id).await;
|
Reminder::from_guild(ctx, component.guild_id, component.user.id).await;
|
||||||
|
|
||||||
let resp = show_delete_page(&reminders, selector.page, selector.timezone).await;
|
let resp = show_delete_page(&reminders, selector.page, selector.timezone);
|
||||||
|
|
||||||
let _ = component
|
let _ = component
|
||||||
.create_interaction_response(&ctx, move |r| {
|
.create_interaction_response(&ctx, move |r| {
|
||||||
@ -199,6 +199,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
ComponentDataModel::TodoPager(pager) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
|
// todo split pager out into a single struct
|
||||||
use chrono_tz::Tz;
|
use chrono_tz::Tz;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_repr::*;
|
use serde_repr::*;
|
||||||
use serenity::{builder::CreateComponents, model::interactions::message_component::ButtonStyle};
|
use serenity::{
|
||||||
|
builder::CreateComponents,
|
||||||
|
model::{
|
||||||
|
id::{ChannelId, GuildId, UserId},
|
||||||
|
interactions::message_component::ButtonStyle,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{component_models::ComponentDataModel, models::reminder::look_flags::LookFlags};
|
use crate::{component_models::ComponentDataModel, models::reminder::look_flags::LookFlags};
|
||||||
|
|
||||||
@ -209,3 +216,123 @@ impl DelPager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct TodoPager {
|
||||||
|
pub page: usize,
|
||||||
|
action: PageAction,
|
||||||
|
pub user_id: Option<UserId>,
|
||||||
|
pub channel_id: Option<ChannelId>,
|
||||||
|
pub guild_id: Option<GuildId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pager for TodoPager {
|
||||||
|
fn next_page(&self, max_pages: usize) -> usize {
|
||||||
|
match self.action {
|
||||||
|
PageAction::First => 0,
|
||||||
|
PageAction::Previous => 0.max(self.page - 1),
|
||||||
|
PageAction::Refresh => self.page,
|
||||||
|
PageAction::Next => (max_pages - 1).min(self.page + 1),
|
||||||
|
PageAction::Last => max_pages - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_button_row(&self, max_pages: usize, comp: &mut CreateComponents) {
|
||||||
|
let next_page = self.next_page(max_pages);
|
||||||
|
|
||||||
|
let (page_first, page_prev, page_refresh, page_next, page_last) =
|
||||||
|
TodoPager::buttons(next_page, self.user_id, self.channel_id, self.guild_id);
|
||||||
|
|
||||||
|
comp.create_action_row(|row| {
|
||||||
|
row.create_button(|b| {
|
||||||
|
b.label("⏮️")
|
||||||
|
.style(ButtonStyle::Primary)
|
||||||
|
.custom_id(page_first.to_custom_id())
|
||||||
|
.disabled(next_page == 0)
|
||||||
|
})
|
||||||
|
.create_button(|b| {
|
||||||
|
b.label("◀️")
|
||||||
|
.style(ButtonStyle::Secondary)
|
||||||
|
.custom_id(page_prev.to_custom_id())
|
||||||
|
.disabled(next_page == 0)
|
||||||
|
})
|
||||||
|
.create_button(|b| {
|
||||||
|
b.label("🔁").style(ButtonStyle::Secondary).custom_id(page_refresh.to_custom_id())
|
||||||
|
})
|
||||||
|
.create_button(|b| {
|
||||||
|
b.label("▶️")
|
||||||
|
.style(ButtonStyle::Secondary)
|
||||||
|
.custom_id(page_next.to_custom_id())
|
||||||
|
.disabled(next_page + 1 == max_pages)
|
||||||
|
})
|
||||||
|
.create_button(|b| {
|
||||||
|
b.label("⏭️")
|
||||||
|
.style(ButtonStyle::Primary)
|
||||||
|
.custom_id(page_last.to_custom_id())
|
||||||
|
.disabled(next_page + 1 == max_pages)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TodoPager {
|
||||||
|
pub fn new(
|
||||||
|
page: usize,
|
||||||
|
user_id: Option<UserId>,
|
||||||
|
channel_id: Option<ChannelId>,
|
||||||
|
guild_id: Option<GuildId>,
|
||||||
|
) -> Self {
|
||||||
|
Self { page, action: PageAction::Refresh, user_id, channel_id, guild_id }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn buttons(
|
||||||
|
page: usize,
|
||||||
|
user_id: Option<UserId>,
|
||||||
|
channel_id: Option<ChannelId>,
|
||||||
|
guild_id: Option<GuildId>,
|
||||||
|
) -> (
|
||||||
|
ComponentDataModel,
|
||||||
|
ComponentDataModel,
|
||||||
|
ComponentDataModel,
|
||||||
|
ComponentDataModel,
|
||||||
|
ComponentDataModel,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
ComponentDataModel::TodoPager(TodoPager {
|
||||||
|
page,
|
||||||
|
action: PageAction::First,
|
||||||
|
user_id,
|
||||||
|
channel_id,
|
||||||
|
guild_id,
|
||||||
|
}),
|
||||||
|
ComponentDataModel::TodoPager(TodoPager {
|
||||||
|
page,
|
||||||
|
action: PageAction::Previous,
|
||||||
|
user_id,
|
||||||
|
channel_id,
|
||||||
|
guild_id,
|
||||||
|
}),
|
||||||
|
ComponentDataModel::TodoPager(TodoPager {
|
||||||
|
page,
|
||||||
|
action: PageAction::Refresh,
|
||||||
|
user_id,
|
||||||
|
channel_id,
|
||||||
|
guild_id,
|
||||||
|
}),
|
||||||
|
ComponentDataModel::TodoPager(TodoPager {
|
||||||
|
page,
|
||||||
|
action: PageAction::Next,
|
||||||
|
user_id,
|
||||||
|
channel_id,
|
||||||
|
guild_id,
|
||||||
|
}),
|
||||||
|
ComponentDataModel::TodoPager(TodoPager {
|
||||||
|
page,
|
||||||
|
action: PageAction::Last,
|
||||||
|
user_id,
|
||||||
|
channel_id,
|
||||||
|
guild_id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -614,7 +614,18 @@ impl RegexFramework {
|
|||||||
s.name(option.name)
|
s.name(option.name)
|
||||||
.description(option.description)
|
.description(option.description)
|
||||||
.kind(option.kind)
|
.kind(option.kind)
|
||||||
.required(option.required)
|
.required(option.required);
|
||||||
|
|
||||||
|
for sub_option in option.options {
|
||||||
|
s.create_sub_option(|ss| {
|
||||||
|
ss.name(sub_option.name)
|
||||||
|
.description(sub_option.description)
|
||||||
|
.kind(sub_option.kind)
|
||||||
|
.required(sub_option.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
s
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,18 +318,4 @@ WHERE
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete(&self, ctx: &Context) {
|
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
DELETE FROM reminders WHERE id = ?
|
|
||||||
",
|
|
||||||
self.id
|
|
||||||
)
|
|
||||||
.execute(&pool)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user