Merge pull request #47 from Ashinch/feature/dark-theme

Add dark theme settings
This commit is contained in:
Ashinch 2022-05-05 20:58:05 +08:00 committed by GitHub
commit 4d2d857676
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 282 additions and 33 deletions

View File

@ -0,0 +1,41 @@
package me.ash.reader.data.preference
import android.content.Context
import androidx.datastore.preferences.core.Preferences
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put
sealed class AmoledDarkThemePreference(val value: Boolean) : Preference() {
object ON : AmoledDarkThemePreference(true)
object OFF : AmoledDarkThemePreference(false)
override fun put(context: Context, scope: CoroutineScope) {
scope.launch {
context.dataStore.put(
DataStoreKeys.AmoledDarkTheme,
value
)
}
}
companion object {
val default = OFF
val values = listOf(ON, OFF)
fun fromPreferences(preferences: Preferences) =
when (preferences[DataStoreKeys.AmoledDarkTheme.key]) {
true -> ON
false -> OFF
else -> default
}
}
}
operator fun AmoledDarkThemePreference.not(): AmoledDarkThemePreference =
when (value) {
true -> AmoledDarkThemePreference.OFF
false -> AmoledDarkThemePreference.ON
}

View File

@ -0,0 +1,66 @@
package me.ash.reader.data.preference
import android.content.Context
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.datastore.preferences.core.Preferences
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import me.ash.reader.R
import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put
sealed class DarkThemePreference(val value: Int) : Preference() {
object UseDeviceTheme : DarkThemePreference(0)
object ON : DarkThemePreference(1)
object OFF : DarkThemePreference(2)
override fun put(context: Context, scope: CoroutineScope) {
scope.launch {
context.dataStore.put(
DataStoreKeys.DarkTheme,
value
)
}
}
fun getDesc(context: Context): String =
when (this) {
UseDeviceTheme -> context.getString(R.string.use_device_theme)
ON -> context.getString(R.string.on)
OFF -> context.getString(R.string.off)
}
@Composable
fun isDarkTheme(): Boolean = when (this) {
UseDeviceTheme -> isSystemInDarkTheme()
ON -> true
OFF -> false
}
companion object {
val default = UseDeviceTheme
val values = listOf(UseDeviceTheme, ON, OFF)
fun fromPreferences(preferences: Preferences) =
when (preferences[DataStoreKeys.DarkTheme.key]) {
0 -> UseDeviceTheme
1 -> ON
2 -> OFF
else -> default
}
}
}
@Composable
operator fun DarkThemePreference.not(): DarkThemePreference =
when (this) {
DarkThemePreference.UseDeviceTheme -> if (isSystemInDarkTheme()) {
DarkThemePreference.OFF
} else {
DarkThemePreference.ON
}
DarkThemePreference.ON -> DarkThemePreference.OFF
DarkThemePreference.OFF -> DarkThemePreference.ON
}

View File

