Put the two collection actions in the collections panel
"Keep offline" and "Change library" were buttons in the library header, in a row that is otherwise entirely library-wide. Both refer to the tree instead. "Keep offline" could only ever mean the scoped collection, while sitting nowhere near the tree that says which that is — and while the sidebar already offered the same question twice, on each row's tray and on a held row. It now sits under the tree, in the panel whose selection decides what it acts on, in the same place and shape the trash already gives Restore and Empty. It stays a labelled control rather than being dropped for the tray: a 26px row's tray is a small thing to hit, and "Kept offline" spelt out for the collection you are looking at is the discoverable version. "Change library" was wedged between Sync and Rescan, two buttons that act on the library you already have. Reading it as one of that group is a way to lose a scan by aiming badly. It is now the last thing in the panel, under the tree it replaces wholesale, behind a rule. On a tablet both are one tap further away, behind the sidebar toggle that leads the header. That is the panel a user is already in when they scope the grid to a collection, so it is where they are when either of these becomes the thing they want. The grid keeps `pin-done`/`pin-total` and its progress bar: the transfer is worth reporting wherever it was started from, including a row the grid is not scoped to. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+11
-11
@@ -54,7 +54,7 @@ The right match confidence is a property of your library, not of the model. "Wha
|
||||
|
||||
Touch has no ctrl, so without a mode there is no way to select a second photograph — the first tap would open it. The hold is the fast way in and the button is the one that can be found.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:1208`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:1182`</sub>
|
||||
|
||||
### Add or remove one photograph
|
||||
|
||||
@@ -63,7 +63,7 @@ Touch has no ctrl, so without a mode there is no way to select a second photogra
|
||||
|
||||
While selecting, a tap never opens. That is the whole point of the mode: one meaning per gesture at a time. Press Done to get tap-to-open back.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:1217`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:1191`</sub>
|
||||
|
||||
### Leave selecting
|
||||
|
||||
@@ -71,7 +71,7 @@ While selecting, a tap never opens. That is the whole point of the mode: one mea
|
||||
- **Pointer** — Press Done in the header
|
||||
- **Keyboard** — Escape
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:1225`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:1199`</sub>
|
||||
|
||||
### Select a range
|
||||
|
||||
@@ -80,7 +80,7 @@ While selecting, a tap never opens. That is the whole point of the mode: one mea
|
||||
|
||||
This replaced a double tap, which had no visible state and could take forty photographs by accident. The run is resolved by the catalog rather than by what is on screen, so the grid can scroll between the two taps — the ranges that hurt on a tablet are longer than a screenful, which is exactly where a finger sweep runs out.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:1286`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:1260`</sub>
|
||||
|
||||
### Find photographs with two people in them
|
||||
|
||||
@@ -89,7 +89,7 @@ This replaced a double tap, which had no visible state and could take forty phot
|
||||
|
||||
"Any of them" is a union and "all of them" is an intersection. The tray is where both terms and the choice between them live, because a filter belongs on the filter bar.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:1933`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:1902`</sub>
|
||||
|
||||
### Resize the thumbnails
|
||||
|
||||
@@ -98,7 +98,7 @@ This replaced a double tap, which had no visible state and could take forty phot
|
||||
|
||||
There is no wheel on a tablet, so without the pinch the cell size could only be changed by a control a finger cannot reach.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:2559`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:2528`</sub>
|
||||
|
||||
### File photographs in a collection
|
||||
|
||||
@@ -107,7 +107,7 @@ There is no wheel on a tablet, so without the pinch the cell size could only be
|
||||
|
||||
The selection is what the drag carries, which is why selecting several is worth the mode: forty photographs file in one gesture.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:2722`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:2691`</sub>
|
||||
|
||||
### Open a photograph
|
||||
|
||||
@@ -116,7 +116,7 @@ The selection is what the drag carries, which is why selecting several is worth
|
||||
|
||||
A tap opens; a tap that *moved* does not. Travel is what separates a deliberate tap from a hand brushing past, and it is the only thing that does: the two are the same length. An earlier version required the finger to dwell 120 ms instead, and that rejected ordinary taps — a real tap is often quicker than a brush.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:2977`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:2946`</sub>
|
||||
|
||||
### Rate a photograph without opening it
|
||||
|
||||
@@ -126,7 +126,7 @@ A tap opens; a tap that *moved* does not. Travel is what separates a deliberate
|
||||
|
||||
A star has to take the press without it also reaching the cell, or every rating throws the user into develop.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:3089`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:3058`</sub>
|
||||
|
||||
### Drop the selection but keep selecting
|
||||
|
||||
@@ -135,7 +135,7 @@ A star has to take the press without it also reaching the cell, or every rating
|
||||
|
||||
Distinct from Done, which leaves the mode entirely. Clearing keeps it, so the next selection can start straight away.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:3744`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:3713`</sub>
|
||||
|
||||
### Select everything the grid is showing
|
||||
|
||||
@@ -144,4 +144,4 @@ Distinct from Done, which leaves the mode entirely. Clearing keeps it, so the ne
|
||||
|
||||
A scoped grid of two hundred frames is two hundred taps otherwise, and "all of them, except those three" is a far more common shape than the taps it took to say it.
|
||||
|
||||
<sub>`ui/dr-ui/ui/library.slint:3761`</sub>
|
||||
<sub>`ui/dr-ui/ui/library.slint:3730`</sub>
|
||||
|
||||
+20
-20
File diff suppressed because one or more lines are too long
+10
-3
@@ -1437,6 +1437,16 @@ in property <bool> panel-visible: true;
|
||||
total-images: root.library-total;
|
||||
error: root.collection-error;
|
||||
|
||||
// TRACES: FR-NC-6a
|
||||
// The two actions that were in the library header and
|
||||
// referred to the tree rather than to the library.
|
||||
// They read the same window state the header did — one
|
||||
// source per fact — and call the same handlers.
|
||||
scanning: root.library-scanning;
|
||||
scope-pinned: root.library-scope-pinned;
|
||||
toggle-pin-scope() => { root.library-toggle-pin-scope(); }
|
||||
change-library() => { root.library-change(); }
|
||||
|
||||
select(id) => { root.collection-select(id); }
|
||||
toggle(id) => { root.collection-toggle(id); }
|
||||
new-collection() => { root.collection-new(); }
|
||||
@@ -1505,10 +1515,8 @@ in property <bool> panel-visible: true;
|
||||
collections-visible: root.collections-visible;
|
||||
toggle-collections() => { root.toggle-collections(); }
|
||||
|
||||
scope-pinned: root.library-scope-pinned;
|
||||
pin-done: root.library-pin-done;
|
||||
pin-total: root.library-pin-total;
|
||||
toggle-pin-scope() => { root.library-toggle-pin-scope(); }
|
||||
root-label: root.library-root-label;
|
||||
timeline: root.library-timeline;
|
||||
timeline-label: root.library-timeline-label;
|
||||
@@ -1566,7 +1574,6 @@ in property <bool> panel-visible: true;
|
||||
viewport-cells-changed(n) => { root.library-viewport-cells(n); }
|
||||
cell-clicked(i) => { root.library-cell-clicked(i); }
|
||||
rescan() => { root.library-rescan(); }
|
||||
change-library() => { root.library-change(); }
|
||||
can-import: root.import-supported;
|
||||
open-import() => { root.import-open(); }
|
||||
open-settings() => { root.settings-open(); }
|
||||
|
||||
@@ -349,6 +349,32 @@ export component CollectionsPanel inherits Rectangle {
|
||||
in property <int> selected-id: 0;
|
||||
in property <int> total-images: 0;
|
||||
in property <string> error: "";
|
||||
/// Whether a scan is running, which is when neither of the two actions at
|
||||
/// the foot of this panel can be honoured: pinning walks a collection the
|
||||
/// scan is still writing, and changing library pulls the catalog out from
|
||||
/// under it.
|
||||
in property <bool> scanning: false;
|
||||
|
||||
// --- what to do with the collection this panel has scoped --------------
|
||||
//
|
||||
// TRACES: FR-NC-6a
|
||||
// These two used to be buttons in the library header, where they were the
|
||||
// only things in a row of library-wide actions that referred to *one
|
||||
// collection* — and where "Keep offline" could only ever mean the scoped
|
||||
// one while sitting nowhere near the tree that says which that is.
|
||||
//
|
||||
// Here they are under the tree, in the panel whose selection decides what
|
||||
// they act on, and in the same place and shape the trash already puts its
|
||||
// own two. The header keeps only what belongs to the whole library.
|
||||
/// TRACES: FR-NC-6a
|
||||
/// Whether the scoped collection is being kept on this device.
|
||||
in property <bool> scope-pinned: false;
|
||||
/// TRACES: FR-NC-6a
|
||||
/// Ask about the scoped collection's local copies — the same question the
|
||||
/// tray on a row and a held row open.
|
||||
callback toggle-pin-scope();
|
||||
/// Open a different library altogether.
|
||||
callback change-library();
|
||||
|
||||
callback select(int);
|
||||
callback toggle(int);
|
||||
@@ -567,6 +593,29 @@ export component CollectionsPanel inherits Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// TRACES: FR-NC-6a
|
||||
// Keep the scoped collection on this device.
|
||||
//
|
||||
// Only while one is scoped: "pin the whole library" is a different and
|
||||
// much more expensive request, and a button that meant either
|
||||
// depending on invisible state would be a trap. Ids at or below zero
|
||||
// are "All photographs" and the trash, neither of which is a
|
||||
// collection to pin.
|
||||
//
|
||||
// No tick on the kept label: `active` already inverts the button,
|
||||
// which says the same thing without a symbol inside a string.
|
||||
//
|
||||
// It opens the same question the tray on a row and a held row open,
|
||||
// rather than pinning outright — see the note on the callback in
|
||||
// `library_ui::wire`. This is the version with a word on it, for the
|
||||
// collection the grid is actually showing.
|
||||
if root.selected-id > 0: Button {
|
||||
text: root.scope-pinned ? "Kept offline" : "Keep offline";
|
||||
active: root.scope-pinned;
|
||||
enabled: !root.scanning;
|
||||
clicked => { root.toggle-pin-scope(); }
|
||||
}
|
||||
|
||||
// --- trash --------------------------------------------------------
|
||||
//
|
||||
// TRACES: FR-CAT-15
|
||||
@@ -669,6 +718,22 @@ export component CollectionsPanel inherits Rectangle {
|
||||
font-size: Theme.text-sm;
|
||||
wrap: word-wrap;
|
||||
}
|
||||
|
||||
// The foot of the panel, under everything the current library holds,
|
||||
// because it is the one control here that replaces all of it.
|
||||
//
|
||||
// It was in the library header, wedged between Sync and Rescan — two
|
||||
// buttons that act on the library you already have. Reading "Change
|
||||
// library" as one of that group is a way to lose a scan by aiming
|
||||
// badly. Down here it is the last thing in the panel and the only
|
||||
// thing below the tree it would replace.
|
||||
Rectangle { height: 1px; background: Theme.rule; }
|
||||
|
||||
Button {
|
||||
text: "Change library";
|
||||
enabled: !root.scanning;
|
||||
clicked => { root.change-library(); }
|
||||
}
|
||||
}
|
||||
|
||||
// Right edge, separating the panel from the grid.
|
||||
|
||||
+14
-45
@@ -845,8 +845,12 @@ export component FlagMark inherits Rectangle {
|
||||
// moment a hand was already travelling toward one — and splitting "what can I
|
||||
// do with these?" across two bars at opposite ends of the window. A row that
|
||||
// only changes when the *library* changes can be aimed at from memory.
|
||||
//
|
||||
// Nor does anything in here refer to *one collection*. "Keep offline" and
|
||||
// "Change library" are in the collections panel, under the tree whose
|
||||
// selection decides what the first of them acts on and which the second
|
||||
// replaces wholesale.
|
||||
component HeaderActions inherits HorizontalLayout {
|
||||
in property <string> scope-label;
|
||||
/// TRACES: FR-UI-2 | FR-UI-4
|
||||
/// Whether taps are selecting rather than opening. The non-gesture half of
|
||||
/// touch multi-selection: the long press is the quick way in, and this is
|
||||
@@ -854,15 +858,12 @@ component HeaderActions inherits HorizontalLayout {
|
||||
in property <bool> select-mode: false;
|
||||
in property <bool> scanning: false;
|
||||
in property <bool> syncing: false;
|
||||
in property <bool> scope-pinned: false;
|
||||
/// Centres each button in a 44px header. Off in the disclosure row, which
|
||||
/// is sized to its content.
|
||||
in property <bool> centred: true;
|
||||
in property <length> row-height: 44px;
|
||||
|
||||
callback toggle-select-mode();
|
||||
callback change-library();
|
||||
callback toggle-pin-scope();
|
||||
callback sync-now();
|
||||
/// TRACES: FR-CAT-10
|
||||
/// Whether this platform can reach a card at all (`dr_plat::imports_supported`).
|
||||
@@ -903,31 +904,6 @@ component HeaderActions inherits HorizontalLayout {
|
||||
clicked => { root.toggle-select-mode(); }
|
||||
}
|
||||
|
||||
if !root.scanning: Button {
|
||||
text: "Change library";
|
||||
y: root.centred ? (root.row-height - self.height) / 2 : 0;
|
||||
clicked => { root.change-library(); }
|
||||
}
|
||||
|
||||
// TRACES: FR-NC-6a
|
||||
// Keep this collection offline. Only offered when the grid is scoped to
|
||||
// one: "pin the whole library" is a different and much more expensive
|
||||
// request, and a button that meant either depending on invisible state
|
||||
// would be a trap.
|
||||
if root.scope-label != "": Button {
|
||||
// No tick on the kept label: `active` already inverts the button,
|
||||
// which says the same thing without a symbol inside a string.
|
||||
//
|
||||
// It opens the same question the sidebar's tray and a held row open,
|
||||
// rather than pinning outright — see the note on the callback in
|
||||
// `library_ui::wire`.
|
||||
text: root.scope-pinned ? "Kept offline" : "Keep offline";
|
||||
active: root.scope-pinned;
|
||||
enabled: !root.scanning;
|
||||
y: root.centred ? (root.row-height - self.height) / 2 : 0;
|
||||
clicked => { root.toggle-pin-scope(); }
|
||||
}
|
||||
|
||||
Button {
|
||||
// Shares the finished index so a second device inherits it rather
|
||||
// than repeating hours of range fetches.
|
||||
@@ -1154,8 +1130,6 @@ export component LibraryGrid inherits Rectangle {
|
||||
callback toggle-collections();
|
||||
|
||||
callback rescan();
|
||||
/// Back to the launch screen, to change library or account.
|
||||
callback change-library();
|
||||
/// Open the settings page.
|
||||
/// TRACES: FR-CAT-10
|
||||
/// Whether this platform can import at all. Forwarded to the header, which
|
||||
@@ -1384,14 +1358,17 @@ export component LibraryGrid inherits Rectangle {
|
||||
|
||||
// --- pinning (FR-NC-6a) -----------------------------------------------
|
||||
//
|
||||
// Whether the collection the grid is scoped to is kept offline, and how
|
||||
// far the download has got. Progress is shown because pinning a trip is
|
||||
// gigabytes of transfer — a button that appeared to do nothing for twenty
|
||||
// minutes would read as broken.
|
||||
in property <bool> scope-pinned: false;
|
||||
// How far the download has got. Progress is shown because pinning a trip
|
||||
// is gigabytes of transfer — a button that appeared to do nothing for
|
||||
// twenty minutes would read as broken.
|
||||
//
|
||||
// Only the progress. Asking for the pin, and saying whether the scoped
|
||||
// collection already has one, belong to the collections panel — the tree
|
||||
// is what decides which collection is meant. This bar reports on the
|
||||
// transfer wherever it was started, including from a row this grid is not
|
||||
// scoped to, which is why it is not gated on the scope.
|
||||
in property <int> pin-done: 0;
|
||||
in property <int> pin-total: 0;
|
||||
callback toggle-pin-scope();
|
||||
/// Narrow to images whose RAW is stored locally — the ones openable now.
|
||||
in property <bool> local-only: false;
|
||||
in property <int> local-count: 0;
|
||||
@@ -1768,15 +1745,11 @@ export component LibraryGrid inherits Rectangle {
|
||||
// is room, and a disclosure would be a click in front of a
|
||||
// button that was already visible.
|
||||
if root.expanded: HeaderActions {
|
||||
scope-label: root.scope-label;
|
||||
scanning: root.scanning;
|
||||
syncing: root.syncing;
|
||||
scope-pinned: root.scope-pinned;
|
||||
can-import: root.can-import;
|
||||
select-mode: root.select-mode;
|
||||
toggle-select-mode => { root.toggle-select-mode(); }
|
||||
change-library => { root.change-library(); }
|
||||
toggle-pin-scope => { root.toggle-pin-scope(); }
|
||||
sync-now => { root.sync-now(); }
|
||||
rescan => { root.rescan(); }
|
||||
open-import => { root.open-import(); }
|
||||
@@ -1828,15 +1801,11 @@ export component LibraryGrid inherits Rectangle {
|
||||
|
||||
HeaderActions {
|
||||
centred: true;
|
||||
scope-label: root.scope-label;
|
||||
scanning: root.scanning;
|
||||
syncing: root.syncing;
|
||||
scope-pinned: root.scope-pinned;
|
||||
can-import: root.can-import;
|
||||
select-mode: root.select-mode;
|
||||
toggle-select-mode => { root.toggle-select-mode(); }
|
||||
change-library => { root.change-library(); }
|
||||
toggle-pin-scope => { root.toggle-pin-scope(); }
|
||||
sync-now => { root.sync-now(); }
|
||||
rescan => { root.rescan(); }
|
||||
open-import => { root.open-import(); }
|
||||
|
||||
Reference in New Issue
Block a user