Improve custom theme
* update string * migrate to use DynamicMaterialTheme instead * support various style for custom theme * use BaseColorScheme with dynamicColorScheme instead, to avoid Activity being recreated * apply theme right when changing theme style * change default style to Fidelity * adaptable to system contrast with Custom theme & Theme based cover
This commit is contained in:
parent
39e5644f5f
commit
b72d910cc9
6 changed files with 101 additions and 68 deletions
|
|
@ -32,6 +32,8 @@ class UiPreferences(
|
|||
// KMK -->
|
||||
fun colorTheme() = preferenceStore.getInt("pref_color_theme", 0xFFDF0090.toInt())
|
||||
|
||||
fun customThemeStyle() = preferenceStore.getEnum("pref_custom_theme_style_key", PaletteStyle.Fidelity)
|
||||
|
||||
fun themeCoverBased() = preferenceStore.getBoolean("pref_theme_cover_based_key", true)
|
||||
|
||||
fun themeCoverBasedStyle() = preferenceStore.getEnum("pref_theme_cover_based_style_key", PaletteStyle.Vibrant)
|
||||
|
|
|
|||
|
|
@ -106,6 +106,40 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||
subtitle = stringResource(KMR.strings.custom_color_description),
|
||||
onClick = { navigator.push(AppCustomThemeColorPickerScreen()) },
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = uiPreferences.customThemeStyle(),
|
||||
title = stringResource(KMR.strings.pref_custom_theme_style),
|
||||
enabled = appTheme == AppTheme.CUSTOM,
|
||||
entries = PaletteStyle.entries
|
||||
.associateWith {
|
||||
when (it) {
|
||||
PaletteStyle.TonalSpot ->
|
||||
stringResource(KMR.strings.pref_theme_cover_based_style_tonalspot)
|
||||
PaletteStyle.Neutral ->
|
||||
stringResource(KMR.strings.pref_theme_cover_based_style_neutral)
|
||||
PaletteStyle.Vibrant ->
|
||||
stringResource(KMR.strings.pref_theme_cover_based_style_vibrant)
|
||||
PaletteStyle.Expressive ->
|
||||
stringResource(KMR.strings.pref_theme_cover_based_style_expressive)
|
||||
PaletteStyle.Rainbow ->
|
||||
stringResource(KMR.strings.pref_theme_cover_based_style_rainbow)
|
||||
PaletteStyle.FruitSalad ->
|
||||
stringResource(KMR.strings.pref_theme_cover_based_style_fruitsalad)
|
||||
PaletteStyle.Monochrome ->
|
||||
stringResource(KMR.strings.pref_theme_cover_based_style_monochrome)
|
||||
PaletteStyle.Fidelity ->
|
||||
stringResource(KMR.strings.pref_theme_cover_based_style_fidelity)
|
||||
PaletteStyle.Content ->
|
||||
stringResource(KMR.strings.pref_theme_cover_based_style_content)
|
||||
else -> it.name
|
||||
}
|
||||
}
|
||||
.toImmutableMap(),
|
||||
onValueChanged = {
|
||||
(context as? Activity)?.let { ActivityCompat.recreate(it) }
|
||||
true
|
||||
},
|
||||
),
|
||||
// KMK <--
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = amoledPref,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package eu.kanade.presentation.theme
|
||||
|
||||
import android.app.UiModeManager
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
|
@ -7,6 +9,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.content.getSystemService
|
||||
import com.materialkolor.Contrast
|
||||
import com.materialkolor.DynamicMaterialTheme
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.domain.ui.model.AppTheme
|
||||
|
|
@ -58,6 +62,7 @@ fun TachiyomiTheme(
|
|||
) {
|
||||
val uiPreferences = Injekt.get<UiPreferences>()
|
||||
// KMK -->
|
||||
val context = LocalContext.current
|
||||
val isAmoled = amoled ?: uiPreferences.themeDarkAmoled().get()
|
||||
if (seedColor != null) {
|
||||
DynamicMaterialTheme(
|
||||
|
|
@ -67,6 +72,11 @@ fun TachiyomiTheme(
|
|||
style = uiPreferences.themeCoverBasedStyle().get(),
|
||||
animate = true,
|
||||
content = content,
|
||||
contrastLevel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
context.getSystemService<UiModeManager>()?.contrast?.toDouble() ?: Contrast.Default.value
|
||||
} else {
|
||||
Contrast.Default.value
|
||||
},
|
||||
)
|
||||
} else {
|
||||
// KMK <--
|
||||
|
|
@ -110,7 +120,11 @@ private fun getThemeColorScheme(
|
|||
}
|
||||
// KMK -->
|
||||
AppTheme.CUSTOM -> {
|
||||
CustomColorScheme(uiPreferences)
|
||||
CustomColorScheme(
|
||||
context = LocalContext.current,
|
||||
seed = uiPreferences.colorTheme().get(),
|
||||
style = uiPreferences.customThemeStyle().get(),
|
||||
)
|
||||
}
|
||||
// KMK <--
|
||||
else -> {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
package eu.kanade.presentation.theme.colorscheme
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import android.app.UiModeManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.google.android.material.color.utilities.Hct
|
||||
import com.google.android.material.color.utilities.MaterialDynamicColors
|
||||
import com.google.android.material.color.utilities.SchemeContent
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import androidx.core.content.getSystemService
|
||||
import com.materialkolor.Contrast
|
||||
import com.materialkolor.PaletteStyle
|
||||
import com.materialkolor.dynamicColorScheme
|
||||
|
||||
internal class CustomColorScheme(uiPreferences: UiPreferences) : BaseColorScheme() {
|
||||
internal class CustomColorScheme(
|
||||
context: Context,
|
||||
seed: Int,
|
||||
style: PaletteStyle,
|
||||
) : BaseColorScheme() {
|
||||
|
||||
private val seed = uiPreferences.colorTheme().get()
|
||||
|
||||
private val custom = CustomCompatColorScheme(seed)
|
||||
private val custom = CustomCompatColorScheme(context, seed, style)
|
||||
|
||||
override val darkScheme
|
||||
get() = custom.darkScheme
|
||||
|
|
@ -21,60 +24,32 @@ internal class CustomColorScheme(uiPreferences: UiPreferences) : BaseColorScheme
|
|||
get() = custom.lightScheme
|
||||
}
|
||||
|
||||
private class CustomCompatColorScheme(seed: Int) : BaseColorScheme() {
|
||||
private class CustomCompatColorScheme(
|
||||
context: Context,
|
||||
seed: Int,
|
||||
style: PaletteStyle,
|
||||
) : BaseColorScheme() {
|
||||
|
||||
override val lightScheme = generateColorSchemeFromSeed(seed = seed, dark = false)
|
||||
override val darkScheme = generateColorSchemeFromSeed(seed = seed, dark = true)
|
||||
|
||||
companion object {
|
||||
private fun Int.toComposeColor(): Color = Color(this)
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
private fun generateColorSchemeFromSeed(seed: Int, dark: Boolean): ColorScheme {
|
||||
val scheme = SchemeContent(
|
||||
Hct.fromInt(seed),
|
||||
dark,
|
||||
0.0,
|
||||
)
|
||||
val dynamicColors = MaterialDynamicColors()
|
||||
return ColorScheme(
|
||||
primary = dynamicColors.primary().getArgb(scheme).toComposeColor(),
|
||||
onPrimary = dynamicColors.onPrimary().getArgb(scheme).toComposeColor(),
|
||||
primaryContainer = dynamicColors.primaryContainer().getArgb(scheme).toComposeColor(),
|
||||
onPrimaryContainer = dynamicColors.onPrimaryContainer().getArgb(scheme).toComposeColor(),
|
||||
inversePrimary = dynamicColors.inversePrimary().getArgb(scheme).toComposeColor(),
|
||||
secondary = dynamicColors.secondary().getArgb(scheme).toComposeColor(),
|
||||
onSecondary = dynamicColors.onSecondary().getArgb(scheme).toComposeColor(),
|
||||
secondaryContainer = dynamicColors.secondaryContainer().getArgb(scheme).toComposeColor(),
|
||||
onSecondaryContainer = dynamicColors.onSecondaryContainer().getArgb(scheme).toComposeColor(),
|
||||
tertiary = dynamicColors.tertiary().getArgb(scheme).toComposeColor(),
|
||||
onTertiary = dynamicColors.onTertiary().getArgb(scheme).toComposeColor(),
|
||||
tertiaryContainer = dynamicColors.tertiary().getArgb(scheme).toComposeColor(),
|
||||
onTertiaryContainer = dynamicColors.onTertiaryContainer().getArgb(scheme).toComposeColor(),
|
||||
background = dynamicColors.background().getArgb(scheme).toComposeColor(),
|
||||
onBackground = dynamicColors.onBackground().getArgb(scheme).toComposeColor(),
|
||||
surface = dynamicColors.surface().getArgb(scheme).toComposeColor(),
|
||||
onSurface = dynamicColors.onSurface().getArgb(scheme).toComposeColor(),
|
||||
surfaceVariant = dynamicColors.surfaceVariant().getArgb(scheme).toComposeColor(),
|
||||
onSurfaceVariant = dynamicColors.onSurfaceVariant().getArgb(scheme).toComposeColor(),
|
||||
surfaceTint = dynamicColors.surfaceTint().getArgb(scheme).toComposeColor(),
|
||||
inverseSurface = dynamicColors.inverseSurface().getArgb(scheme).toComposeColor(),
|
||||
inverseOnSurface = dynamicColors.inverseOnSurface().getArgb(scheme).toComposeColor(),
|
||||
error = dynamicColors.error().getArgb(scheme).toComposeColor(),
|
||||
onError = dynamicColors.onError().getArgb(scheme).toComposeColor(),
|
||||
errorContainer = dynamicColors.errorContainer().getArgb(scheme).toComposeColor(),
|
||||
onErrorContainer = dynamicColors.onErrorContainer().getArgb(scheme).toComposeColor(),
|
||||
outline = dynamicColors.outline().getArgb(scheme).toComposeColor(),
|
||||
outlineVariant = dynamicColors.outlineVariant().getArgb(scheme).toComposeColor(),
|
||||
scrim = Color.Black,
|
||||
surfaceBright = dynamicColors.surfaceBright().getArgb(scheme).toComposeColor(),
|
||||
surfaceDim = dynamicColors.surfaceDim().getArgb(scheme).toComposeColor(),
|
||||
surfaceContainer = dynamicColors.surfaceContainer().getArgb(scheme).toComposeColor(),
|
||||
surfaceContainerHigh = dynamicColors.surfaceContainerHigh().getArgb(scheme).toComposeColor(),
|
||||
surfaceContainerHighest = dynamicColors.surfaceContainerHighest().getArgb(scheme).toComposeColor(),
|
||||
surfaceContainerLow = dynamicColors.surfaceContainerLow().getArgb(scheme).toComposeColor(),
|
||||
surfaceContainerLowest = dynamicColors.surfaceContainerLowest().getArgb(scheme).toComposeColor(),
|
||||
)
|
||||
}
|
||||
}
|
||||
override val lightScheme = dynamicColorScheme(
|
||||
seedColor = Color(seed),
|
||||
isDark = false,
|
||||
isAmoled = false,
|
||||
style = style,
|
||||
contrastLevel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
context.getSystemService<UiModeManager>()?.contrast?.toDouble() ?: Contrast.Default.value
|
||||
} else {
|
||||
Contrast.Default.value
|
||||
},
|
||||
)
|
||||
override val darkScheme = dynamicColorScheme(
|
||||
seedColor = Color(seed),
|
||||
isDark = true,
|
||||
isAmoled = false,
|
||||
style = style,
|
||||
contrastLevel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
context.getSystemService<UiModeManager>()?.contrast?.toDouble() ?: Contrast.Default.value
|
||||
} else {
|
||||
Contrast.Default.value
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.reader
|
|||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.UiModeManager
|
||||
import android.app.assist.AssistContent
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
|
|
@ -59,6 +60,7 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
|||
import com.google.android.material.elevation.SurfaceColors
|
||||
import com.google.android.material.transition.platform.MaterialContainerTransform
|
||||
import com.hippo.unifile.UniFile
|
||||
import com.materialkolor.Contrast
|
||||
import com.materialkolor.dynamicColorScheme
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
|
|
@ -744,6 +746,11 @@ class ReaderActivity : BaseActivity() {
|
|||
isDark = isNightMode(),
|
||||
isAmoled = themeDarkAmoled,
|
||||
style = themeCoverBasedStyle,
|
||||
contrastLevel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
getSystemService<UiModeManager>()?.contrast?.toDouble() ?: Contrast.Default.value
|
||||
} else {
|
||||
Contrast.Default.value
|
||||
},
|
||||
)
|
||||
}
|
||||
// KMK <--
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@
|
|||
|
||||
<!-- Preferences -->
|
||||
<!-- Appearance section -->
|
||||
<string name="pref_custom_theme_style">Custom theme style</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_style">Cover based theme style</string>
|
||||
<string name="pref_theme_cover_based_style_tonalspot">Tonal Spot</string>
|
||||
<string name="pref_theme_cover_based_style_neutral">Neutral</string>
|
||||
<string name="pref_theme_cover_based_style_vibrant">Vibrant</string>
|
||||
|
|
@ -44,7 +45,7 @@
|
|||
|
||||
<!-- Custom Color Picker -->
|
||||
<string name="pref_custom_color">Palette Personalizer</string>
|
||||
<string name="custom_color_description">Pick a color for the custom Theme</string>
|
||||
<string name="custom_color_description">Pick a seed color for the custom Theme</string>
|
||||
<string name="theme_custom">Custom Theme</string>
|
||||
|
||||
<!-- Library section -->
|
||||
|
|
|
|||
Loading…
Reference in a new issue