Re-record the manual for 0.17.0, with albums and the new preset sheet

Every scene is recorded again on the 0.17.0 build, because the header
(Export to Exports), the sidebar (Albums) and the develop column had
all moved. The launch pictures showed the typed folder field, and the
export settings "Export to"; the presets picture predated the sections.

New scenes: presets_film scrolls the sheet down through the shipped
sections and applies Ilford HP5 Plus, a look that changes the film and
nothing else; albums exports four New York frames to an album, selects
it to show the originals behind its files, and opens a new album's
sheet before deleting what it made. record.sh now points the profile's
old export folder at DR_HOME/Exports, which the app turns into the
album "Exports" on first open - the one way to have an album without
the portal's dialogue, which Xvfb cannot show. The launch scene signs
out of a remembered folder instead of typing one, so it shows
"Open folder" beside the folder used last.

Not recorded: the server browser's New folder, which needs a Nextcloud
server, and the download screen, which a folder library never reaches
(the original is a local read, over before the first poll). The manual
says so where it describes each. film_reach and duplicates passed;
inference was pinned to the CPU.
This commit is contained in:
2026-09-26 15:15:51 -04:00
parent 9f95d23ff4
commit 7428f6f845
40 changed files with 300 additions and 101 deletions
+148 -13
View File
@@ -390,24 +390,40 @@ def reset_adjust():
sources=COMMON + ['ui/dr-ui/ui/launch.slint', 'ui/dr-ui/src/launch_ui.rs',
'ui/dr-ui/src/launch.rs'])
def launch():
"""The launch screen belongs to a profile with no library, so this one
is its own: the app is restarted on an empty profile beside the real
one, shown the demo folder, and put back."""
empty = f'{dr.HOME}/launch-xdg'
subprocess.run(['rm', '-rf', empty], check=True)
os.makedirs(f'{empty}/config/darkroom', exist_ok=True)
"""The launch screen belongs to a profile that has not opened a library,
so this one is its own: the app is restarted on a profile beside the
real one that knows the demo folder, taken back to the launch screen by
`Change library`, and signed out of the folder — which leaves it on the
screen with `Open folder` beside it, as someone returning sees it. The
folder is never chosen with `Choose another…`: that is the desktop
portal's dialogue, not the app's to draw, and it does not open on a
private X server."""
other = f'{dr.HOME}/launch-xdg'
subprocess.run(['rm', '-rf', other], check=True)
os.makedirs(f'{other}/config/darkroom', exist_ok=True)
with open(f'{other}/config/darkroom/sessions.json', 'w') as f:
# The formats a first open saves — the RAWs, not JPEG — rather than
# none, which would scan (and tick) everything.
f.write('{ "version": 0, "sessions": [ { "backend": "folder", "server": "%s",'
' "login": "", "user_id": "", "root": "", "root_chosen": true,'
' "formats": ["cr2", "cr3", "nef", "arw", "raf", "rw2", "orf", "dng"],'
' "last_scan": null } ] }'
% (DEMO_LIBRARY or '/var/tmp/dr-demo/library'))
dr.stop()
dr.launch([], xdg=empty)
dr.launch([], xdg=other)
dr.wait_ready()
dr.wait_for('Open folder@Button', 30)
pause(1)
shot('launch')
dr.click_on('Library folder@TextInput')
type_text(DEMO_LIBRARY or '/var/tmp/dr-demo/library')
dr.click_on('Open folder@Button')
dr.wait_for('id:grid-scroll', 60)
pause(3)
dr.click_on('Change library@Button')
dr.wait_for('Open library@Button', 30)
dr.move(10, 10)
pause(1)
shot('launch-folder')
dr.click_on('Sign out@Button')
dr.wait_for('Open folder@Button', 30)
dr.move(10, 10)
pause(1)
shot('launch')
dr.stop()
dr.launch([])
dr.wait_ready()
@@ -1084,6 +1100,39 @@ def presets():
pause(1.0)
@scene(media=['presets-film.gif'],
sources=DEVELOP_SRC + ['ui/dr-ui/ui/presets.slint', 'ui/dr-ui/src/presets.rs',
'core/dr-pipeline/presets/*.drpl', 'core/dr-pipeline/src/bundled.rs'])
def presets_film():
"""The sheet scrolled from Essentials down through the shipped film
sections, and a black-and-white stock applied from the last of them —
a look, so the sheet closes on the photograph with its film changed and
nothing else — then Before held."""
at_develop()
rec('presets-film')
pause(0.4)
dr.click_on('Presets…@Button')
dr.wait_for('CARRIES@Text', 5)
pause(1.5)
x, y = dr.centre('Crisp detail@Button')
for _ in range(80): # a notch at a time, so the film shows the sections pass
if dr.present(f'{PRESET_BW}@Button'):
break
wheel(1, x, y)
pause(0.3)
pause(1.0)
dr.click_on(f'{PRESET_BW}@Button')
dr.wait_gone('CARRIES@Text', 5)
pause(4)
hold_before(1.4)
pause(0.8)
cut()
undo_all()
PRESET_BW = 'Ilford HP5 Plus' # a shipped look in the black-and-white film section
# --- panorama ---------------------------------------------------------------
def wait_for_new(folder, suffix, since, timeout):
"""Until a file ending in `suffix` newer than `since` appears in
@@ -1183,6 +1232,92 @@ def settings():
pause(1.5)
# --- albums -----------------------------------------------------------------
ALBUM = 'Exports' # made by the app from the export folder record.sh sets
def album_row(name):
"""The sidebar row for album `name`: its label is the name and where its
files go, "Exports, On this device · …"."""
for e in dr.ask(f'labels {name}, '):
if e['role'] == 'Button' and e['label'].startswith(f'{name}, '):
return int(e['x'] + e['w'] / 2), int(e['y'] + e['h'] / 2)
raise dr.NotFound(f'no album row for {name}')
def export_button():
"""The selection bar's export button, whose label names the count and
the album: "Export 5 to Exports"."""
for e in dr.ask('labels Export '):
if e['role'] == 'Button' and e['label'].startswith('Export ') and ' to ' in e['label']:
return int(e['x'] + e['w'] / 2), int(e['y'] + e['h'] / 2)
raise dr.NotFound('no export button naming an album')
@scene(media=['albums.gif', 'albums.png', 'album-sheet.png'],
sources=LIBRARY_SRC + ['ui/dr-ui/ui/albums.slint', 'ui/dr-ui/src/albums_ui.rs',
'ui/dr-ui/ui/export.slint', 'ui/dr-ui/src/export.rs'])
def albums():
"""The New York frames exported to the album the profile's old export
folder became, then the album chosen in the sidebar: the grid shows the
originals behind its files. Then the sheet `+` opens, with a name typed
and no folder yet — its `Choose folder…` is the desktop portal's
dialogue, which does not open on a private X server. The files exported
are deleted again, and the album with them."""
folder = os.environ.get('DR_EXPORT_DIR', '')
before = set(os.listdir(folder)) if os.path.isdir(folder) else set()
try:
at_library()
grid_top()
album_row(ALBUM)
rec('albums-a')
pause(0.5)
start_selecting()
dr.click(*cell(NY_FIRST))
pause(0.3)
with_key('shift', dr.click, *cell(NY_LAST))
pause(1.0)
dr.click(*export_button())
pause(3)
cut()
try: # a short batch can be over before this looks
dr.wait_for('Cancel export@Button', 5)
except Exception:
pass
dr.wait_gone('Cancel export@Button', 300)
pause(1)
stop_selecting()
rec('albums-b')
pause(0.5)
dr.click(*album_row(ALBUM))
pause(2.5)
cut()
join('albums', ['albums-a', 'albums-b'])
dr.move(*album_row(ALBUM))
pause(1)
shot('albums')
dr.click_on('New album@Button')
dr.wait_for('Make album@Button', 5)
pause(0.6)
type_text('Prints')
pause(1)
shot('album-sheet')
dr.click_on('Cancel@Button#-1')
pause(0.8)
dr.click_on(f'Edit {ALBUM}@Button')
dr.wait_for('Delete…@Button', 5)
dr.click_on('Delete…@Button')
dr.wait_for('Delete album@Button', 5)
dr.click_on('Delete album@Button')
pause(1)
dr.click_on('All photographs@Text')
pause(1.2)
finally:
if folder and os.path.isdir(folder):
for f in set(os.listdir(folder)) - before:
os.remove(os.path.join(folder, f))
# --- duplicate originals ---------------------------------------------------
DUPLICATED = [NY_FIRST, '_MG_8394'] # copied into a `bck` folder beside their own