From 5260206fd41b800ec6e51744ea152c017cfd2baa Mon Sep 17 00:00:00 2001 From: Antonio Sokic <5701985+finaler1x@users.noreply.github.com> Date: Fri, 30 Oct 2026 19:46:15 +0100 Subject: [PATCH] Issue #3405: Auto Import waits for an import that starts during its listing An import, sync or Lightroom migration that started while the watched folder was listed made the scan mark the new files as tried without importing them, so they were skipped until restart. The listing's result is now dropped in that case and the next listing imports them. --- crates/ui-egui/src/app/frame.rs | 5 +++++ crates/ui-egui/src/tests/drop_import.rs | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/crates/ui-egui/src/app/frame.rs b/crates/ui-egui/src/app/frame.rs index 6e92091c7..fed05d6b4 100644 --- a/crates/ui-egui/src/app/frame.rs +++ b/crates/ui-egui/src/app/frame.rs @@ -97,6 +97,11 @@ impl LightcraftApp { Ok(l) => l, Err(e) => return log::debug!("auto import: {e}"), }; + // an import, sync or Lightroom migration that started while the folder was listed: scanning + // now would mark the new files as tried without importing them; the next listing picks them up + if app.import.is_some() || app.sync_run.is_some() || app.lightroom.is_some() { + return; + } let p = serde_json::json!({"listing": listing, "start": false}); let Ok(r) = app.session.execute("library.autoImportScan", &p) else { return }; let Some(mut params) = r.get("import").cloned().filter(|_| app.import.is_none()) else { return }; diff --git a/crates/ui-egui/src/tests/drop_import.rs b/crates/ui-egui/src/tests/drop_import.rs index 3d8031a69..af6556010 100644 --- a/crates/ui-egui/src/tests/drop_import.rs +++ b/crates/ui-egui/src/tests/drop_import.rs @@ -1107,3 +1107,22 @@ fn public_drop_take_preserves_reentered_barrier_order_and_clears_protection() { assert_eq!(photos(&h), 0, "neither taken handles nor refused arrivals replay"); } } + +/// An import that starts while Auto Import lists its watched folder: the new photo isn't marked as +/// tried and skipped, the next listing imports it once the other import is done. +#[test] +fn auto_import_waits_for_an_import_that_starts_during_its_listing() { + let dir = Scratch::new("auto-race"); + let mut h = app(&dir); + write_png(&dir.path("watch/w.png"), 3); + h.app.session.import_defaults.auto_folder = Some(dir.path("watch")); + // the first listing notes the file's size, the second (size unchanged) imports it + assert!(h.step_until(T, |h| h.app.tasks.is_running("Auto Import")), "the watched folder is listed"); + assert!(h.step_until(T, |h| !h.app.tasks.is_running("Auto Import"))); + assert_eq!(photos(&h), 0); + assert!(h.step_until(T, |h| h.app.tasks.is_running("Auto Import")), "and listed again"); + // the listing's result is applied on a later frame, after this import has started + h.app.import = Some(crate::import::ImportTask::new(vec![dir.path("trip")], json!({"mode": "add"}), 0, false)); + assert!(h.step_until(T, |h| photos(h) == 3), "the trip's two photos and the watched one arrive: {}", photos(&h)); + h.app.session.import_defaults.auto_folder = None; +}