User reports only the first card in 'Recently added' navigates and the
HitTestBehavior.opaque fix in d703fc2 didn't fully resolve it.
Switch all three card widgets (album, artist, playlist) from
GestureDetector to Material(transparent) + InkWell. This is the more
idiomatic Flutter pattern for tap-to-navigate cards:
- InkWell registers via the Material ripple system instead of the
raw gesture arena, sidestepping any subtle deferToChild edge cases
inside horizontal ListViews.
- Visible ripple feedback on tap means a missed tap is now diagnosable
visually — if the ripple shows but nothing navigates, the issue is
on the route side; if no ripple, the tap never landed.
Material color is transparent so the existing dark page background
shows through unchanged.
Same root cause as the playlist card fix in f65650f — GestureDetector
defers to children by default, so taps over the cover image area
(ServerImage / SVG fallback) didn't reliably propagate. Mark the
detector opaque so the entire card surface is tappable, not just the
text below the cover.
Cover-art Image.network calls were passing server-relative URLs
(/api/albums/<id>/cover) straight to NetworkImage, which interprets
"no scheme" as file:/// and crashes with "No host specified in URI".
Same root cause regardless of HTTPS or HTTP server.
ServerImage wraps Image.network with a Riverpod read of
serverUrlProvider and prefixes the configured base URL. Absolute URLs
(e.g. discover screen's Lidarr image_urls) pass through unchanged.
Three call sites updated: album_card, artist_card, playlists_list_screen.
discover_screen left as-is — its row.imageUrl is already absolute (Lidarr
returns full URLs from MusicBrainz / Spotify metadata) and it has a
meaningful errorBuilder that ServerImage doesn't expose.
Also adds a defensive check in audio_handler.setQueueFromTracks: if
the constructed stream URL ends up scheme-less, throw a StateError
naming baseUrl + track.streamUrl + track.id instead of letting it
fall through to ExoPlayer which surfaces a confusing "Cleartext HTTP
traffic to 127.0.0.1 not permitted" error (Android's URL parser
defaults a scheme-less URI to localhost). User reported this exact
confusing error against an HTTPS prod server; the better message
will pinpoint where the empty baseUrl comes from on next reproduction.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.