Android: a non-interactive progress line on the border between the mini player and the nav bar #58

Closed
opened 2026-08-18 05:59:09 +00:00 by logan · 2 comments
Collaborator

Report

Show current song progress as a line running across the border between the mini player bar and the bottom navigation bar. Purely visual — to actually seek, the user goes to the Now Playing screen.

Findings

  • The position is already pushed at 1Hz via PlaybackPositionChanged with local interpolation between reports (trackChangeId + seq guard against adopting a stale report). A progress line should consume the same source, never its own clock.
  • The mini player and <bottom-nav> are separate components stacked in the shell grid, so the line is best drawn by the shell (or by the player as a 2px element on its bottom edge) rather than by either component reaching into the other.

Direction

A 2px element on the boundary, transform: scaleX() driven off the same interpolated position, aria-hidden (the real progress is announced by the seek bar on Now Playing). No pointer events at all — a thin line that sometimes seeks is worse than one that never does.

**Report** Show current song progress as a line running across the border between the mini player bar and the bottom navigation bar. Purely visual — to actually seek, the user goes to the Now Playing screen. **Findings** - The position is already pushed at 1Hz via `PlaybackPositionChanged` with local interpolation between reports (`trackChangeId` + `seq` guard against adopting a stale report). A progress line should consume the same source, never its own clock. - The mini player and `<bottom-nav>` are separate components stacked in the shell grid, so the line is best drawn by the shell (or by the player as a 2px element on its bottom edge) rather than by either component reaching into the other. **Direction** A 2px element on the boundary, `transform: scaleX()` driven off the same interpolated position, `aria-hidden` (the real progress is announced by the seek bar on Now Playing). No pointer events at all — a thin line that sometimes seeks is worse than one that never does.
logan added the Area/PlayerKind/FeaturePlatform/Android
Priority
Medium
3
labels 2026-08-18 14:36:14 +00:00
logan self-assigned this 2026-08-21 07:33:09 +00:00
logan added the
Status
In Progress
label 2026-08-21 07:33:09 +00:00
Author
Collaborator

Picking this up on feat/58-mini-player-progress-line.

Approach, following the Findings rather than inventing one:

  • A new <player-progress-line> in the shell, between the bottom bar
    and <bottom-nav> in DOM order and as its own 2px grid row below
    600px — so neither component reaches into the other, which is what
    the Findings ask for, and it is in the layout rather than over it
    (job-band's rule).
  • It renders nothing above 600px, from matchMedia rather than a
    media query, because that decides whether the element exists —
    job-band and bottom-nav's "resolved to 2 elements" trap.
  • The fill is transform: scaleX() off the same
    PlaybackPositionChanged source the seek bar uses, with the same
    trackChangeId + seq guards and an interval that only interpolates
    between reports and is reset by every one of them. Never its own
    clock.
  • aria-hidden and pointer-events: none throughout: the real
    progress is announced by the seek bar on Now Playing, and a thin
    line that sometimes seeks is worse than one that never does.

Verification: make ui-test for the mechanism (existence, the
matchMedia branch, the report/interpolation rules) and make e2e
against a phone viewport for the boundary placement, port permitting.
No device claim will be made — this tier cannot see the phone.

Picking this up on `feat/58-mini-player-progress-line`. **Approach**, following the Findings rather than inventing one: - A new `<player-progress-line>` in the shell, between the bottom bar and `<bottom-nav>` in DOM order and as its own 2px grid row below 600px — so neither component reaches into the other, which is what the Findings ask for, and it is *in* the layout rather than over it (`job-band`'s rule). - It renders nothing above 600px, from `matchMedia` rather than a media query, because that decides whether the element exists — `job-band` and `bottom-nav`'s "resolved to 2 elements" trap. - The fill is `transform: scaleX()` off the same `PlaybackPositionChanged` source the seek bar uses, with the same `trackChangeId` + `seq` guards and an interval that only interpolates *between* reports and is reset by every one of them. Never its own clock. - `aria-hidden` and `pointer-events: none` throughout: the real progress is announced by the seek bar on Now Playing, and a thin line that sometimes seeks is worse than one that never does. Verification: `make ui-test` for the mechanism (existence, the matchMedia branch, the report/interpolation rules) and `make e2e` against a phone viewport for the boundary placement, port permitting. No device claim will be made — this tier cannot see the phone.
Author
Collaborator

PR: #178 — CI green on
both jobs, WebKit included.

What landed is the Findings' shape rather than a new one: the line is
the shell's element in its own 2px grid row between bottom-bar and
bottom-nav, so neither bar reaches into the other; the fill is
scaleX() off PlaybackPositionChanged with the seek bar's
trackChangeId/seq guards and an interval that only interpolates
between reports; aria-hidden and pointer-events: none throughout.

Two things worth recording against the issue.

It renders nothing above 600px from matchMedia, not from the
stylesheet.
The CSS alone would have been enough to make it invisible
there and not enough to stop the 1 Hz interval running for the life of
every desktop session — job-band's "existence is not a stylesheet's
decision" with a second reason attached.

The phone rule had to go at the foot of index.css. A media query
adds no specificity, so body player-progress-line { display: block }
written above the display: none that keeps it out of the desktop grid
loses to it and the line never appears at any width, silently. That is
the trap the phone section's own header already records, met again.

Not verified on a device. This is a browser at the reference
device's 424x439, which is not a phone — the appearance on Chrome 113 is
unchecked, though a transform and a flat background are nowhere near
that engine's gaps. Worth a look whenever #51's verification pass runs,
since that is the next item in #73's Phase 3 and it is now the only one
left.

PR: https://git.ljones.me/yonlu/yellowjacket/pulls/178 — CI green on both jobs, WebKit included. What landed is the Findings' shape rather than a new one: the line is the **shell's** element in its own 2px grid row between `bottom-bar` and `bottom-nav`, so neither bar reaches into the other; the fill is `scaleX()` off `PlaybackPositionChanged` with the seek bar's `trackChangeId`/`seq` guards and an interval that only interpolates between reports; `aria-hidden` and `pointer-events: none` throughout. Two things worth recording against the issue. **It renders nothing above 600px from `matchMedia`, not from the stylesheet.** The CSS alone would have been enough to make it invisible there and *not* enough to stop the 1 Hz interval running for the life of every desktop session — `job-band`'s "existence is not a stylesheet's decision" with a second reason attached. **The phone rule had to go at the foot of `index.css`.** A media query adds no specificity, so `body player-progress-line { display: block }` written above the `display: none` that keeps it out of the desktop grid loses to it and the line never appears at any width, silently. That is the trap the phone section's own header already records, met again. **Not verified on a device.** This is a browser at the reference device's 424x439, which is not a phone — the appearance on Chrome 113 is unchecked, though a transform and a flat background are nowhere near that engine's gaps. Worth a look whenever #51's verification pass runs, since that is the next item in #73's Phase 3 and it is now the only one left.
logan closed this issue 2026-08-21 15:16:27 +00:00
gitea-actions bot removed the
Status
In Progress
label 2026-08-21 15:35:53 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: yonlu/yellowjacket#58