Queue fix + cross-client queue enhancements #112

Merged
bvandeusen merged 9 commits from dev into main 2026-07-23 08:31:34 -04:00
Owner

Merges the queue fix + enhancement batch to main. All CI-green on dev (web run #535, Android run #537).

Fix

  • Web: clicking play did nothing (#1928) — QueueDrawer was rendered outside QueryClientProvider, so the queue LikeButton (added in #1596) threw "No QueryClient was found" the moment the queue populated on first play, aborting the reactive flush that starts playback. Moved the drawer inside the provider.

Queue enhancements (web + Android)

  • Queue opens scrolled to the now-playing track (#1929 Android, #1931 web).
  • Auto-follow the now-playing track as it auto-advances, with a "Jump to current" pill when the user has scrolled away.
  • Album-art thumbnails in queue rows.
  • Clear-queue action.
  • Android drag-to-reorder + per-row remove (closing the functional gap with web), plus a header count + total-time summary.

Heavy survey items (Up-Next sectioning, save-queue-as-playlist, multi-select) were intentionally scoped out.

🤖 Generated with Claude Code

Merges the queue fix + enhancement batch to `main`. All CI-green on `dev` (web run #535, Android run #537). ## Fix - **Web: clicking play did nothing** (#1928) — `QueueDrawer` was rendered outside `QueryClientProvider`, so the queue `LikeButton` (added in #1596) threw "No QueryClient was found" the moment the queue populated on first play, aborting the reactive flush that starts playback. Moved the drawer inside the provider. ## Queue enhancements (web + Android) - Queue opens scrolled to the now-playing track (#1929 Android, #1931 web). - **Auto-follow** the now-playing track as it auto-advances, with a **"Jump to current"** pill when the user has scrolled away. - **Album-art thumbnails** in queue rows. - **Clear-queue** action. - **Android drag-to-reorder + per-row remove** (closing the functional gap with web), plus a header count + total-time summary. Heavy survey items (Up-Next sectioning, save-queue-as-playlist, multi-select) were intentionally scoped out. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bvandeusen added 9 commits 2026-07-23 08:31:21 -04:00
The queue drawer's <aside> is always mounted, so QueueTrackRow's LikeButton
(added in #1596) instantiates the moment the queue populates on first play.
LikeButton calls useQueryClient() at init; with the drawer outside the
provider it threw 'No QueryClient was found in Svelte context', aborting the
reactive flush that starts playback — so play appeared to do nothing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(player): open Android queue scrolled to now-playing track — #1929
android / Build + lint + test (push) Successful in 4m8s
41ebf1405b
QueueList used a plain LazyColumn with no hoisted state, so the queue always
opened at the top and the current track could be off-screen. Seed a
rememberLazyListState with the current index (coerced into bounds) so the list
renders already positioned on the now-playing row — no post-layout scroll flash.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
QueueList gains an `active` prop; when it flips true (drawer opens) or on mount
(now-playing panel) it centers the current row in view. Index/length are read
untracked so it positions once per open rather than following auto-advance,
matching the Android queue. QueueDrawer passes active={queueDrawerOpen} since
its aside is always mounted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The queue auto-scroll $effect calls scrollIntoView on render, and jsdom
doesn't implement it, so QueueDrawer.test.ts threw an unhandled TypeError that
failed the run even though every assertion passed. Polyfill it as a no-op in
the shared setup; tests never assert on scroll position.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a 40px cover thumbnail (coverUrl(album_id), FALLBACK_COVER on error) to
each queue row, matching the artwork every comparable player shows in its
up-next list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
QueueList now follows the now-playing row as the track auto-advances (only
while it's in view), centers it on open, and surfaces a 'Jump to current' pill
once the user scrolls it off-screen. Header gains a clear-queue action backed
by a new store clearQueue() that empties the queue and stops playback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds moveInQueue/removeFromQueue/clearQueue, each keeping the domain queueRefs
snapshot in lock-step with the Media3 timeline (mirrors playNext/enqueue). Media3
onEvents rebuilds uiState so the queue view reflects reorder/removal/clear.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Queue screen gains: album-art thumbnails (ServerImage), drag-to-reorder via a
grip handle (offset->delta on release, mirroring the web), a remove button per
row, auto-follow of the now-playing track with a 'Jump to current' pill when
scrolled away, a clear-queue action, and a header count + total-time summary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(player): suppress TooManyFunctions on PlayerViewModel facade — #1944
android / Build + lint + test (push) Successful in 3m43s
0774f5f55f
Adding the queue move/remove/clear pass-throughs pushed the VM to 12 functions
(detekt cap 11). It's a thin transport facade forwarding to PlayerController, so
suppress with a rationale rather than splitting the delegating surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bvandeusen merged commit a26ef4e93c into main 2026-07-23 08:31:34 -04:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/minstrel#112