Replace the first palette with the color scheme provided by the system (#48)

* Replace the first palette with the color scheme provided by the system

* Clean up the code
This commit is contained in:
Ashinch 2022-05-07 00:39:38 +08:00 committed by GitHub
parent 4c7ff2a84e
commit b1f6b60e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 177 additions and 31 deletions

View File

@ -1,5 +1,6 @@
package me.ash.reader.ui.page.home package me.ash.reader.ui.page.home
import android.os.Build
import android.view.SoundEffectConstants import android.view.SoundEffectConstants
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -13,6 +14,7 @@ import androidx.compose.ui.unit.Dp
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import me.ash.reader.data.entity.Filter import me.ash.reader.data.entity.Filter
import me.ash.reader.data.preference.FlowFilterBarStylePreference import me.ash.reader.data.preference.FlowFilterBarStylePreference
import me.ash.reader.data.preference.LocalThemeIndex
import me.ash.reader.ui.ext.getName import me.ash.reader.ui.ext.getName
import me.ash.reader.ui.ext.surfaceColorAtElevation import me.ash.reader.ui.ext.surfaceColorAtElevation
import me.ash.reader.ui.theme.palette.onDark import me.ash.reader.ui.theme.palette.onDark
@ -29,6 +31,7 @@ fun FilterBar(
filterOnClick: (Filter) -> Unit = {}, filterOnClick: (Filter) -> Unit = {},
) { ) {
val view = LocalView.current val view = LocalView.current
val themeIndex = LocalThemeIndex.current
NavigationBar( NavigationBar(
modifier = Modifier modifier = Modifier
@ -77,12 +80,12 @@ fun FilterBar(
filterOnClick(item) filterOnClick(item)
}, },
colors = NavigationBarItemDefaults.colors( colors = NavigationBarItemDefaults.colors(
// selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer alwaysLight true, indicatorColor = if (themeIndex == 5 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// unselectedIconColor = MaterialTheme.colorScheme.outline, MaterialTheme.colorScheme.secondaryContainer
// selectedTextColor = MaterialTheme.colorScheme.onSurface alwaysLight true, } else {
// unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant, MaterialTheme.colorScheme.primaryContainer
indicatorColor = MaterialTheme.colorScheme.primaryContainer onDark MaterialTheme.colorScheme.secondaryContainer, } onDark MaterialTheme.colorScheme.secondaryContainer,
) ),
) )
} }
Spacer(modifier = Modifier.width(filterBarPadding)) Spacer(modifier = Modifier.width(filterBarPadding))

View File

