use of net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent in project Pagination-Utils by ygimenez.
the class Pages method categorize.
/**
* Adds menu-like buttons to the specified {@link Message}/{@link MessageEmbed}
* which will browse through a given {@link Map} of pages. You may only specify
* one {@link Page} per button, adding another button with an existing unicode
* will overwrite the current button's {@link Page}. You can specify how long
* the listener will stay active before shutting down itself after a no-activity
* interval.
*
* @param msg The {@link Message} sent which will be categorized.
* @param categories The categories to be shown. The categories are defined by
* a {@link Map} containing emoji unicodes or emote ids as keys and
* {@link Pages} as values.
* @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
* {@link Message} was not sent by the bot.
* @param time The time before the listener automatically stop listening
* for further events (recommended: 60).
* @param unit The time's {@link TimeUnit} (recommended:
* {@link TimeUnit#SECONDS}).
* @param canInteract {@link Predicate} to determine whether the {@link User}
* that pressed the button can interact with it or not.
* @throws ErrorResponseException Thrown if the {@link Message} no longer exists
* or cannot be accessed when triggering a
* {@link GenericMessageReactionEvent}.
* @throws InsufficientPermissionException Thrown if this library cannot remove reactions
* due to lack of bot permission.
* @throws InvalidStateException Thrown if the library wasn't activated.
*/
public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
if (!isActivated())
throw new InvalidStateException();
boolean useBtns = useButtons && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
Map<Emoji, Page> cats = Collections.unmodifiableMap(categories);
clearButtons(msg);
clearReactions(msg);
if (useBtns) {
List<ActionRow> rows = new ArrayList<>();
List<Component> row = new ArrayList<>();
for (Emoji k : cats.keySet()) {
if (row.size() == 5) {
rows.add(ActionRow.of(row));
row = new ArrayList<>();
}
row.add(Button.secondary(Emote.getId(k), k));
}
Button button = Button.danger(CANCEL.name(), paginator.getEmote(CANCEL));
if (rows.size() == 5 && row.size() == 5) {
row.set(4, button);
} else if (row.size() == 5) {
rows.add(ActionRow.of(row));
row = new ArrayList<>();
row.add(button);
} else {
row.add(button);
}
rows.add(ActionRow.of(row));
msg.editMessageComponents(rows).submit();
} else {
for (Emoji k : cats.keySet()) {
msg.addReaction(k.getAsMention().replaceAll("[<>]", "")).submit();
}
msg.addReaction(paginator.getStringEmote(CANCEL)).submit();
}
return handler.addEvent(msg, new ThrowingBiConsumer<>() {
private Emoji currCat = null;
private ScheduledFuture<?> timeout;
private final Consumer<Void> success = s -> {
if (timeout != null)
timeout.cancel(true);
handler.removeEvent(msg);
if (paginator.isDeleteOnCancel())
msg.delete().submit();
};
{
if (time > 0 && unit != null)
timeout = executor.schedule(() -> finalizeEvent(msg, success), time, unit);
}
@Override
public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
Message m = subGet(wrapper.retrieveMessage());
if (canInteract == null || canInteract.test(u)) {
if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
return;
Emoji emoji = null;
Emote emt = NONE;
if (wrapper.getContent() instanceof MessageReaction) {
MessageReaction.ReactionEmote reaction = ((MessageReaction) wrapper.getContent()).getReactionEmote();
emoji = toEmoji(reaction);
emt = toEmote(reaction);
} else if (wrapper.getContent() instanceof Button) {
Button btn = (Button) wrapper.getContent();
emoji = btn.getEmoji();
if (btn.getId() != null && Emote.isNative(btn) && !btn.getId().contains(".")) {
emt = Emote.valueOf(btn.getId().replace("*", ""));
}
}
if (emt == CANCEL) {
finalizeEvent(m, success);
return;
} else if (emoji != null && !Objects.equals(emoji, currCat)) {
Page pg = cats.get(emoji);
if (pg != null) {
if (currCat != null && pg instanceof InteractPage) {
modifyButtons(m, Map.of(Emote.getId(currCat), Button::asEnabled));
}
updatePage(m, pg);
currCat = emoji;
if (pg instanceof InteractPage) {
modifyButtons(m, Map.of(Emote.getId(currCat), Button::asDisabled));
}
}
}
if (timeout != null)
timeout.cancel(true);
if (time > 0 && unit != null)
timeout = executor.schedule(() -> finalizeEvent(m, success), time, unit);
if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
}
}
}
});
}
use of net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent in project Pagination-Utils by ygimenez.
the class Pages method paginate.
/**
* Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
* which will navigate through a given {@link List} of pages. You can specify
* how long the listener will stay active before shutting down itself after a
* no-activity interval.
*
* @param msg The {@link Message} sent which will be paginated.
* @param pages The pages to be shown. The order of the {@link List} will
* define the order of the pages.
* @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
* {@link Message} was not sent by the bot.
* @param time The time before the listener automatically stop listening
* for further events (recommended: 60).
* @param unit The time's {@link TimeUnit} (recommended:
* {@link TimeUnit#SECONDS}).
* @param skipAmount The amount of pages to be skipped when clicking {@link Emote#SKIP_BACKWARD}
* and {@link Emote#SKIP_FORWARD} buttons.
* @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
* @param canInteract {@link Predicate} to determine whether the {@link User}
* that pressed the button can interact with it or not.
* @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
* is still being processed or was already removed (ie. garbage collected).
* @throws ErrorResponseException Thrown if the {@link Message} no longer exists
* or cannot be accessed when triggering a
* {@link GenericMessageReactionEvent}.
* @throws InsufficientPermissionException Thrown if this library cannot remove reactions
* due to lack of bot permission.
* @throws InvalidStateException Thrown if the library wasn't activated or the page list is empty.
*/
public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
if (!isActivated() || pages.isEmpty())
throw new InvalidStateException();
boolean useBtns = useButtons && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
List<Page> pgs = Collections.unmodifiableList(pages);
clearButtons(msg);
clearReactions(msg);
Page pg = pgs.get(0);
if (useBtns)
addButtons((InteractPage) pg, msg, skipAmount > 1, fastForward);
else
addReactions(msg, skipAmount > 1, fastForward);
return handler.addEvent(msg, new ThrowingBiConsumer<>() {
private final int maxP = pgs.size() - 1;
private int p = 0;
private ScheduledFuture<?> timeout;
private final Consumer<Void> success = s -> {
if (timeout != null)
timeout.cancel(true);
handler.removeEvent(msg);
if (paginator.isDeleteOnCancel())
msg.delete().submit();
};
private final Function<Button, Button> LOWER_BOUNDARY_CHECK = b -> b.withDisabled(p == 0);
private final Function<Button, Button> UPPER_BOUNDARY_CHECK = b -> b.withDisabled(p == maxP);
{
if (time > 0 && unit != null)
timeout = executor.schedule(() -> finalizeEvent(msg, success), time, unit);
}
@Override
public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
Message m = subGet(wrapper.retrieveMessage());
if (canInteract == null || canInteract.test(u)) {
if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
return;
Emote emt = NONE;
if (wrapper.getContent() instanceof MessageReaction) {
MessageReaction.ReactionEmote reaction = ((MessageReaction) wrapper.getContent()).getReactionEmote();
emt = toEmote(reaction);
} else if (wrapper.getContent() instanceof Button) {
Button btn = (Button) wrapper.getContent();
if (btn.getId() != null && Emote.isNative(btn) && !btn.getId().contains(".")) {
emt = Emote.valueOf(btn.getId().replace("*", ""));
}
}
Page pg;
boolean update = false;
switch(emt) {
case PREVIOUS:
if (p > 0) {
p--;
update = true;
}
break;
case NEXT:
if (p < maxP) {
p++;
update = true;
}
break;
case SKIP_BACKWARD:
if (p > 0) {
p -= (p - skipAmount < 0 ? p : skipAmount);
update = true;
}
break;
case SKIP_FORWARD:
if (p < maxP) {
p += (p + skipAmount > maxP ? maxP - p : skipAmount);
update = true;
}
break;
case GOTO_FIRST:
if (p > 0) {
p = 0;
update = true;
}
break;
case GOTO_LAST:
if (p < maxP) {
p = maxP;
update = true;
}
break;
case CANCEL:
finalizeEvent(m, success);
return;
}
if (update) {
pg = pgs.get(p);
updatePage(m, pg);
updateButtons(m, pg, useBtns, skipAmount > 1, fastForward);
if (pg instanceof InteractPage) {
modifyButtons(m, Map.of(PREVIOUS.name(), LOWER_BOUNDARY_CHECK, SKIP_BACKWARD.name(), LOWER_BOUNDARY_CHECK, GOTO_FIRST.name(), LOWER_BOUNDARY_CHECK, NEXT.name(), UPPER_BOUNDARY_CHECK, SKIP_FORWARD.name(), UPPER_BOUNDARY_CHECK, GOTO_LAST.name(), UPPER_BOUNDARY_CHECK));
}
}
if (timeout != null)
timeout.cancel(true);
if (time > 0 && unit != null)
timeout = executor.schedule(() -> finalizeEvent(m, success), time, unit);
if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
}
}
}
});
}
use of net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent in project Pagination-Utils by ygimenez.
the class Pages method lazyPaginate.
/**
* Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
* which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
* this pagination type cannot have skip nor fast-forward buttons given the unknown page limit
* You can specify how long the listener will stay active before shutting down itself after a
* no-activity interval.
*
* @param msg The {@link Message} sent which will be paginated.
* @param pageLoader {@link ThrowingFunction}<{@link Integer}, {@link Page}> to generate the next page. If this
* returns null the method will treat it as last page, preventing unnecessary updates.
* @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
* {@link Message} was not sent by the bot.
* @param cache Enables {@link Page} caching, saving previously visited pages.
* @param time The time before the listener automatically stop listening
* for further events (recommended: 60).
* @param unit The time's {@link TimeUnit} (recommended:
* {@link TimeUnit#SECONDS}).
* @param canInteract {@link Predicate} to determine whether the {@link User}
* that pressed the button can interact with it or not.
* @throws ErrorResponseException Thrown if the {@link Message} no longer exists
* or cannot be accessed when triggering a
* {@link GenericMessageReactionEvent}.
* @throws InsufficientPermissionException Thrown if this library cannot remove reactions
* due to lack of bot permission.
* @throws InvalidStateException Thrown if the library wasn't activated or first page cannot be generated.
*/
public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, boolean cache, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
if (!isActivated())
throw new InvalidStateException();
boolean useBtns = useButtons && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
clearButtons(msg);
clearReactions(msg);
List<Page> pageCache = cache ? new ArrayList<>() : null;
Page pg = pageLoader.apply(0);
if (pg == null) {
throw new InvalidStateException();
}
if (cache)
pageCache.add(pg);
if (useBtns)
addButtons((InteractPage) pg, msg, false, false);
else
addReactions(msg, false, false);
return handler.addEvent(msg, new ThrowingBiConsumer<>() {
private int p = 0;
private ScheduledFuture<?> timeout;
private final Consumer<Void> success = s -> {
if (timeout != null)
timeout.cancel(true);
handler.removeEvent(msg);
if (paginator.isDeleteOnCancel())
msg.delete().submit();
};
{
if (time > 0 && unit != null)
timeout = executor.schedule(() -> finalizeEvent(msg, success), time, unit);
}
@Override
public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
Message m = subGet(wrapper.retrieveMessage());
if (canInteract == null || canInteract.test(u)) {
if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
return;
Emote emt = NONE;
if (wrapper.getContent() instanceof MessageReaction) {
MessageReaction.ReactionEmote reaction = ((MessageReaction) wrapper.getContent()).getReactionEmote();
emt = toEmote(reaction);
} else if (wrapper.getContent() instanceof Button) {
Button btn = (Button) wrapper.getContent();
if (btn.getId() != null && Emote.isNative(btn) && !btn.getId().contains(".")) {
emt = Emote.valueOf(btn.getId().replace("*", ""));
}
}
Page pg;
switch(emt) {
case PREVIOUS:
if (p > 0) {
p--;
pg = cache ? pageCache.get(p) : pageLoader.apply(p);
updatePage(m, pg);
updateButtons(m, pg, useBtns, false, false);
}
break;
case NEXT:
p++;
if (cache && pageCache.size() > p) {
pg = pageCache.get(p);
} else {
pg = pageLoader.apply(p);
if (pg == null) {
p--;
return;
}
}
updatePage(m, pg);
updateButtons(m, pg, useBtns, false, false);
if (cache)
pageCache.add(pg);
break;
case CANCEL:
finalizeEvent(m, success);
return;
}
if (timeout != null)
timeout.cancel(true);
if (time > 0 && unit != null)
timeout = executor.schedule(() -> finalizeEvent(m, success), time, unit);
if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
}
}
}
});
}
use of net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent in project Pagination-Utils by ygimenez.
the class Pages method buttonize.
/**
* Adds buttons to the specified {@link Message}/{@link MessageEmbed}, with each
* executing a specific task on click. You may only specify one {@link Runnable}
* per button, adding another button with an existing unicode will overwrite the
* current button's {@link Runnable}. You can specify the time in which the
* listener will automatically stop itself after a no-activity interval.
*
* @param msg The {@link Message} sent which will be buttoned.
* @param buttons The buttons to be shown. The buttons are defined by a
* Map containing emoji unicodes or emote ids as keys and
* {@link ThrowingTriConsumer}<{@link Member}, {@link Message}, {@link InteractionHook}>
* containing desired behavior as value.
* @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
* {@link Message} was not sent by the bot.
* @param showCancelButton Should the {@link Emote#CANCEL} button be created automatically?
* @param time The time before the listener automatically stop
* listening for further events (recommended: 60).
* @param unit The time's {@link TimeUnit} (recommended:
* {@link TimeUnit#SECONDS}).
* @param canInteract {@link Predicate} to determine whether the
* {@link User} that pressed the button can interact
* with it or not.
* @param onCancel Action to be run after the listener is removed.
* @throws ErrorResponseException Thrown if the {@link Message} no longer exists
* or cannot be accessed when triggering a
* {@link GenericMessageReactionEvent}.
* @throws InsufficientPermissionException Thrown if this library cannot remove reactions
* due to lack of bot permission.
* @throws InvalidStateException Thrown if the library wasn't activated.
*/
public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
if (!isActivated())
throw new InvalidStateException();
boolean useBtns = useButtons && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
Map<Emoji, ThrowingConsumer<ButtonWrapper>> btns = Collections.unmodifiableMap(buttons);
clearButtons(msg);
clearReactions(msg);
if (useBtns) {
List<ActionRow> rows = new ArrayList<>();
List<Component> row = new ArrayList<>();
for (Emoji k : btns.keySet()) {
if (row.size() == 5) {
rows.add(ActionRow.of(row));
row = new ArrayList<>();
}
row.add(Button.secondary(Emote.getId(k), k));
}
if (!btns.containsKey(paginator.getEmote(CANCEL)) && showCancelButton) {
Button button = Button.danger(CANCEL.name(), paginator.getEmote(CANCEL));
if (rows.size() == 5 && row.size() == 5) {
row.set(4, button);
} else if (row.size() == 5) {
rows.add(ActionRow.of(row));
row = new ArrayList<>();
row.add(button);
} else {
row.add(button);
}
}
rows.add(ActionRow.of(row));
msg.editMessageComponents(rows).submit();
} else {
for (Emoji k : btns.keySet()) {
msg.addReaction(k.getAsMention().replaceAll("[<>]", "")).submit();
}
if (!btns.containsKey(paginator.getEmote(CANCEL)) && showCancelButton)
msg.addReaction(paginator.getStringEmote(CANCEL)).submit();
}
return handler.addEvent(msg, new ThrowingBiConsumer<>() {
private ScheduledFuture<?> timeout;
private final Consumer<Void> success = s -> {
if (timeout != null)
timeout.cancel(true);
handler.removeEvent(msg);
if (onCancel != null)
onCancel.accept(msg);
if (paginator.isDeleteOnCancel())
msg.delete().submit();
};
{
if (time > 0 && unit != null)
timeout = executor.schedule(() -> finalizeEvent(msg, success), time, unit);
}
@Override
public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
Message m = subGet(wrapper.retrieveMessage());
if (canInteract == null || canInteract.test(u)) {
if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
return;
Emoji emoji = null;
Emote emt = NONE;
if (wrapper.getContent() instanceof MessageReaction) {
MessageReaction.ReactionEmote reaction = ((MessageReaction) wrapper.getContent()).getReactionEmote();
emoji = toEmoji(reaction);
emt = toEmote(reaction);
} else if (wrapper.getContent() instanceof Button) {
Button btn = (Button) wrapper.getContent();
emoji = btn.getEmoji();
if (btn.getId() != null && Emote.isNative(btn) && !btn.getId().contains(".")) {
emt = Emote.valueOf(btn.getId().replace("*", ""));
}
}
if ((!btns.containsKey(paginator.getEmote(CANCEL)) && showCancelButton) && emt == CANCEL) {
finalizeEvent(m, success);
return;
}
InteractionHook hook;
if (wrapper.getSource() instanceof ButtonClickEvent) {
hook = ((ButtonClickEvent) wrapper.getSource()).getHook();
} else {
hook = null;
}
ThrowingConsumer<ButtonWrapper> act = btns.get(emoji);
if (act != null) {
act.accept(new ButtonWrapper(wrapper.getUser(), hook, m));
}
if (timeout != null)
timeout.cancel(true);
if (time > 0 && unit != null)
timeout = executor.schedule(() -> finalizeEvent(m, success), time, unit);
if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
}
}
}
});
}
Aggregations