Merge PR #2024: LR-IMP-LOCAL: Opening on Missing Photos no longer checks every original

This commit is contained in:
aiongg
2026-10-22 02:39:26 +00:00
3 changed files with 63 additions and 1 deletions
+5 -1
View File
@@ -158,7 +158,11 @@ fn stamp_browsed(s: &mut Session, root: &str, files: &[String]) {
/// referred to by an undo / redo step.
fn in_use(s: &mut Session) -> std::collections::HashSet<PhotoId> {
let mut keep = held(s);
keep.extend(s.visible().iter().copied());
// Missing Photos lists library photos only, never Local records, so it keeps nothing here; and
// working it out checks every original (minutes on a sleeping NAS when the library opens on it)
if s.source != crate::LibrarySource::Missing {
keep.extend(s.visible().iter().copied());
}
keep
}
+3
View File
@@ -558,7 +558,10 @@ impl Session {
self.selection.ids.retain(|id| self.catalog.photo(*id).is_some());
self.selection.active = self.selection.active.filter(|id| self.catalog.photo(*id).is_some());
}
// not on Missing Photos: working that view out checks every original (minutes on a
// sleeping NAS), and the app checks them in the background once it runs
if self.selection.active.is_none()
&& self.source != LibrarySource::Missing
&& let Some(first) = self.visible_cloned().first()
{
self.selection = Selection::single(*first);
+55
View File
@@ -259,3 +259,58 @@ fn browsing_again_forgets_untouched_records_of_deleted_files() {
assert_eq!(s.catalog.to_snapshot(), expect);
let _ = std::fs::remove_dir_all(&root);
}
/// Opens `lib` with a probe that counts the originals it checks.
fn open_counting(lib: &Path, clock: &Arc<Mutex<String>>) -> (Session, Arc<std::sync::atomic::AtomicUsize>) {
let checks = Arc::new(std::sync::atomic::AtomicUsize::new(0));
let mut s = Session::new().with_fs();
let c = clock.clone();
s.clock = Box::new(move || c.lock().unwrap().clone());
let n = checks.clone();
s.media.availability.set_probe(Arc::new(move |p| {
n.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
Path::new(p).exists()
}));
s.open_library(lib, false).unwrap();
(s, checks)
}
/// A library last shown on Missing Photos opens without checking its originals: that view holds
/// no Local records, so forgetting them needn't work it out, and no photo is picked from it (each
/// check can wait for a sleeping NAS; a big library on one froze the window for minutes).
#[test]
fn opening_on_missing_photos_checks_no_originals() {
let root = temp_dir("missing");
let (a, lib) = (root.join("a"), root.join("lib"));
for i in 0..5 {
png(&a.join(format!("m{i}.png")), i);
}
let clock = Arc::new(Mutex::new("2026-08-01T10:00:00".to_string()));
let mut s = open(&lib, &clock);
s.execute("library.import", &json!({"paths": [a.to_string_lossy()], "mode": "add"})).unwrap();
s.execute("library.source", &json!({"kind": "missing"})).unwrap();
// every original is there: the view is empty and nothing is selected
assert!(s.visible().is_empty());
assert!(s.selection.active.is_none());
s.close_library().unwrap();
drop(s);
let (s, checks) = open_counting(&lib, &clock);
assert_eq!(s.source, LibrarySource::Missing, "the view is restored");
assert_eq!(checks.load(std::sync::atomic::Ordering::SeqCst), 0, "opening an empty Missing view checked originals");
assert!(s.library.as_ref().unwrap().forgot_local.is_some(), "forgetting still ran");
drop(s);
// the originals go: the view lists them, one is active
std::fs::remove_dir_all(&a).unwrap();
let mut s = open(&lib, &clock);
s.execute("library.source", &json!({"kind": "all"})).unwrap();
s.execute("library.source", &json!({"kind": "missing"})).unwrap();
assert_eq!(s.visible().len(), 5, "all five are missing");
assert!(s.selection.active.is_some());
s.close_library().unwrap();
drop(s);
let (s, checks) = open_counting(&lib, &clock);
assert_eq!(s.source, LibrarySource::Missing);
assert_eq!(checks.load(std::sync::atomic::Ordering::SeqCst), 0, "opening a full Missing view checked originals");
let _ = std::fs::remove_dir_all(&root);
}