diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/HomeScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/HomeScreen.kt index e0be978..aa14a1a 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/HomeScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/HomeScreen.kt @@ -45,6 +45,7 @@ import it.vfsfitvnm.vimusic.ui.components.themed.* import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.px +import it.vfsfitvnm.vimusic.ui.views.BuiltInPlaylistItem import it.vfsfitvnm.vimusic.ui.views.PlaylistPreviewItem import it.vfsfitvnm.vimusic.ui.views.SongItem import it.vfsfitvnm.vimusic.utils.* @@ -351,77 +352,35 @@ fun HomeScreen() { .fillMaxWidth() .height(124.dp * (if (playlistGridExpanded) 3 else 1)) ) { - item { - Box( + item(key = "favorites") { + BuiltInPlaylistItem( + icon = R.drawable.heart, + colorTint = colorPalette.red, + name = "Favorites", modifier = Modifier .padding(all = 8.dp) .clickable( indication = rememberRipple(bounded = true), interactionSource = remember { MutableInteractionSource() }, - onClick = { - builtInPlaylistRoute(BuiltInPlaylist.Favorites) - } + onClick = { builtInPlaylistRoute(BuiltInPlaylist.Favorites) } ) - .background(colorPalette.lightBackground) - .size(108.dp) - ) { - Image( - painter = painterResource(R.drawable.heart), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.red), - modifier = Modifier - .align(Alignment.Center) - .size(24.dp) - ) - - BasicText( - text = "Favorites", - style = typography.xxs.semiBold, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - modifier = Modifier - .fillMaxWidth() - .align(Alignment.BottomStart) - .padding(horizontal = 8.dp, vertical = 4.dp) - ) - } + ) } if (playlistGridExpanded) { - item { - Box( + item(key = "cached") { + BuiltInPlaylistItem( + icon = R.drawable.download, + colorTint = colorPalette.blue, + name = "Cached", modifier = Modifier .padding(all = 8.dp) .clickable( indication = rememberRipple(bounded = true), interactionSource = remember { MutableInteractionSource() }, - onClick = { - builtInPlaylistRoute(BuiltInPlaylist.Cached) - } + onClick = { builtInPlaylistRoute(BuiltInPlaylist.Cached) } ) - .background(colorPalette.lightBackground) - .size(108.dp) - ) { - Image( - painter = painterResource(R.drawable.download), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.blue), - modifier = Modifier - .align(Alignment.Center) - .size(24.dp) - ) - - BasicText( - text = "Cached", - style = typography.xxs.semiBold, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - modifier = Modifier - .fillMaxWidth() - .align(Alignment.BottomStart) - .padding(horizontal = 8.dp, vertical = 4.dp) - ) - } + ) } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlaylistPreviewItem.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlaylistPreviewItem.kt index de55db1..2c6b641 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlaylistPreviewItem.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlaylistPreviewItem.kt @@ -1,10 +1,9 @@ package it.vfsfitvnm.vimusic.ui.views +import androidx.annotation.DrawableRes +import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.BasicText import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -14,8 +13,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -35,66 +36,126 @@ import kotlinx.coroutines.flow.distinctUntilChanged fun PlaylistPreviewItem( playlistPreview: PlaylistPreview, modifier: Modifier = Modifier, - thumbnailSize: Dp = Dimensions.thumbnails.song, + thumbnailSize: Dp = Dimensions.thumbnails.song ) { - val (colorPalette, typography) = LocalAppearance.current val density = LocalDensity.current - val thumbnailSizePx = density.run { - thumbnailSize.toPx().toInt() + val thumbnailSizePx = with(density) { + thumbnailSize.roundToPx() } val thumbnails by remember(playlistPreview.playlist.id) { Database.playlistThumbnailUrls(playlistPreview.playlist.id).distinctUntilChanged() }.collectAsState(initial = emptyList(), context = Dispatchers.IO) + PlaylistItem( + name = playlistPreview.playlist.name, + modifier = modifier, + thumbnailSize = thumbnailSize, + imageContent = { + if (thumbnails.toSet().size == 1) { + AsyncImage( + model = thumbnails.first().thumbnail(thumbnailSizePx), + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .fillMaxSize() + ) + } else { + Box( + modifier = Modifier + .fillMaxSize() + ) { + listOf( + Alignment.TopStart, + Alignment.TopEnd, + Alignment.BottomStart, + Alignment.BottomEnd + ).forEachIndexed { index, alignment -> + AsyncImage( + model = thumbnails.getOrNull(index).thumbnail(thumbnailSizePx), + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .align(alignment) + .size(thumbnailSize) + ) + } + } + } + } + ) +} + +@Composable +fun BuiltInPlaylistItem( + @DrawableRes icon: Int, + colorTint: Color, + name: String, + modifier: Modifier = Modifier, + thumbnailSize: Dp = Dimensions.thumbnails.song +) { + PlaylistItem( + name = name, + modifier = modifier, + thumbnailSize = thumbnailSize, + withGradient = false, + imageContent = { + Image( + painter = painterResource(icon), + contentDescription = null, + colorFilter = ColorFilter.tint(colorTint), + modifier = Modifier + .align(Alignment.Center) + .size(24.dp) + ) + } + ) +} + +@Composable +fun PlaylistItem( + name: String, + modifier: Modifier = Modifier, + thumbnailSize: Dp = Dimensions.thumbnails.song, + withGradient: Boolean = true, + imageContent: @Composable BoxScope.() -> Unit +) { + val (colorPalette, typography) = LocalAppearance.current + Box( modifier = modifier .background(colorPalette.lightBackground) .size(thumbnailSize * 2) ) { - if (thumbnails.toSet().size == 1) { - AsyncImage( - model = thumbnails.first().thumbnail(thumbnailSizePx * 2), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .size(thumbnailSize * 2) - ) - } else { - listOf( - Alignment.TopStart, - Alignment.TopEnd, - Alignment.BottomStart, - Alignment.BottomEnd - ).forEachIndexed { index, alignment -> - AsyncImage( - model = thumbnails.getOrNull(index).thumbnail(thumbnailSizePx), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .align(alignment) - .size(thumbnailSize) - ) - } - } + Box( + modifier = Modifier + .size(thumbnailSize * 2), + content = imageContent + ) BasicText( - text = playlistPreview.playlist.name, + text = name, style = typography.xxs.semiBold.color(Color.White), maxLines = 2, overflow = TextOverflow.Ellipsis, modifier = Modifier .fillMaxWidth() .align(Alignment.BottomStart) - .background( - Brush.verticalGradient( - colors = listOf( - Color.Transparent, - Color.Black.copy(alpha = 0.75f) + .run { + if (withGradient) { + background( + Brush.verticalGradient( + colors = listOf( + Color.Transparent, + Color.Black.copy(alpha = 0.75f) + ) + ) ) - ) - ) + } else { + this + } + } .padding(horizontal = 8.dp, vertical = 4.dp) ) }