Add quick picks tab (#172)
This commit is contained in:
@@ -276,7 +276,7 @@ fun AlbumOverview(
|
|||||||
) {
|
) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "An error has occurred.",
|
text = "An error has occurred.",
|
||||||
style = typography.s.medium.secondary.center,
|
style = typography.s.secondary.center,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.Center)
|
.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import it.vfsfitvnm.vimusic.ui.screens.builtinplaylist.BuiltInPlaylistScreen
|
|||||||
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.localPlaylistRoute
|
import it.vfsfitvnm.vimusic.ui.screens.localPlaylistRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.localplaylist.LocalPlaylistScreen
|
import it.vfsfitvnm.vimusic.ui.screens.localplaylist.LocalPlaylistScreen
|
||||||
|
import it.vfsfitvnm.vimusic.ui.screens.playlistRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.search.SearchScreen
|
import it.vfsfitvnm.vimusic.ui.screens.search.SearchScreen
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.searchResultRoute
|
import it.vfsfitvnm.vimusic.ui.screens.searchResultRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.searchRoute
|
import it.vfsfitvnm.vimusic.ui.screens.searchRoute
|
||||||
@@ -77,7 +78,7 @@ fun HomeScreen(onPlaylistUrl: (String) -> Unit) {
|
|||||||
host {
|
host {
|
||||||
val (tabIndex, onTabChanged) = rememberPreference(
|
val (tabIndex, onTabChanged) = rememberPreference(
|
||||||
homeScreenTabIndexKey,
|
homeScreenTabIndexKey,
|
||||||
defaultValue = 0
|
defaultValue = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -99,6 +100,8 @@ fun HomeScreen(onPlaylistUrl: (String) -> Unit) {
|
|||||||
when (currentTabIndex) {
|
when (currentTabIndex) {
|
||||||
0 -> QuickPicks(
|
0 -> QuickPicks(
|
||||||
onAlbumClick = { albumRoute(it) },
|
onAlbumClick = { albumRoute(it) },
|
||||||
|
onArtistClick = { artistRoute(it) },
|
||||||
|
onPlaylistClick = { playlistRoute(it) },
|
||||||
)
|
)
|
||||||
1 -> HomeSongList()
|
1 -> HomeSongList()
|
||||||
2 -> HomePlaylistList(
|
2 -> HomePlaylistList(
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.screens.home
|
package it.vfsfitvnm.vimusic.ui.screens.home
|
||||||
|
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
import androidx.compose.animation.animateContentSize
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
|
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
|
||||||
import androidx.compose.foundation.lazy.grid.items
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.text.BasicText
|
import androidx.compose.foundation.text.BasicText
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
@@ -28,12 +23,13 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.drawWithContent
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.graphics.BlendMode
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil.compose.AsyncImage
|
import com.valentinilk.shimmer.shimmer
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues
|
import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||||
@@ -43,19 +39,27 @@ import it.vfsfitvnm.vimusic.savers.nullableSaver
|
|||||||
import it.vfsfitvnm.vimusic.savers.resultSaver
|
import it.vfsfitvnm.vimusic.savers.resultSaver
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.NonQueuedMediaItemMenu
|
import it.vfsfitvnm.vimusic.ui.components.themed.NonQueuedMediaItemMenu
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.albumRoute
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.ui.views.AlbumItem
|
import it.vfsfitvnm.vimusic.ui.views.AlbumItem
|
||||||
|
import it.vfsfitvnm.vimusic.ui.views.AlbumItemShimmer
|
||||||
|
import it.vfsfitvnm.vimusic.ui.views.ArtistItem
|
||||||
|
import it.vfsfitvnm.vimusic.ui.views.ArtistItemShimmer
|
||||||
|
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.SmallSongItem
|
||||||
|
import it.vfsfitvnm.vimusic.ui.views.SmallSongItemShimmer
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||||
|
import it.vfsfitvnm.vimusic.utils.center
|
||||||
import it.vfsfitvnm.vimusic.utils.forcePlay
|
import it.vfsfitvnm.vimusic.utils.forcePlay
|
||||||
import it.vfsfitvnm.vimusic.utils.produceSaveableOneShotState
|
import it.vfsfitvnm.vimusic.utils.produceSaveableOneShotState
|
||||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||||
import it.vfsfitvnm.youtubemusic.YouTube
|
import it.vfsfitvnm.youtubemusic.YouTube
|
||||||
import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint
|
import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -66,9 +70,11 @@ import kotlinx.coroutines.flow.flowOn
|
|||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun QuickPicks(
|
fun QuickPicks(
|
||||||
onAlbumClick: (String) -> Unit
|
onAlbumClick: (String) -> Unit,
|
||||||
|
onArtistClick: (String) -> Unit,
|
||||||
|
onPlaylistClick: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val (colorPalette, typography, thumbnailShape) = LocalAppearance.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
val trending by produceSaveableState(
|
val trending by produceSaveableState(
|
||||||
@@ -87,7 +93,6 @@ fun QuickPicks(
|
|||||||
stateSaver = resultSaver(nullableSaver(YouTubeRelatedSaver)),
|
stateSaver = resultSaver(nullableSaver(YouTubeRelatedSaver)),
|
||||||
trending?.id
|
trending?.id
|
||||||
) {
|
) {
|
||||||
println("trendingVideoId: ${trending?.id}")
|
|
||||||
trending?.id?.let { trendingVideoId ->
|
trending?.id?.let { trendingVideoId ->
|
||||||
value = YouTube.related(trendingVideoId)?.map { related ->
|
value = YouTube.related(trendingVideoId)?.map { related ->
|
||||||
related?.copy(
|
related?.copy(
|
||||||
@@ -110,71 +115,96 @@ fun QuickPicks(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val songThumbnailSizePx = Dimensions.thumbnails.song.px
|
val songThumbnailSizeDp = Dimensions.thumbnails.song
|
||||||
|
val songThumbnailSizePx = songThumbnailSizeDp.px
|
||||||
val albumThumbnailSizeDp = 108.dp
|
val albumThumbnailSizeDp = 108.dp
|
||||||
val albumThumbnailSizePx = albumThumbnailSizeDp.px
|
val albumThumbnailSizePx = albumThumbnailSizeDp.px
|
||||||
// val itemInHorizontalGridWidth = (LocalConfiguration.current.screenWidthDp.dp) * 0.8f
|
val artistThumbnailSizeDp = 64.dp
|
||||||
|
val artistThumbnailSizePx = artistThumbnailSizeDp.px
|
||||||
|
val playlistThumbnailSizeDp = 108.dp
|
||||||
|
val playlistThumbnailSizePx = playlistThumbnailSizeDp.px
|
||||||
|
|
||||||
LazyColumn(
|
val sectionTextModifier = Modifier
|
||||||
contentPadding = LocalPlayerAwarePaddingValues.current,
|
.padding(horizontal = 16.dp)
|
||||||
modifier = Modifier
|
.padding(top = 24.dp, bottom = 8.dp)
|
||||||
.background(colorPalette.background0)
|
|
||||||
.fillMaxSize()
|
BoxWithConstraints {
|
||||||
) {
|
val itemInHorizontalGridWidth = maxWidth * 0.9f
|
||||||
item(
|
|
||||||
key = "header",
|
Column(
|
||||||
contentType = 0
|
modifier = Modifier
|
||||||
|
.background(colorPalette.background0)
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(LocalPlayerAwarePaddingValues.current)
|
||||||
) {
|
) {
|
||||||
Header(title = "Quick picks")
|
Header(title = "Quick picks")
|
||||||
}
|
|
||||||
|
|
||||||
trending?.let { song ->
|
relatedResult?.getOrNull()?.let { related ->
|
||||||
item(key = song.id) {
|
LazyHorizontalGrid(
|
||||||
SongItem(
|
rows = GridCells.Fixed(4),
|
||||||
song = song,
|
modifier = Modifier
|
||||||
thumbnailSizePx = songThumbnailSizePx,
|
.fillMaxWidth()
|
||||||
onClick = {
|
.height((songThumbnailSizeDp + Dimensions.itemsVerticalPadding * 2) * 4)
|
||||||
val mediaItem = song.asMediaItem
|
) {
|
||||||
binder?.stopRadio()
|
trending?.let { song ->
|
||||||
binder?.player?.forcePlay(mediaItem)
|
item(key = song.id) {
|
||||||
binder?.setupRadio(
|
SongItem(
|
||||||
NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId)
|
thumbnailModel = song.thumbnailUrl?.thumbnail(songThumbnailSizePx),
|
||||||
)
|
title = song.title,
|
||||||
},
|
authors = song.artistsText,
|
||||||
menuContent = {
|
durationText = null,
|
||||||
NonQueuedMediaItemMenu(mediaItem = song.asMediaItem)
|
menuContent = { NonQueuedMediaItemMenu(mediaItem = song.asMediaItem) },
|
||||||
|
onClick = {
|
||||||
|
val mediaItem = song.asMediaItem
|
||||||
|
binder?.stopRadio()
|
||||||
|
binder?.player?.forcePlay(mediaItem)
|
||||||
|
binder?.setupRadio(
|
||||||
|
NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.width(itemInHorizontalGridWidth)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
relatedResult?.getOrNull()?.let { related ->
|
items(
|
||||||
items(
|
items = related.songs ?: emptyList(),
|
||||||
items = related.songs?.take(6) ?: emptyList(),
|
key = YouTube.Item.Song::key
|
||||||
key = YouTube.Item::key
|
) { song ->
|
||||||
) { song ->
|
SmallSongItem(
|
||||||
SmallSongItem(
|
song = song,
|
||||||
song = song,
|
thumbnailSizePx = songThumbnailSizePx,
|
||||||
thumbnailSizePx = songThumbnailSizePx,
|
onClick = {
|
||||||
onClick = {
|
val mediaItem = song.asMediaItem
|
||||||
val mediaItem = song.asMediaItem
|
binder?.stopRadio()
|
||||||
binder?.stopRadio()
|
binder?.player?.forcePlay(mediaItem)
|
||||||
binder?.player?.forcePlay(mediaItem)
|
binder?.setupRadio(
|
||||||
binder?.setupRadio(
|
NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId)
|
||||||
NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId)
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.width(itemInHorizontalGridWidth)
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
item(
|
BasicText(
|
||||||
key = "albums",
|
text = "Related albums",
|
||||||
contentType = "LazyRow"
|
style = typography.m.semiBold,
|
||||||
) {
|
modifier = sectionTextModifier
|
||||||
LazyRow {
|
)
|
||||||
|
|
||||||
|
LazyHorizontalGrid(
|
||||||
|
rows = GridCells.Fixed(2),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height((albumThumbnailSizeDp + Dimensions.itemsVerticalPadding * 2) * 2)
|
||||||
|
) {
|
||||||
items(
|
items(
|
||||||
items = related.albums ?: emptyList(),
|
items = related.albums ?: emptyList(),
|
||||||
key = YouTube.Item::key
|
key = YouTube.Item.Album::key
|
||||||
) { album ->
|
) { album ->
|
||||||
AlbumItem(
|
AlbumItem(
|
||||||
album = album,
|
album = album,
|
||||||
@@ -186,28 +216,117 @@ fun QuickPicks(
|
|||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
onClick = { onAlbumClick(album.key) }
|
onClick = { onAlbumClick(album.key) }
|
||||||
)
|
)
|
||||||
.fillMaxWidth()
|
.width(itemInHorizontalGridWidth)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
items(
|
BasicText(
|
||||||
items = related.songs?.drop(6) ?: emptyList(),
|
text = "Similar artists",
|
||||||
key = YouTube.Item::key
|
style = typography.m.semiBold,
|
||||||
) { song ->
|
modifier = sectionTextModifier
|
||||||
SmallSongItem(
|
|
||||||
song = song,
|
|
||||||
thumbnailSizePx = songThumbnailSizePx,
|
|
||||||
onClick = {
|
|
||||||
val mediaItem = song.asMediaItem
|
|
||||||
binder?.stopRadio()
|
|
||||||
binder?.player?.forcePlay(mediaItem)
|
|
||||||
binder?.setupRadio(
|
|
||||||
NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
LazyHorizontalGrid(
|
||||||
|
rows = GridCells.Fixed(1),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height((artistThumbnailSizeDp + Dimensions.itemsVerticalPadding * 2))
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
items = related.artists ?: emptyList(),
|
||||||
|
key = YouTube.Item.Artist::key,
|
||||||
|
) { artist ->
|
||||||
|
ArtistItem(
|
||||||
|
artist = artist,
|
||||||
|
thumbnailSizePx = artistThumbnailSizePx,
|
||||||
|
thumbnailSizeDp = artistThumbnailSizeDp,
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable(
|
||||||
|
indication = rememberRipple(bounded = true),
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
onClick = { onArtistClick(artist.key) }
|
||||||
|
)
|
||||||
|
.width(itemInHorizontalGridWidth)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicText(
|
||||||
|
text = "Playlists you might like",
|
||||||
|
style = typography.m.semiBold,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.padding(top = 24.dp, bottom = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
LazyHorizontalGrid(
|
||||||
|
rows = GridCells.Fixed(2),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height((playlistThumbnailSizeDp + Dimensions.itemsVerticalPadding * 2) * 2)
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
items = related.playlists ?: emptyList(),
|
||||||
|
key = YouTube.Item.Playlist::key,
|
||||||
|
) { playlist ->
|
||||||
|
PlaylistItem(
|
||||||
|
playlist = playlist,
|
||||||
|
thumbnailSizePx = playlistThumbnailSizePx,
|
||||||
|
thumbnailSizeDp = playlistThumbnailSizeDp,
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable(
|
||||||
|
indication = rememberRipple(bounded = true),
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
onClick = { onPlaylistClick(playlist.key) }
|
||||||
|
)
|
||||||
|
.width(itemInHorizontalGridWidth)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: relatedResult?.exceptionOrNull()?.let {
|
||||||
|
BasicText(
|
||||||
|
text = "An error has occurred",
|
||||||
|
style = typography.s.secondary.center,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.padding(all = 16.dp)
|
||||||
|
)
|
||||||
|
} ?: Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.shimmer()
|
||||||
|
.graphicsLayer(alpha = 0.99f)
|
||||||
|
.drawWithContent {
|
||||||
|
drawContent()
|
||||||
|
drawRect(
|
||||||
|
brush = Brush.verticalGradient(
|
||||||
|
listOf(Color.Black, Color.Transparent)
|
||||||
|
),
|
||||||
|
blendMode = BlendMode.DstIn
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
repeat(4) {
|
||||||
|
SmallSongItemShimmer(
|
||||||
|
thumbnailSizeDp = songThumbnailSizeDp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TextPlaceholder(modifier = sectionTextModifier)
|
||||||
|
|
||||||
|
repeat(2) {
|
||||||
|
AlbumItemShimmer(thumbnailSizeDp = albumThumbnailSizeDp)
|
||||||
|
}
|
||||||
|
|
||||||
|
TextPlaceholder(modifier = sectionTextModifier)
|
||||||
|
|
||||||
|
ArtistItemShimmer(thumbnailSizeDp = artistThumbnailSizeDp)
|
||||||
|
|
||||||
|
TextPlaceholder(modifier = sectionTextModifier)
|
||||||
|
|
||||||
|
repeat(2) {
|
||||||
|
PlaylistItemShimmer(thumbnailSizeDp = playlistThumbnailSizeDp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ fun PlaylistSongList(
|
|||||||
) {
|
) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "An error has occurred.\nTap to retry",
|
text = "An error has occurred.\nTap to retry",
|
||||||
style = typography.s.medium.secondary.center,
|
style = typography.s.secondary.center,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.Center)
|
.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ fun OnlineSearch(
|
|||||||
) {
|
) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "An error has occurred.",
|
text = "An error has occurred.",
|
||||||
style = typography.s.medium.secondary.center,
|
style = typography.s.secondary.center,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.Center)
|
.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package it.vfsfitvnm.vimusic.utils
|
package it.vfsfitvnm.vimusic.utils
|
||||||
|
|
||||||
class RingBuffer<T>(val size: Int, init: (index: Int) -> T) {
|
class RingBuffer<T>(val size: Int, init: (index: Int) -> T) {
|
||||||
private val list = MutableList(2, init)
|
private val list = MutableList(size, init)
|
||||||
|
|
||||||
private var index = 0
|
private var index = 0
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user