9b7e474e80
- 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>
37 lines
1.2 KiB
Rust
37 lines
1.2 KiB
Rust
use iced::futures::channel::oneshot;
|
|
|
|
/// Run a blocking closure on a thread pool thread and await its result.
|
|
/// Used to offload blocking work (HTTP, disk, process spawning) without
|
|
/// stalling the iced event loop.
|
|
pub async fn async_blocking<T, F>(f: F) -> T
|
|
where
|
|
T: Send + 'static,
|
|
F: FnOnce() -> T + Send + 'static,
|
|
{
|
|
let (tx, rx) = oneshot::channel();
|
|
std::thread::spawn(move || {
|
|
let _ = tx.send(f());
|
|
});
|
|
rx.await.expect("blocking task panicked")
|
|
}
|
|
|
|
/// Open a native folder picker dialog and return the chosen path, or None if
|
|
/// the user cancelled. Tries zenity (GNOME/GTK) then kdialog (KDE) in order.
|
|
pub fn pick_folder(title: &str) -> Option<String> {
|
|
for (cmd, args) in [
|
|
("zenity", vec!["--file-selection", "--directory", "--title", title]),
|
|
("kdialog", vec!["--getexistingdirectory", "/home", "--title", title]),
|
|
] {
|
|
let Ok(out) = std::process::Command::new(cmd).args(&args).output() else {
|
|
continue;
|
|
};
|
|
if out.status.success() {
|
|
let s = String::from_utf8_lossy(&out.stdout).trim().to_string();
|
|
if !s.is_empty() {
|
|
return Some(s);
|
|
}
|
|
}
|
|
}
|
|
None
|
|
}
|