mirror of
https://github.com/storytold/lightcraft.git
synced 2026-11-13 09:20:07 -06:00
Updates: the updater reports installing, ready, installed and failed, and installs at exit
craft-update moves from a231e517 to the head of storytold/craft-libs#696. The check result window now shows for every status but idle, so the first start after an update reports that it installed or why it failed. Restart to Update on a ready update asks the app to close. The install helper now starts when the app exits. on_exit calls Updater::start_pending_update through LightcraftApp on macOS, because the process ends there without dropping the app.
This commit is contained in:
Generated
+1
-1
@@ -1246,7 +1246,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-update"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=a231e517c3b371e1bf0ee8af71ed807424a9a05d#a231e517c3b371e1bf0ee8af71ed807424a9a05d"
|
||||
source = "git+https://github.com/dotCooCoo/craft-libs?rev=c365d75c48b0e47f4b43cdb6592d0cdc39d2d52e#c365d75c48b0e47f4b43cdb6592d0cdc39d2d52e"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dunce",
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ craft-docpath = { version = "0.1.0", git = "https://github.com/storytold/craft-l
|
||||
# Canon CRW decoder shared with the other Craft apps
|
||||
craft-crw = { git = "https://github.com/storytold/craft-libs", rev = "f3b62ec61f45534392376492fc5ad33047375205" }
|
||||
# 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 = "a231e517c3b371e1bf0ee8af71ed807424a9a05d", features = ["egui"] }
|
||||
craft-update = { git = "https://github.com/dotCooCoo/craft-libs", version = "=0.1.0", rev = "c365d75c48b0e47f4b43cdb6592d0cdc39d2d52e", features = ["egui"] }
|
||||
craft-window = { git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7", features = ["egui"] }
|
||||
# internal
|
||||
lightcraft-denoise-core = { path = "crates/denoise-core" }
|
||||
|
||||
@@ -201,6 +201,10 @@ impl eframe::App for App {
|
||||
// app after this and the session's last writes (face data) still go out under the lock.
|
||||
#[cfg(target_os = "macos")]
|
||||
self.0.session.release_library_lock();
|
||||
// macOS only: the process ends below without dropping the app, so a ready update's helper
|
||||
// starts here. Elsewhere dropping the app starts it.
|
||||
#[cfg(target_os = "macos")]
|
||||
self.0.start_pending_update();
|
||||
// macOS (#1331): end the process here, before eframe tears the window down, as Quit from
|
||||
// the menu bar already does (PR #444). AccessKit's macOS adapter subclasses the window's
|
||||
// content view and restores its class on teardown; AppKit's Touch Bar support observes
|
||||
|
||||
@@ -21,6 +21,7 @@ pub(crate) struct Runtime {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
repaint: Option<egui::Context>,
|
||||
/// A requested check's result dialog is showing.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub(crate) manual_window_open: bool,
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub(crate) status_message: Option<String>,
|
||||
@@ -37,6 +38,7 @@ impl Default for Runtime {
|
||||
check_requested: false,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
repaint: None,
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
manual_window_open: false,
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
status_message: None,
|
||||
@@ -50,6 +52,13 @@ impl LightcraftApp {
|
||||
pub fn set_startup_update_check(&mut self, on: bool) {
|
||||
self.updates_rt.startup_check = on;
|
||||
}
|
||||
|
||||
/// Starts the helper of a ready update, which installs it once the process has exited. Call it
|
||||
/// in `on_exit` when the process ends there without dropping the app.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn start_pending_update(&mut self) {
|
||||
self.updates_rt.updater.start_pending_update();
|
||||
}
|
||||
}
|
||||
|
||||
/// The update prompt owns the keyboard while it is open: shortcuts must not reach the library behind it.
|
||||
@@ -89,7 +98,6 @@ pub(crate) fn tick(app: &mut LightcraftApp, ctx: &egui::Context) {
|
||||
rt.repaint = Some(ctx.clone());
|
||||
if std::mem::take(&mut rt.check_requested) {
|
||||
rt.updater.check_now(ctx);
|
||||
rt.manual_window_open = true;
|
||||
} else if rt.startup_check {
|
||||
rt.updater.check_at_start(ctx);
|
||||
}
|
||||
@@ -99,10 +107,18 @@ pub(crate) fn tick(app: &mut LightcraftApp, ctx: &egui::Context) {
|
||||
let _ = (app, ctx);
|
||||
}
|
||||
|
||||
/// Whether the result dialog 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.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn result_window_shows(status: &Status, prompt_open: bool) -> bool {
|
||||
!prompt_open && !matches!(status, Status::Idle)
|
||||
}
|
||||
|
||||
pub(crate) fn show(app: &mut LightcraftApp, ctx: &egui::Context) {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
// The restart helper is scheduled before the app closes, so no update starts over unsaved work.
|
||||
// The close for a ready update waits until nothing is unsaved.
|
||||
let clean = app.session.unsaved().is_none();
|
||||
match app.updates_rt.updater.show_if(ctx, clean) {
|
||||
Action::OpenUrl(url) => ctx.open_url(egui::OpenUrl::new_tab(url)),
|
||||
@@ -111,20 +127,16 @@ pub(crate) fn show(app: &mut LightcraftApp, ctx: &egui::Context) {
|
||||
}
|
||||
// A found update opens the startup prompt and leaves the status idle, which ends the result dialog.
|
||||
let rt = &mut app.updates_rt;
|
||||
if rt.manual_window_open {
|
||||
if result_window_shows(rt.updater.status(), rt.updater.prompt_open()) {
|
||||
let dialog = CheckResultDialog::new(&crate::UPDATE_APP, env!("CARGO_PKG_VERSION"));
|
||||
match dialog.show(ctx, rt.updater.status()) {
|
||||
CheckResultResponse::None => {}
|
||||
CheckResultResponse::Close => rt.manual_window_open = false,
|
||||
// Closing the dialog dismisses the outcome it showed.
|
||||
CheckResultResponse::Close => rt.updater.dismiss_status(),
|
||||
CheckResultResponse::CheckAgain => rt.check_requested = true,
|
||||
// The next `show_if` asks the window to close once nothing is unsaved.
|
||||
CheckResultResponse::RestartToUpdate => rt.updater.restart_to_update(),
|
||||
}
|
||||
if matches!(rt.updater.status(), Status::Idle) {
|
||||
rt.manual_window_open = false;
|
||||
}
|
||||
}
|
||||
// Closing the dialog dismisses the outcome it showed.
|
||||
if !rt.manual_window_open {
|
||||
rt.updater.dismiss_status();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,6 +175,7 @@ mod tests {
|
||||
#[test]
|
||||
fn default_runtime_is_idle() {
|
||||
let rt = Runtime::default();
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
assert!(!rt.manual_window_open);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
@@ -192,4 +205,24 @@ mod tests {
|
||||
output.textures_delta.clear();
|
||||
assert!(app.updates_rt.updater.prompt_open());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user