From a0fb59d0eec7795c91e2e54c0b84c4468bd166fc Mon Sep 17 00:00:00 2001 From: downthecrop Date: Fri, 3 Oct 2025 17:13:23 -0700 Subject: [PATCH] rename and some QOL display stuff --- .../plugin.kt | 42 ++-- .../kotlin/ChatboxHelmets/plugin.properties | 5 + .../kotlin/FooTextPlugin/plugin.properties | 3 - .../src/main/kotlin/KondoKit/plugin.kt | 5 + .../KondoKit/views/ReflectiveEditorView.kt | 189 +++++++++--------- 5 files changed, 120 insertions(+), 124 deletions(-) rename plugin-playground/src/main/kotlin/{FooTextPlugin => ChatboxHelmets}/plugin.kt (93%) create mode 100644 plugin-playground/src/main/kotlin/ChatboxHelmets/plugin.properties delete mode 100644 plugin-playground/src/main/kotlin/FooTextPlugin/plugin.properties diff --git a/plugin-playground/src/main/kotlin/FooTextPlugin/plugin.kt b/plugin-playground/src/main/kotlin/ChatboxHelmets/plugin.kt similarity index 93% rename from plugin-playground/src/main/kotlin/FooTextPlugin/plugin.kt rename to plugin-playground/src/main/kotlin/ChatboxHelmets/plugin.kt index be84b59..0b473b8 100644 --- a/plugin-playground/src/main/kotlin/FooTextPlugin/plugin.kt +++ b/plugin-playground/src/main/kotlin/ChatboxHelmets/plugin.kt @@ -1,4 +1,4 @@ -package FooTextPlugin +package ChatboxHelmets import KondoKit.Exposed import plugin.Plugin @@ -13,17 +13,11 @@ import java.io.InputStreamReader import java.net.HttpURLConnection import java.net.URL -/** - * Iron Helmets in Chatbox - * - * Will be integrated into Kondo - * - * @author downthecrop - */ class plugin : Plugin() { private val TARGET_COMPONENT_ID = 8978483 private val TARGET_COMPONENT_INDEX = 51 + private val SETTINGS_KEY = "chat-helms" private val BUBBLE_ICON = "" private val gson = Gson() @@ -241,7 +235,7 @@ class plugin : Plugin() { override fun Init() { // Load username matches from local storage - val storedData = API.GetData("foo-text-username-matches") + val storedData = API.GetData(SETTINGS_KEY) usernameMatches = when (storedData) { is String -> { try { @@ -251,16 +245,6 @@ class plugin : Plugin() { HashMap() } } - is HashMap<*, *> -> { - // Old format: Direct HashMap (for backward compatibility) - try { - @Suppress("UNCHECKED_CAST") - storedData as HashMap - } catch (e: Exception) { - println("Failed to cast username matches: ${e.message}") - HashMap() - } - } else -> { // No data or unexpected format HashMap() @@ -280,13 +264,13 @@ class plugin : Plugin() { override fun OnPluginsReloaded(): Boolean { grabConfig() - return true + return false } private fun StoreData() { val jsonString = gson.toJson(usernameMatches) println("Storing ${jsonString}") - API.StoreData("foo-text-username-matches", jsonString) + API.StoreData(SETTINGS_KEY, jsonString) } override fun Draw(timeDelta: Long) { @@ -356,6 +340,22 @@ class plugin : Plugin() { fetchAccountTypeFromAPI() } + // Allow setting from the chatbox + override fun ProcessCommand(commandStr: String?, args: Array?) { + super.ProcessCommand(commandStr, args) + when(commandStr) { + "::chathelm" -> { + if (args != null) { + if(args.isEmpty()) return + val type = args[0].toIntOrNull() ?: return + ACCOUNT_TYPE = type + usernameMatches[getCleanUserName()] = ACCOUNT_TYPE + StoreData() + } + } + } + } + private fun replaceUsernameInBytes(bytes: ByteArray, username: String): String { // Convert bytes to string to work with them val text = String(bytes, StandardCharsets.ISO_8859_1) diff --git a/plugin-playground/src/main/kotlin/ChatboxHelmets/plugin.properties b/plugin-playground/src/main/kotlin/ChatboxHelmets/plugin.properties new file mode 100644 index 0000000..439b02b --- /dev/null +++ b/plugin-playground/src/main/kotlin/ChatboxHelmets/plugin.properties @@ -0,0 +1,5 @@ +AUTHOR='downthecrop' +DESCRIPTION='Displays account type icons next to usernames in chat pulled from the live server API. \ + Can be set with a chat command for single player with ::chathelm 1 (0=Normal, 1=IM, 2=HCIM, 3=UIM) \ + or via KondoKit settings.' +VERSION=1.0 \ No newline at end of file diff --git a/plugin-playground/src/main/kotlin/FooTextPlugin/plugin.properties b/plugin-playground/src/main/kotlin/FooTextPlugin/plugin.properties deleted file mode 100644 index 4e30d94..0000000 --- a/plugin-playground/src/main/kotlin/FooTextPlugin/plugin.properties +++ /dev/null @@ -1,3 +0,0 @@ -AUTHOR=YourName -DESCRIPTION=Displays account type icons next to usernames in chat. Uses local storage to cache results and avoid API calls. Supports manual entries for players not on live server. -VERSION=1.0 \ No newline at end of file diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 17a999b..068a7c9 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -309,6 +309,11 @@ class plugin : Plugin() { destroyAltCanvas() } else if (useScaledFixed && altCanvas == null) { initAltCanvas() + } else if (!useScaledFixed && altCanvas != null) { + // Was using scaled fixed but toggled the setting + // restore the original canvas + moveCanvasToFront() + destroyAltCanvas() } when (mode) { diff --git a/plugin-playground/src/main/kotlin/KondoKit/views/ReflectiveEditorView.kt b/plugin-playground/src/main/kotlin/KondoKit/views/ReflectiveEditorView.kt index 535d0dd..92f9229 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/views/ReflectiveEditorView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/views/ReflectiveEditorView.kt @@ -9,7 +9,6 @@ import KondoKit.components.ReflectiveEditorComponents.PluginDownloadManager import KondoKit.components.ReflectiveEditorComponents.PluginProperties import KondoKit.components.ReflectiveEditorComponents.PluginStatus import KondoKit.Helpers.showToast -import KondoKit.plugin import KondoKit.plugin.Companion.TITLE_BAR_COLOR import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR @@ -46,21 +45,22 @@ object ReflectiveEditorView : View { const val PLUGIN_DETAIL_VIEW = "PLUGIN_DETAIL" val pluginsDirectory: File = File(GlobalJsonConfig.instance.pluginsFolder) - // Store fetched GitLab plugins private var gitLabPlugins: List = listOf() - // Store combined plugin status (installed + remote) private var pluginStatuses: List = listOf() - // Store the cog icon to be reused private var cogIcon: Icon? = null - // Store reference to the search field private var searchField: CustomSearchField? = null // Flag for scheduled plugin reload to avoid crashes private var reloadPlugins = false + // Helper function to check if a plugin is the KondoKit plugin + private fun isKondoKit(pluginName: String): Boolean { + return pluginName == "KondoKit" + } + private fun loadCogIcon() { try { val imageStream = this::class.java.getResourceAsStream("res/cog.png") @@ -94,40 +94,31 @@ object ReflectiveEditorView : View { } override fun registerFunctions() { - // Reflective editor functions are handled within the view itself } fun createReflectiveEditorView() { - // Load the cog icon once loadCogIcon() - // Create the main panel with card layout cardLayout = CardLayout() mainPanel = JPanel(cardLayout) mainPanel.background = VIEW_BACKGROUND_COLOR mainPanel.border = BorderFactory.createEmptyBorder(0, 0, 0, 0) - // Help minimize flicker during dynamic swaps mainPanel.isDoubleBuffered = true - // Create the plugin list view val pluginListView = createPluginListView() pluginListView.name = PLUGIN_LIST_VIEW mainPanel.add(pluginListView, PLUGIN_LIST_VIEW) - // Create a placeholder for the plugin detail view val pluginDetailView = BaseView(PLUGIN_DETAIL_VIEW).apply { layout = BorderLayout() background = VIEW_BACKGROUND_COLOR } mainPanel.add(pluginDetailView, PLUGIN_DETAIL_VIEW) - // Set the reflectiveEditorView to our main panel reflectiveEditorView = mainPanel - // Show the plugin list view by default cardLayout.show(mainPanel, PLUGIN_LIST_VIEW) - // Fetch GitLab plugins in the background GitLabPluginFetcher.fetchGitLabPlugins { plugins -> System.out.println("GitLab plugins fetched: ${plugins.size}") gitLabPlugins = plugins @@ -142,17 +133,13 @@ object ReflectiveEditorView : View { panel.layout = BoxLayout(panel, BoxLayout.Y_AXIS) panel.background = VIEW_BACKGROUND_COLOR - // Add search field at the top val searchField = CustomSearchField(panel) { searchText -> pluginSearchText = searchText - // Refresh the plugin list to apply filtering SwingUtilities.invokeLater { addPlugins(reflectiveEditorView!!) } } - // Store reference to the search field this.searchField = searchField - // Restore the search text if it exists if (pluginSearchText.isNotBlank()) { searchField.setText(pluginSearchText) } @@ -168,9 +155,9 @@ object ReflectiveEditorView : View { } searchFieldWrapper = searchFieldWrapperPanel - panel.add(Box.createVerticalStrut(10)) // Spacer + panel.add(Box.createVerticalStrut(10)) panel.add(searchFieldWrapperPanel) - panel.add(Box.createVerticalStrut(10)) // Spacer + panel.add(Box.createVerticalStrut(10)) try { // Get loaded plugins @@ -200,18 +187,21 @@ object ReflectiveEditorView : View { } } - // Sort both lists by package name - pluginsWithExposed.sortBy { it.second.javaClass.`package`.name } - pluginsWithoutExposed.sortBy { it.second.javaClass.`package`.name } + pluginsWithExposed.sortWith(compareBy( + { if (isKondoKit(it.second.javaClass.`package`.name)) 0 else 1 }, + { it.second.javaClass.`package`.name } + )) + pluginsWithoutExposed.sortWith(compareBy( + { if (isKondoKit(it.second.javaClass.`package`.name)) 0 else 1 }, + { it.second.javaClass.`package`.name } + )) - // Add plugins with exposed attributes first for ((pluginInfo, plugin) in pluginsWithExposed) { val pluginPanel = createPluginItemPanel(pluginInfo, plugin) panel.add(pluginPanel) panel.add(Box.createVerticalStrut(5)) } - // Add a separator if we have plugins with exposed attributes if (pluginsWithExposed.isNotEmpty() && pluginsWithoutExposed.isNotEmpty()) { val separator = JPanel() separator.background = VIEW_BACKGROUND_COLOR @@ -221,7 +211,6 @@ object ReflectiveEditorView : View { panel.add(Box.createVerticalStrut(5)) } - // Add plugins without exposed attributes for ((pluginInfo, plugin) in pluginsWithoutExposed) { val pluginPanel = createPluginItemPanel(pluginInfo, plugin) panel.add(pluginPanel) @@ -231,14 +220,14 @@ object ReflectiveEditorView : View { e.printStackTrace() } - // Add disabled plugins to the list (filtered by search text) val disabledDir = File(pluginsDirectory, "disabled") if (disabledDir.exists() && disabledDir.isDirectory) { val disabledPlugins = disabledDir.listFiles { file -> file.isDirectory } ?: arrayOf() - // Add disabled plugins to the list without exposed attributes (filtered by search text) for (pluginDir in disabledPlugins.sortedBy { it.name }) { - // Apply search filter + if (isKondoKit(pluginDir.name)) { + continue + } if (pluginSearchText.isBlank() || pluginDir.name.contains(pluginSearchText, ignoreCase = true)) { val pluginPanel = createDisabledPluginItemPanel(pluginDir.name) panel.add(pluginPanel) @@ -247,15 +236,14 @@ object ReflectiveEditorView : View { } } - // Add a section for available plugins from GitLab that are not installed - // Only show this section when there's a search term if (pluginSearchText.isNotBlank()) { System.out.println("Filtering plugins for search term: '$pluginSearchText'") System.out.println("Total plugin statuses: ${pluginStatuses.size}") val matchingPluginStatuses = pluginStatuses.filter { pluginStatus -> - // Only show plugins that are not currently loaded + // Only show plugins that are not currently loaded and not KondoKit val shouldShow = !pluginStatus.isInstalled && + !isKondoKit(pluginStatus.name) && (pluginStatus.name.contains(pluginSearchText, ignoreCase = true) || (pluginStatus.description?.contains(pluginSearchText, ignoreCase = true) ?: false)) @@ -274,8 +262,6 @@ object ReflectiveEditorView : View { panel.add(separator) panel.add(Box.createVerticalStrut(5)) - // Add a header for available plugins - // Always add the label even if there are no matching plugins to maintain proper layout val headerPanel = JPanel(FlowLayout(FlowLayout.LEFT)) headerPanel.background = VIEW_BACKGROUND_COLOR val headerLabel = JLabel(if (matchingPluginStatuses.isNotEmpty()) "Available Plugins" else "") @@ -286,7 +272,6 @@ object ReflectiveEditorView : View { panel.add(Box.createVerticalStrut(5)) if (matchingPluginStatuses.isNotEmpty()) { - // Add download all button if there are multiple plugins if (matchingPluginStatuses.size > 1) { val downloadAllPanel = JPanel(FlowLayout(FlowLayout.LEFT)) downloadAllPanel.background = VIEW_BACKGROUND_COLOR @@ -366,10 +351,19 @@ object ReflectiveEditorView : View { null } - // Plugin toggle switch (iOS style) - val toggleSwitch = createToggleSwitch(plugin, pluginInfo) + // Plugin toggle switch (iOS style) - skip for KondoKit since it should always be on + val toggleSwitch = if (!isKondoKit(packageName)) { + createToggleSwitch(plugin, pluginInfo) + } else { + // Create a placeholder component that takes the same space but is invisible + val placeholder = JPanel() + placeholder.background = WIDGET_COLOR + placeholder.preferredSize = Dimension(60, 24) // Same size as toggle switch + placeholder.maximumSize = Dimension(60, 24) + placeholder.isVisible = false + placeholder + } - // Layout val infoPanel = JPanel(BorderLayout()) infoPanel.background = WIDGET_COLOR infoPanel.add(nameLabel, BorderLayout.WEST) @@ -377,17 +371,16 @@ object ReflectiveEditorView : View { val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 5, 0)) controlsPanel.background = WIDGET_COLOR - // Add edit button first (left side of controls) editButton?.let { controlsPanel.add(it) } - // Add toggle switch second (right side of controls) - controlsPanel.add(toggleSwitch) + if (!isKondoKit(packageName)) { + controlsPanel.add(toggleSwitch) + } panel.add(infoPanel, BorderLayout.CENTER) panel.add(controlsPanel, BorderLayout.EAST) - // Add right-click context menu (except for KondoKit itself) - if (packageName != "KondoKit") { + if (!isKondoKit(packageName)) { val popupMenu = createPluginContextMenu(plugin, pluginInfo, packageName, false) addContextMenuToPanel(panel, popupMenu) } @@ -432,49 +425,13 @@ object ReflectiveEditorView : View { panel.add(controlsPanel, BorderLayout.EAST) // Add right-click context menu (except for KondoKit itself) - if (pluginName != "KondoKit") { + if (!isKondoKit(pluginName)) { val popupMenu = createPluginContextMenu(null, null, pluginName, true) addContextMenuToPanel(panel, popupMenu) } return panel } - - private fun createGitLabPluginItemPanel(gitLabPlugin: GitLabPlugin): JPanel { - val panel = JPanel(BorderLayout()) - panel.background = WIDGET_COLOR - panel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10) - panel.maximumSize = Dimension(220, 60) - - // Plugin name - val nameLabel = JLabel(gitLabPlugin.path) - nameLabel.foreground = secondaryColor - nameLabel.font = Font("RuneScape Small", Font.PLAIN, 16) - - // Download button - val downloadButton = JButton("Download") - downloadButton.background = TITLE_BAR_COLOR - downloadButton.foreground = secondaryColor - downloadButton.font = Font("RuneScape Small", Font.PLAIN, 14) - downloadButton.addActionListener { - // TODO: Implement download functionality - showToast(mainPanel, "Download functionality not yet implemented", JOptionPane.INFORMATION_MESSAGE) - } - - // Layout - val infoPanel = JPanel(BorderLayout()) - infoPanel.background = WIDGET_COLOR - infoPanel.add(nameLabel, BorderLayout.WEST) - - val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 5, 0)) - controlsPanel.background = WIDGET_COLOR - controlsPanel.add(downloadButton) - - panel.add(infoPanel, BorderLayout.CENTER) - panel.add(controlsPanel, BorderLayout.EAST) - - return panel - } private fun createPluginStatusItemPanel(pluginStatus: PluginStatus): JPanel { val panel = JPanel(BorderLayout()) @@ -524,22 +481,28 @@ object ReflectiveEditorView : View { // Plugin toggle switch (iOS style) val toggleSwitch = ToggleSwitch() - toggleSwitch.setActivated(pluginStatus.isInstalled && !pluginStatus.needsUpdate) - toggleSwitch.isEnabled = pluginStatus.isInstalled && !pluginStatus.needsUpdate - if (pluginStatus.isInstalled && !pluginStatus.needsUpdate) { - toggleSwitch.onToggleListener = { activated -> - // TODO: Implement enable/disable functionality - showToast(mainPanel, "Enable/disable functionality not yet implemented", JOptionPane.INFORMATION_MESSAGE) - // Reset for now since functionality not implemented - toggleSwitch.setActivated(true) - } - } else { - // Hide the toggle switch for non-installed plugins + // Skip the toggle switch for KondoKit since it should always be enabled + if (isKondoKit(pluginStatus.name)) { + // Hide the toggle switch for KondoKit toggleSwitch.isVisible = false + } else { + toggleSwitch.setActivated(pluginStatus.isInstalled && !pluginStatus.needsUpdate) + toggleSwitch.isEnabled = pluginStatus.isInstalled && !pluginStatus.needsUpdate + + if (pluginStatus.isInstalled && !pluginStatus.needsUpdate) { + toggleSwitch.onToggleListener = { activated -> + // TODO: Implement enable/disable functionality + showToast(mainPanel, "Enable/disable functionality not yet implemented", JOptionPane.INFORMATION_MESSAGE) + // Reset for now since functionality not implemented + toggleSwitch.setActivated(true) + } + } else { + // Hide the toggle switch for non-installed plugins + toggleSwitch.isVisible = false + } } - // Layout val infoPanel = JPanel(BorderLayout()) infoPanel.background = WIDGET_COLOR infoPanel.add(nameLabel, BorderLayout.WEST) @@ -548,7 +511,6 @@ object ReflectiveEditorView : View { controlsPanel.background = WIDGET_COLOR controlsPanel.add(actionButton) controlsPanel.add(progressBar) - // Only add toggle switch if it's visible if (toggleSwitch.isVisible) { controlsPanel.add(toggleSwitch) } @@ -556,8 +518,7 @@ object ReflectiveEditorView : View { panel.add(infoPanel, BorderLayout.CENTER) panel.add(controlsPanel, BorderLayout.EAST) - // Add right-click context menu only for installed plugins (except for KondoKit itself) - if (pluginStatus.name != "KondoKit" && pluginStatus.isInstalled) { + if (!isKondoKit(pluginStatus.name) && pluginStatus.isInstalled) { val popupMenu = createPluginContextMenu(null, null, pluginStatus.name, !pluginStatus.needsUpdate) addContextMenuToPanel(panel, popupMenu) } @@ -730,17 +691,16 @@ object ReflectiveEditorView : View { contentPanel.background = VIEW_BACKGROUND_COLOR contentPanel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10) - // Add plugin info val infoPanel = JPanel(BorderLayout()) infoPanel.background = WIDGET_COLOR infoPanel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10) - infoPanel.maximumSize = Dimension(Int.MAX_VALUE, 80) + val infoText = """ - Version: ${pluginInfo.version}
- Author: ${pluginInfo.author}
- Description: ${pluginInfo.description} + Version: ${(pluginInfo.version)}
+ Author: ${(pluginInfo.author ?: "").trim('\'')}
+ Description: ${(pluginInfo.description ?: "").trim('\'')} """.trimIndent() @@ -750,6 +710,31 @@ object ReflectiveEditorView : View { } infoPanel.add(infoLabel, BorderLayout.CENTER) + val font = Font("RuneScape Small", Font.PLAIN, 14) + val fm = infoLabel.getFontMetrics(font) + + val avgCharWidth = fm.stringWidth("x") + val availableWidth = 200 + val charsPerLine = availableWidth / avgCharWidth + + val textContent = infoText.replace("<[^>]*>".toRegex(), "") + val lines = textContent.split('\n').filter { it.isNotBlank() } + + var totalLines = 0 + for (line in lines) { + val lineLength = line.length + totalLines += kotlin.math.ceil(lineLength.toDouble() / charsPerLine).toInt() + } + + val lineHeight = fm.height + val estimatedHeight = (totalLines * lineHeight) + 20 + + val finalHeight = kotlin.math.max(60, kotlin.math.min(estimatedHeight, 150)) + infoPanel.maximumSize = Dimension(Int.MAX_VALUE, finalHeight) + infoPanel.preferredSize = Dimension(220, finalHeight) + + + contentPanel.add(infoPanel) contentPanel.add(Box.createVerticalStrut(10)) @@ -1120,6 +1105,10 @@ object ReflectiveEditorView : View { // Process remote plugins for (gitLabPlugin in gitLabPlugins) { val pluginName = gitLabPlugin.path + // Skip KondoKit since it should always be loaded + if (isKondoKit(pluginName)) { + continue + } val remoteVersion = gitLabPlugin.pluginProperties?.version ?: "Unknown" val description = gitLabPlugin.pluginProperties?.description ?: "No description available" val author = gitLabPlugin.pluginProperties?.author ?: "Unknown"