Skip to content

Commit

Permalink
feat(settings): 添加颜色对比度设置项
Browse files Browse the repository at this point in the history
  • Loading branch information
Super12138 committed Feb 5, 2025
1 parent 7ab13cd commit 1213344
Show file tree
Hide file tree
Showing 13 changed files with 221 additions and 13 deletions.
3 changes: 3 additions & 0 deletions app/src/main/kotlin/cn/super12138/todo/constants/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ object Constants {

const val PREF_DARK_MODE = "dark_mode"
const val PREF_DARK_MODE_DEFAULT = 1 // Follow System

const val PREF_CONTRAST_LEVEL = "contrast_level"
const val PREF_CONTRAST_LEVEL_DEFAULT = 0f // Normal
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ object GlobalValues {
Constants.PREF_DARK_MODE,
Constants.PREF_DARK_MODE_DEFAULT
)
var contrastLevel: Float by SPDelegates(
Constants.PREF_CONTRAST_LEVEL,
Constants.PREF_CONTRAST_LEVEL_DEFAULT
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cn.super12138.todo.logic.model

import android.content.Context
import cn.super12138.todo.R

enum class ContrastLevel(val value: Float) {
VeryLow(-1f),
Low(-0.5f),
Default(0f),
Medium(0.5f),
High(1f);

fun getDisplayName(context: Context): String {
val resId = when (this) {
VeryLow -> R.string.contrast_very_low
Low -> R.string.contrast_low
Default -> R.string.contrast_default
Medium -> R.string.contrast_medium
High -> R.string.contrast_high
}
return context.getString(resId)
}

companion object {
fun fromFloat(float: Float): ContrastLevel {
return ContrastLevel.entries.find { it.value == float } ?: Default
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,25 @@ class MainActivity : ComponentActivity() {
setContent {
val mainViewModel: MainViewModel = viewModel()
val showConfetti = mainViewModel.showConfetti
// 深色模式
val darkTheme = when (mainViewModel.appDarkMode) {
FollowSystem -> isSystemInDarkTheme()
Light -> false
Dark -> true
}
// 配置状态栏和底部导航栏的颜色(在用户切换深色模式时)
// https://github.com/dn0ne/lotus/blob/master/app/src/main/java/com/dn0ne/player/MainActivity.kt#L266
LaunchedEffect(mainViewModel.appDarkMode) {
WindowCompat.getInsetsController(window, window.decorView).apply {
isAppearanceLightStatusBars = !darkTheme
isAppearanceLightNavigationBars = !darkTheme
}
}
ToDoTheme(darkTheme = darkTheme) {

ToDoTheme(
darkTheme = darkTheme,
contrastLevel = mainViewModel.appContrastLevel.value.toDouble()
) {
Surface(color = MaterialTheme.colorScheme.background) {
TodoNavigation(
viewModel = mainViewModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import cn.super12138.todo.R
import cn.super12138.todo.constants.Constants
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
import cn.super12138.todo.ui.pages.settings.components.SwitchSettingsItem
import cn.super12138.todo.ui.pages.settings.components.contrast.ContrastPicker
import cn.super12138.todo.ui.pages.settings.components.darkmode.DarkModePicker
import cn.super12138.todo.ui.pages.settings.components.palette.PalettePicker
import cn.super12138.todo.ui.theme.appPaletteStyle
Expand Down Expand Up @@ -45,7 +46,12 @@ fun SettingsAppearance(
) {
DarkModePicker(onDarkModeChange = { viewModel.setDarkMode(it) })

PalettePicker(onPaletteChange = { appPaletteStyle = it })
PalettePicker(
contrastLevel = viewModel.appContrastLevel,
onPaletteChange = { appPaletteStyle = it }
)

ContrastPicker(onContrastChange = { viewModel.setContrastLevel(it) })

SwitchSettingsItem(
key = Constants.PREF_DYNAMIC_COLOR,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package cn.super12138.todo.ui.pages.settings.components

import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.ScrollableDefaults
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
Expand Down Expand Up @@ -40,6 +42,34 @@ fun RowSettingsItem(
flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
userScrollEnabled: Boolean = true,
content: LazyListScope.() -> Unit
) {
MoreContentSettingsItem(
title = title,
description = description,
shape = shape,
modifier = modifier
) {
LazyRow(
modifier = Modifier.fillMaxWidth(),
state = state,
contentPadding = contentPadding,
reverseLayout = reverseLayout,
horizontalArrangement = horizontalArrangement,
verticalAlignment = verticalAlignment,
flingBehavior = flingBehavior,
userScrollEnabled = userScrollEnabled,
content = content
)
}
}

@Composable
fun MoreContentSettingsItem(
title: String,
description: String? = null,
shape: Shape = MaterialTheme.shapes.large,
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Column(
modifier = modifier
Expand Down Expand Up @@ -70,16 +100,12 @@ fun RowSettingsItem(

Spacer(Modifier.size(8.dp))

LazyRow(
modifier = Modifier.fillMaxWidth(),
state = state,
contentPadding = contentPadding,
reverseLayout = reverseLayout,
horizontalArrangement = horizontalArrangement,
verticalAlignment = verticalAlignment,
flingBehavior = flingBehavior,
userScrollEnabled = userScrollEnabled,
content = content
)
/*Box(
Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.large)
.background(MaterialTheme.colorScheme.surfaceContainer)
) {*/
content()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package cn.super12138.todo.ui.pages.settings.components.contrast

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Label
import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import cn.super12138.todo.R
import cn.super12138.todo.constants.Constants
import cn.super12138.todo.logic.model.ContrastLevel
import cn.super12138.todo.ui.pages.settings.components.MoreContentSettingsItem
import cn.super12138.todo.ui.pages.settings.state.rememberPrefFloatState

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ContrastPicker(
onContrastChange: (ContrastLevel) -> Unit,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
MoreContentSettingsItem(
title = stringResource(R.string.pref_contrast_level),
description = stringResource(R.string.pref_contrast_level_desc)
) {
var contrastState by rememberPrefFloatState(
Constants.PREF_CONTRAST_LEVEL,
Constants.PREF_CONTRAST_LEVEL_DEFAULT
)
val interactionSource = remember { MutableInteractionSource() }

Slider(
modifier = Modifier.semantics {
contentDescription = context.getString(R.string.tip_change_contrast_level)
},
value = contrastState,
onValueChange = {
contrastState = it
onContrastChange(ContrastLevel.fromFloat(it))
},
valueRange = -1f..1f,
steps = 3,
interactionSource = interactionSource,
thumb = {
Label(
label = {
PlainTooltip(
modifier = Modifier
.sizeIn(45.dp, 25.dp)
.wrapContentWidth()
) {
Text(ContrastLevel.fromFloat(contrastState).getDisplayName(context))
}
},
interactionSource = interactionSource
) {
SliderDefaults.Thumb(interactionSource)
}
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import cn.super12138.todo.constants.GlobalValues
import cn.super12138.todo.logic.model.ContrastLevel
import cn.super12138.todo.ui.theme.PaletteStyle
import cn.super12138.todo.ui.theme.dynamicColorScheme

@Composable
fun PaletteItem(
paletteStyle: PaletteStyle,
contrastLevel: ContrastLevel,
selected: Boolean,
onSelect: () -> Unit,
modifier: Modifier = Modifier
Expand All @@ -58,6 +60,7 @@ fun PaletteItem(
Color(0xFF0061A4)
},
isDark = isSystemInDarkTheme(),
contrastLevel = contrastLevel.value.toDouble(),
style = paletteStyle
)
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import cn.super12138.todo.R
import cn.super12138.todo.constants.Constants
import cn.super12138.todo.logic.model.ContrastLevel
import cn.super12138.todo.ui.pages.settings.components.RowSettingsItem
import cn.super12138.todo.ui.pages.settings.state.rememberPrefIntState
import cn.super12138.todo.ui.theme.PaletteStyle

@Composable
fun PalettePicker(
contrastLevel: ContrastLevel,
onPaletteChange: (paletteStyle: PaletteStyle) -> Unit,
modifier: Modifier = Modifier
) {
Expand All @@ -38,6 +40,7 @@ fun PalettePicker(
PaletteItem(
paletteStyle = paletteStyle,
selected = PaletteStyle.fromId(paletteState) == paletteStyle,
contrastLevel = contrastLevel,
onSelect = {
paletteState = paletteStyle.id
onPaletteChange(paletteStyle)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package cn.super12138.todo.ui.pages.settings.state
import android.content.Context
import android.content.SharedPreferences
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableFloatState
import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -28,6 +30,12 @@ fun rememberPrefIntState(key: String, default: Int): MutableIntState {
return remember { PrefMutableIntState(context, key, default) }
}

@Composable
fun rememberPrefFloatState(key: String, default: Float): MutableFloatState {
val context = LocalContext.current
return remember { PrefMutableFloatState(context, key, default) }
}

private class PrefMutableBooleanState(
val context: Context,
val key: String,
Expand Down Expand Up @@ -74,6 +82,29 @@ private class PrefMutableIntState(
}
}

private class PrefMutableFloatState(
val context: Context,
val key: String,
default: Float,
) : MutableFloatState {
private val delegate = mutableFloatStateOf(context.pref.getFloat(key, default))

override var floatValue: Float
get() = delegate.floatValue
set(value) {
delegate.floatValue = value
context.pref.edit().putFloat(key, value).apply()
}

override fun component1(): Float {
return delegate.component1()
}

override fun component2(): (Float) -> Unit {
return delegate.component2()
}
}

/**
* 来自:https://github.com/hushenghao/AndroidEasterEggs/blob/main/basic/src/main/java/com/dede/android_eggs/util/Pref.kt
* @author hushenghao
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope
import cn.super12138.todo.constants.GlobalValues
import cn.super12138.todo.logic.Repository
import cn.super12138.todo.logic.database.TodoEntity
import cn.super12138.todo.logic.model.ContrastLevel
import cn.super12138.todo.logic.model.DarkMode
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -26,6 +27,8 @@ class MainViewModel : ViewModel() {
// 深色模式
var appDarkMode by mutableStateOf(DarkMode.fromId(GlobalValues.darkMode))
private set
var appContrastLevel by mutableStateOf(ContrastLevel.fromFloat(GlobalValues.contrastLevel))
private set

// 多选逻辑参考:https://github.com/X1nto/Mauth
private val _selectedTodoIds = MutableStateFlow(listOf<Int>())
Expand Down Expand Up @@ -118,4 +121,8 @@ class MainViewModel : ViewModel() {
fun setDarkMode(darkMode: DarkMode) {
appDarkMode = darkMode
}

fun setContrastLevel(contrastLevel: ContrastLevel) {
appContrastLevel = contrastLevel
}
}
7 changes: 7 additions & 0 deletions app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,11 @@
<string name="dark_mode_system">跟随系统</string>
<string name="dark_mode_light">浅色模式</string>
<string name="dark_mode_dark">深色模式</string>
<string name="pref_contrast_level">对比度</string>
<string name="pref_contrast_level_desc">调整应用的颜色对比度</string>
<string name="contrast_very_low">非常低</string>
<string name="contrast_low">低</string>
<string name="contrast_default">默认</string>
<string name="contrast_medium">中</string>
<string name="contrast_high">高</string>
</resources>
Loading

0 comments on commit 1213344

Please sign in to comment.