feat(ui): mini-player buffering pose + one-tap retry on error
- Equalizer chip dims while BUFFERING/INITIALIZING (no false 'playing' signal during reconnect) - On ERROR the bar's subtitle becomes 'Couldn't reach · Retry' — tapping replays the current station without leaving the tab - NowPlayingViewModel.retry() re-plays current URL
This commit is contained in:
parent
918aeaf8d3
commit
e2ed74a47d
2 changed files with 42 additions and 2 deletions
|
|
@ -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<String?>(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) },
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue