Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
41 lines
2.7 KiB
Plaintext
41 lines
2.7 KiB
Plaintext
android: the rows go where you put them — a real drag on the playlist and the queue
|
|
|
|
The phone stood in for the desktop's drag with Move up / Move down / Move to
|
|
the top on a row's sheet, which is fine but is not what a finger is for. Press
|
|
and hold a row for 320ms now and it lifts, the rows below make room, and
|
|
letting go lands it — on the playlist page and on the player sheet's queue,
|
|
through one action in src/mobile/reorder.js. The Move rows stay: they are the
|
|
accessible path round 28 named to a screen reader, and they are the only way
|
|
to reorder while the filter is on. Release a press without having moved it and
|
|
the row's sheet opens exactly as a long press always opened it, which is what
|
|
keeps the queue's sheet reachable at all — a queue row has no ⋯, so
|
|
`oncontextmenu` is its only door to Play now, Move to next and Remove from
|
|
queue.
|
|
|
|
Most of the work is in not fighting the page. Nothing carries
|
|
`touch-action: none`, because a flick that starts on a row is how the list is
|
|
scrolled and `touch-action` is latched at touchstart anyway; the scroll is
|
|
refused instead by a non-passive `touchmove` listener added at the lift, which
|
|
works precisely because the finger has been still for 320ms and the browser
|
|
has not started one. A press that moves more than 8px before then is a scroll
|
|
and the gesture lets go of it. Click and contextmenu guards sit on the
|
|
container in the capture phase while a lift is live, or a released drag would
|
|
fire the row's own click and play the track. Rows are measured once at the
|
|
lift in the scroller's content space, so the edge pull — within 64px of either
|
|
edge — leaves the snapshot true, and each displaced row moves by the exact
|
|
difference between its top and its neighbour's rather than by one assumed row
|
|
height, because the queue face puts album separators between rows.
|
|
|
|
No new mutation and no new command: `moveItem` and `moveInQueue` each take a
|
|
numeric target now as well as "up" / "down" / "top", so there is still exactly
|
|
one call to `playlist_set_order` carrying the whole id order, and the existing
|
|
queue guards were already the right guards. The drop is optimistic and snaps
|
|
back with the error toast if the backend says no. Two refusals cover the
|
|
middle of a gesture — the playlist drops nothing if a refetch has replaced its
|
|
rows, and the queue drops nothing if `player.qi` has moved — and dragging is
|
|
off entirely while the playlist's filter has anything in it, because a
|
|
filtered list's visible order is not the stored order. Both walks drive it
|
|
with real pointer events and assert the order out of the store: a drag, a drag
|
|
back, a refusal under the filter, a press that still opens the sheet, and a
|
|
drop the backend is armed to reject.
|