diff options
Diffstat (limited to 'src')
4 files changed, 126 insertions, 131 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt b/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt index 0f07c47f8..2eb5dc3fb 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt @@ -3,14 +3,9 @@ package at.hannibal2.skyhanni.features.commands import at.hannibal2.skyhanni.config.commands.Commands import at.hannibal2.skyhanni.utils.StringUtils.splitLines import at.hannibal2.skyhanni.utils.chat.Text -import at.hannibal2.skyhanni.utils.chat.Text.asComponent -import at.hannibal2.skyhanni.utils.chat.Text.center import at.hannibal2.skyhanni.utils.chat.Text.hover -import at.hannibal2.skyhanni.utils.chat.Text.onClick -import at.hannibal2.skyhanni.utils.chat.Text.send import at.hannibal2.skyhanni.utils.chat.Text.suggest import net.minecraft.util.IChatComponent -import kotlin.math.ceil object HelpCommand { @@ -35,57 +30,21 @@ object HelpCommand { } } - private fun showPage( - page: Int, - search: String, - commands: List<Commands.CommandInfo>, - ) { + private fun showPage(page: Int, search: String, commands: List<Commands.CommandInfo>) { val filtered = commands.filter { it.name.contains(search, ignoreCase = true) || it.description.contains(search, ignoreCase = true) } - val maxPage = if (filtered.isNotEmpty()) { - ceil(filtered.size.toDouble() / COMMANDS_PER_PAGE).toInt() - } else 1 - val page = page.coerceIn(1, maxPage) - val title = if (search.isEmpty()) "§6SkyHanni Commands" else "§6SkyHanni Commands matching '$search'" + val title = if (search.isBlank()) "SkyHanni Commands" else "SkyHanni Commands Matching: \"$search\"" - val text = mutableListOf<IChatComponent>() - - text.add(Text.createDivider()) - text.add(title.asComponent().center()) - text.add( - Text.join( - if (page > 1) "§6§l<<".asComponent { - this.hover = "§eClick to view page ${page - 1}".asComponent() - this.onClick { showPage(page - 1, search, commands) } - } else null, - " ", - "§6(Page $page of $maxPage)", - " ", - if (page < maxPage) "§6§l>>".asComponent { - this.hover = "§eClick to view page ${page + 1}".asComponent() - this.onClick { showPage(page + 1, search, commands) } - } else null, - ).center(), - ) - text.add(Text.createDivider()) - - if (filtered.isEmpty()) { - text.add(Text.EMPTY) - text.add("§cNo commands found.".asComponent().center()) - text.add(Text.EMPTY) - } else { - val start = (page - 1) * COMMANDS_PER_PAGE - val end = (page * COMMANDS_PER_PAGE).coerceAtMost(filtered.size) - for (i in start until end) { - text.add(createCommandEntry(filtered[i])) - } - } - - text.add(Text.createDivider()) - - Text.multiline(text).send(HELP_ID) + Text.displayPaginatedList( + title, + filtered, + chatLineId = HELP_ID, + emptyMessage = "No commands found.", + currentPage = page, + maxPerPage = COMMANDS_PER_PAGE, + ) { createCommandEntry(it) } } fun onCommand(args: Array<String>, commands: List<Commands.CommandInfo>) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt index 3e15e404c..7f67dd98c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt @@ -6,18 +6,16 @@ import at.hannibal2.skyhanni.data.model.GraphNode import at.hannibal2.skyhanni.data.model.GraphNodeTag import at.hannibal2.skyhanni.data.model.findShortestDistance import at.hannibal2.skyhanni.utils.CollectionUtils.sorted -import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.chat.Text import at.hannibal2.skyhanni.utils.chat.Text.asComponent -import at.hannibal2.skyhanni.utils.chat.Text.center import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.chat.Text.onClick import at.hannibal2.skyhanni.utils.chat.Text.send import kotlinx.coroutines.launch -import net.minecraft.util.IChatComponent object NavigationHelper { - private val NAVIGATION_CHAT_ID = -6457562 + private const val NAVIGATION_CHAT_ID = -6457562 val allowedTags = listOf( GraphNodeTag.NPC, @@ -41,40 +39,41 @@ object NavigationHelper { private fun doCommandAsync(args: Array<String>) { val searchTerm = args.joinToString(" ").lowercase() val distances = calculateDistances(searchTerm) - val names = calculateNames(distances) + val locations = calculateNames(distances) - val text = mutableListOf<IChatComponent>() - text.add(Text.createDivider()) - text.add("§7Found ${names.size} locations ($searchTerm)".asComponent().center()) val goBack = { onCommand(searchTerm.split(" ").toTypedArray()) IslandGraphs.stop() } - // TODO dont show a too long list, add pages - for ((name, node) in names) { - val distance = distances[node]!!.round(1) + val title = if (searchTerm.isBlank()) "SkyHanni Navigation Locations" else "SkyHanni Navigation Locations Matching: \"$searchTerm\"" + + Text.displayPaginatedList( + title, + locations, + chatLineId = NAVIGATION_CHAT_ID, + emptyMessage = "No locations found.", + ) { (name, node) -> + val distance = distances[node]!!.roundTo(1) val component = "$name §e$distance".asComponent() component.onClick { IslandGraphs.pathFind(node.position) sendNavigateMessage(name, goBack) } val tag = node.tags.first { it in allowedTags } - // TODO include most closest area, if this is no area (type in area = forger in forge) component.hover = ("§eClick to start navigating to\n" + "§7Type: §r${tag.displayName}\n" + "§7Distance: §e$distance blocks").asComponent() - text.add(component) + component } - text.add(Text.createDivider()) - Text.multiline(text).send(NAVIGATION_CHAT_ID) } private fun sendNavigateMessage(name: String, goBack: () -> Unit) { val componentText = "§7Navigating to §r$name".asComponent() componentText.onClick(onClick = goBack) + componentText.hover = "§eClick to stop navigating and return to previous search".asComponent() componentText.send(NAVIGATION_CHAT_ID) } - private fun calculateNames(distances: Map<GraphNode, Double>): MutableMap<String, GraphNode> { + private fun calculateNames(distances: Map<GraphNode, Double>): List<Pair<String, GraphNode>> { val names = mutableMapOf<String, GraphNode>() for (node in distances.sorted().keys) { // hiding areas that are none @@ -84,23 +83,23 @@ object NavigationHelper { if (name in names) continue names[name] = node } - return names + return names.toList() } private fun calculateDistances( searchTerm: String, ): Map<GraphNode, Double> { - val grapth = IslandGraphs.currentIslandGraph ?: return emptyMap() + val graph = IslandGraphs.currentIslandGraph ?: return emptyMap() val closedNote = IslandGraphs.closedNote ?: return emptyMap() - val nodes = grapth.nodes + val nodes = graph.nodes val distances = mutableMapOf<GraphNode, Double>() for (node in nodes) { val name = node.name ?: continue val remainingTags = node.tags.filter { it in allowedTags } if (remainingTags.isEmpty()) continue if (name.lowercase().contains(searchTerm)) { - distances[node] = grapth.findShortestDistance(closedNote, node) + distances[node] = graph.findShortestDistance(closedNote, node) } if (remainingTags.size != 1) { println("found node with invalid amount of tags: ${node.name} (${remainingTags.map { it.cleanName }}") diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt index 1df878ac9..a4ee7bc6a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt @@ -11,7 +11,6 @@ import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.TimeUtils.minutes import at.hannibal2.skyhanni.utils.chat.Text import at.hannibal2.skyhanni.utils.chat.Text.asComponent -import at.hannibal2.skyhanni.utils.chat.Text.center import at.hannibal2.skyhanni.utils.chat.Text.command import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.chat.Text.send @@ -49,65 +48,34 @@ object ReminderManager { } private fun listReminders(page: Int) { - val reminders = getSortedReminders() - val maxPage = (reminders.size + REMINDERS_PER_PAGE - 1) / REMINDERS_PER_PAGE - - listPage = page.coerceIn(0, maxPage) - - val text: MutableList<IChatComponent> = mutableListOf() - - text.add(Text.createDivider()) - - text.add( + Text.displayPaginatedList( + "SkyHanni Reminders", + getSortedReminders(), + chatLineId = REMINDERS_LIST_ID, + emptyMessage = "No reminders found.", + currentPage = page, + maxPerPage = REMINDERS_PER_PAGE, + ) { reminderEntry -> + val id = reminderEntry.key + val reminder = reminderEntry.value Text.join( - if (listPage > 1) "§6§l<<".asComponent { - hover = "§eClick to view page ${listPage - 1}".asComponent() - command = "/shremind list ${listPage - 1}" - } else null, + "§c✕".asComponent { + hover = "§7Click to remove".asComponent() + command = "/shremind remove -l $id" + }.wrap("§8[", "§8]"), " ", - "§6Reminders (Page $listPage of $maxPage)", + "§e✎".asComponent { + hover = "§7Click to start editing".asComponent() + suggest = "/shremind edit -l $id ${reminder.reason} " + }.wrap("§8[", "§8]"), " ", - if (listPage < maxPage) "§6§l>>".asComponent { - hover = "§eClick to view page ${listPage + 1}".asComponent() - command = "/shremind list ${listPage + 1}" - } else null, - ).center(), - ) - - if (reminders.isNotEmpty()) { - for (i in (listPage - 1) * REMINDERS_PER_PAGE until listPage * REMINDERS_PER_PAGE) { - if (i >= reminders.size) break - val (id, reminder) = reminders[i] - - text.add( - Text.join( - "§c✕".asComponent { - hover = "§7Click to remove".asComponent() - command = "/shremind remove -l $id" - }.wrap("§8[", "§8]"), - " ", - "§e✎".asComponent { - hover = "§7Click to start editing".asComponent() - suggest = "/shremind edit -l $id ${reminder.reason} " - }.wrap("§8[", "§8]"), - " ", - "§6${reminder.formatShort()}".asComponent { - hover = "§7${reminder.formatFull()}".asComponent() - }.wrap("§8[", "§8]"), - " ", - "§7${reminder.reason}", - ), - ) - } - } else { - text.add(Text.EMPTY) - text.add("§cNo reminders found.".asComponent().center()) - text.add(Text.EMPTY) + "§6${reminder.formatShort()}".asComponent { + hover = "§7${reminder.formatFull()}".asComponent() + }.wrap("§8[", "§8]"), + " ", + "§7${reminder.reason}", + ) } - - text.add(Text.createDivider()) - - Text.join(*text.toTypedArray(), separator = Text.NEWLINE).send(REMINDERS_LIST_ID) } private fun createReminder(args: Array<String>) { diff --git a/src/main/java/at/hannibal2/skyhanni/utils/chat/Text.kt b/src/main/java/at/hannibal2/skyhanni/utils/chat/Text.kt index 024550ec5..fe7486d0d 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/chat/Text.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/chat/Text.kt @@ -60,6 +60,7 @@ object Text { } return this } + fun IChatComponent.center(width: Int = Minecraft.getMinecraft().ingameGUI.chatGUI.chatWidth): IChatComponent { val textWidth = this.width() val spaceWidth = SPACE.width() @@ -99,10 +100,78 @@ object Text { this.command = "/shaction $token" } - - fun createDivider() = Text.HYPHEN.fitToChat().style { + fun createDivider(dividerColor: EnumChatFormatting = EnumChatFormatting.BLUE) = HYPHEN.fitToChat().style { strikethrough = true - color = EnumChatFormatting.BLUE + color = dividerColor + } + + /** + * Displays a paginated list of entries in the chat. + * + * @param title The title of the paginated list. + * @param list The list of entries to paginate and display. + * @param chatLineId The ID of the chat line for message updates. + * @param emptyMessage The message to display if the list is empty. + * @param currentPage The current page to display. + * @param maxPerPage The number of entries to display per page. + * @param dividerColor The color of the divider lines. + * @param formatter A function to format each entry into an IChatComponent. + */ + fun <T> displayPaginatedList( + title: String, + list: List<T>, + chatLineId: Int, + emptyMessage: String, + currentPage: Int = 1, + maxPerPage: Int = 15, + dividerColor: EnumChatFormatting = EnumChatFormatting.BLUE, + formatter: (T) -> IChatComponent, + ) { + val text = mutableListOf<IChatComponent>() + + val totalPages = (list.size + maxPerPage - 1) / maxPerPage + val page = if (totalPages == 0) 0 else currentPage + + text.add(createDivider(dividerColor)) + text.add("§6$title".asComponent().center()) + + if (totalPages > 1) { + text.add( + join( + if (page > 1) "§6§l<<".asComponent { + hover = "§eClick to view page ${page - 1}".asComponent() + onClick { + displayPaginatedList(title, list, chatLineId, emptyMessage, page - 1, maxPerPage, dividerColor, formatter) + } + } else null, + " ", + "§6(Page $page of $totalPages)", + " ", + if (page < totalPages) "§6§l>>".asComponent { + hover = "§eClick to view page ${page + 1}".asComponent() + onClick { + displayPaginatedList(title, list, chatLineId, emptyMessage, page + 1, maxPerPage, dividerColor, formatter) + } + } else null, + ).center(), + ) + } + + text.add(createDivider(dividerColor)) + + if (list.isNotEmpty()) { + val start = (page - 1) * maxPerPage + val end = (page * maxPerPage).coerceAtMost(list.size) + for (i in start until end) { + text.add(formatter(list[i])) + } + } else { + text.add(EMPTY) + text.add("§c$emptyMessage".asComponent().center()) + text.add(EMPTY) + } + + text.add(createDivider(dividerColor)) + multiline(text).send(chatLineId) } - } |