library.rs was 7,729 lines wiring together everything "open a remote library" touches: scanning, pulling other devices' judgements out of sidecars found along the way, writing local edits back out to the sidecar outbox, pushing/reloading XMP by hand, fetching and prefetching thumbnails and originals, generating thumbnails locally, the metadata and thumbnail background sweeps, on-disk paths for the catalog and model files, and reading the grid's cells, spans and rating filter. Same motivation as the develop.rs split (docs/dev/code-health.md CH-1): a pure, no-behaviour-change move into one file per area, each under about 1,500 lines. Tracing actual call sites rather than trusting the file's physical layout mattered here: `persist`, `load_folder_etags`, `pull_sidecars`, `load_sidecar_etags`, `record_sidecar_read` and `apply_judgement` sit textually beside the XMP push/reload functions but are called only from `run_scan` (pulling a device's own past judgements out of the sidecars a scan just walked), so they went to scan.rs and not xmp.rs. `cells` came out at over 1,800 lines once its tests moved with it and split further into cells.rs (windowed reads, trash, ordinals) and spans.rs (collection scope, manual reordering, the capture-time histogram) -- ten submodules rather than the nine first planned. Previously-private items reached from a sibling module became `pub(super)`, narrower than the whole-crate reachability one file gave them. Tests moved with the code they test; the two test fixtures used across more than one file (`scanned`, and develop.rs's `session_with_a_left_half_subject` in the matching commit) joined the shared `test_support` module alongside the existing `entry`/ `with_images`/`image_ids` helpers. `mod.rs` re-exports every module's public items under `library::`, including the `pub(crate)` `test_support` module `repairs.rs` reads its fixtures from, so no file outside `library` needed a change. The previous commit split develop.rs the same way; taken alone it left dr-ui without library.rs, so that intermediate commit does not build on its own. This one restores it.
126 lines
4.3 KiB
Rust
126 lines
4.3 KiB
Rust
//! TRACES: FR-CAT-1 | FR-CAT-4 | FR-NC-3 | NFR-P9
|
|
//! Opening a remote library: scan → catalog → grid.
|
|
//!
|
|
//! This is the wire between three pieces that already worked separately —
|
|
//! `dr_sync::scan` walks the tree, `dr_catalog` indexes it, and
|
|
//! `dr_decode::preview` turns bytes into pixels. Until now the "Open library"
|
|
//! button logged its intent and stopped.
|
|
//!
|
|
//! # Threading
|
|
//!
|
|
//! Slint's event loop is single-threaded and must never block (NFR-P9), so
|
|
//! every network and decode operation runs on a worker thread and results
|
|
//! return through an mpsc channel drained by a Slint timer. That is the same
|
|
//! shape the login flow uses; it is repeated rather than shared because the
|
|
//! message types differ and a generic version would obscure both.
|
|
//!
|
|
//! # Why thumbnails are fetched, not derived from the scan
|
|
//!
|
|
//! A scan yields paths and sizes, nothing visual. Each thumbnail costs its own
|
|
//! range request, so they are fetched **only for cells the grid actually
|
|
//! wants** — never for the whole library up front. On the reference library
|
|
//! that is the difference between a few MB and ~370 GB (ARCH §6.7).
|
|
//!
|
|
//! Split into one module per area (docs/dev/code-health.md CH-1): filtering,
|
|
//! sidecar writes, on-disk paths, scanning, XMP, thumbnail fetch and
|
|
//! generation, the background sweeps, and reading the grid's cells and spans.
|
|
//! `mod.rs` re-exports every module's public items so nothing outside
|
|
//! `library` needs to change.
|
|
|
|
mod cells;
|
|
mod filters;
|
|
mod paths;
|
|
mod scan;
|
|
mod sidecar;
|
|
mod spans;
|
|
mod sweep;
|
|
mod thumbnails_fetch;
|
|
mod thumbnails_gen;
|
|
mod xmp;
|
|
|
|
pub use cells::*;
|
|
pub use filters::*;
|
|
pub use paths::*;
|
|
pub use scan::*;
|
|
pub use sidecar::*;
|
|
pub use spans::*;
|
|
pub use sweep::*;
|
|
pub use thumbnails_fetch::*;
|
|
pub use thumbnails_gen::*;
|
|
pub use xmp::*;
|
|
|
|
#[cfg(test)]
|
|
pub(crate) mod test_support {
|
|
//! Fixtures shared with the modules that build on this one's catalog
|
|
//! layout -- `repairs`, whose work lists are read over the same `images`
|
|
//! and `remote` rows a scan writes.
|
|
use dr_catalog::Catalog;
|
|
use dr_sync::{RemoteEntry, RemoteId, RemotePath};
|
|
|
|
use super::scan::persist;
|
|
|
|
pub fn entry(path: &str, file_id: u64, size: u64) -> RemoteEntry {
|
|
RemoteEntry {
|
|
id: RemoteId::Stable(file_id),
|
|
path: RemotePath::new(path),
|
|
kind: dr_sync::EntryKind::File,
|
|
validator: dr_sync::Validator::new("v"),
|
|
size,
|
|
modified: None,
|
|
has_preview: false,
|
|
materialised: true,
|
|
}
|
|
}
|
|
|
|
/// A catalog with `n` images, ready to file into collections.
|
|
pub fn with_images(n: usize) -> Catalog {
|
|
let catalog = Catalog::in_memory().unwrap();
|
|
let images: Vec<RemoteEntry> = (0..n)
|
|
.map(|i| entry(&format!("PhotosRaw/img{i:03}.CR2"), i as u64, 1000))
|
|
.collect();
|
|
let result = dr_sync::ScanResult {
|
|
images,
|
|
directories: vec![(RemotePath::new("PhotosRaw"), dr_sync::Validator::new("e"))],
|
|
progress: Default::default(),
|
|
sidecars: Vec::new(),
|
|
};
|
|
persist(&catalog, "PhotosRaw", &result).unwrap();
|
|
catalog
|
|
}
|
|
|
|
/// A catalog with `n` scanned images, none trashed.
|
|
///
|
|
/// Shared with `spans`, whose collection-membership tests build on the
|
|
/// same "n images, no folders beyond the root" catalog `cells`'s trash
|
|
/// tests do.
|
|
pub fn scanned(n: u64) -> Catalog {
|
|
let catalog = Catalog::in_memory().unwrap();
|
|
let images = (1..=n)
|
|
.map(|i| entry(&format!("PhotosRaw/IMG_{i:04}.CR2"), 1000 + i, 30_000_000))
|
|
.collect();
|
|
persist(
|
|
&catalog,
|
|
"PhotosRaw",
|
|
&dr_sync::ScanResult {
|
|
images,
|
|
directories: vec![(RemotePath::new("PhotosRaw"), dr_sync::Validator::new("e1"))],
|
|
progress: Default::default(),
|
|
sidecars: Vec::new(),
|
|
},
|
|
)
|
|
.unwrap();
|
|
catalog
|
|
}
|
|
|
|
pub fn image_ids(catalog: &Catalog) -> Vec<dr_types::ImageId> {
|
|
let mut stmt = catalog
|
|
.connection()
|
|
.prepare("SELECT id FROM images ORDER BY source_ref")
|
|
.unwrap();
|
|
stmt.query_map([], |r| Ok(dr_types::ImageId(r.get::<_, i64>(0)? as u64)))
|
|
.unwrap()
|
|
.map(Result::unwrap)
|
|
.collect()
|
|
}
|
|
}
|