diff --git a/.classpath b/.classpath
index d91be04..2d9bac5 100644
--- a/.classpath
+++ b/.classpath
@@ -39,17 +39,11 @@
-
-
-
-
-
-
diff --git a/pom.xml b/pom.xml
index ede01b5..5dd077b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,30 +1,31 @@
-
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.4.5
-
+
net.foxgenesis
customjail
0.1.0
Custom Jail
Demo project for Spring Boot
-
+
-
+
-
+
-
-
-
-
+
+
+
+
17
@@ -34,13 +35,13 @@
org.springframework.boot
spring-boot-starter
-
+
net.foxgenesis
watame
0.1.0
-
+
net.foxgenesis
role-storage
@@ -58,5 +59,11 @@
spring-boot-configuration-processor
true
+
+
+ org.projectlombok
+ lombok
+ true
+
diff --git a/src/main/java/net/foxgenesis/customjail/CommonMessages.java b/src/main/java/net/foxgenesis/customjail/CommonMessages.java
new file mode 100644
index 0000000..6091e88
--- /dev/null
+++ b/src/main/java/net/foxgenesis/customjail/CommonMessages.java
@@ -0,0 +1,41 @@
+package net.foxgenesis.customjail;
+
+import java.util.Objects;
+
+import org.springframework.context.MessageSourceResolvable;
+
+public enum CommonMessages implements MessageSourceResolvable {
+ MEMBER("customjail.embed.member"),
+ MODERATOR("customjail.embed.moderator"),
+ ANONYMOUS("customjail.anonymous"),
+ ACCEPT("customjail.embed.accept"),
+ ACCEPTED("customjail.embed.accepted"),
+ YES("customjail.embed.yes"),
+ NO("customjail.embed.no"),
+ REASON("customjail.embed.reason"),
+ DEFAULT_REASON("customjail.embed.defaultReason"),
+ WARNING_LEVEL("customjail.embed.warning-level"),
+ TOTAL_WARNINGS("customjail.embed.total-warnings"),
+ WARNING_EXPIRES("customjail.embed.warning-expires"),
+ WITH_WARNING("customjail.embed.with-warning"),
+ NA("customjail.embed.na"),
+ CASE_ID("customjail.embed.caseid"),
+ DURATION("customjail.embed.duration"),
+ TIME_LEFT("customjail.embed.time-left"),
+ JAIL_DETAILS("customjail.container.jaildetails"),
+ UNJAIL("customjail.embed.unjail"),
+ FORCESTART("customjail.embed.forcestart"),
+ MEMBER_JAILED("customjail.embed.jailed");
+
+ private final String[] codes;
+
+ CommonMessages(String code) {
+ this.codes = new String[] { Objects.requireNonNull(code) };
+ }
+
+ @Override
+ public String[] getCodes() {
+ return codes;
+ }
+
+}
diff --git a/src/main/java/net/foxgenesis/customjail/CustomJailAutoConfiguration.java b/src/main/java/net/foxgenesis/customjail/CustomJailAutoConfiguration.java
index 0b86e46..df53819 100644
--- a/src/main/java/net/foxgenesis/customjail/CustomJailAutoConfiguration.java
+++ b/src/main/java/net/foxgenesis/customjail/CustomJailAutoConfiguration.java
@@ -27,6 +27,7 @@
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.interactions.DiscordLocale;
+import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.Command;
import net.dv8tion.jda.api.interactions.commands.Command.Choice;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
@@ -194,7 +195,7 @@ private static CommandData user(String id, DefaultMemberPermissions permissions,
LocalizationFunction localization) {
return Commands.user(id)
// Set guild only
- .setGuildOnly(true)
+ .setContexts(InteractionContextType.GUILD)
// Set default permissions
.setDefaultPermissions(permissions)
// Set localization
@@ -205,7 +206,7 @@ private static SlashCommandData slash(String id, String description, DefaultMemb
LocalizationFunction localization) {
return Commands.slash(id, description)
// Set guild only
- .setGuildOnly(true)
+ .setContexts(InteractionContextType.GUILD)
// Set default permissions
.setDefaultPermissions(permissions)
// Set localization
diff --git a/src/main/java/net/foxgenesis/customjail/JailFrontend.java b/src/main/java/net/foxgenesis/customjail/JailFrontend.java
index c519570..65d30ce 100644
--- a/src/main/java/net/foxgenesis/customjail/JailFrontend.java
+++ b/src/main/java/net/foxgenesis/customjail/JailFrontend.java
@@ -4,51 +4,47 @@
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.springframework.beans.factory.annotation.Autowired;
-
+import org.springframework.context.MessageSourceResolvable;
+
+import net.dv8tion.jda.api.components.label.Label;
+import net.dv8tion.jda.api.components.selections.SelectMenu;
+import net.dv8tion.jda.api.components.selections.SelectOption;
+import net.dv8tion.jda.api.components.selections.StringSelectMenu;
+import net.dv8tion.jda.api.components.textdisplay.TextDisplay;
+import net.dv8tion.jda.api.components.textinput.TextInput;
+import net.dv8tion.jda.api.components.textinput.TextInputStyle;
import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.User;
-import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent;
-import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
-import net.dv8tion.jda.api.interactions.components.ActionRow;
-import net.dv8tion.jda.api.interactions.components.buttons.Button;
-import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
-import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
-import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
-import net.dv8tion.jda.api.interactions.components.text.TextInput;
-import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
-import net.dv8tion.jda.api.interactions.modals.Modal;
+import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
+import net.dv8tion.jda.api.utils.MarkdownUtil;
import net.foxgenesis.customjail.database.warning.Warning;
import net.foxgenesis.customjail.jail.JailDetails;
import net.foxgenesis.customjail.jail.JailSystem;
import net.foxgenesis.customjail.jail.exception.LocalizedException;
import net.foxgenesis.customjail.util.CustomTime;
import net.foxgenesis.customjail.util.Utilities;
-import net.foxgenesis.watame.util.discord.Colors;
import net.foxgenesis.watame.util.discord.DiscordUtils;
-import net.foxgenesis.watame.util.discord.InteractionListener;
-import net.foxgenesis.watame.util.discord.Response;
+import net.foxgenesis.watame.util.discord.components.Response;
import net.foxgenesis.watame.util.lang.DiscordLocaleMessageSource;
-import net.foxgenesis.watame.util.lang.LocalizedEmbedBuilder;
+import net.foxgenesis.watame.util.lang.Localized;
+import net.foxgenesis.watame.util.lang.LocalizedContainerBuilder;
+import net.foxgenesis.watame.util.lang.LocalizedModalBuilder;
public class JailFrontend extends ListenerAdapter {
@@ -70,7 +66,8 @@ public void onUserContextInteraction(UserContextInteractionEvent event) {
if (jail.isJailed(event.getTargetMember()))
error(event, "customjail.alreadyJailed").queue();
else
- new JailUserListener(event);
+// new JailUserListener(event);
+ displayJailModal(event);
}
case "Jail Details" -> {
@@ -81,33 +78,22 @@ public void onUserContextInteraction(UserContextInteractionEvent event) {
if (!jail.isJailed(member))
error(event, "customjail.notJailed").queue();
else if (isNonBotUser(event, member)) {
- Optional jailEndTimestamp = jail.getJailEndTimestamp(member);
- boolean isTimerRunning = jailEndTimestamp.isPresent();
-
// Create embed
JailDetails details = jail.getJailDetails(member);
- LocalizedEmbedBuilder builder = new LocalizedEmbedBuilder(messages, locale);
- details.applyToEmbedBuilder(builder, messages, locale, member,
- jail.getJailEndTimestamp(member));
-
- MessageEmbed embed = builder.build();
-
- // Create actions
- ActionRow interactions = ActionRow.of(
- Button.danger(Utilities.Interactions.wrapInteraction("forcestart", member),
- messages.getMessage("customjail.embed.forcestart", locale))
- .withDisabled(isTimerRunning),
- Button.danger(Utilities.Interactions.wrapInteraction("unjail", member),
- messages.getMessage("customjail.embed.unjail", locale)));
+ LocalizedContainerBuilder cb = new LocalizedContainerBuilder(messages, locale);
+ details.applyToContainerBuilder(cb, member, jail.getJailEndTimestamp(member));
// Reply with embed and actions
- event.replyEmbeds(embed).setComponents(interactions).setEphemeral(true).queue();
+ event.replyComponents(cb.build())
+ // This is required any time you are using Components V2
+ .useComponentsV2().setEphemeral(true).queue();
}
}
case "View Warnings" -> {
if (isValidUser(event, event.getTargetMember())) {
- new WarningPage(event, jail, event.getTargetMember(), messages);
+ // new WarningPage(event, jail, event.getTargetMember(), messages);
+ new WarningPageContainer(event, jail, event.getTargetMember(), messages);
}
}
}
@@ -161,6 +147,28 @@ public void onModalInteraction(ModalInteractionEvent event) {
if (Utilities.Interactions.unwrapInteraction(event, (id, unwrappedMember, variant) -> {
unwrappedMember.ifPresentOrElse(member -> {
switch (id) {
+ // Callback from jail user modal
+ case "jailuser" -> {
+ if (isValidUser(event, member))
+ if (jail.isJailed(member)) {
+ error(event, "customjail.alreadyJailed").queue();
+ return;
+ }
+
+ CustomTime duration = event.getValue("time-selection").getAsStringList().stream()
+ .reduce((a, b) -> a + b).map(CustomTime::new).orElseThrow();
+ boolean active = Boolean.valueOf(event.getValue("add-warning").getAsStringList().get(0));
+ boolean anon = Boolean.valueOf(event.getValue("anon").getAsStringList().get(0));
+ String reason = event.getValue("reason").getAsString();
+
+ attemptAction(event, (hook, locale) -> {
+ jail.jail(member, event.getMember(), duration, reason, active, anon);
+
+ String response = messages.getMessage("customjail.embed.jailed-user", new Object[] {
+ member.getAsMention(), duration.getLocalizedDisplayString(messages, locale) }, locale);
+ return Response.success(response);
+ }).queue();
+ }
case "addreason" -> {
// Ensure the callback is valid
if (variant.isEmpty()) {
@@ -275,7 +283,7 @@ private void handleWarningCommands(SlashCommandInteractionEvent event) {
case "list" -> {
Member member = event.getOption("user", OptionMapping::getAsMember);
if (isNonBotUser(event, member))
- new WarningPage(event, jail, member, messages);
+ new WarningPageContainer(event, jail, member, messages);
}
// Add warning
case "add" -> {
@@ -422,187 +430,93 @@ private void displayReasonModal(GenericComponentInteractionCreateEvent event, Su
wrappedMember != null ? wrappedMember.get() : event.getMember(), callback),
messages.getMessage("customjail.modal.title", locale));
- TextInput body = TextInput
- .create("reason", messages.getMessage("customjail.embed.reason", locale), TextInputStyle.PARAGRAPH)
+ TextInput body = TextInput.create("reason", TextInputStyle.PARAGRAPH)
.setPlaceholder(messages.getMessage("customjail.modal.placeholder", locale)).setMinLength(3)
.setMaxLength(500).setRequired(false).build();
- builder.addActionRow(body);
+ builder.addComponents(Label.of(messages.getMessage(CommonMessages.REASON, locale), body));
event.replyModal(builder.build()).queue();
}
- private class JailUserListener extends InteractionListener {
- private CompletableFuture expirationFuture;
-
- private final Member member;
- private final int warningLevel;
- private final int warnings;
- private final String warningExpires;
-
- private CustomTime time;
-
- public JailUserListener(UserContextInteractionEvent event) {
- super(event);
- this.member = event.getTargetMember();
- this.warningLevel = jail.getWarningLevel(member);
- this.warnings = jail.getTotalWarnings(member);
- this.warningExpires = jail.getWarningEndTimestamp(member)
- .orElseGet(() -> messages.getMessage("customjail.embed.na", locale));
-
- ActionRow interactions = ActionRow.of(getAddWarningButton(true), addAnonButton(true),
- Button.danger("jailuser", messages.getMessage("customjail.embed.jail-user", locale)).asDisabled());
-
- InteractionHook hook = event.getHook();
- event.replyEmbeds(createJailEmbed())
- // Add time menu
- .addActionRow(getTimeMenu())
- // Add buttons
- .addComponents(interactions)
- // Set user only
- .setEphemeral(true)
- // Send
- .queue(v -> {
- hook.getJDA().addEventListener(this);
- expirationFuture = CompletableFuture.runAsync(() -> {
- hook.getJDA().removeEventListener(this);
- hook.editOriginalEmbeds(
- Response.error(messages.getMessage("watame.interaction.expired", null, locale)))
- .setReplace(true).queue();
- }, CompletableFuture.delayedExecutor(894, TimeUnit.SECONDS));
- });
- }
+ private void displayJailModal(UserContextInteractionEvent event) {
+ Locale locale = event.getUserLocale().toLocale();
+ Member target = event.getTargetMember();
- @Override
- public void onButtonInteraction(ButtonInteractionEvent event) {
- if (!shouldRespond(event))
- return;
- switch (event.getButton().getId()) {
- case "with-warning" -> event.editButton(getAddWarningButton(false)).queue();
- case "without-warning" -> event.editButton(getAddWarningButton(true)).queue();
- case "anon" -> event.editButton(addAnonButton(false)).queue();
- case "non-anon" -> event.editButton(addAnonButton(true)).queue();
- case "jailuser" -> event.replyModal(createJailModal(member)).queue();
- }
- }
+ LocalizedModalBuilder builder = new LocalizedModalBuilder(messages, locale,
+ Utilities.Interactions.wrapInteraction("jailuser", target, "jailuser"), "customjail.embed.jail-user");
- @Override
- public void onStringSelectInteraction(StringSelectInteractionEvent event) {
- if (!shouldRespond(event))
- return;
- switch (event.getComponentId()) {
- case "time-selection" -> {
- time = event.getValues().stream().reduce((a, b) -> a + b).map(CustomTime::new).orElseThrow();
-
- Message message = event.getMessage();
- Button withWarning = message.getButtonById("with-warning"),
- withoutWarning = message.getButtonById("without-warning"), anon = message.getButtonById("anon"),
- nonAnon = message.getButtonById("non-anon"), jailButton = message.getButtonById("jailuser");
-
- event.editComponents(
- ActionRow.of(event.getSelectMenu().createCopy().setDefaultValues(event.getValues()).build()),
- ActionRow.of(withWarning != null ? withWarning : withoutWarning, anon != null ? anon : nonAnon,
- jailButton.asEnabled()))
- .queue();
- }
- }
- }
+ TextDisplay details = getJailModalDetails(target, locale);
- @Override
- public void onModalInteraction(ModalInteractionEvent event) {
- Message.Interaction interactionContext = event.getMessage().getInteraction();
- if (interactionContext != null && interactionContext.getIdLong() == id) {
- Message message = event.getMessage();
+ TextInput body = TextInput.create("reason", TextInputStyle.PARAGRAPH)
+ .setPlaceholder(messages.getMessage("customjail.modal.placeholder", locale)).setMinLength(3)
+ .setMaxLength(500).setRequired(false).build();
- boolean withWarning = message.getButtonById("with-warning") != null;
- boolean anon = message.getButtonById("anon") != null;
- String reason = event.getValue("reason").getAsString();
+ SelectOption[] yesNo = new SelectOption[] {
+ SelectOption.of(messages.getMessage(CommonMessages.YES, locale), Boolean.TRUE.toString()),
+ SelectOption.of(messages.getMessage(CommonMessages.NO, locale), Boolean.FALSE.toString()) };
+ SelectMenu addWarning = StringSelectMenu.create("add-warning").addOptions(yesNo).setDefaultOptions(yesNo[0])
+ .setRequired(true).build();
+ SelectMenu anon = StringSelectMenu.create("anon").addOptions(yesNo).setDefaultOptions(yesNo[0])
+ .setRequired(true).build();
- expirationFuture.cancel(true);
- event.getJDA().removeEventListener(this);
+ SelectMenu timeMenu = getTimeMenu(locale);
- event.deferEdit().flatMap(hook -> {
- Locale locale = event.getUserLocale().toLocale();
+ builder.addComponents(details);
+ builder.addLocalizedLabelWithDescription(CommonMessages.DURATION,
+ Localized.resolved("customjail.embed.duration-description"), timeMenu);
+ builder.addLocalizedLabelWithDescription(CommonMessages.WITH_WARNING,
+ Localized.resolved("customjail.embed.with-warning-description"), addWarning);
+ builder.addLocalizedLabelWithDescription(CommonMessages.ANONYMOUS,
+ Localized.resolved("customjail.embed.anonymous-description"), anon);
- MessageEmbed embed = null;
- try {
- jail.jail(member, event.getMember(), time, reason, withWarning, anon);
+ builder.addLocalizedLabelWithDescription(CommonMessages.REASON,
+ Localized.resolved("customjail.embed.reason-description"), body);
- embed = Response.success(messages.getMessage("customjail.embed.jailed-user", new Object[] {
- member.getAsMention(), time.getLocalizedDisplayString(messages, locale) }, locale));
- } catch (LocalizedException e) {
- embed = Response.error(messages.getMessage(e.getErrorMessage(), locale));
- } catch (Exception e) {
- embed = Response.error(DiscordUtils.toString(e));
- }
+ event.replyModal(builder.build()).queue();
+ }
- return hook.editOriginalEmbeds(embed != null ? embed : Response.error("Uknown error while jailing"))
- .setReplace(true);
- }).queue();
- }
- }
+ private TextDisplay getJailModalDetails(Member target, Locale locale) {
+ int warningLevel = jail.getWarningLevel(target);
+ int totalWarnings = jail.getTotalWarnings(target);
+ Object expires = jail.getWarningEndTimestamp(target).map(Object.class::cast).orElse(CommonMessages.NA);
- private MessageEmbed createJailEmbed() {
- LocalizedEmbedBuilder builder = new LocalizedEmbedBuilder(messages, locale);
- builder.setColor(Colors.INFO);
- builder.setLocalizedTitle("customjail.embed.jail-user");
- builder.setThumbnail(member.getEffectiveAvatarUrl());
-
- builder.addLocalizedField("customjail.embed.member", member.getAsMention(), true);
- builder.addLocalizedField("customjail.embed.warning-level", "" + warningLevel, true);
- builder.addLocalizedField("customjail.embed.total-warnings", "" + warnings, true);
- builder.addLocalizedField("customjail.embed.warning-expires", warningExpires, false);
- return builder.build();
- }
+ StringBuilder builder = new StringBuilder();
- private Button addAnonButton(boolean anon) {
- return anon
- ? Button.primary("anon", messages.getMessage("customjail.embed.anon", locale))
- .withEmoji(Emoji.fromFormatted("U+1F92B"))
- : Button.secondary("non-anon", messages.getMessage("customjail.embed.non-anon", locale))
- .withEmoji(Emoji.fromFormatted("U+1F4E3"));
- }
+ appendBoldField(builder, locale, CommonMessages.MEMBER, target.getAsMention());
+ appendBoldField(builder, locale, CommonMessages.WARNING_LEVEL, MarkdownUtil.monospace(warningLevel + ""));
+ appendBoldField(builder, locale, CommonMessages.TOTAL_WARNINGS, MarkdownUtil.monospace(totalWarnings + ""));
+ appendBoldField(builder, locale, CommonMessages.WARNING_EXPIRES, expires);
- private Button getAddWarningButton(boolean addWarning) {
- return addWarning
- ? Button.primary("with-warning", messages.getMessage("customjail.embed.with-warning", locale))
- .withEmoji(Emoji.fromFormatted("U+2705"))
- : Button.secondary("without-warning",
- messages.getMessage("customjail.embed.without-warning", locale))
- .withEmoji(Emoji.fromFormatted("U+274C"));
- }
+ return TextDisplay.of(builder.toString());
+ }
- private SelectMenu getTimeMenu() {
- SelectOption[] options = Arrays
- // Stream times
- .stream(jail.getJailTimings())
- // Create select option
- .map(time -> SelectOption.of(new CustomTime(time).getLocalizedDisplayString(messages, locale),
- time))
- // To array
- .toArray(SelectOption[]::new);
-
- return StringSelectMenu
- // Set ID
- .create("time-selection")
- // Set placeholder
- .setPlaceholder(messages.getMessage("customjail.embed.set-time", locale))
- // Add time options
- .addOptions(options)
- // Build
- .build();
+ private void appendBoldField(StringBuilder builder, Locale locale, Object... args) {
+ Object[] resolved = Arrays.copyOf(args, args.length);
+ for (int i = 0; i < resolved.length; i++) {
+ Object arg = resolved[i];
+ if (arg instanceof MessageSourceResolvable resolvable)
+ resolved[i] = messages.getMessage(resolvable, locale);
}
+ builder.append(String.format("**%s:** %s\n", resolved));
+ }
- private Modal createJailModal(Member member) {
- Modal.Builder builder = Modal.create(Utilities.Interactions.wrapInteraction("jailuser", member),
- messages.getMessage("customjail.modal.title", locale));
-
- TextInput body = TextInput
- .create("reason", messages.getMessage("customjail.embed.reason", locale), TextInputStyle.PARAGRAPH)
- .setPlaceholder(messages.getMessage("customjail.modal.placeholder", locale)).setMinLength(3)
- .setMaxLength(500).setRequired(false).build();
-
- builder.addActionRow(body);
- return builder.build();
- }
+ private SelectMenu getTimeMenu(Locale locale) {
+ SelectOption[] options = Arrays
+ // Stream times
+ .stream(jail.getJailTimings())
+ // Create select option
+ .map(time -> SelectOption.of(new CustomTime(time).getLocalizedDisplayString(messages, locale), time))
+ // To array
+ .toArray(SelectOption[]::new);
+
+ return StringSelectMenu
+ // Set ID
+ .create("time-selection")
+ // Set placeholder
+ .setPlaceholder(messages.getMessage("customjail.embed.set-time", locale))
+ // Add time options
+ .addOptions(options)
+ // Build
+ .build();
}
}
diff --git a/src/main/java/net/foxgenesis/customjail/WarningPage.java b/src/main/java/net/foxgenesis/customjail/WarningPage.java
deleted file mode 100644
index 6b0700e..0000000
--- a/src/main/java/net/foxgenesis/customjail/WarningPage.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package net.foxgenesis.customjail;
-
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-
-import org.springframework.context.MessageSource;
-import org.springframework.context.MessageSourceResolvable;
-import org.springframework.context.support.DefaultMessageSourceResolvable;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-
-import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.entities.MessageEmbed;
-import net.dv8tion.jda.api.events.interaction.command.GenericCommandInteractionEvent;
-import net.dv8tion.jda.api.utils.MarkdownUtil;
-import net.dv8tion.jda.api.utils.TimeFormat;
-import net.foxgenesis.customjail.database.warning.Warning;
-import net.foxgenesis.customjail.jail.WarningSystem;
-import net.foxgenesis.customjail.util.CachedObject;
-import net.foxgenesis.watame.util.discord.Colors;
-import net.foxgenesis.watame.util.discord.DiscordUtils;
-import net.foxgenesis.watame.util.discord.Response;
-import net.foxgenesis.watame.util.lang.LocalizedEmbedBuilder;
-import net.foxgenesis.watame.util.lang.LocalizedPageMenu;
-
-public class WarningPage extends LocalizedPageMenu {
- private static final MessageSourceResolvable NA = new DefaultMessageSourceResolvable("customjail.embed.na");
-
- private final WarningSystem database;
- private final Member target;
-
- private final CachedObject warningLevelCache;
- private final CachedObject expiresCache;
-
- public WarningPage(GenericCommandInteractionEvent event, WarningSystem database, Member target,
- MessageSource source) {
- super(event, database.getWarningPage(target, PageRequest.of(0, 3, Sort.by("time").descending())), source);
- this.database = Objects.requireNonNull(database);
- this.target = Objects.requireNonNull(target);
-
- // Cache Database calls
- this.warningLevelCache = new CachedObject<>(() -> database.getWarningLevel(target), 15, TimeUnit.SECONDS);
- this.expiresCache = new CachedObject<>(
- () -> database.getWarningEndTimestamp(target).orElseGet(() -> messages.getMessage(NA, locale)), 15,
- TimeUnit.SECONDS);
-
- this.sendInitalMessage(event);
- }
-
- @Override
- protected MessageEmbed createEmbed(Page page, Locale locale) {
- LocalizedEmbedBuilder builder = new LocalizedEmbedBuilder(messages, locale);
- builder.setColor(Colors.INFO);
- builder.setThumbnail(target.getEffectiveAvatarUrl());
-
- builder.appendLocalizedDescription("customjail.embed.warning.title", target.getAsMention());
- builder.newLine();
-
- builder.appendLocalizedDescription("customjail.embed.warning.level", warningLevelCache.get());
- builder.newLine();
-
- builder.appendLocalizedDescription("customjail.embed.warning.expires", expiresCache.get());
- builder.newLine();
- builder.newLine();
-
- // Write notes
- writeNotes(builder, page, locale);
-
- Object[] args = { page.getTotalElements(), page.getNumber() + 1, page.getTotalPages() };
- builder.setLocalizedFooter("customjail.warnings.footer", args);
-
- return builder.build();
- }
-
- private void writeNotes(LocalizedEmbedBuilder builder, Page page, Locale locale) {
- StringBuilder sb = builder.getDescriptionBuilder();
- sb.append(">>> ");
-
- Iterator iterator = page.iterator();
- while (iterator.hasNext()) {
- Warning warning = iterator.next();
- // FIXME: clean up and make readable
- // "%1$s#%caseid%:% messages.getMessage("customjail.embed.defaultReason", null, locale)));
-
- if (iterator.hasNext())
- sb.append("\n\n");
- }
- }
-
- @Override
- protected MessageEmbed createEmptyPageEmbed(Locale locale) {
- return Response
- .error(messages.getMessage("customjail.warnings.empty", null, "customjail.warnings.empty", locale));
- }
-
- @Override
- protected Page getNewPage(Pageable pagable) {
- return database.getWarningPage(target, pagable);
- }
-
- @Override
- protected MessageEmbed createExpiredEmbed(Locale locale) {
- return Response.error(messages.getMessage(INTERACTION_EXPIRED, locale));
- }
-}
diff --git a/src/main/java/net/foxgenesis/customjail/WarningPageContainer.java b/src/main/java/net/foxgenesis/customjail/WarningPageContainer.java
new file mode 100644
index 0000000..92d3fc4
--- /dev/null
+++ b/src/main/java/net/foxgenesis/customjail/WarningPageContainer.java
@@ -0,0 +1,132 @@
+package net.foxgenesis.customjail;
+
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import org.springframework.context.MessageSource;
+import org.springframework.context.MessageSourceResolvable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+
+import net.dv8tion.jda.api.components.container.Container;
+import net.dv8tion.jda.api.components.separator.Separator.Spacing;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.events.interaction.command.GenericCommandInteractionEvent;
+import net.dv8tion.jda.api.utils.TimeFormat;
+import net.foxgenesis.customjail.database.warning.Warning;
+import net.foxgenesis.customjail.jail.WarningSystem;
+import net.foxgenesis.customjail.util.CachedObject;
+import net.foxgenesis.watame.util.StringUtils;
+import net.foxgenesis.watame.util.discord.Colors;
+import net.foxgenesis.watame.util.discord.DiscordUtils;
+import net.foxgenesis.watame.util.discord.components.ComponentUtils;
+import net.foxgenesis.watame.util.lang.Localized;
+import net.foxgenesis.watame.util.lang.LocalizedContainerBuilder;
+import net.foxgenesis.watame.util.lang.LocalizedContainerPageMenu;
+import net.foxgenesis.watame.util.lang.LocalizedSectionBuilder;
+
+public class WarningPageContainer extends LocalizedContainerPageMenu {
+ private static final MessageSourceResolvable TITLE = Localized.resolved("customjail.embed.warnings");
+
+ private final WarningSystem database;
+ private final Member target;
+
+ private final CachedObject warningLevelCache;
+ private final CachedObject totalWarningsCache;
+ private final CachedObject