@ -204,7 +204,6 @@ fun ColorAndStyle(
) )
} }
@SuppressLint("FlowOperatorInvokedInComposition")
@Composable @Composable
fun Palettes( fun Palettes(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,

View File

@ -1,6 +1,5 @@
package me.ash.reader.ui.theme package me.ash.reader.ui.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
@ -14,7 +13,7 @@ import me.ash.reader.ui.theme.palette.dynamicLightColorScheme
@Composable @Composable
fun AppTheme( fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(), useDarkTheme: Boolean,
wallpaperPalettes: List<TonalPalettes> = extractTonalPalettesFromUserWallpaper(), wallpaperPalettes: List<TonalPalettes> = extractTonalPalettesFromUserWallpaper(),
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
@ -34,7 +33,7 @@ fun AppTheme(
ProvideZcamViewingConditions { ProvideZcamViewingConditions {
CompositionLocalProvider( CompositionLocalProvider(
LocalTonalPalettes provides tonalPalettes.also { it.Preheating() }, LocalTonalPalettes provides tonalPalettes.apply { Preheating() },
) { ) {
MaterialTheme( MaterialTheme(
colorScheme = colorScheme =

View File

@ -5,6 +5,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import me.ash.reader.data.preference.LocalAmoledDarkTheme import me.ash.reader.data.preference.LocalAmoledDarkTheme
import me.ash.reader.data.preference.LocalDarkTheme import me.ash.reader.data.preference.LocalDarkTheme
@ -127,6 +128,7 @@ fun String.checkColorHex(): String? {
return "[0-9a-fA-F]{6}".toRegex().find(s)?.value return "[0-9a-fA-F]{6}".toRegex().find(s)?.value
} }
@Stable
fun String.safeHexToColor(): Color = fun String.safeHexToColor(): Color =
try { try {
Color(java.lang.Long.parseLong(this, 16)) Color(java.lang.Long.parseLong(this, 16))

View File

@ -3,11 +3,18 @@
* *
* @link https://github.com/Kyant0/MusicYou * @link https://github.com/Kyant0/MusicYou
* @author Kyant0 * @author Kyant0
* @modifier Ashinch
*/ */
package me.ash.reader.ui.theme.palette package me.ash.reader.ui.theme.palette
import android.content.Context
import android.os.Build
import androidx.annotation.ColorRes
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import me.ash.reader.ui.theme.palette.colorspace.cielab.CieLab import me.ash.reader.ui.theme.palette.colorspace.cielab.CieLab
@ -21,6 +28,8 @@ typealias TonalValue = Int
typealias TonalPalette = MutableMap<TonalValue, Color> typealias TonalPalette = MutableMap<TonalValue, Color>
val tonalTokens = listOf(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99, 100)
val LocalTonalPalettes = compositionLocalOf { val LocalTonalPalettes = compositionLocalOf {
TonalPalettes(238.36, 15.0) TonalPalettes(238.36, 15.0)
} }
@ -97,20 +106,144 @@ data class TonalPalettes(
@Composable @Composable
fun Preheating() { fun Preheating() {
val tonalValues = listOf(0, 10, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 95, 98, 99, 100) tonalTokens.forEach { primary(it) }
tonalValues.forEach { primary(it) } tonalTokens.forEach { secondary(it) }
tonalValues.forEach { secondary(it) } tonalTokens.forEach { tertiary(it) }
tonalValues.forEach { tertiary(it) } tonalTokens.forEach { neutral(it) }
tonalValues.forEach { neutral(it) } tonalTokens.forEach { neutralVariant(it) }
tonalValues.forEach { neutralVariant(it) } tonalTokens.forEach { error(it) }
tonalValues.forEach { error(it) } }
@RequiresApi(Build.VERSION_CODES.S)
private fun primarySystem(context: Context, tone: TonalValue): Color = when (tone) {
0 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_1000)
10 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_900)
20 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_800)
30 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_700)
40 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_600)
50 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_500)
60 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_400)
70 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_300)
80 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_200)
90 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_100)
95 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_50)
99 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_10)
100 -> ColorResourceHelper.getColor(context, android.R.color.system_accent1_0)
else -> throw IllegalArgumentException("Unknown primary tone: $tone")
}
@RequiresApi(Build.VERSION_CODES.S)
private fun secondarySystem(context: Context, tone: TonalValue): Color = when (tone) {
0 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_1000)
10 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_900)
20 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_800)
30 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_700)
40 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_600)
50 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_500)
60 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_400)
70 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_300)
80 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_200)
90 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_100)
95 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_50)
99 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_10)
100 -> ColorResourceHelper.getColor(context, android.R.color.system_accent2_0)
else -> throw IllegalArgumentException("Unknown secondary tone: $tone")
}
@RequiresApi(Build.VERSION_CODES.S)
private fun tertiarySystem(context: Context, tone: TonalValue): Color = when (tone) {
0 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_1000)
10 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_900)
20 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_800)
30 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_700)
40 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_600)
50 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_500)
60 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_400)
70 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_300)
80 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_200)
90 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_100)
95 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_50)
99 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_10)
100 -> ColorResourceHelper.getColor(context, android.R.color.system_accent3_0)
else -> throw IllegalArgumentException("Unknown tertiary tone: $tone")
}
@RequiresApi(Build.VERSION_CODES.S)
private fun neutralSystem(context: Context, tone: TonalValue): Color = when (tone) {
0 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_1000)
10 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_900)
20 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_800)
30 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_700)
40 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
50 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_500)
60 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_400)
70 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_300)
80 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_200)
90 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_100)
95 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_50)
99 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_10)
100 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral1_0)
else -> throw IllegalArgumentException("Unknown neutral tone: $tone")
}
@RequiresApi(Build.VERSION_CODES.S)
private fun neutralVariantSystem(context: Context, tone: TonalValue): Color = when (tone) {
0 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_1000)
10 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_900)
20 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_800)
30 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_700)
40 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_600)
50 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_500)
60 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_400)
70 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_300)
80 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_200)
90 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_100)
95 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_50)
99 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_10)
100 -> ColorResourceHelper.getColor(context, android.R.color.system_neutral2_0)
else -> throw IllegalArgumentException("Unknown neutral variant tone: $tone")
} }
companion object { companion object {
@Composable @Composable
@Stable
fun Color.toTonalPalettes(): TonalPalettes { fun Color.toTonalPalettes(): TonalPalettes {
val zcam = toRgb().toZcam() val zcam = toRgb().toZcam()
return TonalPalettes(hue = zcam.hz, primaryChroma = zcam.Cz) return TonalPalettes(hue = zcam.hz, primaryChroma = zcam.Cz)
} }
@RequiresApi(Build.VERSION_CODES.S)
@Composable
@Stable
fun Context.getSystemTonalPalettes(): TonalPalettes {
val tonalPalettes = LocalTonalPalettes.current
tonalTokens.forEach {
tonalPalettes.primary[it] = tonalPalettes.primarySystem(this, it)
}
tonalTokens.forEach {
tonalPalettes.secondary[it] = tonalPalettes.secondarySystem(this, it)
}
tonalTokens.forEach {
tonalPalettes.tertiary[it] = tonalPalettes.tertiarySystem(this, it)
}
tonalTokens.forEach {
tonalPalettes.neutral[it] = tonalPalettes.neutralSystem(this, it)
}
tonalTokens.forEach {
tonalPalettes.neutralVariant[it] = tonalPalettes.neutralVariantSystem(this, it)
}
tonalTokens.forEach {
tonalPalettes error it
}
return tonalPalettes
}
}
}
@RequiresApi(23)
object ColorResourceHelper {
@DoNotInline
fun getColor(context: Context, @ColorRes id: Int): Color {
return Color(context.resources.getColor(id, context.theme))
} }
} }

