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 -->
|
// KMK -->
|
||||||
fun colorTheme() = preferenceStore.getInt("pref_color_theme", 0xFFDF0090.toInt())
|
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 themeCoverBased() = preferenceStore.getBoolean("pref_theme_cover_based_key", true)
|
||||||
|
|
||||||
fun themeCoverBasedStyle() = preferenceStore.getEnum("pref_theme_cover_based_style_key", PaletteStyle.Vibrant)
|
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),
|
subtitle = stringResource(KMR.strings.custom_color_description),
|
||||||
onClick = { navigator.push(AppCustomThemeColorPickerScreen()) },
|
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 <--
|
// KMK <--
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
pref = amoledPref,
|
pref = amoledPref,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package eu.kanade.presentation.theme
|
package eu.kanade.presentation.theme
|
||||||
|
|
||||||
|
import android.app.UiModeManager
|
||||||
|
import android.os.Build
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.material3.ColorScheme
|
import androidx.compose.material3.ColorScheme
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
|
@ -7,6 +9,8 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
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.core.content.getSystemService
|
||||||
|
import com.materialkolor.Contrast
|
||||||
import com.materialkolor.DynamicMaterialTheme
|
import com.materialkolor.DynamicMaterialTheme
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
import eu.kanade.domain.ui.model.AppTheme
|
import eu.kanade.domain.ui.model.AppTheme
|
||||||
|
|
@ -58,6 +62,7 @@ fun TachiyomiTheme(
|
||||||
) {
|
) {
|
||||||
val uiPreferences = Injekt.get<UiPreferences>()
|
val uiPreferences = Injekt.get<UiPreferences>()
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
val context = LocalContext.current
|
||||||
val isAmoled = amoled ?: uiPreferences.themeDarkAmoled().get()
|
val isAmoled = amoled ?: uiPreferences.themeDarkAmoled().get()
|
||||||
if (seedColor != null) {
|
if (seedColor != null) {
|
||||||
DynamicMaterialTheme(
|
DynamicMaterialTheme(
|
||||||
|
|
@ -67,6 +72,11 @@ fun TachiyomiTheme(
|
||||||
style = uiPreferences.themeCoverBasedStyle().get(),
|
style = uiPreferences.themeCoverBasedStyle().get(),
|
||||||
animate = true,
|
animate = true,
|
||||||
content = content,
|
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 {
|
} else {
|
||||||
// KMK <--
|
// KMK <--
|
||||||
|
|
@ -110,7 +120,11 @@ private fun getThemeColorScheme(
|
||||||
}
|
}
|
||||||
// KMK -->
|
// KMK -->
|
||||||
AppTheme.CUSTOM -> {
|
AppTheme.CUSTOM -> {
|
||||||
CustomColorScheme(uiPreferences)
|
CustomColorScheme(
|
||||||
|
context = LocalContext.current,
|
||||||
|
seed = uiPreferences.colorTheme().get(),
|
||||||
|
style = uiPreferences.customThemeStyle().get(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// KMK <--
|
// KMK <--
|
||||||
else -> {
|
else -> {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,21 @@
|
||||||
package eu.kanade.presentation.theme.colorscheme
|
package eu.kanade.presentation.theme.colorscheme
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.app.UiModeManager
|
||||||
import androidx.compose.material3.ColorScheme
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import com.google.android.material.color.utilities.Hct
|
import androidx.core.content.getSystemService
|
||||||
import com.google.android.material.color.utilities.MaterialDynamicColors
|
import com.materialkolor.Contrast
|
||||||
import com.google.android.material.color.utilities.SchemeContent
|
import com.materialkolor.PaletteStyle
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
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(context, seed, style)
|
||||||
|
|
||||||
private val custom = CustomCompatColorScheme(seed)
|
|
||||||
|
|
||||||
override val darkScheme
|
override val darkScheme
|
||||||
get() = custom.darkScheme
|
get() = custom.darkScheme
|
||||||
|
|
@ -21,60 +24,32 @@ internal class CustomColorScheme(uiPreferences: UiPreferences) : BaseColorScheme
|
||||||
get() = custom.lightScheme
|
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 lightScheme = dynamicColorScheme(
|
||||||
override val darkScheme = generateColorSchemeFromSeed(seed = seed, dark = true)
|
seedColor = Color(seed),
|
||||||
|
isDark = false,
|
||||||
companion object {
|
isAmoled = false,
|
||||||
private fun Int.toComposeColor(): Color = Color(this)
|
style = style,
|
||||||
|
contrastLevel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
@SuppressLint("RestrictedApi")
|
context.getSystemService<UiModeManager>()?.contrast?.toDouble() ?: Contrast.Default.value
|
||||||
private fun generateColorSchemeFromSeed(seed: Int, dark: Boolean): ColorScheme {
|
} else {
|
||||||
val scheme = SchemeContent(
|
Contrast.Default.value
|
||||||
Hct.fromInt(seed),
|
},
|
||||||
dark,
|
)
|
||||||
0.0,
|
override val darkScheme = dynamicColorScheme(
|
||||||
)
|
seedColor = Color(seed),
|
||||||
val dynamicColors = MaterialDynamicColors()
|
isDark = true,
|
||||||
return ColorScheme(
|
isAmoled = false,
|
||||||
primary = dynamicColors.primary().getArgb(scheme).toComposeColor(),
|
style = style,
|
||||||
onPrimary = dynamicColors.onPrimary().getArgb(scheme).toComposeColor(),
|
contrastLevel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
primaryContainer = dynamicColors.primaryContainer().getArgb(scheme).toComposeColor(),
|
context.getSystemService<UiModeManager>()?.contrast?.toDouble() ?: Contrast.Default.value
|
||||||
onPrimaryContainer = dynamicColors.onPrimaryContainer().getArgb(scheme).toComposeColor(),
|
} else {
|
||||||
inversePrimary = dynamicColors.inversePrimary().getArgb(scheme).toComposeColor(),
|
Contrast.Default.value
|
||||||
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(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.reader
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.UiModeManager
|
||||||
import android.app.assist.AssistContent
|
import android.app.assist.AssistContent
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
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.elevation.SurfaceColors
|
||||||
import com.google.android.material.transition.platform.MaterialContainerTransform
|
import com.google.android.material.transition.platform.MaterialContainerTransform
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
|
import com.materialkolor.Contrast
|
||||||
import com.materialkolor.dynamicColorScheme
|
import com.materialkolor.dynamicColorScheme
|
||||||
import dev.chrisbanes.insetter.applyInsetter
|
import dev.chrisbanes.insetter.applyInsetter
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
|
|
@ -744,6 +746,11 @@ class ReaderActivity : BaseActivity() {
|
||||||
isDark = isNightMode(),
|
isDark = isNightMode(),
|
||||||
isAmoled = themeDarkAmoled,
|
isAmoled = themeDarkAmoled,
|
||||||
style = themeCoverBasedStyle,
|
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 <--
|
// KMK <--
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,10 @@
|
||||||
|
|
||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<!-- Appearance section -->
|
<!-- Appearance section -->
|
||||||
|
<string name="pref_custom_theme_style">Custom theme style</string>
|
||||||
<string name="pref_details_page_theme">Details page</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">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_tonalspot">Tonal Spot</string>
|
||||||
<string name="pref_theme_cover_based_style_neutral">Neutral</string>
|
<string name="pref_theme_cover_based_style_neutral">Neutral</string>
|
||||||
<string name="pref_theme_cover_based_style_vibrant">Vibrant</string>
|
<string name="pref_theme_cover_based_style_vibrant">Vibrant</string>
|
||||||
|
|
@ -44,7 +45,7 @@
|
||||||
|
|
||||||
<!-- Custom Color Picker -->
|
<!-- Custom Color Picker -->
|
||||||
<string name="pref_custom_color">Palette Personalizer</string>
|
<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>
|
<string name="theme_custom">Custom Theme</string>
|
||||||
|
|
||||||
<!-- Library section -->
|
<!-- Library section -->
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue