Say what the application is doing, in one bar and one list

Every background job reported into a window property of its own —
library-thumbs-done, library-pin-total, library-syncing — which only the
grid ever read. A pin download that outlived the view it was started from
drew nothing at all once the user opened an image, and there was no answer
anywhere to "what is this busy with", because the answer was spread across
eight properties nothing collected.

They report to one register now (ui/dr-ui/src/activity.rs). It publishes an
aggregate, which draws a three-pixel bar across the top of the shell in
every view, and a row per job, which the settings page lists: scans,
thumbnail batches, pin and open downloads, sidecar uploads, the sync and
the trash. Failures stay on the list until they are cleared; routine
successes do not, or a scroll would bury them.

The handle removes a still-running job when it drops, so a worker that dies
mid-transfer takes its row with it rather than leaving the bar sweeping for
the rest of the session.

Also carries in-flight work from a parallel session — the drawn icon set
and the dr-pipeline ops split. dr-pipeline's build script does not compile
at this commit; ui/dr-ui does, with clippy clean and its tests passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 18:32:09 +02:00
co-authored by Claude Opus 5
parent 70435b712e
commit 65e6a96a65
27 changed files with 3873 additions and 236 deletions
+57
View File
@@ -0,0 +1,57 @@
# TRACES: FR-DEV-3a | FR-DEV-3c
id: exposure
label: op.exposure
order: 20
doc: |
Exposure — a linear gain, expressed in stops.
The simplest operation in the pipeline and the one that most justifies
working in linear light: a stop is a doubling, so exposure is a single
multiply. Applied to gamma-encoded data it would be neither a doubling nor
reversible, which is why this stage sits where it does (ARCH §5.2).
placement: |
A correction to how the scene was captured, so it precedes every operation
that interprets tone.
params:
exposure:
label: param.exposure
kind: stops
min: -5
max: 5
doc: |
±5 stops. Wider than most edits need, but recovering a badly
underexposed frame is a real use and raw data often supports it.
uniforms:
gain:
value: exp2(exposure)
doc: The linear gain for the current setting.
wgsl: |
c = c * gain;
tests:
- name: one_stop_is_a_doubling
why: |
The definition of a stop. If this is wrong, every exposure adjustment is
subtly off and no test of "looks right" would catch it.
set: { exposure: 1 }
expect: { gain: 2.0 }
- name: one_stop_down_is_a_halving
set: { exposure: -1 }
expect: { gain: 0.5 }
- name: stops_compose_additively
why: +2 stops must equal +1 applied twice.
set: { exposure: 2 }
expect: { gain: 4.0 }
- name: neutral_is_unity_gain
why: |
An unedited image must be the image, not an interpretation of it.
expect: { gain: 1.0 }
expect_active: false