68 lines
3.8 KiB
Markdown
68 lines
3.8 KiB
Markdown
# Now Playing UX Improvements
|
|
|
|
**Date:** 2026-03-10
|
|
|
|
## Task Description
|
|
|
|
Five UX enhancements to the Now Playing screen in the Android 247 Radio app.
|
|
|
|
## Changes Made
|
|
|
|
### 1. Bouncing Marquee Text (`NowPlayingScreen.kt`)
|
|
- Created `BounceMarqueeText` composable that measures text width vs container
|
|
- If text fits: displays centered, stationary (single line)
|
|
- If text overflows: animates horizontal translation with a bounce pattern (scroll to end, pause 1.5s, scroll back, pause 1.5s, repeat)
|
|
- Scroll speed scales proportionally with overflow distance (18ms per dp)
|
|
- Uses `rememberTextMeasurer` for unconstrained width measurement, `rememberInfiniteTransition` with `keyframes` for bounce animation
|
|
- Both stroke and fill text layers share the same animated offset
|
|
- Replaced multi-line wrapping in `TrackInfoSection` with single-line marquee
|
|
|
|
### 2. Timer/Latency Icons (`NowPlayingScreen.kt`)
|
|
- Replaced the concatenated text string in `TimerSection` with a `Row` of icon+value pairs
|
|
- Session elapsed: `Icons.Outlined.Schedule` icon
|
|
- Connection elapsed: `Icons.Outlined.Wifi` icon
|
|
- Latency: `Icons.Outlined.Speed` icon
|
|
- Icons sized at 14dp, tinted with same dimmed color as text
|
|
|
|
### 3. Cross-Fade Metadata and Artwork (`NowPlayingViewModel.kt`, `NowPlayingScreen.kt`)
|
|
- Added `displayMetadata` and `displayArtworkUrl` StateFlows to ViewModel
|
|
- These are "committed" values that only update after artwork resolution completes
|
|
- When metadata changes, artwork resolve runs in background while old metadata+art remains displayed
|
|
- Once resolve completes, both metadata and artwork URL update atomically
|
|
- Station changes trigger immediate display reset
|
|
- Added `AnimatedContent` with 600ms fade transition around `ArtworkImage`
|
|
- Screen now reads `displayMetadata` for track info instead of raw `playbackState.metadata`
|
|
|
|
### 4. Stream Quality Indicator (5 files)
|
|
- `StreamConnection.kt`: Added `StreamInfo` data class (bitrate, ssl, contentType); parsed from ICY response headers (`icy-br`, `Content-Type`, URL scheme)
|
|
- `AudioEngineEvent.kt`: Added `StreamInfoReceived` event
|
|
- `AudioEngine.kt`: Emits `StreamInfoReceived` after connection opens
|
|
- `PlaybackState.kt`: Added `streamInfo: StreamInfo?` to `Playing` and `Paused` states
|
|
- `RadioPlaybackService.kt`: Handles `StreamInfoReceived` event, updates `Playing` state
|
|
- `RadioController.kt`: Carries `streamInfo` to `Paused` state on pause
|
|
- `NowPlayingScreen.kt`: Added `QualityBadge` composable showing bitrate, codec (MP3/AAC/OGG/FLAC), and SSL lock icon
|
|
|
|
### 5. Dominant Color White Handling (`NowPlayingScreen.kt`)
|
|
- Added `.clearFilters()` to `Palette.Builder` chain before `.generate()`
|
|
- Removes the default Palette filter that excludes near-white and near-black colors
|
|
- White-dominant album art now correctly produces a white background with dark text
|
|
|
|
## Files Modified
|
|
- `app/src/main/java/xyz/cottongin/radio247/ui/screens/nowplaying/NowPlayingScreen.kt`
|
|
- `app/src/main/java/xyz/cottongin/radio247/ui/screens/nowplaying/NowPlayingViewModel.kt`
|
|
- `app/src/main/java/xyz/cottongin/radio247/audio/StreamConnection.kt`
|
|
- `app/src/main/java/xyz/cottongin/radio247/audio/AudioEngine.kt`
|
|
- `app/src/main/java/xyz/cottongin/radio247/audio/AudioEngineEvent.kt`
|
|
- `app/src/main/java/xyz/cottongin/radio247/service/PlaybackState.kt`
|
|
- `app/src/main/java/xyz/cottongin/radio247/service/RadioPlaybackService.kt`
|
|
- `app/src/main/java/xyz/cottongin/radio247/service/RadioController.kt`
|
|
|
|
## Verification
|
|
- Build: `./gradlew compileDebugKotlin` -- exit 0 (only pre-existing deprecation warnings)
|
|
- Tests: `./gradlew testDebugUnitTest` -- 56/56 pass, 0 failures
|
|
|
|
## Follow-up Items
|
|
- Test on device: marquee animation with various track name lengths
|
|
- Test on device: cross-fade timing with slow MusicBrainz lookups
|
|
- Test on device: verify ICY headers (`icy-br`) are present for non-SomaFM stations
|