Revamp SettingsScreen
This commit is contained in:
@@ -1,25 +1,35 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.screens
|
package it.vfsfitvnm.vimusic.ui.screens
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.compose.animation.AnimatedContentScope
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
|
import androidx.compose.animation.with
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
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.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import it.vfsfitvnm.route.Route0
|
||||||
import it.vfsfitvnm.route.RouteHandler
|
import it.vfsfitvnm.route.RouteHandler
|
||||||
|
import it.vfsfitvnm.route.fastFade
|
||||||
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.EnumValueSelectorDialog
|
import it.vfsfitvnm.vimusic.ui.components.themed.EnumValueSelectorDialog
|
||||||
|
import it.vfsfitvnm.vimusic.ui.screens.settings.AppearanceScreen
|
||||||
|
import it.vfsfitvnm.vimusic.ui.screens.settings.BackupAndRestoreScreen
|
||||||
|
import it.vfsfitvnm.vimusic.ui.screens.settings.rememberAppearanceRoute
|
||||||
|
import it.vfsfitvnm.vimusic.ui.screens.settings.rememberBackupAndRestoreRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
||||||
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
|
||||||
@@ -28,10 +38,26 @@ import it.vfsfitvnm.vimusic.utils.semiBold
|
|||||||
fun SettingsScreen() {
|
fun SettingsScreen() {
|
||||||
val albumRoute = rememberPlaylistOrAlbumRoute()
|
val albumRoute = rememberPlaylistOrAlbumRoute()
|
||||||
val artistRoute = rememberArtistRoute()
|
val artistRoute = rememberArtistRoute()
|
||||||
|
val appearanceRoute = rememberAppearanceRoute()
|
||||||
|
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
RouteHandler(listenToGlobalEmitter = true) {
|
RouteHandler(
|
||||||
|
listenToGlobalEmitter = true,
|
||||||
|
transitionSpec = {
|
||||||
|
when (targetState.route) {
|
||||||
|
appearanceRoute ->
|
||||||
|
slideIntoContainer(AnimatedContentScope.SlideDirection.Left) with
|
||||||
|
slideOutOfContainer(AnimatedContentScope.SlideDirection.Left)
|
||||||
|
else -> when (initialState.route) {
|
||||||
|
appearanceRoute ->
|
||||||
|
slideIntoContainer(AnimatedContentScope.SlideDirection.Right) with
|
||||||
|
slideOutOfContainer(AnimatedContentScope.SlideDirection.Right)
|
||||||
|
else -> fastFade
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
albumRoute { browseId ->
|
albumRoute { browseId ->
|
||||||
PlaylistOrAlbumScreen(
|
PlaylistOrAlbumScreen(
|
||||||
browseId = browseId ?: error("browseId cannot be null")
|
browseId = browseId ?: error("browseId cannot be null")
|
||||||
@@ -44,17 +70,20 @@ fun SettingsScreen() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appearanceRoute {
|
||||||
|
AppearanceScreen()
|
||||||
|
}
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val colorPalette = LocalColorPalette.current
|
val colorPalette = LocalColorPalette.current
|
||||||
val typography = LocalTypography.current
|
val typography = LocalTypography.current
|
||||||
val preferences = LocalPreferences.current
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(bottom = 72.dp)
|
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
|
.padding(bottom = 72.dp)
|
||||||
) {
|
) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -82,43 +111,66 @@ fun SettingsScreen() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(
|
@Composable
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
fun Entry(
|
||||||
modifier = Modifier
|
@DrawableRes icon: Int,
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
color: Color,
|
||||||
.background(
|
title: String,
|
||||||
color = colorPalette.lightBackground,
|
description: String,
|
||||||
shape = RoundedCornerShape(8.dp)
|
route: Route0
|
||||||
)
|
|
||||||
.padding(vertical = 8.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
) {
|
) {
|
||||||
Image(
|
Row(
|
||||||
painter = painterResource(R.drawable.contrast),
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
contentDescription = null,
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
.clickable(
|
||||||
.size(20.dp)
|
indication = rememberRipple(bounded = true),
|
||||||
)
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
onClick = {
|
||||||
|
route()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.padding(horizontal = 16.dp, vertical = 12.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(color = color, shape = CircleShape)
|
||||||
|
.size(36.dp)
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(icon),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(colorPalette.background),
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.Center)
|
||||||
|
.size(18.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
BasicText(
|
Column {
|
||||||
text = "Appearance",
|
BasicText(
|
||||||
style = typography.m.semiBold,
|
text = title,
|
||||||
modifier = Modifier
|
style = typography.s.semiBold,
|
||||||
)
|
modifier = Modifier
|
||||||
|
)
|
||||||
|
|
||||||
|
BasicText(
|
||||||
|
text = description,
|
||||||
|
style = typography.xs.secondary.medium,
|
||||||
|
maxLines = 1,
|
||||||
|
modifier = Modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EnumValueSelectorEntry(
|
Entry(
|
||||||
title = "Theme mode",
|
color = colorPalette.blue,
|
||||||
selectedValue = preferences.colorPaletteMode,
|
icon = R.drawable.color_palette,
|
||||||
onValueSelected = preferences.onColorPaletteModeChange
|
title = "Appearance",
|
||||||
)
|
description = "Change the colors and shapes of the app",
|
||||||
|
route = appearanceRoute,
|
||||||
EnumValueSelectorEntry(
|
|
||||||
title = "Thumbnail roundness",
|
|
||||||
selectedValue = preferences.thumbnailRoundness,
|
|
||||||
onValueSelected = preferences.onThumbnailRoundnessChange
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,7 +178,7 @@ fun SettingsScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private inline fun <reified T: Enum<T>>EnumValueSelectorEntry(
|
inline fun <reified T: Enum<T>>EnumValueSelectorEntry(
|
||||||
title: String,
|
title: String,
|
||||||
selectedValue: T,
|
selectedValue: T,
|
||||||
crossinline onValueSelected: (T) -> Unit,
|
crossinline onValueSelected: (T) -> Unit,
|
||||||
@@ -158,7 +210,8 @@ private inline fun <reified T: Enum<T>>EnumValueSelectorEntry(
|
|||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
onClick = { isShowingDialog = true }
|
onClick = { isShowingDialog = true }
|
||||||
)
|
)
|
||||||
.padding(horizontal = 32.dp, vertical = 8.dp)
|
.padding(start = 24.dp)
|
||||||
|
.padding(horizontal = 32.dp, vertical = 16.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
BasicText(
|
BasicText(
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package it.vfsfitvnm.vimusic.ui.screens.settings
|
||||||
|
|
||||||
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
|
import androidx.compose.foundation.*
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.text.BasicText
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import it.vfsfitvnm.route.RouteHandler
|
||||||
|
import it.vfsfitvnm.vimusic.R
|
||||||
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
|
import it.vfsfitvnm.vimusic.ui.screens.*
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
||||||
|
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
||||||
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
|
||||||
|
@ExperimentalAnimationApi
|
||||||
|
@Composable
|
||||||
|
fun AppearanceScreen() {
|
||||||
|
val albumRoute = rememberPlaylistOrAlbumRoute()
|
||||||
|
val artistRoute = rememberArtistRoute()
|
||||||
|
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
|
RouteHandler(listenToGlobalEmitter = true) {
|
||||||
|
albumRoute { browseId ->
|
||||||
|
PlaylistOrAlbumScreen(
|
||||||
|
browseId = browseId ?: error("browseId cannot be null")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
artistRoute { browseId ->
|
||||||
|
ArtistScreen(
|
||||||
|
browseId = browseId ?: error("browseId cannot be null")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
host {
|
||||||
|
val colorPalette = LocalColorPalette.current
|
||||||
|
val typography = LocalTypography.current
|
||||||
|
val preferences = LocalPreferences.current
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(colorPalette.background)
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(scrollState)
|
||||||
|
.padding(bottom = 72.dp)
|
||||||
|
) {
|
||||||
|
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(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
.size(24.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
BasicText(
|
||||||
|
text = "Appearance",
|
||||||
|
style = typography.m.semiBold
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
.size(24.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumValueSelectorEntry(
|
||||||
|
title = "Theme mode",
|
||||||
|
selectedValue = preferences.colorPaletteMode,
|
||||||
|
onValueSelected = preferences.onColorPaletteModeChange
|
||||||
|
)
|
||||||
|
|
||||||
|
EnumValueSelectorEntry(
|
||||||
|
title = "Thumbnail roundness",
|
||||||
|
selectedValue = preferences.thumbnailRoundness,
|
||||||
|
onValueSelected = preferences.onThumbnailRoundnessChange
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package it.vfsfitvnm.vimusic.ui.screens.settings
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import it.vfsfitvnm.route.Route0
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberAppearanceRoute(): Route0 {
|
||||||
|
return remember {
|
||||||
|
Route0("AppearanceRoute")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,10 +35,10 @@ val DarkColorPalette = ColorPalette(
|
|||||||
lightGray = Color(0xfff8f8f8),
|
lightGray = Color(0xfff8f8f8),
|
||||||
gray = Color(0xFFE5E5E5),
|
gray = Color(0xFFE5E5E5),
|
||||||
darkGray = Color(0xFF838383),
|
darkGray = Color(0xFF838383),
|
||||||
blue = Color(0xff4046bf),
|
blue = Color(0xff507fdd),
|
||||||
red = Color(0xffbf4040),
|
red = Color(0xffbf4040),
|
||||||
green = Color(0xff7fbf40),
|
green = Color(0xff7fbf40),
|
||||||
orange = Color(0xffe8820e),
|
orange = Color(0xffe9a033),
|
||||||
|
|
||||||
primaryContainer = Color(0xff4046bf),
|
primaryContainer = Color(0xff4046bf),
|
||||||
onPrimaryContainer = Color.White,
|
onPrimaryContainer = Color.White,
|
||||||
|
|||||||
9
app/src/main/res/drawable/color_palette.xml
Normal file
9
app/src/main/res/drawable/color_palette.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="512dp"
|
||||||
|
android:height="512dp"
|
||||||
|
android:viewportWidth="512"
|
||||||
|
android:viewportHeight="512">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M441,336.2l-0.06,-0.05c-9.93,-9.18 -22.78,-11.34 -32.16,-12.92l-0.69,-0.12c-9.05,-1.49 -10.48,-2.5 -14.58,-6.17 -2.44,-2.17 -5.35,-5.65 -5.35,-9.94s2.91,-7.77 5.34,-9.94l30.28,-26.87c25.92,-22.91 40.2,-53.66 40.2,-86.59S449.73,119.92 423.78,97c-35.89,-31.59 -85,-49 -138.37,-49C223.72,48 162,71.37 116,112.11c-43.87,38.77 -68,90.71 -68,146.24s24.16,107.47 68,146.23c21.75,19.24 47.49,34.18 76.52,44.42a266.17,266.17 0,0 0,86.87 15h1.81c61,0 119.09,-20.57 159.39,-56.4 9.7,-8.56 15.15,-20.83 15.34,-34.56C456.14,358.87 450.56,345.09 441,336.2ZM112,208a32,32 0,1 1,32 32A32,32 0,0 1,112 208ZM152,343a32,32 0,1 1,32 -32A32,32 0,0 1,152 343ZM192,144a32,32 0,1 1,32 32A32,32 0,0 1,192 144ZM256,415a48,48 0,1 1,48 -48A48,48 0,0 1,256 415ZM328,176a32,32 0,1 1,32 -32A32,32 0,0 1,328 176Z"/>
|
||||||
|
</vector>
|
||||||
Reference in New Issue
Block a user