refactor: apply CLAUDE.md code quality improvements and add packaging

- Add #![forbid(unsafe_code)] to main.rs (issue #3)
- Replace raw ANSI escape codes with owo-colors crate (issue #2)
- Replace manual HOME path construction with dirs::home_dir() (issue #5)
- Ship umutray.service as a static file; service::install() substitutes
  the binary path at install time instead of generating the unit at runtime
- Add packaging/PKGBUILD following Arch Rust package guidelines
- Add CLAUDE.md tracking refactor tasks
- setup.rs: clean up downloaded temp files on abort/back, save launcher
  to config only after successful install, auto-start download when a
  preset has an installer_url
- util.rs: add pick_folder() using zenity/kdialog subprocesses (no rfd)
- config.rs: populate installer_url for all 6 built-in presets with
  official download URLs
- Document the Option<Option<Vec<String>>> gamescope pattern at main.rs:307

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-04-18 19:28:10 -07:00
parent f2f584febf
commit 9b7e474e80
11 changed files with 233 additions and 57 deletions
+14 -15
View File
@@ -1,3 +1,5 @@
#![forbid(unsafe_code)]
mod config;
mod detect;
mod diagnose;
@@ -11,6 +13,7 @@ mod util;
use anyhow::Result;
use clap::{Parser, Subcommand};
use owo_colors::OwoColorize;
use std::path::PathBuf;
/// Tray-based Wine launcher manager for Linux via umu/Proton-GE.
@@ -105,7 +108,7 @@ enum Commands {
action: ConfigAction,
},
/// Manage the systemd --user service that autostarts the tray
/// Manage the XDG autostart entry that starts the tray on login
Service {
#[command(subcommand)]
action: ServiceAction,
@@ -219,13 +222,13 @@ enum ConfigAction {
#[derive(Subcommand)]
enum ServiceAction {
/// Write the unit, daemon-reload, and enable+start the service (includes app menu entry)
/// Write ~/.config/autostart/umutray.desktop so the tray starts on login (includes app menu entry)
Install,
/// Stop, disable, and remove the unit file (includes app menu entry)
/// Remove the autostart entry and app menu entry
Uninstall,
/// Show `systemctl --user status` for the service
/// Show whether the XDG autostart entry is present
Status,
/// Install only the app menu entry — no systemd service required
/// Install only the app menu entry
InstallDesktop,
/// Remove the app menu entry
UninstallDesktop,
@@ -263,11 +266,7 @@ fn main() -> Result<()> {
for l in &config.launchers {
let installed = l.full_exe_path().exists();
let running = launcher::is_running(l);
let marker = if installed {
"\x1b[1;32m✓\x1b[0m"
} else {
"·"
};
let marker = if installed { "".green().bold().to_string() } else { "·".to_string() };
let state = if running { " (running)" } else { "" };
println!(" {marker} {:12} {}{}", l.name, l.display, state);
}
@@ -303,11 +302,7 @@ fn main() -> Result<()> {
println!(" {}:", l.display);
for g in &l.games {
let installed = g.full_exe_path(l).exists();
let marker = if installed {
"\x1b[1;32m✓\x1b[0m"
} else {
"·"
};
let marker = if installed { "".green().bold().to_string() } else { "·".to_string() };
let flags = format_game_flags(g);
println!(" {marker} {:14} {}{}", g.name, g.display, flags);
}
@@ -403,6 +398,10 @@ fn main() -> Result<()> {
gamescope,
no_gamescope,
} => {
// gs_update is Option<Option<Vec<String>>> where:
// None = leave gamescope unchanged
// Some(None) = disable gamescope
// Some(Some(args)) = enable gamescope with these CLI args
let gs_update = if no_gamescope {
Some(None)
} else {