pager improvements. deleting working
This commit is contained in:
		@@ -1,26 +1,16 @@
 | 
				
			|||||||
use std::{collections::HashMap, iter};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use chrono::offset::Utc;
 | 
					use chrono::offset::Utc;
 | 
				
			||||||
use chrono_tz::{Tz, TZ_VARIANTS};
 | 
					use chrono_tz::{Tz, TZ_VARIANTS};
 | 
				
			||||||
use levenshtein::levenshtein;
 | 
					use levenshtein::levenshtein;
 | 
				
			||||||
use regex::Regex;
 | 
					 | 
				
			||||||
use regex_command_attr::command;
 | 
					use regex_command_attr::command;
 | 
				
			||||||
use serenity::{
 | 
					use serenity::{client::Context, model::misc::Mentionable};
 | 
				
			||||||
    client::Context,
 | 
					 | 
				
			||||||
    model::{
 | 
					 | 
				
			||||||
        channel::Message,
 | 
					 | 
				
			||||||
        id::{ChannelId, MessageId, RoleId},
 | 
					 | 
				
			||||||
        misc::Mentionable,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    component_models::{ComponentDataModel, Restrict},
 | 
					    component_models::{ComponentDataModel, Restrict},
 | 
				
			||||||
    consts::{REGEX_ALIAS, REGEX_COMMANDS, THEME_COLOR},
 | 
					    consts::THEME_COLOR,
 | 
				
			||||||
    framework::{
 | 
					    framework::{
 | 
				
			||||||
        CommandInvoke, CommandOptions, CreateGenericResponse, OptionValue, PermissionLevel,
 | 
					        CommandInvoke, CommandOptions, CreateGenericResponse, OptionValue, PermissionLevel,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    models::{channel_data::ChannelData, guild_data::GuildData, user_data::UserData, CtxData},
 | 
					    models::{channel_data::ChannelData, CtxData},
 | 
				
			||||||
    PopularTimezones, RegexFramework, SQLPool,
 | 
					    PopularTimezones, RegexFramework, SQLPool,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    collections::HashMap,
 | 
					 | 
				
			||||||
    default::Default,
 | 
					    default::Default,
 | 
				
			||||||
    string::ToString,
 | 
					    string::ToString,
 | 
				
			||||||
    time::{SystemTime, UNIX_EPOCH},
 | 
					    time::{SystemTime, UNIX_EPOCH},
 | 
				
			||||||
@@ -8,20 +7,14 @@ use std::{
 | 
				
			|||||||
use chrono::NaiveDateTime;
 | 
					use chrono::NaiveDateTime;
 | 
				
			||||||
use num_integer::Integer;
 | 
					use num_integer::Integer;
 | 
				
			||||||
use regex_command_attr::command;
 | 
					use regex_command_attr::command;
 | 
				
			||||||
use serenity::{
 | 
					use serenity::{client::Context, model::channel::Channel};
 | 
				
			||||||
    client::Context,
 | 
					 | 
				
			||||||
    futures::StreamExt,
 | 
					 | 
				
			||||||
    model::{
 | 
					 | 
				
			||||||
        channel::{Channel, Message},
 | 
					 | 
				
			||||||
        id::ChannelId,
 | 
					 | 
				
			||||||
        interactions::message_component::ButtonStyle,
 | 
					 | 
				
			||||||
        misc::Mentionable,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    check_subscription_on_message,
 | 
					    check_subscription_on_message,
 | 
				
			||||||
    component_models::{ComponentDataModel, LookPager, PageAction},
 | 
					    component_models::{
 | 
				
			||||||
 | 
					        pager::{DelPager, LookPager, Pager},
 | 
				
			||||||
 | 
					        ComponentDataModel, DelSelector,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    consts::{
 | 
					    consts::{
 | 
				
			||||||
        EMBED_DESCRIPTION_MAX_LENGTH, REGEX_CHANNEL_USER, REGEX_NATURAL_COMMAND_1,
 | 
					        EMBED_DESCRIPTION_MAX_LENGTH, REGEX_CHANNEL_USER, REGEX_NATURAL_COMMAND_1,
 | 
				
			||||||
        REGEX_NATURAL_COMMAND_2, REGEX_REMIND_COMMAND, THEME_COLOR,
 | 
					        REGEX_NATURAL_COMMAND_2, REGEX_REMIND_COMMAND, THEME_COLOR,
 | 
				
			||||||
@@ -160,7 +153,7 @@ async fn offset(ctx: &Context, invoke: &(dyn CommandInvoke + Send + Sync), args:
 | 
				
			|||||||
            let channels = guild
 | 
					            let channels = guild
 | 
				
			||||||
                .channels
 | 
					                .channels
 | 
				
			||||||
                .iter()
 | 
					                .iter()
 | 
				
			||||||
                .filter(|(channel_id, channel)| match channel {
 | 
					                .filter(|(_, channel)| match channel {
 | 
				
			||||||
                    Channel::Guild(guild_channel) => guild_channel.is_text_based(),
 | 
					                    Channel::Guild(guild_channel) => guild_channel.is_text_based(),
 | 
				
			||||||
                    _ => false,
 | 
					                    _ => false,
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
@@ -333,30 +326,7 @@ async fn look(ctx: &Context, invoke: &(dyn CommandInvoke + Send + Sync), args: C
 | 
				
			|||||||
            .fold(0, |t, r| t + r.len())
 | 
					            .fold(0, |t, r| t + r.len())
 | 
				
			||||||
            .div_ceil(EMBED_DESCRIPTION_MAX_LENGTH);
 | 
					            .div_ceil(EMBED_DESCRIPTION_MAX_LENGTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let page_first = ComponentDataModel::LookPager(LookPager {
 | 
					        let pager = LookPager::new(flags, timezone);
 | 
				
			||||||
            flags: flags.clone(),
 | 
					 | 
				
			||||||
            page: 0,
 | 
					 | 
				
			||||||
            action: PageAction::First,
 | 
					 | 
				
			||||||
            timezone,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        let page_prev = ComponentDataModel::LookPager(LookPager {
 | 
					 | 
				
			||||||
            flags: flags.clone(),
 | 
					 | 
				
			||||||
            page: 0,
 | 
					 | 
				
			||||||
            action: PageAction::Previous,
 | 
					 | 
				
			||||||
            timezone,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        let page_next = ComponentDataModel::LookPager(LookPager {
 | 
					 | 
				
			||||||
            flags: flags.clone(),
 | 
					 | 
				
			||||||
            page: 0,
 | 
					 | 
				
			||||||
            action: PageAction::Next,
 | 
					 | 
				
			||||||
            timezone,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        let page_last = ComponentDataModel::LookPager(LookPager {
 | 
					 | 
				
			||||||
            flags: flags.clone(),
 | 
					 | 
				
			||||||
            page: 0,
 | 
					 | 
				
			||||||
            action: PageAction::Last,
 | 
					 | 
				
			||||||
            timezone,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        invoke
 | 
					        invoke
 | 
				
			||||||
            .respond(
 | 
					            .respond(
 | 
				
			||||||
@@ -372,32 +342,9 @@ async fn look(ctx: &Context, invoke: &(dyn CommandInvoke + Send + Sync), args: C
 | 
				
			|||||||
                        .color(*THEME_COLOR)
 | 
					                        .color(*THEME_COLOR)
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                    .components(|comp| {
 | 
					                    .components(|comp| {
 | 
				
			||||||
                        comp.create_action_row(|row| {
 | 
					                        pager.create_button_row(pages, comp);
 | 
				
			||||||
                            row.create_button(|b| {
 | 
					
 | 
				
			||||||
                                b.label("⏮️")
 | 
					                        comp
 | 
				
			||||||
                                    .style(ButtonStyle::Primary)
 | 
					 | 
				
			||||||
                                    .custom_id(page_first.to_custom_id())
 | 
					 | 
				
			||||||
                                    .disabled(true)
 | 
					 | 
				
			||||||
                            })
 | 
					 | 
				
			||||||
                            .create_button(|b| {
 | 
					 | 
				
			||||||
                                b.label("◀️")
 | 
					 | 
				
			||||||
                                    .style(ButtonStyle::Secondary)
 | 
					 | 
				
			||||||
                                    .custom_id(page_prev.to_custom_id())
 | 
					 | 
				
			||||||
                                    .disabled(true)
 | 
					 | 
				
			||||||
                            })
 | 
					 | 
				
			||||||
                            .create_button(|b| {
 | 
					 | 
				
			||||||
                                b.label("▶️")
 | 
					 | 
				
			||||||
                                    .style(ButtonStyle::Secondary)
 | 
					 | 
				
			||||||
                                    .custom_id(page_next.to_custom_id())
 | 
					 | 
				
			||||||
                                    .disabled(pages == 1)
 | 
					 | 
				
			||||||
                            })
 | 
					 | 
				
			||||||
                            .create_button(|b| {
 | 
					 | 
				
			||||||
                                b.label("⏭️")
 | 
					 | 
				
			||||||
                                    .style(ButtonStyle::Primary)
 | 
					 | 
				
			||||||
                                    .custom_id(page_last.to_custom_id())
 | 
					 | 
				
			||||||
                                    .disabled(pages == 1)
 | 
					 | 
				
			||||||
                            })
 | 
					 | 
				
			||||||
                        })
 | 
					 | 
				
			||||||
                    }),
 | 
					                    }),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .await
 | 
					            .await
 | 
				
			||||||
@@ -409,19 +356,92 @@ async fn look(ctx: &Context, invoke: &(dyn CommandInvoke + Send + Sync), args: C
 | 
				
			|||||||
#[description("Delete reminders")]
 | 
					#[description("Delete reminders")]
 | 
				
			||||||
#[required_permissions(Managed)]
 | 
					#[required_permissions(Managed)]
 | 
				
			||||||
async fn delete(ctx: &Context, invoke: &(dyn CommandInvoke + Send + Sync)) {
 | 
					async fn delete(ctx: &Context, invoke: &(dyn CommandInvoke + Send + Sync)) {
 | 
				
			||||||
 | 
					    let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let timezone = UserData::timezone_of(&invoke.author_id(), &pool).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let reminders = Reminder::from_guild(ctx, invoke.guild_id(), invoke.author_id()).await;
 | 
					    let reminders = Reminder::from_guild(ctx, invoke.guild_id(), invoke.author_id()).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let enumerated_reminders = reminders.iter().enumerate().map(|(count, reminder)| {
 | 
					    if reminders.is_empty() {
 | 
				
			||||||
        format!(
 | 
					        let _ = invoke
 | 
				
			||||||
            "**{}**: '{}' *<#{}>* at <t:{}>",
 | 
					            .respond(
 | 
				
			||||||
            count + 1,
 | 
					                ctx.http.clone(),
 | 
				
			||||||
            reminder.display_content(),
 | 
					                CreateGenericResponse::new().content("No reminders to delete!"),
 | 
				
			||||||
            reminder.channel,
 | 
					 | 
				
			||||||
            reminder.utc_time.timestamp()
 | 
					 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
    });
 | 
					            .await;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        let mut char_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let _ = invoke.respond(ctx.http.clone(), CreateGenericResponse::new().content("test")).await;
 | 
					        let (shown_reminders, display_vec): (Vec<&Reminder>, Vec<String>) = reminders
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .enumerate()
 | 
				
			||||||
 | 
					            .map(|(count, reminder)| (reminder, reminder.display_del(count, &timezone)))
 | 
				
			||||||
 | 
					            .take_while(|(_, p)| {
 | 
				
			||||||
 | 
					                char_count += p.len();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                char_count < EMBED_DESCRIPTION_MAX_LENGTH
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .unzip();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let display = display_vec.join("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pages = reminders
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .enumerate()
 | 
				
			||||||
 | 
					            .map(|(count, reminder)| reminder.display_del(count, &timezone))
 | 
				
			||||||
 | 
					            .fold(0, |t, r| t + r.len())
 | 
				
			||||||
 | 
					            .div_ceil(EMBED_DESCRIPTION_MAX_LENGTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pager = DelPager::new(timezone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let del_selector = ComponentDataModel::DelSelector(DelSelector { page: 0, timezone });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        invoke
 | 
				
			||||||
 | 
					            .respond(
 | 
				
			||||||
 | 
					                ctx.http.clone(),
 | 
				
			||||||
 | 
					                CreateGenericResponse::new()
 | 
				
			||||||
 | 
					                    .embed(|e| {
 | 
				
			||||||
 | 
					                        e.title("Delete Reminders")
 | 
				
			||||||
 | 
					                            .description(display)
 | 
				
			||||||
 | 
					                            .footer(|f| f.text(format!("Page {} of {}", 1, pages)))
 | 
				
			||||||
 | 
					                            .color(*THEME_COLOR)
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .components(|comp| {
 | 
				
			||||||
 | 
					                        pager.create_button_row(pages, comp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        comp.create_action_row(|row| {
 | 
				
			||||||
 | 
					                            row.create_select_menu(|menu| {
 | 
				
			||||||
 | 
					                                menu.custom_id(del_selector.to_custom_id()).options(|opt| {
 | 
				
			||||||
 | 
					                                    for (count, reminder) in shown_reminders.iter().enumerate() {
 | 
				
			||||||
 | 
					                                        opt.create_option(|o| {
 | 
				
			||||||
 | 
					                                            o.label(count + 1).value(reminder.id).description({
 | 
				
			||||||
 | 
					                                                let c = reminder.display_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                if c.len() > 100 {
 | 
				
			||||||
 | 
					                                                    format!(
 | 
				
			||||||
 | 
					                                                        "{}...",
 | 
				
			||||||
 | 
					                                                        reminder
 | 
				
			||||||
 | 
					                                                            .display_content()
 | 
				
			||||||
 | 
					                                                            .chars()
 | 
				
			||||||
 | 
					                                                            .take(97)
 | 
				
			||||||
 | 
					                                                            .collect::<String>()
 | 
				
			||||||
 | 
					                                                    )
 | 
				
			||||||
 | 
					                                                } else {
 | 
				
			||||||
 | 
					                                                    c.to_string()
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
 | 
					                                            })
 | 
				
			||||||
 | 
					                                        });
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    opt
 | 
				
			||||||
 | 
					                                })
 | 
				
			||||||
 | 
					                            })
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
 | 
					                    }),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[command("timer")]
 | 
					#[command("timer")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,29 +1,25 @@
 | 
				
			|||||||
 | 
					pub(crate) mod pager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::io::Cursor;
 | 
					use std::io::Cursor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use chrono_tz::Tz;
 | 
					use chrono_tz::Tz;
 | 
				
			||||||
use rmp_serde::Serializer;
 | 
					use rmp_serde::Serializer;
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use serde_repr::*;
 | 
					 | 
				
			||||||
use serenity::{
 | 
					use serenity::{
 | 
				
			||||||
    builder::CreateEmbed,
 | 
					    builder::CreateEmbed,
 | 
				
			||||||
    client::Context,
 | 
					    client::Context,
 | 
				
			||||||
    model::{
 | 
					    model::{
 | 
				
			||||||
        channel::Channel,
 | 
					        channel::Channel,
 | 
				
			||||||
        id::{ChannelId, GuildId, RoleId, UserId},
 | 
					        id::{GuildId, RoleId, UserId},
 | 
				
			||||||
        interactions::{
 | 
					        interactions::{message_component::MessageComponentInteraction, InteractionResponseType},
 | 
				
			||||||
            message_component::{ButtonStyle, MessageComponentInteraction},
 | 
					 | 
				
			||||||
            InteractionResponseType,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        prelude::InteractionApplicationCommandCallbackDataFlags,
 | 
					        prelude::InteractionApplicationCommandCallbackDataFlags,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
 | 
					    component_models::pager::{DelPager, LookPager, Pager},
 | 
				
			||||||
    consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
 | 
					    consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
 | 
				
			||||||
    models::{
 | 
					    models::reminder::Reminder,
 | 
				
			||||||
        reminder::{look_flags::LookFlags, Reminder},
 | 
					 | 
				
			||||||
        user_data::UserData,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    SQLPool,
 | 
					    SQLPool,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,6 +29,8 @@ use crate::{
 | 
				
			|||||||
pub enum ComponentDataModel {
 | 
					pub enum ComponentDataModel {
 | 
				
			||||||
    Restrict(Restrict),
 | 
					    Restrict(Restrict),
 | 
				
			||||||
    LookPager(LookPager),
 | 
					    LookPager(LookPager),
 | 
				
			||||||
 | 
					    DelPager(DelPager),
 | 
				
			||||||
 | 
					    DelSelector(DelSelector),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ComponentDataModel {
 | 
					impl ComponentDataModel {
 | 
				
			||||||
@@ -109,7 +107,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
 | 
				
			|||||||
                    .iter()
 | 
					                    .iter()
 | 
				
			||||||
                    .map(|reminder| reminder.display(&flags, &pager.timezone))
 | 
					                    .map(|reminder| reminder.display(&flags, &pager.timezone))
 | 
				
			||||||
                    .fold(0, |t, r| t + r.len())
 | 
					                    .fold(0, |t, r| t + r.len())
 | 
				
			||||||
                    .div_ceil(EMBED_DESCRIPTION_MAX_LENGTH) as u16;
 | 
					                    .div_ceil(EMBED_DESCRIPTION_MAX_LENGTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let channel_name =
 | 
					                let channel_name =
 | 
				
			||||||
                    if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) {
 | 
					                    if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) {
 | 
				
			||||||
@@ -118,12 +116,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
 | 
				
			|||||||
                        None
 | 
					                        None
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let next_page = match pager.action {
 | 
					                let next_page = pager.next_page(pages);
 | 
				
			||||||
                    PageAction::First => 0,
 | 
					 | 
				
			||||||
                    PageAction::Previous => 0.max(pager.page - 1),
 | 
					 | 
				
			||||||
                    PageAction::Next => (pages - 1).min(pager.page + 1),
 | 
					 | 
				
			||||||
                    PageAction::Last => pages - 1,
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let mut char_count = 0;
 | 
					                let mut char_count = 0;
 | 
				
			||||||
                let mut skip_char_count = 0;
 | 
					                let mut skip_char_count = 0;
 | 
				
			||||||
@@ -144,31 +137,6 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
 | 
				
			|||||||
                    .collect::<Vec<String>>()
 | 
					                    .collect::<Vec<String>>()
 | 
				
			||||||
                    .join("\n");
 | 
					                    .join("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let page_first = ComponentDataModel::LookPager(LookPager {
 | 
					 | 
				
			||||||
                    flags: flags.clone(),
 | 
					 | 
				
			||||||
                    page: next_page,
 | 
					 | 
				
			||||||
                    action: PageAction::First,
 | 
					 | 
				
			||||||
                    timezone: pager.timezone,
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                let page_prev = ComponentDataModel::LookPager(LookPager {
 | 
					 | 
				
			||||||
                    flags: flags.clone(),
 | 
					 | 
				
			||||||
                    page: next_page,
 | 
					 | 
				
			||||||
                    action: PageAction::Previous,
 | 
					 | 
				
			||||||
                    timezone: pager.timezone,
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                let page_next = ComponentDataModel::LookPager(LookPager {
 | 
					 | 
				
			||||||
                    flags: flags.clone(),
 | 
					 | 
				
			||||||
                    page: next_page,
 | 
					 | 
				
			||||||
                    action: PageAction::Next,
 | 
					 | 
				
			||||||
                    timezone: pager.timezone,
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                let page_last = ComponentDataModel::LookPager(LookPager {
 | 
					 | 
				
			||||||
                    flags: flags.clone(),
 | 
					 | 
				
			||||||
                    page: next_page,
 | 
					 | 
				
			||||||
                    action: PageAction::Last,
 | 
					 | 
				
			||||||
                    timezone: pager.timezone,
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let mut embed = CreateEmbed::default();
 | 
					                let mut embed = CreateEmbed::default();
 | 
				
			||||||
                embed
 | 
					                embed
 | 
				
			||||||
                    .title(format!(
 | 
					                    .title(format!(
 | 
				
			||||||
@@ -179,40 +147,223 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
 | 
				
			|||||||
                    .footer(|f| f.text(format!("Page {} of {}", next_page + 1, pages)))
 | 
					                    .footer(|f| f.text(format!("Page {} of {}", next_page + 1, pages)))
 | 
				
			||||||
                    .color(*THEME_COLOR);
 | 
					                    .color(*THEME_COLOR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let _ =
 | 
					                let _ = component
 | 
				
			||||||
 | 
					                    .create_interaction_response(&ctx, |r| {
 | 
				
			||||||
 | 
					                        r.kind(InteractionResponseType::UpdateMessage).interaction_response_data(
 | 
				
			||||||
 | 
					                            |response| {
 | 
				
			||||||
 | 
					                                response.embeds(vec![embed]).components(|comp| {
 | 
				
			||||||
 | 
					                                    pager.create_button_row(pages, comp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    comp
 | 
				
			||||||
 | 
					                                })
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .await;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ComponentDataModel::DelPager(pager) => {
 | 
				
			||||||
 | 
					                let reminders =
 | 
				
			||||||
 | 
					                    Reminder::from_guild(ctx, component.guild_id, component.user.id).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let pages = reminders
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .enumerate()
 | 
				
			||||||
 | 
					                    .map(|(count, reminder)| reminder.display_del(count, &pager.timezone))
 | 
				
			||||||
 | 
					                    .fold(0, |t, r| t + r.len())
 | 
				
			||||||
 | 
					                    .div_ceil(EMBED_DESCRIPTION_MAX_LENGTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let next_page = pager.next_page(pages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let mut char_count = 0;
 | 
				
			||||||
 | 
					                let mut skip_char_count = 0;
 | 
				
			||||||
 | 
					                let mut first_num = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let (shown_reminders, display_vec): (Vec<&Reminder>, Vec<String>) = reminders
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .enumerate()
 | 
				
			||||||
 | 
					                    .map(|(count, reminder)| {
 | 
				
			||||||
 | 
					                        (reminder, reminder.display_del(count, &pager.timezone))
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .skip_while(|(_, p)| {
 | 
				
			||||||
 | 
					                        first_num += 1;
 | 
				
			||||||
 | 
					                        skip_char_count += p.len();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        skip_char_count < EMBED_DESCRIPTION_MAX_LENGTH * next_page
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .take_while(|(_, p)| {
 | 
				
			||||||
 | 
					                        char_count += p.len();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        char_count < EMBED_DESCRIPTION_MAX_LENGTH
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .unzip();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let display = display_vec.join("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let del_selector = ComponentDataModel::DelSelector(DelSelector {
 | 
				
			||||||
 | 
					                    page: next_page,
 | 
				
			||||||
 | 
					                    timezone: pager.timezone,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let mut embed = CreateEmbed::default();
 | 
				
			||||||
 | 
					                embed
 | 
				
			||||||
 | 
					                    .title("Delete Reminders")
 | 
				
			||||||
 | 
					                    .description(display)
 | 
				
			||||||
 | 
					                    .footer(|f| f.text(format!("Page {} of {}", next_page + 1, pages)))
 | 
				
			||||||
 | 
					                    .color(*THEME_COLOR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                component
 | 
					                component
 | 
				
			||||||
                    .create_interaction_response(&ctx, |r| {
 | 
					                    .create_interaction_response(&ctx, |r| {
 | 
				
			||||||
                            r.kind(InteractionResponseType::UpdateMessage)
 | 
					                        r.kind(InteractionResponseType::UpdateMessage).interaction_response_data(
 | 
				
			||||||
                                .interaction_response_data(|response| {
 | 
					                            |response| {
 | 
				
			||||||
                                response.embeds(vec![embed]).components(|comp| {
 | 
					                                response.embeds(vec![embed]).components(|comp| {
 | 
				
			||||||
 | 
					                                    pager.create_button_row(pages, comp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                    comp.create_action_row(|row| {
 | 
					                                    comp.create_action_row(|row| {
 | 
				
			||||||
                                            row.create_button(|b| {
 | 
					                                        row.create_select_menu(|menu| {
 | 
				
			||||||
                                                b.label("⏮️")
 | 
					                                            menu.custom_id(del_selector.to_custom_id()).options(
 | 
				
			||||||
                                                    .style(ButtonStyle::Primary)
 | 
					                                                |opt| {
 | 
				
			||||||
                                                    .custom_id(page_first.to_custom_id())
 | 
					                                                    for (count, reminder) in
 | 
				
			||||||
                                                    .disabled(next_page == 0)
 | 
					                                                        shown_reminders.iter().enumerate()
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        opt.create_option(|o| {
 | 
				
			||||||
 | 
					                                                            o.label(count + first_num)
 | 
				
			||||||
 | 
					                                                                .value(reminder.id)
 | 
				
			||||||
 | 
					                                                                .description({
 | 
				
			||||||
 | 
					                                                                    let c =
 | 
				
			||||||
 | 
					                                                                        reminder.display_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                                    if c.len() > 100 {
 | 
				
			||||||
 | 
					                                                                        format!(
 | 
				
			||||||
 | 
					                                                                            "{}...",
 | 
				
			||||||
 | 
					                                                                            reminder
 | 
				
			||||||
 | 
					                                                                                .display_content()
 | 
				
			||||||
 | 
					                                                                                .chars()
 | 
				
			||||||
 | 
					                                                                                .take(97)
 | 
				
			||||||
 | 
					                                                                                .collect::<String>(
 | 
				
			||||||
 | 
					                                                                                )
 | 
				
			||||||
 | 
					                                                                        )
 | 
				
			||||||
 | 
					                                                                    } else {
 | 
				
			||||||
 | 
					                                                                        c.to_string()
 | 
				
			||||||
 | 
					                                                                    }
 | 
				
			||||||
                                                                })
 | 
					                                                                })
 | 
				
			||||||
                                            .create_button(|b| {
 | 
					                                                        });
 | 
				
			||||||
                                                b.label("◀️")
 | 
					                                                    }
 | 
				
			||||||
                                                    .style(ButtonStyle::Secondary)
 | 
					
 | 
				
			||||||
                                                    .custom_id(page_prev.to_custom_id())
 | 
					                                                    opt
 | 
				
			||||||
                                                    .disabled(next_page == 0)
 | 
					                                                },
 | 
				
			||||||
                                            })
 | 
					                                            )
 | 
				
			||||||
                                            .create_button(|b| {
 | 
					 | 
				
			||||||
                                                b.label("▶️")
 | 
					 | 
				
			||||||
                                                    .style(ButtonStyle::Secondary)
 | 
					 | 
				
			||||||
                                                    .custom_id(page_next.to_custom_id())
 | 
					 | 
				
			||||||
                                                    .disabled(next_page + 1 == pages)
 | 
					 | 
				
			||||||
                                            })
 | 
					 | 
				
			||||||
                                            .create_button(|b| {
 | 
					 | 
				
			||||||
                                                b.label("⏭️")
 | 
					 | 
				
			||||||
                                                    .style(ButtonStyle::Primary)
 | 
					 | 
				
			||||||
                                                    .custom_id(page_last.to_custom_id())
 | 
					 | 
				
			||||||
                                                    .disabled(next_page + 1 == pages)
 | 
					 | 
				
			||||||
                                        })
 | 
					                                        })
 | 
				
			||||||
                                    })
 | 
					                                    })
 | 
				
			||||||
                                })
 | 
					                                })
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
 | 
					                    .await;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ComponentDataModel::DelSelector(selector) => {
 | 
				
			||||||
 | 
					                let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
 | 
				
			||||||
 | 
					                let selected_id = component.data.values.join(",");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sqlx::query!("DELETE FROM reminders WHERE FIND_IN_SET(id, ?)", selected_id)
 | 
				
			||||||
 | 
					                    .execute(&pool)
 | 
				
			||||||
 | 
					                    .await
 | 
				
			||||||
 | 
					                    .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let reminders =
 | 
				
			||||||
 | 
					                    Reminder::from_guild(ctx, component.guild_id, component.user.id).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let mut char_count = 0;
 | 
				
			||||||
 | 
					                let mut skip_char_count = 0;
 | 
				
			||||||
 | 
					                let mut first_num = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let (shown_reminders, display_vec): (Vec<&Reminder>, Vec<String>) = reminders
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .enumerate()
 | 
				
			||||||
 | 
					                    .map(|(count, reminder)| {
 | 
				
			||||||
 | 
					                        (reminder, reminder.display_del(count, &selector.timezone))
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .skip_while(|(_, p)| {
 | 
				
			||||||
 | 
					                        first_num += 1;
 | 
				
			||||||
 | 
					                        skip_char_count += p.len();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        skip_char_count < EMBED_DESCRIPTION_MAX_LENGTH * selector.page
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .take_while(|(_, p)| {
 | 
				
			||||||
 | 
					                        char_count += p.len();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        char_count < EMBED_DESCRIPTION_MAX_LENGTH
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .unzip();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let display = display_vec.join("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let pages = reminders
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .enumerate()
 | 
				
			||||||
 | 
					                    .map(|(count, reminder)| reminder.display_del(count, &selector.timezone))
 | 
				
			||||||
 | 
					                    .fold(0, |t, r| t + r.len())
 | 
				
			||||||
 | 
					                    .div_ceil(EMBED_DESCRIPTION_MAX_LENGTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let pager = DelPager::new(selector.timezone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let del_selector = ComponentDataModel::DelSelector(DelSelector {
 | 
				
			||||||
 | 
					                    page: selector.page,
 | 
				
			||||||
 | 
					                    timezone: selector.timezone,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let mut embed = CreateEmbed::default();
 | 
				
			||||||
 | 
					                embed
 | 
				
			||||||
 | 
					                    .title("Delete Reminders")
 | 
				
			||||||
 | 
					                    .description(display)
 | 
				
			||||||
 | 
					                    .footer(|f| f.text(format!("Page {} of {}", selector.page + 1, pages)))
 | 
				
			||||||
 | 
					                    .color(*THEME_COLOR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                component
 | 
				
			||||||
 | 
					                    .create_interaction_response(&ctx, |r| {
 | 
				
			||||||
 | 
					                        r.kind(InteractionResponseType::UpdateMessage).interaction_response_data(
 | 
				
			||||||
 | 
					                            |response| {
 | 
				
			||||||
 | 
					                                response.embeds(vec![embed]).components(|comp| {
 | 
				
			||||||
 | 
					                                    pager.create_button_row(pages, comp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    comp.create_action_row(|row| {
 | 
				
			||||||
 | 
					                                        row.create_select_menu(|menu| {
 | 
				
			||||||
 | 
					                                            menu.custom_id(del_selector.to_custom_id()).options(
 | 
				
			||||||
 | 
					                                                |opt| {
 | 
				
			||||||
 | 
					                                                    for (count, reminder) in
 | 
				
			||||||
 | 
					                                                        shown_reminders.iter().enumerate()
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        opt.create_option(|o| {
 | 
				
			||||||
 | 
					                                                            o.label(count + 1)
 | 
				
			||||||
 | 
					                                                                .value(reminder.id)
 | 
				
			||||||
 | 
					                                                                .description({
 | 
				
			||||||
 | 
					                                                                    let c =
 | 
				
			||||||
 | 
					                                                                        reminder.display_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                                    if c.len() > 100 {
 | 
				
			||||||
 | 
					                                                                        format!(
 | 
				
			||||||
 | 
					                                                                            "{}...",
 | 
				
			||||||
 | 
					                                                                            reminder
 | 
				
			||||||
 | 
					                                                                                .display_content()
 | 
				
			||||||
 | 
					                                                                                .chars()
 | 
				
			||||||
 | 
					                                                                                .take(97)
 | 
				
			||||||
 | 
					                                                                                .collect::<String>(
 | 
				
			||||||
 | 
					                                                                                )
 | 
				
			||||||
 | 
					                                                                        )
 | 
				
			||||||
 | 
					                                                                    } else {
 | 
				
			||||||
 | 
					                                                                        c.to_string()
 | 
				
			||||||
 | 
					                                                                    }
 | 
				
			||||||
 | 
					                                                                })
 | 
				
			||||||
 | 
					                                                        });
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                    opt
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                            )
 | 
				
			||||||
 | 
					                                        })
 | 
				
			||||||
 | 
					                                    })
 | 
				
			||||||
 | 
					                                })
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                    .await;
 | 
					                    .await;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -227,19 +378,8 @@ pub struct Restrict {
 | 
				
			|||||||
    pub guild_id: GuildId,
 | 
					    pub guild_id: GuildId,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize_repr, Deserialize_repr, Debug)]
 | 
					#[derive(Serialize, Deserialize)]
 | 
				
			||||||
#[repr(u8)]
 | 
					pub struct DelSelector {
 | 
				
			||||||
pub enum PageAction {
 | 
					    pub page: usize,
 | 
				
			||||||
    First = 0,
 | 
					 | 
				
			||||||
    Previous = 1,
 | 
					 | 
				
			||||||
    Next = 2,
 | 
					 | 
				
			||||||
    Last = 3,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug)]
 | 
					 | 
				
			||||||
pub struct LookPager {
 | 
					 | 
				
			||||||
    pub flags: LookFlags,
 | 
					 | 
				
			||||||
    pub page: u16,
 | 
					 | 
				
			||||||
    pub action: PageAction,
 | 
					 | 
				
			||||||
    pub timezone: Tz,
 | 
					    pub timezone: Tz,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										183
									
								
								src/component_models/pager.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/component_models/pager.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,183 @@
 | 
				
			|||||||
 | 
					use chrono_tz::Tz;
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					use serde_repr::*;
 | 
				
			||||||
 | 
					use serenity::{builder::CreateComponents, model::interactions::message_component::ButtonStyle};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{component_models::ComponentDataModel, models::reminder::look_flags::LookFlags};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait Pager {
 | 
				
			||||||
 | 
					    fn next_page(&self, max_pages: usize) -> usize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn create_button_row(&self, max_pages: usize, comp: &mut CreateComponents);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize_repr, Deserialize_repr)]
 | 
				
			||||||
 | 
					#[repr(u8)]
 | 
				
			||||||
 | 
					enum PageAction {
 | 
				
			||||||
 | 
					    First = 0,
 | 
				
			||||||
 | 
					    Previous = 1,
 | 
				
			||||||
 | 
					    Next = 2,
 | 
				
			||||||
 | 
					    Last = 3,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct LookPager {
 | 
				
			||||||
 | 
					    pub flags: LookFlags,
 | 
				
			||||||
 | 
					    pub page: usize,
 | 
				
			||||||
 | 
					    action: PageAction,
 | 
				
			||||||
 | 
					    pub timezone: Tz,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Pager for LookPager {
 | 
				
			||||||
 | 
					    fn next_page(&self, max_pages: usize) -> usize {
 | 
				
			||||||
 | 
					        match self.action {
 | 
				
			||||||
 | 
					            PageAction::First => 0,
 | 
				
			||||||
 | 
					            PageAction::Previous => 0.max(self.page - 1),
 | 
				
			||||||
 | 
					            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_next, page_last) =
 | 
				
			||||||
 | 
					            LookPager::buttons(self.flags, next_page, self.timezone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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_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 LookPager {
 | 
				
			||||||
 | 
					    pub fn new(flags: LookFlags, timezone: Tz) -> Self {
 | 
				
			||||||
 | 
					        Self { flags, page: 0, action: PageAction::First, timezone }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn buttons(
 | 
				
			||||||
 | 
					        flags: LookFlags,
 | 
				
			||||||
 | 
					        page: usize,
 | 
				
			||||||
 | 
					        timezone: Tz,
 | 
				
			||||||
 | 
					    ) -> (ComponentDataModel, ComponentDataModel, ComponentDataModel, ComponentDataModel) {
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ComponentDataModel::LookPager(LookPager {
 | 
				
			||||||
 | 
					                flags,
 | 
				
			||||||
 | 
					                page,
 | 
				
			||||||
 | 
					                action: PageAction::First,
 | 
				
			||||||
 | 
					                timezone,
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            ComponentDataModel::LookPager(LookPager {
 | 
				
			||||||
 | 
					                flags,
 | 
				
			||||||
 | 
					                page,
 | 
				
			||||||
 | 
					                action: PageAction::Previous,
 | 
				
			||||||
 | 
					                timezone,
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            ComponentDataModel::LookPager(LookPager {
 | 
				
			||||||
 | 
					                flags,
 | 
				
			||||||
 | 
					                page,
 | 
				
			||||||
 | 
					                action: PageAction::Next,
 | 
				
			||||||
 | 
					                timezone,
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            ComponentDataModel::LookPager(LookPager {
 | 
				
			||||||
 | 
					                flags,
 | 
				
			||||||
 | 
					                page,
 | 
				
			||||||
 | 
					                action: PageAction::Last,
 | 
				
			||||||
 | 
					                timezone,
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct DelPager {
 | 
				
			||||||
 | 
					    pub page: usize,
 | 
				
			||||||
 | 
					    action: PageAction,
 | 
				
			||||||
 | 
					    pub timezone: Tz,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Pager for DelPager {
 | 
				
			||||||
 | 
					    fn next_page(&self, max_pages: usize) -> usize {
 | 
				
			||||||
 | 
					        match self.action {
 | 
				
			||||||
 | 
					            PageAction::First => 0,
 | 
				
			||||||
 | 
					            PageAction::Previous => 0.max(self.page - 1),
 | 
				
			||||||
 | 
					            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_next, page_last) =
 | 
				
			||||||
 | 
					            DelPager::buttons(next_page, self.timezone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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_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 DelPager {
 | 
				
			||||||
 | 
					    pub fn new(timezone: Tz) -> Self {
 | 
				
			||||||
 | 
					        Self { page: 0, action: PageAction::First, timezone }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn buttons(
 | 
				
			||||||
 | 
					        page: usize,
 | 
				
			||||||
 | 
					        timezone: Tz,
 | 
				
			||||||
 | 
					    ) -> (ComponentDataModel, ComponentDataModel, ComponentDataModel, ComponentDataModel) {
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ComponentDataModel::DelPager(DelPager { page, action: PageAction::First, timezone }),
 | 
				
			||||||
 | 
					            ComponentDataModel::DelPager(DelPager { page, action: PageAction::Previous, timezone }),
 | 
				
			||||||
 | 
					            ComponentDataModel::DelPager(DelPager { page, action: PageAction::Next, timezone }),
 | 
				
			||||||
 | 
					            ComponentDataModel::DelPager(DelPager { page, action: PageAction::Last, timezone }),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -16,15 +16,13 @@ use serenity::{
 | 
				
			|||||||
    framework::Framework,
 | 
					    framework::Framework,
 | 
				
			||||||
    futures::prelude::future::BoxFuture,
 | 
					    futures::prelude::future::BoxFuture,
 | 
				
			||||||
    http::Http,
 | 
					    http::Http,
 | 
				
			||||||
    json::Value,
 | 
					 | 
				
			||||||
    model::{
 | 
					    model::{
 | 
				
			||||||
        channel::{Channel, GuildChannel, Message},
 | 
					        channel::{Channel, GuildChannel, Message},
 | 
				
			||||||
        guild::{Guild, Member},
 | 
					        guild::{Guild, Member},
 | 
				
			||||||
        id::{ChannelId, GuildId, MessageId, RoleId, UserId},
 | 
					        id::{ChannelId, GuildId, MessageId, RoleId, UserId},
 | 
				
			||||||
        interactions::{
 | 
					        interactions::{
 | 
				
			||||||
            application_command::{
 | 
					            application_command::{
 | 
				
			||||||
                ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOption,
 | 
					                ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
 | 
				
			||||||
                ApplicationCommandOptionType,
 | 
					 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            InteractionResponseType,
 | 
					            InteractionResponseType,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -772,7 +770,8 @@ impl RegexFramework {
 | 
				
			|||||||
                ApplicationCommand::set_global_application_commands(&http, |c| {
 | 
					                ApplicationCommand::set_global_application_commands(&http, |c| {
 | 
				
			||||||
                    self._populate_commands(c)
 | 
					                    self._populate_commands(c)
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .await;
 | 
					                .await
 | 
				
			||||||
 | 
					                .unwrap();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Some(debug_guild) => {
 | 
					            Some(debug_guild) => {
 | 
				
			||||||
                debug_guild
 | 
					                debug_guild
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -304,9 +304,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
 | 
				
			|||||||
        .add_command("natural", &reminder_cmds::NATURAL_COMMAND)
 | 
					        .add_command("natural", &reminder_cmds::NATURAL_COMMAND)
 | 
				
			||||||
        .add_command("n", &reminder_cmds::NATURAL_COMMAND)
 | 
					        .add_command("n", &reminder_cmds::NATURAL_COMMAND)
 | 
				
			||||||
        .add_command("", &reminder_cmds::NATURAL_COMMAND)
 | 
					        .add_command("", &reminder_cmds::NATURAL_COMMAND)
 | 
				
			||||||
        // management commands
 | 
					 | 
				
			||||||
        .add_command("del", &reminder_cmds::DELETE_COMMAND)
 | 
					 | 
				
			||||||
        */
 | 
					        */
 | 
				
			||||||
 | 
					        // management commands
 | 
				
			||||||
 | 
					        .add_command(&reminder_cmds::DELETE_COMMAND)
 | 
				
			||||||
        .add_command(&reminder_cmds::LOOK_COMMAND)
 | 
					        .add_command(&reminder_cmds::LOOK_COMMAND)
 | 
				
			||||||
        .add_command(&reminder_cmds::PAUSE_COMMAND)
 | 
					        .add_command(&reminder_cmds::PAUSE_COMMAND)
 | 
				
			||||||
        .add_command(&reminder_cmds::OFFSET_COMMAND)
 | 
					        .add_command(&reminder_cmds::OFFSET_COMMAND)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,6 @@ use serde::{Deserialize, Serialize};
 | 
				
			|||||||
use serde_repr::*;
 | 
					use serde_repr::*;
 | 
				
			||||||
use serenity::model::id::ChannelId;
 | 
					use serenity::model::id::ChannelId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::consts::REGEX_CHANNEL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, Debug)]
 | 
					#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, Debug)]
 | 
				
			||||||
#[repr(u8)]
 | 
					#[repr(u8)]
 | 
				
			||||||
pub enum TimeDisplayType {
 | 
					pub enum TimeDisplayType {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,11 +4,6 @@ pub mod errors;
 | 
				
			|||||||
mod helper;
 | 
					mod helper;
 | 
				
			||||||
pub mod look_flags;
 | 
					pub mod look_flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::{
 | 
					 | 
				
			||||||
    convert::{TryFrom, TryInto},
 | 
					 | 
				
			||||||
    env,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use chrono::{NaiveDateTime, TimeZone};
 | 
					use chrono::{NaiveDateTime, TimeZone};
 | 
				
			||||||
use chrono_tz::Tz;
 | 
					use chrono_tz::Tz;
 | 
				
			||||||
use serenity::{
 | 
					use serenity::{
 | 
				
			||||||
@@ -19,14 +14,13 @@ use sqlx::MySqlPool;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    models::reminder::{
 | 
					    models::reminder::{
 | 
				
			||||||
        errors::InteractionError,
 | 
					 | 
				
			||||||
        helper::longhand_displacement,
 | 
					        helper::longhand_displacement,
 | 
				
			||||||
        look_flags::{LookFlags, TimeDisplayType},
 | 
					        look_flags::{LookFlags, TimeDisplayType},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    SQLPool,
 | 
					    SQLPool,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct Reminder {
 | 
					pub struct Reminder {
 | 
				
			||||||
    pub id: u32,
 | 
					    pub id: u32,
 | 
				
			||||||
    pub uid: String,
 | 
					    pub uid: String,
 | 
				
			||||||
@@ -284,6 +278,19 @@ WHERE
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn display_del(&self, count: usize, timezone: &Tz) -> String {
 | 
				
			||||||
 | 
					        format!(
 | 
				
			||||||
 | 
					            "**{}**: '{}' *<#{}>* at **{}**",
 | 
				
			||||||
 | 
					            count + 1,
 | 
				
			||||||
 | 
					            self.display_content(),
 | 
				
			||||||
 | 
					            self.channel,
 | 
				
			||||||
 | 
					            timezone
 | 
				
			||||||
 | 
					                .timestamp(self.utc_time.timestamp(), 0)
 | 
				
			||||||
 | 
					                .format("%Y-%m-%d %H:%M:%S")
 | 
				
			||||||
 | 
					                .to_string()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn display(&self, flags: &LookFlags, timezone: &Tz) -> String {
 | 
					    pub fn display(&self, flags: &LookFlags, timezone: &Tz) -> String {
 | 
				
			||||||
        let time_display = match flags.time_display {
 | 
					        let time_display = match flags.time_display {
 | 
				
			||||||
            TimeDisplayType::Absolute => timezone
 | 
					            TimeDisplayType::Absolute => timezone
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user