UI: a Synchronize Folder rescan keeps what was ticked (review fix)

When a stale scan was made again, the dialog came back with the default
choices, so a ticked "Remove missing" or "Read metadata" was silently
dropped before the next click. The choices now carry over. A saved
dialog without `relink_moved` reads it as on, the engine's default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nathaniel Ledford
2026-10-09 18:28:31 -04:00
co-authored by Claude Opus 5.5
parent 97e2c7ff51
commit 465c1f87fc
3 changed files with 17 additions and 5 deletions
+5 -1
View File
@@ -677,7 +677,7 @@ pub enum Dialog {
/// What the scan found (`None` while it runs).
counts: Option<SyncCounts>,
import_new: bool,
#[serde(default)]
#[serde(default = "yes")]
relink_moved: bool,
remove_missing: bool,
read_metadata: bool,
@@ -686,6 +686,10 @@ pub enum Dialog {
Shortcuts,
}
fn yes() -> bool {
true
}
/// How many changes a Synchronize Folder scan found, by kind.
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
+7 -3
View File
@@ -173,13 +173,17 @@ pub fn confirm(app: &mut LightcraftApp, dlg: &Dialog) -> Result<Value, String> {
);
app.sync_owns_changes = false;
if r.is_err() {
// (the folder changed since the scan, or went offline): look again, in the background
let (path, disk) = (path.clone(), *disk);
// (the folder changed since the scan, or went offline): look again, in the background,
// keeping what was ticked; the error is what is reported, not a failure to look again
let name = match dlg {
Dialog::SynchronizeFolder { name, .. } => name.clone(),
_ => String::new(),
};
open(app, &path, &name, disk)?;
if open(app, path, &name, *disk).is_ok()
&& let Some(Dialog::SynchronizeFolder { import_new: i, relink_moved: l, remove_missing: m, read_metadata: x, .. }) = &mut app.ui.dialog
{
(*i, *l, *m, *x) = (*import_new, *relink_moved, *remove_missing, *read_metadata);
}
}
r
}
+5 -1
View File
@@ -167,6 +167,9 @@ fn a_scan_gone_stale_in_the_dialog_is_made_again_in_the_background() {
let dir = Scratch::new("restale");
let mut h = changed_folder(&dir);
open_and_scan(&mut h, &dir.path("trip"));
let r = h.request("ui.clickWidget", json!({"id": "syncRemoveMissing"}), T);
assert_eq!(r["ok"], true, "{r}");
h.step();
// a photo of the folder changes while the dialog is open
let a = h.app.session.catalog.photos().find(|p| p.file_name == "a.png").unwrap().id;
let r = h.request("engine.execute", json!({"command": "photo.rate", "params": {"ids": [a.0], "rating": 3}}), T);
@@ -177,7 +180,8 @@ fn a_scan_gone_stale_in_the_dialog_is_made_again_in_the_background() {
assert!(matches!(h.app.ui.dialog, Some(Dialog::SynchronizeFolder { .. })), "the dialog stays open");
let rescanned = h.step_until(T, |h| matches!(&h.app.ui.dialog, Some(Dialog::SynchronizeFolder { counts: Some(_), .. })));
assert!(rescanned, "and scans again");
assert!(matches!(h.app.ui.dialog, Some(Dialog::SynchronizeFolder { remove_missing: true, .. })), "keeping what was ticked");
let r = h.request("ui.dialog.confirm", json!({}), T);
assert_eq!(r["ok"], true, "{r}");
assert_eq!(in_library(&h), vec!["a.png", "b.png", "c.png"]);
assert_eq!(in_library(&h), vec!["a.png", "c.png"], "c came in, the missing b went");
}