release v2026.05.11.1: Flutter caching, navigation, and player polish #39

Merged
bvandeusen merged 262 commits from dev into main 2026-05-11 13:47:43 -04:00
Showing only changes of commit 69179e0af3 - Show all commits
@@ -95,39 +95,12 @@ fun AlbumDetailScreen(
onRefresh = { viewModel.refresh().join() },
modifier = Modifier.fillMaxSize().padding(inner),
) {
Crossfade(targetState = state, label = "album-detail") { s ->
when (s) {
is AlbumDetailUiState.Loading -> SkeletonTrackList()
is AlbumDetailUiState.Error -> EmptyState(
title = "Couldn't load album",
body = s.message,
)
is AlbumDetailUiState.Success -> {
val albumLiked by viewModel.albumLiked.collectAsStateWithLifecycle()
val likedTrackIds by viewModel.likedTrackIds
.collectAsStateWithLifecycle()
val playerState by playerViewModel.uiState
.collectAsStateWithLifecycle()
AlbumBody(
detail = s.detail,
albumLiked = albumLiked,
likedTrackIds = likedTrackIds,
playingTrackId = playerState.currentTrack?.id,
onPlayAll = { viewModel.play(startTrackId = null) },
onShuffleAll = viewModel::shuffle,
onTrackClick = { id -> viewModel.play(startTrackId = id) },
onToggleAlbumLike = viewModel::toggleLikeAlbum,
onToggleTrackLike = viewModel::toggleLikeTrack,
onNavigateToAlbum = { id ->
navController.navigate(AlbumDetail(id))
},
onNavigateToArtist = { id ->
navController.navigate(ArtistDetail(id))
},
)
}
}
}
AlbumDetailStateContent(
state = state,
viewModel = viewModel,
playerViewModel = playerViewModel,
navController = navController,
)
}
}
}
@@ -138,6 +111,48 @@ private fun titleFor(state: AlbumDetailUiState): String = when (state) {
is AlbumDetailUiState.Error -> "Album"
}
@Composable
private fun AlbumDetailStateContent(
state: AlbumDetailUiState,
viewModel: AlbumDetailViewModel,
playerViewModel: com.fabledsword.minstrel.player.ui.PlayerViewModel,
navController: NavHostController,
) {
Crossfade(targetState = state, label = "album-detail") { s ->
when (s) {
is AlbumDetailUiState.Loading -> SkeletonTrackList()
is AlbumDetailUiState.Error -> EmptyState(
title = "Couldn't load album",
body = s.message,
)
is AlbumDetailUiState.Success -> {
val albumLiked by viewModel.albumLiked.collectAsStateWithLifecycle()
val likedTrackIds by viewModel.likedTrackIds
.collectAsStateWithLifecycle()
val playerState by playerViewModel.uiState
.collectAsStateWithLifecycle()
AlbumBody(
detail = s.detail,
albumLiked = albumLiked,
likedTrackIds = likedTrackIds,
playingTrackId = playerState.currentTrack?.id,
onPlayAll = { viewModel.play(startTrackId = null) },
onShuffleAll = viewModel::shuffle,
onTrackClick = { id -> viewModel.play(startTrackId = id) },
onToggleAlbumLike = viewModel::toggleLikeAlbum,
onToggleTrackLike = viewModel::toggleLikeTrack,
onNavigateToAlbum = { id ->
navController.navigate(AlbumDetail(id))
},
onNavigateToArtist = { id ->
navController.navigate(ArtistDetail(id))
},
)
}
}
}
}
@Composable
private fun AlbumBody(
detail: AlbumDetailRef,