mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-25 09:39:18 +00:00
Start work on data list pagination via PagineDown, update locales
This commit is contained in:
@@ -75,7 +75,7 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
||||
}
|
||||
if (args.length < 2) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/userdata list <username>")
|
||||
"/userdata list <username> [page]")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
@@ -83,12 +83,28 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
||||
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
||||
optionalUser -> optionalUser.ifPresentOrElse(
|
||||
user -> plugin.getDatabase().getUserData(user).thenAccept(dataList -> {
|
||||
// Check if there is data to display
|
||||
if (dataList.isEmpty()) {
|
||||
plugin.getLocales().getLocale("error_no_data_to_display")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
plugin.getDataEditor().displayDataList(player, dataList, user);
|
||||
|
||||
// Determine page to display
|
||||
int page = 1;
|
||||
if (args.length >= 3) {
|
||||
try {
|
||||
page = Integer.parseInt(args[2]);
|
||||
} catch (NumberFormatException e) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/userdata list <username> [page]")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Show list
|
||||
plugin.getDataEditor().displayDataSnapshotList(player, dataList, user, page);
|
||||
}),
|
||||
() -> plugin.getLocales().getLocale("error_invalid_player")
|
||||
.ifPresent(player::sendMessage))));
|
||||
|
||||
@@ -2,11 +2,13 @@ package net.william278.husksync.config;
|
||||
|
||||
import de.themoep.minedown.adventure.MineDown;
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import net.william278.paginedown.ListOptions;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Loaded locales used by the plugin to display various locales
|
||||
@@ -30,10 +32,7 @@ public class Locales {
|
||||
* @return An {@link Optional} containing the locale corresponding to the id, if it exists
|
||||
*/
|
||||
public Optional<String> getRawLocale(@NotNull String localeId) {
|
||||
if (rawLocales.containsKey(localeId)) {
|
||||
return Optional.of(rawLocales.get(localeId).replaceAll(Pattern.quote("\\n"), "\n"));
|
||||
}
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(rawLocales.get(localeId)).map(StringEscapeUtils::unescapeJava);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,13 +58,16 @@ public class Locales {
|
||||
|
||||
/**
|
||||
* Returns a MineDown-formatted locale from the locales file, with replacements applied
|
||||
* <p>
|
||||
* Note that replacements will be MineDown-escaped before application
|
||||
*
|
||||
* @param localeId String identifier of the locale, corresponding to a key in the file
|
||||
* @param replacements Ordered array of replacement strings to fill in placeholders with
|
||||
* @return An {@link Optional} containing the replacement-applied, formatted locale corresponding to the id, if it exists
|
||||
*/
|
||||
public Optional<MineDown> getLocale(@NotNull String localeId, @NotNull String... replacements) {
|
||||
return getRawLocale(localeId, replacements).map(MineDown::new);
|
||||
return getRawLocale(localeId, Arrays.stream(replacements).map(Locales::escapeMineDown)
|
||||
.toArray(String[]::new)).map(MineDown::new);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,6 +87,62 @@ public class Locales {
|
||||
return rawLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string from {@link MineDown} formatting for use in a MineDown-formatted locale
|
||||
* <p>
|
||||
* Although MineDown provides {@link MineDown#escape(String)}, that method fails to escape events
|
||||
* properly when using the escaped string in a replacement, so this is used instead
|
||||
*
|
||||
* @param string The string to escape
|
||||
* @return The escaped string
|
||||
*/
|
||||
@NotNull
|
||||
public static String escapeMineDown(@NotNull String string) {
|
||||
final StringBuilder value = new StringBuilder();
|
||||
for (int i = 0; i < string.length(); ++i) {
|
||||
char c = string.charAt(i);
|
||||
boolean isEscape = c == '\\';
|
||||
boolean isColorCode = i + 1 < string.length() && (c == 167 || c == '&');
|
||||
boolean isEvent = c == '[' || c == ']' || c == '(' || c == ')';
|
||||
if (isEscape || isColorCode || isEvent) {
|
||||
value.append('\\');
|
||||
}
|
||||
|
||||
value.append(c);
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base list options to use for a paginated chat list
|
||||
*
|
||||
* @param itemsPerPage The number of items to display per page
|
||||
* @return The list options
|
||||
*/
|
||||
@NotNull
|
||||
public ListOptions.Builder getBaseChatList(int itemsPerPage) {
|
||||
return new ListOptions.Builder()
|
||||
.setFooterFormat(getRawLocale("list_footer",
|
||||
"%previous_page_button%", "%current_page%",
|
||||
"%total_pages%", "%next_page_button%", "%page_jumpers%").orElse(""))
|
||||
.setNextButtonFormat(getRawLocale("list_next_page_button",
|
||||
"%next_page_index%", "%command%").orElse(""))
|
||||
.setPreviousButtonFormat(getRawLocale("list_previous_page_button",
|
||||
"%previous_page_index%", "%command%").orElse(""))
|
||||
.setPageJumpersFormat(getRawLocale("list_page_jumpers",
|
||||
"%page_jump_buttons%").orElse(""))
|
||||
.setPageJumperPageFormat(getRawLocale("list_page_jumper_button",
|
||||
"%target_page_index%", "%command%").orElse(""))
|
||||
.setPageJumperCurrentPageFormat(getRawLocale("list_page_jumper_current_page",
|
||||
"%current_page%").orElse(""))
|
||||
.setPageJumperPageSeparator(getRawLocale("list_page_jumper_separator").orElse(""))
|
||||
.setPageJumperGroupSeparator(getRawLocale("list_page_jumper_group_separator").orElse(""))
|
||||
.setItemsPerPage(itemsPerPage)
|
||||
.setEscapeItemsMineDown(false)
|
||||
.setSpaceAfterHeader(false)
|
||||
.setSpaceBeforeFooter(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the locales from a BoostedYaml {@link YamlDocument} locales file
|
||||
*
|
||||
|
||||
@@ -9,7 +9,6 @@ import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.player.User;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -143,32 +142,16 @@ public class DataEditor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a chat list detailing a player's saved list of {@link UserDataSnapshot}
|
||||
* Display a paginated chat list of {@link UserDataSnapshot}s
|
||||
*
|
||||
* @param user The online user to display the message to
|
||||
* @param userDataList The list of {@link UserDataSnapshot} to display
|
||||
* @param dataOwner The {@link User} who owns the {@link UserDataSnapshot}
|
||||
* @param userDataList The list of {@link UserDataSnapshot}s to display
|
||||
* @param dataOwner The {@link User} who owns the {@link UserDataSnapshot}s
|
||||
* @param page The page of the list to display
|
||||
*/
|
||||
public void displayDataList(@NotNull OnlineUser user, @NotNull List<UserDataSnapshot> userDataList,
|
||||
@NotNull User dataOwner) {
|
||||
locales.getLocale("data_list_title",
|
||||
dataOwner.username, dataOwner.uuid.toString())
|
||||
.ifPresent(user::sendMessage);
|
||||
|
||||
final String[] numberedIcons = "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳".split("");
|
||||
for (int i = 0; i < Math.min(20, userDataList.size()); i++) {
|
||||
final UserDataSnapshot userData = userDataList.get(i);
|
||||
locales.getLocale("data_list_item",
|
||||
numberedIcons[i],
|
||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault())
|
||||
.format(userData.versionTimestamp()),
|
||||
userData.versionUUID().toString().split("-")[0],
|
||||
userData.versionUUID().toString(),
|
||||
userData.cause().name().toLowerCase().replaceAll("_", " "),
|
||||
dataOwner.username,
|
||||
userData.pinned() ? "※" : " ")
|
||||
.ifPresent(user::sendMessage);
|
||||
}
|
||||
public void displayDataSnapshotList(@NotNull OnlineUser user, @NotNull List<UserDataSnapshot> userDataList,
|
||||
@NotNull User dataOwner, final int page) {
|
||||
DataSnapshotList.create(userDataList, dataOwner, locales).displayPage(user, page);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package net.william278.husksync.editor;
|
||||
|
||||
import net.william278.husksync.config.Locales;
|
||||
import net.william278.husksync.data.UserDataSnapshot;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.player.User;
|
||||
import net.william278.paginedown.PaginatedList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Represents a chat-viewable paginated list of {@link UserDataSnapshot}s
|
||||
*/
|
||||
public class DataSnapshotList {
|
||||
|
||||
// Used for displaying number ordering next to snapshots in the list
|
||||
private static final String[] CIRCLED_NUMBER_ICONS = "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳".split("");
|
||||
|
||||
@NotNull
|
||||
private final PaginatedList paginatedList;
|
||||
|
||||
private DataSnapshotList(@NotNull List<UserDataSnapshot> snapshots, @NotNull User dataOwner,
|
||||
@NotNull Locales locales) {
|
||||
final AtomicInteger snapshotNumber = new AtomicInteger(1);
|
||||
this.paginatedList = PaginatedList.of(snapshots.stream()
|
||||
.map(snapshot -> locales.getRawLocale("data_list_item",
|
||||
getNumberIcon(snapshotNumber.getAndIncrement()),
|
||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
|
||||
Locale.getDefault()).format(snapshot.versionTimestamp()),
|
||||
snapshot.versionUUID().toString().split("-")[0],
|
||||
snapshot.versionUUID().toString(),
|
||||
snapshot.cause().name().toLowerCase().replaceAll("_", " "),
|
||||
dataOwner.username,
|
||||
snapshot.pinned() ? "※" : " ")
|
||||
.orElse("• " + snapshot.versionUUID())).toList(),
|
||||
locales.getBaseChatList(6)
|
||||
.setHeaderFormat(locales.getRawLocale("data_list_title", dataOwner.username,
|
||||
"%first_item_on_page_index%", "%last_item_on_page_index%", "%total_items%")
|
||||
.orElse(""))
|
||||
.setCommand("/husksync:userdata list " + dataOwner.username)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link DataSnapshotList} from a list of {@link UserDataSnapshot}s
|
||||
*
|
||||
* @param snapshots The list of {@link UserDataSnapshot}s to display
|
||||
* @param user The {@link User} who owns the {@link UserDataSnapshot}s
|
||||
* @param locales The {@link Locales} instance
|
||||
* @return A new {@link DataSnapshotList}, to be viewed with {@link #displayPage(OnlineUser, int)}
|
||||
*/
|
||||
protected static DataSnapshotList create(@NotNull List<UserDataSnapshot> snapshots, @NotNull User user,
|
||||
@NotNull Locales locales) {
|
||||
return new DataSnapshotList(snapshots, user, locales);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an icon for the given snapshot number, via {@link #CIRCLED_NUMBER_ICONS}
|
||||
*
|
||||
* @param number the snapshot number
|
||||
* @return the icon for the given snapshot number
|
||||
*/
|
||||
private static String getNumberIcon(int number) {
|
||||
if (number < 1 || number > 20) {
|
||||
return String.valueOf(number);
|
||||
}
|
||||
return CIRCLED_NUMBER_ICONS[number - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a page of the list of {@link UserDataSnapshot} to the user
|
||||
*
|
||||
* @param onlineUser The online user to display the message to
|
||||
* @param page The page number to display
|
||||
*/
|
||||
protected void displayPage(@NotNull OnlineUser onlineUser, int page) {
|
||||
onlineUser.sendMessage(paginatedList.getNearestValidPage(page));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user