diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ee3a552..3565b4b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,10 +5,6 @@ plugins { } android { - signingConfigs { - create("release") { - } - } compileSdk = 33 defaultConfig { @@ -65,10 +61,6 @@ android { freeCompilerArgs += "-Xcontext-receivers" jvmTarget = "1.8" } - - packagingOptions { - resources.excludes.add("META-INF/INDEX.LIST") - } } kapt { diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistContent.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistContent.kt index 79170c5..87fe41f 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistContent.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistContent.kt @@ -41,10 +41,8 @@ inline fun ArtistContent( crossinline bookmarkIconContent: @Composable () -> Unit, crossinline shareIconContent: @Composable () -> Unit, crossinline itemContent: @Composable LazyItemScope.(T) -> Unit, - noinline itemShimmer: @Composable () -> Unit, + noinline itemPlaceholderContent: @Composable () -> Unit, ) { - val (_, typography) = LocalAppearance.current - var items by rememberSaveable(stateSaver = stateSaver) { mutableStateOf(listOf()) } @@ -124,7 +122,7 @@ inline fun ArtistContent( if (hasMore || items.isEmpty()) { ShimmerHost { repeat(if (hasMore) 3 else 8) { - itemShimmer() + itemPlaceholderContent() } } @@ -147,7 +145,7 @@ inline fun ArtistContent( HeaderPlaceholder() repeat(5) { - itemShimmer() + itemPlaceholderContent() } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistOverview.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistOverview.kt index 3ed1e4a..894938d 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistOverview.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistOverview.kt @@ -47,10 +47,10 @@ 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.styling.shimmer -import it.vfsfitvnm.vimusic.ui.views.AlternativeAlbumItem -import it.vfsfitvnm.vimusic.ui.views.AlternativeAlbumItemPlaceholder -import it.vfsfitvnm.vimusic.ui.views.SmallSongItem -import it.vfsfitvnm.vimusic.ui.views.SmallSongItemShimmer +import it.vfsfitvnm.vimusic.ui.views.AlbumItem +import it.vfsfitvnm.vimusic.ui.views.AlbumItemPlaceholder +import it.vfsfitvnm.vimusic.ui.views.SongItem +import it.vfsfitvnm.vimusic.ui.views.SongItemPlaceholder import it.vfsfitvnm.vimusic.utils.asMediaItem import it.vfsfitvnm.vimusic.utils.center import it.vfsfitvnm.vimusic.utils.forcePlay @@ -159,7 +159,7 @@ fun ArtistOverview( } songs.forEach { song -> - SmallSongItem( + SongItem( song = song, thumbnailSizePx = songThumbnailSizePx, onClick = { @@ -209,10 +209,11 @@ fun ArtistOverview( items = albums, key = Innertube.AlbumItem::key ) { album -> - AlternativeAlbumItem( + AlbumItem( album = album, thumbnailSizePx = albumThumbnailSizePx, thumbnailSizeDp = albumThumbnailSizeDp, + alternative = true, modifier = Modifier .clickable( indication = rememberRipple(bounded = true), @@ -259,10 +260,11 @@ fun ArtistOverview( items = singles, key = Innertube.AlbumItem::key ) { album -> - AlternativeAlbumItem( + AlbumItem( album = album, thumbnailSizePx = albumThumbnailSizePx, thumbnailSizeDp = albumThumbnailSizeDp, + alternative = true, modifier = Modifier .clickable( indication = rememberRipple(bounded = true), @@ -279,7 +281,7 @@ fun ArtistOverview( TextPlaceholder(modifier = sectionTextModifier) repeat(5) { - SmallSongItemShimmer( + SongItemPlaceholder( thumbnailSizeDp = songThumbnailSizeDp, ) } @@ -289,7 +291,10 @@ fun ArtistOverview( Row { repeat(2) { - AlternativeAlbumItemPlaceholder(thumbnailSizeDp = albumThumbnailSizeDp) + AlbumItemPlaceholder( + thumbnailSizeDp = albumThumbnailSizeDp, + alternative = true + ) } } } @@ -312,7 +317,7 @@ fun ArtistOverview( TextPlaceholder(modifier = sectionTextModifier) repeat(5) { - SmallSongItemShimmer( + SongItemPlaceholder( thumbnailSizeDp = songThumbnailSizeDp, ) } @@ -322,7 +327,10 @@ fun ArtistOverview( Row { repeat(2) { - AlternativeAlbumItemPlaceholder(thumbnailSizeDp = albumThumbnailSizeDp) + AlbumItemPlaceholder( + thumbnailSizeDp = albumThumbnailSizeDp, + alternative = true + ) } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistScreen.kt index 41377c4..021bede 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistScreen.kt @@ -37,9 +37,9 @@ 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.AlbumItem -import it.vfsfitvnm.vimusic.ui.views.AlbumItemShimmer -import it.vfsfitvnm.vimusic.ui.views.SmallSongItem -import it.vfsfitvnm.vimusic.ui.views.SmallSongItemShimmer +import it.vfsfitvnm.vimusic.ui.views.AlbumItemPlaceholder +import it.vfsfitvnm.vimusic.ui.views.SongItem +import it.vfsfitvnm.vimusic.ui.views.SongItemPlaceholder import it.vfsfitvnm.vimusic.utils.artistScreenTabIndexKey import it.vfsfitvnm.vimusic.utils.asMediaItem import it.vfsfitvnm.vimusic.utils.forcePlay @@ -242,7 +242,7 @@ fun ArtistScreen(browseId: String) { } }, itemContent = { song -> - SmallSongItem( + SongItem( song = song, thumbnailSizePx = thumbnailSizePx, onClick = { @@ -252,8 +252,8 @@ fun ArtistScreen(browseId: String) { } ) }, - itemShimmer = { - SmallSongItemShimmer(thumbnailSizeDp = thumbnailSizeDp) + itemPlaceholderContent = { + SongItemPlaceholder(thumbnailSizeDp = thumbnailSizeDp) } ) } @@ -299,8 +299,8 @@ fun ArtistScreen(browseId: String) { ) ) }, - itemShimmer = { - AlbumItemShimmer(thumbnailSizeDp = thumbnailSizeDp) + itemPlaceholderContent = { + AlbumItemPlaceholder(thumbnailSizeDp = thumbnailSizeDp) } ) } @@ -346,8 +346,8 @@ fun ArtistScreen(browseId: String) { ) ) }, - itemShimmer = { - AlbumItemShimmer(thumbnailSizeDp = thumbnailSizeDp) + itemPlaceholderContent = { + AlbumItemPlaceholder(thumbnailSizeDp = thumbnailSizeDp) } ) } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/home/QuickPicks.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/home/QuickPicks.kt index b1c783d..c8fe42d 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/home/QuickPicks.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/home/QuickPicks.kt @@ -6,14 +6,17 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.BasicText import androidx.compose.foundation.verticalScroll @@ -44,14 +47,13 @@ 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.AlbumItem -import it.vfsfitvnm.vimusic.ui.views.AlbumItemShimmer +import it.vfsfitvnm.vimusic.ui.views.AlbumItemPlaceholder import it.vfsfitvnm.vimusic.ui.views.ArtistItem -import it.vfsfitvnm.vimusic.ui.views.ArtistItemShimmer +import it.vfsfitvnm.vimusic.ui.views.ArtistItemPlaceholder import it.vfsfitvnm.vimusic.ui.views.PlaylistItem -import it.vfsfitvnm.vimusic.ui.views.PlaylistItemShimmer -import it.vfsfitvnm.vimusic.ui.views.SmallSongItem -import it.vfsfitvnm.vimusic.ui.views.SmallSongItemShimmer +import it.vfsfitvnm.vimusic.ui.views.PlaylistItemPlaceholder import it.vfsfitvnm.vimusic.ui.views.SongItem +import it.vfsfitvnm.vimusic.ui.views.SongItemPlaceholder import it.vfsfitvnm.vimusic.utils.asMediaItem import it.vfsfitvnm.vimusic.utils.center import it.vfsfitvnm.vimusic.utils.forcePlay @@ -104,7 +106,7 @@ fun QuickPicks( val songThumbnailSizePx = songThumbnailSizeDp.px val albumThumbnailSizeDp = 108.dp val albumThumbnailSizePx = albumThumbnailSizeDp.px - val artistThumbnailSizeDp = 64.dp + val artistThumbnailSizeDp = 92.dp val artistThumbnailSizePx = artistThumbnailSizeDp.px val playlistThumbnailSizeDp = 108.dp val playlistThumbnailSizePx = playlistThumbnailSizeDp.px @@ -158,7 +160,7 @@ fun QuickPicks( items = related.songs ?: emptyList(), key = Innertube.SongItem::key ) { song -> - SmallSongItem( + SongItem( song = song, thumbnailSizePx = songThumbnailSizePx, onClick = { @@ -181,12 +183,7 @@ fun QuickPicks( modifier = sectionTextModifier ) - LazyHorizontalGrid( - rows = GridCells.Fixed(2), - modifier = Modifier - .fillMaxWidth() - .height((albumThumbnailSizeDp + Dimensions.itemsVerticalPadding * 2) * 2) - ) { + LazyRow { items( items = related.albums ?: emptyList(), key = Innertube.AlbumItem::key @@ -195,13 +192,13 @@ fun QuickPicks( album = album, thumbnailSizePx = albumThumbnailSizePx, thumbnailSizeDp = albumThumbnailSizeDp, + alternative = true, modifier = Modifier .clickable( indication = rememberRipple(bounded = true), interactionSource = remember { MutableInteractionSource() }, onClick = { onAlbumClick(album.key) } ) - .width(itemInHorizontalGridWidth) ) } } @@ -212,12 +209,7 @@ fun QuickPicks( modifier = sectionTextModifier ) - LazyHorizontalGrid( - rows = GridCells.Fixed(1), - modifier = Modifier - .fillMaxWidth() - .height((artistThumbnailSizeDp + Dimensions.itemsVerticalPadding * 2)) - ) { + LazyRow { items( items = related.artists ?: emptyList(), key = Innertube.ArtistItem::key, @@ -226,13 +218,13 @@ fun QuickPicks( artist = artist, thumbnailSizePx = artistThumbnailSizePx, thumbnailSizeDp = artistThumbnailSizeDp, + alternative = true, modifier = Modifier .clickable( indication = rememberRipple(bounded = true), interactionSource = remember { MutableInteractionSource() }, onClick = { onArtistClick(artist.key) } ) - .width(itemInHorizontalGridWidth) ) } } @@ -245,12 +237,7 @@ fun QuickPicks( .padding(top = 24.dp, bottom = 8.dp) ) - LazyHorizontalGrid( - rows = GridCells.Fixed(2), - modifier = Modifier - .fillMaxWidth() - .height((playlistThumbnailSizeDp + Dimensions.itemsVerticalPadding * 2) * 2) - ) { + LazyRow { items( items = related.playlists ?: emptyList(), key = Innertube.PlaylistItem::key, @@ -259,13 +246,13 @@ fun QuickPicks( playlist = playlist, thumbnailSizePx = playlistThumbnailSizePx, thumbnailSizeDp = playlistThumbnailSizeDp, + alternative = true, modifier = Modifier .clickable( indication = rememberRipple(bounded = true), interactionSource = remember { MutableInteractionSource() }, onClick = { onPlaylistClick(playlist.key) } ) - .width(itemInHorizontalGridWidth) ) } } @@ -292,25 +279,42 @@ fun QuickPicks( } ) { repeat(4) { - SmallSongItemShimmer( + SongItemPlaceholder( thumbnailSizeDp = songThumbnailSizeDp, ) } TextPlaceholder(modifier = sectionTextModifier) - repeat(2) { - AlbumItemShimmer(thumbnailSizeDp = albumThumbnailSizeDp) + Row { + repeat(2) { + AlbumItemPlaceholder( + thumbnailSizeDp = albumThumbnailSizeDp, + alternative = true + ) + } } TextPlaceholder(modifier = sectionTextModifier) - ArtistItemShimmer(thumbnailSizeDp = artistThumbnailSizeDp) + Row { + repeat(2) { + ArtistItemPlaceholder( + thumbnailSizeDp = albumThumbnailSizeDp, + alternative = true + ) + } + } TextPlaceholder(modifier = sectionTextModifier) - repeat(2) { - PlaylistItemShimmer(thumbnailSizeDp = playlistThumbnailSizeDp) + Row { + repeat(2) { + PlaylistItemPlaceholder( + thumbnailSizeDp = albumThumbnailSizeDp, + alternative = true + ) + } } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/PlayerBottomSheet.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/PlayerBottomSheet.kt index d6d077b..87046aa 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/PlayerBottomSheet.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/PlayerBottomSheet.kt @@ -57,7 +57,7 @@ import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.onOverlay import it.vfsfitvnm.vimusic.ui.styling.px -import it.vfsfitvnm.vimusic.ui.views.SmallSongItemShimmer +import it.vfsfitvnm.vimusic.ui.views.SongItemPlaceholder import it.vfsfitvnm.vimusic.ui.views.SongItem import it.vfsfitvnm.vimusic.utils.medium import it.vfsfitvnm.vimusic.utils.rememberMediaItemIndex @@ -233,7 +233,7 @@ fun PlayerBottomSheet( .shimmer() ) { repeat(3) { index -> - SmallSongItemShimmer( + SongItemPlaceholder( thumbnailSizeDp = Dimensions.thumbnails.song, modifier = Modifier .alpha(1f - index * 0.125f) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResult.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResult.kt index 62b8fb7..ec141fc 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResult.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResult.kt @@ -48,7 +48,7 @@ inline fun SearchResult( noinline fromMusicShelfRendererContent: (MusicShelfRenderer.Content) -> T?, crossinline onSearchAgain: () -> Unit, crossinline itemContent: @Composable LazyItemScope.(T) -> Unit, - noinline itemShimmer: @Composable BoxScope.() -> Unit, + noinline itemPlaceholderContent: @Composable BoxScope.() -> Unit, ) { val (_, typography) = LocalAppearance.current @@ -163,7 +163,7 @@ inline fun SearchResult( Box( modifier = Modifier .alpha(1f - index * 0.125f), - content = itemShimmer + content = itemPlaceholderContent ) } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResultScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResultScreen.kt index 1f282e8..dd7d28b 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResultScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResultScreen.kt @@ -26,15 +26,15 @@ import it.vfsfitvnm.vimusic.ui.screens.playlistRoute import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.px import it.vfsfitvnm.vimusic.ui.views.AlbumItem -import it.vfsfitvnm.vimusic.ui.views.AlbumItemShimmer +import it.vfsfitvnm.vimusic.ui.views.AlbumItemPlaceholder import it.vfsfitvnm.vimusic.ui.views.ArtistItem -import it.vfsfitvnm.vimusic.ui.views.ArtistItemShimmer +import it.vfsfitvnm.vimusic.ui.views.ArtistItemPlaceholder import it.vfsfitvnm.vimusic.ui.views.PlaylistItem -import it.vfsfitvnm.vimusic.ui.views.PlaylistItemShimmer -import it.vfsfitvnm.vimusic.ui.views.SmallSongItem -import it.vfsfitvnm.vimusic.ui.views.SmallSongItemShimmer +import it.vfsfitvnm.vimusic.ui.views.PlaylistItemPlaceholder +import it.vfsfitvnm.vimusic.ui.views.SongItem +import it.vfsfitvnm.vimusic.ui.views.SongItemPlaceholder import it.vfsfitvnm.vimusic.ui.views.VideoItem -import it.vfsfitvnm.vimusic.ui.views.VideoItemShimmer +import it.vfsfitvnm.vimusic.ui.views.VideoItemPlaceholder import it.vfsfitvnm.vimusic.utils.asMediaItem import it.vfsfitvnm.vimusic.utils.forcePlay import it.vfsfitvnm.vimusic.utils.rememberPreference @@ -91,7 +91,7 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) { stateSaver = InnertubeSongItemListSaver, fromMusicShelfRendererContent = Innertube.SongItem.Companion::from, itemContent = { song -> - SmallSongItem( + SongItem( song = song, thumbnailSizePx = thumbnailSizePx, onClick = { @@ -101,8 +101,8 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) { } ) }, - itemShimmer = { - SmallSongItemShimmer(thumbnailSizeDp = thumbnailSizeDp) + itemPlaceholderContent = { + SongItemPlaceholder(thumbnailSizeDp = thumbnailSizeDp) } ) } @@ -131,8 +131,8 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) { ) }, - itemShimmer = { - AlbumItemShimmer(thumbnailSizeDp = thumbnailSizeDp) + itemPlaceholderContent = { + AlbumItemPlaceholder(thumbnailSizeDp = thumbnailSizeDp) } ) } @@ -160,8 +160,8 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) { ) ) }, - itemShimmer = { - ArtistItemShimmer(thumbnailSizeDp = thumbnailSizeDp) + itemPlaceholderContent = { + ArtistItemPlaceholder(thumbnailSizeDp = thumbnailSizeDp) } ) } @@ -188,8 +188,8 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) { } ) }, - itemShimmer = { - VideoItemShimmer( + itemPlaceholderContent = { + VideoItemPlaceholder( thumbnailHeightDp = thumbnailHeightDp, thumbnailWidthDp = thumbnailWidthDp ) @@ -220,8 +220,8 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) { ) ) }, - itemShimmer = { - PlaylistItemShimmer(thumbnailSizeDp = thumbnailSizeDp) + itemPlaceholderContent = { + PlaylistItemPlaceholder(thumbnailSizeDp = thumbnailSizeDp) } ) } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/YouTubeItems.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/InnertubeItems.kt similarity index 71% rename from app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/YouTubeItems.kt rename to app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/InnertubeItems.kt index 12ffdd7..c8fee72 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/YouTubeItems.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/InnertubeItems.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -43,8 +44,29 @@ import it.vfsfitvnm.vimusic.utils.secondary import it.vfsfitvnm.vimusic.utils.semiBold import it.vfsfitvnm.youtubemusic.Innertube +@ExperimentalAnimationApi @Composable -fun SmallSongItemShimmer( +fun SongItem( + song: Innertube.SongItem, + thumbnailSizePx: Int, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + SongItem( + thumbnailModel = song.thumbnail?.size(thumbnailSizePx), + title = song.info?.name, + authors = song.authors?.joinToString("") { it.name ?: "" }, + durationText = song.durationText, + onClick = onClick, + menuContent = { + NonQueuedMediaItemMenu(mediaItem = song.asMediaItem) + }, + modifier = modifier + ) +} + +@Composable +fun SongItemPlaceholder( thumbnailSizeDp: Dp, modifier: Modifier = Modifier ) { @@ -70,27 +92,6 @@ fun SmallSongItemShimmer( } } -@ExperimentalAnimationApi -@Composable -fun SmallSongItem( - song: Innertube.SongItem, - thumbnailSizePx: Int, - onClick: () -> Unit, - modifier: Modifier = Modifier -) { - SongItem( - thumbnailModel = song.thumbnail?.size(thumbnailSizePx), - title = song.info?.name, - authors = song.authors?.joinToString("") { it.name ?: "" }, - durationText = song.durationText, - onClick = onClick, - menuContent = { - NonQueuedMediaItemMenu(mediaItem = song.asMediaItem) - }, - modifier = modifier - ) -} - @ExperimentalFoundationApi @ExperimentalAnimationApi @Composable @@ -104,9 +105,9 @@ fun VideoItem( val menuState = LocalMenuState.current val (colorPalette, typography, thumbnailShape) = LocalAppearance.current - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), + ItemContainer( + alternative = false, + thumbnailSizeDp = 0.dp, modifier = modifier .combinedClickable( indication = rememberRipple(bounded = true), @@ -118,9 +119,6 @@ fun VideoItem( }, onClick = onClick ) - .fillMaxWidth() - .padding(vertical = Dimensions.itemsVerticalPadding) - .padding(horizontal = 16.dp) ) { Box { AsyncImage( @@ -147,7 +145,7 @@ fun VideoItem( } } - Column { + ItemInfoContainer { BasicText( text = video.info?.name ?: "", style = typography.xs.semiBold, @@ -169,7 +167,7 @@ fun VideoItem( maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier - .padding(top = 8.dp) + .padding(top = 4.dp) ) } } @@ -179,19 +177,17 @@ fun VideoItem( @ExperimentalFoundationApi @ExperimentalAnimationApi @Composable -fun VideoItemShimmer( +fun VideoItemPlaceholder( thumbnailHeightDp: Dp, thumbnailWidthDp: Dp, modifier: Modifier = Modifier ) { val (colorPalette, _, thumbnailShape) = LocalAppearance.current - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), + ItemContainer( + alternative = false, + thumbnailSizeDp = 0.dp, modifier = modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = Dimensions.itemsVerticalPadding) ) { Spacer( modifier = Modifier @@ -199,7 +195,7 @@ fun VideoItemShimmer( .size(width = thumbnailWidthDp, height = thumbnailHeightDp) ) - Column { + ItemInfoContainer { TextPlaceholder() TextPlaceholder() TextPlaceholder( @@ -216,15 +212,14 @@ fun PlaylistItem( thumbnailSizePx: Int, thumbnailSizeDp: Dp, modifier: Modifier = Modifier, + alternative: Boolean = false, ) { val (colorPalette, typography, thumbnailShape) = LocalAppearance.current - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), + ItemContainer( + alternative = alternative, + thumbnailSizeDp = thumbnailSizeDp, modifier = modifier - .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) - .fillMaxWidth() ) { Box { AsyncImage( @@ -251,7 +246,7 @@ fun PlaylistItem( } } - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + ItemInfoContainer { BasicText( text = playlist.info?.name ?: "", style = typography.xs.semiBold, @@ -270,18 +265,17 @@ fun PlaylistItem( } @Composable -fun PlaylistItemShimmer( +fun PlaylistItemPlaceholder( thumbnailSizeDp: Dp, modifier: Modifier = Modifier, + alternative: Boolean = false, ) { val (colorPalette, _, thumbnailShape) = LocalAppearance.current - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), + ItemContainer( + alternative = alternative, + thumbnailSizeDp = thumbnailSizeDp, modifier = modifier - .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) - .fillMaxWidth() ) { Spacer( modifier = Modifier @@ -289,7 +283,7 @@ fun PlaylistItemShimmer( .size(thumbnailSizeDp) ) - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + ItemInfoContainer { TextPlaceholder() TextPlaceholder() } @@ -302,15 +296,14 @@ fun AlbumItem( thumbnailSizePx: Int, thumbnailSizeDp: Dp, modifier: Modifier = Modifier, + alternative: Boolean = false ) { val (_, typography, thumbnailShape) = LocalAppearance.current - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), + ItemContainer( + alternative = alternative, + thumbnailSizeDp = thumbnailSizeDp, modifier = modifier - .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) - .fillMaxWidth() ) { AsyncImage( model = album.thumbnail?.size(thumbnailSizePx), @@ -321,97 +314,22 @@ fun AlbumItem( .size(thumbnailSizeDp) ) - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + ItemInfoContainer { BasicText( text = album.info?.name ?: "", style = typography.xs.semiBold, - maxLines = 2, + maxLines = if (alternative) 1 else 2, overflow = TextOverflow.Ellipsis, ) - BasicText( - text = album.authors?.joinToString("") { it.name ?: "" } ?: "", - style = typography.xs.semiBold.secondary, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - ) - - album.year?.let { year -> + if (!alternative) { BasicText( - text = year, - style = typography.xxs.semiBold.secondary, - maxLines = 1, + text = album.authors?.joinToString("") { it.name ?: "" } ?: "", + style = typography.xs.semiBold.secondary, + maxLines = 2, overflow = TextOverflow.Ellipsis, - modifier = Modifier - .padding(top = 8.dp) ) } - } - } -} - -@Composable -fun AlbumItemShimmer( - thumbnailSizeDp: Dp, - modifier: Modifier = Modifier, -) { - val (colorPalette, _, thumbnailShape) = LocalAppearance.current - - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), - modifier = modifier - .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) - .fillMaxWidth() - ) { - Spacer( - modifier = Modifier - .background(color = colorPalette.shimmer, shape = thumbnailShape) - .size(thumbnailSizeDp) - ) - - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { - TextPlaceholder() - TextPlaceholder() - TextPlaceholder( - modifier = Modifier - .padding(top = 8.dp) - ) - } - } -} - -@Composable -fun AlternativeAlbumItem( - album: Innertube.AlbumItem, - thumbnailSizePx: Int, - thumbnailSizeDp: Dp, - modifier: Modifier = Modifier, -) { - val (_, typography, thumbnailShape) = LocalAppearance.current - - Column( - verticalArrangement = Arrangement.spacedBy(12.dp), - modifier = modifier - .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) - .width(thumbnailSizeDp) - ) { - AsyncImage( - model = album.thumbnail?.size(thumbnailSizePx), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .clip(thumbnailShape) - .size(thumbnailSizeDp) - ) - - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { - BasicText( - text = album.info?.name ?: "", - style = typography.xs.semiBold, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) BasicText( text = album.year ?: "", @@ -419,23 +337,24 @@ fun AlternativeAlbumItem( maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier + .padding(top = 4.dp) ) } } } @Composable -fun AlternativeAlbumItemPlaceholder( +fun AlbumItemPlaceholder( thumbnailSizeDp: Dp, modifier: Modifier = Modifier, + alternative: Boolean = false ) { val (colorPalette, _, thumbnailShape) = LocalAppearance.current - Column( - verticalArrangement = Arrangement.spacedBy(12.dp), + ItemContainer( + alternative = alternative, + thumbnailSizeDp = thumbnailSizeDp, modifier = modifier - .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) - .width(thumbnailSizeDp) ) { Spacer( modifier = Modifier @@ -443,9 +362,17 @@ fun AlternativeAlbumItemPlaceholder( .size(thumbnailSizeDp) ) - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { - TextPlaceholder() + ItemInfoContainer { TextPlaceholder() + + if (!alternative) { + TextPlaceholder() + } + + TextPlaceholder( + modifier = Modifier + .padding(top = 4.dp) + ) } } } @@ -456,15 +383,15 @@ fun ArtistItem( thumbnailSizePx: Int, thumbnailSizeDp: Dp, modifier: Modifier = Modifier, + alternative: Boolean = false, ) { val (_, typography) = LocalAppearance.current - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), + ItemContainer( + alternative = alternative, + thumbnailSizeDp = thumbnailSizeDp, + horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier - .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) - .fillMaxWidth() ) { AsyncImage( model = artist.thumbnail?.size(thumbnailSizePx), @@ -474,11 +401,13 @@ fun ArtistItem( .size(thumbnailSizeDp) ) - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + ItemInfoContainer( + horizontalAlignment = if (alternative) Alignment.CenterHorizontally else Alignment.Start, + ) { BasicText( text = artist.info?.name ?: "", style = typography.xs.semiBold, - maxLines = 2, + maxLines = if (alternative) 1 else 2, overflow = TextOverflow.Ellipsis ) @@ -497,18 +426,18 @@ fun ArtistItem( } @Composable -fun ArtistItemShimmer( +fun ArtistItemPlaceholder( thumbnailSizeDp: Dp, modifier: Modifier = Modifier, + alternative: Boolean = false, ) { val (colorPalette) = LocalAppearance.current - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), + ItemContainer( + alternative = alternative, + thumbnailSizeDp = thumbnailSizeDp, + horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier - .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) - .fillMaxWidth() ) { Spacer( modifier = Modifier @@ -516,7 +445,9 @@ fun ArtistItemShimmer( .size(thumbnailSizeDp) ) - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + ItemInfoContainer( + horizontalAlignment = if (alternative) Alignment.CenterHorizontally else Alignment.Start, + ) { TextPlaceholder() TextPlaceholder( modifier = Modifier @@ -525,3 +456,49 @@ fun ArtistItemShimmer( } } } + +@Composable +private inline fun ItemContainer( + alternative: Boolean, + thumbnailSizeDp: Dp, + modifier: Modifier = Modifier, + horizontalAlignment: Alignment.Horizontal = Alignment.Start, + verticalAlignment: Alignment.Vertical = Alignment.CenterVertically, + content: @Composable () -> Unit +) { + if (alternative) { + Column( + horizontalAlignment = horizontalAlignment, + verticalArrangement = Arrangement.spacedBy(12.dp), + modifier = modifier + .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) + .width(thumbnailSizeDp) + ) { + content() + } + } else { + Row( + verticalAlignment = verticalAlignment, + horizontalArrangement = Arrangement.spacedBy(12.dp), + modifier = modifier + .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) + .fillMaxWidth() + ) { + content() + } + } +} + +@Composable +private inline fun ItemInfoContainer( + modifier: Modifier = Modifier, + horizontalAlignment: Alignment.Horizontal = Alignment.Start, + content: @Composable ColumnScope.() -> Unit +) { + Column( + horizontalAlignment = horizontalAlignment, + verticalArrangement = Arrangement.spacedBy(4.dp), + modifier = modifier, + content = content + ) +} diff --git a/innertube/src/main/kotlin/it/vfsfitvnm/youtubemusic/Innertube.kt b/innertube/src/main/kotlin/it/vfsfitvnm/youtubemusic/Innertube.kt index a0a5a42..002f44b 100644 --- a/innertube/src/main/kotlin/it/vfsfitvnm/youtubemusic/Innertube.kt +++ b/innertube/src/main/kotlin/it/vfsfitvnm/youtubemusic/Innertube.kt @@ -57,8 +57,6 @@ object Innertube { internal const val musicTwoRowItemRendererMask = "musicTwoRowItemRenderer(thumbnailRenderer,title,subtitle,navigationEndpoint)" const val playlistPanelVideoRendererMask = "playlistPanelVideoRenderer(title,navigationEndpoint,longBylineText,shortBylineText,thumbnail,lengthText)" -// contents.singleColumnBrowseResultsRenderer.tabs.tabRenderer.content.sectionListRenderer.contents(musicPlaylistShelfRenderer(continuations,contents.musicResponsiveListItemRenderer(flexColumns,fixedColumns,thumbnail)),gridRenderer(continuations,items.musicTwoRowItemRenderer(thumbnailRenderer,title,subtitle,navigationEndpoint))) - internal fun HttpRequestBuilder.mask(value: String = "*") = header("X-Goog-FieldMask", value) diff --git a/innertube/src/main/kotlin/it/vfsfitvnm/youtubemusic/requests/RelatedPage.kt b/innertube/src/main/kotlin/it/vfsfitvnm/youtubemusic/requests/RelatedPage.kt index c2ad8ce..f50f8cf 100644 --- a/innertube/src/main/kotlin/it/vfsfitvnm/youtubemusic/requests/RelatedPage.kt +++ b/innertube/src/main/kotlin/it/vfsfitvnm/youtubemusic/requests/RelatedPage.kt @@ -54,7 +54,8 @@ suspend fun Innertube.relatedPage(body: NextBody) = runCatchingNonCancellable { ?.musicCarouselShelfRenderer ?.contents ?.mapNotNull(MusicCarouselShelfRenderer.Content::musicTwoRowItemRenderer) - ?.mapNotNull(Innertube.PlaylistItem::from), + ?.mapNotNull(Innertube.PlaylistItem::from) + ?.sortedByDescending { it.channel?.name == "YouTube Music" }, albums = sectionListRenderer ?.findSectionByStrapline("MORE FROM") ?.musicCarouselShelfRenderer