Compare commits

...

4 commits

Author SHA1 Message Date
Rukira
8b054cd33d Hiding dock icon for MacOS
Some checks failed
Release Pipeline / Bump Version & Create Tag (push) Has been cancelled
Release Pipeline / Package Linux (DEB) (push) Has been cancelled
Release Pipeline / Package macOS (DMG) (push) Has been cancelled
Release Pipeline / Package Windows (MSI) (push) Has been cancelled
Release Pipeline / Create GitHub & Forgejo Releases (push) Has been cancelled
2026-08-25 11:38:37 +01:00
Rukira
846794fa36 Sticky buttons in Settings 2026-08-25 11:32:19 +01:00
Rukira
59b296d04d Roadmap update 2026-08-25 11:24:05 +01:00
Rukira
d07f0f31bd Bug report template 2026-08-25 10:44:52 +01:00
6 changed files with 240 additions and 272 deletions

View file

@ -62,6 +62,7 @@ body:
options:
- macOS
- Windows
- Linux
validations:
required: true
@ -80,6 +81,7 @@ body:
Logs help us understand what went wrong behind the scenes. Here's how to find them:
**macOS:** Open Finder, press **Cmd+Shift+G**, and paste: `~/Library/Application Support/WoWBackup/logs`
**Windows:** Press **Win+R**, and paste: `%APPDATA%\WoWBackup\logs`
You can also open this folder from the app: go to **Settings** and click the **Open Logs** button at the bottom.

View file

