Files
Android-247-Radio/chat-summaries/2026-03-10_now-playing-ux-improvements-summary.md
2026-03-10 20:17:03 -04:00

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