Create NotificationScreen

This commit is contained in:
vfsfitvnm 2022-06-11 18:57:32 +02:00
parent baea3d252c
commit afc64cae74
10 changed files with 277 additions and 21 deletions

View file

@ -0,0 +1,51 @@
package it.vfsfitvnm.vimusic.ui.components.themed
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.center
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.unit.dp
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.utils.drawCircle
@Composable
fun Switch(
isChecked: Boolean,
modifier: Modifier = Modifier,
) {
val colorPalette = LocalColorPalette.current
val backgroundColor by animateColorAsState(if (isChecked) colorPalette.primaryContainer else colorPalette.lightBackground)
val color by animateColorAsState(if (isChecked) colorPalette.onPrimaryContainer else colorPalette.textDisabled)
val offset by animateDpAsState(if (isChecked) 36.dp else 12.dp)
Spacer(
modifier = modifier
.width(48.dp)
.height(24.dp)
.background(color = backgroundColor, shape = CircleShape)
.drawBehind {
drawCircle(
color = color,
radius = 8.dp.toPx(),
center = size.center.copy(x = offset.toPx()),
shadow = Shadow(
color = Color.Black.copy(alpha = 0.4f),
blurRadius = 8.dp.toPx(),
offset = Offset(x = -1.dp.toPx(), y = 1.dp.toPx())
)
)
}
)
}

View file

@ -28,9 +28,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.media3.common.Player
import it.vfsfitvnm.route.Route
import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.route.rememberRoute
import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.enums.SongCollection
@ -86,13 +84,7 @@ fun HomeScreen(
}
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
RouteHandler(
// route = route,
// onRouteChanged = onRouteChanged,
listenToGlobalEmitter = true
) {
println("route: ${this.route?.tag}")
RouteHandler(listenToGlobalEmitter = true) {
settingsRoute {
SettingsScreen()
}

View file

@ -11,8 +11,7 @@ import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.*
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
@ -20,13 +19,11 @@ import it.vfsfitvnm.route.*
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.EnumValueSelectorDialog
import it.vfsfitvnm.vimusic.ui.components.themed.Switch
import it.vfsfitvnm.vimusic.ui.screens.settings.*
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.utils.disabled
import it.vfsfitvnm.vimusic.utils.medium
import it.vfsfitvnm.vimusic.utils.secondary
import it.vfsfitvnm.vimusic.utils.semiBold
import it.vfsfitvnm.vimusic.utils.*
@ExperimentalAnimationApi
@Composable
@ -34,6 +31,7 @@ fun SettingsScreen() {
val albumRoute = rememberPlaylistOrAlbumRoute()
val artistRoute = rememberArtistRoute()
val appearanceRoute = rememberAppearanceRoute()
val notificationRoute = rememberNotificationRoute()
val backupAndRestoreRoute = rememberBackupAndRestoreRoute()
val otherRoute = rememberOtherRoute()
val aboutRoute = rememberAboutRoute()
@ -44,10 +42,11 @@ fun SettingsScreen() {
listenToGlobalEmitter = true,
transitionSpec = {
when (targetState.route) {
appearanceRoute, backupAndRestoreRoute, otherRoute, aboutRoute -> leftSlide
albumRoute, artistRoute -> fastFade
else -> when (initialState.route) {
appearanceRoute, backupAndRestoreRoute, otherRoute, aboutRoute -> rightSlide
else -> fastFade
albumRoute, artistRoute -> fastFade
null -> leftSlide
else -> rightSlide
}
}
}
@ -68,6 +67,10 @@ fun SettingsScreen() {
AppearanceScreen()
}
notificationRoute {
NotificationScreen()
}
backupAndRestoreRoute {
BackupAndRestoreScreen()
}
@ -177,6 +180,14 @@ fun SettingsScreen() {
route = appearanceRoute,
)
Entry(
color = colorPalette.cyan,
icon = R.drawable.notifications,
title = "Notification",
description = "Customize the notification appearance",
route = notificationRoute
)
Entry(
color = colorPalette.orange,
icon = R.drawable.server,
@ -213,8 +224,6 @@ inline fun <reified T: Enum<T>>EnumValueSelectorEntry(
modifier: Modifier = Modifier,
crossinline valueText: (T) -> String = Enum<T>::name
) {
val typography = LocalTypography.current
var isShowingDialog by remember {
mutableStateOf(false)
}
@ -241,6 +250,53 @@ inline fun <reified T: Enum<T>>EnumValueSelectorEntry(
)
}
@Composable
fun SwitchSettingEntry(
title: String,
text: String,
isChecked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
isEnabled: Boolean = true
) {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.clickable(
indication = rememberRipple(bounded = true),
interactionSource = remember { MutableInteractionSource() },
onClick = { onCheckedChange(!isChecked) },
enabled = isEnabled
)
.padding(start = 24.dp)
.padding(horizontal = 32.dp, vertical = 16.dp)
.fillMaxWidth()
) {
Column(
modifier = Modifier
.weight(1f)
) {
BasicText(
text = title,
style = typography.xs.semiBold.copy(color = if (isEnabled) colorPalette.text else colorPalette.darkGray),
)
BasicText(
text = text,
style = typography.xs.semiBold.copy(color = if (isEnabled) colorPalette.textSecondary else colorPalette.darkGray),
)
}
Switch(isChecked = isChecked)
}
}
@Composable
@NonRestartableComposable
fun SettingsEntry(
@ -319,4 +375,4 @@ fun SettingsEntryGroupText(
.padding(start = 24.dp, top = 24.dp)
.padding(horizontal = 32.dp)
)
}
}

View file

@ -0,0 +1,92 @@
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 NotificationScreen() {
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 = "Notification",
style = typography.m.semiBold
)
Spacer(
modifier = Modifier
.padding(horizontal = 16.dp, vertical = 8.dp)
.size(24.dp)
)
}
SwitchSettingEntry(
title = "[SOON] Show Like button",
text = "Mark a song as favorite",
isChecked = preferences.displayLikeButtonInNotification,
onCheckedChange = {
preferences.displayLikeButtonInNotification = it
},
isEnabled = false
)
}
}
}
}

