feat: M3 weighted shuffle v1 — real /api/radio with scoring #21
@@ -222,7 +222,7 @@ private fun AlbumCover(album: AlbumRef) {
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
if (album.coverUrl.isEmpty()) {
|
||||
if (album.id.isEmpty()) {
|
||||
Icon(
|
||||
imageVector = Lucide.Disc3,
|
||||
contentDescription = null,
|
||||
@@ -231,7 +231,7 @@ private fun AlbumCover(album: AlbumRef) {
|
||||
)
|
||||
} else {
|
||||
AsyncImage(
|
||||
model = album.coverUrl,
|
||||
model = album.displayCoverUrl,
|
||||
contentDescription = album.title,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.fabledsword.minstrel.player.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -21,10 +22,12 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coil3.compose.AsyncImage
|
||||
import com.composables.icons.lucide.Lucide
|
||||
import com.composables.icons.lucide.Music
|
||||
import com.composables.icons.lucide.Pause
|
||||
@@ -41,9 +44,9 @@ private const val COVER_SIZE_DP = 48
|
||||
* fresh install. Tapping the body navigates to the full
|
||||
* NowPlayingScreen via [onExpandClick].
|
||||
*
|
||||
* Cover art is a placeholder Lucide icon for now — TrackRef carries
|
||||
* no coverUrl; covers come from the AlbumRef join we'll add in a
|
||||
* later 5.x slice. AsyncImage / Coil wire-up lands then.
|
||||
* Cover comes from TrackRef.coverUrl (derived from albumId via the
|
||||
* BaseUrlInterceptor placeholder); falls back to the Lucide.Music
|
||||
* icon when the album binding is missing.
|
||||
*/
|
||||
@Composable
|
||||
fun MiniPlayer(
|
||||
@@ -69,14 +72,24 @@ fun MiniPlayer(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(COVER_SIZE_DP.dp)
|
||||
.clip(RoundedCornerShape(FabledSwordFlatTokens.radiusSm)),
|
||||
.clip(RoundedCornerShape(FabledSwordFlatTokens.radiusSm))
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Lucide.Music,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
if (track.coverUrl.isEmpty()) {
|
||||
Icon(
|
||||
imageVector = Lucide.Music,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
} else {
|
||||
AsyncImage(
|
||||
model = track.coverUrl,
|
||||
contentDescription = track.title,
|
||||
modifier = Modifier.size(COVER_SIZE_DP.dp),
|
||||
contentScale = ContentScale.Crop,
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.width(12.dp))
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.fabledsword.minstrel.player.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -24,12 +25,14 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavHostController
|
||||
import coil3.compose.AsyncImage
|
||||
import com.composables.icons.lucide.ListMusic
|
||||
import com.composables.icons.lucide.Lucide
|
||||
import com.composables.icons.lucide.Music
|
||||
@@ -75,7 +78,7 @@ fun NowPlayingScreen(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
CoverPlaceholder()
|
||||
NowPlayingCover(coverUrl = track.coverUrl, contentDescription = track.title)
|
||||
Spacer(Modifier.height(24.dp))
|
||||
TrackHeader(
|
||||
title = track.title,
|
||||
@@ -112,21 +115,31 @@ private fun ViewQueueButton(onClick: () -> Unit) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CoverPlaceholder() {
|
||||
private fun NowPlayingCover(coverUrl: String, contentDescription: String) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.widthIn(max = COVER_MAX_WIDTH_DP.dp)
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
.clip(RoundedCornerShape(FabledSwordFlatTokens.radiusLg)),
|
||||
.clip(RoundedCornerShape(FabledSwordFlatTokens.radiusLg))
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Lucide.Music,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.size(96.dp),
|
||||
)
|
||||
if (coverUrl.isEmpty()) {
|
||||
Icon(
|
||||
imageVector = Lucide.Music,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.size(96.dp),
|
||||
)
|
||||
} else {
|
||||
AsyncImage(
|
||||
model = coverUrl,
|
||||
contentDescription = contentDescription,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = ContentScale.Crop,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user