From e1bf6bc860b0d8390f69d445ef4f4b8b8a6d0d05 Mon Sep 17 00:00:00 2001 From: Andre601 <11576465+Andre601@users.noreply.github.com> Date: Wed, 25 Mar 2020 22:30:32 +0100 Subject: [PATCH 1/5] Implement EmbedPaginator --- .../jdautilities/menu/EmbedPaginator.java | 537 ++++++++++++++++++ 1 file changed, 537 insertions(+) create mode 100644 menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java diff --git a/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java new file mode 100644 index 00000000..0dd0a43f --- /dev/null +++ b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java @@ -0,0 +1,537 @@ +/* + * Copyright 2016-2018 John Grosh (jagrosh) & Kaidan Gustave (TheMonitorLizard) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jagrosh.jdautilities.menu; + +import com.jagrosh.jdautilities.commons.waiter.EventWaiter; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.message.GenericMessageEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; +import net.dv8tion.jda.api.exceptions.PermissionException; +import net.dv8tion.jda.api.requests.RestAction; +import net.dv8tion.jda.internal.utils.Checks; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.function.BiFunction; +import java.util.function.Consumer; + +/** + * A {@link com.jagrosh.jdautilities.menu.Menu Menu} implementation, nearly identical to + * {@link com.jagrosh.jdautilities.menu.Paginator Paginator}, that displays an individual + * {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbed} on each page instead of a list of text items. + * + *

Like Paginator, reaction functions allow the user to traverse to the last page using the left arrow, the next + * page using the right arrow, and to stop the EmbedPaginator prematurely using the stop reaction. + * + * @author Andre_601 + */ +public class EmbedPaginator extends Menu{ + + private final BiFunction text; + private final Consumer finalAction; + private final boolean waitOnSinglePage; + private final List embeds; + private final int bulkSkipNumber; + private final boolean wrapPageEnds; + private final String leftText; + private final String rightText; + private final boolean allowTextInput; + + public static final String BIG_LEFT = "\u23EA"; + public static final String LEFT = "\u25C0"; + public static final String STOP = "\u23F9"; + public static final String RIGHT = "\u25B6"; + public static final String BIG_RIGHT = "\u23E9"; + + protected EmbedPaginator(EventWaiter waiter, Set users, Set roles, long timeout, TimeUnit unit, + BiFunction text, Consumer finalAction, + boolean waitOnSinglePage, List embeds, int bulkSkipNumber, + boolean wrapPageEnds, String leftText, String rightText, boolean allowTextInput){ + super(waiter, users, roles, timeout, unit); + this.text = text; + this.finalAction = finalAction; + this.waitOnSinglePage = waitOnSinglePage; + this.embeds = embeds; + this.bulkSkipNumber = bulkSkipNumber; + this.wrapPageEnds = wrapPageEnds; + this.leftText = leftText; + this.rightText = rightText; + this.allowTextInput = allowTextInput; + } + + /** + * Begins pagination on page 1 as a new {@link net.dv8tion.jda.api.entities.Message Message} + * in the provided {@link net.dv8tion.jda.api.entities.MessageChannel MessageChannel}. + * + * @param channel + * The MessageChannel to send the new Message to + */ + @Override + public void display(MessageChannel channel){ + paginate(channel, 1); + } + + /** + * Begins pagination on page 1 displaying this by editing the provided + * {@link net.dv8tion.jda.api.entities.Message Message}. + * + * @param message + * The Message to display the Menu in + */ + @Override + public void display(Message message){ + paginate(message, 1); + } + + /** + * Begins pagination as a new {@link net.dv8tion.jda.api.entities.Message Message} + * in the provided {@link net.dv8tion.jda.api.entities.MessageChannel MessageChannel}, starting + * on whatever page number is provided. + * + * @param channel + * The MessageChannel to send the new Message to + * @param pageNum + * The page number to begin on + */ + public void paginate(MessageChannel channel, int pageNum){ + if(pageNum < 1) + pageNum = 1; + else if(pageNum > embeds.size()) + pageNum = embeds.size(); + Message msg = renderPage(pageNum); + initialize(channel.sendMessage(msg), pageNum); + } + + /** + * Begins pagination displaying this by editing the provided + * {@link net.dv8tion.jda.api.entities.Message Message}, starting on whatever + * page number is provided. + * + * @param message + * The MessageChannel to send the new Message to + * @param pageNum + * The page number to begin on + */ + public void paginate(Message message, int pageNum){ + if(pageNum < 1) + pageNum = 1; + else if(pageNum > embeds.size()) + pageNum = embeds.size(); + Message msg = renderPage(pageNum); + initialize(message.editMessage(msg), pageNum); + } + + private void initialize(RestAction action, int pageNum){ + action.queue(m->{ + if(embeds.size()>1){ + if(bulkSkipNumber > 1) + m.addReaction(BIG_LEFT).queue(); + m.addReaction(LEFT).queue(); + m.addReaction(STOP).queue(); + if(bulkSkipNumber > 1) + m.addReaction(RIGHT).queue(); + m.addReaction(bulkSkipNumber > 1 ? BIG_RIGHT : RIGHT) + .queue(); + }else if(waitOnSinglePage){ + m.addReaction(STOP).queue(); + }else{ + finalAction.accept(m); + } + }); + } + + private void pagination(Message message, int pageNum){ + if(allowTextInput || (leftText != null && rightText != null)) + paginationWithTextInput(message, pageNum); + else + paginationWithoutTextInput(message, pageNum); + } + + private void paginationWithTextInput(Message message, int pageNum){ + waiter.waitForEvent(GenericMessageEvent.class, event -> { + if(event instanceof MessageReactionAddEvent) + return checkReaction((MessageReactionAddEvent) event, message.getIdLong()); + else if(event instanceof MessageReceivedEvent){ + MessageReceivedEvent mre = (MessageReceivedEvent) event; + if(!mre.getChannel().equals(message.getChannel())) + return false; + String rawContent = mre.getMessage().getContentRaw().trim(); + if(leftText != null && rightText != null){ + if(rawContent.equalsIgnoreCase(leftText) || rawContent.equalsIgnoreCase(rightText)) + return isValidUser(mre.getAuthor(), mre.isFromGuild() ? mre.getGuild() : null); + } + + if(allowTextInput){ + try{ + int i = Integer.parseInt(rawContent); + + if(1 <= i && i <= embeds.size() && i != pageNum) + return isValidUser(mre.getAuthor(), mre.isFromGuild() ? mre.getGuild() : null); + }catch(NumberFormatException ignored){} + } + } + return false; + }, event -> { + if(event instanceof MessageReactionAddEvent){ + handleMessageReactionAddAction((MessageReactionAddEvent)event, message, pageNum); + }else{ + MessageReceivedEvent mre = (MessageReceivedEvent) event; + String rawContent = mre.getMessage().getContentRaw().trim(); + + int pages = embeds.size(); + final int targetPage; + + if(leftText != null && rawContent.equalsIgnoreCase(leftText) && (1 < pageNum || wrapPageEnds)) + targetPage = pageNum - 1 < 1 && wrapPageEnds ? pages : pageNum - 1; + else if(rightText != null && rawContent.equalsIgnoreCase(rightText) && (pageNum < pages || wrapPageEnds)) + targetPage = pageNum + 1 > pages && wrapPageEnds ? 1 : pageNum + 1; + else + targetPage = Integer.parseInt(rawContent); + + message.editMessage(renderPage(targetPage)).queue(m -> pagination(m, targetPage)); + mre.getMessage().delete().queue(v -> {}, t -> {}); + } + }, timeout, unit, () -> finalAction.accept(message)); + } + + private void paginationWithoutTextInput(Message message, int pageNum){ + waiter.waitForEvent(MessageReactionAddEvent.class, + event -> checkReaction(event, message.getIdLong()), + event -> handleMessageReactionAddAction(event, message, pageNum), + timeout, unit, () -> finalAction.accept(message)); + } + + private boolean checkReaction(MessageReactionAddEvent event, long messageId){ + if(event.getMessageIdLong() != messageId) + return false; + switch(event.getReactionEmote().getName()){ + case LEFT: + case STOP: + case RIGHT: + return isValidUser(event.getUser(), event.isFromGuild() ? event.getGuild() : null); + case BIG_LEFT: + case BIG_RIGHT: + return bulkSkipNumber > 1 && isValidUser(event.getUser(), event.isFromGuild() ? event.getGuild() : null); + default: + return false; + } + } + + private void handleMessageReactionAddAction(MessageReactionAddEvent event, Message message, int pageNum){ + int newPageNum = pageNum; + int pages = embeds.size(); + switch(event.getReaction().getReactionEmote().getName()){ + case LEFT: + if(newPageNum == 1 && wrapPageEnds) + newPageNum = pages + 1; + if(newPageNum > 1) + newPageNum--; + break; + case RIGHT: + if(newPageNum == pages && wrapPageEnds) + newPageNum = 0; + if(newPageNum < pages) + newPageNum++; + break; + case BIG_LEFT: + if(newPageNum > 1 || wrapPageEnds){ + for(int i = 1; (newPageNum > 1 || wrapPageEnds) && i < bulkSkipNumber; i++){ + if(newPageNum == 1 && wrapPageEnds) + newPageNum = pages + 1; + newPageNum--; + } + } + break; + case BIG_RIGHT: + if(newPageNum < pages || wrapPageEnds){ + for(int i = 1; (newPageNum < pages || wrapPageEnds) && i < bulkSkipNumber; i++){ + if(newPageNum == pages && wrapPageEnds) + newPageNum = 0; + newPageNum++; + } + } + break; + case STOP: + finalAction.accept(message); + return; + } + + try{ + event.getReaction().removeReaction(event.getUser()).queue(); + }catch(PermissionException ignored){} + + int n = newPageNum; + message.editMessage(renderPage(newPageNum)).queue(m -> pagination(m, n)); + } + + private Message renderPage(int pageNum){ + MessageBuilder mbuilder = new MessageBuilder(); + MessageEmbed membed = this.embeds.get(pageNum-1); + mbuilder.setEmbed(membed); + if(text != null) + mbuilder.append(text.apply(pageNum, embeds.size())); + return mbuilder.build(); + } + + /** + * The {@link Menu.Builder Menu.Builder} for a {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator}. + * + * @author Andre_601 + */ + public class Builder extends Menu.Builder{ + + private BiFunction text = (page, pages) -> null; + private Consumer finalAction = m -> m.delete().queue(); + private boolean waitOnSinglePage = false; + private int bulkSkipNumber = 1; + private boolean wrapPageEnds = false; + private String leftText = null; + private String rightText = null; + private boolean allowTextInput = false; + + private List embeds = new LinkedList<>(); + + /** + * Builds the {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator} with this Builder. + * + * @return The Paginator built from this Builder. + * + * @throws java.lang.IllegalArgumentException + * If one of the following is violated: + *

+ */ + @Override + public EmbedPaginator build(){ + Checks.check(waiter != null, "Must set an EventWaiter"); + Checks.check(!embeds.isEmpty(), "Must include at least one item to paginate"); + + return new EmbedPaginator( + waiter, users, roles, timeout, unit, text, finalAction, waitOnSinglePage, embeds, bulkSkipNumber, + wrapPageEnds, leftText, rightText, allowTextInput + ); + } + + /** + * Sets the text of the {@link net.dv8tion.jda.api.entities.Message Message} to be displayed when the + * {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator} is built. + * + * @param text + * The Message content to be displayed avove the embed when the EmbedPaginator is built. + * + * @return This builder + */ + public Builder setText(String text){ + this.text = (i0, i1) -> text; + return this; + } + + /** + * Sets the text of the {@link net.dv8tion.jda.api.entities.Message Message} to be displayed relative to the + * total page number and the current page as determined by the provided + * {@link java.util.function.BiFunction BiFunction}. + *
As the page changes, the BiFunction will re-process the current page number and the total page number, + * allowing for the displayed text of the Message to change depending on the page number. + * + * @param textBiFunction + * The BiFunction that uses both current and total page numbers, to get text for the Message + * + * @return This builder + */ + public Builder setText(BiFunction textBiFunction){ + this.text = textBiFunction; + return this; + } + + /** + * Sets the {@link java.util.function.Consumer Consumer} to perform if the + * {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator} times out. + * + * @param finalAction + * The Consumer action to perform if the EmbedPaginator times out + * + * @return This builder + */ + public Builder setFinalAction(Consumer finalAction){ + this.finalAction = finalAction; + return this; + } + + /** + * Sets whether the {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator} will instantly + * timeout, and possibly run a provided {@link java.lang.Runnable Runnable}, if only a single slide is + * available to display. + * + * @param waitOnSinglePage + * {@code true} if the EmbedPaginator will still generate + * + * @return This builder + */ + public Builder waitOnSinglePage(boolean waitOnSinglePage){ + this.waitOnSinglePage = waitOnSinglePage; + return this; + } + + /** + * Clears all previously set items. + * + * @return This builder + */ + public Builder clearItems(){ + this.embeds.clear(); + return this; + } + + /** + * Adds {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to the list of items to paginate. + * + * @param embeds + * The MessageEmbed list of items to add + * + * @return This builder + */ + public Builder addItems(MessageEmbed... embeds){ + this.embeds.addAll(Arrays.asList(embeds)); + return this; + } + + /** + * Adds {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to the list of items to paginate. + *
This method creates a new, basic MessageEmbed containing only the provided String as description. + *
Use the {@link com.jagrosh.jdautilities.menu.Paginator Paginator} for more Embed customization, + * without providing your own MessageEmbed instances. + * + * @param items + * The String list of items to add as MessageEmbeds + * + * @return This builder + */ + public Builder addItems(String... items){ + for(String item : items) + this.embeds.add(new EmbedBuilder().setDescription(item).build()); + return this; + } + + /** + * Sets the {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to paginate. + *
This method clears all previously set items before setting. + * + * @param embeds + * The MessageEmbed list of items to add + * + * @return This builder + */ + public Builder setItems(MessageEmbed... embeds){ + this.embeds.clear(); + this.embeds.addAll(Arrays.asList(embeds)); + return this; + } + + /** + * Sets the {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to paginate. + *
This method clears all previously set items before setting each String as a new MessageEmbed. + *
Use the {@link com.jagrosh.jdautilities.menu.Paginator Paginator} for more Embed customization, + * without providing your own MessageEmbed instances. + * + * @param items + * The String list of items to add + * + * @return This builder + */ + public Builder setItems(String... items){ + this.embeds.clear(); + addItems(items); + return this; + } + + /** + * Sets the {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator}'s bulk-skip function to + * skip multiple pages using alternate forward and backwards reactions. + * + * @param bulkSkipNumber + * The number of pages to skip when the bulk-skip reactions are used. + * + * @return This builder + */ + public Builder setBulkSkipNumber(int bulkSkipNumber){ + this.bulkSkipNumber = bulkSkipNumber; + return this; + } + + /** + * Sets the {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator} to wrap from the last page + * to the first when traversing right and vice versa from the left. + * + * @param wrapPageEnds + * {@code true} to enable wrapping. + * + * @return This builder + */ + public Builder wrapPageEnds(boolean wrapPageEnds){ + this.wrapPageEnds = wrapPageEnds; + return this; + } + + /** + * Sets the {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator} to allow a page number to + * be specified by a user via text. + * + *

Note that setting this doesn't mean that left and right text inputs provided via + * {@link EmbedPaginator.Builder#setLeftRightText(String, String)} will be invalidated if they were set + * previously! To invalidate those, provide {@code null} for one or both of the parameters of that method. + * + * @param allowTextInput + * {@code true} if the EmbedPaginator will allow page-number text input. + * + * @return This builder + */ + public Builder allowTextInput(boolean allowTextInput){ + this.allowTextInput = allowTextInput; + return this; + } + + /** + * Sets the {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator} to traverse left or right + * when a provided text input is sent in the form of a Message to the + * {@link net.dv8tion.jda.api.entities.GuildChannel GuildChannel} the menu is displayed in. + * + * @param left + * The left text input, causes the EmbedPaginator to traverse one page left. + * @param right + * The right text input, causes the EmbedPaginator to traverse one page right. + * + * @return This builder + */ + public Builder setLeftRightText(String left, String right){ + if(left == null || right == null){ + leftText = null; + rightText = null; + }else{ + leftText = left; + rightText = right; + } + return this; + } + } +} From 7a885812b9bb2ab683bb3005d8df29d120172754 Mon Sep 17 00:00:00 2001 From: Andre601 <11576465+Andre601@users.noreply.github.com> Date: Wed, 25 Mar 2020 22:49:00 +0100 Subject: [PATCH 2/5] Make EmbedPaginator.Builder static --- .../main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java index 0dd0a43f..810d9ac8 100644 --- a/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java +++ b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java @@ -297,7 +297,7 @@ private Message renderPage(int pageNum){ * * @author Andre_601 */ - public class Builder extends Menu.Builder{ + public static class Builder extends Menu.Builder{ private BiFunction text = (page, pages) -> null; private Consumer finalAction = m -> m.delete().queue(); From 1fc357fd6cce05bb74bc4e5d9fb1a000f034aa59 Mon Sep 17 00:00:00 2001 From: Andre601 <11576465+Andre601@users.noreply.github.com> Date: Wed, 25 Mar 2020 23:34:34 +0100 Subject: [PATCH 3/5] Add missing queue actions --- .../java/com/jagrosh/jdautilities/menu/EmbedPaginator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java index 810d9ac8..67bdceaa 100644 --- a/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java +++ b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java @@ -150,9 +150,9 @@ private void initialize(RestAction action, int pageNum){ if(bulkSkipNumber > 1) m.addReaction(RIGHT).queue(); m.addReaction(bulkSkipNumber > 1 ? BIG_RIGHT : RIGHT) - .queue(); + .queue(v -> pagination(m, pageNum), t -> pagination(m, pageNum)); }else if(waitOnSinglePage){ - m.addReaction(STOP).queue(); + m.addReaction(STOP).queue(v -> pagination(m, pageNum), t -> pagination(m, pageNum)); }else{ finalAction.accept(m); } From a009f6086ab9d20899a947ba8ab6363acb2380cb Mon Sep 17 00:00:00 2001 From: Andre601 <11576465+Andre601@users.noreply.github.com> Date: Sun, 26 Apr 2020 21:29:02 +0200 Subject: [PATCH 4/5] Improve formatting --- .../jdautilities/menu/EmbedPaginator.java | 166 ++++++++++++------ 1 file changed, 113 insertions(+), 53 deletions(-) diff --git a/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java index 67bdceaa..3c974b55 100644 --- a/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java +++ b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java @@ -65,7 +65,8 @@ public class EmbedPaginator extends Menu{ protected EmbedPaginator(EventWaiter waiter, Set users, Set roles, long timeout, TimeUnit unit, BiFunction text, Consumer finalAction, boolean waitOnSinglePage, List embeds, int bulkSkipNumber, - boolean wrapPageEnds, String leftText, String rightText, boolean allowTextInput){ + boolean wrapPageEnds, String leftText, String rightText, boolean allowTextInput) + { super(waiter, users, roles, timeout, unit); this.text = text; this.finalAction = finalAction; @@ -86,7 +87,8 @@ protected EmbedPaginator(EventWaiter waiter, Set users, Set roles, l * The MessageChannel to send the new Message to */ @Override - public void display(MessageChannel channel){ + public void display(MessageChannel channel) + { paginate(channel, 1); } @@ -98,7 +100,8 @@ public void display(MessageChannel channel){ * The Message to display the Menu in */ @Override - public void display(Message message){ + public void display(Message message) + { paginate(message, 1); } @@ -112,7 +115,8 @@ public void display(Message message){ * @param pageNum * The page number to begin on */ - public void paginate(MessageChannel channel, int pageNum){ + public void paginate(MessageChannel channel, int pageNum) + { if(pageNum < 1) pageNum = 1; else if(pageNum > embeds.size()) @@ -131,7 +135,8 @@ else if(pageNum > embeds.size()) * @param pageNum * The page number to begin on */ - public void paginate(Message message, int pageNum){ + public void paginate(Message message, int pageNum) + { if(pageNum < 1) pageNum = 1; else if(pageNum > embeds.size()) @@ -140,9 +145,11 @@ else if(pageNum > embeds.size()) initialize(message.editMessage(msg), pageNum); } - private void initialize(RestAction action, int pageNum){ - action.queue(m->{ - if(embeds.size()>1){ + private void initialize(RestAction action, int pageNum) + { + action.queue(m -> { + if(embeds.size()>1) + { if(bulkSkipNumber > 1) m.addReaction(BIG_LEFT).queue(); m.addReaction(LEFT).queue(); @@ -151,49 +158,61 @@ private void initialize(RestAction action, int pageNum){ m.addReaction(RIGHT).queue(); m.addReaction(bulkSkipNumber > 1 ? BIG_RIGHT : RIGHT) .queue(v -> pagination(m, pageNum), t -> pagination(m, pageNum)); - }else if(waitOnSinglePage){ + } + else if(waitOnSinglePage) + { m.addReaction(STOP).queue(v -> pagination(m, pageNum), t -> pagination(m, pageNum)); - }else{ + } + else + { finalAction.accept(m); } }); } - private void pagination(Message message, int pageNum){ + private void pagination(Message message, int pageNum) + { if(allowTextInput || (leftText != null && rightText != null)) paginationWithTextInput(message, pageNum); else paginationWithoutTextInput(message, pageNum); } - private void paginationWithTextInput(Message message, int pageNum){ + private void paginationWithTextInput(Message message, int pageNum) + { waiter.waitForEvent(GenericMessageEvent.class, event -> { if(event instanceof MessageReactionAddEvent) return checkReaction((MessageReactionAddEvent) event, message.getIdLong()); - else if(event instanceof MessageReceivedEvent){ + else if(event instanceof MessageReceivedEvent) + { MessageReceivedEvent mre = (MessageReceivedEvent) event; if(!mre.getChannel().equals(message.getChannel())) return false; String rawContent = mre.getMessage().getContentRaw().trim(); - if(leftText != null && rightText != null){ + if(leftText != null && rightText != null) + { if(rawContent.equalsIgnoreCase(leftText) || rawContent.equalsIgnoreCase(rightText)) return isValidUser(mre.getAuthor(), mre.isFromGuild() ? mre.getGuild() : null); } - if(allowTextInput){ - try{ + if(allowTextInput) + { + try { int i = Integer.parseInt(rawContent); if(1 <= i && i <= embeds.size() && i != pageNum) return isValidUser(mre.getAuthor(), mre.isFromGuild() ? mre.getGuild() : null); - }catch(NumberFormatException ignored){} + } catch(NumberFormatException ignored) {} } } return false; }, event -> { - if(event instanceof MessageReactionAddEvent){ + if(event instanceof MessageReactionAddEvent) + { handleMessageReactionAddAction((MessageReactionAddEvent)event, message, pageNum); - }else{ + } + else + { MessageReceivedEvent mre = (MessageReceivedEvent) event; String rawContent = mre.getMessage().getContentRaw().trim(); @@ -213,17 +232,20 @@ else if(rightText != null && rawContent.equalsIgnoreCase(rightText) && (pageNum }, timeout, unit, () -> finalAction.accept(message)); } - private void paginationWithoutTextInput(Message message, int pageNum){ + private void paginationWithoutTextInput(Message message, int pageNum) + { waiter.waitForEvent(MessageReactionAddEvent.class, event -> checkReaction(event, message.getIdLong()), event -> handleMessageReactionAddAction(event, message, pageNum), timeout, unit, () -> finalAction.accept(message)); } - private boolean checkReaction(MessageReactionAddEvent event, long messageId){ + private boolean checkReaction(MessageReactionAddEvent event, long messageId) + { if(event.getMessageIdLong() != messageId) return false; - switch(event.getReactionEmote().getName()){ + switch(event.getReactionEmote().getName()) + { case LEFT: case STOP: case RIGHT: @@ -236,10 +258,12 @@ private boolean checkReaction(MessageReactionAddEvent event, long messageId){ } } - private void handleMessageReactionAddAction(MessageReactionAddEvent event, Message message, int pageNum){ + private void handleMessageReactionAddAction(MessageReactionAddEvent event, Message message, int pageNum) + { int newPageNum = pageNum; int pages = embeds.size(); - switch(event.getReaction().getReactionEmote().getName()){ + switch(event.getReaction().getReactionEmote().getName()) + { case LEFT: if(newPageNum == 1 && wrapPageEnds) newPageNum = pages + 1; @@ -253,8 +277,10 @@ private void handleMessageReactionAddAction(MessageReactionAddEvent event, Messa newPageNum++; break; case BIG_LEFT: - if(newPageNum > 1 || wrapPageEnds){ - for(int i = 1; (newPageNum > 1 || wrapPageEnds) && i < bulkSkipNumber; i++){ + if(newPageNum > 1 || wrapPageEnds) + { + for(int i = 1; (newPageNum > 1 || wrapPageEnds) && i < bulkSkipNumber; i++) + { if(newPageNum == 1 && wrapPageEnds) newPageNum = pages + 1; newPageNum--; @@ -262,8 +288,10 @@ private void handleMessageReactionAddAction(MessageReactionAddEvent event, Messa } break; case BIG_RIGHT: - if(newPageNum < pages || wrapPageEnds){ - for(int i = 1; (newPageNum < pages || wrapPageEnds) && i < bulkSkipNumber; i++){ + if(newPageNum < pages || wrapPageEnds) + { + for(int i = 1; (newPageNum < pages || wrapPageEnds) && i < bulkSkipNumber; i++) + { if(newPageNum == pages && wrapPageEnds) newPageNum = 0; newPageNum++; @@ -275,15 +303,16 @@ private void handleMessageReactionAddAction(MessageReactionAddEvent event, Messa return; } - try{ + try { event.getReaction().removeReaction(event.getUser()).queue(); - }catch(PermissionException ignored){} + } catch(PermissionException ignored) {} int n = newPageNum; message.editMessage(renderPage(newPageNum)).queue(m -> pagination(m, n)); } - private Message renderPage(int pageNum){ + private Message renderPage(int pageNum) + { MessageBuilder mbuilder = new MessageBuilder(); MessageEmbed membed = this.embeds.get(pageNum-1); mbuilder.setEmbed(membed); @@ -293,11 +322,13 @@ private Message renderPage(int pageNum){ } /** - * The {@link Menu.Builder Menu.Builder} for a {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator}. + * The {@link com.jagrosh.jdautilities.menu.Menu.Builder Menu.Builder} for + * a {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator}. * * @author Andre_601 */ - public static class Builder extends Menu.Builder{ + public static class Builder extends Menu.Builder + { private BiFunction text = (page, pages) -> null; private Consumer finalAction = m -> m.delete().queue(); @@ -308,7 +339,7 @@ public static class Builder extends Menu.Builder{ private String rightText = null; private boolean allowTextInput = false; - private List embeds = new LinkedList<>(); + private final List embeds = new LinkedList<>(); /** * Builds the {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator} with this Builder. @@ -323,7 +354,8 @@ public static class Builder extends Menu.Builder{ * */ @Override - public EmbedPaginator build(){ + public EmbedPaginator build() + { Checks.check(waiter != null, "Must set an EventWaiter"); Checks.check(!embeds.isEmpty(), "Must include at least one item to paginate"); @@ -338,11 +370,12 @@ public EmbedPaginator build(){ * {@link com.jagrosh.jdautilities.menu.EmbedPaginator EmbedPaginator} is built. * * @param text - * The Message content to be displayed avove the embed when the EmbedPaginator is built. + * The Message content to be displayed above the embed when the EmbedPaginator is built. * * @return This builder */ - public Builder setText(String text){ + public Builder setText(String text) + { this.text = (i0, i1) -> text; return this; } @@ -359,7 +392,8 @@ public Builder setText(String text){ * * @return This builder */ - public Builder setText(BiFunction textBiFunction){ + public Builder setText(BiFunction textBiFunction) + { this.text = textBiFunction; return this; } @@ -373,7 +407,8 @@ public Builder setText(BiFunction textBiFunction){ * * @return This builder */ - public Builder setFinalAction(Consumer finalAction){ + public Builder setFinalAction(Consumer finalAction) + { this.finalAction = finalAction; return this; } @@ -388,7 +423,8 @@ public Builder setFinalAction(Consumer finalAction){ * * @return This builder */ - public Builder waitOnSinglePage(boolean waitOnSinglePage){ + public Builder waitOnSinglePage(boolean waitOnSinglePage) + { this.waitOnSinglePage = waitOnSinglePage; return this; } @@ -398,7 +434,8 @@ public Builder waitOnSinglePage(boolean waitOnSinglePage){ * * @return This builder */ - public Builder clearItems(){ + public Builder clearItems() + { this.embeds.clear(); return this; } @@ -407,11 +444,12 @@ public Builder clearItems(){ * Adds {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to the list of items to paginate. * * @param embeds - * The MessageEmbed list of items to add + * The list of MessageEmbeds to add * * @return This builder */ - public Builder addItems(MessageEmbed... embeds){ + public Builder addItems(MessageEmbed... embeds) + { this.embeds.addAll(Arrays.asList(embeds)); return this; } @@ -424,12 +462,19 @@ public Builder addItems(MessageEmbed... embeds){ * * @param items * The String list of items to add as MessageEmbeds + * + * @throws java.lang.IllegalArgumentException + * When one of the provided Strings is longer than 2048 characters. * * @return This builder */ - public Builder addItems(String... items){ + public Builder addItems(String... items) + { for(String item : items) + { + Checks.check(item.length() <= MessageEmbed.TEXT_MAX_LENGTH, "Text may not be longer than 2048 characters."); this.embeds.add(new EmbedBuilder().setDescription(item).build()); + } return this; } @@ -442,7 +487,8 @@ public Builder addItems(String... items){ * * @return This builder */ - public Builder setItems(MessageEmbed... embeds){ + public Builder setItems(MessageEmbed... embeds) + { this.embeds.clear(); this.embeds.addAll(Arrays.asList(embeds)); return this; @@ -456,10 +502,14 @@ public Builder setItems(MessageEmbed... embeds){ * * @param items * The String list of items to add + * + * @throws java.lang.IllegalArgumentException + * When one of the provided Strings is longer than 2048 characters. * * @return This builder */ - public Builder setItems(String... items){ + public Builder setItems(String... items) + { this.embeds.clear(); addItems(items); return this; @@ -474,8 +524,9 @@ public Builder setItems(String... items){ * * @return This builder */ - public Builder setBulkSkipNumber(int bulkSkipNumber){ - this.bulkSkipNumber = bulkSkipNumber; + public Builder setBulkSkipNumber(int bulkSkipNumber) + { + this.bulkSkipNumber = Math.max(bulkSkipNumber, 1); return this; } @@ -488,7 +539,8 @@ public Builder setBulkSkipNumber(int bulkSkipNumber){ * * @return This builder */ - public Builder wrapPageEnds(boolean wrapPageEnds){ + public Builder wrapPageEnds(boolean wrapPageEnds) + { this.wrapPageEnds = wrapPageEnds; return this; } @@ -506,7 +558,8 @@ public Builder wrapPageEnds(boolean wrapPageEnds){ * * @return This builder */ - public Builder allowTextInput(boolean allowTextInput){ + public Builder allowTextInput(boolean allowTextInput) + { this.allowTextInput = allowTextInput; return this; } @@ -516,6 +569,9 @@ public Builder allowTextInput(boolean allowTextInput){ * when a provided text input is sent in the form of a Message to the * {@link net.dv8tion.jda.api.entities.GuildChannel GuildChannel} the menu is displayed in. * + *

If one or both these parameters are provided {@code null} this resets both of them and they will no + * longer be available when the Paginator is built. + * * @param left * The left text input, causes the EmbedPaginator to traverse one page left. * @param right @@ -523,11 +579,15 @@ public Builder allowTextInput(boolean allowTextInput){ * * @return This builder */ - public Builder setLeftRightText(String left, String right){ - if(left == null || right == null){ + public Builder setLeftRightText(String left, String right) + { + if(left == null || right == null) + { leftText = null; rightText = null; - }else{ + } + else + { leftText = left; rightText = right; } From c45ea7cff1ad3d7780feb9194032bad08f26e0f9 Mon Sep 17 00:00:00 2001 From: Andre601 <11576465+Andre601@users.noreply.github.com> Date: Thu, 11 Mar 2021 12:45:37 +0100 Subject: [PATCH 5/5] Add methods with Collection --- .../jdautilities/menu/EmbedPaginator.java | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java index 3c974b55..f5d7e3ad 100644 --- a/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java +++ b/menu/src/main/java/com/jagrosh/jdautilities/menu/EmbedPaginator.java @@ -26,10 +26,7 @@ import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.internal.utils.Checks; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -454,6 +451,21 @@ public Builder addItems(MessageEmbed... embeds) return this; } + /** + * Adds the collection of provided {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to the list + * of items to paginate. + * + * @param embeds + * The collection of MessageEmbeds to add + * + * @return This builder + */ + public Builder addItems(Collection embeds) + { + this.embeds.addAll(embeds); + return this; + } + /** * Adds {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to the list of items to paginate. *
This method creates a new, basic MessageEmbed containing only the provided String as description. @@ -480,7 +492,7 @@ public Builder addItems(String... items) /** * Sets the {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to paginate. - *
This method clears all previously set items before setting. + *
This method clears all previously set items before adding the provided MessageEmbeds. * * @param embeds * The MessageEmbed list of items to add @@ -490,7 +502,23 @@ public Builder addItems(String... items) public Builder setItems(MessageEmbed... embeds) { this.embeds.clear(); - this.embeds.addAll(Arrays.asList(embeds)); + addItems(Arrays.asList(embeds)); + return this; + } + + /** + * Sets the {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to paginate. + *
This method clears all previously set items before adding the provided collection of MessageEmbeds. + * + * @param embeds + * The collection of MessageEmbeds to set. + * + * @return This builder + */ + public Builder setItems(Collection embeds) + { + this.embeds.clear(); + addItems(embeds); return this; }