diff --git a/crates/ui-egui/src/dialogs/confirm.rs b/crates/ui-egui/src/dialogs/confirm.rs index 6b8998c33..4b7d37cef 100644 --- a/crates/ui-egui/src/dialogs/confirm.rs +++ b/crates/ui-egui/src/dialogs/confirm.rs @@ -212,10 +212,13 @@ pub fn confirm_dialog(app: &mut LightcraftApp, dlg: &Dialog) -> Result 0 { app.ui.settings.ask_before_move = false; } - crate::panels::left::move_photos(app, Some(ids), folder).map(|n| json!({"moved": n})) + Ok(json!({"moved": moved})) } // the catalog found: no file dialog; none: File ▸ Import Lightroom Catalog… asks for it Dialog::LightroomCatalog { catalog, .. } => { diff --git a/crates/ui-egui/src/tests/folder_drop.rs b/crates/ui-egui/src/tests/folder_drop.rs index b7a515131..438e035d6 100644 --- a/crates/ui-egui/src/tests/folder_drop.rs +++ b/crates/ui-egui/src/tests/folder_drop.rs @@ -328,6 +328,46 @@ fn dont_ask_again_moves_the_next_drop_at_once() { let _ = std::fs::remove_dir_all(&root); } +#[test] +fn dont_ask_again_is_kept_only_when_the_move_began() { + let (root, trip, home) = folders("dont-ask-refused"); + let mut h = app(&[(trip.join("beach.png"), false), (home.join("garden.png"), false)]); + click(&mut h, &format!("libraryFolderToggle:{}", folder_key(&root))); + let target = folder_row(&h, &home).unwrap(); + let beach = id_of(&h, "beach.png"); + // a file of that name is in the folder already (not in the library): the move is refused + std::fs::copy(trip.join("beach.png"), home.join("beach.png")).unwrap(); + drop_beach(&mut h, beach, target); + click(&mut h, "check:moveDontAsk"); + assert!(matches!(h.app.ui.dialog, Some(crate::state::Dialog::MovePhotos { dont_ask: true, .. })), "ticked"); + click(&mut h, "button:dialogOk"); + assert!(h.app.ui.dialog.is_none(), "the refusal closes the question"); + assert!(trip.join("beach.png").is_file(), "nothing moved"); + assert!(h.app.ui.settings.ask_before_move, "a refused move leaves the question on"); + let _ = std::fs::remove_dir_all(&root); +} + +/// A confirmation that finds the photos in the folder already (they were moved there while the question was +/// open, or a folder synchronization relinked them) moves nothing, so it doesn't turn the question off either. +#[test] +fn dont_ask_again_is_kept_only_when_a_photo_moved() { + let (root, trip, home) = folders("dont-ask-already"); + let mut h = app(&[(trip.join("beach.png"), false), (home.join("garden.png"), false)]); + click(&mut h, &format!("libraryFolderToggle:{}", folder_key(&root))); + let target = folder_row(&h, &home).unwrap(); + let beach = id_of(&h, "beach.png"); + drop_beach(&mut h, beach, target); + click(&mut h, "check:moveDontAsk"); + assert!(matches!(h.app.ui.dialog, Some(crate::state::Dialog::MovePhotos { dont_ask: true, .. })), "ticked"); + // the photo gets there some other way while the question is open + h.app.run("photo.moveToFolder", json!({"folder": home.to_string_lossy(), "ids": [beach]})).unwrap(); + assert!(home.join("beach.png").is_file()); + click(&mut h, "button:dialogOk"); + assert!(h.app.ui.dialog.is_none()); + assert!(h.app.ui.settings.ask_before_move, "nothing moved: the question stays on"); + let _ = std::fs::remove_dir_all(&root); +} + #[test] fn a_question_left_open_while_another_library_opens_moves_nothing() { let (root, trip, home) = folders("other-library"); diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index 1d801329e..98863fe6a 100644 --- a/docs/parity-checklist.md +++ b/docs/parity-checklist.md @@ -1,6 +1,6 @@ # Lightroom parity checklist -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-29 · **Change:** minor (LR-IMP-ADD-DIALOG: remembered import thumbnail size, density-aware bounded previews and one job per candidate/size bucket (#2237, part of #2056); import loupe remains open; counts unchanged; LR-FILT-SEARCH-META: `>=` / `<=` in fielded search tokens; MENU-FILE-CLOSE, KEY-CLOSEWINDOW: the notes say Close Window quits the app, after the same check as Quit; MENU-EDIT-SELECTNONE, MENU-EDIT-PASTESELECTED: Edit lists Select Only Active Photo after Deselect All and Paste Settings from Previous after Paste Selected Settings…; on macOS no doubled separators are left where Settings… moved to the app menu; LR-BEHAV-TITLEBAR: a double-click follows the system setting, and a panel over the bar keeps the window still; KEYC-METADATA, LRC-LIB-KEYWORDS: ⌥0 / ⌥⇧0 go to the next / previous keyword set; LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings; KEYC-METADATA: ⌘K / Ctrl+K Add Keywords; LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-29 · **Change:** minor (LRC-LIB-LIBFOLDERS: Don't ask again in the Move Photos question is kept only when the move started; a refused move leaves the question on; LR-IMP-ADD-DIALOG: remembered import thumbnail size, density-aware bounded previews and one job per candidate/size bucket (#2237, part of #2056); import loupe remains open; counts unchanged; LR-FILT-SEARCH-META: `>=` / `<=` in fielded search tokens; MENU-FILE-CLOSE, KEY-CLOSEWINDOW: the notes say Close Window quits the app, after the same check as Quit; MENU-EDIT-SELECTNONE, MENU-EDIT-PASTESELECTED: Edit lists Select Only Active Photo after Deselect All and Paste Settings from Previous after Paste Selected Settings…; on macOS no doubled separators are left where Settings… moved to the app menu; LR-BEHAV-TITLEBAR: a double-click follows the system setting, and a panel over the bar keeps the window still; KEYC-METADATA, LRC-LIB-KEYWORDS: ⌥0 / ⌥⇧0 go to the next / previous keyword set; LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings; KEYC-METADATA: ⌘K / Ctrl+K Add Keywords; LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 The measured, row-by-row checklist: one row per Lightroom feature, menu item and shortcut, what we have and what is missing. It answers *does the feature exist?* (feature breadth). Whether it is good @@ -703,7 +703,7 @@ From `08-lightroom-classic-extras.md` (Classic-only features) and part 2 of `06- | LRC-LIB-CATALOG-LOCK | Catalog open in one program at a time | P1 | ✅ | `cmd:app.openLibrary`, `crates/catalog/src/lock.rs`, `crates/engine/src/library.rs` (`open_library`) | exclusive OS lock on `catalog.lock` for the session (app and `lightcraft-cli --library`); a second opener is refused with who has it (`catalog.lock.owner`: program, process, computer); released by the OS on a crash, so never stale; file systems without locks open unprotected with a warning (the app's notices, `library.info` → `settingsWarnings`, and the CLI's stderr; issue #171); no read-only mode; the browser build (OPFS) has no guard across tabs yet. A library that can't be opened at launch (locked, unreadable, newer format, drive missing) shows a window — Try Again, Choose Another Library…, Continue Without Saving (then a banner; nothing written), Quit — instead of a silent demo session (`crates/ui-egui/src/panels/library_problem.rs`); the lock is released explicitly when the library closes, not by letting its file handle close, so a program another thread is starting at that moment (which holds a copy of every file handle until it is launched) cannot keep the library "already open" for a moment (issue #680) | | LRC-LIB-CATALOG-SWITCH | New / Open Recent catalog, catalog name shown | P1 | ✅ | `cmd:app.newLibrary`, `cmd:app.openLibrary`, `cmd:app.recentLibraries`, `cmd:app.clearRecentLibraries`, `crates/ui-egui/src/dialogs/settings.rs`, `crates/ui-egui/src/panels/left.rs`, `crates/ui-egui/src/panels/library_problem.rs` (`launch_plan`, `show_chooser`), `crates/ui-egui/src/tests/launch_library.rs` | File ▸ New Library… (name, then location), File ▸ Open Recent Library (last 8; missing ones greyed out, dropped when opened; Remove from List ▸ one entry, or `app.recentLibraries {remove}`, which forgets only the path; Clear), the open library's name under My Photos and in the window title (issue #902); Open/New refused during imports and their folder scans; a library that can't be opened leaves the current one and its reference pin intact; a successful switch clears the catalog-local reference pin; ⌘O (Ctrl+O on Windows and Linux) runs Open Library… and asks for a folder once (`crates/ui-egui/src/tests/keymap.rs`: `cmd_o_opens_the_library_picker_once`); a dialog or a text field with the focus keeps the key; Settings ▸ General ▸ At launch: Open the last library (default) or Ask me, a window listing the recent libraries (name, folder, when last opened; missing, unreadable or no-longer-library ones greyed out with the reason, checked read-only — nothing is locked or written, so a library another program has open is reported, with who has it, when Open is pressed; the last one selected; Open, Open Another…, New Library…, Remove from List, Quit; ↑ ↓ Return Esc), also shown once when Alt/Option is held in the first 2 s after the window appears (macOS reports an Option key held since before launch only once it changes); `--library` and `LIGHTCRAFT_LIBRARY` come first and `lightcraft-cli` never asks (issue #1290) | | LRC-LIB-FOLDERS | Disk folder tree | P1 | ✅ | `cmd:library.browse`, `cmd:folder.rename`, `cmd:folder.move`, `crates/ui-egui/src/panels/left.rs` (`local_section`, `folder_tree`) | standard places + the browsed folder + Browse Folder…, each an expandable tree of subfolders, breadcrumb navigation; context menu: Rename Folder…, Move Folder To…, Show in Finder (on disk, photos relinked; one undo step each: undo / redo move the folder back and forth, refused when the destination is taken) | -| LRC-LIB-LIBFOLDERS | Library folders | P1 | ✅ | `cmd:library.folders`, `cmd:library.source` (`libraryFolder`), `cmd:library.filter` (`libraryFolder`), `cmd:library.removeFolder`, `cmd:folder.rename`, `cmd:folder.move`, `cmd:folder.label`, `cmd:folder.create`, `cmd:photo.moveToFolder`, `cmd:folder.scanChanges`, `cmd:folder.synchronize`, `crates/catalog/src/folders.rs`, `crates/engine/src/sync.rs`, `crates/ui-egui/src/sync.rs`, `crates/ui-egui/src/panels/left.rs` (`folders_section`, `folder_menu_for_library`, `row_menu`), `crates/ui-egui/src/tests/panels.rs` | sidebar Folders: the folders the library's photos were imported from, with photo counts (subfolders included), as another way to explore the library next to By Date and Keywords; Local stays the way to browse any folder on disk. Each disk is a row of its own and starts open: a drive letter, a Windows share (`\\server\share`, `\\?\UNC\…`, `\\wsl$\…`), a macOS share or disk (`/Volumes/tokyo`), a Linux mount (`/media`, `/run/media`, `/mnt`, gvfs `smb-share:…`, `/net/`), NFS (`/Network/Servers/`), else “This Computer” — told apart from the stored paths alone, so an offline share lists like a mounted one and the sidebar never waits on a network. Only folders that hold imported photos are listed (browsed, deleted and demo photos don't count); every folder is a row of its own (`Users` → `me` → `Pictures`), and a folder that holds nothing itself and leads to one folder starts open; every level indents one step more than its parent however deep it goes (16 pt while the deepest open row of any sidebar tree fits the panel with room for its name and count; narrower in bands of 14, 12, 10 and 8 pt when it would not, the same for every tree, chosen from the last frame; issue #2298): past 8 pt the whole sidebar (Albums, Local, By Date, Folders, Keywords) scrolls sideways when its widest row is wider than the panel (rows are measured one frame behind; Create Album and the counts stay at the visible edge); a name that does not fit ends in an ellipsis at the count (the full name on hover; a row asks for room for at most 140 pt of its name, so depth, not one long name, makes the sidebar scroll), as does the grid title; selection and hover bars end at the panel's edge; click makes the folder the source, like an album or a Local folder (its photos and those of the folders inside it fill the grid, titled “photos/travel”; the filter bar narrows it further; `library.source` `libraryFolder` + `path`; kept with the library's view), and its row is always opened into view; the shown folder follows a rename or move and their undo (engine-tested; the sidebar test covers rename), is dropped back to All Photos when it is removed or no longer holds a photo, and a smart album made from the view keeps it, also when its rules are edited (the editor has no folder field). Only a folder that shows exactly its own photos can be shown (not the startup disk, not `/Volumes`-like folders above disks, not an empty one). A row that would cover other disks' photos too (the startup disk, `/Volumes`, `/mnt`…) only opens. Right-click (row or triangle): Rename Folder…, Move Folder To…, New Folder on Disk… (`folder.create`; one undo step, undo removes it while empty), Move Selected Photos Here (`photo.moveToFolder`, also *Move to Folder…* in the photo context menu, and photos dragged from the grid onto a Folders row: the row lights up, the dragged label says “Move 3 photos to “Trip””, a closed folder held under the pointer opens, a row covering several disks and Local photos are refused with the reason, photos already there say so; a drop asks first (“Move 2 photos to “Porto”?”, Don't ask again, Settings → Confirm before moving photos to another folder on disk), and photos that leave the view leave the selection; files and XMP sidecars move, virtual copies follow, across volumes copied (streamed) and verified before the source goes, a name taken in the destination refuses the whole move, one undo step; an undo with the share offline or read-only is refused with the reason and kept until it can run, nothing deleted), Show in Finder (on disk, photos relinked, as in Local), Set Color Label ▸ (the five colours with their custom names, None, Edit Label Names…; `folder.label`, one undo step; the row shows the label's dot before its count and says it with its name; kept in the catalog as a folder record under the folder's identity, so it follows Rename / Move and their undo and redo, the folders inside going along), Synchronize Folder… (the dialog opens at once and scans the folder and the folders inside it on a worker thread — the look for new files beside parallel checks of the library's photos — then offers Import new photos (checked; files only browsed in Local count as new), Relink photos whose file was renamed or moved within the folder (checked; matched by content — a Duplicate's too — or, for a photo with no hash on record such as one from a Lightroom catalog, by file size and dimensions when exactly one file agrees), Remove missing photos from the library (to Recently Deleted) and Read metadata updates from XMP sidecars (saved after the photo came in or was last edited here, and saying something the library doesn't; the sidecar wins), with counts and skipped duplicates / unreadable files; a folder with none of these changes only says the library is up to date with it, with one Close and no choices, and closing it starts no job; `folder.scanChanges` / `folder.synchronize`, which acts on exactly the scan shown — a scan whose folder's photos changed meanwhile is refused and made again in the background — and is one undo step, also with a full history; a folder that isn't there (an unplugged disk) is reported as such, not as every photo missing; a whole disk or a folder holding disks needs `disk: true`; Esc stops the scan; Synchronize hands everything to a worker thread — the import, the checks that moved and missing files are still as found, the sidecar reads — and commits its steps between frames, shown in the activity stack with ✕ to stop, so no file is touched on the UI thread) and Remove from Library… (asks; moves the folder's photos to Recently Deleted, one undo step, no file touched); a disk row (not the startup disk) offers Set Color Label ▸, Synchronize Folder… and Remove Disk from Library… (the command needs `disk: true` for a whole disk or a folder spanning several). Limits: names are compared as written (macOS `/Volumes/tokyo` vs `/Volumes/TOKYO` are two disks; `/Volumes/Macintosh HD/…` and `/…` two rows); no disk capacity / online status; no “include subfolders” switch (a folder always includes the ones inside it); photos can't yet be dragged onto a folder row (use the menus); a name clash on moving photos is refused rather than renamed -1, -2; folders can't be filtered or sorted by label, and a label stays with the old path when the folder is moved outside LightCraft (Find Missing relinks photos, not folder records); Synchronize has no “show import dialog first” or “show missing photos” option, and only knows when a photo came in or was last developed here: a rating, label or metadata change made here (auto-write off) after another app saved the sidecar is listed as an update, and reading it restores the sidecar's older value (reading is never the default); the walk for new files stops when the scan is cancelled, and its depth/entry limits are only logged | +| LRC-LIB-LIBFOLDERS | Library folders | P1 | ✅ | `cmd:library.folders`, `cmd:library.source` (`libraryFolder`), `cmd:library.filter` (`libraryFolder`), `cmd:library.removeFolder`, `cmd:folder.rename`, `cmd:folder.move`, `cmd:folder.label`, `cmd:folder.create`, `cmd:photo.moveToFolder`, `cmd:folder.scanChanges`, `cmd:folder.synchronize`, `crates/catalog/src/folders.rs`, `crates/engine/src/sync.rs`, `crates/ui-egui/src/sync.rs`, `crates/ui-egui/src/panels/left.rs` (`folders_section`, `folder_menu_for_library`, `row_menu`), `crates/ui-egui/src/tests/panels.rs` | sidebar Folders: the folders the library's photos were imported from, with photo counts (subfolders included), as another way to explore the library next to By Date and Keywords; Local stays the way to browse any folder on disk. Each disk is a row of its own and starts open: a drive letter, a Windows share (`\\server\share`, `\\?\UNC\…`, `\\wsl$\…`), a macOS share or disk (`/Volumes/tokyo`), a Linux mount (`/media`, `/run/media`, `/mnt`, gvfs `smb-share:…`, `/net/`), NFS (`/Network/Servers/`), else “This Computer” — told apart from the stored paths alone, so an offline share lists like a mounted one and the sidebar never waits on a network. Only folders that hold imported photos are listed (browsed, deleted and demo photos don't count); every folder is a row of its own (`Users` → `me` → `Pictures`), and a folder that holds nothing itself and leads to one folder starts open; every level indents one step more than its parent however deep it goes (16 pt while the deepest open row of any sidebar tree fits the panel with room for its name and count; narrower in bands of 14, 12, 10 and 8 pt when it would not, the same for every tree, chosen from the last frame; issue #2298): past 8 pt the whole sidebar (Albums, Local, By Date, Folders, Keywords) scrolls sideways when its widest row is wider than the panel (rows are measured one frame behind; Create Album and the counts stay at the visible edge); a name that does not fit ends in an ellipsis at the count (the full name on hover; a row asks for room for at most 140 pt of its name, so depth, not one long name, makes the sidebar scroll), as does the grid title; selection and hover bars end at the panel's edge; click makes the folder the source, like an album or a Local folder (its photos and those of the folders inside it fill the grid, titled “photos/travel”; the filter bar narrows it further; `library.source` `libraryFolder` + `path`; kept with the library's view), and its row is always opened into view; the shown folder follows a rename or move and their undo (engine-tested; the sidebar test covers rename), is dropped back to All Photos when it is removed or no longer holds a photo, and a smart album made from the view keeps it, also when its rules are edited (the editor has no folder field). Only a folder that shows exactly its own photos can be shown (not the startup disk, not `/Volumes`-like folders above disks, not an empty one). A row that would cover other disks' photos too (the startup disk, `/Volumes`, `/mnt`…) only opens. Right-click (row or triangle): Rename Folder…, Move Folder To…, New Folder on Disk… (`folder.create`; one undo step, undo removes it while empty), Move Selected Photos Here (`photo.moveToFolder`, also *Move to Folder…* in the photo context menu, and photos dragged from the grid onto a Folders row: the row lights up, the dragged label says “Move 3 photos to “Trip””, a closed folder held under the pointer opens, a row covering several disks and Local photos are refused with the reason, photos already there say so; a drop asks first (“Move 2 photos to “Porto”?”, Don't ask again, which is kept only once the move has started, Settings → Confirm before moving photos to another folder on disk), and photos that leave the view leave the selection; files and XMP sidecars move, virtual copies follow, across volumes copied (streamed) and verified before the source goes, a name taken in the destination refuses the whole move, one undo step; an undo with the share offline or read-only is refused with the reason and kept until it can run, nothing deleted), Show in Finder (on disk, photos relinked, as in Local), Set Color Label ▸ (the five colours with their custom names, None, Edit Label Names…; `folder.label`, one undo step; the row shows the label's dot before its count and says it with its name; kept in the catalog as a folder record under the folder's identity, so it follows Rename / Move and their undo and redo, the folders inside going along), Synchronize Folder… (the dialog opens at once and scans the folder and the folders inside it on a worker thread — the look for new files beside parallel checks of the library's photos — then offers Import new photos (checked; files only browsed in Local count as new), Relink photos whose file was renamed or moved within the folder (checked; matched by content — a Duplicate's too — or, for a photo with no hash on record such as one from a Lightroom catalog, by file size and dimensions when exactly one file agrees), Remove missing photos from the library (to Recently Deleted) and Read metadata updates from XMP sidecars (saved after the photo came in or was last edited here, and saying something the library doesn't; the sidecar wins), with counts and skipped duplicates / unreadable files; a folder with none of these changes only says the library is up to date with it, with one Close and no choices, and closing it starts no job; `folder.scanChanges` / `folder.synchronize`, which acts on exactly the scan shown — a scan whose folder's photos changed meanwhile is refused and made again in the background — and is one undo step, also with a full history; a folder that isn't there (an unplugged disk) is reported as such, not as every photo missing; a whole disk or a folder holding disks needs `disk: true`; Esc stops the scan; Synchronize hands everything to a worker thread — the import, the checks that moved and missing files are still as found, the sidecar reads — and commits its steps between frames, shown in the activity stack with ✕ to stop, so no file is touched on the UI thread) and Remove from Library… (asks; moves the folder's photos to Recently Deleted, one undo step, no file touched); a disk row (not the startup disk) offers Set Color Label ▸, Synchronize Folder… and Remove Disk from Library… (the command needs `disk: true` for a whole disk or a folder spanning several). Limits: names are compared as written (macOS `/Volumes/tokyo` vs `/Volumes/TOKYO` are two disks; `/Volumes/Macintosh HD/…` and `/…` two rows); no disk capacity / online status; no “include subfolders” switch (a folder always includes the ones inside it); photos can't yet be dragged onto a folder row (use the menus); a name clash on moving photos is refused rather than renamed -1, -2; folders can't be filtered or sorted by label, and a label stays with the old path when the folder is moved outside LightCraft (Find Missing relinks photos, not folder records); Synchronize has no “show import dialog first” or “show missing photos” option, and only knows when a photo came in or was last developed here: a rating, label or metadata change made here (auto-write off) after another app saved the sidecar is listed as an update, and reading it restores the sidecar's older value (reading is never the default); the walk for new files stops when the scan is cancelled, and its depth/entry limits are only logged | | LRC-LIB-COLLECTIONS | Collections & sets | P1 | ✅ | `cmd:album.create`, `cmd:album.createSmart`, `cmd:album.toggleTarget`, `cmd:album.setTarget`, `cmd:album.clearQuick` | albums + folders (sets), smart albums (rule editor; rules incl. File Path — the whole string, either separator, case-insensitive), Quick Collection and target album (B in the grids adds / removes the selection; album menu ▸ Set as Target Album; the target is marked +) | | LRC-LIB-SMARTCOLL | Smart-collection rules | P1 | ✅ | `cmd:album.createSmart`, `cmd:album.setRules`, `cmd:album.ruleFields`, `cmd:dialog.smartAlbum`, `crates/catalog/src/rules.rs`, `crates/ui-egui/src/dialogs/rules_editor.rs` | rule editor: match all / any / none, nested groups (⌥+ or + Group), 47 fields. The field menu shows Rating, Pick Flag, Color Label and Any Searchable Text, then one submenu per group (`FIELD_GROUPS`; `album.ruleFields` reports each field's `group`): Source (album — a plain or a smart album, so one smart album can include or exclude another; a rule that would make an album include itself, directly or through others, is refused, and a loop saved anyway can't recurse: inside it, the album being evaluated counts as holding no photos, so an "isn't" rule on it matches every photo, and the sidebar marks it ⚠ —, virtual copy, copy name, in a stack), File (filename, extension, file path, type, format, video duration), Date (capture / import / edit), Keywords & People (keywords, keyword count, people on named faces, people count), Description (title, caption, alt text, creator, copyright, copyright status), Camera Info (camera, lens, focal length, aperture, shutter speed as 1/250, ISO), Location (any, city, state / province, country, GPS), Size (long / short edge, aspect ratio and megapixels, all of the photo as shown: oriented and cropped), Develop (has edits, cropped, treatment), Assisted Culling (focus, best of similar shots); text / number / date / in-the-last operators; live match count; also usable as a library filter (`ruleSet`). Missing vs Classic: develop preset, flash, exposure bias, camera serial, colour profile / bit depth, IPTC Job, smart-preview status. Choice values read as words in every language (Public Domain, Black & White; `album.ruleFields` gives `choiceLabels`), while rules store the ids; yes/no fields read Yes / No and take `true`/`false`, `"yes"`/`"no"`, `"true"`/`"false"` or 1/0. Every value is checked against its field (`RuleSet::check`): numbers (rating 0–5), shutter speeds, dates (`2026`, `2026-08`, `2026-08-14`, then `T10`, `T10:00` or `T10:00:00`, a space working as the `T`, and after whole seconds a fraction and a time zone as imported capture times carry them (`.250+02:00`); no 30 February; `rules::rule_date` is the one reading for the check and the matcher; each date field has a calendar picker, `crates/ui-egui/src/widgets/date_picker.rs`, that picks a year, a month or a day and keeps a "between" in order), between = two bounds in order, in the last = more than 0 of a known unit, choices (ids, the flag's picked / rejected, a colour label's custom name), text with something to look for, an existing album (plain or smart, not a folder), no empty groups; each problem names its rule (`rule 2.1: no rating 0–5 is 9`), and album.createSmart / setRules / library.filter refuse them. The editor marks each bad rule under its row (inside groups too), keeps OK disabled until they are fixed (and its confirm refuses them before renaming anything), picks an Album rule's album with an album picker (`crates/ui-egui/src/widgets/album_picker.rs`: the sidebar's tree with folders, or type part of a name or folder; ↑ / ↓ / Enter; albums that can't be picked shown greyed with the reason) (is / isn't; a folder can't be tested), and drawing it never changes a rule: a rating of 9, "in the last 0 days" or 20,000 days, a "between" that isn't a pair all stay as stored (and are marked where they can't match) until edited. Album rules saved with an old operator (≥, between) are read as the "isn't" they always meant (`RuleSet::upgrade`). Saved smart albums whose rules no longer check are marked ⚠ in the sidebar (tooltip: what to fix; `albums.list` `problems`, `Catalog::smart_album_problems`); the name and rules of an album are saved as one undo step (`album.setRules` `name`). Problems read as the field's name and the issue in the editor's language (“Titel: braucht einen Suchbegriff”; `Problem::issue` / `field`, `Issue::text`, translated in every locale), while commands keep the English `rule 2.1: …` message for agents | | LRC-LIB-PUBLISH | Publish services | P2 | ⬜ | | | @@ -963,3 +963,4 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove | 2026-10-23 | patch | LRC-LIB-FILTERBAR: showing an album (`library.source`) while the filter holds an album drops the filter's album, as showing a library folder already dropped its folder filter; before, the old album stayed in the filter unseen (the filter bar has no album chip) and narrowed the next source such as All Photos; the row's note says so; status unchanged (✅) | | 2026-10-27 | patch | MENU-EDIT-SELECTNONE, MENU-EDIT-PASTESELECTED: Select Only Active Photo and Paste Settings from Previous were not in the Edit menu's layout and ended up after Settings…, near the end of the menu; they now sit with the other Select and Paste rows. On macOS the Edit menu no longer shows two separators in a row where Settings… moved to the app menu; status unchanged (✅) | | 2026-10-27 | patch | MENU-FILE-CLOSE, KEY-CLOSEWINDOW: the notes say that Close Window and the red close button of the main window quit the app, after the check Quit makes; kept on purpose; a user page says so; status unchanged (✅) | +| 2026-10-24 | patch | LRC-LIB-LIBFOLDERS: Don't ask again in the Move Photos question is kept only when the move started, so a move that is refused no longer switches the question off; status unchanged (✅) | diff --git a/docs/whats-new.md b/docs/whats-new.md index 3dcbdee47..b1fe25141 100644 --- a/docs/whats-new.md +++ b/docs/whats-new.md @@ -13,6 +13,9 @@ ## 2026-10-24 +### A refused move no longer switches the Move Photos question off +- Ticking Don't ask again in the question that appears when you drop photos on a Folders row used to be remembered even when the move was then refused (for example because a file of the same name is already in that folder). The choice is now kept only once the move has started, so a refused move leaves the question on. + ### Relative-date filters and smart albums follow the clock - A current view or source count using “in the last” rules now refreshes when the session clock moves into a new minute, even when no catalog edit occurred. This fixes stale photos remaining in the grid and stale counts for