mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-11 00:11:46 +00:00
Merge pull request #12384 from dotCooCoo/chore/craft-update-updater-fixes
Updates: the updater reports installing, ready, installed and failed, and installs at exit
This commit is contained in:
8 files changed
+181
-51
No files matched your search
Generated
+14
-27
@@ -1406,17 +1406,17 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-docpath"
|
||||
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"
|
||||
|
||||
[[package]]
|
||||
name = "craft-fonts-build"
|
||||
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"
|
||||
|
||||
[[package]]
|
||||
name = "craft-i18n"
|
||||
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 = [
|
||||
"fixed_decimal",
|
||||
"icu_decimal",
|
||||
@@ -1439,7 +1439,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-jpeg"
|
||||
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 = [
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
@@ -1457,7 +1457,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-pdf"
|
||||
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 = [
|
||||
"bytemuck",
|
||||
"hayro",
|
||||
@@ -1469,7 +1469,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-print"
|
||||
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 = [
|
||||
"craft-winprint-gdi",
|
||||
"log",
|
||||
@@ -1483,7 +1483,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-ui"
|
||||
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 = [
|
||||
"craft-fonts-build",
|
||||
"craft-i18n",
|
||||
@@ -1504,7 +1504,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",
|
||||
@@ -1530,7 +1530,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-winprint-gdi"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/winprint.rs?rev=417ac3c4d14d3da5485a99c7d5ce8f05664ec312#417ac3c4d14d3da5485a99c7d5ce8f05664ec312"
|
||||
source = "git+https://github.com/storytold/winprint.rs?rev=64e7afd4d1483512385012c340ecaaaf0f3beb7f#64e7afd4d1483512385012c340ecaaaf0f3beb7f"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
@@ -2964,7 +2964,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "hayro"
|
||||
version = "0.7.1"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=c5a1cbfb5f9049f9270955caffb5bee5997aebf7#c5a1cbfb5f9049f9270955caffb5bee5997aebf7"
|
||||
source = "git+https://github.com/dotCooCoo/craft-libs?rev=c7c84230631cbc01ee928f0a0e0d838b1ed612ae#c7c84230631cbc01ee928f0a0e0d838b1ed612ae"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"hayro-interpret",
|
||||
@@ -2994,7 +2994,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "hayro-interpret"
|
||||
version = "0.7.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=c5a1cbfb5f9049f9270955caffb5bee5997aebf7#c5a1cbfb5f9049f9270955caffb5bee5997aebf7"
|
||||
source = "git+https://github.com/dotCooCoo/craft-libs?rev=c7c84230631cbc01ee928f0a0e0d838b1ed612ae#c7c84230631cbc01ee928f0a0e0d838b1ed612ae"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"hayro-cmap",
|
||||
@@ -3012,7 +3012,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "hayro-jbig2"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=c5a1cbfb5f9049f9270955caffb5bee5997aebf7#c5a1cbfb5f9049f9270955caffb5bee5997aebf7"
|
||||
source = "git+https://github.com/dotCooCoo/craft-libs?rev=c7c84230631cbc01ee928f0a0e0d838b1ed612ae#c7c84230631cbc01ee928f0a0e0d838b1ed612ae"
|
||||
dependencies = [
|
||||
"fearless_simd",
|
||||
"hayro-ccitt",
|
||||
@@ -3036,7 +3036,7 @@ checksum = "bc2d80da85f31c3fdc0366431f44cfd645a9da1e242ed1f4a61f213d9765660f"
|
||||
[[package]]
|
||||
name = "hayro-syntax"
|
||||
version = "0.7.2"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=c5a1cbfb5f9049f9270955caffb5bee5997aebf7#c5a1cbfb5f9049f9270955caffb5bee5997aebf7"
|
||||
source = "git+https://github.com/dotCooCoo/craft-libs?rev=c7c84230631cbc01ee928f0a0e0d838b1ed612ae#c7c84230631cbc01ee928f0a0e0d838b1ed612ae"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"hayro-ccitt",
|
||||
@@ -9473,7 +9473,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "winprint"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/storytold/winprint.rs?rev=5f80b9baf6b58937c401656634e42d33f00ddf49#5f80b9baf6b58937c401656634e42d33f00ddf49"
|
||||
source = "git+https://github.com/storytold/winprint.rs?rev=64e7afd4d1483512385012c340ecaaaf0f3beb7f#64e7afd4d1483512385012c340ecaaaf0f3beb7f"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"fmt-derive",
|
||||
@@ -10006,7 +10006,6 @@ dependencies = [
|
||||
"nix",
|
||||
"typed-path",
|
||||
"windows-sys 0.61.2",
|
||||
"zopfli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10021,18 +10020,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.4.12"
|
||||
|
||||
+10
-10
@@ -10,7 +10,7 @@ license = "MIT OR Apache-2.0"
|
||||
rust-version = "1.95"
|
||||
|
||||
[workspace.dependencies]
|
||||
craft-ui = { git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7", features = ["serde"] }
|
||||
craft-ui = { git = "https://github.com/dotCooCoo/craft-libs", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae", features = ["serde"] }
|
||||
# internal
|
||||
photocraft-geom = { path = "crates/geom" }
|
||||
photocraft-color = { path = "crates/color" }
|
||||
@@ -39,13 +39,13 @@ photocraft-tablet = { path = "crates/tablet" }
|
||||
photocraft-ipp = { path = "crates/ipp" }
|
||||
|
||||
# external
|
||||
craft-print = { git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7" }
|
||||
craft-pdf = { git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7", features = ["raster"] }
|
||||
craft-docpath = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7" }
|
||||
craft-jpeg = { git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7" }
|
||||
craft-print = { git = "https://github.com/dotCooCoo/craft-libs", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae" }
|
||||
craft-pdf = { git = "https://github.com/dotCooCoo/craft-libs", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae", features = ["raster"] }
|
||||
craft-docpath = { version = "0.1.0", git = "https://github.com/dotCooCoo/craft-libs", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae" }
|
||||
craft-jpeg = { git = "https://github.com/dotCooCoo/craft-libs", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae" }
|
||||
craft-pcraft-format = { git = "https://github.com/storytold/craft-libs", rev = "b8f7d93b00dfb8f172938f3d2d796ae62dcfe123" }
|
||||
# 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"] }
|
||||
thiserror = "2"
|
||||
serde = { version = "1", features = ["derive", "rc"] }
|
||||
serde_json = "1"
|
||||
@@ -205,7 +205,7 @@ egui_demo_lib = { git = "https://github.com/storytold/egui.git", rev = "6d518fc7
|
||||
egui_inspection = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
|
||||
winit = { git = "https://github.com/storytold/winit.git", rev = "a517b3846ee8457d84ee4975110bfda6797c44dc" }
|
||||
# craft-pdf's vendored Hayro trees: consumers patch the same craft-libs revision (crates/pdf README).
|
||||
hayro = { git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7" }
|
||||
hayro-syntax = { git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7" }
|
||||
hayro-interpret = { git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7" }
|
||||
hayro-jbig2 = { git = "https://github.com/storytold/craft-libs", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7" }
|
||||
hayro = { git = "https://github.com/dotCooCoo/craft-libs", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae" }
|
||||
hayro-syntax = { git = "https://github.com/dotCooCoo/craft-libs", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae" }
|
||||
hayro-interpret = { git = "https://github.com/dotCooCoo/craft-libs", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae" }
|
||||
hayro-jbig2 = { git = "https://github.com/dotCooCoo/craft-libs", rev = "c7c84230631cbc01ee928f0a0e0d838b1ed612ae" }
|
||||
@@ -763,6 +763,7 @@ pub fn native(automation: Option<photocraft_automation::AuthorizedWorkspace>) ->
|
||||
open_url: Some(Box::new(|url: &str| open::that(url).map_err(|e| e.to_string()))),
|
||||
beep: Some(platform_beep),
|
||||
check_updates: Some(crate::updates::service()),
|
||||
last_update: Some(crate::updates::last_update),
|
||||
clipboard_set_image: Some({
|
||||
let clip = clip.clone();
|
||||
guarded_clipboard_set(move |w: u32, h: u32, px: &[u8]| {
|
||||
|
||||
@@ -218,7 +218,9 @@ fn open_filters_keep_literal_extensions_on_windows_and_macos() {
|
||||
|
||||
#[test]
|
||||
fn native_services_provide_update_transport() {
|
||||
assert!(native(None).check_updates.is_some());
|
||||
let services = native(None);
|
||||
assert!(services.check_updates.is_some());
|
||||
assert!(services.last_update.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -20,6 +20,19 @@ pub fn service() -> CheckFn {
|
||||
})
|
||||
}
|
||||
|
||||
/// What the last self-update came to, once: `craft-update` removes its records as it reads them.
|
||||
pub fn last_update() -> Option<Result<String, String>> {
|
||||
use craft_update::self_update::{Outcome, current_version, take_outcome};
|
||||
let app = &photocraft_ui_egui::UPDATE_APP;
|
||||
let paths = craft_update::Paths::for_app(app).ok()?;
|
||||
let version = photocraft_engine::build_info::VERSION;
|
||||
let running = current_version(app, version).map_or_else(|| version.to_string(), |v| v.to_string());
|
||||
match take_outcome(&paths, &running)? {
|
||||
Outcome::Installed(installed) => Some(Ok(installed.to_string())),
|
||||
Outcome::Failed(reason) => Some(Err(reason)),
|
||||
}
|
||||
}
|
||||
|
||||
fn check() -> CheckResult {
|
||||
let http = craft_update::Http::new("PhotoCraft/Update")?;
|
||||
let found = craft_update::check_for_update(&photocraft_ui_egui::UPDATE_APP, &http, photocraft_engine::build_info::VERSION)?;
|
||||
|
||||
@@ -263,8 +263,8 @@ pub use services::{
|
||||
AdoptAutosaveFn, AppendTextFn, AutomationCommandFn, AutomationOpenPcraftFn, AutomationReadFn, AutomationWriteFn, AutosaveFn, AutosaveResultsFn, CapsLockFn,
|
||||
CaptionStyleFn, ClipboardGetFn, ClipboardGetSvgFn, ClipboardSetFn, ClipboardUnreadableFn, CursorPosFn, DiscardAutosaveFn, EncodePngFn, ExportFn,
|
||||
ExportSettings, ExternalSvgEditor, ExternalSvgSession, ExternalVectorSave, ExternalVectorSource, FileStamp, FileStampFn, FormatChoices, ImportFn, Inbox,
|
||||
LoadTextFn, OpenExternalSvgFn, OpenUrlFn, OsEventsFn, PenEndFn, PhotoshopShortcutsFn, PlaceInbox, QuitFn, RecoverFn, Recoverable, RightButtonDownFn,
|
||||
SameFileFn, SaveFileFn, SaveTextFn, Services, SystemThemeFn, TabletPollFn, WindowFrameFn, WriteFn,
|
||||
LastUpdateFn, LoadTextFn, OpenExternalSvgFn, OpenUrlFn, OsEventsFn, PenEndFn, PhotoshopShortcutsFn, PlaceInbox, QuitFn, RecoverFn, Recoverable,
|
||||
RightButtonDownFn, SameFileFn, SaveFileFn, SaveTextFn, Services, SystemThemeFn, TabletPollFn, WindowFrameFn, WriteFn,
|
||||
};
|
||||
pub use text::bidi_text;
|
||||
pub use text::cjk_fonts;
|
||||
|
||||
@@ -429,6 +429,10 @@ pub type PenEndFn = Box<dyn Fn() -> Option<bool> + Send + Sync>;
|
||||
/// whether the app window is focused (to re-assert WinTab overlap priority on activation).
|
||||
pub type TabletPollFn = Box<dyn FnMut(bool)>;
|
||||
|
||||
/// What the last self-update came to: `Ok` with the version it installed, `Err` with the reason it
|
||||
/// could not be installed, `None` when there is nothing to report ([`Services::last_update`]).
|
||||
pub type LastUpdateFn = fn() -> Option<Result<String, String>>;
|
||||
|
||||
/// Platform services injected by the app binary (file dialogs, codecs), keeping this crate free of
|
||||
/// I/O dependencies.
|
||||
#[derive(Default)]
|
||||
@@ -486,6 +490,9 @@ pub struct Services {
|
||||
pub alert: Option<fn()>,
|
||||
/// Starts a background check for published releases (desktop, outside Flatpak).
|
||||
pub check_updates: Option<photocraft_engine::updates_cmds::CheckFn>,
|
||||
/// What the last self-update came to, read once at the first frame: `Ok` with the version it
|
||||
/// installed, `Err` with the reason it could not be installed (desktop).
|
||||
pub last_update: Option<LastUpdateFn>,
|
||||
/// Files delivered asynchronously (web drag-and-drop): drained every frame and opened as
|
||||
/// documents.
|
||||
pub inbox: Option<Inbox>,
|
||||
|
||||
@@ -11,6 +11,12 @@ pub(crate) struct Runtime {
|
||||
/// The startup prompt and the self-update behind it (desktop).
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
updater: craft_update::updater::Updater,
|
||||
/// What the last self-update came to, shown in the result window until it is closed.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
last_update: craft_update::updater::Status,
|
||||
/// The check running was asked for with Help ▸ Check for Updates.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
requested: bool,
|
||||
}
|
||||
|
||||
impl Default for Runtime {
|
||||
@@ -20,6 +26,10 @@ impl Default for Runtime {
|
||||
notified_version: None,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
updater: craft_update::updater::Updater::new(&crate::UPDATE_APP, photocraft_engine::build_info::VERSION),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
last_update: craft_update::updater::Status::Idle,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
requested: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,11 +61,33 @@ pub(crate) fn check(app: &mut PhotocraftApp, _ctx: &egui::Context, params: Value
|
||||
app.updates_rt.startup_checked = true;
|
||||
// A release the user dismissed is offered again by a manual check.
|
||||
app.updates_rt.notified_version = None;
|
||||
// The window shows this check from now on.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
app.updates_rt.requested = true;
|
||||
app.updates_rt.updater.dismiss_status();
|
||||
app.updates_rt.last_update = craft_update::updater::Status::Idle;
|
||||
// A check made before the first frame leaves the last self-update's records for the
|
||||
// next start.
|
||||
app.services.last_update = None;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub(crate) fn tick(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if let Some(read) = app.services.last_update.take() {
|
||||
use craft_update::updater::Status as Shown;
|
||||
app.updates_rt.last_update = match read() {
|
||||
Some(Ok(version)) => Shown::Updated(version),
|
||||
Some(Err(reason)) => Shown::InstallFailed(reason),
|
||||
None => Shown::Idle,
|
||||
};
|
||||
if app.updates_rt.last_update != Shown::Idle {
|
||||
app.ui.updates_open = true;
|
||||
}
|
||||
}
|
||||
// `updates.status` also polls (automation may consume the result before this frame).
|
||||
app.session.updates.poll();
|
||||
if let Status::Available { release } = &app.session.updates.status
|
||||
@@ -64,7 +96,19 @@ pub(crate) fn tick(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
||||
app.updates_rt.notified_version = Some(release.version.clone());
|
||||
app.ui.updates_open = true;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
app.updates_rt.updater.offer(release_of(release));
|
||||
{
|
||||
let updater = &mut app.updates_rt.updater;
|
||||
updater.offer(release_of(release));
|
||||
// While an update installs or waits for the app to close, or while the launcher keeps
|
||||
// this version, no prompt opens: a manual check reports that state in the result window.
|
||||
if std::mem::take(&mut app.updates_rt.requested) && !updater.prompt_open() {
|
||||
updater.check_now(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if !matches!(app.session.updates.status, Status::Checking) {
|
||||
app.updates_rt.requested = false;
|
||||
}
|
||||
if app.session.updates.check.is_none() {
|
||||
return;
|
||||
@@ -89,7 +133,7 @@ pub(crate) fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
||||
{
|
||||
let was_open = app.updates_rt.updater.prompt_open();
|
||||
app.updates_rt.updater.tick(ctx);
|
||||
// The restart helper is scheduled before the app closes, so no update starts over unsaved work.
|
||||
// An update starts, and a ready one asks the app to close, only while no work is unsaved.
|
||||
let clean = !app.has_unsaved_work();
|
||||
match app.updates_rt.updater.show_if(ctx, clean) {
|
||||
craft_update::updater::Action::None => {}
|
||||
@@ -98,8 +142,9 @@ pub(crate) fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
||||
// relaunches once the process exits.
|
||||
craft_update::updater::Action::Close => ctx.send_viewport_cmd(egui::ViewportCommand::Close),
|
||||
}
|
||||
// The last self-update's outcome, hidden while the prompt showed, is still shown after it.
|
||||
if was_open && !app.updates_rt.updater.prompt_open() {
|
||||
app.ui.updates_open = false;
|
||||
app.ui.updates_open = app.updates_rt.last_update != craft_update::updater::Status::Idle;
|
||||
}
|
||||
}
|
||||
if let Some(url) = download {
|
||||
@@ -108,15 +153,37 @@ pub(crate) fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
||||
if app.updates_rt.updater.prompt_open() {
|
||||
return;
|
||||
}
|
||||
if app.ui.updates_open {
|
||||
let dialog = craft_update::CheckResultDialog::new(&crate::UPDATE_APP, photocraft_engine::build_info::VERSION);
|
||||
match dialog.show(ctx, &check_status(&app.session.updates.status)) {
|
||||
craft_update::CheckResultResponse::None => {}
|
||||
craft_update::CheckResultResponse::Close => app.ui.updates_open = false,
|
||||
craft_update::CheckResultResponse::CheckAgain => {
|
||||
let _ = check(app, ctx, serde_json::json!({}));
|
||||
}
|
||||
let status = shown_status(app);
|
||||
let dialog = craft_update::CheckResultDialog::new(&crate::UPDATE_APP, photocraft_engine::build_info::VERSION);
|
||||
match dialog.show(ctx, &status) {
|
||||
craft_update::CheckResultResponse::None => {}
|
||||
craft_update::CheckResultResponse::Close => {
|
||||
app.ui.updates_open = false;
|
||||
app.updates_rt.updater.dismiss_status();
|
||||
app.updates_rt.last_update = craft_update::updater::Status::Idle;
|
||||
}
|
||||
craft_update::CheckResultResponse::CheckAgain => {
|
||||
let _ = check(app, ctx, serde_json::json!({}));
|
||||
}
|
||||
craft_update::CheckResultResponse::RestartToUpdate => app.updates_rt.updater.restart_to_update(),
|
||||
}
|
||||
}
|
||||
|
||||
/// What the open result window shows: the updater's answer to a manual check (an update installing
|
||||
/// or ready, or a version the launcher keeps), else the last self-update's outcome, else the
|
||||
/// engine's check.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn shown_status(app: &PhotocraftApp) -> craft_update::updater::Status {
|
||||
use craft_update::updater::Status as Shown;
|
||||
let updater = app.updates_rt.updater.status();
|
||||
if !app.ui.updates_open {
|
||||
Shown::Idle
|
||||
} else if *updater != Shown::Idle {
|
||||
updater.clone()
|
||||
} else if app.updates_rt.last_update != Shown::Idle {
|
||||
app.updates_rt.last_update.clone()
|
||||
} else {
|
||||
check_status(&app.session.updates.status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,6 +337,59 @@ mod tests {
|
||||
assert!(app.updates_rt.updater.prompt_open());
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn press_escape(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
||||
let escape = egui::Event::Key { key: egui::Key::Escape, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE };
|
||||
let mut output = ctx.run_ui(egui::RawInput { events: vec![escape], ..Default::default() }, |ui| show(app, ui.ctx()));
|
||||
output.textures_delta.clear();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn the_last_update_opens_the_result_window_once_until_it_is_closed() {
|
||||
use craft_update::updater::Status as Shown;
|
||||
let (mut app, _, _) = app();
|
||||
app.services.last_update = Some(|| Some(Ok("99.0.0".into())));
|
||||
let ctx = egui::Context::default();
|
||||
at(&mut app, &ctx, 0.0);
|
||||
assert!(app.ui.updates_open);
|
||||
assert_eq!(shown_status(&app), Shown::Updated("99.0.0".into()));
|
||||
assert!(app.services.last_update.is_none(), "read once");
|
||||
at(&mut app, &ctx, 1.0);
|
||||
assert_eq!(shown_status(&app), Shown::Updated("99.0.0".into()), "shown until closed");
|
||||
press_escape(&mut app, &ctx);
|
||||
assert!(!app.ui.updates_open);
|
||||
assert_eq!(app.updates_rt.last_update, Shown::Idle);
|
||||
assert_eq!(shown_status(&app), Shown::Idle);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn a_failed_update_is_reported_until_a_manual_check_replaces_it() {
|
||||
use craft_update::updater::Status as Shown;
|
||||
let (mut app, calls, _) = app();
|
||||
app.services.last_update = Some(|| Some(Err("the installer exited with code 1603".into())));
|
||||
app.session.edit_prefs(|p| p.general.automatically_check_updates = false);
|
||||
let ctx = egui::Context::default();
|
||||
at(&mut app, &ctx, 0.0);
|
||||
assert_eq!(shown_status(&app), Shown::InstallFailed("the installer exited with code 1603".into()));
|
||||
menus::invoke(&mut app, &ctx, "help.checkForUpdates", serde_json::json!({})).unwrap();
|
||||
assert_eq!(*calls.lock().unwrap(), 1);
|
||||
assert_eq!(shown_status(&app), Shown::Checking, "the window shows the new check");
|
||||
|
||||
let (mut early, _, _) = self::app();
|
||||
early.services.last_update = Some(|| Some(Err("unread".into())));
|
||||
menus::invoke(&mut early, &ctx, "help.checkForUpdates", serde_json::json!({})).unwrap();
|
||||
at(&mut early, &ctx, 0.0);
|
||||
assert_eq!(shown_status(&early), Shown::Checking, "a check before the first frame is not replaced by the last update");
|
||||
assert!(early.services.last_update.is_none());
|
||||
|
||||
let (mut quiet, _, _) = self::app();
|
||||
quiet.services.last_update = Some(|| None);
|
||||
at(&mut quiet, &ctx, 0.0);
|
||||
assert!(!quiet.ui.updates_open, "nothing to report opens nothing");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_manual_check_that_fails_to_start_opens_the_status_window() {
|
||||
let mut app =
|
||||
|
||||
Reference in new issue
Block a user