Config screen
This commit is contained in:
parent
ac88e62abe
commit
4b3c512a9d
28 changed files with 2015 additions and 59 deletions
104
docs/plans/feature-1-system-tray.md
Normal file
104
docs/plans/feature-1-system-tray.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# Feature 1: System Tray Icon
|
||||
|
||||
## Context
|
||||
The app lives primarily in the system tray. The window is secondary — it opens for configuration/status and closes back to tray. This is the shell that all UI features plug into.
|
||||
|
||||
## Dependencies
|
||||
- **Depends on**: Feature 0 (Foundation) — logging, platform detection
|
||||
- **Depended on by**: Features 2-5 (all UI features are accessed through the tray)
|
||||
|
||||
## Approach
|
||||
Use Compose Desktop's built-in `Tray` composable (`androidx.compose.ui.window.Tray`). No extra libraries needed — it supports icons, tooltips, context menus, and notifications natively.
|
||||
|
||||
## App Lifecycle Model
|
||||
The app always runs with a tray icon visible. The main window is shown/hidden based on user interaction. Closing the window hides it to tray — it does not exit the app. Exiting is only via the tray menu "Quit" item.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Step 1: Create a tray icon asset
|
||||
**Files to create:**
|
||||
- `composeApp/src/jvmMain/resources/tray-icon.png` (32x32, simple recognizable icon)
|
||||
|
||||
For macOS dark mode support, add JVM arg: `-Dapple.awt.enableTemplateImages=true`
|
||||
|
||||
### Step 2: Restructure main.kt for tray-first lifecycle
|
||||
**Files to modify:**
|
||||
- `composeApp/src/jvmMain/kotlin/com/rukira/wowbackup/main.kt`
|
||||
|
||||
```kotlin
|
||||
fun main() = application {
|
||||
// Initialize logging (from Feature 0)
|
||||
|
||||
var isWindowVisible by remember { mutableStateOf(true) }
|
||||
// Which screen to show: STATUS (default) or CONFIG
|
||||
var currentScreen by remember { mutableStateOf(Screen.STATUS) }
|
||||
|
||||
Tray(
|
||||
icon = painterResource("tray-icon.png"),
|
||||
tooltip = "WoW Backup",
|
||||
onAction = { isWindowVisible = true }, // click tray -> show window
|
||||
menu = {
|
||||
Item("Status", onClick = {
|
||||
currentScreen = Screen.STATUS
|
||||
isWindowVisible = true
|
||||
})
|
||||
Item("Settings", onClick = {
|
||||
currentScreen = Screen.CONFIG
|
||||
isWindowVisible = true
|
||||
})
|
||||
Separator()
|
||||
Item("Quit", onClick = ::exitApplication)
|
||||
}
|
||||
)
|
||||
|
||||
if (isWindowVisible) {
|
||||
Window(
|
||||
onCloseRequest = { isWindowVisible = false }, // close -> hide to tray
|
||||
title = "WoW Backup",
|
||||
) {
|
||||
App(currentScreen)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Define screen navigation enum
|
||||
**Files to create:**
|
||||
- `composeApp/src/jvmMain/kotlin/com/rukira/wowbackup/ui/Screen.kt`
|
||||
|
||||
```kotlin
|
||||
enum class Screen { STATUS, CONFIG, RESTORE }
|
||||
```
|
||||
|
||||
### Step 4: Update App.kt for screen routing
|
||||
**Files to modify:**
|
||||
- `composeApp/src/jvmMain/kotlin/com/rukira/wowbackup/App.kt`
|
||||
|
||||
Strip all template code. Route to placeholder screens based on `currentScreen`:
|
||||
- `Screen.STATUS` -> "Status screen placeholder"
|
||||
- `Screen.CONFIG` -> "Config screen placeholder"
|
||||
- `Screen.RESTORE` -> "Restore screen placeholder"
|
||||
|
||||
### Step 5: Auto-show config if not configured
|
||||
In `main.kt`, on startup check `ConfigManager.isConfigured`. If false, set `currentScreen = Screen.CONFIG` and `isWindowVisible = true`.
|
||||
|
||||
### Step 6: macOS JVM args
|
||||
**Files to modify:**
|
||||
- `composeApp/build.gradle.kts` — add to desktop application config:
|
||||
|
||||
```kotlin
|
||||
compose.desktop {
|
||||
application {
|
||||
jvmArgs("-Dapple.awt.enableTemplateImages=true")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Verification
|
||||
1. `./gradlew composeApp:run` — app launches with tray icon visible
|
||||
2. Tray icon shows context menu with Status, Settings, Quit
|
||||
3. Clicking "Status" or "Settings" opens the window to the correct placeholder
|
||||
4. Closing the window hides it (app stays running in tray)
|
||||
5. Clicking tray icon again re-shows the window
|
||||
6. "Quit" exits the app fully
|
||||
7. On first run (no config), window auto-opens to config screen
|
||||
Loading…
Add table
Add a link
Reference in a new issue