Split collections_ui.rs into a module directory by area of behaviour

collections_ui.rs had grown to 4,591 lines covering the sidebar controller,
the click/drag selection policy, tree refresh, the drag gesture, the trash
worker, twelve wiring functions, and the row's rename/create/context menu,
all in one file. Split into collections_ui/ with one module per area, the
way develop/ and library/ were already split on this branch:

- controller.rs: CollectionsController and the pure drop/delete/release
  decisions (decide_drop, decide_delete, decide_release, menu_detail,
  delete_warning) that a test can drive without a window.
- press.rs: PressUndo and the click-and-release selection policy
  (apply_press, select_row, commit_press, cancel_press).
- tree_sync.rs: rebuilding the sidebar from the catalog and pushing
  catalog-derived state into the grid (refresh_tree, offline_state,
  sync_lifted/sync_selection/sync_reorderable/sync_badges,
  refresh_membership, direct_holdings).
- drag.rs: the cursor bitmap (compose_drag_image, blit_scaled) and the
  hold/spring timers (arm_hold, arm_spring, should_spring,
  collapse_spring_opened) plus their delay constants.
- trash.rs: the soft delete (start_trash, start_restore, drain_trash,
  stop_trash, refresh_trash, format_bytes).
- wiring_grid.rs / wiring_tree.rs: the wire() entry point and its twelve
  wire_* functions, split in two because together they were the largest
  single piece (grid-facing selection/drag/trash vs. sidebar-facing
  navigation/create/rename/row-drag/menu/membership).
- rename_menu.rs: creating, naming and renaming collections, and the row's
  context menu (apply_rename, create_child, unique_name, open_row_menu,
  close_row_menu, close_rename).

mod.rs carries the module's own top-level doc comment, the `pub use`
re-exports for the eight items the rest of the crate reaches by
`collections_ui::` path (CollectionsController, wire, refresh_tree,
sync_badges, sync_selection, select_row, commit_press, cancel_press), and a
shared `test_support` for the one fixture (`ids`) more than one file's
tests needed. Every item that only crossed a boundary within this module,
not out of it, was narrowed to `pub(super)` rather than kept at the
crate-wide `pub` a single file gave it for free.

Extracted with a brace-aware pass that kept each item's own leading doc
comment and attributes attached to it, and tests moved with the code they
exercise; every TRACES/GESTURE comment lands on the same code it did
before. No file outside the new directory changed — lib.rs's `mod
collections_ui;` resolves to the directory automatically, and every
outside caller's `collections_ui::` path still resolves through mod.rs's
re-exports.
This commit is contained in:
2026-09-20 20:29:21 +02:00
parent e86edef47c
commit 9c8f21b754
11 changed files with 4809 additions and 4602 deletions
+74
View File
@@ -0,0 +1,74 @@
//! TRACES: FR-CAT-7 | FR-UI-5 | NFR-P9
//! The collections sidebar, grid selection, and the drag between them.
//!
//! `dr_catalog::collections` owns the data rules — hierarchy, membership,
//! revisions, cycles. This module owns the *interaction*: what is selected,
//! what a drag is carrying, and where a release lands.
//!
//! # What this module does and does not own
//!
//! Slint's `DragArea`/`DropArea` own the *gesture* — pointer capture, the
//! threshold separating a click from a drag, arbitration against the grid's
//! Flickable, the image under the cursor, and hit-testing the release. So the
//! drop arrives already addressed to a collection, and nothing here tracks
//! pointer positions or guesses a target.
//!
//! What is left here is what Slint cannot know:
//!
//! - **the payload** — which images the drag carries, built from the selection
//! at the moment the drag starts;
//! - **the spring** — a dwell timer that opens a collapsed collection so a
//! nested child can be reached mid-drag, and closes again what the drag only
//! passed over.
//!
//! An earlier version hand-rolled the whole gesture on `TouchArea` and did not
//! work, for a reason worth keeping: an interactive `Flickable` claims any drag
//! starting inside it for scrolling and cancels the child TouchArea's press, so
//! the drag could never leave the grid.
//!
//! # Selection
//!
//! Selection is by **catalog image id**, never by row index. The grid is a
//! window over the catalog (FR-CAT-4) and scrubbing replaces every row, so an
//! index-based selection would silently come to mean forty different
//! photographs after a scrub. Ids survive that; they also survive a rescan.
//!
//! # Split into one module per area (docs/dev/code-health.md CH-1)
//!
//! `controller` holds the running state and the pure drop/delete/release
//! decisions; `press` the click-and-release selection policy; `tree_sync`
//! rebuilding the sidebar and pushing catalog state into the grid; `drag` the
//! cursor bitmap and the spring; `trash` the soft delete; `wiring_grid` and
//! `wiring_tree` the callbacks, split in two because together they were the
//! largest single piece; and `rename_menu` creating, naming and the row's
//! context menu. `mod.rs` re-exports what the rest of the crate calls by
//! `collections_ui::` path, so nothing outside this module needs to change.
mod controller;
mod drag;
mod press;
mod rename_menu;
mod trash;
mod tree_sync;
mod wiring_grid;
mod wiring_tree;
pub use controller::CollectionsController;
pub use press::{cancel_press, commit_press, select_row};
pub use tree_sync::{refresh_tree, sync_badges, sync_selection};
pub use wiring_grid::wire;
/// Test-only helpers shared by more than one of this module's submodules.
///
/// `ids` was defined once in the pre-split file and called from tests all
/// over it — both the pure `decide_drop` tests in `controller` and the press
/// tests in `press`. Splitting the tests with the code they exercise left it
/// needed in both, so it lives here once instead of being copied.
#[cfg(test)]
pub(super) mod test_support {
use dr_types::ImageId;
pub(super) fn ids(n: u64) -> Vec<ImageId> {
(1..=n).map(ImageId).collect()
}
}