From b1d36b914364f734748ac63cc81cd120d55125ed Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sat, 26 Sep 2026 08:02:51 -0400 Subject: [PATCH] Picture the duplicate originals review in the manual The manual described the review (7c9a4ee) without a picture, because the demo library holds no duplicates. The new duplicates scene makes two: it copies two New York frames into a bck folder beside their own, restarts the app so the scan finds them, waits for the sidebar row the sweep's dating brings (54aee50), opens the review from it, presses Check and takes the page. It deletes the copies and restarts on the library as it was; record.sh's snapshot restore would remove them too. It is registered last, so no other scene sees the copies. The picture shows both groups proved the same file, the camera-named copy outside bck marked Stays, and "Move 2 copies to trash" ready. --- docs/manual/README.md | 2 ++ docs/manual/index.html | 1 + docs/manual/media/duplicates.png | 3 ++ tools/manual/scenes.py | 62 ++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 docs/manual/media/duplicates.png diff --git a/docs/manual/README.md b/docs/manual/README.md index fb8e584..3a50876 100644 --- a/docs/manual/README.md +++ b/docs/manual/README.md @@ -145,6 +145,8 @@ flag or label the copies agree on, faces and the names on them, and the edit if only a copy had one. Where the copies disagree on a flag or a label, the one that stays keeps its own and the line says so. +![Two frames with a copy each in a bck folder, checked and proved the same, the copy that stays marked on each](media/duplicates.png) + `Move N copies to trash` does it, one group at a time: each group is merged and its spare copies moved together, or not at all. The copies go to the trash, not away — select them in the trash view and `Restore` puts them diff --git a/docs/manual/index.html b/docs/manual/index.html index 704157c..c6a5b5f 100644 --- a/docs/manual/index.html +++ b/docs/manual/index.html @@ -242,6 +242,7 @@ that stays will gain: the highest rating, every keyword and collection, a flag or label the copies agree on, faces and the names on them, and the edit if only a copy had one. Where the copies disagree on a flag or a label, the one that stays keeps its own and the line says so.

+
Two frames with a copy each in a bck folder, checked and proved the same, the copy that stays marked on each
Two frames with a copy each in a bck folder, checked and proved the same, the copy that stays marked on each

Move N copies to trash does it, one group at a time: each group is merged and its spare copies moved together, or not at all. The copies go to the trash, not away — select them in the trash view and Restore puts them diff --git a/docs/manual/media/duplicates.png b/docs/manual/media/duplicates.png new file mode 100644 index 0000000..3401462 --- /dev/null +++ b/docs/manual/media/duplicates.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25bfb3abb610ae0a1e6bacfb6d63efac9cb617a0b4c2bde9cb5cedc2ecac2750 +size 72110 diff --git a/tools/manual/scenes.py b/tools/manual/scenes.py index 49d7e9e..57dc200 100755 --- a/tools/manual/scenes.py +++ b/tools/manual/scenes.py @@ -34,6 +34,7 @@ import fnmatch import inspect import os import re +import shutil import subprocess import sys import tempfile @@ -1182,6 +1183,67 @@ def settings(): pause(1.5) +# --- duplicate originals --------------------------------------------------- +DUPLICATED = [NY_FIRST, '_MG_8394'] # copied into a `bck` folder beside their own + + +def library_file(name): + """The path of file `name` in the demo library.""" + for root, _, files in os.walk(DEMO_LIBRARY): + if name in files: + return os.path.join(root, name) + raise FileNotFoundError(f'{name} is not in {DEMO_LIBRARY}') + + +@scene(media=['duplicates.png'], + sources=LIBRARY_SRC + ['ui/dr-ui/ui/duplicates.slint', 'ui/dr-ui/src/duplicates_ui.rs', + 'ui/dr-ui/src/duplicates.rs', 'core/dr-catalog/src/duplicates.rs']) +def duplicates(): + """The demo library holds no duplicates, so this makes two: copies of two + New York frames in a `bck` folder beside theirs, the way a hand-kept + backup sits. The app is restarted so its scan finds them, and the row + under the trash appears once the sweep has read their capture times. The + review is opened from there and checked, and the copies are deleted again + before the app is restarted on the library as it was. (The snapshot + record.sh restores would remove them too.)""" + made = [] + try: + for name in DUPLICATED: + src = library_file(f'{name}.CR2') + folder = os.path.join(os.path.dirname(src), 'bck') + os.makedirs(folder, exist_ok=True) + made.append(os.path.join(folder, f'{name}.CR2')) + shutil.copy2(src, made[-1]) + dr.stop() + dr.launch([]) + dr.wait_ready() + dr.wait_for('id:grid-scroll', 60) + dr.wait_for('Duplicate originals@Text', 300) + pause(1) + dr.click_on('Duplicate originals@Text') + dr.wait_for(f'Check {len(DUPLICATED)} groups@Button', 30) + pause(1) + dr.click_on(f'Check {len(DUPLICATED)} groups@Button') + dr.wait_gone(f'Check {len(DUPLICATED)} groups@Button', 60) + pause(3) + shot('duplicates') + dr.click_on('‹ Back@Button') + pause(1) + finally: + for f in made: + if os.path.exists(f): + os.remove(f) + for f in made: + d = os.path.dirname(f) + if os.path.isdir(d) and not os.listdir(d): + os.rmdir(d) + dr.stop() + dr.launch([]) + dr.wait_ready() + dr.wait_for('id:grid-scroll', 60) + pause(3) + + # --- running them ----------------------------------------------------------- def order(names): """`names` with their prerequisites, each once, prerequisites first."""