From 175b66465acc0eaa8b2a3915bb8b1ca7974a9ff4 Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Sat, 2 Aug 2025 19:01:15 +0200 Subject: [PATCH] Moves book index generation to its own class --- .../command/CommandDelete.java | 5 +- .../command/CommandGive.java | 6 +- .../command/CommandLoad.java | 6 +- .../gui/PagedBookIndex.java | 212 ++++++++++++++++++ .../utility/BookFileHelper.java | 128 ----------- 5 files changed, 221 insertions(+), 136 deletions(-) create mode 100644 src/main/java/net/knarcraft/bookswithoutborders/gui/PagedBookIndex.java diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java index c3e9458..3ef6894 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java @@ -1,6 +1,7 @@ package net.knarcraft.bookswithoutborders.command; import net.knarcraft.bookswithoutborders.BooksWithoutBorders; +import net.knarcraft.bookswithoutborders.gui.PagedBookIndex; import net.knarcraft.bookswithoutborders.state.BookDirectory; import net.knarcraft.bookswithoutborders.utility.BookFileHelper; import net.knarcraft.bookswithoutborders.utility.BookHelper; @@ -43,14 +44,14 @@ public class CommandDelete implements TabExecutor { String command = deletePublic ? "deletepublicbook" : "deletebook"; //List deletable files if (args.length == 0) { - BookFileHelper.printBooks(sender, deletePublic, command, 1); + PagedBookIndex.printBooks(sender, deletePublic, command, 1); return true; } //Delete the file if (args.length == 1) { int page = InputCleaningHelper.parsePageNumber(args[0]); if (page > 0) { - BookFileHelper.printBooks(sender, deletePublic, command, page); + PagedBookIndex.printBooks(sender, deletePublic, command, page); return true; } diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java index 38390f5..28ed22b 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java @@ -1,7 +1,7 @@ package net.knarcraft.bookswithoutborders.command; import net.knarcraft.bookswithoutborders.BooksWithoutBorders; -import net.knarcraft.bookswithoutborders.utility.BookFileHelper; +import net.knarcraft.bookswithoutborders.gui.PagedBookIndex; import net.knarcraft.bookswithoutborders.utility.BookLoader; import net.knarcraft.bookswithoutborders.utility.InputCleaningHelper; import net.knarcraft.bookswithoutborders.utility.TabCompletionTypeHelper; @@ -46,12 +46,12 @@ public class CommandGive implements TabExecutor { boolean giveBook(CommandSender sender, String[] args, boolean givePublic, String folder) { String command = givePublic ? "givepublicbook" : "givebook"; if (args.length == 0) { - BookFileHelper.printBooks(sender, givePublic, command, 1); + PagedBookIndex.printBooks(sender, givePublic, command, 1); return true; } else if (args.length == 1) { int page = InputCleaningHelper.parsePageNumber(args[0]); if (page > 0) { - BookFileHelper.printBooks(sender, givePublic, command, page); + PagedBookIndex.printBooks(sender, givePublic, command, page); return true; } } diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java index 122666d..cb01a2b 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java @@ -1,7 +1,7 @@ package net.knarcraft.bookswithoutborders.command; import net.knarcraft.bookswithoutborders.BooksWithoutBorders; -import net.knarcraft.bookswithoutborders.utility.BookFileHelper; +import net.knarcraft.bookswithoutborders.gui.PagedBookIndex; import net.knarcraft.bookswithoutborders.utility.BookLoader; import net.knarcraft.bookswithoutborders.utility.InputCleaningHelper; import net.knarcraft.bookswithoutborders.utility.TabCompletionTypeHelper; @@ -51,12 +51,12 @@ public class CommandLoad implements TabExecutor { //Show books available to the player String command = loadPublic ? "loadpublicbook" : "loadbook"; if (argumentCount == 0) { - BookFileHelper.printBooks(sender, loadPublic, command, 1); + PagedBookIndex.printBooks(sender, loadPublic, command, 1); return true; } else if (argumentCount == 1) { int page = InputCleaningHelper.parsePageNumber(args[0]); if (page > 0) { - BookFileHelper.printBooks(sender, loadPublic, command, page); + PagedBookIndex.printBooks(sender, loadPublic, command, page); return true; } } diff --git a/src/main/java/net/knarcraft/bookswithoutborders/gui/PagedBookIndex.java b/src/main/java/net/knarcraft/bookswithoutborders/gui/PagedBookIndex.java new file mode 100644 index 0000000..65fef32 --- /dev/null +++ b/src/main/java/net/knarcraft/bookswithoutborders/gui/PagedBookIndex.java @@ -0,0 +1,212 @@ +package net.knarcraft.bookswithoutborders.gui; + +import net.knarcraft.bookswithoutborders.BooksWithoutBorders; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.hover.content.Text; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A class for displaying a paged index of all available books + */ +public class PagedBookIndex { + + private final static int booksPerPage = 10; + + /** + * Prints the available books + * + * @param sender

The sender to display the books to

+ * @param listPublic

Whether to display public books

+ * @param command

The base command causing this to be called

+ * @param page

The page of the book list to display

+ */ + public static void printBooks(@NotNull CommandSender sender, boolean listPublic, @NotNull String command, int page) { + List availableBooks = BooksWithoutBorders.getAvailableBooks(sender, listPublic); + + Map firstInstances; + if (listPublic) { + firstInstances = BooksWithoutBorders.getLetterIndex(null); + } else if (sender instanceof Player player) { + firstInstances = BooksWithoutBorders.getLetterIndex(player.getUniqueId()); + } else { + firstInstances = new HashMap<>(); + } + + int totalPages = (int) Math.ceil((double) availableBooks.size() / booksPerPage); + if (page > totalPages) { + sender.sendMessage(ChatColor.GRAY + "No such page"); + } else { + PagedBookIndex.showBookMenu(sender, command, page, totalPages, availableBooks, firstInstances); + } + } + + /** + * Shows a menu listing available books + * + * @param sender

The sender wanting to see the book menu

+ * @param command

The main command used to trigger display of the book menu

+ * @param page

The currently selected page

+ * @param totalPages

The total amount of pages

+ * @param availableBooks

All books available to the sender

+ * @param firstInstances

The map between a character, and the index of the first instance of that character in the book list

+ */ + private static void showBookMenu(@NotNull CommandSender sender, @NotNull String command, int page, + int totalPages, @NotNull List availableBooks, + @NotNull Map firstInstances) { + ComponentBuilder componentBuilder = new ComponentBuilder(); + + // Display the alphabet index as the header + displayAlphabetIndex(componentBuilder, command, firstInstances); + + // Display the list of books, with the next and previous buttons + displayPreviousButton(componentBuilder, command, page); + displayBookList(componentBuilder, command, page, availableBooks); + displayNextButton(componentBuilder, command, page, totalPages); + + // Display total pages and the manual change page command suggestion + componentBuilder.append(" ", ComponentBuilder.FormatRetention.NONE); + displayTotalPages(componentBuilder, page, totalPages); + componentBuilder.append(" ", ComponentBuilder.FormatRetention.NONE); + displayPageCommand(componentBuilder, command, page); + sender.spigot().sendMessage(componentBuilder.create()); + } + + /** + * Displays the suggestion for manually going to any page + * + * @param componentBuilder

The component builder to append to

+ * @param command

The command used for switching pages

+ * @param page

The current page

+ */ + private static void displayPageCommand(@NotNull ComponentBuilder componentBuilder, @NotNull String command, int page) { + componentBuilder.append("[Page Command]", ComponentBuilder.FormatRetention.NONE).event(new HoverEvent( + HoverEvent.Action.SHOW_TEXT, new Text("/" + command + " page" + page))).event( + new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " page" + page)); + } + + /** + * Displays the current page and total amount of pages + * + * @param componentBuilder

The component builder to append to

+ * @param page

The current page

+ * @param totalPages

The total amount of pages

+ */ + private static void displayTotalPages(@NotNull ComponentBuilder componentBuilder, int page, int totalPages) { + componentBuilder.append("Page " + page + " of " + totalPages, + ComponentBuilder.FormatRetention.NONE).color(ChatColor.GREEN); + } + + /** + * Displays the list of books on the current page + * + * @param componentBuilder

The component builder to append to

+ * @param command

The command used for switching pages

+ * @param page

The current page

+ * @param availableBooks

All available books

+ */ + private static void displayBookList(@NotNull ComponentBuilder componentBuilder, @NotNull String command, int page, + @NotNull List availableBooks) { + int startIndex = (page - 1) * booksPerPage; + for (int bookIndex = startIndex; bookIndex < Math.min(startIndex + booksPerPage, availableBooks.size()); bookIndex++) { + componentBuilder.append("[" + (bookIndex + 1) + "]").color(ChatColor.GOLD).event( + new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " + + (bookIndex + 1))).event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new Text("Select book by index"))); + + componentBuilder.append(" ", ComponentBuilder.FormatRetention.NONE); + + componentBuilder.append(getNiceName(availableBooks.get(bookIndex))).color(ChatColor.WHITE).event( + new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " + + availableBooks.get(bookIndex))).event( + new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Select book by path"))); + componentBuilder.append("\n"); + } + } + + /** + * Displays the alphabet-based page index + * + * @param componentBuilder

The component builder to append to

+ * @param command

The command used for switching pages

+ * @param firstInstances

The map of where the first index of a letter is found

+ */ + private static void displayAlphabetIndex(@NotNull ComponentBuilder componentBuilder, + @NotNull String command, @NotNull Map firstInstances) { + for (int characterIndex = 0; characterIndex <= 25; characterIndex++) { + char character = (char) ('a' + characterIndex); + if (firstInstances.containsKey(character)) { + int pageIndex = (firstInstances.get(character) / booksPerPage) + 1; + componentBuilder.append(character + "").color( + ChatColor.AQUA).event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, + "/" + command + " page" + pageIndex)).event(new HoverEvent( + HoverEvent.Action.SHOW_TEXT, new Text("To page " + pageIndex))); + } else { + componentBuilder.append(character + "", ComponentBuilder.FormatRetention.NONE).color(ChatColor.GRAY); + } + } + componentBuilder.append("\n"); + } + + /** + * Displays the previous page button + * + * @param componentBuilder

The component builder to append to

+ * @param command

The command used for switching pages

+ * @param page

The current page

+ */ + private static void displayPreviousButton(@NotNull ComponentBuilder componentBuilder, + @NotNull String command, int page) { + if (page > 1) { + String fullCommand = "/" + command + " page" + (page - 1); + HoverEvent prevPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("To page " + (page - 1))); + ClickEvent prevPageClick = new ClickEvent(ClickEvent.Action.RUN_COMMAND, fullCommand); + componentBuilder.append("Previous [<]", ComponentBuilder.FormatRetention.NONE).event(prevPagePreview).event(prevPageClick); + } else { + componentBuilder.append("Previous [<]", ComponentBuilder.FormatRetention.NONE).color(ChatColor.GRAY); + } + componentBuilder.append("\n"); + } + + /** + * Displays the next page button + * + * @param componentBuilder

The component builder to append to

+ * @param command

The command used for switching pages

+ * @param page

The current page

+ * @param totalPages

The total amount of pages

+ */ + private static void displayNextButton(@NotNull ComponentBuilder componentBuilder, + @NotNull String command, int page, int totalPages) { + if (page < totalPages) { + String fullCommand = "/" + command + " page" + (page + 1); + HoverEvent nextPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("To page " + (page + 1))); + ClickEvent nextPageClick = new ClickEvent(ClickEvent.Action.RUN_COMMAND, fullCommand); + componentBuilder.append("Next [>]", ComponentBuilder.FormatRetention.NONE).event(nextPagePreview).event(nextPageClick); + } else { + componentBuilder.append("Next [>]", ComponentBuilder.FormatRetention.NONE).color(ChatColor.GRAY); + } + } + + /** + * Gets a nice name from a book's path + * + * @param bookPath

The path of a book

+ * @return

The prettified book name

+ */ + @NotNull + private static String getNiceName(@NotNull String bookPath) { + bookPath = ChatColor.translateAlternateColorCodes('&', bookPath.substring(0, bookPath.length() - 4)); + String[] parts = bookPath.split(","); + return parts[0].replace("_", " ") + ChatColor.RESET + " by " + parts[1] + ChatColor.RESET; + } + +} diff --git a/src/main/java/net/knarcraft/bookswithoutborders/utility/BookFileHelper.java b/src/main/java/net/knarcraft/bookswithoutborders/utility/BookFileHelper.java index 2e33ebd..c8abaed 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/utility/BookFileHelper.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/utility/BookFileHelper.java @@ -3,13 +3,7 @@ package net.knarcraft.bookswithoutborders.utility; import net.knarcraft.bookswithoutborders.BooksWithoutBorders; import net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig; import net.knarcraft.bookswithoutborders.state.BookDirectory; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.ClickEvent; -import net.md_5.bungee.api.chat.ComponentBuilder; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -29,8 +23,6 @@ import static net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig */ public final class BookFileHelper { - private final static int booksPerPage = 10; - private BookFileHelper() { } @@ -113,126 +105,6 @@ public final class BookFileHelper { return BookFileHelper.listFiles(sender, file); } - /** - * Prints the available books - * - * @param sender

The sender to display the books to

- * @param listPublic

Whether to display public books

- * @param command

The base command causing this to be called

- * @param page

The page of the book list to display

- */ - public static void printBooks(@NotNull CommandSender sender, boolean listPublic, @NotNull String command, int page) { - List availableBooks = BooksWithoutBorders.getAvailableBooks(sender, listPublic); - - Map firstInstances; - if (listPublic) { - firstInstances = BooksWithoutBorders.getLetterIndex(null); - } else if (sender instanceof Player player) { - firstInstances = BooksWithoutBorders.getLetterIndex(player.getUniqueId()); - } else { - firstInstances = new HashMap<>(); - } - - int totalPages = (int) Math.ceil((double) availableBooks.size() / booksPerPage); - if (page > totalPages) { - sender.sendMessage(ChatColor.GRAY + "No such page"); - } else { - showBookMenu(sender, command, page, totalPages, availableBooks, firstInstances); - } - } - - /** - * Shows a menu listing available books - * - * @param sender

The sender wanting to see the book menu

- * @param command

The main command used to trigger display of the book menu

- * @param page

The currently selected page

- * @param totalPages

The total amount of pages

- * @param availableBooks

All books available to the sender

- * @param firstInstances

The map between a character, and the index of the first instance of that character in the book list

- */ - private static void showBookMenu(@NotNull CommandSender sender, @NotNull String command, int page, - int totalPages, @NotNull List availableBooks, - @NotNull Map firstInstances) { - ComponentBuilder headerComponent = new ComponentBuilder(); - - // Display links to first page where a letter can be found - for (int characterIndex = 0; characterIndex <= 25; characterIndex++) { - char character = (char) ('a' + characterIndex); - if (firstInstances.containsKey(character)) { - int pageIndex = (firstInstances.get(character) / booksPerPage) + 1; - headerComponent.append(character + "").color( - ChatColor.AQUA).event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, - "/" + command + " page" + pageIndex)).event(new HoverEvent( - HoverEvent.Action.SHOW_TEXT, new Text("To page " + pageIndex))); - } else { - headerComponent.append(character + "", ComponentBuilder.FormatRetention.NONE).color(ChatColor.GRAY); - } - } - - sender.spigot().sendMessage(headerComponent.create()); - - // Print the previous page button - ComponentBuilder previousComponent = new ComponentBuilder(); - if (page > 1) { - String fullCommand = "/" + command + " page" + (page - 1); - HoverEvent prevPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("To page " + (page - 1))); - ClickEvent prevPageClick = new ClickEvent(ClickEvent.Action.RUN_COMMAND, fullCommand); - previousComponent.append("Previous [<]").event(prevPagePreview).event(prevPageClick); - } else { - previousComponent.append("Previous [<]").color(ChatColor.GRAY); - } - sender.spigot().sendMessage(previousComponent.create()); - - // Print the main list of all book indexes and titles - int startIndex = (page - 1) * booksPerPage; - for (int bookIndex = startIndex; bookIndex < Math.min(startIndex + booksPerPage, availableBooks.size()); bookIndex++) { - ComponentBuilder bookComponent = new ComponentBuilder(); - bookComponent.append("[" + (bookIndex + 1) + "]").color(ChatColor.GOLD).event( - new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " + - (bookIndex + 1))).event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new Text("Select book by index"))); - - bookComponent.append(" ", ComponentBuilder.FormatRetention.NONE); - - bookComponent.append(getNiceName(availableBooks.get(bookIndex))).color(ChatColor.WHITE).event( - new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " + - availableBooks.get(bookIndex))).event( - new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Select book by path"))); - sender.spigot().sendMessage(bookComponent.create()); - } - - // Print the next page button - ComponentBuilder nextComponent = new ComponentBuilder(); - if (page < totalPages) { - String fullCommand = "/" + command + " page" + (page + 1); - HoverEvent nextPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("To page " + (page + 1))); - ClickEvent nextPageClick = new ClickEvent(ClickEvent.Action.RUN_COMMAND, fullCommand); - nextComponent.append("Next [>]").event(nextPagePreview).event(nextPageClick); - } else { - nextComponent.append("Next [>]").color(ChatColor.GRAY); - } - nextComponent.append(" Page " + page + " of " + totalPages + " ", - ComponentBuilder.FormatRetention.NONE).color(ChatColor.GREEN); - nextComponent.append("[Page Command]", ComponentBuilder.FormatRetention.NONE).event(new HoverEvent( - HoverEvent.Action.SHOW_TEXT, new Text("/" + command + " page" + page))).event( - new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " page" + page)); - sender.spigot().sendMessage(nextComponent.create()); - } - - /** - * Gets a nice name from a book's path - * - * @param bookPath

The path of a book

- * @return

The prettified book name

- */ - @NotNull - private static String getNiceName(@NotNull String bookPath) { - bookPath = ChatColor.translateAlternateColorCodes('&', bookPath.substring(0, bookPath.length() - 4)); - String[] parts = bookPath.split(","); - return parts[0].replace("_", " ") + ChatColor.RESET + " by " + parts[1] + ChatColor.RESET; - } - /** * Gets a map between characters, and the first instance of a book's title starting with that character *