diff --git a/Cargo.lock b/Cargo.lock index a62aa7337..194793cb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1211,7 +1211,7 @@ dependencies = [ [[package]] name = "craft-update" version = "0.1.0" -source = "git+https://github.com/storytold/craft-libs?rev=c5a1cbfb5f9049f9270955caffb5bee5997aebf7#c5a1cbfb5f9049f9270955caffb5bee5997aebf7" +source = "git+https://github.com/dotCooCoo/craft-libs?rev=c7c84230631cbc01ee928f0a0e0d838b1ed612ae#c7c84230631cbc01ee928f0a0e0d838b1ed612ae" dependencies = [ "chrono", "dunce", @@ -6223,7 +6223,6 @@ dependencies = [ "nix 0.31.3", "typed-path", "windows-sys 0.61.2", - "zopfli", ] [[package]] @@ -6238,18 +6237,6 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" -[[package]] -name = "zopfli" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf7fc5d30c28483d93805c4a5e12b05bbb52407fa67c5f8bd552374cd01fb11" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", -] - [[package]] name = "zune-core" version = "0.5.3" diff --git a/Cargo.toml b/Cargo.toml index 60d198514..64ff8456e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ egui-wgpu = "0.37" # Monotonic time on native and web (performance.now on wasm). web-time = "1.1" # craft-update: app-specific pretend versions apply to startup and manual checks. -craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7", features = ["egui"] } +craft-update = { git = "https://github.com/dotCooCoo/craft-libs", version = "=0.1.0", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae", features = ["egui"] } rfd = "0.17" arboard = { version = "3.6", default-features = false } diff --git a/crates/ui-egui/src/updates_ui.rs b/crates/ui-egui/src/updates_ui.rs index ce8f53a3f..ccd9733b4 100644 --- a/crates/ui-egui/src/updates_ui.rs +++ b/crates/ui-egui/src/updates_ui.rs @@ -17,15 +17,13 @@ pub struct Runtime { enabled: bool, /// Help ▸ Check for Updates… was chosen; the next frame's `tick` starts it with the context. check_requested: bool, - /// The check-result dialog is open (from a requested check until it is closed). - result_open: bool, /// The current result was already written to the command history. result_echoed: bool, } impl Default for Runtime { fn default() -> Self { - Self { updater: Updater::new(&crate::UPDATE_APP, VERSION), enabled: false, check_requested: false, result_open: false, result_echoed: false } + Self { updater: Updater::new(&crate::UPDATE_APP, VERSION), enabled: false, check_requested: false, result_echoed: false } } } @@ -39,7 +37,6 @@ impl CadApp { /// Help ▸ Check for Updates…: check now, and show the result when there is nothing newer. pub fn check_now(app: &mut CadApp) { app.updates_rt.check_requested = true; - app.updates_rt.result_open = true; app.updates_rt.result_echoed = false; } @@ -55,45 +52,70 @@ pub fn tick(app: &mut CadApp, ctx: &egui::Context) { let outcome = match rt.updater.status() { Status::UpToDate => Some(crate::tl!("CADCraft is up to date.")), Status::Failed(_) => Some(crate::tl!("Could not check for updates.")), - Status::Idle | Status::Checking => None, - }; - let Some(message) = outcome else { - // A check that found an update leaves `Idle`; the prompt takes over from the dialog. - if rt.result_open && matches!(rt.updater.status(), Status::Idle) { - rt.result_open = false; + Status::Idle | Status::Checking | Status::Installing | Status::Ready | Status::Managed | Status::Updated(_) | Status::InstallFailed(_) => { + None } - return; }; - if !rt.result_open { - rt.updater.dismiss_status(); - } else if !std::mem::replace(&mut rt.result_echoed, true) { + if let Some(message) = outcome + && !std::mem::replace(&mut rt.result_echoed, true) + { app.session.echo(message); } } +/// Whether the check result window shows: for every status but idle (a requested check, and the +/// first start after an update, which reports that it installed or why it failed), and never +/// over the startup prompt. +fn result_window_shows(status: &Status, prompt_open: bool) -> bool { + !prompt_open && !matches!(status, Status::Idle) +} + /// Draw the prompt while there is one and act on its answer. pub fn show(app: &mut CadApp, ctx: &egui::Context) { - // The restart helper is scheduled before the app closes, so no update starts over unsaved work. + // The close for a ready update waits until no drawing holds unsaved changes. let clean = !app.session.docs.iter().any(|d| d.is_dirty()); let rt = &mut app.updates_rt; - if rt.result_open { + if result_window_shows(rt.updater.status(), rt.updater.prompt_open()) { match CheckResultDialog::new(&crate::UPDATE_APP, VERSION).show(ctx, rt.updater.status()) { - CheckResultResponse::Close => { - rt.result_open = false; - rt.updater.dismiss_status(); - } + CheckResultResponse::Close => rt.updater.dismiss_status(), CheckResultResponse::CheckAgain => { rt.result_echoed = false; rt.check_requested = true; } + // The next `show_if` asks the window to close once nothing is unsaved. + CheckResultResponse::RestartToUpdate => rt.updater.restart_to_update(), CheckResultResponse::None => {} } } match app.updates_rt.updater.show_if(ctx, clean) { Action::OpenUrl(url) => ctx.open_url(egui::OpenUrl::new_tab(url)), - // The guarded close path asks about unsaved changes; the restart helper relaunches once the - // process has exited. + // The guarded close path asks about unsaved changes. The install helper starts when the + // app exits and drops the updater. Action::Close => ctx.send_viewport_cmd(egui::ViewportCommand::Close), Action::None => {} } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn result_window_shows_every_status_but_idle() { + let shown = [ + Status::Checking, + Status::UpToDate, + Status::Failed("no network".into()), + Status::Installing, + Status::Ready, + Status::Managed, + Status::Updated("0.2.0".into()), + Status::InstallFailed("disk full".into()), + ]; + for status in &shown { + assert!(result_window_shows(status, false), "{status:?}"); + assert!(!result_window_shows(status, true), "{status:?} over the prompt"); + } + assert!(!result_window_shows(&Status::Idle, false)); + } +}