feat: M3 weighted shuffle v1 — real /api/radio with scoring #21

Merged
bvandeusen merged 262 commits from dev into main 2026-04-27 11:00:29 -04:00
Showing only changes of commit a9b3c936f1 - Show all commits
@@ -96,44 +96,57 @@ fun NowPlayingScreen(
snackbarHost = { SnackbarHost(snackbarHostState) },
containerColor = MaterialTheme.colorScheme.background,
) { inner ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(inner)
.padding(horizontal = 24.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
NowPlayingCover(coverUrl = track.coverUrl, contentDescription = track.title)
Spacer(Modifier.height(24.dp))
TrackHeader(
title = track.title,
artist = track.artistName,
album = track.albumTitle,
)
Spacer(Modifier.height(24.dp))
ScrubberRow(
positionMs = state.positionMs,
durationMs = state.durationMs,
onSeek = viewModel::seekTo,
)
Spacer(Modifier.height(8.dp))
TransportRow(
isPlaying = state.isPlaying,
onPrev = viewModel::skipToPrevious,
onPlayPause = { if (state.isPlaying) viewModel.pause() else viewModel.play() },
onNext = viewModel::skipToNext,
)
Spacer(Modifier.height(16.dp))
BottomActionsRow(
navController = navController,
track = track,
shuffleEnabled = state.shuffleEnabled,
repeatMode = state.repeatMode,
onToggleShuffle = viewModel::toggleShuffle,
onCycleRepeat = viewModel::cycleRepeat,
)
}
NowPlayingBody(
inner = inner,
state = state,
track = track,
navController = navController,
viewModel = viewModel,
)
}
}
@Composable
private fun NowPlayingBody(
inner: androidx.compose.foundation.layout.PaddingValues,
state: com.fabledsword.minstrel.player.PlayerUiState,
track: com.fabledsword.minstrel.models.TrackRef,
navController: NavHostController,
viewModel: PlayerViewModel,
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(inner)
.padding(horizontal = 24.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
NowPlayingCover(coverUrl = track.coverUrl, contentDescription = track.title)
Spacer(Modifier.height(24.dp))
TrackHeader(title = track.title, artist = track.artistName, album = track.albumTitle)
Spacer(Modifier.height(24.dp))
ScrubberRow(
positionMs = state.positionMs,
durationMs = state.durationMs,
onSeek = viewModel::seekTo,
)
Spacer(Modifier.height(8.dp))
TransportRow(
isPlaying = state.isPlaying,
onPrev = viewModel::skipToPrevious,
onPlayPause = { if (state.isPlaying) viewModel.pause() else viewModel.play() },
onNext = viewModel::skipToNext,
)
Spacer(Modifier.height(16.dp))
BottomActionsRow(
navController = navController,
track = track,
shuffleEnabled = state.shuffleEnabled,
repeatMode = state.repeatMode,
onToggleShuffle = viewModel::toggleShuffle,
onCycleRepeat = viewModel::cycleRepeat,
)
}
}