feat(android): the touch model reaches the other three lists
Plan 019 phases 3 and 4, which finish #63. The queue panel and both playlist detail views get tap-to-play and hold-to-select; the playlist views get swipe-to-queue as well. Phase 3 was not the pure wiring the plan expected, in two places. A tap on a queue row plays that position. Copying track-list's tap -- which sets the queue to the list the row is in -- would rebuild the queue from the queue, discarding its source, its shuffle order and anything inserted by hand. It reads as a no-op and is not one. And the queue panel has no swipe, deliberately. A right swipe means add to the queue everywhere else it exists, and a queue row is already in the queue; the only thing it could mean there is remove, which is the same gesture with the opposite effect one screen away. Removing a queue row is on the row, on its sheet since #60, and now on its selection bar. The assertion is that its rows do not opt in. The reveal became utils/swipe-to-queue.ts rather than being copied into three lists, keyed on a data-swipe attribute so one stylesheet carries the touch-action half of the device fix to rows that are called two different things. Phase 4 was already true and is now asserted: a claimed tap has its click swallowed, so an explore-link inside a row never sees one and tap-to-play wins with no rule of its own. Its test was vacuous when written -- the tap helper sent no click, so there was nothing to swallow -- which also weakened phase 1's. It sends one now. Escape leaves selection mode, from selection-bar rather than from each of the four hosts, since that element exists only while the mode does. The platform's back gesture deliberately does not reach it: the shell owns the history stack and four lists reaching for history is four stacks. That is #200. Verified on the reference phone: a queue row taps to its own index and refuses a swipe, a playlist row queues on a swipe and plays its playlist on a tap, and a hold raises the bar without the menu. Closes #63
This commit is contained in:
@@ -39,6 +39,11 @@ import { ICON_MORE_ACTIONS } from '@utils/icon-language';
|
||||
* region: the number changes under the user's finger as they tap rows,
|
||||
* and nothing else on screen announces it.
|
||||
*
|
||||
* **Escape leaves the mode, from here rather than from each host.**
|
||||
* This element exists only while the mode does, so it is the one place
|
||||
* a dismissal can be attached and detached with the thing it
|
||||
* dismisses. It is the same exception the overlaid queue's Escape is.
|
||||
*
|
||||
* **It renders nothing at zero.** The mode ends when the last row is
|
||||
* deselected — `SelectionController.toggleInMode` is where that is
|
||||
* decided — so a bar with a count of none is a state this should never
|
||||
@@ -120,6 +125,43 @@ export class SelectionBar extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape leaves the mode.
|
||||
*
|
||||
* A mode changes what a tap means, so it has to have an exit that
|
||||
* is not "find the ×" -- and this is the documented exception to
|
||||
* the app's one-keyboard-authority rule, on exactly the grounds
|
||||
* the overlaid queue's Escape is: **it is a dismissal, not a
|
||||
* shortcut**, so it is not a panel-scoped binding and it is
|
||||
* attached only while there is something to dismiss. Putting it
|
||||
* here rather than in each host is what gives all four surfaces
|
||||
* the same answer, since this element exists only while the mode
|
||||
* does.
|
||||
*
|
||||
* The platform's own back gesture is the other half of that and is
|
||||
* deliberately *not* here: the shell owns the history stack
|
||||
* (#6/#55), and a component reaching for `history` itself is how
|
||||
* two stacks come to disagree about what one press means -- the
|
||||
* fault that deleted `navStack`. See #200.
|
||||
*/
|
||||
private onKeydown = (e: KeyboardEvent) => {
|
||||
if (e.key !== 'Escape' || this.count <= 0) return;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.emit('selection-exit');
|
||||
};
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
document.addEventListener('keydown', this.onKeydown, true);
|
||||
}
|
||||
|
||||
override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('keydown', this.onKeydown, true);
|
||||
}
|
||||
|
||||
override render() {
|
||||
if (this.count <= 0) return nothing;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user