From 6426ea8ece662ef8667d957929c695593b5be2d3 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Sat, 24 Oct 2026 15:23:28 +0200 Subject: [PATCH 1/2] Enable Filters: a folder moved while filters are off is followed by the filter put aside, and Cmd+L still brings it back (follow-up to #2709) --- crates/engine/src/cmd/browse.rs | 8 ++- crates/engine/src/lib.rs | 2 + crates/engine/src/tests_shelved_folder.rs | 69 +++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 crates/engine/src/tests_shelved_folder.rs diff --git a/crates/engine/src/cmd/browse.rs b/crates/engine/src/cmd/browse.rs index 6f3f88963..8b9acf65f 100644 --- a/crates/engine/src/cmd/browse.rs +++ b/crates/engine/src/cmd/browse.rs @@ -484,13 +484,17 @@ pub(crate) fn follow_folder(s: &mut Session, from: &str, to: &str) { follow_library_folder(&mut s.filter.library_folder, from, to); if let Some(f) = s.shelved_filter.as_mut() { follow_library_folder(&mut f.library_folder, from, to); + follow_library_folder(&mut f.folder, from, to); } if let Some(b) = &mut s.browse && let Ok(rel) = Path::new(&b.path).strip_prefix(from) { b.path = Path::new(to).join(rel).to_string_lossy().to_string(); - let f = b.path.clone(); - s.filter.folder = Some(f); + // with filters off the filter stays empty: Cmd+L brings back the one put aside + if s.shelved_filter.is_none() { + let f = b.path.clone(); + s.filter.folder = Some(f); + } } } diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index 4ad5695dc..e3593556c 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -1383,6 +1383,8 @@ mod tests_segment; #[cfg(test)] mod tests_settings_files; #[cfg(test)] +mod tests_shelved_folder; +#[cfg(test)] mod tests_slide; #[cfg(test)] mod tests_slideshow_export; diff --git a/crates/engine/src/tests_shelved_folder.rs b/crates/engine/src/tests_shelved_folder.rs new file mode 100644 index 000000000..a68b329cf --- /dev/null +++ b/crates/engine/src/tests_shelved_folder.rs @@ -0,0 +1,69 @@ +//! A filter Enable Filters (Cmd+L) put aside and a folder moved on disk meanwhile: switched back +//! on, the filter is the one put aside, and a folder it names is where the folder went. + +use lightcraft_catalog::{Op, Photo, Source}; +use serde_json::json; + +use crate::Session; + +fn add(s: &mut Session, path: &str, rating: u8) { + let id = s.catalog.alloc_photo_id(); + let mut p = Photo::new(id, Source::File { path: path.into() }, "x.jpg", "JPEG", 60, 40, "2026-01-01T10:00:00"); + p.rating = rating; + s.catalog.apply(Op::AddPhoto { photo: Box::new(p) }).unwrap(); +} + +/// A scratch folder that goes away with the test, however it ends. +struct Scratch(std::path::PathBuf); + +impl Scratch { + fn new(tag: &str) -> Scratch { + let dir = std::env::temp_dir().join(format!("lc-shelved-{tag}-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(dir.join("trip")).unwrap(); + std::fs::create_dir_all(dir.join("archive")).unwrap(); + Scratch(dir) + } + fn path(&self, rel: &str) -> String { + self.0.join(rel).components().collect::().to_string_lossy().to_string() + } +} + +impl Drop for Scratch { + fn drop(&mut self) { + let _ = std::fs::remove_dir_all(&self.0); + } +} + +#[test] +fn a_folder_in_the_filter_put_aside_follows_a_move() { + let dir = Scratch::new("filter"); + let (trip, archive) = (dir.path("trip"), dir.path("archive")); + let mut s = Session::new(); + add(&mut s, &format!("{trip}/a.jpg"), 0); + add(&mut s, &dir.path("elsewhere.jpg"), 0); + s.execute("library.filter", &json!({"folder": trip})).unwrap(); + assert_eq!(s.visible().len(), 1, "the filter hides a photo, or a stale folder would look alike"); + s.execute("library.toggleFilters", &json!({})).unwrap(); + s.execute("folder.move", &json!({"path": trip, "into": archive})).unwrap(); + let r = s.execute("library.toggleFilters", &json!({})).unwrap(); + assert_eq!(r["enabled"], json!(true)); + assert_eq!(s.filter.folder.as_deref(), Some(dir.path("archive/trip").as_str()), "the folder where it went"); + assert_eq!(s.visible().len(), 1, "the moved photo, as before the move"); +} + +#[test] +fn moving_the_browsed_folder_while_off_brings_back_the_filter_put_aside() { + let dir = Scratch::new("browse"); + let (trip, archive) = (dir.path("trip"), dir.path("archive")); + let mut s = Session::new(); + s.execute("library.browse", &json!({"path": trip})).unwrap(); + s.execute("library.filter", &json!({"rating": 4})).unwrap(); + let set = s.filter.clone(); + s.execute("library.toggleFilters", &json!({})).unwrap(); + s.execute("folder.move", &json!({"path": trip, "into": archive})).unwrap(); + assert!(s.filters_off(), "still off after the move"); + let r = s.execute("library.toggleFilters", &json!({})).unwrap(); + assert_eq!(r["enabled"], json!(true), "Cmd+L turns filtering back on"); + assert_eq!(s.filter, set, "the stars put aside, nothing added"); +} From b04e0de4ac35a40dadfa7d49da2c8c4b5d9b7bd2 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Sat, 24 Oct 2026 15:43:20 +0200 Subject: [PATCH 2/2] Enable Filters: a folder in the filter follows a move with filters on too (follow-up to #2709) --- crates/engine/src/cmd/browse.rs | 1 + crates/engine/src/tests_shelved_folder.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/crates/engine/src/cmd/browse.rs b/crates/engine/src/cmd/browse.rs index 8b9acf65f..a5896c7e9 100644 --- a/crates/engine/src/cmd/browse.rs +++ b/crates/engine/src/cmd/browse.rs @@ -482,6 +482,7 @@ pub(crate) fn follow_folder(s: &mut Session, from: &str, to: &str) { // a library folder chosen at or below it follows too, as a source or as a filter follow_library_folder(&mut s.library_folder, from, to); follow_library_folder(&mut s.filter.library_folder, from, to); + follow_library_folder(&mut s.filter.folder, from, to); if let Some(f) = s.shelved_filter.as_mut() { follow_library_folder(&mut f.library_folder, from, to); follow_library_folder(&mut f.folder, from, to); diff --git a/crates/engine/src/tests_shelved_folder.rs b/crates/engine/src/tests_shelved_folder.rs index a68b329cf..c29453df6 100644 --- a/crates/engine/src/tests_shelved_folder.rs +++ b/crates/engine/src/tests_shelved_folder.rs @@ -52,6 +52,20 @@ fn a_folder_in_the_filter_put_aside_follows_a_move() { assert_eq!(s.visible().len(), 1, "the moved photo, as before the move"); } +#[test] +fn a_folder_in_the_filter_follows_a_move_with_filters_on() { + let dir = Scratch::new("live"); + let (trip, archive) = (dir.path("trip"), dir.path("archive")); + let mut s = Session::new(); + add(&mut s, &format!("{trip}/a.jpg"), 0); + add(&mut s, &dir.path("elsewhere.jpg"), 0); + s.execute("library.filter", &json!({"folder": trip})).unwrap(); + assert_eq!(s.visible().len(), 1, "the filter hides a photo, or a stale folder would look alike"); + s.execute("folder.move", &json!({"path": trip, "into": archive})).unwrap(); + assert_eq!(s.filter.folder.as_deref(), Some(dir.path("archive/trip").as_str()), "the folder where it went"); + assert_eq!(s.visible().len(), 1, "the moved photo, as before the move"); +} + #[test] fn moving_the_browsed_folder_while_off_brings_back_the_filter_put_aside() { let dir = Scratch::new("browse");