Skip to content

Commit

Permalink
feat: abstract initial message methods + add a few util methods allow…
Browse files Browse the repository at this point in the history
…ing you to set the initial message straight from plain text / embed content
  • Loading branch information
ANutley committed Oct 11, 2024
1 parent 32a3255 commit 23283c0
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 65 deletions.
16 changes: 2 additions & 14 deletions menus/src/main/java/me/anutley/jdautils/menus/ButtonMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@

public class ButtonMenu extends Menu {

protected final MessageCreateData initialMessage;
protected final Consumer<ButtonInteractionEvent> action;
protected final List<ActionRow> actionRows;

public ButtonMenu(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, MessageCreateData initialMessage, Consumer<ButtonInteractionEvent> action, List<ActionRow> actionRows) {
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral);
this.initialMessage = initialMessage;
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral, initialMessage);
this.action = action;
this.actionRows = actionRows;
}
Expand Down Expand Up @@ -67,7 +65,6 @@ private void waitForClick(long messageId) {

public static class Builder extends Menu.Builder<Builder, ButtonMenu> {

protected MessageCreateData initialMessage = null;
protected Consumer<ButtonInteractionEvent> action = null;
protected List<ActionRow> actionRows = new ArrayList<>();

Expand All @@ -87,21 +84,12 @@ public ButtonMenu build() {
super.units,
super.recursive,
super.ephemeral,
initialMessage,
super.initialMessage,
action,
actionRows
);
}

/**
* @param initialMessage Sets the initial message that should be sent with the components
* @return Itself for chaining convenience
*/
public Builder setInitialMessage(MessageCreateData initialMessage) {
this.initialMessage = initialMessage;
return this;
}

/**
* @param action The consumer that will be accepted after a button is clicked
* @return Itself for chaining convenience
Expand Down
46 changes: 41 additions & 5 deletions menus/src/main/java/me/anutley/jdautils/menus/Menu.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package me.anutley.jdautils.menus;

import me.anutley.jdautils.eventwaiter.EventWaiter;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.events.interaction.command.GenericCommandInteractionEvent;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
Expand All @@ -24,6 +23,7 @@ public abstract class Menu {
protected final TimeUnit units;
protected final boolean recursive;
protected final boolean ephemeral;
protected final MessageCreateData initialMessage;

private final long startTimestamp = System.currentTimeMillis();

Expand All @@ -35,15 +35,17 @@ public abstract class Menu {
* @param units The units for the timeout
* @param recursive Whether the menu should recursively listen for actions
* @param ephemeral Whether menus that reply to interactions should be ephemeral
* @param initialMessage The initial message that should be sent with the components
*/
public Menu(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral) {
public Menu(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, MessageCreateData initialMessage) {
this.eventWaiter = eventWaiter;
this.allowedUsers = allowedUsers;
this.allowedRoles = allowedRoles;
this.timeout = timeout;
this.units = units;
this.recursive = recursive;
this.ephemeral = ephemeral;
this.initialMessage = initialMessage;
}

/**
Expand Down Expand Up @@ -77,7 +79,11 @@ protected boolean isAllowed(User user, @Nullable Guild guild) {
if (guild == null || !guild.isMember(user))
return false;

return guild.getMember(user).getRoles().stream().anyMatch(allowedRoles::contains);
Member member = guild.getMember(user);

if (member == null) return false;

return member.getRoles().stream().anyMatch(allowedRoles::contains);
}

/**
Expand Down Expand Up @@ -108,6 +114,7 @@ public static abstract class Builder<B extends Builder<B, M>, M extends Menu> {
protected TimeUnit units = TimeUnit.MINUTES;
protected boolean recursive = true;
protected boolean ephemeral = false;
protected MessageCreateData initialMessage = null;

/**
* @return The built menu
Expand Down Expand Up @@ -195,5 +202,34 @@ public B setEphemeral(boolean ephemeral) {
this.ephemeral = ephemeral;
return (B) this;
}

/**
* @param initialMessage Sets the initial message that should be sent with the components
* @return Itself for chaining convenience
*/
public B setInitialMessage(MessageCreateData initialMessage) {
this.initialMessage = initialMessage;
return (B) this;
}

/**
* @param content Sets the initial message (plain text) that should be sent with the components
* @return Itself for chaining convenience
*/
public B setInitialMessage(String content) {
this.initialMessage = MessageCreateData.fromContent(content);
return (B) this;
}


/**
* @param embed Sets the initial message (embed) that should be sent with the components
* @return Itself for chaining convenience
*/
public B setInitialMessage(MessageEmbed... embed) {
this.initialMessage = MessageCreateData.fromEmbeds(embed);
return (B) this;
}

}
}
18 changes: 3 additions & 15 deletions menus/src/main/java/me/anutley/jdautils/menus/ReactionMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@

