Move the library's routes and status onto its own Slint global

The scan/opening/status/error lines, offline mode and its retry, pinning a
collection offline, the sync and thumbnail-sweep state, and the callbacks
that route the grid to a rescan, a sync, another library, a panorama merge
or an export — the last of what AppWindow still carried under the
library- prefix — move onto the `Library` global started earlier on this
branch. Rust reaches them through window.global::<Library>() rather than
window.set_/get_/on_/invoke_ on the root.

library-visible is the one name that stays: it is computed from
active-page and active-view, the shell's own routing state, which a
global cannot read. AppWindow now declares no other library- property or
callback.
This commit is contained in:
2026-09-20 22:22:55 +02:00
parent 6bf67cefc4
commit 1e472fd251
20 changed files with 542 additions and 433 deletions
+43 -24
View File
@@ -57,7 +57,9 @@ pub fn open(
let conn = match store.connection(&account, crate::remote::needs_secret(&account)) {
Ok(c) => c,
Err(e) => {
window.set_library_error(format!("credentials: {e}").into());
window
.global::<Library>()
.set_library_error(format!("credentials: {e}").into());
window.set_active_view(View::Library);
return;
}
@@ -79,10 +81,14 @@ pub fn open(
ctl.place_untouched.set(true);
window.set_active_view(View::Library);
window.set_library_open(true);
window.set_library_scanning(true);
window.set_library_error(slint::SharedString::new());
window.set_library_status("Starting…".into());
window.global::<Library>().set_library_open(true);
window.global::<Library>().set_library_scanning(true);
window
.global::<Library>()
.set_library_error(slint::SharedString::new());
window
.global::<Library>()
.set_library_status("Starting…".into());
// Always visible: two folders one letter apart are easy to confuse, and a
// scan of the wrong one is indistinguishable from a broken scan.
window
@@ -92,8 +98,10 @@ pub fn open(
// An empty filter would walk the whole tree and match nothing, which looks
// exactly like a broken scan. Say so instead.
if filter.is_empty() {
window.set_library_scanning(false);
window.set_library_error("No formats selected — tick at least one.".into());
window.global::<Library>().set_library_scanning(false);
window
.global::<Library>()
.set_library_error("No formats selected — tick at least one.".into());
return;
}
@@ -166,8 +174,10 @@ fn open_catalog_soon(
return;
}
window.set_library_opening(true);
window.set_library_status("Reading the catalog on this device…".into());
window.global::<Library>().set_library_opening(true);
window
.global::<Library>()
.set_library_status("Reading the catalog on this device…".into());
let rx = spawn_catalog_open(path.clone());
let weak = window.as_weak();
@@ -192,7 +202,7 @@ fn open_catalog_soon(
}
};
stop(&held.catalog_timer);
w.set_library_opening(false);
w.global::<Library>().set_library_opening(false);
match got {
CatalogOpen::Opened(cat) => {
@@ -307,7 +317,9 @@ fn begin_scan(
filter.iter().count(),
path.display()
);
window.set_library_status("Starting…".into());
window
.global::<Library>()
.set_library_status("Starting…".into());
let rx = library::spawn_scan(
conn.clone(),
@@ -358,9 +370,10 @@ fn drain_scan(
Err(std::sync::mpsc::TryRecvError::Disconnected) => {
// A worker that died without sending must not leave
// the screen on "Scanning…" forever.
if w.get_library_scanning() {
w.set_library_scanning(false);
w.set_library_error("scan ended unexpectedly".into());
if w.global::<Library>().get_library_scanning() {
w.global::<Library>().set_library_scanning(false);
w.global::<Library>()
.set_library_error("scan ended unexpectedly".into());
job.fail("ended unexpectedly");
}
stop(&ctl.scan_timer);
@@ -384,7 +397,7 @@ fn drain_scan(
format!("{directories} folders · {images} images")
};
job.detail(status.clone());
w.set_library_status(status.into());
w.global::<Library>().set_library_status(status.into());
}
ScanMessage::Done {
found,
@@ -398,7 +411,7 @@ fn drain_scan(
{pruned} folders unchanged, {judgements} judgements \
taken in) in {elapsed_ms} ms"
);
w.set_library_scanning(false);
w.global::<Library>().set_library_scanning(false);
// A completed scan is the strongest possible evidence
// the server is reachable, so it clears offline mode
@@ -452,7 +465,7 @@ fn drain_scan(
status
};
job.finish(status.clone());
w.set_library_status(status.into());
w.global::<Library>().set_library_status(status.into());
// Usually already open — `show_catalog_now` opened it
// before this scan started, so the grid has been
@@ -487,7 +500,9 @@ fn drain_scan(
// than the part that was scrolled past.
start_sweep(&w, ctl);
}
Err(e) => w.set_library_error(format!("opening catalog: {e}").into()),
Err(e) => w
.global::<Library>()
.set_library_error(format!("opening catalog: {e}").into()),
}
stop(&ctl.scan_timer);
return;
@@ -498,7 +513,7 @@ fn drain_scan(
lost_root,
} => {
log::warn!("scan failed: {message}");
w.set_library_scanning(false);
w.global::<Library>().set_library_scanning(false);
// Recorded as a failure even where it is only the
// connection: the grid's offline banner says the server
// is unreachable, and this says which piece of work
@@ -540,7 +555,7 @@ fn drain_scan(
// for.
open_catalog_for_offline(&w, ctl, &catalog_path, &coll_ctl);
} else {
w.set_library_error(message.into());
w.global::<Library>().set_library_error(message.into());
}
stop(&ctl.scan_timer);
return;
@@ -568,9 +583,13 @@ pub(crate) fn start_rescan(
return;
};
window.set_library_scanning(true);
window.set_library_error(slint::SharedString::new());
window.set_library_status("Rescanning…".into());
window.global::<Library>().set_library_scanning(true);
window
.global::<Library>()
.set_library_error(slint::SharedString::new());
window
.global::<Library>()
.set_library_status("Rescanning…".into());
let path = library::catalog_path(&conn.account);
let rx = library::spawn_scan(
@@ -616,7 +635,7 @@ fn open_catalog_for_offline(
// No catalog and no server. This is the one genuinely empty case:
// a first run that never reached the server has nothing indexed.
log::warn!("offline with no local catalog: {e}");
window.set_library_error(
window.global::<Library>().set_library_error(
"Offline, and this library has not been scanned on this device yet.".into(),
);
}