Redesign BuiltInPlaylistScreen (#172)
This commit is contained in:
parent
0d3ce95c80
commit
acc2768eb4
4 changed files with 213 additions and 209 deletions
|
@ -1,207 +0,0 @@
|
|||
package it.vfsfitvnm.vimusic.ui.screens
|
||||
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
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.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.text.BasicText
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import it.vfsfitvnm.route.RouteHandler
|
||||
import it.vfsfitvnm.vimusic.Database
|
||||
import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues
|
||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.enums.BuiltInPlaylist
|
||||
import it.vfsfitvnm.vimusic.models.DetailedSong
|
||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.InFavoritesMediaItemMenu
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.InHistoryMediaItemMenu
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Menu
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.MenuEntry
|
||||
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.SongItem
|
||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||
import it.vfsfitvnm.vimusic.utils.enqueue
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayFromBeginning
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@ExperimentalAnimationApi
|
||||
@Composable
|
||||
fun BuiltInPlaylistScreen(builtInPlaylist: BuiltInPlaylist) {
|
||||
val lazyListState = rememberLazyListState()
|
||||
|
||||
RouteHandler(listenToGlobalEmitter = true) {
|
||||
globalRoutes()
|
||||
|
||||
host {
|
||||
val menuState = LocalMenuState.current
|
||||
|
||||
val binder = LocalPlayerServiceBinder.current
|
||||
val (colorPalette, typography) = LocalAppearance.current
|
||||
|
||||
val thumbnailSize = Dimensions.thumbnails.song.px
|
||||
|
||||
val songs by remember(binder?.cache, builtInPlaylist) {
|
||||
when (builtInPlaylist) {
|
||||
BuiltInPlaylist.Favorites -> Database.favorites()
|
||||
BuiltInPlaylist.Offline -> Database.songsWithContentLength().map { songs ->
|
||||
songs.filter { song ->
|
||||
song.contentLength?.let {
|
||||
binder?.cache?.isCached(song.id, 0, song.contentLength)
|
||||
} ?: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
||||
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
contentPadding = LocalPlayerAwarePaddingValues.current,
|
||||
modifier = Modifier
|
||||
.background(colorPalette.background0)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
item {
|
||||
TopAppBar(
|
||||
modifier = Modifier
|
||||
.height(52.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.chevron_back),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable(onClick = pop)
|
||||
.padding(vertical = 8.dp, horizontal = 16.dp)
|
||||
.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(top = 16.dp, bottom = 8.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
BasicText(
|
||||
text = when (builtInPlaylist) {
|
||||
BuiltInPlaylist.Favorites -> "Favorites"
|
||||
BuiltInPlaylist.Offline -> "Offline"
|
||||
},
|
||||
style = typography.m.semiBold
|
||||
)
|
||||
|
||||
BasicText(
|
||||
text = "${songs.size} songs",
|
||||
style = typography.xxs.semiBold.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.zIndex(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.shuffle),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable(enabled = songs.isNotEmpty()) {
|
||||
binder?.stopRadio()
|
||||
binder?.player?.forcePlayFromBeginning(
|
||||
songs
|
||||
.shuffled()
|
||||
.map(DetailedSong::asMediaItem)
|
||||
)
|
||||
}
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ellipsis_horizontal),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
menuState.display {
|
||||
Menu {
|
||||
MenuEntry(
|
||||
icon = R.drawable.enqueue,
|
||||
text = "Enqueue",
|
||||
isEnabled = songs.isNotEmpty(),
|
||||
onClick = {
|
||||
menuState.hide()
|
||||
binder?.player?.enqueue(songs.map(DetailedSong::asMediaItem))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
itemsIndexed(
|
||||
items = songs,
|
||||
key = { _, song -> song.id },
|
||||
contentType = { _, song -> song },
|
||||
) { index, song ->
|
||||
SongItem(
|
||||
song = song,
|
||||
thumbnailSize = thumbnailSize,
|
||||
onClick = {
|
||||
binder?.stopRadio()
|
||||
binder?.player?.forcePlayAtIndex(
|
||||
songs.map(DetailedSong::asMediaItem),
|
||||
index
|
||||
)
|
||||
},
|
||||
menuContent = {
|
||||
when (builtInPlaylist) {
|
||||
BuiltInPlaylist.Favorites -> InFavoritesMediaItemMenu(song = song)
|
||||
BuiltInPlaylist.Offline -> InHistoryMediaItemMenu(song = song)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package it.vfsfitvnm.vimusic.ui.screens.builtinplaylist
|
||||
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
|
||||
import it.vfsfitvnm.route.RouteHandler
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.enums.BuiltInPlaylist
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Scaffold
|
||||
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
||||
|
||||
@ExperimentalAnimationApi
|
||||
@Composable
|
||||
fun BuiltInPlaylistScreen(builtInPlaylist: BuiltInPlaylist) {
|
||||
val saveableStateHolder = rememberSaveableStateHolder()
|
||||
|
||||
val (tabIndex, onTabIndexChanged) = rememberSaveable {
|
||||
mutableStateOf(when (builtInPlaylist) {
|
||||
BuiltInPlaylist.Favorites -> 0
|
||||
BuiltInPlaylist.Offline -> 1
|
||||
})
|
||||
}
|
||||
|
||||
RouteHandler(listenToGlobalEmitter = true) {
|
||||
globalRoutes()
|
||||
|
||||
host {
|
||||
Scaffold(
|
||||
topIconButtonId = R.drawable.chevron_back,
|
||||
onTopIconButtonClick = pop,
|
||||
tabIndex = tabIndex,
|
||||
onTabChanged = onTabIndexChanged,
|
||||
tabColumnContent = { Item ->
|
||||
Item(0, "Favorites", R.drawable.heart)
|
||||
Item(1, "Offline", R.drawable.airplane)
|
||||
}
|
||||
) { currentTabIndex ->
|
||||
saveableStateHolder.SaveableStateProvider(key = currentTabIndex) {
|
||||
when (currentTabIndex) {
|
||||
0 -> BuiltInPlaylistSongList(builtInPlaylist = BuiltInPlaylist.Favorites)
|
||||
1 -> BuiltInPlaylistSongList(builtInPlaylist = BuiltInPlaylist.Offline)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package it.vfsfitvnm.vimusic.ui.screens.builtinplaylist
|
||||
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicText
|
||||
import androidx.compose.runtime.Composable
|
||||
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.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import it.vfsfitvnm.vimusic.Database
|
||||
import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues
|
||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.enums.BuiltInPlaylist
|
||||
import it.vfsfitvnm.vimusic.models.DetailedSong
|
||||
import it.vfsfitvnm.vimusic.savers.DetailedSongListSaver
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.InFavoritesMediaItemMenu
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.InHistoryMediaItemMenu
|
||||
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.SongItem
|
||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||
import it.vfsfitvnm.vimusic.utils.enqueue
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayFromBeginning
|
||||
import it.vfsfitvnm.vimusic.utils.medium
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@ExperimentalAnimationApi
|
||||
@Composable
|
||||
fun BuiltInPlaylistSongList(builtInPlaylist: BuiltInPlaylist) {
|
||||
val (colorPalette, typography) = LocalAppearance.current
|
||||
val binder = LocalPlayerServiceBinder.current
|
||||
|
||||
val songs by produceSaveableState(
|
||||
initialValue = emptyList(),
|
||||
stateSaver = DetailedSongListSaver
|
||||
) {
|
||||
when (builtInPlaylist) {
|
||||
BuiltInPlaylist.Favorites -> Database
|
||||
.favorites()
|
||||
.flowOn(Dispatchers.IO)
|
||||
BuiltInPlaylist.Offline -> Database
|
||||
.songsWithContentLength()
|
||||
.flowOn(Dispatchers.IO)
|
||||
.map { songs ->
|
||||
songs.filter { song ->
|
||||
song.contentLength?.let {
|
||||
binder?.cache?.isCached(song.id, 0, song.contentLength)
|
||||
} ?: false
|
||||
}
|
||||
}
|
||||
}.collect { value = it }
|
||||
}
|
||||
|
||||
val thumbnailSize = Dimensions.thumbnails.song.px
|
||||
|
||||
Box {
|
||||
LazyColumn(
|
||||
contentPadding = LocalPlayerAwarePaddingValues.current,
|
||||
modifier = Modifier
|
||||
.background(colorPalette.background0)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
item(
|
||||
key = "header",
|
||||
contentType = 0
|
||||
) {
|
||||
Header(
|
||||
title = when (builtInPlaylist) {
|
||||
BuiltInPlaylist.Favorites -> "Favorites"
|
||||
BuiltInPlaylist.Offline -> "Offline"
|
||||
}
|
||||
) {
|
||||
BasicText(
|
||||
text = "Enqueue",
|
||||
style = typography.xxs.medium,
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.clickable(enabled = songs.isNotEmpty()) {
|
||||
binder?.player?.enqueue(songs.map(DetailedSong::asMediaItem))
|
||||
}
|
||||
.background(colorPalette.background2)
|
||||
.padding(all = 8.dp)
|
||||
.padding(horizontal = 8.dp)
|
||||
)
|
||||
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
itemsIndexed(
|
||||
items = songs,
|
||||
key = { _, song -> song.id },
|
||||
contentType = { _, song -> song },
|
||||
) { index, song ->
|
||||
SongItem(
|
||||
song = song,
|
||||
thumbnailSize = thumbnailSize,
|
||||
onClick = {
|
||||
binder?.stopRadio()
|
||||
binder?.player?.forcePlayAtIndex(
|
||||
songs.map(DetailedSong::asMediaItem),
|
||||
index
|
||||
)
|
||||
},
|
||||
menuContent = {
|
||||
when (builtInPlaylist) {
|
||||
BuiltInPlaylist.Favorites -> InFavoritesMediaItemMenu(song = song)
|
||||
BuiltInPlaylist.Offline -> InHistoryMediaItemMenu(song = song)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomEnd)
|
||||
.padding(all = 16.dp)
|
||||
.padding(LocalPlayerAwarePaddingValues.current)
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.clickable(enabled = songs.isNotEmpty()) {
|
||||
binder?.stopRadio()
|
||||
binder?.player?.forcePlayFromBeginning(songs.shuffled().map(DetailedSong::asMediaItem))
|
||||
}
|
||||
.background(colorPalette.background2)
|
||||
.size(62.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.shuffle),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(20.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,15 +11,15 @@ import it.vfsfitvnm.vimusic.R
|
|||
import it.vfsfitvnm.vimusic.models.SearchQuery
|
||||
import it.vfsfitvnm.vimusic.query
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Scaffold
|
||||
import it.vfsfitvnm.vimusic.ui.screens.BuiltInPlaylistScreen
|
||||
import it.vfsfitvnm.vimusic.ui.screens.IntentUriScreen
|
||||
import it.vfsfitvnm.vimusic.ui.screens.localplaylist.LocalPlaylistScreen
|
||||
import it.vfsfitvnm.vimusic.ui.screens.albumRoute
|
||||
import it.vfsfitvnm.vimusic.ui.screens.artistRoute
|
||||
import it.vfsfitvnm.vimusic.ui.screens.builtInPlaylistRoute
|
||||
import it.vfsfitvnm.vimusic.ui.screens.builtinplaylist.BuiltInPlaylistScreen
|
||||
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
||||
import it.vfsfitvnm.vimusic.ui.screens.intentUriRoute
|
||||
import it.vfsfitvnm.vimusic.ui.screens.localPlaylistRoute
|
||||
import it.vfsfitvnm.vimusic.ui.screens.localplaylist.LocalPlaylistScreen
|
||||
import it.vfsfitvnm.vimusic.ui.screens.search.SearchScreen
|
||||
import it.vfsfitvnm.vimusic.ui.screens.searchResultRoute
|
||||
import it.vfsfitvnm.vimusic.ui.screens.searchRoute
|
||||
|
|
Loading…
Reference in a new issue