Revamp compose-routing

This commit is contained in:
vfsfitvnm 2022-07-24 23:04:33 +02:00
parent 795bf3d56f
commit fcd84cde43
23 changed files with 122 additions and 474 deletions

View file

@ -43,9 +43,9 @@ import it.vfsfitvnm.vimusic.transaction
import it.vfsfitvnm.vimusic.ui.components.ChunkyButton import it.vfsfitvnm.vimusic.ui.components.ChunkyButton
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
import it.vfsfitvnm.vimusic.ui.components.Pager import it.vfsfitvnm.vimusic.ui.components.Pager
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute import it.vfsfitvnm.vimusic.ui.screens.albumRoute
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute import it.vfsfitvnm.vimusic.ui.screens.artistRoute
import it.vfsfitvnm.vimusic.ui.screens.rememberCreatePlaylistRoute import it.vfsfitvnm.vimusic.ui.screens.viewPlaylistsRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.addNext import it.vfsfitvnm.vimusic.utils.addNext
import it.vfsfitvnm.vimusic.utils.asMediaItem import it.vfsfitvnm.vimusic.utils.asMediaItem
@ -235,9 +235,6 @@ fun BaseMediaItemMenu(
) { ) {
val context = LocalContext.current val context = LocalContext.current
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
MediaItemMenu( MediaItemMenu(
mediaItem = mediaItem, mediaItem = mediaItem,
onDismiss = onDismiss, onDismiss = onDismiss,
@ -299,8 +296,6 @@ fun MediaItemMenu(
Database.playlistPreviews(PlaylistSortBy.DateAdded, SortOrder.Descending) Database.playlistPreviews(PlaylistSortBy.DateAdded, SortOrder.Descending)
}.collectAsState(initial = emptyList(), context = Dispatchers.IO) }.collectAsState(initial = emptyList(), context = Dispatchers.IO)
val viewPlaylistsRoute = rememberCreatePlaylistRoute()
Menu(modifier = modifier) { Menu(modifier = modifier) {
RouteHandler( RouteHandler(
transitionSpec = { transitionSpec = {

View file

@ -81,9 +81,7 @@ import kotlinx.coroutines.runBlocking
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun AlbumScreen( fun AlbumScreen(browseId: String) {
browseId: String
) {
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val albumResult by remember(browseId) { val albumResult by remember(browseId) {
@ -99,21 +97,8 @@ fun AlbumScreen(
Database.albumSongs(browseId) Database.albumSongs(browseId)
}.collectAsState(initial = emptyList(), context = Dispatchers.IO) }.collectAsState(initial = emptyList(), context = Dispatchers.IO)
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val context = LocalContext.current val context = LocalContext.current

View file

@ -63,26 +63,11 @@ import kotlinx.coroutines.runBlocking
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun ArtistScreen( fun ArtistScreen(browseId: String) {
browseId: String,
) {
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val binder = LocalPlayerServiceBinder.current val binder = LocalPlayerServiceBinder.current

View file

@ -54,26 +54,11 @@ import kotlinx.coroutines.flow.map
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun BuiltInPlaylistScreen( fun BuiltInPlaylistScreen(builtInPlaylist: BuiltInPlaylist) {
builtInPlaylist: BuiltInPlaylist,
) {
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val menuState = LocalMenuState.current val menuState = LocalMenuState.current

View file

@ -108,15 +108,6 @@ fun HomeScreen() {
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val lazyHorizontalGridState = rememberLazyGridState() val lazyHorizontalGridState = rememberLazyGridState()
val intentUriRoute = rememberIntentUriRoute()
val settingsRoute = rememberSettingsRoute()
val playlistRoute = rememberLocalPlaylistRoute()
val builtInPlaylistRoute = rememberBuiltInPlaylistRoute()
val searchRoute = rememberSearchRoute()
val searchResultRoute = rememberSearchResultRoute()
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
var playlistSortBy by rememberPreference(playlistSortByKey, PlaylistSortBy.DateAdded) var playlistSortBy by rememberPreference(playlistSortByKey, PlaylistSortBy.DateAdded)
var playlistSortOrder by rememberPreference(playlistSortOrderKey, SortOrder.Descending) var playlistSortOrder by rememberPreference(playlistSortOrderKey, SortOrder.Descending)
var playlistGridExpanded by rememberPreference(playlistGridExpandedKey, false) var playlistGridExpanded by rememberPreference(playlistGridExpandedKey, false)
@ -137,7 +128,7 @@ fun HomeScreen() {
SettingsScreen() SettingsScreen()
} }
playlistRoute { playlistId -> localPlaylistRoute { playlistId ->
LocalPlaylistScreen( LocalPlaylistScreen(
playlistId = playlistId ?: error("playlistId cannot be null") playlistId = playlistId ?: error("playlistId cannot be null")
) )
@ -520,7 +511,7 @@ fun HomeScreen() {
.clickable( .clickable(
indication = rememberRipple(bounded = true), indication = rememberRipple(bounded = true),
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
onClick = { playlistRoute(playlistPreview.playlist.id) } onClick = { localPlaylistRoute(playlistPreview.playlist.id) }
) )
) )
} }

View file

@ -54,8 +54,6 @@ import kotlinx.coroutines.withContext
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun IntentUriScreen(uri: Uri) { fun IntentUriScreen(uri: Uri) {
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
@ -98,17 +96,7 @@ fun IntentUriScreen(uri: Uri) {
} }
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val menuState = LocalMenuState.current val menuState = LocalMenuState.current

View file

@ -65,30 +65,15 @@ import kotlinx.coroutines.flow.map
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun LocalPlaylistScreen( fun LocalPlaylistScreen(playlistId: Long) {
playlistId: Long,
) {
val playlistWithSongs by remember(playlistId) { val playlistWithSongs by remember(playlistId) {
Database.playlistWithSongs(playlistId).map { it ?: PlaylistWithSongs.NotFound } Database.playlistWithSongs(playlistId).map { it ?: PlaylistWithSongs.NotFound }
}.collectAsState(initial = PlaylistWithSongs.Empty, context = Dispatchers.IO) }.collectAsState(initial = PlaylistWithSongs.Empty, context = Dispatchers.IO)
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val hapticFeedback = LocalHapticFeedback.current val hapticFeedback = LocalHapticFeedback.current

View file

@ -75,26 +75,11 @@ import kotlinx.coroutines.withContext
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun PlaylistScreen( fun PlaylistScreen(browseId: String) {
browseId: String,
) {
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val context = LocalContext.current val context = LocalContext.current

View file

@ -1,104 +1,45 @@
package it.vfsfitvnm.vimusic.ui.screens package it.vfsfitvnm.vimusic.ui.screens
import android.annotation.SuppressLint
import android.net.Uri import android.net.Uri
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import it.vfsfitvnm.route.Route0 import it.vfsfitvnm.route.Route0
import it.vfsfitvnm.route.Route1 import it.vfsfitvnm.route.Route1
import it.vfsfitvnm.route.RouteHandlerScope
import it.vfsfitvnm.vimusic.enums.BuiltInPlaylist import it.vfsfitvnm.vimusic.enums.BuiltInPlaylist
@Composable val aboutRoute = Route0("aboutRoute")
fun rememberIntentUriRoute(): Route1<Uri?> { val albumRoute = Route1<String?>("albumRoute")
val uri = rememberSaveable { val appearanceSettingsRoute = Route0("appearanceSettingsRoute")
mutableStateOf<Uri?>(null) val artistRoute = Route1<String?>("artistRoute")
} val backupAndRestoreRoute = Route0("backupAndRestoreRoute")
return remember { val builtInPlaylistRoute = Route1<BuiltInPlaylist>("builtInPlaylistRoute")
Route1("IntentUriRoute", uri) val cacheSettingsRoute = Route0("cacheSettingsRoute")
} val intentUriRoute = Route1<Uri?>("intentUriRoute")
} val localPlaylistRoute = Route1<Long?>("localPlaylistRoute")
val otherSettingsRoute = Route0("otherSettingsRoute")
val playerSettingsRoute = Route0("playerSettingsRoute")
val playlistRoute = Route1<String?>("playlistRoute")
val searchResultRoute = Route1<String>("searchResultRoute")
val searchRoute = Route1<String>("searchRoute")
val settingsRoute = Route0("settingsRoute")
val viewPlaylistsRoute = Route0("createPlaylistRoute")
@SuppressLint("ComposableNaming")
@Suppress("NOTHING_TO_INLINE")
@ExperimentalAnimationApi
@Composable @Composable
fun rememberPlaylistRoute(): Route1<String?> { inline fun RouteHandlerScope.globalRoutes() {
val browseId = rememberSaveable { albumRoute { browseId ->
mutableStateOf<String?>(null) AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
} }
return remember {
Route1("PlaylistRoute", browseId)
}
}
@Composable artistRoute { browseId ->
fun rememberAlbumRoute(): Route1<String?> { ArtistScreen(
val browseId = rememberSaveable { browseId = browseId ?: error("browseId cannot be null")
mutableStateOf<String?>(null) )
}
return remember {
Route1("AlbumRoute", browseId)
}
}
@Composable
fun rememberArtistRoute(): Route1<String?> {
val browseId = rememberSaveable {
mutableStateOf<String?>(null)
}
return remember {
Route1("ArtistRoute", browseId)
}
}
@Composable
fun rememberLocalPlaylistRoute(): Route1<Long?> {
val playlistId = rememberSaveable {
mutableStateOf<Long?>(null)
}
return remember {
Route1("LocalPlaylistRoute", playlistId)
}
}
@Composable
fun rememberBuiltInPlaylistRoute(): Route1<BuiltInPlaylist> {
val playlistType = rememberSaveable {
mutableStateOf(BuiltInPlaylist.Favorites)
}
return remember {
Route1("BuiltInPlaylistRoute", playlistType)
}
}
@Composable
fun rememberSearchRoute(): Route1<String> {
val initialTextInput = remember {
mutableStateOf("")
}
return remember {
Route1("SearchRoute", initialTextInput)
}
}
@Composable
fun rememberCreatePlaylistRoute(): Route0 {
return remember {
Route0("CreatePlaylistRoute")
}
}
@Composable
fun rememberSearchResultRoute(): Route1<String> {
val searchQuery = rememberSaveable {
mutableStateOf("")
}
return remember {
Route1("SearchResultRoute", searchQuery)
}
}
@Composable
fun rememberSettingsRoute(): Route0 {
return remember {
Route0("SettingsRoute")
} }
} }

View file

@ -71,10 +71,7 @@ import kotlinx.coroutines.withContext
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun SearchResultScreen( fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
query: String,
onSearchAgain: () -> Unit,
) {
val (colorPalette, typography) = LocalAppearance.current val (colorPalette, typography) = LocalAppearance.current
val binder = LocalPlayerServiceBinder.current val binder = LocalPlayerServiceBinder.current
@ -107,10 +104,6 @@ fun SearchResultScreen(
val thumbnailSizePx = Dimensions.thumbnails.song.px val thumbnailSizePx = Dimensions.thumbnails.song.px
val albumRoute = rememberAlbumRoute()
val playlistRoute = rememberPlaylistRoute()
val artistRoute = rememberArtistRoute()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> albumRoute { browseId ->
AlbumScreen( AlbumScreen(
@ -118,14 +111,14 @@ fun SearchResultScreen(
) )
} }
playlistRoute { browseId -> artistRoute { browseId ->
PlaylistScreen( ArtistScreen(
browseId = browseId ?: "browseId cannot be null" browseId = browseId ?: "browseId cannot be null"
) )
} }
artistRoute { browseId -> playlistRoute { browseId ->
ArtistScreen( PlaylistScreen(
browseId = browseId ?: "browseId cannot be null" browseId = browseId ?: "browseId cannot be null"
) )
} }

View file

@ -69,26 +69,9 @@ import kotlinx.coroutines.withContext
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun SearchScreen( fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (Uri) -> Unit) {
initialTextInput: String,
onSearch: (String) -> Unit,
onUri: (Uri) -> Unit,
) {
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val (colorPalette, typography) = LocalAppearance.current val (colorPalette, typography) = LocalAppearance.current

View file

@ -29,15 +29,6 @@ import it.vfsfitvnm.vimusic.utils.*
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun SettingsScreen() { fun SettingsScreen() {
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
val appearanceSettingsRoute = rememberAppearanceSettingsRoute()
val playerSettingsRoute = rememberPlayerSettingsRoute()
val backupAndRestoreRoute = rememberBackupAndRestoreRoute()
val cacheSettingsRoute = rememberCacheSettingsRoute()
val otherSettingsRoute = rememberOtherSettingsRoute()
val aboutRoute = rememberAboutRoute()
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
RouteHandler( RouteHandler(
@ -53,17 +44,7 @@ fun SettingsScreen() {
} }
} }
) { ) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
appearanceSettingsRoute { appearanceSettingsRoute {
AppearanceSettingsScreen() AppearanceSettingsScreen()

View file

@ -27,10 +27,7 @@ import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.vimusic.BuildConfig import it.vfsfitvnm.vimusic.BuildConfig
import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.TopAppBar import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.screens.AlbumScreen import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.bold import it.vfsfitvnm.vimusic.utils.bold
import it.vfsfitvnm.vimusic.utils.secondary import it.vfsfitvnm.vimusic.utils.secondary
@ -39,23 +36,10 @@ import it.vfsfitvnm.vimusic.utils.semiBold
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun AboutScreen() { fun AboutScreen() {
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val (colorPalette, typography) = LocalAppearance.current val (colorPalette, typography) = LocalAppearance.current

View file

@ -25,12 +25,9 @@ import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
import it.vfsfitvnm.vimusic.ui.components.TopAppBar import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.screens.AlbumScreen
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.EnumValueSelectorSettingsEntry import it.vfsfitvnm.vimusic.ui.screens.EnumValueSelectorSettingsEntry
import it.vfsfitvnm.vimusic.ui.screens.SettingsEntryGroupText import it.vfsfitvnm.vimusic.ui.screens.SettingsEntryGroupText
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.colorPaletteModeKey import it.vfsfitvnm.vimusic.utils.colorPaletteModeKey
import it.vfsfitvnm.vimusic.utils.rememberPreference import it.vfsfitvnm.vimusic.utils.rememberPreference
@ -40,23 +37,11 @@ import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun AppearanceSettingsScreen() { fun AppearanceSettingsScreen() {
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val (colorPalette, typography) = LocalAppearance.current val (colorPalette, typography) = LocalAppearance.current

View file

@ -43,10 +43,7 @@ import it.vfsfitvnm.vimusic.service.PlayerService
import it.vfsfitvnm.vimusic.ui.components.TopAppBar import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.ConfirmationDialog import it.vfsfitvnm.vimusic.ui.components.themed.ConfirmationDialog
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.screens.AlbumScreen import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.intent import it.vfsfitvnm.vimusic.utils.intent
import it.vfsfitvnm.vimusic.utils.semiBold import it.vfsfitvnm.vimusic.utils.semiBold
@ -59,23 +56,11 @@ import kotlin.system.exitProcess
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun BackupAndRestoreScreen() { fun BackupAndRestoreScreen() {
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val (colorPalette, typography) = LocalAppearance.current val (colorPalette, typography) = LocalAppearance.current

View file

@ -35,14 +35,11 @@ import it.vfsfitvnm.vimusic.enums.CoilDiskCacheMaxSize
import it.vfsfitvnm.vimusic.enums.ExoPlayerDiskCacheMaxSize import it.vfsfitvnm.vimusic.enums.ExoPlayerDiskCacheMaxSize
import it.vfsfitvnm.vimusic.ui.components.TopAppBar import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.screens.AlbumScreen
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.DisabledSettingsEntry import it.vfsfitvnm.vimusic.ui.screens.DisabledSettingsEntry
import it.vfsfitvnm.vimusic.ui.screens.EnumValueSelectorSettingsEntry import it.vfsfitvnm.vimusic.ui.screens.EnumValueSelectorSettingsEntry
import it.vfsfitvnm.vimusic.ui.screens.SettingsEntry import it.vfsfitvnm.vimusic.ui.screens.SettingsEntry
import it.vfsfitvnm.vimusic.ui.screens.SettingsEntryGroupText import it.vfsfitvnm.vimusic.ui.screens.SettingsEntryGroupText
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.coilDiskCacheMaxSizeKey import it.vfsfitvnm.vimusic.utils.coilDiskCacheMaxSizeKey
import it.vfsfitvnm.vimusic.utils.exoPlayerDiskCacheMaxSizeKey import it.vfsfitvnm.vimusic.utils.exoPlayerDiskCacheMaxSizeKey
@ -55,23 +52,11 @@ import kotlinx.coroutines.launch
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun CacheSettingsScreen() { fun CacheSettingsScreen() {
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val context = LocalContext.current val context = LocalContext.current

View file

@ -35,13 +35,10 @@ import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.TopAppBar import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.screens.AlbumScreen
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.SettingsEntry import it.vfsfitvnm.vimusic.ui.screens.SettingsEntry
import it.vfsfitvnm.vimusic.ui.screens.SettingsEntryGroupText import it.vfsfitvnm.vimusic.ui.screens.SettingsEntryGroupText
import it.vfsfitvnm.vimusic.ui.screens.SwitchSettingEntry import it.vfsfitvnm.vimusic.ui.screens.SwitchSettingEntry
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.isIgnoringBatteryOptimizations import it.vfsfitvnm.vimusic.utils.isIgnoringBatteryOptimizations
import it.vfsfitvnm.vimusic.utils.isInvincibilityEnabledKey import it.vfsfitvnm.vimusic.utils.isInvincibilityEnabledKey
@ -51,23 +48,11 @@ import it.vfsfitvnm.vimusic.utils.semiBold
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun OtherSettingsScreen() { fun OtherSettingsScreen() {
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val context = LocalContext.current val context = LocalContext.current

View file

@ -30,13 +30,10 @@ import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.TopAppBar import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.screens.AlbumScreen
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.SettingsEntry import it.vfsfitvnm.vimusic.ui.screens.SettingsEntry
import it.vfsfitvnm.vimusic.ui.screens.SettingsEntryGroupText import it.vfsfitvnm.vimusic.ui.screens.SettingsEntryGroupText
import it.vfsfitvnm.vimusic.ui.screens.SwitchSettingEntry import it.vfsfitvnm.vimusic.ui.screens.SwitchSettingEntry
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.persistentQueueKey import it.vfsfitvnm.vimusic.utils.persistentQueueKey
import it.vfsfitvnm.vimusic.utils.rememberPreference import it.vfsfitvnm.vimusic.utils.rememberPreference
@ -47,23 +44,11 @@ import it.vfsfitvnm.vimusic.utils.volumeNormalizationKey
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun PlayerSettingsScreen() { fun PlayerSettingsScreen() {
val albumRoute = rememberAlbumRoute()
val artistRoute = rememberArtistRoute()
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(listenToGlobalEmitter = true) {
albumRoute { browseId -> globalRoutes()
AlbumScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
artistRoute { browseId ->
ArtistScreen(
browseId = browseId ?: error("browseId cannot be null")
)
}
host { host {
val context = LocalContext.current val context = LocalContext.current

View file

@ -1,47 +0,0 @@
package it.vfsfitvnm.vimusic.ui.screens.settings
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import it.vfsfitvnm.route.Route0
@Composable
fun rememberAppearanceSettingsRoute(): Route0 {
return remember {
Route0("AppearanceSettingsRoute")
}
}
@Composable
fun rememberPlayerSettingsRoute(): Route0 {
return remember {
Route0("PlayerSettingsRoute")
}
}
@Composable
fun rememberBackupAndRestoreRoute(): Route0 {
return remember {
Route0("BackupAndRestoreRoute")
}
}
@Composable
fun rememberCacheSettingsRoute(): Route0 {
return remember {
Route0("CacheSettingsRoute")
}
}
@Composable
fun rememberOtherSettingsRoute(): Route0 {
return remember {
Route0("OtherSettingsRoute")
}
}
@Composable
fun rememberAboutRoute(): Route0 {
return remember {
Route0("AboutRoute")
}
}

View file

@ -1,10 +1,15 @@
@file:Suppress("UNCHECKED_CAST")
package it.vfsfitvnm.route package it.vfsfitvnm.route
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.SaverScope import androidx.compose.runtime.saveable.SaverScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
@Stable @Immutable
open class Route internal constructor(val tag: String) { open class Route internal constructor(val tag: String) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
return when { return when {
@ -19,7 +24,7 @@ open class Route internal constructor(val tag: String) {
} }
object GlobalEmitter { object GlobalEmitter {
var listener: ((Route) -> Unit)? = null var listener: ((Route, Array<Any?>) -> Unit)? = null
} }
object Saver : androidx.compose.runtime.saveable.Saver<Route?, String> { object Saver : androidx.compose.runtime.saveable.Saver<Route?, String> {
@ -35,10 +40,8 @@ fun rememberRoute(route: Route? = null): MutableState<Route?> {
} }
} }
@Stable @Immutable
class Route0( class Route0(tag: String) : Route(tag) {
tag: String
) : Route(tag) {
context(RouteHandlerScope) context(RouteHandlerScope)
@Composable @Composable
operator fun invoke(content: @Composable () -> Unit) { operator fun invoke(content: @Composable () -> Unit) {
@ -48,64 +51,36 @@ class Route0(
} }
fun global() { fun global() {
GlobalEmitter.listener?.invoke(this) GlobalEmitter.listener?.invoke(this, emptyArray())
} }
} }
@Stable @Immutable
class Route1<P0>( class Route1<P0>(tag: String) : Route(tag) {
tag: String,
state0: MutableState<P0>
) : Route(tag) {
var p0 by state0
context(RouteHandlerScope) context(RouteHandlerScope)
@Composable @Composable
operator fun invoke(content: @Composable (P0) -> Unit) { operator fun invoke(content: @Composable (P0) -> Unit) {
if (this == route) { if (this == route) {
if (route is Route1<*>) { content(parameters[0] as P0)
@Suppress("UNCHECKED_CAST")
(route as Route1<P0>).let { route ->
this.p0 = route.p0
}
}
content(this.p0)
} }
} }
fun global(p0: P0 = this.p0) { fun global(p0: P0) {
this.p0 = p0 GlobalEmitter.listener?.invoke(this, arrayOf(p0))
GlobalEmitter.listener?.invoke(this)
} }
} }
@Stable @Immutable
class Route2<P0, P1>( class Route2<P0, P1>(tag: String) : Route(tag) {
tag: String,
state0: MutableState<P0>,
state1: MutableState<P1>
) : Route(tag) {
var p0 by state0
var p1 by state1
context(RouteHandlerScope) context(RouteHandlerScope)
@Composable @Composable
operator fun invoke(content: @Composable (P0, P1) -> Unit) { operator fun invoke(content: @Composable (P0, P1) -> Unit) {
if (this == route) { if (this == route) {
if (route is Route2<*, *>) { content(parameters[0] as P0, parameters[1] as P1)
@Suppress("UNCHECKED_CAST")
(route as Route2<P0, P1>).let { route ->
this.p0 = route.p0
this.p1 = route.p1
}
}
content(this.p0, this.p1)
} }
} }
fun global(p0: P0 = this.p0, p1: P1 = this.p1) { fun global(p0: P0, p1: P1) {
this.p0 = p0 GlobalEmitter.listener?.invoke(this, arrayOf(p0, p1))
this.p1 = p1
GlobalEmitter.listener?.invoke(this)
} }
} }

View file

@ -7,7 +7,12 @@ import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.ContentTransform import androidx.compose.animation.ContentTransform
import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.updateTransition import androidx.compose.animation.core.updateTransition
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ExperimentalAnimationApi @ExperimentalAnimationApi
@ -45,9 +50,14 @@ fun RouteHandler(
) { ) {
val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
val parameters = rememberSaveable {
arrayOfNulls<Any?>(2)
}
val scope = remember(route) { val scope = remember(route) {
RouteHandlerScope( RouteHandlerScope(
route = route, route = route,
parameters = parameters,
push = onRouteChanged, push = onRouteChanged,
pop = { if (handleBackPress) backDispatcher?.onBackPressed() else onRouteChanged(null) } pop = { if (handleBackPress) backDispatcher?.onBackPressed() else onRouteChanged(null) }
) )
@ -55,7 +65,10 @@ fun RouteHandler(
if (listenToGlobalEmitter) { if (listenToGlobalEmitter) {
LaunchedEffect(route) { LaunchedEffect(route) {
Route.GlobalEmitter.listener = if (route == null) onRouteChanged else null Route.GlobalEmitter.listener = if (route == null) ({ newRoute, newParameters ->
newParameters.forEachIndexed(parameters::set)
onRouteChanged(newRoute)
}) else null
} }
} }
@ -65,7 +78,7 @@ fun RouteHandler(
updateTransition(targetState = scope, label = null).AnimatedContent( updateTransition(targetState = scope, label = null).AnimatedContent(
transitionSpec = transitionSpec, transitionSpec = transitionSpec,
contentKey = { it.route?.tag }, contentKey = RouteHandlerScope::route,
modifier = modifier, modifier = modifier,
) { ) {
it.content() it.content()

View file

@ -2,11 +2,12 @@ package it.vfsfitvnm.route
import android.annotation.SuppressLint import android.annotation.SuppressLint
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable
@Immutable @Stable
class RouteHandlerScope( class RouteHandlerScope(
val route: Route?, val route: Route?,
val parameters: Array<Any?>,
private val push: (Route?) -> Unit, private val push: (Route?) -> Unit,
val pop: () -> Unit, val pop: () -> Unit,
) { ) {
@ -18,23 +19,17 @@ class RouteHandlerScope(
} }
} }
operator fun Route0.invoke() { operator fun Route.invoke() {
push(this) push(this)
} }
operator fun <P0> Route1<P0>.invoke( operator fun <P0> Route.invoke(p0: P0) {
p0: P0 = this.p0 parameters[0] = p0
) { invoke()
this.p0 = p0
push(this)
} }
operator fun <P0, P1> Route2<P0, P1>.invoke( operator fun <P0, P1> Route.invoke(p0: P0, p1: P1) {
p0: P0 = this.p0, parameters[1] = p1
p1: P1 = this.p1 invoke(p0)
) {
this.p0 = p0
this.p1 = p1
push(this)
} }
} }

View file

@ -1,8 +1,14 @@
package it.vfsfitvnm.route package it.vfsfitvnm.route
import androidx.compose.animation.* import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.with
@ExperimentalAnimationApi @ExperimentalAnimationApi
val AnimatedContentScope<RouteHandlerScope>.leftSlide: ContentTransform val AnimatedContentScope<RouteHandlerScope>.leftSlide: ContentTransform