Skip to content

Instantly share code, notes, and snippets.

@MinnDevelopment
Last active September 10, 2020 13:25
Show Gist options
  • Save MinnDevelopment/feea5b6ed3687b666b2aace62b806f8f to your computer and use it in GitHub Desktop.
Save MinnDevelopment/feea5b6ed3687b666b2aace62b806f8f to your computer and use it in GitHub Desktop.
public class ActionMenu extends Menu implements Menu.Page {
private final Message message;
private final List<Button> buttons = new ArrayList<>();
public ActionMenu(Message message) {
this.message = message;
}
public ActionMenu addButton(Button button) {
buttons.add(button);
return this;
}
public ActionMenu addAction(String reactionCode, Consumer<? super GenericMessageReactionEvent> action) {
return addButton(new ActionButton(reactionCode, action));
}
@Override
protected List<Page> initializePages() {
return Collections.singletonList(this);
}
@Override
public Message getMessage() {
return message;
}
@Override
public List<Button> getButtons() {
return buttons;
}
private static final class ActionButton implements Button {
private final String code;
private final Consumer<? super GenericMessageReactionEvent> action;
private ActionButton(String code, Consumer<? super GenericMessageReactionEvent> action) {
this.code = code;
this.action = action;
}
@Override
public String getReaction() {
return code;
}
@Override
public Page onInteraction(Menu menu, GenericMessageReactionEvent event) {
action.accept(event);
return menu.getCurrentPage();
}
}
}
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.GenericEvent;
import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent;
import net.dv8tion.jda.api.hooks.EventListener;
import net.dv8tion.jda.api.hooks.SubscribeEvent;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class Menu implements EventListener {
private final List<Page> pages;
private final String nonce = String.valueOf(ThreadLocalRandom.current().nextLong());
private Page currentPage;
private long messageId = 0L;
private Predicate<? super GenericMessageReactionEvent> condition = (e) -> true;
public Menu() {
pages = initializePages();
}
public Menu setCondition(Predicate<? super GenericMessageReactionEvent> condition) {
this.condition = condition;
return this;
}
public Menu setTargetUser(User user) {
long userId = user.getIdLong();
return setCondition(event -> event.getUserIdLong() == userId);
}
public Menu addPage(Page page) {
pages.add(page);
return this;
}
public Page getHomePage() {
return pages.get(0);
}
public List<Page> getPages() {
return pages;
}
public Page getCurrentPage() {
return currentPage;
}
public long getMessageId() {
return messageId;
}
public void send(MessageChannel channel) {
Page homePage = getHomePage();
currentPage = homePage;
channel.getJDA().addEventListener(this);
channel.sendMessage(homePage.getMessage()).nonce(nonce).queue(m -> {
messageId = m.getIdLong();
homePage.getButtons().forEach(button -> m.addReaction(button.getReaction()).queue());
});
}
protected List<Page> initializePages() {
return new ArrayList<>();
}
@Override
@SubscribeEvent
public void onEvent(@NotNull GenericEvent event) {
if (event instanceof MessageReceivedEvent) {
Message message = ((MessageReceivedEvent) event).getMessage();
String messageNonce = message.getNonce();
if (nonce.equals(messageNonce))
messageId = message.getIdLong();
}
else if (event instanceof MessageDeleteEvent) {
if (((MessageDeleteEvent) event).getMessageIdLong() == messageId)
event.getJDA().removeEventListener(this);
}
else if (event instanceof GenericMessageReactionEvent) {
onReaction((GenericMessageReactionEvent) event);
}
}
private void onReaction(GenericMessageReactionEvent event) {
if (event.getMessageIdLong() != messageId) return;
if (event.getUserIdLong() == event.getJDA().getSelfUser().getIdLong()) return;
if (!condition.test(event)) return;
String code = event.getReactionEmote().getAsReactionCode();
currentPage.getButtons()
.stream()
.filter(b -> b.getReaction().equals(code))
.findFirst()
.ifPresent(b -> {
currentPage = b.onInteraction(this, event);
if (currentPage == null)
event.getJDA().removeEventListener(this);
else
event.getChannel().editMessageById(messageId, currentPage.getMessage()).override(true).queue();
});
}
public static List<Button> getNavigationButtons() {
return Arrays.asList(
new HeadButton(), new PreviousButton(),
new NextButton(), new TailButton()
);
}
interface Page {
Message getMessage();
List<Button> getButtons();
static Page from(Message message, List<Button> buttons) {
return new BasicPage(message).addButtons(buttons);
}
}
interface Button {
String getReaction();
Page onInteraction(Menu menu, GenericMessageReactionEvent event);
static Button from(String reactionCode, BiFunction<? super Menu, ? super GenericMessageReactionEvent, ? extends Page> action) {
return new BasicButton(reactionCode).setAction(action);
}
}
public static class BasicPage implements Page {
private final List<Button> buttons = new ArrayList<>();
private final Message message;
public BasicPage(Message message) {
this.message = message;
}
@Override
public Message getMessage() {
return message;
}
@Override
public List<Button> getButtons() {
return buttons;
}
public BasicPage addButtons(Button... buttons) {
Collections.addAll(this.buttons, buttons);
return this;
}
public BasicPage addButtons(Collection<? extends Button> buttons) {
this.buttons.addAll(buttons);
return this;
}
}
public static class BasicButton implements Button {
private final String reaction;
private BiFunction<? super Menu, ? super GenericMessageReactionEvent, ? extends Page> action = (menu, event) -> menu.getCurrentPage();
public BasicButton(String reaction) {
this.reaction = reaction;
}
@Override
public String getReaction() {
return reaction;
}
@Override
public Page onInteraction(Menu menu, GenericMessageReactionEvent event) {
return action.apply(menu, event);
}
public BasicButton setAction(BiFunction<? super Menu, ? super GenericMessageReactionEvent, ? extends Page> action) {
this.action = action;
return this;
}
}
/// Page that renders an embed
public static class EmbedPage extends BasicPage {
public EmbedPage(MessageEmbed embed) {
this(embed, getNavigationButtons());
}
public EmbedPage(MessageEmbed embed, Collection<? extends Button> buttons) {
super(new MessageBuilder().setEmbed(embed).build());
super.addButtons(buttons);
}
}
/// Jump to next page
public static class NextButton implements Button {
@Override
public String getReaction() {
return "▶️";
}
@Override
public Page onInteraction(Menu menu, GenericMessageReactionEvent event) {
int current = menu.getPages().indexOf(menu.getCurrentPage());
int next = (current + 1) % menu.getPages().size();
return menu.getPages().get(next);
}
}
/// Jump to previous page
public static class PreviousButton implements Button {
@Override
public String getReaction() {
return "◀️";
}
@Override
public Page onInteraction(Menu menu, GenericMessageReactionEvent event) {
int current = menu.getPages().indexOf(menu.getCurrentPage());
int next = current - 1;
if (next < 0)
next = menu.getPages().size() + next;
return menu.getPages().get(next);
}
}
/// Jump to last page
public static class TailButton implements Button {
@Override
public String getReaction() {
return "⏭️";
}
@Override
public Page onInteraction(Menu menu, GenericMessageReactionEvent event) {
return menu.getPages().get(menu.getPages().size() - 1);
}
}
/// Jump to first page
public static class HeadButton implements Button {
@Override
public String getReaction() {
return "⏮️";
}
@Override
public Page onInteraction(Menu menu, GenericMessageReactionEvent event) {
return menu.getHomePage();
}
}
/// Delete message
public static class DeleteButton implements Button {
@Override
public String getReaction() {
return "❌";
}
@Override
public Page onInteraction(Menu menu, GenericMessageReactionEvent event) {
event.getChannel().deleteMessageById(event.getMessageId()).queue();
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment