chore: dynamically modify icons

This commit is contained in:
hstyi
2025-07-06 17:22:43 +08:00
committed by hstyi
parent d40b8a4c9c
commit 53d3d96a06
5 changed files with 57 additions and 13 deletions

View File

@@ -68,6 +68,11 @@ internal class ReconnectableTransportSupportLoader(private val owner: Window, pr
} }
} }
override fun isOpening(): Boolean {
if (isOpened()) return false
return mutex.isLocked
}
private fun connect(): MyTransportSupport { private fun connect(): MyTransportSupport {
val provider = TransferProtocolProvider.valueOf(host.protocol) val provider = TransferProtocolProvider.valueOf(host.protocol)
if (provider == null) { if (provider == null) {

View File

@@ -111,7 +111,7 @@ internal class TransportSelectionPanel(
}) })
swingCoroutineScope.launch { swingCoroutineScope.launch {
tabbed.remove(that) tabbed.remove(that)
tabbed.addTab(host.name, panel) tabbed.addTab(host.name, TransportViewer.MyIcon.Success, panel)
tabbed.selectedIndex = tabbed.tabCount - 1 tabbed.selectedIndex = tabbed.tabCount - 1
} }
} }

View File

@@ -23,4 +23,9 @@ internal interface TransportSupportLoader : Disposable {
* 快速检查是否已经成功打开 * 快速检查是否已经成功打开
*/ */
fun isOpened(): Boolean = true fun isOpened(): Boolean = true
/**
* 是否正在打开中,也有可能是加载中
*/
fun isOpening(): Boolean = false
} }

View File

@@ -70,9 +70,8 @@ internal class TransportTabbed(
showContextMenu(index, e) showContextMenu(index, e)
} else if (SwingUtilities.isLeftMouseButton(e) && e.clickCount % 2 == 0) { } else if (SwingUtilities.isLeftMouseButton(e) && e.clickCount % 2 == 0) {
val tab = getTransportPanel(index) ?: return val tab = getTransportPanel(index) ?: return
if (tab.loader.isOpened().not()) { if (tab.loader.isOpening() || tab.loader.isOpened()) return
tab.reload() tab.reload()
}
} }
} }
}) })
@@ -156,7 +155,7 @@ internal class TransportTabbed(
return true return true
} }
}) })
addTab(I18n.getString("termora.transport.local"), panel) addTab(I18n.getString("termora.transport.local"), TransportViewer.MyIcon.Success, panel)
super.setTabClosable(0, false) super.setTabClosable(0, false)
} }
@@ -171,7 +170,7 @@ internal class TransportTabbed(
val popupMenu = FlatPopupMenu() val popupMenu = FlatPopupMenu()
// 克隆 // 克隆
val clone = popupMenu.add(I18n.getString("termora.tabbed.contextmenu.clone")) val clone = popupMenu.add(I18n.getString("termora.copy"))
clone.addActionListener(object : AnAction() { clone.addActionListener(object : AnAction() {
override fun actionPerformed(evt: AnActionEvent) { override fun actionPerformed(evt: AnActionEvent) {
val c = addSelectionTab() val c = addSelectionTab()

View File

@@ -3,11 +3,10 @@ package app.termora.transfer
import app.termora.Disposable import app.termora.Disposable
import app.termora.Disposer import app.termora.Disposer
import app.termora.DynamicColor import app.termora.DynamicColor
import app.termora.Icons
import app.termora.actions.DataProvider import app.termora.actions.DataProvider
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import java.awt.BorderLayout import java.awt.*
import java.awt.event.ComponentAdapter import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent import java.awt.event.ComponentEvent
import java.nio.file.Path import java.nio.file.Path
@@ -78,9 +77,9 @@ internal class TransportViewer : JPanel(BorderLayout()), DataProvider, Disposabl
coroutineScope.launch(Dispatchers.Swing) { coroutineScope.launch(Dispatchers.Swing) {
while (isActive) { while (isActive) {
delay(250.milliseconds)
checkDisconnected(leftTabbed) checkDisconnected(leftTabbed)
checkDisconnected(rightTabbed) checkDisconnected(rightTabbed)
delay(250.milliseconds)
} }
} }
@@ -93,11 +92,17 @@ internal class TransportViewer : JPanel(BorderLayout()), DataProvider, Disposabl
val tab = tabbed.getTransportPanel(i) ?: continue val tab = tabbed.getTransportPanel(i) ?: continue
val icon = tabbed.getIconAt(i) val icon = tabbed.getIconAt(i)
if (tab.loader.isOpened()) { if (tab.loader.isOpened()) {
if (icon == null) continue if (icon != MyIcon.Success) {
tabbed.setIconAt(i, null) tabbed.setIconAt(i, MyIcon.Success)
}
} else if (tab.loader.isOpening()) {
if (icon != MyIcon.Warning) {
tabbed.setIconAt(i, MyIcon.Warning)
}
} else { } else {
if (icon == Icons.breakpoint) continue if (icon != MyIcon.Error) {
tabbed.setIconAt(i, Icons.breakpoint) tabbed.setIconAt(i, MyIcon.Error)
}
} }
} }
} }
@@ -142,4 +147,34 @@ internal class TransportViewer : JPanel(BorderLayout()), DataProvider, Disposabl
coroutineScope.cancel() coroutineScope.cancel()
} }
internal class MyIcon(private val color: Color) : Icon {
private val size = 10
// https://plugins.jetbrains.com/docs/intellij/icons-style.html#action-icons
companion object {
val Success = MyIcon(DynamicColor(Color(89, 168, 105), Color(73, 156, 84)))
val Error = MyIcon(DynamicColor(Color(219, 88, 96), Color(199, 84, 80)))
val Warning = MyIcon(DynamicColor(Color(237, 162, 0), Color(240, 167, 50)))
}
override fun paintIcon(c: Component, g: Graphics, x: Int, y: Int) {
if (g is Graphics2D) {
g.color = color
val centerX = x + (iconWidth - size) / 2
val centerY = y + (iconHeight - size) / 2
g.fillRoundRect(centerX, centerY, size, size, size, size)
}
}
override fun getIconWidth(): Int {
return 16
}
override fun getIconHeight(): Int {
return 16
}
}
} }