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. + + `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.
+
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."""