@ -14,6 +14,8 @@ import me.ash.reader.ui.ext.dataStore
data class Settings( data class Settings(
val themeIndex: Int = ThemeIndexPreference.default, val themeIndex: Int = ThemeIndexPreference.default,
val customPrimaryColor: String = CustomPrimaryColorPreference.default, val customPrimaryColor: String = CustomPrimaryColorPreference.default,
val darkTheme: DarkThemePreference = DarkThemePreference.default,
val amoledDarkTheme: AmoledDarkThemePreference = AmoledDarkThemePreference.default,
val feedsFilterBarStyle: FeedsFilterBarStylePreference = FeedsFilterBarStylePreference.default, val feedsFilterBarStyle: FeedsFilterBarStylePreference = FeedsFilterBarStylePreference.default,
val feedsFilterBarFilled: FeedsFilterBarFilledPreference = FeedsFilterBarFilledPreference.default, val feedsFilterBarFilled: FeedsFilterBarFilledPreference = FeedsFilterBarFilledPreference.default,
@ -41,6 +43,8 @@ fun Preferences.toSettings(): Settings {
return Settings( return Settings(
themeIndex = ThemeIndexPreference.fromPreferences(this), themeIndex = ThemeIndexPreference.fromPreferences(this),
customPrimaryColor = CustomPrimaryColorPreference.fromPreferences(this), customPrimaryColor = CustomPrimaryColorPreference.fromPreferences(this),
darkTheme = DarkThemePreference.fromPreferences(this),
amoledDarkTheme = AmoledDarkThemePreference.fromPreferences(this),
feedsFilterBarStyle = FeedsFilterBarStylePreference.fromPreferences(this), feedsFilterBarStyle = FeedsFilterBarStylePreference.fromPreferences(this),
feedsFilterBarFilled = FeedsFilterBarFilledPreference.fromPreferences(this), feedsFilterBarFilled = FeedsFilterBarFilledPreference.fromPreferences(this),
@ -60,7 +64,9 @@ fun Preferences.toSettings(): Settings {
flowArticleListImage = FlowArticleListImagePreference.fromPreferences(this), flowArticleListImage = FlowArticleListImagePreference.fromPreferences(this),
flowArticleListDesc = FlowArticleListDescPreference.fromPreferences(this), flowArticleListDesc = FlowArticleListDescPreference.fromPreferences(this),
flowArticleListTime = FlowArticleListTimePreference.fromPreferences(this), flowArticleListTime = FlowArticleListTimePreference.fromPreferences(this),
flowArticleListDateStickyHeader = FlowArticleListDateStickyHeaderPreference.fromPreferences(this), flowArticleListDateStickyHeader = FlowArticleListDateStickyHeaderPreference.fromPreferences(
this
),
flowArticleListTonalElevation = FlowArticleListTonalElevationPreference.fromPreferences(this), flowArticleListTonalElevation = FlowArticleListTonalElevationPreference.fromPreferences(this),
) )
} }
@ -80,6 +86,8 @@ fun SettingsProvider(
CompositionLocalProvider( CompositionLocalProvider(
LocalThemeIndex provides settings.themeIndex, LocalThemeIndex provides settings.themeIndex,
LocalCustomPrimaryColor provides settings.customPrimaryColor, LocalCustomPrimaryColor provides settings.customPrimaryColor,
LocalDarkTheme provides settings.darkTheme,
LocalAmoledDarkTheme provides settings.amoledDarkTheme,
LocalFeedsTopBarTonalElevation provides settings.feedsTopBarTonalElevation, LocalFeedsTopBarTonalElevation provides settings.feedsTopBarTonalElevation,
LocalFeedsGroupListExpand provides settings.feedsGroupListExpand, LocalFeedsGroupListExpand provides settings.feedsGroupListExpand,
@ -110,6 +118,10 @@ val LocalThemeIndex =
compositionLocalOf { ThemeIndexPreference.default } compositionLocalOf { ThemeIndexPreference.default }
val LocalCustomPrimaryColor = val LocalCustomPrimaryColor =
compositionLocalOf { CustomPrimaryColorPreference.default } compositionLocalOf { CustomPrimaryColorPreference.default }
val LocalDarkTheme =
compositionLocalOf<DarkThemePreference> { DarkThemePreference.default }
val LocalAmoledDarkTheme =
compositionLocalOf<AmoledDarkThemePreference> { AmoledDarkThemePreference.default }
val LocalFeedsFilterBarStyle = val LocalFeedsFilterBarStyle =
compositionLocalOf<FeedsFilterBarStylePreference> { FeedsFilterBarStylePreference.default } compositionLocalOf<FeedsFilterBarStylePreference> { FeedsFilterBarStylePreference.default }

View File

@ -13,8 +13,8 @@ import coil.compose.AsyncImage
import coil.imageLoader import coil.imageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
import com.caverock.androidsvg.SVG import com.caverock.androidsvg.SVG
import me.ash.reader.data.preference.LocalDarkTheme
import me.ash.reader.ui.svg.parseDynamicColor import me.ash.reader.ui.svg.parseDynamicColor
import me.ash.reader.ui.theme.LocalUseDarkTheme
import me.ash.reader.ui.theme.palette.LocalTonalPalettes import me.ash.reader.ui.theme.palette.LocalTonalPalettes
@Composable @Composable
@ -24,10 +24,10 @@ fun DynamicSVGImage(
contentDescription: String, contentDescription: String,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val useDarkTheme = LocalUseDarkTheme.current val useDarkTheme = LocalDarkTheme.current.isDarkTheme()
val tonalPalettes = LocalTonalPalettes.current val tonalPalettes = LocalTonalPalettes.current
var size by remember { mutableStateOf(IntSize.Zero) } var size by remember { mutableStateOf(IntSize.Zero) }
val pic by remember(tonalPalettes, size) { val pic by remember(useDarkTheme, tonalPalettes, size) {
mutableStateOf( mutableStateOf(
PictureDrawable( PictureDrawable(
SVG.getFromString(svgImageString.parseDynamicColor(tonalPalettes, useDarkTheme)) SVG.getFromString(svgImageString.parseDynamicColor(tonalPalettes, useDarkTheme))

View File

@ -130,6 +130,16 @@ sealed class DataStoreKeys<T> {
get() = stringPreferencesKey("customPrimaryColor") get() = stringPreferencesKey("customPrimaryColor")
} }
object DarkTheme : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int>
get() = intPreferencesKey("darkTheme")
}
object AmoledDarkTheme : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("amoledDarkTheme")
}
object FeedsFilterBarStyle : DataStoreKeys<Int>() { object FeedsFilterBarStyle : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int> override val key: Preferences.Key<Int>
get() = intPreferencesKey("feedsFilterBarStyle") get() = intPreferencesKey("feedsFilterBarStyle")

View File

@ -14,6 +14,7 @@ import com.google.accompanist.navigation.animation.AnimatedNavHost
import com.google.accompanist.navigation.animation.rememberAnimatedNavController import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import me.ash.reader.data.entity.Filter import me.ash.reader.data.entity.Filter
import me.ash.reader.data.preference.LocalDarkTheme
import me.ash.reader.ui.ext.* import me.ash.reader.ui.ext.*
import me.ash.reader.ui.page.home.HomeViewAction import me.ash.reader.ui.page.home.HomeViewAction
import me.ash.reader.ui.page.home.HomeViewModel import me.ash.reader.ui.page.home.HomeViewModel
@ -22,13 +23,13 @@ import me.ash.reader.ui.page.home.flow.FlowPage
import me.ash.reader.ui.page.home.read.ReadPage import me.ash.reader.ui.page.home.read.ReadPage
import me.ash.reader.ui.page.settings.SettingsPage import me.ash.reader.ui.page.settings.SettingsPage
import me.ash.reader.ui.page.settings.color.ColorAndStyle import me.ash.reader.ui.page.settings.color.ColorAndStyle
import me.ash.reader.ui.page.settings.color.DarkTheme
import me.ash.reader.ui.page.settings.color.feeds.FeedsPageStyle import me.ash.reader.ui.page.settings.color.feeds.FeedsPageStyle
import me.ash.reader.ui.page.settings.color.flow.FlowPageStyle import me.ash.reader.ui.page.settings.color.flow.FlowPageStyle
import me.ash.reader.ui.page.settings.interaction.Interaction import me.ash.reader.ui.page.settings.interaction.Interaction
import me.ash.reader.ui.page.settings.tips.TipsAndSupport import me.ash.reader.ui.page.settings.tips.TipsAndSupport
import me.ash.reader.ui.page.startup.StartupPage import me.ash.reader.ui.page.startup.StartupPage
import me.ash.reader.ui.theme.AppTheme import me.ash.reader.ui.theme.AppTheme
import me.ash.reader.ui.theme.LocalUseDarkTheme
@OptIn(ExperimentalAnimationApi::class, androidx.compose.material.ExperimentalMaterialApi::class) @OptIn(ExperimentalAnimationApi::class, androidx.compose.material.ExperimentalMaterialApi::class)
@Composable @Composable
@ -86,8 +87,9 @@ fun HomeEntry(
} }
} }
AppTheme { val useDarkTheme = LocalDarkTheme.current.isDarkTheme()
val useDarkTheme = LocalUseDarkTheme.current
AppTheme(useDarkTheme = useDarkTheme) {
rememberSystemUiController().run { rememberSystemUiController().run {
setStatusBarColor(Color.Transparent, !useDarkTheme) setStatusBarColor(Color.Transparent, !useDarkTheme)
@ -129,6 +131,9 @@ fun HomeEntry(
animatedComposable(route = RouteName.COLOR_AND_STYLE) { animatedComposable(route = RouteName.COLOR_AND_STYLE) {
ColorAndStyle(navController) ColorAndStyle(navController)
} }
animatedComposable(route = RouteName.DARK_THEME) {
DarkTheme(navController)
}
animatedComposable(route = RouteName.FEEDS_PAGE_STYLE) { animatedComposable(route = RouteName.FEEDS_PAGE_STYLE) {
FeedsPageStyle(navController) FeedsPageStyle(navController)
} }

View File

@ -14,6 +14,7 @@ object RouteName {
// Color & Style // Color & Style
const val COLOR_AND_STYLE = "color_and_style" const val COLOR_AND_STYLE = "color_and_style"
const val DARK_THEME = "dark_theme"
const val FEEDS_PAGE_STYLE = "feeds_page_style" const val FEEDS_PAGE_STYLE = "feeds_page_style"
const val FLOW_PAGE_STYLE = "flow_page_style" const val FLOW_PAGE_STYLE = "flow_page_style"

View File

@ -2,7 +2,6 @@ package me.ash.reader.ui.page.home.read
import android.util.Log import android.util.Log
import androidx.compose.animation.* import androidx.compose.animation.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyListState
@ -77,7 +76,7 @@ fun ReadPage(
} }
Scaffold( Scaffold(
modifier = Modifier.background(MaterialTheme.colorScheme.surface), containerColor = MaterialTheme.colorScheme.surface,
topBar = {}, topBar = {},
content = { content = {
Box(Modifier.fillMaxSize()) { Box(Modifier.fillMaxSize()) {

View File

@ -19,6 +19,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import me.ash.reader.ui.theme.palette.LocalTonalPalettes
import me.ash.reader.ui.theme.palette.onDark
@Composable @Composable
fun SettingItem( fun SettingItem(
@ -31,6 +33,8 @@ fun SettingItem(
onClick: () -> Unit, onClick: () -> Unit,
action: (@Composable () -> Unit)? = null action: (@Composable () -> Unit)? = null
) { ) {
val tonalPalettes = LocalTonalPalettes.current
Surface( Surface(
modifier = modifier modifier = modifier
.clickable { onClick() } .clickable { onClick() }
@ -71,7 +75,8 @@ fun SettingItem(
Divider( Divider(
modifier = Modifier modifier = Modifier
.padding(start = 16.dp) .padding(start = 16.dp)
.size(1.dp, 32.dp) .size(1.dp, 32.dp),
color = tonalPalettes neutralVariant 80 onDark (tonalPalettes neutralVariant 30),
) )
} }
Box(Modifier.padding(start = 16.dp)) { Box(Modifier.padding(start = 16.dp)) {

View File

@ -26,16 +26,12 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.preference.CustomPrimaryColorPreference import me.ash.reader.data.preference.*
import me.ash.reader.data.preference.LocalCustomPrimaryColor
import me.ash.reader.data.preference.LocalThemeIndex
import me.ash.reader.data.preference.ThemeIndexPreference
import me.ash.reader.ui.component.* import me.ash.reader.ui.component.*
import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.common.RouteName
import me.ash.reader.ui.page.settings.SettingItem import me.ash.reader.ui.page.settings.SettingItem
import me.ash.reader.ui.svg.PALETTE import me.ash.reader.ui.svg.PALETTE
import me.ash.reader.ui.svg.SVGString import me.ash.reader.ui.svg.SVGString
import me.ash.reader.ui.theme.LocalUseDarkTheme
import me.ash.reader.ui.theme.palette.* import me.ash.reader.ui.theme.palette.*
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.dynamic.extractTonalPalettesFromUserWallpaper import me.ash.reader.ui.theme.palette.dynamic.extractTonalPalettesFromUserWallpaper
@ -47,9 +43,11 @@ fun ColorAndStyle(
navController: NavHostController, navController: NavHostController,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val useDarkTheme = LocalUseDarkTheme.current val darkTheme = LocalDarkTheme.current
val darkThemeNot = !darkTheme
val themeIndex = LocalThemeIndex.current val themeIndex = LocalThemeIndex.current
val customPrimaryColor = LocalCustomPrimaryColor.current val customPrimaryColor = LocalCustomPrimaryColor.current
val scope = rememberCoroutineScope()
val wallpaperTonalPalettes = extractTonalPalettesFromUserWallpaper() val wallpaperTonalPalettes = extractTonalPalettesFromUserWallpaper()
var radioButtonSelected by remember { mutableStateOf(if (themeIndex > 4) 0 else 1) } var radioButtonSelected by remember { mutableStateOf(if (themeIndex > 4) 0 else 1) }
@ -151,12 +149,19 @@ fun ColorAndStyle(
) )
SettingItem( SettingItem(
title = stringResource(R.string.dark_theme), title = stringResource(R.string.dark_theme),
desc = stringResource(R.string.use_device_theme), desc = darkTheme.getDesc(context),
enable = false,
separatedActions = true, separatedActions = true,
onClick = {}, onClick = {
navController.navigate(RouteName.DARK_THEME) {
launchSingleTop = true
}
},
) { ) {
Switch(activated = useDarkTheme, enable = false) Switch(
activated = darkTheme.isDarkTheme()
) {
darkThemeNot.put(context, scope)
}
} }
SettingItem( SettingItem(
title = stringResource(R.string.basic_fonts), title = stringResource(R.string.basic_fonts),

View File

@ -0,0 +1,100 @@
package me.ash.reader.ui.page.settings.color
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import me.ash.reader.R
import me.ash.reader.data.preference.DarkThemePreference
import me.ash.reader.data.preference.LocalAmoledDarkTheme
import me.ash.reader.data.preference.LocalDarkTheme
import me.ash.reader.data.preference.not
import me.ash.reader.ui.component.DisplayText
import me.ash.reader.ui.component.FeedbackIconButton
import me.ash.reader.ui.component.Subtitle
import me.ash.reader.ui.component.Switch
import me.ash.reader.ui.page.settings.SettingItem
import me.ash.reader.ui.theme.palette.onLight
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DarkTheme(
navController: NavHostController,
) {
val context = LocalContext.current
val darkTheme = LocalDarkTheme.current
val amoledDarkTheme = LocalAmoledDarkTheme.current
val scope = rememberCoroutineScope()
Scaffold(
modifier = Modifier
.background(MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface)
.statusBarsPadding()
.navigationBarsPadding(),
containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface,
topBar = {
SmallTopAppBar(
colors = TopAppBarDefaults.smallTopAppBarColors(
containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface
),
title = {},
navigationIcon = {
FeedbackIconButton(
imageVector = Icons.Rounded.ArrowBack,
contentDescription = stringResource(R.string.back),
tint = MaterialTheme.colorScheme.onSurface
) {
navController.popBackStack()
}
},
actions = {}
)
},
content = {
LazyColumn {
item {
DisplayText(text = stringResource(R.string.dark_theme), desc = "")
}
item {
DarkThemePreference.values.map {
SettingItem(
title = it.getDesc(context),
onClick = {
it.put(context, scope)
},
) {
RadioButton(selected = it == darkTheme, onClick = {
it.put(context, scope)
})
}
}
Subtitle(
modifier = Modifier.padding(horizontal = 24.dp),
text = stringResource(R.string.other),
)
SettingItem(
title = stringResource(R.string.amoled_dark_theme),
onClick = {
(!amoledDarkTheme).put(context, scope)
},
) {
Switch(activated = amoledDarkTheme.value) {
(!amoledDarkTheme).put(context, scope)
}
}
}
}
}
)
}

View File

@ -4,7 +4,6 @@ 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
import androidx.compose.runtime.compositionLocalOf
import me.ash.reader.data.preference.LocalThemeIndex import me.ash.reader.data.preference.LocalThemeIndex
import me.ash.reader.ui.theme.palette.LocalTonalPalettes import me.ash.reader.ui.theme.palette.LocalTonalPalettes
import me.ash.reader.ui.theme.palette.TonalPalettes import me.ash.reader.ui.theme.palette.TonalPalettes
@ -13,8 +12,6 @@ import me.ash.reader.ui.theme.palette.dynamic.extractTonalPalettesFromUserWallpa
import me.ash.reader.ui.theme.palette.dynamicDarkColorScheme import me.ash.reader.ui.theme.palette.dynamicDarkColorScheme
import me.ash.reader.ui.theme.palette.dynamicLightColorScheme import me.ash.reader.ui.theme.palette.dynamicLightColorScheme
val LocalUseDarkTheme = compositionLocalOf { false }
@Composable @Composable
fun AppTheme( fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(), useDarkTheme: Boolean = isSystemInDarkTheme(),
@ -38,7 +35,6 @@ fun AppTheme(
ProvideZcamViewingConditions { ProvideZcamViewingConditions {
CompositionLocalProvider( CompositionLocalProvider(
LocalTonalPalettes provides tonalPalettes.also { it.Preheating() }, LocalTonalPalettes provides tonalPalettes.also { it.Preheating() },
LocalUseDarkTheme provides useDarkTheme,
) { ) {
MaterialTheme( MaterialTheme(
colorScheme = colorScheme =

View File

@ -6,7 +6,8 @@ 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.ui.graphics.Color import androidx.compose.ui.graphics.Color
import me.ash.reader.ui.theme.LocalUseDarkTheme import me.ash.reader.data.preference.LocalAmoledDarkTheme
import me.ash.reader.data.preference.LocalDarkTheme
@Composable @Composable
fun dynamicLightColorScheme(): ColorScheme { fun dynamicLightColorScheme(): ColorScheme {
@ -41,6 +42,8 @@ fun dynamicLightColorScheme(): ColorScheme {
@Composable @Composable
fun dynamicDarkColorScheme(): ColorScheme { fun dynamicDarkColorScheme(): ColorScheme {
val palettes = LocalTonalPalettes.current val palettes = LocalTonalPalettes.current
val amoledDarkTheme = LocalAmoledDarkTheme.current
return darkColorScheme( return darkColorScheme(
primary = palettes primary 80, primary = palettes primary 80,
onPrimary = palettes primary 20, onPrimary = palettes primary 20,
@ -57,7 +60,7 @@ fun dynamicDarkColorScheme(): ColorScheme {
onTertiaryContainer = palettes tertiary 90, onTertiaryContainer = palettes tertiary 90,
background = palettes neutral 10, background = palettes neutral 10,
onBackground = palettes neutral 90, onBackground = palettes neutral 90,
surface = palettes neutral 10, surface = palettes neutral if (amoledDarkTheme.value) 0 else 10,
onSurface = palettes neutral 90, onSurface = palettes neutral 90,
surfaceVariant = palettes neutralVariant 30, surfaceVariant = palettes neutralVariant 30,
onSurfaceVariant = palettes neutralVariant 80, onSurfaceVariant = palettes neutralVariant 80,
@ -68,20 +71,18 @@ fun dynamicDarkColorScheme(): ColorScheme {
) )
} }
@Suppress("NOTHING_TO_INLINE")
@Composable @Composable
inline infix fun Color.onLight(lightColor: Color): Color = infix fun Color.onLight(lightColor: Color): Color =
if (!LocalUseDarkTheme.current) lightColor else this if (!LocalDarkTheme.current.isDarkTheme()) lightColor else this
@Suppress("NOTHING_TO_INLINE")
@Composable @Composable
inline infix fun Color.onDark(darkColor: Color): Color = infix fun Color.onDark(darkColor: Color): Color =
if (LocalUseDarkTheme.current) darkColor else this if (LocalDarkTheme.current.isDarkTheme()) darkColor else this
@Composable @Composable
infix fun Color.alwaysLight(isAlways: Boolean): Color { infix fun Color.alwaysLight(isAlways: Boolean): Color {
val colorScheme = MaterialTheme.colorScheme val colorScheme = MaterialTheme.colorScheme
return if (isAlways && LocalUseDarkTheme.current) { return if (isAlways && LocalDarkTheme.current.isDarkTheme()) {
when (this) { when (this) {
colorScheme.primary -> colorScheme.onPrimary colorScheme.primary -> colorScheme.onPrimary
colorScheme.secondary -> colorScheme.onSecondary colorScheme.secondary -> colorScheme.onSecondary

View File

@ -102,6 +102,10 @@
<string name="style">样式</string> <string name="style">样式</string>
<string name="dark_theme">深色主题</string> <string name="dark_theme">深色主题</string>
<string name="use_device_theme">跟随系统设置</string> <string name="use_device_theme">跟随系统设置</string>
<string name="on">开启</string>
<string name="off">关闭</string>
<string name="amoled_dark_theme">Amoled 深色主题</string>
<string name="other">其他</string>
<string name="tonal_elevation">色调海拔</string> <string name="tonal_elevation">色调海拔</string>
<string name="fonts">字体</string> <string name="fonts">字体</string>
<string name="basic_fonts">基本字体</string> <string name="basic_fonts">基本字体</string>

View File

@ -103,6 +103,10 @@
<string name="style">Style</string> <string name="style">Style</string>
<string name="dark_theme">Dark Theme</string> <string name="dark_theme">Dark Theme</string>
<string name="use_device_theme">Use Device Theme</string> <string name="use_device_theme">Use Device Theme</string>
<string name="on">On</string>
<string name="off">Off</string>
<string name="other">Other</string>
<string name="amoled_dark_theme">Amoled Dark Theme</string>
<string name="tonal_elevation">Tonal Elevation</string> <string name="tonal_elevation">Tonal Elevation</string>
<string name="fonts">Fonts</string> <string name="fonts">Fonts</string>
<string name="basic_fonts">Basic Fonts</string> <string name="basic_fonts">Basic Fonts</string>