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

3.8 KiB

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