@ -70,7 +70,7 @@ compose.desktop {
application {
mainClass = "com.rukira.wowbackup.MainKt"
jvmArgs("-Dapple.awt.enableTemplateImages=true")
jvmArgs("-Dapple.awt.enableTemplateImages=true", "-Dapple.awt.UIElement=true")
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
@ -82,6 +82,12 @@ compose.desktop {
macOS {
bundleID = "com.rukira.wowbackup"
iconFile.set(project.file("src/jvmMain/resources/icon.icns"))
infoPlist {
extraKeysRawXml = """
<key>LSUIElement</key>
<true/>
""".trimIndent()
}
}
windows {

View file

@ -28,6 +28,9 @@ import java.awt.GraphicsEnvironment
private val logger = KotlinLogging.logger {}
fun main() {
if (Platform.current == OS.Mac) {
System.setProperty("apple.awt.UIElement", "true")
}
LoggingSetup.init()
logger.info { "WoW Backup starting" }

View file

@ -63,7 +63,12 @@ fun ConfigScreen(
var showForceBackupDialog by remember { mutableStateOf(false) }
val scrollState = rememberScrollState()
Box(modifier = Modifier.fillMaxSize()) {
Column(modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.weight(1f)
.fillMaxWidth(),
) {
Column(
modifier = Modifier
.fillMaxSize()
@ -263,14 +268,29 @@ fun ConfigScreen(
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
// === Footer ===
Spacer(Modifier.height(8.dp))
VerticalScrollbar(
modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(),
adapter = rememberScrollbarAdapter(scrollState),
style = ScrollbarStyle(
minimalHeight = 48.dp,
thickness = 8.dp,
shape = RoundedCornerShape(4.dp),
hoverDurationMillis = 300,
unhoverColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f),
hoverColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
),
)
}
// === Sticky Footer ===
HorizontalDivider()
Spacer(Modifier.height(8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 16.dp),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
@ -303,20 +323,6 @@ fun ConfigScreen(
}
}
VerticalScrollbar(
modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(),
adapter = rememberScrollbarAdapter(scrollState),
style = ScrollbarStyle(
minimalHeight = 48.dp,
thickness = 8.dp,
shape = RoundedCornerShape(4.dp),
hoverDurationMillis = 300,
unhoverColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f),
hoverColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
),
)
}
// Force backup confirmation dialog
if (showForceBackupDialog) {
ConfirmationDialog(

View file

@ -84,18 +84,31 @@ Strip all template code. Route to placeholder screens based on `currentScreen`:
### 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
### Step 6: macOS JVM args and Dock hiding (LSUIElement)
**Files to modify:**
- `composeApp/build.gradle.kts` — add to desktop application config:
```kotlin
compose.desktop {
application {
jvmArgs("-Dapple.awt.enableTemplateImages=true")
jvmArgs("-Dapple.awt.enableTemplateImages=true", "-Dapple.awt.UIElement=true")
nativeDistributions {
macOS {
infoPlist {
extraKeysRawXml = """
<key>LSUIElement</key>
<true/>
""".trimIndent()
}
}
}
}
}
```
Also set `System.setProperty("apple.awt.UIElement", "true")` in `main.kt` for macOS so that the dock icon is suppressed during development runs.
## Verification
1. `./gradlew composeApp:run` — app launches with tray icon visible
2. Tray icon shows context menu with Status, Settings, Quit

View file

@ -4,75 +4,13 @@ This document outlines the current state of the project, remaining core features
---
## 1. Immediate Priority: Feature 5 (Restore System)
## Immediate Priority: Feature 5 (Restore System)
The core backup and scheduling pipeline is complete, but the restoration flow is currently a stub placeholder. Implementing Feature 5 is the final step to complete the original functional scope of `docs/masterplan.md`.
### Tasks:
1. **Restore Engine (`RestoreEngine.kt`)**
- Implement `restoreBackup(entry: BackupEntry, targetDir: File): RestoreResult`.
- Support restoring from both timestamped directory structures and `.zip` archives (extracting using `ZipInputStream`).
- Clean/delete existing target folders (`WTF` and/or `Interface`) safely before copy/extraction.
- Implement live progress reporting (`RestoreProgress` with total files, completed count, current file name).
- Ensure full cancellation support via Kotlin Coroutines.
2. **Safety & Validation Mechanics**
- Warn or guard if World of Warcraft is currently running during restoration.
- Verify backup integrity and destination disk space before starting destructive deletion.
- Create an automatic temporary safety snapshot of current `WTF`/`Interface` folders prior to overwrite.
3. **Restore ViewModel (`RestoreViewModel.kt`)**
- Expose `RestoreUiState` combining available backups list, selected entry, progress, and confirmation states.
- Manage restore lifecycle (start, cancel, dismiss, error handling).
4. **Restore Screen UI (`RestoreScreen.kt`)**
- Replace placeholder with scrollable list of existing backups displaying date/time, archive size, and format badge.
- Material 3 confirmation dialog detailing destructive overwrite.
- Progress overlay with `LinearProgressIndicator`, active file, and cancellation button.
- Empty state when no backups are present.
5. **App Wiring**
- Connect `Screen.RESTORE` in `App.kt` to `RestoreScreen`.
- Enable the "Restore" button on `StatusScreen.kt`.
---
## 2. Testing Infrastructure & Automated Test Suite
Currently, the project contains no automated test suite (`src/jvmTest` is empty). Adding tests will prevent regressions during future maintenance.
### Test Targets:
1. **`BackupHistoryTest`**:
- Timestamp parsing across formats and edge cases.
- Backup listing and correct descending sort order.
- Retention policy pruning (ensuring only oldest backups exceeding count are deleted).
- Metrics computation for directory trees and ZIP files.
2. **`BackupEngineTest` & `RestoreEngineTest`**:
- File copy accuracy, recursive folder preservation, and attribute retention.
- ZIP compression and decompression fidelity.
- Cancellation responsiveness and cleanup of partial writes.
3. **`ConfigManagerTest`**:
- JSON serialization / deserialization defaults and edge cases.
- Thread-safe updates and reactive `StateFlow` emissions.
4. **`WoWLocationsTest`**:
- Install directory heuristics and resolution from root `World of Warcraft` to `_retail_` or `_classic_`.
- Missing folder detection and permission warnings.
---
## 3. Build Automation & Release Pipeline (Completed)
Automated multi-platform packaging and release pipeline implemented via GitHub Actions (`.github/workflows/release.yml`) and documented in `INSTALL.md` and `docs/plans/feature-6-release-pipeline.md`.
### Implemented:
1. **GitHub Actions Release Pipeline**
- Automated semantic patch version computation and git tagging on push to `main` and `workflow_dispatch`.
- Matrix builds on macOS (`macos-latest`), Windows (`windows-latest`), and Linux (`ubuntu-latest`).
2. **Automated Distribution Packaging & GitHub Releases**
- Automated artifact generation and release publishing for `.dmg` (macOS), `.msi` (Windows), and `.deb` (Linux).
- Dynamic version injection via `-PappVersion` in `composeApp/build.gradle.kts`.
3. **Installation Documentation**
- Detailed `INSTALL.md` guide covering installation and security prompts (Gatekeeper / SmartScreen) across all platforms.
---
## 4. Future Enhancements (Post-v1.0)
## Future Enhancements (Post-v1.0)
1. **Multi-Flavour & Account Profile Support**
- Support backing up multiple game versions simultaneously (`_retail_`, `_classic_`, `_classic_era_`, `_ptr_`).