View file

@ -11,6 +11,13 @@ fun rememberAppearanceRoute(): Route0 {
}
}
@Composable
fun rememberNotificationRoute(): Route0 {
return remember {
Route0("NotificationRoute")
}
}
@Composable
fun rememberBackupAndRestoreRoute(): Route0 {
return remember {

View file

@ -19,6 +19,7 @@ data class ColorPalette(
val green: Color,
val orange: Color,
val magenta: Color,
val cyan: Color,
val primaryContainer: Color,
val onPrimaryContainer: Color,
@ -40,6 +41,7 @@ val DarkColorPalette = ColorPalette(
green = Color(0xff82b154),
orange = Color(0xffe9a033),
magenta = Color(0xffbb4da4),
cyan = Color(0xFF4DA5BB),
primaryContainer = Color(0xff4046bf),
onPrimaryContainer = Color.White,
@ -67,6 +69,7 @@ val LightColorPalette = ColorPalette(
green = Color(0xff7fbf40),
orange = Color(0xffe8730e),
magenta = Color(0xffbb4da4),
cyan = Color(0xFF4DBBB2),
primaryContainer = Color(0xff4046bf),
onPrimaryContainer = Color.White,

View file

@ -0,0 +1,29 @@
package it.vfsfitvnm.vimusic.utils
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.drawscope.DrawScope
fun DrawScope.drawCircle(
color: Color,
shadow: Shadow,
radius: Float = size.minDimension / 2.0f,
center: Offset = this.center,
alpha: Float = 1.0f,
style: PaintingStyle = PaintingStyle.Fill,
colorFilter: ColorFilter? = null,
blendMode: BlendMode = DrawScope.DefaultBlendMode
) = drawContext.canvas.nativeCanvas.drawCircle(
center.x,
center.y,
radius,
Paint().also {
it.color = color
it.alpha = alpha
it.blendMode = blendMode
it.colorFilter = colorFilter
it.style = style
}.asFrameworkPaint().also {
it.setShadowLayer(shadow.blurRadius, shadow.offset.x, shadow.offset.y, shadow.color.toArgb())
}
)

View file

@ -23,6 +23,7 @@ class Preferences(holder: SharedPreferences) : SharedPreferences by holder {
var homePageSongCollection by preference("homePageSongCollection", SongCollection.MostPlayed)
var thumbnailRoundness by preference("thumbnailRoundness", ThumbnailRoundness.Light)
var coilDiskCacheMaxSizeBytes by preference("coilDiskCacheMaxSizeBytes", 512L * 1024 * 1024)
var displayLikeButtonInNotification by preference("displayLikeButtonInNotification", false)
}
val Context.preferences: Preferences

View file

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:pathData="M352.92,80C288,80 256,144 256,144s-32,-64 -96.92,-64c-52.76,0 -94.54,44.14 -95.08,96.81 -1.1,109.33 86.73,187.08 183,252.42a16,16 0,0 0,18 0c96.26,-65.34 184.09,-143.09 183,-252.42 -0.54,-52.67 -42.32,-96.81 -95.08,-96.81z"
android:strokeLineJoin="round"
android:strokeWidth="32"
android:fillColor="#00000000"
android:strokeColor="#000"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M440.08,341.31c-1.66,-2 -3.29,-4 -4.89,-5.93 -22,-26.61 -35.31,-42.67 -35.31,-118 0,-39 -9.33,-71 -27.72,-95 -13.56,-17.73 -31.89,-31.18 -56.05,-41.12a3,3 0,0 1,-0.82 -0.67C306.6,51.49 282.82,32 256,32s-50.59,19.49 -59.28,48.56a3.13,3.13 0,0 1,-0.81 0.65c-56.38,23.21 -83.78,67.74 -83.78,136.14 0,75.36 -13.29,91.42 -35.31,118 -1.6,1.93 -3.23,3.89 -4.89,5.93a35.16,35.16 0,0 0,-4.65 37.62c6.17,13 19.32,21.07 34.33,21.07H410.5c14.94,0 28,-8.06 34.19,-21A35.17,35.17 0,0 0,440.08 341.31Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M256,480a80.06,80.06 0,0 0,70.44 -42.13,4 4,0 0,0 -3.54,-5.87H189.12a4,4 0,0 0,-3.55 5.87A80.06,80.06 0,0 0,256 480Z"/>
</vector>