mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-18 16:28:55 +00:00
Implement Pagination
This commit is contained in:
parent
ad0f798531
commit
2913d92682
2 changed files with 121 additions and 0 deletions
|
@ -3,11 +3,13 @@ use std::sync::Arc;
|
|||
|
||||
pub mod announcer;
|
||||
pub mod args;
|
||||
pub mod pagination;
|
||||
pub mod reaction_watch;
|
||||
pub mod setup;
|
||||
|
||||
pub use announcer::Announcer;
|
||||
pub use args::Duration;
|
||||
pub use pagination::Pagination;
|
||||
pub use reaction_watch::{ReactionHandler, ReactionWatcher};
|
||||
|
||||
/// The global app data.
|
||||
|
|
119
youmubot-prelude/src/pagination.rs
Normal file
119
youmubot-prelude/src/pagination.rs
Normal file
|
@ -0,0 +1,119 @@
|
|||
use crate::{Context, ReactionHandler, ReactionWatcher};
|
||||
use serenity::{
|
||||
builder::EditMessage,
|
||||
framework::standard::{CommandError, CommandResult},
|
||||
model::{
|
||||
channel::{Message, Reaction, ReactionType},
|
||||
id::ChannelId,
|
||||
},
|
||||
};
|
||||
|
||||
impl ReactionWatcher {
|
||||
/// Start a pagination.
|
||||
///
|
||||
/// Takes a copy of Context (which you can `clone`), a pager (see "Pagination") and a target channel id.
|
||||
/// Pagination will handle all events on adding/removing an "arrow" emoji (⬅️ and ➡️).
|
||||
/// This is a blocking call - it will block the thread until duration is over.
|
||||
pub fn paginate<T: Pagination>(
|
||||
&self,
|
||||
ctx: Context,
|
||||
channel: ChannelId,
|
||||
pager: T,
|
||||
duration: std::time::Duration,
|
||||
) -> CommandResult {
|
||||
let handler = PaginationHandler::new(pager, ctx, channel)?;
|
||||
self.handle_reactions(handler, duration)
|
||||
}
|
||||
}
|
||||
|
||||
/// Pagination allows the bot to display content in multiple pages.
|
||||
///
|
||||
/// You need to implement the "render_page" function, which takes a dummy content and
|
||||
/// embed assigning function.
|
||||
/// Pagination is automatically implemented for functions with the same signature as `render_page`.
|
||||
///
|
||||
/// Pages start at 0.
|
||||
pub trait Pagination {
|
||||
/// Render a page.
|
||||
///
|
||||
/// This would either create or edit a message, but you should not be worry about it.
|
||||
fn render_page<'a>(
|
||||
&self,
|
||||
page: u8,
|
||||
target: &'a mut EditMessage,
|
||||
) -> (&'a mut EditMessage, CommandResult);
|
||||
}
|
||||
|
||||
impl<T> Pagination for T
|
||||
where
|
||||
T: for<'a> Fn(u8, &'a mut EditMessage) -> (&'a mut EditMessage, CommandResult),
|
||||
{
|
||||
fn render_page<'a>(
|
||||
&self,
|
||||
page: u8,
|
||||
target: &'a mut EditMessage,
|
||||
) -> (&'a mut EditMessage, CommandResult) {
|
||||
self(page, target)
|
||||
}
|
||||
}
|
||||
|
||||
struct PaginationHandler<T: Pagination> {
|
||||
pager: T,
|
||||
message: Message,
|
||||
page: u8,
|
||||
ctx: Context,
|
||||
}
|
||||
|
||||
impl<T: Pagination> PaginationHandler<T> {
|
||||
pub fn new(pager: T, mut ctx: Context, channel: ChannelId) -> Result<Self, CommandError> {
|
||||
let message = channel.send_message(&mut ctx, |e| {
|
||||
e.content("Youmu is loading the first page...")
|
||||
})?;
|
||||
// React to the message
|
||||
message.react(&mut ctx, "⬅️")?;
|
||||
message.react(&mut ctx, "➡️️")?;
|
||||
let mut p = Self {
|
||||
pager,
|
||||
message: message.clone(),
|
||||
page: 0,
|
||||
ctx,
|
||||
};
|
||||
p.call_pager()?;
|
||||
Ok(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pagination> PaginationHandler<T> {
|
||||
/// Call the pager, log the error (if any).
|
||||
fn call_pager(&mut self) -> CommandResult {
|
||||
let mut res: CommandResult = Ok(());
|
||||
let mut msg = self.message.clone();
|
||||
msg.edit(&self.ctx, |e| {
|
||||
let (e, r) = self.pager.render_page(self.page, e);
|
||||
res = r;
|
||||
e
|
||||
})?;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pagination> ReactionHandler for PaginationHandler<T> {
|
||||
fn handle_reaction(&mut self, reaction: &Reaction, _is_add: bool) -> CommandResult {
|
||||
match &reaction.emoji {
|
||||
ReactionType::Unicode(ref s) => match s.as_str() {
|
||||
"⬅" if self.page == 0 => return Ok(()),
|
||||
"⬅" => {
|
||||
self.page -= 1;
|
||||
self.call_pager()?;
|
||||
}
|
||||
"➡" => {
|
||||
self.page += 1;
|
||||
self.call_pager()?;
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue