3535import net .dv8tion .jda .api .Permission ;
3636import net .dv8tion .jda .api .entities .Emoji ;
3737import net .dv8tion .jda .api .entities .Guild ;
38+ import net .dv8tion .jda .api .entities .MessageEmbed ;
3839import net .dv8tion .jda .api .entities .Role ;
39- import net .dv8tion .jda .api .interactions .Interaction ;
4040import net .dv8tion .jda .api .interactions .commands .OptionMapping ;
4141import net .dv8tion .jda .api .interactions .commands .OptionType ;
4242import net .dv8tion .jda .api .interactions .commands .build .OptionData ;
4848import net .dv8tion .jda .api .interactions .components .text .TextInput ;
4949import net .dv8tion .jda .api .interactions .components .text .TextInputStyle ;
5050
51- import javax .annotation .Nullable ;
5251import java .awt .Color ;
5352import java .util .ArrayList ;
5453import java .util .Collection ;
5554import java .util .List ;
5655import java .util .Objects ;
5756import java .util .UUID ;
57+ import java .util .stream .Collectors ;
5858
5959public class RoleSelectCommand extends SlashCommand {
6060
@@ -67,8 +67,6 @@ public class RoleSelectCommand extends SlashCommand {
6767 .onModalInteraction (COMMAND ::onModalInteraction )
6868 .build ();
6969
70- private static final Color COLOUR = new Color (24 , 221 , 136 , 255 );
71-
7270 private RoleSelectCommand () {
7371 this .name = "role-select" ;
7472 this .guildOnly = true ;
@@ -80,99 +78,97 @@ private RoleSelectCommand() {
8078 Permission .MANAGE_ROLES
8179 };
8280 options = List .of (
81+ new OptionData (OptionType .STRING , "roles" , "Mention the roles to add to the panel." , true ),
8382 new OptionData (OptionType .BOOLEAN , "dropdown" , "If the role selection panel should be a dropdown rather than buttons." )
8483 );
8584 }
8685
8786 @ Override
8887 protected void execute (final SlashCommandEvent event ) {
88+ final var selfMember = Objects .requireNonNull (event .getGuild ()).getSelfMember ();
89+ Objects .requireNonNull (event .getMember ());
90+ final var args = event .getOption ("roles" , List .<String >of (), m -> m .getMentionedRoles ()
91+ .stream ()
92+ .filter (r -> !r .isManaged () && selfMember .canInteract (r ) && event .getMember ().canInteract (r ))
93+ .map (Role ::getId )
94+ .collect (Collectors .toList ()));
95+
96+ if (args .isEmpty ()) {
97+ event
98+ .deferReply (true )
99+ .setContent ("Please provide at least one role for the panel." )
100+ .queue ();
101+ return ;
102+ } else if (args .size () > 25 ) {
103+ event
104+ .deferReply (true )
105+ .setContent ("Please provide less than 25 roles for the panel." )
106+ .queue ();
107+ }
108+ args .add (0 , String .valueOf (event .getOption ("dropdown" , false , OptionMapping ::getAsBoolean )));
109+
89110 final var title = TextInput .create ("title" , "Title" , TextInputStyle .SHORT )
90111 .setRequired (false )
112+ .setMaxLength (MessageEmbed .TITLE_MAX_LENGTH )
91113 .setPlaceholder ("The title of the role panel to create." )
92114 .build ();
93115
94116 final var description = TextInput .create ("description" , "Description" , TextInputStyle .PARAGRAPH )
95117 .setRequired (false )
118+ .setMaxLength (Math .min (MessageEmbed .DESCRIPTION_MAX_LENGTH , TextInput .TEXT_INPUT_MAX_LENGTH ))
96119 .setPlaceholder ("The description role panel to create." )
97120 .build ();
98121
99- // TODO implement mappings for role icons and add colour option
122+ final var colour = TextInput .create ("colour" , "Colour" , TextInputStyle .SHORT )
123+ .setRequired (false )
124+ .setPlaceholder ("The colour the embed will have. Example: #ffffff" )
125+ .build ();
100126
101- final var modal = COMPONENT_LISTENER .createModal ("Role selection panel creation" , Component .Lifespan .TEMPORARY ,
102- String .valueOf (event .getOption ("dropdown" , false , OptionMapping ::getAsBoolean )))
127+ final var modal = COMPONENT_LISTENER .createModal ("Role selection panel creation" , Component .Lifespan .TEMPORARY , args )
103128 .addActionRows (
104129 ActionRow .of (title ),
105- ActionRow .of (description )
130+ ActionRow .of (description ),
131+ ActionRow .of (colour )
106132 )
107133 .build ();
108134
109135 event .replyModal (modal ).queue ();
110136 }
111137
112- private static void addMenuOptions (@ NonNull final Interaction interaction ,
113- @ NonNull final SelectMenu .Builder menu ,
114- @ NonNull final String placeHolder ,
115- @ Nullable final Integer minValues ) {
116-
117- final var guild = Objects .requireNonNull (interaction .getGuild ());
118- final var highestBotRole = guild .getSelfMember ().getRoles ().get (0 );
119- final var guildRoles = guild .getRoles ();
120-
121- final var roles = guildRoles .subList (guildRoles .indexOf (highestBotRole ) + 1 , guildRoles .size ());
122-
123- if (minValues != null ) {
124- menu .setMinValues (minValues );
125- }
126-
127- menu .setPlaceholder (placeHolder )
128- .setMaxValues (roles .size ())
129- .addOptions (roles .stream ()
130- .filter (role -> !role .isPublicRole ())
131- .filter (role -> !role .getTags ().isBot ())
132- .map (RoleSelectCommand ::roleToSelection )
133- .toList ());
134- }
135-
136- @ NonNull
137- private static SelectOption roleToSelection (@ NonNull final Role role ) {
138- final var roleIcon = role .getIcon ();
139-
140- if (roleIcon == null || !roleIcon .isEmoji () || !roleIcon .isEmoji ()) {
141- return SelectOption .of (role .getName (), role .getId ());
142- } else {
143- return SelectOption .of (role .getName (), role .getId ())
144- .withEmoji (Emoji .fromUnicode (Objects .requireNonNull (roleIcon .getEmoji ())));
145- }
146- }
147-
148138 public void onModalInteraction (final ModalInteractionContext context ) {
149139 final var event = context .getEvent ();
150140 if (!event .isFromGuild ()) return ;
151- final var menu = COMPONENT_LISTENER .createMenu (new String []{MenuType .IN_CREATION .toString ()},
152- Component .Lifespan .TEMPORARY ,
153- // Parse the isDropdown
154- context .getArguments ().get (0 ));
155-
156- addMenuOptions (event , menu , "Select the roles to display" , 1 );
141+ Objects .requireNonNull (context .getGuild ());
157142
158143 final var titleOption = event .getValue ("title" );
159144 final var descriptionOption = event .getValue ("description" );
145+ final var colourOption = event .getValue ("colour" );
160146
161147 final var title = titleOption == null ? null : titleOption .getAsString ();
162148 final var description = descriptionOption == null ? null : descriptionOption .getAsString ();
149+ final var colour = colourOption == null ? null : Color .decode (colourOption .getAsString ());
163150
164- event .reply (new MessageBuilder ()
165- .setEmbeds (
166- new EmbedBuilder ()
167- .setTitle (title )
168- .setColor (COLOUR )
169- .setDescription (description )
170- .build ()
171- )
172- .setActionRows (ActionRow .of (menu .build ()))
173- .build ())
174- .setEphemeral (true )
175- .queue ();
151+ final var isDropdown = Boolean .parseBoolean (context .getArguments ().get (0 ));
152+ final var roles = context .getArguments ().subList (1 , context .getArguments ().size ())
153+ .stream ()
154+ .map (context .getGuild ()::getRoleById )
155+ .toList ();
156+
157+ final var message = new MessageBuilder ()
158+ .setEmbeds (
159+ new EmbedBuilder ()
160+ .setTitle (title )
161+ .setColor (colour )
162+ .setDescription (description )
163+ .build ()
164+ )
165+ .setActionRows ();
166+
167+ if (isDropdown ) {
168+ handleDropdownCreation (context , message , roles );
169+ } else {
170+ handleButtonOption (context , message , roles );
171+ }
176172 }
177173
178174 protected void onSelectMenu (final SelectMenuInteractionContext context ) {
@@ -187,21 +183,10 @@ protected void onSelectMenu(final SelectMenuInteractionContext context) {
187183 .filter (selfMember ::canInteract )
188184 .toList ();
189185
190- final boolean isDropdown = Boolean .parseBoolean (context .getArguments ().get (0 ));
191-
192- switch (MenuType .valueOf (context .getItemComponentArguments ().get (0 ))) {
193- case IN_CREATION -> {
194- if (isDropdown ) {
195- handleDropdownCreation (context , selectedRoles );
196- } else {
197- handleButtonOption (context , selectedRoles );
198- }
199- }
200- case ROLE_PANEL -> handleRoleSelection (context , selectedRoles , guild );
201- }
186+ handleRoleSelection (context , selectedRoles , guild );
202187 }
203188
204- private static void handleButtonOption (final @ NonNull SelectMenuInteractionContext context , final List <Role > selectedRoles ) {
189+ private static void handleButtonOption (final @ NonNull ModalInteractionContext context , final MessageBuilder builder , final List <Role > selectedRoles ) {
205190 final UUID id = UUID .randomUUID ();
206191 final var idString = id .toString ();
207192 final List <ActionRow > rows = new ArrayList <>();
@@ -222,47 +207,39 @@ private static void handleButtonOption(final @NonNull SelectMenuInteractionConte
222207 .toList ()
223208 ));
224209 }
225- /* TODO what's the actual limit?
226- if (rows.size() > 5) {
227- context.getEvent().deferReply(true).setContent("Too many roles selected!");
228- return;
229- }
230- */
231210
232211 final var component = new Component (COMPONENT_LISTENER .getName (), id , List .of (), Component .Lifespan .PERMANENT );
233212 COMPONENT_LISTENER .insertComponent (component );
234213
235- context .getEvent ().getChannel ()
236- .sendMessageEmbeds ( context . getEvent (). getMessage (). getEmbeds (). get ( 0 ))
237- .setActionRows ( rows )
214+ context .getEvent ().getMessageChannel ()
215+ .sendMessage ( builder . setActionRows ( rows ). build ( ))
216+ .flatMap ( $ -> context . getEvent (). reply ( "Message created and sent successfully!" ). setEphemeral ( true ) )
238217 .queue ();
239-
240- context .getEvent ().reply ("Message created and sent successfully!" ).setEphemeral (true ).queue ();
241218 }
242219
243220 private static Button createButtonForRole (final String id , final Role role ) {
244221 final var icon = role .getIcon ();
245222 final var bId = Component .createIdWithArguments (id , role .getId ());
246223 if (icon != null && icon .isEmoji ()) {
247- return Button .of (ButtonStyle .PRIMARY , bId , role .getName (), Emoji .fromUnicode (icon .getEmoji ()));
224+ return Button .of (ButtonStyle .PRIMARY , bId , role .getName (), Emoji .fromUnicode (Objects . requireNonNull ( icon .getEmoji () )));
248225 }
249226 return Button .primary (bId , role .getName ());
250227 }
251228
252- private static void handleDropdownCreation (final @ NonNull SelectMenuInteractionContext context , final List <Role > selectedRoles ) {
253- SelectMenu .Builder menu = COMPONENT_LISTENER .createMenu (new String [] { MenuType . ROLE_PANEL . toString ()}, Component .Lifespan .PERMANENT , String . valueOf ( true ) )
229+ private static void handleDropdownCreation (final @ NonNull ModalInteractionContext context , final MessageBuilder message , final List <Role > selectedRoles ) {
230+ SelectMenu .Builder menu = COMPONENT_LISTENER .createMenu (Component .Lifespan .PERMANENT )
254231 .setPlaceholder ("Select your roles" )
255232 .setMaxValues (selectedRoles .size ())
256233 .setMinValues (0 );
257234
258235 selectedRoles .forEach (role -> menu .addOption (role .getName (), role .getId ()));
259236
260- context .getEvent ().getChannel ()
261- .sendMessageEmbeds (context .getEvent ().getMessage ().getEmbeds ().get (0 ))
262- .setActionRow (menu .build ())
237+ context .getEvent ().getMessageChannel ()
238+ .sendMessage (message
239+ .setActionRows (ActionRow .of (menu .build ()))
240+ .build ())
241+ .flatMap ($ -> context .getEvent ().reply ("Message created and sent successfully!" ).setEphemeral (true ))
263242 .queue ();
264-
265- context .getEvent ().reply ("Message created and sent successfully!" ).setEphemeral (true ).queue ();
266243 }
267244
268245 private static void handleRoleSelection (final @ NonNull SelectMenuInteractionContext context , final @ NonNull Collection <Role > selectedRoles , final Guild guild ) {
@@ -324,9 +301,4 @@ protected void onButtonInteraction(@NonNull final ButtonInteractionContext conte
324301 .queue ();
325302 }
326303 }
327-
328- enum MenuType {
329- IN_CREATION ,
330- ROLE_PANEL
331- }
332304}
0 commit comments