5 Commits

Author SHA1 Message Date
bvandeusen bb9e979876 feat(web,flutter): #401 — now-playing highlight on TrackRow + PlaylistTrackRow
Cross-platform consistency: when a track is currently playing, its row
on the album / liked / history / search / playlist detail surfaces
gets the same accent-border + bg-lift treatment that QueueTrackRow
applies on the queue panel. Closes the inconsistency caught during
the #375 DRY audit (the queue row had a "you are here" indicator;
other track-row surfaces did not).

Web — TrackRow.svelte + PlaylistTrackRow.svelte:
  isCurrent = player.current?.id === track.id
  → border-l-2 border-l-accent bg-surface-hover when true.
  PlaylistTrackRow additionally gates on !isUnavailable so deleted
  rows never match a phantom playing id.

Flutter — TrackRow + _PlaylistTrackRow:
  TrackRow becomes a ConsumerWidget, watches mediaItemProvider, and
  wraps its InkWell in a Container whose BoxDecoration carries the
  fs.iron background + 2px fs.accent left border when current. Title
  text also shifts to fs.accent and FontWeight.w500. Same pattern for
  _PlaylistTrackRow.

No "Now playing" pill on these surfaces — the player bar already
names the track, so the accent band alone reads as enough cue.

For #401 / #356 umbrella.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:05:33 -04:00
bvandeusen 983a9d92be fix(flutter): tighter track row + missing artist in mini player + hide redundant artist on artist page
Track row (album detail):
- Vertical padding 10→6 and only render the artist line when non-empty,
  so tracks without a populated artist row don't reserve a blank line.
- Number column 28→22 — visually tighter without making 3-digit
  numbers cramp.

Mini player missing artist:
- Symptom was an empty `artist` field on MediaItem after tapping a
  track in album detail; layout change wasn't the cause. Real cause:
  albumProvider's cold-cache only wrote cachedAlbums + cachedTracks,
  never cachedArtists. The drift JOINs that build the AlbumRef + each
  TrackRef returned null for the artist row, so artistName fell back
  to '' and the audio handler stamped MediaItem.artist=''.
- Cold-cache now collects every distinct (artistId, artistName) pair
  off the album header + each track, inserts them into cachedArtists
  alongside the album/tracks. Subsequent JOINs populate artistName,
  the audio handler stamps it on MediaItem, and the mini player picks
  it up via the existing artistName.isNotEmpty render.
- Existing cached albums won't get artist names until they're
  re-fetched (cache invalidation TBD). Future cold-cache hits will.

Artist detail album grid:
- AlbumCard gains showArtist (default true). Pass false in the artist
  detail grid since the page header already names the artist. cellH
  trimmed by the 16dp artist line.
2026-05-11 08:47:50 -04:00
bvandeusen 5114a8118c feat(flutter): CachedIndicator + Download buttons + app startup wiring
CachedIndicator (lib/library/widgets/cached_indicator.dart) — small
download glyph rendered next to a track row when AudioCacheManager
reports the track as cached. FutureBuilder one-shot.

Wiring:
  - track_row.dart: render CachedIndicator before the duration label
  - playlist_detail: 'Download' OutlinedButton next to Play; pins all
    playable tracks with source: autoPlaylist + SnackBar feedback
  - album_detail: 'Download' IconButton in the header; same pin pattern
  - app.dart: now ConsumerStatefulWidget — initState fires the initial
    sync + activates the prefetcher provider

Together these complete the operator-facing surfaces of the offline
slice: visible cache state, explicit download trigger, automatic
sync + queue-ahead prefetch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 23:23:26 -04:00
bvandeusen 25ff7afc33 feat(flutter): TrackRow renders TrackActionsButton by default
Adds optional actions: bool = true param. When true (default), renders
the 3-dot menu trigger at the end of the row. Album detail / Search /
History / Liked tabs all consume TrackRow so they pick up the menu
transitively.

Pair with c8baaa5 which wired the button into the other 3 surfaces;
this commit completes the wire-up by including TrackRow itself (its
write was missed in the previous commit).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 13:43:40 -04:00
bvandeusen c47deb3c87 feat(flutter/library): card + row widgets (artist/album/track)
HorizontalScrollRow takes an optional shared ScrollController so
multi-row sections (Most played: 3 rows) couple their scroll like the
web HorizontalScrollRow.svelte. Cards fall back to the synced
album-fallback.svg when coverUrl is empty.
2026-05-02 17:29:03 -04:00