1+ use crate :: abstraction:: components_v2:: { self , Status } ;
12use crate :: built_info;
23use lazy_static:: lazy_static;
3- use poise:: CreateReply ;
4- use poise:: serenity_prelude:: CreateActionRow ;
54use reqwest:: header:: HeaderMap ;
6- use serenity:: all:: RoleId ;
7- use serenity :: builder :: {
8- CreateButton , CreateEmbed , CreateInteractionResponse , CreateInteractionResponseMessage ,
5+ use serenity:: all:: {
6+ ButtonStyle , ComponentInteractionCollector , CreateButton , CreateComponent ,
7+ CreateInteractionResponse , CreateInteractionResponseMessage , MessageFlags , RoleId ,
98} ;
109use std:: env;
1110use std:: sync:: Arc ;
@@ -28,7 +27,7 @@ impl Default for CommandData {
2827 "Authorization" ,
2928 format ! (
3029 "Bearer {}" ,
31- std :: env:: var( "PLAYMATCH_API_AUTH" ) . expect( "missing PLAYMATCH_API_AUTH" )
30+ env:: var( "PLAYMATCH_API_AUTH" ) . expect( "missing PLAYMATCH_API_AUTH" )
3231 )
3332 . parse ( )
3433 . expect ( "Invalid Authorization header" ) ,
@@ -72,7 +71,6 @@ pub async fn is_user_trusted_or_above(ctx: CommandContext<'_>) -> CheckResult {
7271 let user = ctx. author ( ) ;
7372 let member = ctx. author_member ( ) . await ;
7473
75- // Check if user is owner
7674 if ctx. framework ( ) . options ( ) . owners . contains ( & user. id ) {
7775 return Ok ( true ) ;
7876 }
@@ -83,75 +81,86 @@ pub async fn is_user_trusted_or_above(ctx: CommandContext<'_>) -> CheckResult {
8381
8482 let member = member. unwrap ( ) ;
8583
86- // Check if user has the Staff or Trusted role
8784 if member. roles . iter ( ) . any ( |role_id| {
8885 role_id == & RoleId :: new ( * STAFF_ROLE_ID ) || TRUSTED_ROLE_IDS . contains ( & role_id. get ( ) )
8986 } ) {
9087 return Ok ( true ) ;
9188 }
9289
93- ctx. say ( "You do not have permission to use this command." )
94- . await ?;
90+ ctx. send ( components_v2:: status_reply (
91+ Status :: Error ,
92+ "You do not have permission to use this command." ,
93+ ) )
94+ . await ?;
9595
9696 Ok ( false )
9797}
9898
99- pub async fn paginate < U , E > (
99+ pub async fn paginate < U : Send + Sync + ' static , E > (
100100 ctx : poise:: Context < ' _ , U , E > ,
101101 pages : & [ & str ] ,
102102) -> Result < ( ) , serenity:: Error > {
103- // Define some unique identifiers for the navigation buttons
104103 let ctx_id = ctx. id ( ) ;
105104 let author_id = ctx. author ( ) . id ;
106- let prev_button_id = format ! ( "{}prev" , ctx_id) ;
107- let next_button_id = format ! ( "{}next" , ctx_id) ;
108-
109- // Send the embed with the first page as content
110- let reply = {
111- let components = CreateActionRow :: Buttons ( vec ! [
112- CreateButton :: new( & prev_button_id) . emoji( '◀' ) ,
113- CreateButton :: new( & next_button_id) . emoji( '▶' ) ,
114- ] ) ;
115-
116- CreateReply :: default ( )
117- . embed ( CreateEmbed :: default ( ) . description ( pages[ 0 ] ) )
118- . components ( vec ! [ components] )
105+ let prev_button_id = format ! ( "{ctx_id}prev" ) ;
106+ let next_button_id = format ! ( "{ctx_id}next" ) ;
107+ let ctx_id_str = ctx_id. to_string ( ) ;
108+ let total = pages. len ( ) . max ( 1 ) ;
109+
110+ let build_buttons = |prev_id : & str , next_id : & str | -> Vec < CreateButton < ' static > > {
111+ vec ! [
112+ CreateButton :: new( prev_id. to_owned( ) )
113+ . emoji( '◀' )
114+ . style( ButtonStyle :: Secondary ) ,
115+ CreateButton :: new( next_id. to_owned( ) )
116+ . emoji( '▶' )
117+ . style( ButtonStyle :: Secondary ) ,
118+ ]
119119 } ;
120120
121- ctx. send ( reply) . await ?;
122-
123- // Loop through incoming interactions with the navigation buttons
124- let mut current_page = 0 ;
125- while let Some ( press) = serenity:: collector:: ComponentInteractionCollector :: new ( ctx)
126- // We defined our button IDs to start with `ctx_id`. If they don't, some other command's
127- // button was pressed
128- . filter ( move |press| {
129- press. data . custom_id . starts_with ( & ctx_id. to_string ( ) ) && press. user . id == author_id
130- } )
131- // Timeout when no navigation button has been pressed for 24 hours
132- . timeout ( Duration :: from_secs ( 3600 * 24 ) )
133- . await
134- {
135- // Depending on which button was pressed, go to next or previous page
121+ let container = components_v2:: paginate_container (
122+ pages[ 0 ] . to_owned ( ) ,
123+ 0 ,
124+ total,
125+ build_buttons ( & prev_button_id, & next_button_id) ,
126+ ) ;
127+ ctx. send ( components_v2:: reply_from_container ( container) )
128+ . await ?;
129+
130+ let mut current_page = 0usize ;
131+ loop {
132+ let prefix = ctx_id_str. clone ( ) ;
133+ let Some ( press) = ComponentInteractionCollector :: new ( ctx. serenity_context ( ) )
134+ . timeout ( Duration :: from_secs ( 3600 * 24 ) )
135+ . author_id ( author_id)
136+ . filter ( move |press| press. data . custom_id . starts_with ( & prefix) )
137+ . await
138+ else {
139+ break ;
140+ } ;
141+
136142 if press. data . custom_id == next_button_id {
137- current_page += 1 ;
138- if current_page >= pages. len ( ) {
139- current_page = 0 ;
140- }
143+ current_page = ( current_page + 1 ) % total;
141144 } else if press. data . custom_id == prev_button_id {
142- current_page = current_page. checked_sub ( 1 ) . unwrap_or ( pages . len ( ) - 1 ) ;
145+ current_page = current_page. checked_sub ( 1 ) . unwrap_or ( total - 1 ) ;
143146 } else {
144- // This is an unrelated button interaction
145147 continue ;
146148 }
147149
148- // Update the message with the new page contents
150+ let container = components_v2:: paginate_container (
151+ pages[ current_page] . to_owned ( ) ,
152+ current_page,
153+ total,
154+ build_buttons ( & prev_button_id, & next_button_id) ,
155+ ) ;
156+
149157 press
150158 . create_response (
151- ctx. serenity_context ( ) ,
159+ ctx. serenity_context ( ) . http . as_ref ( ) ,
152160 CreateInteractionResponse :: UpdateMessage (
153161 CreateInteractionResponseMessage :: new ( )
154- . embed ( CreateEmbed :: new ( ) . description ( pages[ current_page] ) ) ,
162+ . flags ( MessageFlags :: IS_COMPONENTS_V2 )
163+ . components ( vec ! [ CreateComponent :: Container ( container) ] ) ,
155164 ) ,
156165 )
157166 . await ?;
0 commit comments