polish the play indicator, queue rows and detail spacing

- shadow the play indicator over album art so it reads against busy art
- drop the download indicator from the queue view
- enlarge the now playing star toggle
- leave a little more room between the detail controls and the song list
This commit is contained in:
austinried
2026-10-04 00:30:02 +00:00
parent 83d0bafeb9
commit 9cb93d37e1
4 changed files with 29 additions and 20 deletions
@@ -225,7 +225,7 @@ fun HeroHeader(
modifier = modifier =
modifier modifier
.fillMaxWidth() .fillMaxWidth()
.padding(start = 24.dp, end = 24.dp, top = topInset + 24.dp, bottom = 16.dp), .padding(start = 24.dp, end = 24.dp, top = topInset + 24.dp, bottom = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
CoverArt( CoverArt(
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@@ -133,14 +134,35 @@ private fun CoverArtCell(
.matchParentSize() .matchParentSize()
.border(1.5.dp, MaterialTheme.colorScheme.primary, shape), .border(1.5.dp, MaterialTheme.colorScheme.primary, shape),
) )
PlayIndicator(
shadow = true,
modifier = Modifier.align(Alignment.Center).size(PLAY_ICON_SIZE),
)
}
}
}
@Composable
private fun PlayIndicator(
shadow: Boolean,
modifier: Modifier = Modifier,
) {
Box(modifier) {
if (shadow) {
Icon(
imageVector = Icons.Rounded.PlayArrow,
contentDescription = null,
tint = Color.Black.copy(alpha = 0.6f),
modifier = Modifier.matchParentSize().offset(x = 1.dp, y = 1.dp),
)
}
Icon( Icon(
imageVector = Icons.Rounded.PlayArrow, imageVector = Icons.Rounded.PlayArrow,
contentDescription = "Playing", contentDescription = "Playing",
tint = MaterialTheme.colorScheme.primary, tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.align(Alignment.Center).size(PLAY_ICON_SIZE), modifier = Modifier.matchParentSize(),
) )
} }
}
} }
@Composable @Composable
@@ -153,12 +175,7 @@ private fun TrackCell(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
if (isPlaying) { if (isPlaying) {
Icon( PlayIndicator(shadow = false, modifier = Modifier.size(PLAY_ICON_SIZE))
imageVector = Icons.Rounded.PlayArrow,
contentDescription = "Playing",
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(PLAY_ICON_SIZE),
)
} else if (track != null) { } else if (track != null) {
SmallNumber(track.toString()) SmallNumber(track.toString())
} }
@@ -356,6 +356,7 @@ fun NowPlayingScreen(
} else { } else {
MaterialTheme.colorScheme.onSurfaceVariant MaterialTheme.colorScheme.onSurfaceVariant
}, },
modifier = Modifier.size(32.dp),
) )
} }
} }
@@ -47,9 +47,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.subtracks.data.model.CoverArtRef import com.subtracks.data.model.CoverArtRef
import com.subtracks.data.model.SongDownload
import com.subtracks.data.model.SongItem import com.subtracks.data.model.SongItem
import com.subtracks.data.repo.DownloadRepository
import com.subtracks.data.repo.QUEUE_CHUNK import com.subtracks.data.repo.QUEUE_CHUNK
import com.subtracks.data.repo.QueueRepository import com.subtracks.data.repo.QueueRepository
import com.subtracks.data.repo.QueueWindowItem import com.subtracks.data.repo.QueueWindowItem
@@ -276,10 +274,8 @@ fun QueueRoute(
viewModel: QueueViewModel = koinViewModel(), viewModel: QueueViewModel = koinViewModel(),
controller: PlaybackController = koinInject(), controller: PlaybackController = koinInject(),
sourceRepository: SourceRepository = koinInject(), sourceRepository: SourceRepository = koinInject(),
downloadRepository: DownloadRepository = koinInject(),
) { ) {
val playback by controller.state.collectAsStateWithLifecycle() val playback by controller.state.collectAsStateWithLifecycle()
val downloads by downloadRepository.states().collectAsStateWithLifecycle()
val queueContext = playback.context val queueContext = playback.context
// The item's album keeps the header stable while the async name lookup runs, so it does not // The item's album keeps the header stable while the async name lookup runs, so it does not
// flash the fallback when tapping between context and manually queued tracks. // flash the fallback when tapping between context and manually queued tracks.
@@ -299,7 +295,6 @@ fun QueueRoute(
currentSongId = playback.item?.id, currentSongId = playback.item?.id,
shuffle = playback.shuffle, shuffle = playback.shuffle,
contextTitle = sourceTitle.value, contextTitle = sourceTitle.value,
downloads = downloads,
onClearUpNext = controller::clearUpNext, onClearUpNext = controller::clearUpNext,
coverArt = sourceRepository::coverArt, coverArt = sourceRepository::coverArt,
onBack = onBack, onBack = onBack,
@@ -335,7 +330,6 @@ fun QueueScreen(
generation: Int = 0, generation: Int = 0,
shuffle: Boolean = false, shuffle: Boolean = false,
contextTitle: String? = null, contextTitle: String? = null,
downloads: Map<String, SongDownload> = emptyMap(),
onClearUpNext: () -> Unit = {}, onClearUpNext: () -> Unit = {},
) { ) {
val listState = rememberLazyListState() val listState = rememberLazyListState()
@@ -452,7 +446,6 @@ fun QueueScreen(
isPlaying = row.isPlaying(currentPosition, currentSongId), isPlaying = row.isPlaying(currentPosition, currentSongId),
floating = isDragging, floating = isDragging,
coverArt = coverArt, coverArt = coverArt,
download = downloads[row.song.song.id],
dragHandle = dragHandle =
if (!enabled) { if (!enabled) {
null null
@@ -553,7 +546,6 @@ private fun QueueRowItem(
isPlaying: Boolean, isPlaying: Boolean,
floating: Boolean, floating: Boolean,
coverArt: (String?, Boolean) -> CoverArtRef?, coverArt: (String?, Boolean) -> CoverArtRef?,
download: SongDownload?,
dragHandle: Modifier?, dragHandle: Modifier?,
onClick: () -> Unit, onClick: () -> Unit,
onRemove: () -> Unit, onRemove: () -> Unit,
@@ -562,7 +554,6 @@ private fun QueueRowItem(
song = row.song.song, song = row.song.song,
coverArtId = row.song.coverArt, coverArtId = row.song.coverArt,
coverArt = coverArt, coverArt = coverArt,
download = download,
isPlaying = isPlaying, isPlaying = isPlaying,
trailingContent = { trailingContent = {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {