Skip to content

Commit 0881667

Browse files
committed
Refactor to implement the paginated quote list.
1 parent 40ff38b commit 0881667

File tree

7 files changed

+233
-62
lines changed

7 files changed

+233
-62
lines changed

src/main/java/com/mcmoddev/mmdbot/modules/commands/CommandModule.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.mcmoddev.mmdbot.modules.commands.server.moderation.CmdUser;
4949
import com.mcmoddev.mmdbot.modules.commands.server.quotes.CmdAddQuote;
5050
import com.mcmoddev.mmdbot.modules.commands.server.quotes.CmdGetQuote;
51+
import com.mcmoddev.mmdbot.modules.commands.server.quotes.CmdListQuotes;
5152
import com.mcmoddev.mmdbot.modules.commands.server.quotes.CmdRemoveQuote;
5253
import com.mcmoddev.mmdbot.modules.commands.server.tricks.CmdAddTrick;
5354
import com.mcmoddev.mmdbot.modules.commands.server.tricks.CmdListTricks;
@@ -120,6 +121,7 @@ public static void setupCommandModule() {
120121
.addCommand(new CmdAddQuote())
121122
.addCommand(new CmdGetQuote())
122123
.addCommand(new CmdRemoveQuote())
124+
.addCommand(new CmdListQuotes())
123125
.setHelpWord("help")
124126
.build();
125127

@@ -128,6 +130,7 @@ public static void setupCommandModule() {
128130
MMDBot.getInstance().addEventListener(CmdMappings.ButtonListener.INSTANCE);
129131
MMDBot.getInstance().addEventListener(CmdTranslateMappings.ButtonListener.INSTANCE);
130132
MMDBot.getInstance().addEventListener(new CmdListTricks.ButtonListener());
133+
MMDBot.getInstance().addEventListener(new CmdListQuotes.ButtonListener());
131134
MMDBot.LOGGER.warn("Command module enabled and loaded.");
132135
} else {
133136
MMDBot.LOGGER.warn("Command module disabled via config, commands will not work at this time!");

src/main/java/com/mcmoddev/mmdbot/modules/commands/server/quotes/CmdAddQuote.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public CmdAddQuote() {
5454
super();
5555
name = "addquote";
5656
aliases = new String[] { "add-quote", "quoteadd", "quote-add" };
57-
help = "Adds a new Quote to the list.\nAdd a quote like so: !addquote \"I said something funny - author\"!";
57+
help = "Adds a new Quote to the list.\nAdd a quote like so: !addquote \"I said something funny\" - author";
5858
}
5959

6060
@Override
@@ -75,7 +75,7 @@ protected void execute(final CommandEvent event) {
7575
}
7676

7777
// Verify that there's a message being quoted.
78-
if (!(args[0].charAt(0) == '\"') || !(args[0].charAt(args[0].length() - 3) == '\"') ) {
78+
if (!(args[0].charAt(0) == '\"') || !(args[0].charAt(args[0].length() - 2) == '\"') ) {
7979
channel.sendMessage("Invalid arguments. See the help for this command.").queue();
8080
return;
8181
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package com.mcmoddev.mmdbot.modules.commands.server.quotes;
2+
3+
import com.jagrosh.jdautilities.command.Command;
4+
import com.jagrosh.jdautilities.command.CommandEvent;
5+
import com.mcmoddev.mmdbot.core.Utils;
6+
import com.mcmoddev.mmdbot.utilities.quotes.Quote;
7+
import com.mcmoddev.mmdbot.utilities.quotes.QuoteList;
8+
import net.dv8tion.jda.api.EmbedBuilder;
9+
import net.dv8tion.jda.api.entities.Emoji;
10+
import net.dv8tion.jda.api.entities.TextChannel;
11+
import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
12+
import net.dv8tion.jda.api.hooks.ListenerAdapter;
13+
import net.dv8tion.jda.api.interactions.components.Button;
14+
import net.dv8tion.jda.api.interactions.components.Component;
15+
import net.dv8tion.jda.api.requests.restaction.MessageAction;
16+
import org.jetbrains.annotations.NotNull;
17+
18+
import java.awt.Color;
19+
import java.time.Instant;
20+
import java.util.ArrayList;
21+
import java.util.List;
22+
23+
24+
/**
25+
* Retrieve all quotes from the database.
26+
* Allows an int argument, otherwise starts from 0.
27+
* The int represents the first quote to start with, and will increase from there.
28+
*
29+
* Uses pagination and Interaction buttons.
30+
* Implementation shamelessly stolen from willbl
31+
*
32+
* Possible forms:
33+
* !quotes
34+
* !quotes 155
35+
*
36+
* Can be used by anyone.
37+
*
38+
*
39+
* @author Curle
40+
*/
41+
public class CmdListQuotes extends Command {
42+
43+
private static final int QUOTE_PER_PAGE = 10;
44+
45+
/**
46+
* Create the command.
47+
* Sets all the usual flags.
48+
*/
49+
public CmdListQuotes() {
50+
super();
51+
name = "listquotes";
52+
aliases = new String[] { "quotes", "list-quotes", "quoteslist" };
53+
help = "Get all quotes. Specify a starting number if you like, otherwise starts from 0.";
54+
}
55+
56+
57+
@Override
58+
protected void execute(final CommandEvent event) {
59+
if (!Utils.checkCommand(this, event))
60+
return;
61+
62+
final TextChannel channel = event.getTextChannel();
63+
String argsFull = event.getArgs();
64+
String[] args = argsFull.split(" ");
65+
66+
int start = 0;
67+
if(args.length > 1) {
68+
start = Integer.parseInt(args[0]);
69+
}
70+
71+
MessageAction sentMessage = event.getChannel().sendMessageEmbeds(getQuotes(start).build());
72+
73+
Component[] buttons = createButtons(start);
74+
if (buttons.length > 0)
75+
sentMessage.setActionRow(buttons);
76+
77+
sentMessage.queue();
78+
79+
}
80+
81+
/**
82+
* Create the row of Component interaction buttons.
83+
*
84+
* Currently, this just creates a left and right arrow.
85+
* Left arrow scrolls back a page. Right arrow scrolls forward a page.
86+
* @param start The quote number at the start of the current page.
87+
* @return A row of buttons to go back and forth by one page in a quote list.
88+
*/
89+
private static Component[] createButtons(int start) {
90+
List<Component> components = new ArrayList<>();
91+
if (start != 0) {
92+
components.add(Button.secondary(ButtonListener.BUTTON_ID_PREFIX + "-" + start + "-prev", Emoji.fromUnicode("◀️")));
93+
}
94+
if (start + QUOTE_PER_PAGE < QuoteList.getQuoteSlot()) {
95+
components.add(Button.primary(ButtonListener.BUTTON_ID_PREFIX + "-" + start + "-next", Emoji.fromUnicode("▶️")));
96+
}
97+
return components.toArray(new Component[0]);
98+
}
99+
100+
/**
101+
* Gather a page of quotes, as an embed.
102+
*
103+
* @param start The quote number at the start of the current page.
104+
* @return An EmbedBuilder which is ready to be sent.
105+
*/
106+
private static EmbedBuilder getQuotes(int start) {
107+
// Build the list in a StringBuilder.
108+
StringBuilder str = new StringBuilder();
109+
110+
// From the specified starting point until the end of the page..
111+
for (int x = start; x < start + QUOTE_PER_PAGE; x++) {
112+
// But stop early if we hit the end of the list,
113+
if (x >= QuoteList.getQuoteSlot())
114+
break;
115+
116+
// Get the current Quote
117+
Quote fetchedQuote = QuoteList.getQuote(x);
118+
119+
// Put it in the description.
120+
// message - author
121+
str.append(fetchedQuote == null ? "Quote does not exist." :
122+
fetchedQuote.getQuoteText() + " - " + fetchedQuote.getQuotee().resolveReference());
123+
124+
str.append("\n");
125+
}
126+
127+
// We have to make sure that this doesn't crash if we list a fresh bot.
128+
if (str.length() == 0)
129+
return new EmbedBuilder()
130+
.setColor(Color.GREEN)
131+
.setDescription("There are no quotes loaded currently.")
132+
.setTimestamp(Instant.now());
133+
else
134+
return new EmbedBuilder()
135+
.setColor(Color.GREEN)
136+
.setTitle("Quote Page " + ((start / QUOTE_PER_PAGE) + 1))
137+
.setDescription(str.toString())
138+
.setTimestamp(Instant.now());
139+
140+
}
141+
142+
public static class ButtonListener extends ListenerAdapter {
143+
private static final String BUTTON_ID_PREFIX = "quotelist";
144+
145+
@Override
146+
public void onButtonClick(@NotNull final ButtonClickEvent event) {
147+
var button = event.getButton();
148+
if (button == null || button.getId() == null) {
149+
return;
150+
}
151+
152+
String[] idParts = button.getId().split("-");
153+
if (idParts.length != 3) {
154+
return;
155+
}
156+
157+
if (!idParts[0].equals(BUTTON_ID_PREFIX)) {
158+
return;
159+
}
160+
161+
int current = Integer.parseInt(idParts[1]);
162+
163+
if (idParts[2].equals("next")) {
164+
event
165+
.editMessageEmbeds(getQuotes(current + QUOTE_PER_PAGE).build())
166+
.setActionRow(createButtons(current + QUOTE_PER_PAGE))
167+
.queue();
168+
} else if (idParts[2].equals("prev")) {
169+
event
170+
.editMessageEmbeds(getQuotes(current - QUOTE_PER_PAGE).build())
171+
.setActionRow(createButtons(current - QUOTE_PER_PAGE))
172+
.queue();
173+
}
174+
}
175+
}
176+
}

src/main/java/com/mcmoddev/mmdbot/utilities/quotes/IQuote.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,10 @@ public interface IQuote {
8383
*/
8484
MessageEmbed getQuoteMessage();
8585

86+
/**
87+
* Get the closest text representation of the thing being quoted.
88+
* @return Depends on the subclass.
89+
*/
90+
String getQuoteText();
91+
8692
}

src/main/java/com/mcmoddev/mmdbot/utilities/quotes/NullQuote.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ public MessageEmbed getQuoteMessage() {
3434
return QuoteList.getQuoteNotPresent();
3535
}
3636

37+
@Override
38+
public String getQuoteText() {
39+
return "Quote not found.";
40+
}
41+
3742
/**
3843
* Create a new NullQuote.
3944
*/

src/main/java/com/mcmoddev/mmdbot/utilities/quotes/StringQuote.java

Lines changed: 12 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,8 @@
2020
*/
2121
package com.mcmoddev.mmdbot.utilities.quotes;
2222

23-
import com.mcmoddev.mmdbot.MMDBot;
24-
import com.mcmoddev.mmdbot.core.References;
2523
import net.dv8tion.jda.api.EmbedBuilder;
2624
import net.dv8tion.jda.api.entities.MessageEmbed;
27-
import net.dv8tion.jda.api.entities.User;
28-
import net.dv8tion.jda.internal.entities.UserById;
2925

3026
import java.awt.Color;
3127
import java.time.Instant;
@@ -65,63 +61,19 @@ protected String getData() {
6561

6662
@Override
6763
public MessageEmbed getQuoteMessage() {
68-
EmbedBuilder builder = new EmbedBuilder();
69-
builder.setTitle("Quote " + this.getID());
70-
builder.setColor(Color.GREEN);
71-
builder.addField("Content", this.getData(), false);
72-
73-
// Resolve the person being quoted.
74-
UserReference quotee = this.getQuotee();
75-
switch (quotee.getReferenceType()) {
76-
case SNOWFLAKE:
77-
// Try to find the user's data in a server
78-
User user = MMDBot.getInstance().getUserById(quotee.getSnowflakeData());
79-
// If we have it...
80-
if (user != null) {
81-
// Use it
82-
builder.addField("Author", user.getAsTag(), false);
83-
} else {
84-
// Otherwise, fall back to the snowflake.
85-
builder.addField("Author", Long.toString(quotee.getSnowflakeData()), false);
86-
}
87-
break;
88-
case STRING:
89-
builder.addField("Author", quotee.getStringData(), false);
90-
break;
91-
92-
case ANONYMOUS: // Intentional fallthrough.
93-
default:
94-
builder.addField("Author", quotee.getAnonymousData(), false);
95-
break;
96-
}
97-
98-
// Resolve the person that made the quote..
99-
UserReference author = this.getQuoteAuthor();
100-
switch (author.getReferenceType()) {
101-
case SNOWFLAKE:
102-
// Try to find the user's data in a server
103-
User user = MMDBot.getInstance().getUserById(author.getSnowflakeData());
104-
// If we have it...
105-
if (user != null) {
106-
// Use it
107-
builder.setFooter("Quoted by " + user.getAsTag());
108-
} else {
109-
// Otherwise, fall back to the snowflake.
110-
builder.setFooter("Quoted by " + author.getSnowflakeData());
111-
}
112-
break;
113-
case STRING:
114-
builder.setFooter("Quoted by " + author.getStringData());
115-
break;
116-
117-
case ANONYMOUS: // Intentional fallthrough.
118-
default:
119-
builder.setFooter("Quoted by " + author.getAnonymousData());
120-
break;
121-
}
64+
return new EmbedBuilder()
65+
.setTitle("Quote " + this.getID())
66+
.setColor(Color.GREEN)
67+
.addField("Content", this.getData(), false)
68+
.addField("Author", quotee.resolveReference(), false)
69+
.setFooter("Quoted by " + creator.resolveReference())
70+
.setTimestamp(Instant.now())
71+
.build();
72+
}
12273

123-
builder.setTimestamp(Instant.now());
124-
return builder.build();
74+
@Override
75+
public String getQuoteText() {
76+
return data;
12577
}
12678

12779
/**

src/main/java/com/mcmoddev/mmdbot/utilities/quotes/UserReference.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
*/
2121
package com.mcmoddev.mmdbot.utilities.quotes;
2222

23+
import com.mcmoddev.mmdbot.MMDBot;
24+
import net.dv8tion.jda.api.entities.User;
25+
2326
/**
2427
* The information containing "who" or "what" a quote is referencing.
2528
* Can be for either the thing being quoted, or the thing that created the quote.
@@ -126,6 +129,32 @@ public String getAnonymousData() {
126129
return anonymousData;
127130
}
128131

132+
/**
133+
* Convert the Reference to its closest String representation.
134+
* @return A mention if the user is a Snowflake and is in the current guild,
135+
* An ID if the user is a snowflake and is not in the current guild,
136+
* A message if the user is anonymous or String.
137+
*/
138+
public String resolveReference() {
139+
switch (getReferenceType()) {
140+
case SNOWFLAKE:
141+
// Try to find the user's data in a server
142+
User user = MMDBot.getInstance().getUserById(getSnowflakeData());
143+
// If we have it...
144+
if (user != null) {
145+
return user.getAsTag();
146+
} else {
147+
return String.valueOf(getSnowflakeData());
148+
}
149+
case STRING:
150+
return getStringData();
151+
152+
case ANONYMOUS: // Intentional fallthrough.
153+
default:
154+
return getAnonymousData();
155+
}
156+
}
157+
129158
/**
130159
* A Quote can reference one of these things:
131160
* - A Discord user

0 commit comments

Comments
 (0)