Revert "turned pager into a single type"

This reverts commit 4490f19c
This commit is contained in:
jellywx 2021-10-26 20:11:19 +01:00
parent 6cf660c7ee
commit 9b54fba5e5
4 changed files with 300 additions and 124 deletions

View File

@ -8,16 +8,12 @@ use chrono::NaiveDateTime;
use chrono_tz::Tz; use chrono_tz::Tz;
use num_integer::Integer; use num_integer::Integer;
use regex_command_attr::command; use regex_command_attr::command;
use serenity::{ use serenity::{builder::CreateEmbed, client::Context, model::channel::Channel};
builder::CreateEmbed,
client::Context,
model::{channel::Channel, id::UserId},
};
use crate::{ use crate::{
check_subscription_on_message, check_subscription_on_message,
component_models::{ component_models::{
pager::{DelData, LookData, Pager}, pager::{DelPager, LookPager, Pager},
ComponentDataModel, DelSelector, ComponentDataModel, DelSelector,
}, },
consts::{ consts::{
@ -333,7 +329,7 @@ async fn look(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
.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 pager = Pager::new(0, LookData { flags, timezone }); let pager = LookPager::new(flags, timezone);
invoke invoke
.respond( .respond(
@ -367,7 +363,7 @@ async fn delete(ctx: &Context, invoke: &mut CommandInvoke, _args: CommandOptions
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 resp = show_delete_page(&reminders, 0, timezone, invoke.author_id()); let resp = show_delete_page(&reminders, 0, timezone);
let _ = invoke.respond(&ctx, resp).await; let _ = invoke.respond(&ctx, resp).await;
} }
@ -398,9 +394,8 @@ pub fn show_delete_page(
reminders: &[Reminder], reminders: &[Reminder],
page: usize, page: usize,
timezone: Tz, timezone: Tz,
author_id: UserId,
) -> CreateGenericResponse { ) -> CreateGenericResponse {
let pager = Pager::new(page, DelData { author_id, timezone }); let pager = DelPager::new(page, timezone);
if reminders.is_empty() { if reminders.is_empty() {
return CreateGenericResponse::new() return CreateGenericResponse::new()
@ -455,7 +450,7 @@ pub fn show_delete_page(
let display = display_vec.join("\n"); let display = display_vec.join("\n");
let del_selector = ComponentDataModel::DelSelector(DelSelector { page, timezone, author_id }); let del_selector = ComponentDataModel::DelSelector(DelSelector { page, timezone });
CreateGenericResponse::new() CreateGenericResponse::new()
.embed(|e| { .embed(|e| {

View File

@ -3,7 +3,7 @@ use serenity::client::Context;
use crate::{ use crate::{
component_models::{ component_models::{
pager::{Pager, TodoData}, pager::{Pager, TodoPager},
ComponentDataModel, TodoSelector, ComponentDataModel, TodoSelector,
}, },
consts::{EMBED_DESCRIPTION_MAX_LENGTH, SELECT_MAX_ENTRIES, THEME_COLOR}, consts::{EMBED_DESCRIPTION_MAX_LENGTH, SELECT_MAX_ENTRIES, THEME_COLOR},
@ -136,7 +136,7 @@ pub fn show_todo_page(
channel_id: Option<u64>, channel_id: Option<u64>,
guild_id: Option<u64>, guild_id: Option<u64>,
) -> CreateGenericResponse { ) -> CreateGenericResponse {
let pager = Pager::new(page, TodoData { user_id, channel_id, guild_id }); let pager = TodoPager::new(page, user_id, channel_id, guild_id);
let pages = max_todo_page(todo_values); let pages = max_todo_page(todo_values);
let mut page = page; let mut page = page;

View File

@ -1,4 +1,4 @@
pub mod pager; pub(crate) mod pager;
use std::io::Cursor; use std::io::Cursor;
@ -21,7 +21,7 @@ use crate::{
reminder_cmds::{max_delete_page, show_delete_page}, reminder_cmds::{max_delete_page, show_delete_page},
todo_cmds::{max_todo_page, show_todo_page}, todo_cmds::{max_todo_page, show_todo_page},
}, },
component_models::pager::{DelData, LookData, Pager, TodoData}, component_models::pager::{DelPager, LookPager, Pager, TodoPager},
consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR}, consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
framework::CommandInvoke, framework::CommandInvoke,
models::reminder::Reminder, models::reminder::Reminder,
@ -29,15 +29,15 @@ use crate::{
}; };
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
#[serde(untagged)] #[serde(tag = "type")]
#[repr(u8)]
pub enum ComponentDataModel { pub enum ComponentDataModel {
Restrict(Restrict), Restrict(Restrict),
LookPager(LookPager),
DelPager(DelPager),
TodoPager(TodoPager),
DelSelector(DelSelector), DelSelector(DelSelector),
TodoSelector(TodoSelector), TodoSelector(TodoSelector),
LookPager(Pager<LookData>),
DelPager(Pager<DelData>),
TodoPager(Pager<TodoData>),
MacroPager(Pager<GuildId>),
} }
impl ComponentDataModel { impl ComponentDataModel {
@ -90,20 +90,11 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
.await .await
.unwrap(); .unwrap();
} else { } else {
component // tell them they cant do this
.create_interaction_response(&ctx, |r| {
r.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|response| response
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
.content("Only the original command user can interact with this message")
)
})
.await
.unwrap();
} }
} }
ComponentDataModel::LookPager(pager) => { ComponentDataModel::LookPager(pager) => {
let flags = pager.data.flags; let flags = pager.flags;
let channel_opt = component.channel_id.to_channel_cached(&ctx); let channel_opt = component.channel_id.to_channel_cached(&ctx);
@ -121,7 +112,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
let pages = reminders let pages = reminders
.iter() .iter()
.map(|reminder| reminder.display(&flags, &pager.data.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); .div_ceil(EMBED_DESCRIPTION_MAX_LENGTH);
@ -139,7 +130,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
let display = reminders let display = reminders
.iter() .iter()
.map(|reminder| reminder.display(&flags, &pager.data.timezone)) .map(|reminder| reminder.display(&flags, &pager.timezone))
.skip_while(|p| { .skip_while(|p| {
skip_char_count += p.len(); skip_char_count += p.len();
@ -178,33 +169,15 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
.await; .await;
} }
ComponentDataModel::DelPager(pager) => { ComponentDataModel::DelPager(pager) => {
if component.user.id == pager.data.author_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 max_pages = max_delete_page(&reminders, &pager.data.timezone); let max_pages = max_delete_page(&reminders, &pager.timezone);
let resp = show_delete_page( let resp = show_delete_page(&reminders, pager.next_page(max_pages), pager.timezone);
&reminders,
pager.next_page(max_pages),
pager.data.timezone,
pager.data.author_id,
);
let mut invoke = CommandInvoke::component(component); let mut invoke = CommandInvoke::component(component);
let _ = invoke.respond(&ctx, resp).await; let _ = invoke.respond(&ctx, resp).await;
} else {
component
.create_interaction_response(&ctx, |r| {
r.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|response| response
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
.content("Only the original command user can interact with this message")
)
})
.await
.unwrap();
}
} }
ComponentDataModel::DelSelector(selector) => { ComponentDataModel::DelSelector(selector) => {
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap(); let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
@ -218,12 +191,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( let resp = show_delete_page(&reminders, selector.page, selector.timezone);
&reminders,
selector.page,
selector.timezone,
selector.author_id,
);
let mut invoke = CommandInvoke::component(component); let mut invoke = CommandInvoke::component(component);
let _ = invoke.respond(&ctx, resp).await; let _ = invoke.respond(&ctx, resp).await;
@ -234,9 +202,9 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
let values = sqlx::query!( let values = sqlx::query!(
// fucking braindead mysql use <=> instead of = for null comparison // fucking braindead mysql use <=> instead of = for null comparison
"SELECT id, value FROM todos WHERE user_id <=> ? AND channel_id <=> ? AND guild_id <=> ?", "SELECT id, value FROM todos WHERE user_id <=> ? AND channel_id <=> ? AND guild_id <=> ?",
pager.data.user_id, pager.user_id,
pager.data.channel_id, pager.channel_id,
pager.data.guild_id, pager.guild_id,
) )
.fetch_all(&pool) .fetch_all(&pool)
.await .await
@ -250,9 +218,9 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
let resp = show_todo_page( let resp = show_todo_page(
&values, &values,
pager.next_page(max_pages), pager.next_page(max_pages),
pager.data.user_id, pager.user_id,
pager.data.channel_id, pager.channel_id,
pager.data.guild_id, pager.guild_id,
); );
let mut invoke = CommandInvoke::component(component); let mut invoke = CommandInvoke::component(component);
@ -292,7 +260,6 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
let mut invoke = CommandInvoke::component(component); let mut invoke = CommandInvoke::component(component);
let _ = invoke.respond(&ctx, resp).await; let _ = invoke.respond(&ctx, resp).await;
} }
ComponentDataModel::MacroPager(pager) => {}
} }
} }
} }
@ -308,7 +275,6 @@ pub struct Restrict {
pub struct DelSelector { pub struct DelSelector {
pub page: usize, pub page: usize,
pub timezone: Tz, pub timezone: Tz,
pub author_id: UserId,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]

View File

@ -1,30 +1,37 @@
// todo split pager out into a single struct
use chrono_tz::Tz; use chrono_tz::Tz;
use rmp_serde::Serializer;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::*; use serde_repr::*;
use serenity::{ use serenity::{builder::CreateComponents, model::interactions::message_component::ButtonStyle};
builder::CreateComponents,
model::{id::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};
#[derive(Serialize, Deserialize)] pub trait Pager {
pub struct Pager<D> { fn next_page(&self, max_pages: usize) -> usize;
pub page: usize,
action: PageAction, fn create_button_row(&self, max_pages: usize, comp: &mut CreateComponents);
pub data: D,
} }
impl<D> Pager<D> #[derive(Serialize_repr, Deserialize_repr)]
where #[repr(u8)]
D: Serialize + Clone, enum PageAction {
{ First = 0,
pub fn new(page: usize, data: D) -> Self { Previous = 1,
Self { page, action: PageAction::Refresh, data } Refresh = 2,
} Next = 3,
Last = 4,
}
pub fn next_page(&self, max_pages: usize) -> usize { #[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 { match self.action {
PageAction::First => 0, PageAction::First => 0,
PageAction::Previous => 0.max(self.page - 1), PageAction::Previous => 0.max(self.page - 1),
@ -34,26 +41,11 @@ where
} }
} }
pub fn to_custom_id(&self) -> String { fn create_button_row(&self, max_pages: usize, comp: &mut CreateComponents) {
let mut buf = Vec::new();
self.serialize(&mut Serializer::new(&mut buf)).unwrap();
base64::encode(buf)
}
fn buttons(&self, page: usize) -> (Pager<D>, Pager<D>, Pager<D>, Pager<D>, Pager<D>) {
(
Pager { page, action: PageAction::First, data: self.data.clone() },
Pager { page, action: PageAction::Previous, data: self.data.clone() },
Pager { page, action: PageAction::Refresh, data: self.data.clone() },
Pager { page, action: PageAction::Next, data: self.data.clone() },
Pager { page, action: PageAction::Last, data: self.data.clone() },
)
}
pub fn create_button_row(&self, max_pages: usize, comp: &mut CreateComponents) {
let next_page = self.next_page(max_pages); let next_page = self.next_page(max_pages);
let (page_first, page_prev, page_refresh, page_next, page_last) = self.buttons(next_page); let (page_first, page_prev, page_refresh, page_next, page_last) =
LookPager::buttons(self.flags, next_page, self.timezone);
comp.create_action_row(|row| { comp.create_action_row(|row| {
row.create_button(|b| { row.create_button(|b| {
@ -87,31 +79,254 @@ where
} }
} }
#[derive(Serialize_repr, Deserialize_repr)] impl LookPager {
#[repr(u8)] pub fn new(flags: LookFlags, timezone: Tz) -> Self {
enum PageAction { Self { flags, page: 0, action: PageAction::First, timezone }
First = 0, }
Previous = 1,
Refresh = 2, pub fn buttons(
Next = 3, flags: LookFlags,
Last = 4, page: usize,
timezone: Tz,
) -> (
ComponentDataModel,
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::Refresh,
timezone,
}),
ComponentDataModel::LookPager(LookPager {
flags,
page,
action: PageAction::Next,
timezone,
}),
ComponentDataModel::LookPager(LookPager {
flags,
page,
action: PageAction::Last,
timezone,
}),
)
}
} }
#[derive(Deserialize, Serialize, Clone)] #[derive(Serialize, Deserialize)]
pub struct LookData { pub struct DelPager {
pub flags: LookFlags, pub page: usize,
action: PageAction,
pub timezone: Tz, pub timezone: Tz,
} }
#[derive(Deserialize, Serialize, Clone)] impl Pager for DelPager {
pub struct DelData { fn next_page(&self, max_pages: usize) -> usize {
pub author_id: UserId, match self.action {
pub timezone: Tz, 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) =
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_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)
})
});
}
} }
#[derive(Deserialize, Serialize, Clone)] impl DelPager {
pub struct TodoData { pub fn new(page: usize, timezone: Tz) -> Self {
Self { page, action: PageAction::Refresh, timezone }
}
pub fn buttons(
page: usize,
timezone: Tz,
) -> (
ComponentDataModel,
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::Refresh, timezone }),
ComponentDataModel::DelPager(DelPager { page, action: PageAction::Next, timezone }),
ComponentDataModel::DelPager(DelPager { page, action: PageAction::Last, timezone }),
)
}
}
#[derive(Deserialize, Serialize)]
pub struct TodoPager {
pub page: usize,
action: PageAction,
pub user_id: Option<u64>, pub user_id: Option<u64>,
pub channel_id: Option<u64>, pub channel_id: Option<u64>,
pub guild_id: Option<u64>, pub guild_id: Option<u64>,
} }
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<u64>,
channel_id: Option<u64>,
guild_id: Option<u64>,
) -> Self {
Self { page, action: PageAction::Refresh, user_id, channel_id, guild_id }
}
pub fn buttons(
page: usize,
user_id: Option<u64>,
channel_id: Option<u64>,
guild_id: Option<u64>,
) -> (
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,
}),
)
}
}