supa fixa

This commit is contained in:
downthecrop 2025-10-22 21:48:05 -07:00
parent 9f5d6f59e3
commit 16546ef862
3 changed files with 206 additions and 165 deletions

View file

@ -176,9 +176,22 @@ class plugin : Plugin() {
// Ensure Swing updates happen on the EDT to avoid flicker
SwingUtilities.invokeLater {
updateDisplaySettings()
frame.remove(rightPanelWrapper)
frame.layout = BorderLayout()
rightPanelWrapper?.let { frame.add(it, BorderLayout.EAST) }
rightPanelWrapper?.let { wrapper ->
wrapper.ignoreRepaint = true
try {
val parent = wrapper.parent
val wrapperNeedsAttach = parent != frame
if (wrapperNeedsAttach) {
parent?.remove(wrapper)
frame.layout = BorderLayout()
frame.add(wrapper, BorderLayout.EAST)
}
wrapper.revalidate()
wrapper.repaint()
} finally {
wrapper.ignoreRepaint = false
}
}
frame.revalidate()
frame.repaint()

View file

@ -83,6 +83,8 @@ object ReflectiveEditorView : View {
// Search text for filtering plugins
private var pluginSearchText: String = ""
private var searchFieldWrapper: JPanel? = null
private var pluginListContentPanel: JPanel? = null
private var pluginListScrollablePanel: ScrollablePanel? = null
override val name: String = VIEW_NAME
override val iconSpriteId: Int = WRENCH_ICON
@ -166,160 +168,179 @@ object ReflectiveEditorView : View {
panel.add(searchFieldWrapperPanel)
panel.add(Box.createVerticalStrut(10))
try {
// Get loaded plugins
val loadedPluginsField = PluginRepository::class.java.getDeclaredField("loadedPlugins")
loadedPluginsField.isAccessible = true
val loadedPlugins = loadedPluginsField.get(null) as HashMap<*, *>
// Separate plugins with and without exposed attributes
val pluginsWithExposed = mutableListOf<Pair<PluginInfo, Plugin>>()
val pluginsWithoutExposed = mutableListOf<Pair<PluginInfo, Plugin>>()
for ((pluginInfo, plugin) in loadedPlugins) {
val exposedFields = (plugin as Plugin).javaClass.declaredFields.filter { field ->
field.annotations.any { annotation ->
annotation.annotationClass.simpleName == "Exposed"
}
}
// Apply search filter
val pluginName = plugin.javaClass.`package`.name
if (pluginSearchText.isBlank() || pluginName.contains(pluginSearchText, ignoreCase = true)) {
if (exposedFields.isNotEmpty()) {
pluginsWithExposed.add(pluginInfo as PluginInfo to plugin)
} else {
pluginsWithoutExposed.add(pluginInfo as PluginInfo to plugin)
}
}
}
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 }
))
for ((pluginInfo, plugin) in pluginsWithExposed) {
val pluginPanel = createPluginItemPanel(pluginInfo, plugin)
panel.add(pluginPanel)
panel.add(Box.createVerticalStrut(5))
}
if (pluginsWithExposed.isNotEmpty() && pluginsWithoutExposed.isNotEmpty()) {
val separator = JPanel()
separator.background = VIEW_BACKGROUND_COLOR
separator.preferredSize = Dimension(Int.MAX_VALUE, 1)
separator.maximumSize = Dimension(Int.MAX_VALUE, 1)
panel.add(separator)
panel.add(Box.createVerticalStrut(5))
}
for ((pluginInfo, plugin) in pluginsWithoutExposed) {
val pluginPanel = createPluginItemPanel(pluginInfo, plugin)
panel.add(pluginPanel)
panel.add(Box.createVerticalStrut(5))
}
} catch (e: Exception) {
e.printStackTrace()
pluginListContentPanel = JPanel().apply {
layout = BoxLayout(this, BoxLayout.Y_AXIS)
background = VIEW_BACKGROUND_COLOR
alignmentX = Component.CENTER_ALIGNMENT
}
panel.add(pluginListContentPanel)
val disabledDir = File(pluginsDirectory, "disabled")
if (disabledDir.exists() && disabledDir.isDirectory) {
val disabledPlugins = disabledDir.listFiles { file -> file.isDirectory } ?: arrayOf()
for (pluginDir in disabledPlugins.sortedBy { it.name }) {
if (isKondoKit(pluginDir.name)) {
continue
}
if (pluginSearchText.isBlank() || pluginDir.name.contains(pluginSearchText, ignoreCase = true)) {
val pluginPanel = createDisabledPluginItemPanel(pluginDir.name)
panel.add(pluginPanel)
panel.add(Box.createVerticalStrut(5))
}
}
}
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 and not KondoKit
val shouldShow = !pluginStatus.isInstalled &&
!isKondoKit(pluginStatus.name) &&
(pluginStatus.name.contains(pluginSearchText, ignoreCase = true) ||
(pluginStatus.description?.contains(pluginSearchText, ignoreCase = true) ?: false))
System.out.println("Plugin: ${pluginStatus.name}, isInstalled: ${pluginStatus.isInstalled}, shouldShow: $shouldShow")
shouldShow
}
System.out.println("Matching plugin statuses: ${matchingPluginStatuses.size}")
// Add a separator
val separator = JPanel()
separator.background = VIEW_BACKGROUND_COLOR
separator.preferredSize = Dimension(Int.MAX_VALUE, 1)
separator.maximumSize = Dimension(Int.MAX_VALUE, 1)
panel.add(Box.createVerticalStrut(10))
panel.add(separator)
panel.add(Box.createVerticalStrut(5))
val headerPanel = JPanel(FlowLayout(FlowLayout.LEFT))
headerPanel.background = VIEW_BACKGROUND_COLOR
val headerLabel = JLabel(if (matchingPluginStatuses.isNotEmpty()) "Available Plugins" else "")
headerLabel.foreground = secondaryColor
headerLabel.font = Font("RuneScape Small", Font.BOLD, 16)
headerPanel.add(headerLabel)
panel.add(headerPanel)
panel.add(Box.createVerticalStrut(5))
if (matchingPluginStatuses.isNotEmpty()) {
if (matchingPluginStatuses.size > 1) {
val downloadAllPanel = JPanel(FlowLayout(FlowLayout.LEFT))
downloadAllPanel.background = VIEW_BACKGROUND_COLOR
val downloadAllButton = JButton("Download All")
downloadAllButton.background = TITLE_BAR_COLOR
downloadAllButton.foreground = secondaryColor
downloadAllButton.font = Font("RuneScape Small", Font.PLAIN, 14)
downloadAllButton.addActionListener {
startMultiplePluginDownloads(matchingPluginStatuses)
}
downloadAllPanel.add(downloadAllButton)
panel.add(downloadAllPanel)
panel.add(Box.createVerticalStrut(5))
}
// Add matching plugin statuses
for (pluginStatus in matchingPluginStatuses) {
System.out.println("Adding plugin to UI: ${pluginStatus.name}")
val pluginPanel = createPluginStatusItemPanel(pluginStatus)
panel.add(pluginPanel)
panel.add(Box.createVerticalStrut(5))
}
}
}
// Wrap the panel in a ScrollablePanel for custom scrolling
val scrollablePanel = ScrollablePanel(panel)
// Reset scroll position to top
SwingUtilities.invokeLater {
// For ScrollablePanel, we need to reset the internal offset
resetScrollablePanel(scrollablePanel)
}
pluginListScrollablePanel = scrollablePanel
val container = JPanel(BorderLayout())
container.background = VIEW_BACKGROUND_COLOR
container.add(scrollablePanel, BorderLayout.CENTER)
populatePluginListContent()
SwingUtilities.invokeLater {
resetScrollablePanel(scrollablePanel)
}
return container
}
private fun populatePluginListContent() {
val contentPanel = pluginListContentPanel ?: return
val treeLock = contentPanel.treeLock
synchronized(treeLock) {
contentPanel.removeAll()
try {
// Get loaded plugins
val loadedPluginsField = PluginRepository::class.java.getDeclaredField("loadedPlugins")
loadedPluginsField.isAccessible = true
val loadedPlugins = loadedPluginsField.get(null) as HashMap<*, *>
// Separate plugins with and without exposed attributes
val pluginsWithExposed = mutableListOf<Pair<PluginInfo, Plugin>>()
val pluginsWithoutExposed = mutableListOf<Pair<PluginInfo, Plugin>>()
for ((pluginInfo, plugin) in loadedPlugins) {
val exposedFields = (plugin as Plugin).javaClass.declaredFields.filter { field ->
field.annotations.any { annotation ->
annotation.annotationClass.simpleName == "Exposed"
}
}
// Apply search filter
val pluginName = plugin.javaClass.`package`.name
if (pluginSearchText.isBlank() || pluginName.contains(pluginSearchText, ignoreCase = true)) {
if (exposedFields.isNotEmpty()) {
pluginsWithExposed.add(pluginInfo as PluginInfo to plugin)
} else {
pluginsWithoutExposed.add(pluginInfo as PluginInfo to plugin)
}
}
}
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 }
))
for ((pluginInfo, plugin) in pluginsWithExposed) {
val pluginPanel = createPluginItemPanel(pluginInfo, plugin)
contentPanel.add(pluginPanel)
contentPanel.add(Box.createVerticalStrut(5))
}
if (pluginsWithExposed.isNotEmpty() && pluginsWithoutExposed.isNotEmpty()) {
val separator = JPanel()
separator.background = VIEW_BACKGROUND_COLOR
separator.preferredSize = Dimension(Int.MAX_VALUE, 1)
separator.maximumSize = Dimension(Int.MAX_VALUE, 1)
contentPanel.add(separator)
contentPanel.add(Box.createVerticalStrut(5))
}
for ((pluginInfo, plugin) in pluginsWithoutExposed) {
val pluginPanel = createPluginItemPanel(pluginInfo, plugin)
contentPanel.add(pluginPanel)
contentPanel.add(Box.createVerticalStrut(5))
}
} catch (e: Exception) {
e.printStackTrace()
}
val disabledDir = File(pluginsDirectory, "disabled")
if (disabledDir.exists() && disabledDir.isDirectory) {
val disabledPlugins = disabledDir.listFiles { file -> file.isDirectory } ?: arrayOf()
for (pluginDir in disabledPlugins.sortedBy { it.name }) {
if (isKondoKit(pluginDir.name)) {
continue
}
if (pluginSearchText.isBlank() || pluginDir.name.contains(pluginSearchText, ignoreCase = true)) {
val pluginPanel = createDisabledPluginItemPanel(pluginDir.name)
contentPanel.add(pluginPanel)
contentPanel.add(Box.createVerticalStrut(5))
}
}
}
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 and not KondoKit
val shouldShow = !pluginStatus.isInstalled &&
!isKondoKit(pluginStatus.name) &&
(pluginStatus.name.contains(pluginSearchText, ignoreCase = true) ||
(pluginStatus.description?.contains(pluginSearchText, ignoreCase = true) ?: false))
System.out.println("Plugin: ${pluginStatus.name}, isInstalled: ${pluginStatus.isInstalled}, shouldShow: $shouldShow")
shouldShow
}
System.out.println("Matching plugin statuses: ${matchingPluginStatuses.size}")
// Add a separator
val separator = JPanel()
separator.background = VIEW_BACKGROUND_COLOR
separator.preferredSize = Dimension(Int.MAX_VALUE, 1)
separator.maximumSize = Dimension(Int.MAX_VALUE, 1)
contentPanel.add(Box.createVerticalStrut(10))
contentPanel.add(separator)
contentPanel.add(Box.createVerticalStrut(5))
val headerPanel = JPanel(FlowLayout(FlowLayout.LEFT))
headerPanel.background = VIEW_BACKGROUND_COLOR
val headerLabel = JLabel(if (matchingPluginStatuses.isNotEmpty()) "Available Plugins" else "")
headerLabel.foreground = secondaryColor
headerLabel.font = Font("RuneScape Small", Font.BOLD, 16)
headerPanel.add(headerLabel)
contentPanel.add(headerPanel)
contentPanel.add(Box.createVerticalStrut(5))
if (matchingPluginStatuses.isNotEmpty()) {
if (matchingPluginStatuses.size > 1) {
val downloadAllPanel = JPanel(FlowLayout(FlowLayout.LEFT))
downloadAllPanel.background = VIEW_BACKGROUND_COLOR
val downloadAllButton = JButton("Download All")
downloadAllButton.background = TITLE_BAR_COLOR
downloadAllButton.foreground = secondaryColor
downloadAllButton.font = Font("RuneScape Small", Font.PLAIN, 14)
downloadAllButton.addActionListener {
startMultiplePluginDownloads(matchingPluginStatuses)
}
downloadAllPanel.add(downloadAllButton)
contentPanel.add(downloadAllPanel)
contentPanel.add(Box.createVerticalStrut(5))
}
// Add matching plugin statuses
for (pluginStatus in matchingPluginStatuses) {
System.out.println("Adding plugin to UI: ${pluginStatus.name}")
val pluginPanel = createPluginStatusItemPanel(pluginStatus)
contentPanel.add(pluginPanel)
contentPanel.add(Box.createVerticalStrut(5))
}
}
}
}
contentPanel.revalidate()
contentPanel.repaint()
}
private fun createPluginItemPanel(pluginInfo: PluginInfo, plugin: Plugin): JPanel {
val panel = JPanel(BorderLayout())
panel.background = WIDGET_COLOR
@ -793,30 +814,37 @@ object ReflectiveEditorView : View {
// Update plugin statuses to reflect current loaded plugins
updatePluginStatuses()
// Batch updates to avoid intermediate repaints/flicker
mainPanel.ignoreRepaint = true
try {
// Remove the existing plugin list view if present
val contentPanel = pluginListContentPanel
if (contentPanel == null) {
// Fallback path: rebuild the list view if it was not initialized yet
val existingListView = mainPanel.components.find { it.name == PLUGIN_LIST_VIEW }
val pluginListView = createPluginListView()
pluginListView.name = PLUGIN_LIST_VIEW
if (existingListView != null) {
mainPanel.remove(existingListView)
}
// Create a new plugin list view off-EDT (already on EDT here) and add it
val pluginListView = createPluginListView()
pluginListView.name = PLUGIN_LIST_VIEW
mainPanel.add(pluginListView, PLUGIN_LIST_VIEW)
// Switch card after the new component is in place
cardLayout.show(mainPanel, PLUGIN_LIST_VIEW)
// Revalidate/repaint once at the end
searchFieldWrapper?.isVisible = true
mainPanel.revalidate()
mainPanel.repaint()
} finally {
mainPanel.ignoreRepaint = false
} else {
contentPanel.isVisible = false
try {
populatePluginListContent()
} finally {
contentPanel.isVisible = true
}
}
searchFieldWrapper?.isVisible = true
cardLayout.show(mainPanel, PLUGIN_LIST_VIEW)
pluginListScrollablePanel?.let { scrollPanel ->
SwingUtilities.invokeLater {
resetScrollablePanel(scrollPanel)
}
}
mainPanel.revalidate()
mainPanel.repaint()
}
var customToolTipWindow: JWindow? = null
@ -1338,4 +1366,4 @@ object ReflectiveEditorView : View {
scrollablePanel.repaint()
}
}
}
}