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
+9 -5
View File
@@ -12,7 +12,7 @@ use dr_catalog::Catalog;
use dr_types::ImageId;
use slint::ComponentHandle;
use crate::{AppWindow, Collections};
use crate::{AppWindow, Collections, Library};
use super::controller::CollectionsController;
use super::tree_sync::refresh_tree;
@@ -56,7 +56,9 @@ pub(super) fn start_trash(
}
log::info!("moving {} image(s) to the trash", moves.len());
window.set_library_status(format!("Moving {} to the trash…", moves.len()).into());
window
.global::<Library>()
.set_library_status(format!("Moving {} to the trash…", moves.len()).into());
// The images are leaving the grid; a selection pointing at them would
// survive as a set of ids the user can no longer see.
ctl.clear_selection();
@@ -131,7 +133,9 @@ pub(super) fn start_restore(
}
log::info!("restoring {} image(s) from the trash", moves.len());
window.set_library_status(format!("Restoring {}…", moves.len()).into());
window
.global::<Library>()
.set_library_status(format!("Restoring {}…", moves.len()).into());
// The images are leaving the trash view, so a selection pointing at them
// would survive as ids the user can no longer see.
ctl.clear_selection();
@@ -214,7 +218,7 @@ pub(super) fn drain_trash(
if failed > 0 {
job.detail(format!("{failed} failed"));
}
w.set_library_status(status.into());
w.global::<Library>().set_library_status(status.into());
}
TrashMessage::Done { moved, failed } => {
// Reported honestly, including the partial case: "38 of
@@ -233,7 +237,7 @@ pub(super) fn drain_trash(
} else {
job.fail(status.clone());
}
w.set_library_status(status.into());
w.global::<Library>().set_library_status(status.into());
if let Some(first) = failed.first() {
w.global::<Collections>()
.set_collection_error(first.as_str().into());
+10 -7
View File
@@ -233,7 +233,7 @@ fn wire_selection(
Ok(()) => {
w.global::<Collections>()
.set_collection_error(slint::SharedString::new());
w.set_library_status(
w.global::<Library>().set_library_status(
format!(
"{} photograph{} moved",
moving.len(),
@@ -378,7 +378,7 @@ fn wire_selection_filing(
Ok(added) => {
w.global::<Collections>()
.set_collection_error(slint::SharedString::new());
w.set_library_status(
w.global::<Library>().set_library_status(
format!(
"{added} photograph{} in {name}",
if added == 1 { "" } else { "s" }
@@ -485,7 +485,7 @@ fn wire_selection_filing(
chosen.len()
)
};
w.set_library_status(msg.into());
w.global::<Library>().set_library_status(msg.into());
refresh_tree(&w, &ctl, cat);
sync_badges(&w, cat, &visible());
@@ -690,7 +690,8 @@ fn wire_drag(
Ok(()) => {
w.global::<Collections>()
.set_collection_error(slint::SharedString::new());
w.set_library_status("Moved collection".into());
w.global::<Library>()
.set_library_status("Moved collection".into());
let borrow = catalog.borrow();
if let Some(cat) = borrow.as_ref() {
refresh_tree(&w, &ctl, cat);
@@ -731,7 +732,7 @@ fn wire_drag(
carried.len()
)
};
w.set_library_status(msg.into());
w.global::<Library>().set_library_status(msg.into());
}
Err(e) => w
.global::<Collections>()
@@ -921,7 +922,8 @@ fn wire_trash_from_grid(
if chosen.is_empty() {
// A keystroke that does nothing reads as a broken key, so it
// says why rather than failing silently.
w.set_library_status("Select an image first".into());
w.global::<Library>()
.set_library_status("Select an image first".into());
return;
}
start_trash(&w, &ctl, &catalog, &session, &chosen, &reload);
@@ -967,7 +969,8 @@ fn wire_trash_from_grid(
let ids: Vec<ImageId> = listed.iter().map(|t| t.image_id).collect();
log::info!("emptying trash: {} image(s)", ids.len());
w.set_library_status(format!("Deleting {} image(s)…", ids.len()).into());
w.global::<Library>()
.set_library_status(format!("Deleting {} image(s)…", ids.len()).into());
let count = ids.len();
let rx = crate::trash::spawn_purge(
+7 -5
View File
@@ -260,7 +260,7 @@ pub(super) fn wire_remove(
// Named explicitly as a membership change: the images are
// still in the library, and a user who reads this as a
// delete will not trust the feature again.
w.set_library_status(
w.global::<Library>().set_library_status(
format!("Removed {n} from this collection; still in the library")
.into(),
);
@@ -424,7 +424,8 @@ pub(super) fn wire_row_drag(
Ok(()) => {
w.global::<Collections>()
.set_collection_error(slint::SharedString::new());
w.set_library_status("Moved to the top level".into());
w.global::<Library>()
.set_library_status("Moved to the top level".into());
refresh_tree(&w, &ctl, cat);
log::info!("promoted collection {} by drag", source.0);
}
@@ -540,7 +541,8 @@ pub(super) fn wire_row_menu(
Ok(()) => {
w.global::<Collections>()
.set_collection_error(slint::SharedString::new());
w.set_library_status("Moved to the top level".into());
w.global::<Library>()
.set_library_status("Moved to the top level".into());
close_row_menu(&w, &ctl);
refresh_tree(&w, &ctl, cat);
log::info!("promoted collection {} to the top level", id.0);
@@ -629,7 +631,7 @@ pub(super) fn wire_row_menu(
// Named as a membership change, as the removal button is:
// a user who reads this as a delete of their photographs
// will not trust the feature again.
w.set_library_status(if holds > 0 {
w.global::<Library>().set_library_status(if holds > 0 {
format!(
"Deleted the collection; its {holds} photograph(s) stay in the library"
)
@@ -729,7 +731,7 @@ pub(super) fn wire_membership(
.set_collection_error(slint::SharedString::new());
// The same wording the scoped button uses, and for the same
// reason: this is a membership change, not a delete.
w.set_library_status(
w.global::<Library>().set_library_status(
format!("Removed {n} from that collection; still in the library")
.into(),
);