diff --git a/app/src/main/java/com/rada/ui/player/NowPlayingBar.kt b/app/src/main/java/com/rada/ui/player/NowPlayingBar.kt index b5982b0..b9cf1b4 100644 --- a/app/src/main/java/com/rada/ui/player/NowPlayingBar.kt +++ b/app/src/main/java/com/rada/ui/player/NowPlayingBar.kt @@ -65,6 +65,10 @@ fun NowPlayingBar( val isLocal by viewModel.isLocal.collectAsState() val streamMeta by viewModel.streamMeta.collectAsState() val localMedia by viewModel.localMedia.collectAsState() + val isError = bufferState == PlaybackManager.BufferState.ERROR + val isBuffering = + bufferState == PlaybackManager.BufferState.BUFFERING || + bufferState == PlaybackManager.BufferState.INITIALIZING // Swipe-down (or quick drag-down) dismisses the bar until a *new* // source starts playing — a floating thing should answer to gestures. var dismissedFor by remember { mutableStateOf(null) } @@ -145,13 +149,22 @@ fun NowPlayingBar( .background(LocalTokens.current.accentFill), contentAlignment = Alignment.Center, ) { - if (isPlaying) { + if (isPlaying && !isBuffering) { EqualizerBars( active = true, color = LocalTokens.current.accentOnFill, barWidth = 3.dp, modifier = Modifier.size(22.dp), ) + } else if (isBuffering && !isError) { + EqualizerBars( + active = false, + color = LocalTokens.current.accentOnFill.copy(alpha = 0.7f), + barWidth = 3.dp, + modifier = Modifier + .size(22.dp) + .padding(2.dp), + ) } else { Icon( if (isLocal) Icons.Default.MusicNote else Icons.Default.Radio, @@ -186,7 +199,28 @@ fun NowPlayingBar( color = LocalTokens.current.text, ) } - if (subtitle.isNotEmpty()) { + if (isError) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = { viewModel.retry() }, + ), + ) { + Text( + "Couldn't reach · ", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.error, + ) + Text( + "Retry", + style = MaterialTheme.typography.bodySmall, + fontWeight = FontWeight.Bold, + color = tokens.accentText, + ) + } + } else if (subtitle.isNotEmpty()) { AnimatedContent( targetState = subtitle, transitionSpec = { metadataEnter(reduce) togetherWith metadataExit(reduce) }, diff --git a/app/src/main/java/com/rada/ui/player/NowPlayingViewModel.kt b/app/src/main/java/com/rada/ui/player/NowPlayingViewModel.kt index 9105fc3..698b501 100644 --- a/app/src/main/java/com/rada/ui/player/NowPlayingViewModel.kt +++ b/app/src/main/java/com/rada/ui/player/NowPlayingViewModel.kt @@ -23,4 +23,10 @@ class NowPlayingViewModel @Inject constructor( fun togglePlayPause() { playbackManager.togglePlayPause() } + + /** Reconnect the current station (mini-player error state). */ + fun retry() { + val url = playbackManager.currentStationUrl ?: return + playbackManager.playStation(url, playbackManager.currentStationName) + } }