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.
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)
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>
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>
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>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Merges the queue fix + enhancement batch to
main. All CI-green ondev(web run #535, Android run #537).Fix
QueueDrawerwas rendered outsideQueryClientProvider, so the queueLikeButton(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)
Heavy survey items (Up-Next sectioning, save-queue-as-playlist, multi-select) were intentionally scoped out.
🤖 Generated with Claude Code
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>