Improve sorting options for songs and playlists (#104)
This commit is contained in:
@@ -12,10 +12,12 @@ import androidx.room.migration.AutoMigrationSpec
|
|||||||
import androidx.room.migration.Migration
|
import androidx.room.migration.Migration
|
||||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
import it.vfsfitvnm.vimusic.enums.PlaylistSortBy
|
||||||
import it.vfsfitvnm.vimusic.enums.SongSortBy
|
import it.vfsfitvnm.vimusic.enums.SongSortBy
|
||||||
import it.vfsfitvnm.vimusic.enums.SortOrder
|
import it.vfsfitvnm.vimusic.enums.SortOrder
|
||||||
import it.vfsfitvnm.vimusic.models.*
|
import it.vfsfitvnm.vimusic.models.*
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
@@ -30,6 +32,14 @@ interface Database {
|
|||||||
@Query("SELECT * FROM Song WHERE totalPlayTimeMs > 0 ORDER BY ROWID DESC")
|
@Query("SELECT * FROM Song WHERE totalPlayTimeMs > 0 ORDER BY ROWID DESC")
|
||||||
fun songsByRowIdDesc(): Flow<List<DetailedSong>>
|
fun songsByRowIdDesc(): Flow<List<DetailedSong>>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM Song WHERE totalPlayTimeMs > 0 ORDER BY title ASC")
|
||||||
|
fun songsByTitleAsc(): Flow<List<DetailedSong>>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM Song WHERE totalPlayTimeMs > 0 ORDER BY title DESC")
|
||||||
|
fun songsByTitleDesc(): Flow<List<DetailedSong>>
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT * FROM Song WHERE totalPlayTimeMs > 0 ORDER BY totalPlayTimeMs ASC")
|
@Query("SELECT * FROM Song WHERE totalPlayTimeMs > 0 ORDER BY totalPlayTimeMs ASC")
|
||||||
fun songsByPlayTimeAsc(): Flow<List<DetailedSong>>
|
fun songsByPlayTimeAsc(): Flow<List<DetailedSong>>
|
||||||
@@ -44,6 +54,10 @@ interface Database {
|
|||||||
SortOrder.Ascending -> songsByPlayTimeAsc()
|
SortOrder.Ascending -> songsByPlayTimeAsc()
|
||||||
SortOrder.Descending -> songsByPlayTimeDesc()
|
SortOrder.Descending -> songsByPlayTimeDesc()
|
||||||
}
|
}
|
||||||
|
SongSortBy.Title -> when (sortOrder) {
|
||||||
|
SortOrder.Ascending -> songsByTitleAsc()
|
||||||
|
SortOrder.Descending -> songsByTitleDesc()
|
||||||
|
}
|
||||||
SongSortBy.DateAdded -> when (sortOrder) {
|
SongSortBy.DateAdded -> when (sortOrder) {
|
||||||
SortOrder.Ascending -> songsByRowIdAsc()
|
SortOrder.Ascending -> songsByRowIdAsc()
|
||||||
SortOrder.Descending -> songsByRowIdDesc()
|
SortOrder.Descending -> songsByRowIdDesc()
|
||||||
@@ -81,8 +95,29 @@ interface Database {
|
|||||||
fun playlistWithSongs(id: Long): Flow<PlaylistWithSongs?>
|
fun playlistWithSongs(id: Long): Flow<PlaylistWithSongs?>
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT id, name, (SELECT COUNT(*) FROM SongPlaylistMap WHERE playlistId = id) as songCount FROM Playlist")
|
@Query("SELECT id, name, (SELECT COUNT(*) FROM SongPlaylistMap WHERE playlistId = id) as songCount FROM Playlist ORDER BY name ASC")
|
||||||
fun playlistPreviews(): Flow<List<PlaylistPreview>>
|
fun playlistPreviewsByName(): Flow<List<PlaylistPreview>>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT id, name, (SELECT COUNT(*) FROM SongPlaylistMap WHERE playlistId = id) as songCount FROM Playlist ORDER BY ROWID ASC")
|
||||||
|
fun playlistPreviewsByDateAdded(): Flow<List<PlaylistPreview>>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT id, name, (SELECT COUNT(*) FROM SongPlaylistMap WHERE playlistId = id) as songCount FROM Playlist ORDER BY songCount ASC")
|
||||||
|
fun playlistPreviewsByDateSongCount(): Flow<List<PlaylistPreview>>
|
||||||
|
|
||||||
|
fun playlistPreviews(sortBy: PlaylistSortBy, sortOrder: SortOrder): Flow<List<PlaylistPreview>> {
|
||||||
|
return when (sortBy) {
|
||||||
|
PlaylistSortBy.Name -> playlistPreviewsByName()
|
||||||
|
PlaylistSortBy.DateAdded -> playlistPreviewsByDateAdded()
|
||||||
|
PlaylistSortBy.SongCount -> playlistPreviewsByDateSongCount()
|
||||||
|
}.map {
|
||||||
|
when (sortOrder) {
|
||||||
|
SortOrder.Ascending -> it
|
||||||
|
SortOrder.Descending -> it.reversed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Query("SELECT thumbnailUrl FROM Song JOIN SongPlaylistMap ON id = songId WHERE playlistId = :id ORDER BY position LIMIT 4")
|
@Query("SELECT thumbnailUrl FROM Song JOIN SongPlaylistMap ON id = songId WHERE playlistId = :id ORDER BY position LIMIT 4")
|
||||||
fun playlistThumbnailUrls(id: Long): Flow<List<String?>>
|
fun playlistThumbnailUrls(id: Long): Flow<List<String?>>
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package it.vfsfitvnm.vimusic.enums
|
||||||
|
|
||||||
|
enum class PlaylistSortBy {
|
||||||
|
Name,
|
||||||
|
DateAdded,
|
||||||
|
SongCount
|
||||||
|
}
|
||||||
@@ -2,5 +2,6 @@ package it.vfsfitvnm.vimusic.enums
|
|||||||
|
|
||||||
enum class SongSortBy {
|
enum class SongSortBy {
|
||||||
PlayTime,
|
PlayTime,
|
||||||
|
Title,
|
||||||
DateAdded
|
DateAdded
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package it.vfsfitvnm.vimusic.ui.components.themed
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.BasicText
|
||||||
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.shadow
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DropDownSection(content: @Composable ColumnScope.() -> Unit) {
|
||||||
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.shadow(
|
||||||
|
elevation = 2.dp,
|
||||||
|
shape = RoundedCornerShape(16.dp)
|
||||||
|
)
|
||||||
|
.background(colorPalette.elevatedBackground)
|
||||||
|
.width(IntrinsicSize.Max),
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DropDownSectionSpacer() {
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(4.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DropDownTextItem(
|
||||||
|
text: String,
|
||||||
|
isSelected: Boolean,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
|
DropDownTextItem(
|
||||||
|
text = text,
|
||||||
|
textColor = if (isSelected) {
|
||||||
|
colorPalette.onPrimaryContainer
|
||||||
|
} else {
|
||||||
|
colorPalette.textSecondary
|
||||||
|
},
|
||||||
|
backgroundColor = if (isSelected) {
|
||||||
|
colorPalette.primaryContainer
|
||||||
|
} else {
|
||||||
|
colorPalette.elevatedBackground
|
||||||
|
},
|
||||||
|
onClick = onClick
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DropDownTextItem(
|
||||||
|
text: String,
|
||||||
|
backgroundColor: Color? = null,
|
||||||
|
textColor: Color? = null,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
|
|
||||||
|
BasicText(
|
||||||
|
text = text,
|
||||||
|
style = typography.xxs.medium.copy(
|
||||||
|
color = textColor ?: colorPalette.text,
|
||||||
|
letterSpacing = 1.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.clickable(
|
||||||
|
indication = rememberRipple(bounded = true),
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
onClick = onClick
|
||||||
|
)
|
||||||
|
.background(backgroundColor ?: colorPalette.elevatedBackground)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.widthIn(min = 124.dp, max = 248.dp)
|
||||||
|
.padding(
|
||||||
|
horizontal = 16.dp,
|
||||||
|
vertical = 8.dp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -22,6 +22,8 @@ import it.vfsfitvnm.route.RouteHandler
|
|||||||
import it.vfsfitvnm.route.empty
|
import it.vfsfitvnm.route.empty
|
||||||
import it.vfsfitvnm.vimusic.*
|
import it.vfsfitvnm.vimusic.*
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
|
import it.vfsfitvnm.vimusic.enums.PlaylistSortBy
|
||||||
|
import it.vfsfitvnm.vimusic.enums.SortOrder
|
||||||
import it.vfsfitvnm.vimusic.models.DetailedSong
|
import it.vfsfitvnm.vimusic.models.DetailedSong
|
||||||
import it.vfsfitvnm.vimusic.models.Playlist
|
import it.vfsfitvnm.vimusic.models.Playlist
|
||||||
import it.vfsfitvnm.vimusic.models.SongPlaylistMap
|
import it.vfsfitvnm.vimusic.models.SongPlaylistMap
|
||||||
@@ -276,7 +278,7 @@ fun MediaItemMenu(
|
|||||||
onGlobalRouteEmitted: (() -> Unit)? = null,
|
onGlobalRouteEmitted: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
val playlistPreviews by remember {
|
val playlistPreviews by remember {
|
||||||
Database.playlistPreviews()
|
Database.playlistPreviews(PlaylistSortBy.DateAdded, SortOrder.Descending)
|
||||||
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
||||||
|
|
||||||
val viewPlaylistsRoute = rememberCreatePlaylistRoute()
|
val viewPlaylistsRoute = rememberCreatePlaylistRoute()
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
|
|
||||||
@ExperimentalFoundationApi
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun ArtistScreen(
|
fun ArtistScreen(
|
||||||
|
|||||||
@@ -12,18 +12,16 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
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.grid.rememberLazyGridState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.foundation.text.BasicText
|
import androidx.compose.foundation.text.BasicText
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
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.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.draw.shadow
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -32,25 +30,21 @@ import androidx.compose.ui.graphics.Shadow
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import it.vfsfitvnm.route.RouteHandler
|
import it.vfsfitvnm.route.RouteHandler
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
import it.vfsfitvnm.vimusic.enums.BuiltInPlaylist
|
import it.vfsfitvnm.vimusic.enums.*
|
||||||
import it.vfsfitvnm.vimusic.enums.SongSortBy
|
|
||||||
import it.vfsfitvnm.vimusic.enums.SortOrder
|
|
||||||
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
|
||||||
import it.vfsfitvnm.vimusic.models.DetailedSong
|
import it.vfsfitvnm.vimusic.models.DetailedSong
|
||||||
import it.vfsfitvnm.vimusic.models.Playlist
|
import it.vfsfitvnm.vimusic.models.Playlist
|
||||||
import it.vfsfitvnm.vimusic.models.SearchQuery
|
import it.vfsfitvnm.vimusic.models.SearchQuery
|
||||||
import it.vfsfitvnm.vimusic.query
|
import it.vfsfitvnm.vimusic.query
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.DropdownMenu
|
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.InHistoryMediaItemMenu
|
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.*
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.ui.views.PlaylistPreviewItem
|
import it.vfsfitvnm.vimusic.ui.views.PlaylistPreviewItem
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
@@ -64,6 +58,7 @@ fun HomeScreen() {
|
|||||||
val (colorPalette, typography) = LocalAppearance.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
|
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
|
val lazyHorizontalGridState = rememberLazyGridState()
|
||||||
|
|
||||||
val intentUriRoute = rememberIntentUriRoute()
|
val intentUriRoute = rememberIntentUriRoute()
|
||||||
val settingsRoute = rememberSettingsRoute()
|
val settingsRoute = rememberSettingsRoute()
|
||||||
@@ -74,8 +69,12 @@ fun HomeScreen() {
|
|||||||
val albumRoute = rememberAlbumRoute()
|
val albumRoute = rememberAlbumRoute()
|
||||||
val artistRoute = rememberArtistRoute()
|
val artistRoute = rememberArtistRoute()
|
||||||
|
|
||||||
val playlistPreviews by remember {
|
var playlistSortBy by rememberPreference(playlistSortByKey, PlaylistSortBy.DateAdded)
|
||||||
Database.playlistPreviews()
|
var playlistSortOrder by rememberPreference(playlistSortOrderKey, SortOrder.Descending)
|
||||||
|
var playlistGridExpanded by rememberPreference(playlistGridExpandedKey, false)
|
||||||
|
|
||||||
|
val playlistPreviews by remember(playlistSortBy, playlistSortOrder) {
|
||||||
|
Database.playlistPreviews(playlistSortBy, playlistSortOrder)
|
||||||
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
||||||
|
|
||||||
var songSortBy by rememberPreference(songSortByKey, SongSortBy.DateAdded)
|
var songSortBy by rememberPreference(songSortByKey, SongSortBy.DateAdded)
|
||||||
@@ -151,14 +150,9 @@ fun HomeScreen() {
|
|||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
val isFirstLaunch by rememberPreference(isFirstLaunchKey, true)
|
val isFirstLaunch by rememberPreference(isFirstLaunchKey, true)
|
||||||
val isCachedPlaylistShown by rememberPreference(isCachedPlaylistShownKey, false)
|
|
||||||
|
|
||||||
val thumbnailSize = Dimensions.thumbnails.song.px
|
val thumbnailSize = Dimensions.thumbnails.song.px
|
||||||
|
|
||||||
var isGridExpanded by remember {
|
|
||||||
mutableStateOf(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
var isCreatingANewPlaylist by rememberSaveable {
|
var isCreatingANewPlaylist by rememberSaveable {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
@@ -262,28 +256,100 @@ fun HomeScreen() {
|
|||||||
.size(20.dp)
|
.size(20.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
Image(
|
Box {
|
||||||
painter = painterResource(if (isGridExpanded) R.drawable.grid else R.drawable.grid_single),
|
var isSortMenuDisplayed by remember {
|
||||||
contentDescription = null,
|
mutableStateOf(false)
|
||||||
colorFilter = ColorFilter.tint(colorPalette.textSecondary),
|
}
|
||||||
modifier = Modifier
|
|
||||||
.clickable {
|
Image(
|
||||||
isGridExpanded = !isGridExpanded
|
painter = painterResource(R.drawable.sort),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
isSortMenuDisplayed = true
|
||||||
|
}
|
||||||
|
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||||
|
.size(20.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
DropdownMenu(
|
||||||
|
isDisplayed = isSortMenuDisplayed,
|
||||||
|
onDismissRequest = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
}
|
}
|
||||||
.padding(all = 10.dp)
|
) {
|
||||||
.size(16.dp)
|
DropDownSection {
|
||||||
)
|
DropDownTextItem(
|
||||||
|
text = "NAME",
|
||||||
|
isSelected = playlistSortBy == PlaylistSortBy.Name,
|
||||||
|
onClick = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
|
playlistSortBy = PlaylistSortBy.Name
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
DropDownTextItem(
|
||||||
|
text = "DATE ADDED",
|
||||||
|
isSelected = playlistSortBy == PlaylistSortBy.DateAdded,
|
||||||
|
onClick = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
|
playlistSortBy = PlaylistSortBy.DateAdded
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
DropDownTextItem(
|
||||||
|
text = "SONG COUNT",
|
||||||
|
isSelected = playlistSortBy == PlaylistSortBy.SongCount,
|
||||||
|
onClick = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
|
playlistSortBy = PlaylistSortBy.SongCount
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDownSectionSpacer()
|
||||||
|
|
||||||
|
DropDownSection {
|
||||||
|
DropDownTextItem(
|
||||||
|
text = when (playlistSortOrder) {
|
||||||
|
SortOrder.Ascending -> "ASCENDING"
|
||||||
|
SortOrder.Descending -> "DESCENDING"
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
|
playlistSortOrder = !playlistSortOrder
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
DropDownSectionSpacer()
|
||||||
|
|
||||||
|
DropDownSection {
|
||||||
|
DropDownTextItem(
|
||||||
|
text = when (playlistGridExpanded) {
|
||||||
|
true -> "EXPAND"
|
||||||
|
false -> "COMPACT"
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
|
playlistGridExpanded = !playlistGridExpanded
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
LazyHorizontalGrid(
|
LazyHorizontalGrid(
|
||||||
rows = GridCells.Fixed(if (isGridExpanded) 3 else 1),
|
state = lazyHorizontalGridState,
|
||||||
|
rows = GridCells.Fixed(if (playlistGridExpanded) 3 else 1),
|
||||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.animateContentSize()
|
.animateContentSize()
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(124.dp * (if (isGridExpanded) 3 else 1))
|
.height(124.dp * (if (playlistGridExpanded) 3 else 1))
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
Box(
|
Box(
|
||||||
@@ -321,7 +387,7 @@ fun HomeScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCachedPlaylistShown) {
|
if (playlistGridExpanded) {
|
||||||
item {
|
item {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -361,6 +427,7 @@ fun HomeScreen() {
|
|||||||
|
|
||||||
items(
|
items(
|
||||||
items = playlistPreviews,
|
items = playlistPreviews,
|
||||||
|
key = { it.playlist.id },
|
||||||
contentType = { it }
|
contentType = { it }
|
||||||
) { playlistPreview ->
|
) { playlistPreview ->
|
||||||
PlaylistPreviewItem(
|
PlaylistPreviewItem(
|
||||||
@@ -370,10 +437,9 @@ fun HomeScreen() {
|
|||||||
.padding(all = 8.dp)
|
.padding(all = 8.dp)
|
||||||
.clickable(
|
.clickable(
|
||||||
indication = rememberRipple(bounded = true),
|
indication = rememberRipple(bounded = true),
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
) {
|
onClick = { playlistRoute(playlistPreview.playlist.id) }
|
||||||
playlistRoute(playlistPreview.playlist.id)
|
)
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -436,96 +502,45 @@ fun HomeScreen() {
|
|||||||
isSortMenuDisplayed = false
|
isSortMenuDisplayed = false
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
@Composable
|
DropDownSection {
|
||||||
fun Item(
|
DropDownTextItem(
|
||||||
text: String,
|
|
||||||
textColor: Color,
|
|
||||||
backgroundColor: Color,
|
|
||||||
onClick: () -> Unit
|
|
||||||
) {
|
|
||||||
BasicText(
|
|
||||||
text = text,
|
|
||||||
style = typography.xxs.medium.copy(color = textColor, letterSpacing = 1.sp),
|
|
||||||
modifier = Modifier
|
|
||||||
.clip(RoundedCornerShape(16.dp))
|
|
||||||
.clickable(
|
|
||||||
indication = rememberRipple(bounded = true),
|
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
|
||||||
onClick = {
|
|
||||||
isSortMenuDisplayed = false
|
|
||||||
onClick()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.background(backgroundColor)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.widthIn(min = 124.dp, max = 248.dp)
|
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Item(
|
|
||||||
text: String,
|
|
||||||
isSelected: Boolean,
|
|
||||||
onClick: () -> Unit
|
|
||||||
) {
|
|
||||||
Item(
|
|
||||||
text = text,
|
|
||||||
textColor = if (isSelected) {
|
|
||||||
colorPalette.onPrimaryContainer
|
|
||||||
} else {
|
|
||||||
colorPalette.textSecondary
|
|
||||||
},
|
|
||||||
backgroundColor = if (isSelected) {
|
|
||||||
colorPalette.primaryContainer
|
|
||||||
} else {
|
|
||||||
colorPalette.elevatedBackground
|
|
||||||
},
|
|
||||||
onClick = onClick
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.shadow(elevation = 2.dp, shape = RoundedCornerShape(16.dp))
|
|
||||||
.background(colorPalette.elevatedBackground)
|
|
||||||
.width(IntrinsicSize.Max),
|
|
||||||
) {
|
|
||||||
Item(
|
|
||||||
text = "PLAY TIME",
|
text = "PLAY TIME",
|
||||||
isSelected = songSortBy == SongSortBy.PlayTime,
|
isSelected = songSortBy == SongSortBy.PlayTime,
|
||||||
onClick = {
|
onClick = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
songSortBy = SongSortBy.PlayTime
|
songSortBy = SongSortBy.PlayTime
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Item(
|
|
||||||
|
DropDownTextItem(
|
||||||
|
text = "TITLE",
|
||||||
|
isSelected = songSortBy == SongSortBy.Title,
|
||||||
|
onClick = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
|
songSortBy = SongSortBy.Title
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
DropDownTextItem(
|
||||||
text = "DATE ADDED",
|
text = "DATE ADDED",
|
||||||
isSelected = songSortBy == SongSortBy.DateAdded,
|
isSelected = songSortBy == SongSortBy.DateAdded,
|
||||||
onClick = {
|
onClick = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
songSortBy = SongSortBy.DateAdded
|
songSortBy = SongSortBy.DateAdded
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(
|
DropDownSectionSpacer()
|
||||||
modifier = Modifier
|
|
||||||
.height(4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
DropDownSection {
|
||||||
modifier = Modifier
|
DropDownTextItem(
|
||||||
.shadow(elevation = 2.dp, shape = RoundedCornerShape(16.dp))
|
|
||||||
.background(colorPalette.elevatedBackground)
|
|
||||||
.width(IntrinsicSize.Max),
|
|
||||||
) {
|
|
||||||
Item(
|
|
||||||
text = when (songSortOrder) {
|
text = when (songSortOrder) {
|
||||||
SortOrder.Ascending -> "ASCENDING"
|
SortOrder.Ascending -> "ASCENDING"
|
||||||
SortOrder.Descending -> "DESCENDING"
|
SortOrder.Descending -> "DESCENDING"
|
||||||
},
|
},
|
||||||
textColor = colorPalette.text,
|
|
||||||
backgroundColor = colorPalette.elevatedBackground,
|
|
||||||
onClick = {
|
onClick = {
|
||||||
|
isSortMenuDisplayed = false
|
||||||
songSortOrder = !songSortOrder
|
songSortOrder = !songSortOrder
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ fun AppearanceSettingsScreen() {
|
|||||||
|
|
||||||
var colorPaletteMode by rememberPreference(colorPaletteModeKey, ColorPaletteMode.System)
|
var colorPaletteMode by rememberPreference(colorPaletteModeKey, ColorPaletteMode.System)
|
||||||
var thumbnailRoundness by rememberPreference(thumbnailRoundnessKey, ThumbnailRoundness.Light)
|
var thumbnailRoundness by rememberPreference(thumbnailRoundnessKey, ThumbnailRoundness.Light)
|
||||||
var isCachedPlaylistShown by rememberPreference(isCachedPlaylistShownKey, false)
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -100,17 +99,6 @@ fun AppearanceSettingsScreen() {
|
|||||||
thumbnailRoundness = it
|
thumbnailRoundness = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
SettingsEntryGroupText(title = "OTHER")
|
|
||||||
|
|
||||||
SwitchSettingEntry(
|
|
||||||
title = "Cached playlist",
|
|
||||||
text = "Display a playlist whose songs can be played offline",
|
|
||||||
isChecked = isCachedPlaylistShown,
|
|
||||||
onCheckedChange = {
|
|
||||||
isCachedPlaylistShown = it
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,15 @@ import androidx.core.content.edit
|
|||||||
|
|
||||||
const val colorPaletteModeKey = "colorPaletteMode"
|
const val colorPaletteModeKey = "colorPaletteMode"
|
||||||
const val thumbnailRoundnessKey = "thumbnailRoundness"
|
const val thumbnailRoundnessKey = "thumbnailRoundness"
|
||||||
const val isCachedPlaylistShownKey = "isCachedPlaylistShown"
|
|
||||||
const val coilDiskCacheMaxSizeKey = "coilDiskCacheMaxSize"
|
const val coilDiskCacheMaxSizeKey = "coilDiskCacheMaxSize"
|
||||||
const val exoPlayerDiskCacheMaxSizeKey = "exoPlayerDiskCacheMaxSize"
|
const val exoPlayerDiskCacheMaxSizeKey = "exoPlayerDiskCacheMaxSize"
|
||||||
const val isInvincibilityEnabledKey = "isInvincibilityEnabled"
|
const val isInvincibilityEnabledKey = "isInvincibilityEnabled"
|
||||||
const val isFirstLaunchKey = "isFirstLaunch"
|
const val isFirstLaunchKey = "isFirstLaunch"
|
||||||
const val songSortOrderKey = "songSortOrder"
|
const val songSortOrderKey = "songSortOrder"
|
||||||
const val songSortByKey = "songSortBy"
|
const val songSortByKey = "songSortBy"
|
||||||
|
const val playlistSortOrderKey = "playlistSortOrder"
|
||||||
|
const val playlistSortByKey = "playlistSortBy"
|
||||||
|
const val playlistGridExpandedKey = "playlistGridExpanded"
|
||||||
const val searchFilterKey = "searchFilter"
|
const val searchFilterKey = "searchFilter"
|
||||||
const val repeatModeKey = "repeatMode"
|
const val repeatModeKey = "repeatMode"
|
||||||
const val skipSilenceKey = "skipSilence"
|
const val skipSilenceKey = "skipSilence"
|
||||||
|
|||||||
Reference in New Issue
Block a user