View File

@ -8,43 +8,53 @@
package me.ash.reader.ui.theme.palette.dynamic package me.ash.reader.ui.theme.palette.dynamic
import android.annotation.SuppressLint
import android.app.WallpaperManager import android.app.WallpaperManager
import android.os.Build import android.os.Build
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import kotlinx.coroutines.flow.map import me.ash.reader.data.preference.LocalCustomPrimaryColor
import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.theme.palette.TonalPalettes import me.ash.reader.ui.theme.palette.TonalPalettes
import me.ash.reader.ui.theme.palette.TonalPalettes.Companion.getSystemTonalPalettes
import me.ash.reader.ui.theme.palette.TonalPalettes.Companion.toTonalPalettes import me.ash.reader.ui.theme.palette.TonalPalettes.Companion.toTonalPalettes
import me.ash.reader.ui.theme.palette.safeHexToColor import me.ash.reader.ui.theme.palette.safeHexToColor
@SuppressLint("FlowOperatorInvokedInComposition") object PresetColor {
val blue = Color(0xFF80BBFF)
val pink = Color(0xFFFFD8E4)
val purple = Color(0xFF62539f)
val yellow = Color(0xFFE9B666)
}
@Composable @Composable
@Stable
fun extractTonalPalettesFromUserWallpaper(): List<TonalPalettes> { fun extractTonalPalettesFromUserWallpaper(): List<TonalPalettes> {
val context = LocalContext.current val context = LocalContext.current
val customPrimaryColor = val customPrimaryColor = LocalCustomPrimaryColor.current
context.dataStore.data.map { it[DataStoreKeys.CustomPrimaryColor.key] ?: "" }
.collectAsState(initial = "").value
val preset = mutableListOf( val preset = mutableListOf(
Color(0xFF80BBFF).toTonalPalettes(), PresetColor.blue.toTonalPalettes(),
Color(0xFFFFD8E4).toTonalPalettes(), PresetColor.pink.toTonalPalettes(),
Color(0xFF62539f).toTonalPalettes(), PresetColor.purple.toTonalPalettes(),
Color(0xFFE9B666).toTonalPalettes(), PresetColor.yellow.toTonalPalettes(),
customPrimaryColor.safeHexToColor().toTonalPalettes() customPrimaryColor.safeHexToColor().toTonalPalettes()
) )
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && !LocalView.current.isInEditMode) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && !LocalView.current.isInEditMode) {
val colors = WallpaperManager.getInstance(LocalContext.current) val colors = WallpaperManager.getInstance(LocalContext.current)
.getWallpaperColors(WallpaperManager.FLAG_SYSTEM) .getWallpaperColors(WallpaperManager.FLAG_SYSTEM)
val primary = colors?.primaryColor?.toArgb() val primary = colors?.primaryColor?.toArgb()
val secondary = colors?.secondaryColor?.toArgb() val secondary = colors?.secondaryColor?.toArgb()
val tertiary = colors?.tertiaryColor?.toArgb() val tertiary = colors?.tertiaryColor?.toArgb()
if (primary != null) preset.add(Color(primary).toTonalPalettes()) if (primary != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
preset.add(context.getSystemTonalPalettes())
} else {
preset.add(Color(primary).toTonalPalettes())
}
}
if (secondary != null) preset.add(Color(secondary).toTonalPalettes()) if (secondary != null) preset.add(Color(secondary).toTonalPalettes())
if (tertiary != null) preset.add(Color(tertiary).toTonalPalettes()) if (tertiary != null) preset.add(Color(tertiary).toTonalPalettes())
} }