public class ReactionMenu extends Menu {

protected final MessageCreateData initialMessage;
protected final Consumer<MessageReactionAddEvent> action;
protected final List<String> reactions;

public ReactionMenu(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, MessageCreateData initialMessage, Consumer<MessageReactionAddEvent> action, List<String> reactions) {
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral);
this.initialMessage = initialMessage;
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral, initialMessage);
this.action = action;
this.reactions = reactions;
}
Expand Down Expand Up @@ -69,15 +67,14 @@ private void waitForClick(long messageId) {

public static class Builder extends Menu.Builder<ReactionMenu.Builder, ReactionMenu> {

protected MessageCreateData initialMessage = null;
protected Consumer<MessageReactionAddEvent> action = null;
protected List<String> reactions = new ArrayList<>();

@Override
public ReactionMenu build() {

if (eventWaiter == null) throw new IllegalStateException("The Event Waiter must be set!");
if (reactions.size() == 0) throw new IllegalStateException("There must be at least one reaction");
if (reactions.isEmpty()) throw new IllegalStateException("There must be at least one reaction");
if (action == null) throw new IllegalStateException("There must be a callback action");
if (initialMessage == null) throw new IllegalStateException("There must be an initial message");

Expand All @@ -89,21 +86,12 @@ public ReactionMenu build() {
super.units,
super.recursive,
super.ephemeral,
initialMessage,
super.initialMessage,
action,
reactions
);
}

/**
* @param initialMessage Sets the initial message that should be sent with the components
* @return Itself for chaining convenience
*/
public Builder setInitialMessage(MessageCreateData initialMessage) {
this.initialMessage = initialMessage;
return this;
}

/**
* @param action The consumer that will be accepted after a button is clicked
* @return Itself for chaining convenience
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@
// TODO implement other types of select menu or make this generic
public class StringSelectionMenu extends Menu {

protected final MessageCreateData initialMessage;
protected final Consumer<StringSelectInteractionEvent> action;
protected final List<ActionRow> actionRows;

public StringSelectionMenu(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, MessageCreateData initialMessage, Consumer<StringSelectInteractionEvent> action, List<ActionRow> actionRows) {
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral);
this.initialMessage = initialMessage;
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral, initialMessage);
this.action = action;
this.actionRows = actionRows;
}
Expand Down Expand Up @@ -66,15 +64,14 @@ private void waitForClick(long messageId) {

public static class Builder extends Menu.Builder<StringSelectionMenu.Builder, StringSelectionMenu> {

protected MessageCreateData initialMessage = null;
protected Consumer<StringSelectInteractionEvent> action = null;
protected List<ActionRow> actionRows = new ArrayList<>();

@Override
public StringSelectionMenu build() {

if (eventWaiter == null) throw new IllegalStateException("The Event Waiter must be set!");
if (actionRows.size() == 0) throw new IllegalStateException("There must be at least one action row");
if (actionRows.isEmpty()) throw new IllegalStateException("There must be at least one action row");
if (action == null) throw new IllegalStateException("There must be a callback action");
if (initialMessage == null) throw new IllegalStateException("There must be an initial message");

Expand All @@ -86,21 +83,12 @@ public StringSelectionMenu build() {
super.units,
super.recursive,
super.ephemeral,
initialMessage,
super.initialMessage,
action,
actionRows
);
}

/**
* @param initialMessage Sets the initial message that should be sent with the components
* @return Itself for chaining convenience
*/
public StringSelectionMenu.Builder setInitialMessage(MessageCreateData initialMessage) {
this.initialMessage = initialMessage;
return this;
}

/**
* @param action The consumer that will be accepted after a button is clicked
* @return Itself for chaining convenience
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
*/
public class ButtonPaginator extends Paginator<Button> {

public ButtonPaginator(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, List<MessageCreateData> pages) {
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral, pages);
public ButtonPaginator(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, MessageCreateData initialMessage, List<MessageCreateData> pages) {
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral, initialMessage, pages);
}

@Override
Expand Down Expand Up @@ -80,17 +80,17 @@ else if (event.getButton().equals(getStopButton()))

@Override
public Button getNextButton() {
return Button.primary("next", Emoji.fromUnicode("\u27A1")).withDisabled(isEnd());
return Button.primary("next", Emoji.fromUnicode("")).withDisabled(isEnd());
}

@Override
public Button getPrevButton() {
return Button.primary("prev", Emoji.fromUnicode("\u2B05")).withDisabled(isStart());
return Button.primary("prev", Emoji.fromUnicode("")).withDisabled(isStart());
}

@Override
public Button getStopButton() {
return Button.secondary("stop", Emoji.fromUnicode("\u23F9"));
return Button.secondary("stop", Emoji.fromUnicode(""));
}

@Override
Expand All @@ -105,7 +105,7 @@ public static class Builder extends Paginator.Builder<Builder, ButtonPaginator>
public ButtonPaginator build() {

if (eventWaiter == null) throw new IllegalStateException("The Event Waiter must be set!");
if (pages.size() == 0) throw new IllegalStateException("There must be at least one page");
if (pages.isEmpty()) throw new IllegalStateException("There must be at least one page");

return new ButtonPaginator(
super.eventWaiter,
Expand All @@ -115,6 +115,7 @@ public ButtonPaginator build() {
super.units,
super.recursive,
super.ephemeral,
super.initialMessage,
super.pages
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/
public abstract class Paginator<T> extends Menu {

protected List<MessageCreateData> pages;
protected final List<MessageCreateData> pages;
protected int index = 0;

/**
Expand All @@ -33,10 +33,11 @@ public abstract class Paginator<T> extends Menu {
* @param units The units for the timeout
* @param recursive Whether the menu should recursively listen for actions
* @param ephemeral Whether menus that reply to interactions should be ephemeral
* @param pages A list of Message's which the paginator should use for its content
* @param initialMessage The initial message that should be sent with the components
* @param pages A list of Messages which the paginator should use for its content
*/
public Paginator(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, List<MessageCreateData> pages) {
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral);
public Paginator(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, MessageCreateData initialMessage, List<MessageCreateData> pages) {
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral, initialMessage);
this.pages = pages;
}

Expand Down Expand Up @@ -158,5 +159,16 @@ public B addPage(MessageEmbed messageEmbed) {
return (B) this;
}

/**
* This method is the same as just using {@link #addPage(MessageCreateData)} for the first time but keeping it here for consistency
* @param initialMessage The initial message of the paginator
* @return Itself for chaining convenience
*/
@Override
public B setInitialMessage(MessageCreateData initialMessage) {
pages.set(0, initialMessage);
return (B) this;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
*/
public class ReactionPaginator extends Paginator<String> {

public ReactionPaginator(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, List<MessageCreateData> pages) {
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral, pages);
public ReactionPaginator(EventWaiter eventWaiter, List<User> allowedUsers, List<Role> allowedRoles, long timeout, TimeUnit units, boolean recursive, boolean ephemeral, MessageCreateData initialMessage, List<MessageCreateData> pages) {
super(eventWaiter, allowedUsers, allowedRoles, timeout, units, recursive, ephemeral, initialMessage, pages);
}

@Override
Expand Down Expand Up @@ -78,17 +78,17 @@ else if (event.getEmoji().getName().equals(getDeleteButton()))

@Override
public String getNextButton() {
return "\u27A1";
return "";
}

@Override
public String getPrevButton() {
return "\u2B05";
return "";
}

@Override
public String getStopButton() {
return "\u23F9";
return "";
}

@Override
Expand All @@ -103,7 +103,7 @@ public static class Builder extends Paginator.Builder<ReactionPaginator.Builder,
public ReactionPaginator build() {

if (eventWaiter == null) throw new IllegalStateException("The Event Waiter must be set!");
if (pages.size() == 0) throw new IllegalStateException("There must be at least one page");
if (pages.isEmpty()) throw new IllegalStateException("There must be at least one page");

return new ReactionPaginator(
super.eventWaiter,
Expand All @@ -113,6 +113,7 @@ public ReactionPaginator build() {
super.units,
super.recursive,
super.ephemeral,
super.initialMessage,
super.pages
);
}
Expand Down

0 comments on commit 23283c0

Please sign in to comment.