Skip to content

Instantly share code, notes, and snippets.

@Shengaero
Last active September 20, 2017 20:13
Show Gist options
  • Save Shengaero/8ee79ce868437c11ef3378c2f700f003 to your computer and use it in GitHub Desktop.
Save Shengaero/8ee79ce868437c11ef3378c2f700f003 to your computer and use it in GitHub Desktop.
The 2.0 version of ButtonMenu.java
/*
* Copyright 2016 John Grosh (jagrosh).
*
* 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.buttonmenu;
import java.awt.Color;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import com.jagrosh.jdautilities.menu.Menu;
import com.jagrosh.jdautilities.waiter.EventWaiter;
import net.dv8tion.jda.core.EmbedBuilder;
import net.dv8tion.jda.core.MessageBuilder;
import net.dv8tion.jda.core.entities.Emote;
import net.dv8tion.jda.core.entities.Message;
import net.dv8tion.jda.core.entities.MessageChannel;
import net.dv8tion.jda.core.entities.MessageReaction.ReactionEmote;
import net.dv8tion.jda.core.entities.Role;
import net.dv8tion.jda.core.entities.User;
import net.dv8tion.jda.core.events.message.react.MessageReactionAddEvent;
import net.dv8tion.jda.core.requests.RestAction;
/**
*
* @author John Grosh
*/
public class ButtonMenu extends Menu
{
private final Color color;
private final String text;
private final String description;
private final List<String> choices;
private final Consumer<ReactionEmote> action;
private final Runnable cancel;
protected ButtonMenu(EventWaiter waiter, Set<User> users, Set<Role> roles, long timeout, TimeUnit unit,
Color color, String text, String description, List<String> choices, Consumer<ReactionEmote> action, Runnable cancel)
{
super(waiter, users, roles, timeout, unit);
this.color = color;
this.text = text;
this.description = description;
this.choices = choices;
this.action = action;
this.cancel = cancel;
}
/**
* Shows the ButtonMenu as a new {@link net.dv8tion.jda.core.entities.Message Message}
* in the provided {@link net.dv8tion.jda.core.entities.MessageChannel MessageChannel}.
*
* @param channel
* The MessageChannel to send the new Message to
*/
@Override
public void display(MessageChannel channel)
{
initialize(channel.sendMessage(getMessage()));
}
/**
* Displays this ButtonMenu by editing the provided {@link net.dv8tion.jda.core.entities.Message Message}.
*
* @param message
* The Message to display the Menu in
*/
@Override
public void display(Message message)
{
initialize(message.editMessage(getMessage()));
}
// Initializes the ButtonMenu using a Message RestAction
// This is either through editing a previously existing Message
// OR through sending a new one to a TextChannel.
private void initialize(RestAction<Message> ra)
{
ra.queue(m -> {
for(int i=0; i<choices.size(); i++)
{
// Get the emote to display.
Emote emote;
try {
emote = m.getJDA().getEmoteById(choices.get(i));
} catch(Exception e) {
emote = null;
}
// If the emote is null that means that it might be an emoji.
// If it's neither, that's on the developer and we'll let it
// throw an error when we queue a rest action.
RestAction<Void> r = emote==null ? m.addReaction(choices.get(i)) : m.addReaction(emote);
if(i+1<choices.size())
r.queue(); // If there is still more reactions to add we delay using the EventWaiter
else
// This is the last reaction added.
r.queue(v -> {
waiter.waitForEvent(MessageReactionAddEvent.class, event -> {
// If the message is not the same as the ButtonMenu
// currently being displayed.
if(!event.getMessageId().equals(m.getId()))
return false;
// If the reaction is an Emote we get the Snowflake,
// otherwise we get the unicode value.
String re = event.getReaction().getEmote().isEmote()
? event.getReaction().getEmote().getId()
: event.getReaction().getEmote().getName();
// If the value we got is not registered as a button to
// the ButtonMenu being displayed we return false.
if(!choices.contains(re))
return false;
// Last check is that the person who added the reaction
// is a valid user.
return isValidUser(event);
}, (MessageReactionAddEvent event) -> {
// What happens next is after a valid event
// is fired and processed above.
// Delete the message
m.delete().queue();
// Preform the specified action with the ReactionEmote
action.accept(event.getReaction().getEmote());
}, timeout, unit, cancel);
});
}
});
}
// Generates a ButtonMenu message
private Message getMessage()
{
MessageBuilder mbuilder = new MessageBuilder();
if(text!=null)
mbuilder.append(text);
if(description!=null)
mbuilder.setEmbed(new EmbedBuilder().setColor(color).setDescription(description).build());
return mbuilder.build();
}
/**
*
* @author John Grosh
*/
public static class Builder extends Menu.Builder<Builder, ButtonMenu>
{
private Color color;
private String text;
private String description;
private final List<String> choices = new LinkedList<>();
private Consumer<ReactionEmote> action;
private Runnable cancel = () -> {};
@Override
public ButtonMenu build() {
if(waiter==null)
throw new IllegalArgumentException("Must set an EventWaiter");
if(choices.isEmpty())
throw new IllegalArgumentException("Must have at least one choice");
if(action==null)
throw new IllegalArgumentException("Must provide an action consumer");
if(text==null && description==null)
throw new IllegalArgumentException("Either text or description must be set");
return new ButtonMenu(waiter, users, roles, timeout, unit, color, text, description, choices, action, cancel);
}
/**
* Sets the {@link java.awt.Color Color} of the {@link net.dv8tion.jda.core.entities.MessageEmbed MessageEmbed},
* if description of the MessageEmbed is set.
*
* @param color
* The Color of the MessageEmbed
*
* @return This builder
*/
@Override
public Builder setColor(Color color) {
this.color = color;
return this;
}
/**
* Sets the text of the {@link net.dv8tion.jda.core.entities.Message Message} to be displayed
* when the {@link com.jagrosh.jdautilities.menu.buttonmenu.ButtonMenu ButtonMenu} is built.
*
* <p>This is displayed directly above the embed.
*
* @param text
* The Message content to be displayed above the embed when the ButtonMenu is built
*
* @return This builder
*/
public Builder setText(String text) {
this.text = text;
return this;
}
/**
* Sets the description to be placed in an {@link net.dv8tion.jda.core.entities.MessageEmbed MessageEmbed}.
* <br>If this is {@code null}, no MessageEmbed will be displayed
*
* @param description
* The content of the MessageEmbed's description
*
* @return This builder
*/
public Builder setDescription(String description) {
this.description = description;
return this;
}
/**
* Sets the {@link java.util.function.Consumer Consumer} action to perform upon selecting a button.
*
* @param action
* The Consumer action to perform upon selecting a button
*
* @return This builder
*/
public Builder setAction(Consumer<ReactionEmote> action) {
this.action = action;
return this;
}
/**
* Sets the {@link java.lang.Runnable Runnable} to perform if the
* {@link com.jagrosh.jdautilities.menu.buttonmenu.ButtonMenu ButtonMenu} times out.
*
* @param cancel
* The Runnable action to perform if the ButtonMenu times out
*
* @return This builder
*/
public Builder setCancel(Runnable cancel) {
this.cancel = cancel;
return this;
}
/**
* Adds a single String unicode emoji as a button choice.
*
* <p>Any non-unicode {@link net.dv8tion.jda.core.entities.Emote Emote} should be
* added using {@link com.jagrosh.jdautilities.menu.buttonmenu.ButtonMenu.Builder#addChoice(Emote)
* ButtonMenu.Builder#addChoice(Emote)}.
*
* @param emoji
* The String unicode emoji to add
*
* @return This builder
*/
public Builder addChoice(String emoji)
{
this.choices.add(emoji);
return this;
}
/**
* Adds a single custom {@link net.dv8tion.jda.core.entities.Emote Emote} as button choices.
*
* <p>Any regular unicode emojis should be added using {@link
* com.jagrosh.jdautilities.menu.buttonmenu.ButtonMenu.Builder#addChoice(String)
* ButtonMenu.Builder#addChoice(String)}.
*
* @param emote
* The Emote object to add
*
* @return This builder
*/
public Builder addChoice(Emote emote)
{
return addChoice(emote.getId());
}
/**
* Adds String unicode emojis as button choices.
*
* <p>Any non-unicode {@link net.dv8tion.jda.core.entities.Emote Emote}s should be
* added using {@link com.jagrosh.jdautilities.menu.buttonmenu.ButtonMenu.Builder#addChoices(Emote...)
* ButtonMenu.Builder#addChoices(Emote...)}.
*
* @param emojis
* The String unicode emojis to add
*
* @return This builder
*/
public Builder addChoices(String... emojis) {
for(String emoji : emojis)
addChoice(emoji);
return this;
}
/**
* Adds custom {@link net.dv8tion.jda.core.entities.Emote Emote}s as button choices.
*
* <p>Any regular unicode emojis should be added using {@link
* com.jagrosh.jdautilities.menu.buttonmenu.ButtonMenu.Builder#addChoices(String...)
* ButtonMenu.Builder#addChoices(String...)}.
*
* @param emotes
* The Emote objects to add
*
* @return This builder
*/
public Builder addChoices(Emote... emotes) {
for(Emote emote : emotes)
addChoice(emote);
return this;
}
/**
* Sets the String unicode emojis as button choices.
*
* <p>Any non-unicode {@link net.dv8tion.jda.core.entities.Emote Emote}s should be
* set using {@link com.jagrosh.jdautilities.menu.buttonmenu.ButtonMenu.Builder#setChoices(Emote...)
* ButtonMenu.Builder#setChoices(Emote...)}.
*
* @param emojis
* The String unicode emojis to set
*
* @return This builder
*/
public Builder setChoices(String... emojis) {
this.choices.clear();
return addChoices(emojis);
}
/**
* Sets the {@link net.dv8tion.jda.core.entities.Emote Emote}s as button choices.
*
* <p>Any regular unicode emojis should be set using {@link
* com.jagrosh.jdautilities.menu.buttonmenu.ButtonMenu.Builder#setChoices(String...)
* ButtonMenu.Builder#setChoices(String...)}.
*
* @param emotes
* The Emote objects to set
*
* @return This builder
*/
public Builder setChoices(Emote... emotes) {
this.choices.clear();
return addChoices(emotes);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment