Move ratings, flags and keywording onto the library's Slint global

The keywording sheet's rows and its open/assign/unassign callbacks, the
star and flag callbacks a cell click or a judgement key fires, the burst
toggle and representative-chosen callbacks, the trash-selection shortcut,
and the rating/unjudged/flag filter chips with their rating-counts model
move from AppWindow onto the `Library` global started in the previous
commit. Rust reaches them through window.global::<Library>() rather than
window.set_/get_/on_ on the root.
This commit is contained in:
2026-09-20 21:57:40 +02:00
parent 402dcdc24c
commit 00e2fe6aaf
8 changed files with 309 additions and 272 deletions
+91 -73
View File
@@ -64,7 +64,9 @@ pub fn sync_ratings(window: &AppWindow, catalog: &Catalog, ids: &[dr_types::Imag
pub(super) fn refresh_rating_counts(window: &AppWindow, catalog: &Catalog) {
let counts = dr_catalog::rating::rating_histogram(catalog.connection()).unwrap_or_default();
let as_i32: Vec<i32> = counts.iter().map(|n| *n as i32).collect();
window.set_library_rating_counts(slint::ModelRc::new(slint::VecModel::from(as_i32)));
window
.global::<Library>()
.set_library_rating_counts(slint::ModelRc::new(slint::VecModel::from(as_i32)));
// TRACES: FR-CAT-9
// How many originals are actually here, for the "On this device" chip.
@@ -126,7 +128,9 @@ fn refresh_keywords(window: &AppWindow, ctl: &Rc<LibraryController>, images: &[d
})
.collect();
window.set_library_keywords(slint::ModelRc::new(slint::VecModel::from(model)));
window
.global::<Library>()
.set_library_keywords(slint::ModelRc::new(slint::VecModel::from(model)));
}
/// Put a keyword on the selection, or take it off.
@@ -824,17 +828,19 @@ pub(super) fn wire_ratings_and_flags(
{
let weak = window.as_weak();
let ctl = ctl.clone();
window.on_library_cell_rated(move |row, stars| {
let Some(w) = weak.upgrade() else { return };
let id = ctl
.image_ids
.borrow()
.get(row as usize)
.map(|id| dr_types::ImageId(*id as u64));
let Some(id) = id else { return };
window
.global::<Library>()
.on_library_cell_rated(move |row, stars| {
let Some(w) = weak.upgrade() else { return };
let id = ctl
.image_ids
.borrow()
.get(row as usize)
.map(|id| dr_types::ImageId(*id as u64));
let Some(id) = id else { return };
apply_judgement(&w, &ctl, &[id], Some(stars.clamp(0, 5) as u8), None);
});
apply_judgement(&w, &ctl, &[id], Some(stars.clamp(0, 5) as u8), None);
});
}
// Fold a burst up, or open it out (FR-CULL-5). A reload rather than a repaint, because
@@ -842,27 +848,29 @@ pub(super) fn wire_ratings_and_flags(
{
let weak = window.as_weak();
let ctl = ctl.clone();
window.on_library_burst_toggled(move |row| {
let Some(w) = weak.upgrade() else { return };
let id = ctl
.image_ids
.borrow()
.get(row as usize)
.map(|id| dr_types::ImageId(*id as u64));
let Some(id) = id else { return };
window
.global::<Library>()
.on_library_burst_toggled(move |row| {
let Some(w) = weak.upgrade() else { return };
let id = ctl
.image_ids
.borrow()
.get(row as usize)
.map(|id| dr_types::ImageId(*id as u64));
let Some(id) = id else { return };
let changed = {
let borrow = ctl.catalog.borrow();
match borrow.as_ref() {
Some(catalog) => crate::bursts::toggle(catalog, id),
None => false,
let changed = {
let borrow = ctl.catalog.borrow();
match borrow.as_ref() {
Some(catalog) => crate::bursts::toggle(catalog, id),
None => false,
}
};
if changed {
ctl.requested.borrow_mut().clear();
load_window(&w, &ctl);
}
};
if changed {
ctl.requested.borrow_mut().clear();
load_window(&w, &ctl);
}
});
});
}
// Name the frame an open burst folds to (FR-CULL-5). The default is the
@@ -878,26 +886,28 @@ pub(super) fn wire_ratings_and_flags(
{
let weak = window.as_weak();
let ctl = ctl.clone();
window.on_library_burst_representative_chosen(move |row| {
let Some(w) = weak.upgrade() else { return };
let ids: Vec<dr_types::ImageId> = ctl
.image_ids
.borrow()
.iter()
.map(|id| dr_types::ImageId(*id as u64))
.collect();
let Some(id) = ids.get(row as usize).copied() else {
return;
};
window
.global::<Library>()
.on_library_burst_representative_chosen(move |row| {
let Some(w) = weak.upgrade() else { return };
let ids: Vec<dr_types::ImageId> = ctl
.image_ids
.borrow()
.iter()
.map(|id| dr_types::ImageId(*id as u64))
.collect();
let Some(id) = ids.get(row as usize).copied() else {
return;
};
let borrow = ctl.catalog.borrow();
let Some(catalog) = borrow.as_ref() else {
return;
};
if crate::bursts::choose(catalog, id) {
crate::bursts::sync_badges(&w, catalog, &ids);
}
});
let borrow = ctl.catalog.borrow();
let Some(catalog) = borrow.as_ref() else {
return;
};
if crate::bursts::choose(catalog, id) {
crate::bursts::sync_badges(&w, catalog, &ids);
}
});
}
// A rating or flag key. Applies to the whole selection, which is what
@@ -906,18 +916,20 @@ pub(super) fn wire_ratings_and_flags(
let weak = window.as_weak();
let ctl = ctl.clone();
let coll_for_keys = coll_ctl.clone();
window.on_library_judged(move |rating, flag| {
let Some(w) = weak.upgrade() else { return };
let chosen = coll_for_keys.selected();
window
.global::<Library>()
.on_library_judged(move |rating, flag| {
let Some(w) = weak.upgrade() else { return };
let chosen = coll_for_keys.selected();
// Exactly one axis is meant per keystroke; the other arrives as
// -1 so a star press cannot disturb a flag or the reverse.
if rating >= 0 {
apply_judgement(&w, &ctl, &chosen, Some(rating.clamp(0, 5) as u8), None);
} else if flag >= 0 {
apply_judgement(&w, &ctl, &chosen, None, Some(flag_from_code(flag)));
}
});
// Exactly one axis is meant per keystroke; the other arrives as
// -1 so a star press cannot disturb a flag or the reverse.
if rating >= 0 {
apply_judgement(&w, &ctl, &chosen, Some(rating.clamp(0, 5) as u8), None);
} else if flag >= 0 {
apply_judgement(&w, &ctl, &chosen, None, Some(flag_from_code(flag)));
}
});
}
}
@@ -936,28 +948,34 @@ pub(super) fn wire_keywords(
let weak = window.as_weak();
let ctl = ctl.clone();
let coll_for_keywords = coll_ctl.clone();
window.on_library_keywords_opened(move || {
let Some(w) = weak.upgrade() else { return };
refresh_keywords(&w, &ctl, &coll_for_keywords.selected());
});
window
.global::<Library>()
.on_library_keywords_opened(move || {
let Some(w) = weak.upgrade() else { return };
refresh_keywords(&w, &ctl, &coll_for_keywords.selected());
});
}
{
let weak = window.as_weak();
let ctl = ctl.clone();
window.on_library_assign_keyword(move |word| {
let Some(w) = weak.upgrade() else { return };
apply_keyword(&w, &ctl, word.as_str(), true);
});
window
.global::<Library>()
.on_library_assign_keyword(move |word| {
let Some(w) = weak.upgrade() else { return };
apply_keyword(&w, &ctl, word.as_str(), true);
});
}
{
let weak = window.as_weak();
let ctl = ctl.clone();
window.on_library_unassign_keyword(move |word| {
let Some(w) = weak.upgrade() else { return };
apply_keyword(&w, &ctl, word.as_str(), false);
});
window
.global::<Library>()
.on_library_unassign_keyword(move |word| {
let Some(w) = weak.upgrade() else { return };
apply_keyword(&w, &ctl, word.as_str(), false);
});
}
}