Compare commits

..

5 Commits

Author SHA1 Message Date
Kingkor Roy Tirtho
27e591d8a3 cd: remove AppImage upload steps from Linux build process 2026-07-22 01:11:53 +06:00
Kingkor Roy Tirtho
2af3a41bba cd: remove AppImage packaging and upload steps from Linux build process 2026-07-22 01:06:50 +06:00
Kingkor Roy Tirtho
720ac1136a cd: move ssh to end 2026-07-21 23:53:49 +06:00
Kingkor Roy Tirtho
8fcd35eb9b feat: add SSH debug session setup on failure for improved troubleshooting 2026-07-21 22:38:51 +06:00
Kingkor Roy Tirtho
019bbfae14 feat: add hover effect to menu items in System Tray for improved user experience 2026-07-21 22:22:12 +06:00
2 changed files with 77 additions and 7 deletions

View File

@ -16,6 +16,11 @@ on:
required: false required: false
type: boolean type: boolean
default: false default: false
debug_ssh:
description: 'Enable SSH debug session on failure (tmate)'
required: false
type: boolean
default: false
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@ -149,6 +154,12 @@ jobs:
name: android-apk name: android-apk
path: Spotube-android-all-arch.apk path: Spotube-android-all-arch.apk
- name: Setup tmate session on failure
if: ${{ inputs.debug_ssh && failure() }}
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
build-linux: build-linux:
name: Linux Desktop name: Linux Desktop
needs: prepare-deps needs: prepare-deps
@ -183,16 +194,14 @@ jobs:
run: chmod +x gradlew run: chmod +x gradlew
- name: Package Linux - name: Package Linux
run: ./gradlew :composeApp:packageReleaseDeb :composeApp:packageReleaseRpm :composeApp:packageReleaseAppImage run: ./gradlew :composeApp:packageReleaseDeb :composeApp:packageReleaseRpm
- name: Rename Linux artifacts - name: Rename Linux artifacts
run: | run: |
DEB_FILE=$(find composeApp/build -name "*.deb" -type f | head -1) DEB_FILE=$(find composeApp/build -name "*.deb" -type f | head -1)
RPM_FILE=$(find composeApp/build -name "*.rpm" -type f | head -1) RPM_FILE=$(find composeApp/build -name "*.rpm" -type f | head -1)
APPIMAGE_FILE=$(find composeApp/build -name "*.AppImage" -type f | head -1)
cp "$DEB_FILE" Spotube-linux-x86_64.deb cp "$DEB_FILE" Spotube-linux-x86_64.deb
cp "$RPM_FILE" Spotube-linux-x86_64.rpm cp "$RPM_FILE" Spotube-linux-x86_64.rpm
cp "$APPIMAGE_FILE" Spotube-linux-x86_64.AppImage
- name: Upload DEB - name: Upload DEB
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@ -206,11 +215,11 @@ jobs:
name: linux-rpm name: linux-rpm
path: Spotube-linux-x86_64.rpm path: Spotube-linux-x86_64.rpm
- name: Upload AppImage - name: Setup tmate session on failure
uses: actions/upload-artifact@v4 if: ${{ inputs.debug_ssh && failure() }}
uses: mxschmitt/action-tmate@v3
with: with:
name: linux-appimage limit-access-to-actor: true
path: Spotube-linux-x86_64.AppImage
build-windows: build-windows:
name: Windows Desktop name: Windows Desktop
@ -252,6 +261,12 @@ jobs:
name: windows-exe name: windows-exe
path: Spotube-windows-x86_64-setup.exe path: Spotube-windows-x86_64-setup.exe
- name: Setup tmate session on failure
if: ${{ inputs.debug_ssh && failure() }}
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
build-macos: build-macos:
name: macOS Desktop name: macOS Desktop
needs: prepare-deps needs: prepare-deps
@ -294,6 +309,12 @@ jobs:
name: macos-dmg name: macos-dmg
path: Spotube-macos-universal.dmg path: Spotube-macos-universal.dmg
- name: Setup tmate session on failure
if: ${{ inputs.debug_ssh && failure() }}
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
create-release: create-release:
name: Create GitHub Release name: Create GitHub Release
if: ${{ !inputs.dry_run }} if: ${{ !inputs.dry_run }}

View File

@ -217,6 +217,23 @@ class SystemTrayService(
val loopNone = javax.swing.JRadioButtonMenuItem("Loop: OFF", state.loopState == LoopState.NONE) val loopNone = javax.swing.JRadioButtonMenuItem("Loop: OFF", state.loopState == LoopState.NONE)
val loopOne = javax.swing.JRadioButtonMenuItem("Loop: ONE", state.loopState == LoopState.ONE) val loopOne = javax.swing.JRadioButtonMenuItem("Loop: ONE", state.loopState == LoopState.ONE)
val loopAll = javax.swing.JRadioButtonMenuItem("Loop: ALL", state.loopState == LoopState.ALL) val loopAll = javax.swing.JRadioButtonMenuItem("Loop: ALL", state.loopState == LoopState.ALL)
val hoverBackground = UIManager.getColor("MenuItem.selectionBackground") ?: Color(75, 110, 175)
listOf(loopNone, loopOne, loopAll).forEach { item ->
item.isOpaque = true
val normalBackground = item.background
item.addMouseListener(object : MouseAdapter() {
override fun mouseEntered(e: MouseEvent) {
item.background = hoverBackground
}
override fun mouseExited(e: MouseEvent) {
item.background = normalBackground
}
})
}
loopGroup.add(loopNone) loopGroup.add(loopNone)
loopGroup.add(loopOne) loopGroup.add(loopOne)
loopGroup.add(loopAll) loopGroup.add(loopAll)
@ -318,15 +335,47 @@ class SystemTrayService(
private fun createMenuItem(label: String, enabled: Boolean = true, action: () -> Unit): JMenuItem { private fun createMenuItem(label: String, enabled: Boolean = true, action: () -> Unit): JMenuItem {
return JMenuItem(label).apply { return JMenuItem(label).apply {
isEnabled = enabled isEnabled = enabled
isOpaque = true
maximumSize = Dimension(Int.MAX_VALUE, preferredSize.height) maximumSize = Dimension(Int.MAX_VALUE, preferredSize.height)
addActionListener { action() } addActionListener { action() }
val normalBackground = background
val hoverBackground = UIManager.getColor("MenuItem.selectionBackground") ?: Color(75, 110, 175)
addMouseListener(object : MouseAdapter() {
override fun mouseEntered(e: MouseEvent) {
if (isEnabled) {
background = hoverBackground
}
}
override fun mouseExited(e: MouseEvent) {
background = normalBackground
}
})
} }
} }
private fun createCheckBoxMenuItem(label: String, selected: Boolean, action: () -> Unit): JCheckBoxMenuItem { private fun createCheckBoxMenuItem(label: String, selected: Boolean, action: () -> Unit): JCheckBoxMenuItem {
return JCheckBoxMenuItem(label, selected).apply { return JCheckBoxMenuItem(label, selected).apply {
isOpaque = true
maximumSize = Dimension(Int.MAX_VALUE, preferredSize.height) maximumSize = Dimension(Int.MAX_VALUE, preferredSize.height)
addActionListener { action() } addActionListener { action() }
val normalBackground = background
val hoverBackground = UIManager.getColor("MenuItem.selectionBackground") ?: Color(75, 110, 175)
addMouseListener(object : MouseAdapter() {
override fun mouseEntered(e: MouseEvent) {
if (isEnabled) {
background = hoverBackground
}
}
override fun mouseExited(e: MouseEvent) {
background = normalBackground
}
})
} }
} }