Let a collection be picked up, rearranged, and emptied after the fact

Collections could be made and filled and never reorganised. Nesting had
a drag; un-nesting had nothing, in either direction — "All photographs"
refused every drop, which is right for a photograph and wrong for a
collection, which has a top level to be returned to. So a collection put
inside another was in there permanently. Right-click deleted an *empty*
collection outright and refused otherwise, which is wrong in both
directions at once: destructive with no confirmation, and no way at all
to delete a collection that held anything without emptying it by hand,
child by child. And a photograph could only leave the collection the
grid was scoped to, since that is the only one a button in the header
can name — the cell's badge says a photograph is in three collections
and never which three.

Three ways in, one vocabulary:

**Hold a row.** The tree is inside a Flickable, which claims any drag
beginning inside it, so with a finger a drag on a row is a scroll until
something says otherwise. The hold is that something. It lifts the row —
drawn before anything moves, so the gesture says it has been understood
— and then what the user does decides which of two things they meant:
move, and it is a rearrangement; let go, and it is the row menu. The
same fork the grid already uses to tell hold-to-select from drag-to-file.
`decide_release` is that fork, and it is tested, because getting it
wrong one way puts a sheet over every tidied tree and the other way
makes the menu unreachable by touch.

**The row menu.** Rename, new collection inside, move to top level,
keep offline, delete. Deleting asks once when there is anything to lose
and says what survives: the photographs stay in the library, and nested
collections move up rather than going with it — which is what the
catalog does, and what a user would never assume. An empty collection
goes on the first press, because a dialogue about losing nothing is how
people learn to dismiss dialogues.

**"Collections…" on a selection.** Every collection the selection is
filed in, each with a count — "3 of 40", so nobody takes forty
photographs out of a collection thirty-seven were never in — and a way
out of any of them without navigating there first.

The long press used to open the offline question by itself. That
question is one item in this menu now: there is one hold per row, and
while it was spent on a single action nothing else the tree can do had
a touch route at all. Nothing is lost — the tray on the row keeps its
tap, and the question gains a full-width control in place of a 30px
icon in a row shorter than the touch minimum.

The row-press handler moves to `collections_ui` with the rest of what a
collection row does; it lived in `library_ui` only because it opened
that prompt.
This commit is contained in:
2026-09-07 19:59:44 +02:00
parent 577bbd82b0
commit 1e171c6d31
8 changed files with 1525 additions and 163 deletions
+35
View File
@@ -113,6 +113,34 @@ pub const GESTURES: &[Gesture] = &[
pointer: "Click the ring at the head of its row",
keys: "",
},
Gesture {
title: "Pick a collection up to rearrange the tree",
section: "Collections sidebar",
touch: "Press and hold it until it lifts, then drag it",
pointer: "Drag it, or hold it until it lifts and then drag",
keys: "",
},
Gesture {
title: "Act on a collection — rename, nest, un-nest, delete",
section: "Collections sidebar",
touch: "Press and hold the collection, then let go without moving",
pointer: "Right-click it",
keys: "",
},
Gesture {
title: "Take a collection back out of the one it is nested in",
section: "Collections sidebar",
touch: "Hold it, then drag it onto \"All photographs\" — or let go and choose \"Move to top level\"",
pointer: "Drag it onto \"All photographs\", or right-click it and choose \"Move to top level\"",
keys: "",
},
Gesture {
title: "Rename a collection",
section: "Collections sidebar",
touch: "Hold the collection, then \"Rename\"",
pointer: "Double-click its name, or right-click it and choose \"Rename\"",
keys: "",
},
Gesture {
title: "Pull a face out of the wrong person",
section: "People",
@@ -232,4 +260,11 @@ pub const GESTURES: &[Gesture] = &[
pointer: "While selecting, press \"Select all\"",
keys: "",
},
Gesture {
title: "Take photographs out of a collection",
section: "Library grid",
touch: "Select them, then \"Collections…\" in the selection bar",
pointer: "Select them, then \"Collections…\" in the selection bar",
keys: "",
},
];