feat(settings): 添加外观与个性化设置

里面有动态配色和主题样式两个设置的实现
后续还有待优化 SharedPreferences 的读写方式
This commit is contained in:
Super12138 2025-02-05 09:38:35 +08:00
parent e729125111
commit 32e22929ed
21 changed files with 522 additions and 33 deletions

View file

@ -1,6 +1,8 @@
package cn.super12138.todo
import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
import cn.super12138.todo.logic.database.TodoDatabase
import cn.super12138.todo.ui.pages.crash.CrashHandler
@ -8,6 +10,8 @@ class TodoApp : Application() {
private val database by lazy { TodoDatabase.getDatabase(this) }
companion object {
@SuppressLint("StaticFieldLeak")
lateinit var context: Context
lateinit var db: TodoDatabase
}
@ -15,6 +19,7 @@ class TodoApp : Application() {
super.onCreate()
db = database
context = applicationContext
val crashHandler = CrashHandler(applicationContext)
Thread.setDefaultUncaughtExceptionHandler(crashHandler)

View file

@ -0,0 +1,11 @@
package cn.super12138.todo.constants
object Constants {
const val SP_NAME = "cn.super12138.todo_preferences"
const val PREF_DYNAMIC_COLOR = "dynamic_color"
const val PREF_DYNAMIC_COLOR_DEFAULT = true
const val PREF_PALETTE_STYLE = "palette_style"
const val PREF_PALETTE_STYLE_DEFAULT = 1 // TonalSpot
}

View file

@ -0,0 +1,14 @@
package cn.super12138.todo.constants
import cn.super12138.todo.utils.SPDelegates
object GlobalValues {
var dynamicColor: Boolean by SPDelegates(
Constants.PREF_DYNAMIC_COLOR,
Constants.PREF_DYNAMIC_COLOR_DEFAULT
)
var paletteStyle: Int by SPDelegates(
Constants.PREF_PALETTE_STYLE,
Constants.PREF_PALETTE_STYLE_DEFAULT
)
}

View file

@ -10,6 +10,7 @@ import cn.super12138.todo.ui.pages.editor.TodoEditorPage
import cn.super12138.todo.ui.pages.main.MainPage
import cn.super12138.todo.ui.pages.settings.SettingsAbout
import cn.super12138.todo.ui.pages.settings.SettingsAboutLicence
import cn.super12138.todo.ui.pages.settings.SettingsAppearance
import cn.super12138.todo.ui.pages.settings.SettingsMain
import cn.super12138.todo.ui.theme.materialSharedAxisXIn
import cn.super12138.todo.ui.theme.materialSharedAxisXOut
@ -82,10 +83,17 @@ fun TodoNavigation(
composable(TodoScreen.SettingsMain.name) {
SettingsMain(
onNavigateUp = { navController.navigateUp() },
toAppearancePage = { navController.navigate(TodoScreen.SettingsAppearance.name) },
toAboutPage = { navController.navigate(TodoScreen.SettingsAbout.name) }
)
}
composable(TodoScreen.SettingsAppearance.name) {
SettingsAppearance(
onNavigateUp = { navController.navigateUp() }
)
}
composable(TodoScreen.SettingsAbout.name) {
SettingsAbout(
onNavigateUp = { navController.navigateUp() },

View file

@ -4,6 +4,7 @@ enum class TodoScreen {
Main,
TodoEditor,
SettingsMain,
SettingsAppearance,
SettingsAbout,
SettingsAboutLicence
}

View file

@ -14,7 +14,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import cn.super12138.todo.R
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
import cn.super12138.todo.ui.pages.settings.components.DefaultSettingsItem
import cn.super12138.todo.ui.pages.settings.components.SettingsItem
import cn.super12138.todo.utils.getAppVersion
@OptIn(ExperimentalMaterial3Api::class)
@ -29,8 +29,7 @@ fun SettingsAbout(
title = stringResource(R.string.pref_about),
onBack = onNavigateUp,
scrollBehavior = scrollBehavior,
modifier = modifier
.nestedScroll(scrollBehavior.nestedScrollConnection),
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
) { innerPadding ->
val context = LocalContext.current
Column(
@ -39,17 +38,17 @@ fun SettingsAbout(
.padding(innerPadding)
.verticalScroll(rememberScrollState())
) {
DefaultSettingsItem(
SettingsItem(
title = stringResource(R.string.pref_app_version),
description = getAppVersion(context),
enableClick = false
)
DefaultSettingsItem(
SettingsItem(
title = stringResource(R.string.pref_developer),
description = stringResource(R.string.developer_name),
enableClick = false
)
DefaultSettingsItem(
SettingsItem(
title = stringResource(R.string.pref_licence),
description = stringResource(R.string.pref_licence_desc),
onClick = toLicencePage

View file

@ -0,0 +1,55 @@
package cn.super12138.todo.ui.pages.settings
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ColorLens
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
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.palette.PalettePicker
import cn.super12138.todo.ui.theme.appPaletteStyle
import cn.super12138.todo.ui.theme.isDynamicColorEnable
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SettingsAppearance(
onNavigateUp: () -> Unit,
modifier: Modifier = Modifier
) {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
LargeTopAppBarScaffold(
title = stringResource(R.string.pref_appearance),
onBack = onNavigateUp,
scrollBehavior = scrollBehavior,
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.verticalScroll(rememberScrollState())
) {
SwitchSettingsItem(
key = Constants.PREF_DYNAMIC_COLOR,
default = Constants.PREF_DYNAMIC_COLOR_DEFAULT,
leadingIcon = Icons.Outlined.ColorLens,
title = stringResource(R.string.pref_appearance_dynamic_color),
description = stringResource(R.string.pref_appearance_dynamic_color_desc),
onCheckedChange = { isDynamicColorEnable = it },
)
PalettePicker(onPaletteChange = { appPaletteStyle = it })
}
}
}

View file

@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ColorLens
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TopAppBarDefaults
@ -14,12 +15,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import cn.super12138.todo.R
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
import cn.super12138.todo.ui.pages.settings.components.DefaultSettingsItem
import cn.super12138.todo.ui.pages.settings.components.SettingsItem
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SettingsMain(
onNavigateUp: () -> Unit,
toAppearancePage: () -> Unit,
toAboutPage: () -> Unit,
modifier: Modifier = Modifier
) {
@ -35,7 +37,13 @@ fun SettingsMain(
.padding(innerPadding)
.verticalScroll(rememberScrollState())
) {
DefaultSettingsItem(
SettingsItem(
leadingIcon = Icons.Outlined.ColorLens,
title = stringResource(R.string.pref_appearance),
description = stringResource(R.string.pref_appearance_desc),
onClick = toAppearancePage
)
SettingsItem(
leadingIcon = Icons.Outlined.Info,
title = stringResource(R.string.pref_about),
description = stringResource(R.string.pref_about_desc),

View file

@ -20,7 +20,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun DefaultSettingsItem(
fun SettingsItem(
leadingIcon: ImageVector? = null,
title: String,
description: String? = null,
@ -28,7 +28,7 @@ fun DefaultSettingsItem(
onClick: () -> Unit = {},
modifier: Modifier = Modifier
) {
DefaultSettingsItem(
SettingsItem(
leadingIcon = leadingIcon,
title = title,
description = description,
@ -40,7 +40,7 @@ fun DefaultSettingsItem(
}
@Composable
fun DefaultSettingsItem(
fun SettingsItem(
leadingIcon: ImageVector? = null,
title: String,
description: String? = null,
@ -49,7 +49,7 @@ fun DefaultSettingsItem(
onClick: () -> Unit = {},
modifier: Modifier = Modifier
) {
DefaultSettingsItem(
SettingsItem(
leadingIcon = {
leadingIcon?.let {
Icon(
@ -70,7 +70,7 @@ fun DefaultSettingsItem(
}
@Composable
fun DefaultSettingsItem(
fun SettingsItem(
leadingIcon: (@Composable () -> Unit)? = null,
title: String,
description: String? = null,

View file

@ -2,31 +2,40 @@ package cn.super12138.todo.ui.pages.settings.components
import androidx.compose.material3.Switch
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import cn.super12138.todo.ui.pages.settings.state.rememberPrefBooleanState
@Composable
fun SwitchSettingsItem(
key: String,
default: Boolean,
leadingIcon: ImageVector? = null,
title: String,
description: String? = null,
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
onClick: () -> Unit = {},
modifier: Modifier = Modifier
) {
DefaultSettingsItem(
var switchState by rememberPrefBooleanState(key, default)
SettingsItem(
leadingIcon = leadingIcon,
title = title,
description = description,
trailingContent = {
Switch(
checked = checked,
onCheckedChange = onCheckedChange,
modifier = modifier,
checked = switchState,
onCheckedChange = {
switchState = it
onCheckedChange(it)
}
)
},
onClick = onClick,
onClick = {
switchState = !switchState
onCheckedChange(switchState)
},
modifier = modifier
)
}

View file

@ -0,0 +1,103 @@
package cn.super12138.todo.ui.pages.settings.components.palette
import android.os.Build
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
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.ui.theme.PaletteStyle
import cn.super12138.todo.ui.theme.dynamicColorScheme
@Composable
fun PaletteItem(
paletteStyle: PaletteStyle,
selected: Boolean,
onSelect: () -> Unit,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
// 单个主题最外层布局
Column(
modifier = Modifier
.width(90.dp)
.clip(MaterialTheme.shapes.large)
.clickable {
onSelect()
}
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
// 为不同主题样式设置不同色板
MaterialTheme(
colorScheme = dynamicColorScheme(
keyColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && GlobalValues.dynamicColor) {
colorResource(id = android.R.color.system_accent1_500)
} else {
Color(0xFFFF0000)
},
isDark = isSystemInDarkTheme(),
style = paletteStyle
)
) {
val borderWidth by animateDpAsState(if (selected) 3.dp else (-1).dp)
// 颜色预览区域
Column(
modifier = Modifier
.width(70.dp)
.clip(MaterialTheme.shapes.large)
.border(
width = borderWidth,
color = MaterialTheme.colorScheme.primary,
shape = MaterialTheme.shapes.large
),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
listOf(
MaterialTheme.colorScheme.primary,
MaterialTheme.colorScheme.secondary,
MaterialTheme.colorScheme.tertiary,
MaterialTheme.colorScheme.tertiaryContainer,
MaterialTheme.colorScheme.secondaryContainer,
MaterialTheme.colorScheme.primaryContainer,
).fastForEach {
Box(
Modifier
.fillMaxWidth()
.height(24.dp)
.background(it)
)
}
}
}
Spacer(Modifier.size(8.dp))
Text(
text = paletteStyle.getDisplayName(context),
style = MaterialTheme.typography.bodyMedium
)
}
}

View file

@ -0,0 +1,78 @@
package cn.super12138.todo.ui.pages.settings.components.palette
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.MaterialTheme
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.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import cn.super12138.todo.R
import cn.super12138.todo.constants.Constants
import cn.super12138.todo.ui.pages.settings.state.rememberPrefIntState
import cn.super12138.todo.ui.theme.PaletteStyle
@Composable
fun PalettePicker(
onPaletteChange: (paletteStyle: PaletteStyle) -> Unit,
modifier: Modifier = Modifier
) {
var paletteState by rememberPrefIntState(
Constants.PREF_PALETTE_STYLE,
Constants.PREF_PALETTE_STYLE_DEFAULT
)
Column(
modifier = modifier
.fillMaxWidth()
.wrapContentHeight()
.clip(MaterialTheme.shapes.large)
.padding(horizontal = 24.dp, vertical = 20.dp),
) {
Text(
text = stringResource(R.string.pref_palette_style),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleLarge.copy(
color = MaterialTheme.colorScheme.onSurface,
fontSize = 20.sp
)
)
Spacer(Modifier.size(8.dp))
val paletteOptions = remember {
PaletteStyle.entries.toList()
}
LazyRow(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(5.dp)
) {
items(items = paletteOptions, key = { it.name }) { paletteStyle ->
PaletteItem(
paletteStyle = paletteStyle,
selected = PaletteStyle.fromId(paletteState) == paletteStyle,
onSelect = {
paletteState = paletteStyle.id
onPaletteChange(paletteStyle)
}
)
}
}
}
}

View file

@ -0,0 +1,87 @@
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.MutableIntState
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
/**
* 来自https://github.com/hushenghao/AndroidEasterEggs/blob/main/app/src/main/java/com/dede/android_eggs/views/settings/compose/basic/PrefMutableState.kt
* 在命名上有改动
* @author hushenghao
*/
@Composable
fun rememberPrefBooleanState(key: String, default: Boolean): MutableState<Boolean> {
val context = LocalContext.current
return remember { PrefMutableBooleanState(context, key, default) }
}
@Composable
fun rememberPrefIntState(key: String, default: Int): MutableIntState {
val context = LocalContext.current
return remember { PrefMutableIntState(context, key, default) }
}
private class PrefMutableBooleanState(
val context: Context,
val key: String,
default: Boolean,
) : MutableState<Boolean> {
private val delegate = mutableStateOf(context.pref.getBoolean(key, default))
override var value: Boolean
get() = delegate.value
set(value) {
delegate.value = value
context.pref.edit().putBoolean(key, value).apply()
}
override fun component1(): Boolean {
return delegate.component1()
}
override fun component2(): (Boolean) -> Unit {
return delegate.component2()
}
}
private class PrefMutableIntState(
val context: Context,
val key: String,
default: Int,
) : MutableIntState {
private val delegate = mutableIntStateOf(context.pref.getInt(key, default))
override var intValue: Int
get() = delegate.intValue
set(value) {
delegate.intValue = value
context.pref.edit().putInt(key, value).apply()
}
override fun component1(): Int {
return delegate.component1()
}
override fun component2(): (Int) -> Unit {
return delegate.component2()
}
}
/**
* 来自https://github.com/hushenghao/AndroidEasterEggs/blob/main/basic/src/main/java/com/dede/android_eggs/util/Pref.kt
* @author hushenghao
*/
val Context.pref: SharedPreferences
get() {
return applicationContext.getSharedPreferences(
applicationContext.packageName + "_preferences",
Context.MODE_PRIVATE
)
}

View file

@ -1,13 +1,37 @@
package cn.super12138.todo.ui.theme
enum class PaletteStyle {
TonalSpot,
Neutral,
Vibrant,
Expressive,
Rainbow,
FruitSalad,
Monochrome,
Fidelity,
Content,
import android.content.Context
import cn.super12138.todo.R
enum class PaletteStyle(val id: Int) {
TonalSpot(1),
Neutral(2),
Vibrant(3),
Expressive(4),
Rainbow(5),
FruitSalad(6),
Monochrome(7),
Fidelity(8),
Content(9);
fun getDisplayName(context: Context): String {
val resId = when (this) {
TonalSpot -> R.string.palette_tonal_spot
Neutral -> R.string.palette_neutral
Vibrant -> R.string.palette_vibrant
Expressive -> R.string.palette_expressive
Rainbow -> R.string.palette_rainbow
FruitSalad -> R.string.palette_fruit_salad
Monochrome -> R.string.palette_monochrome
Fidelity -> R.string.palette_fidelity
Content -> R.string.palette_content
}
return context.getString(resId)
}
companion object {
fun fromId(id: Int): PaletteStyle {
return PaletteStyle.entries.find { it.id == id } ?: TonalSpot
}
}
}

View file

@ -4,17 +4,24 @@ import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import cn.super12138.todo.constants.GlobalValues
var isDynamicColorEnable by mutableStateOf(GlobalValues.dynamicColor)
var appPaletteStyle by mutableStateOf(PaletteStyle.fromId(GlobalValues.paletteStyle))
@Composable
fun ToDoTheme(
color: Color? = null,
darkTheme: Boolean = isSystemInDarkTheme(),
style: PaletteStyle = PaletteStyle.TonalSpot,
style: PaletteStyle = appPaletteStyle,
contrastLevel: Double = 0.0,
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
dynamicColor: Boolean = isDynamicColorEnable,
content: @Composable () -> Unit
) {
val baseColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && dynamicColor) {

View file

@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
class MainViewModel : ViewModel() {
// 待办
val toDos: Flow<List<TodoEntity>> = Repository.getAllTodos()
var selectedEditTodo by mutableStateOf<TodoEntity?>(null)
private set

View file

@ -0,0 +1,14 @@
package cn.super12138.todo.utils
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class SPDelegates<T>(private val key: String, private val default: T) : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return SPUtils.getValue(key, default)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
SPUtils.putValue(key, value)
}
}

View file

@ -0,0 +1,37 @@
package cn.super12138.todo.utils
import android.content.Context
import android.content.SharedPreferences
import cn.super12138.todo.TodoApp
import cn.super12138.todo.constants.Constants
object SPUtils {
private val sp: SharedPreferences by lazy {
TodoApp.context.getSharedPreferences(Constants.SP_NAME, Context.MODE_PRIVATE)
}
fun <T> getValue(name: String, default: T): T = with(sp) {
val res: Any = when (default) {
is Long -> getLong(name, default)
is String -> getString(name, default).orEmpty()
is Int -> getInt(name, default)
is Boolean -> getBoolean(name, default)
is Float -> getFloat(name, default)
else -> throw java.lang.IllegalArgumentException()
}
@Suppress("UNCHECKED_CAST")
res as T
}
fun <T> putValue(name: String, value: T) = with(sp.edit()) {
when (value) {
is Long -> putLong(name, value)
is String -> putString(name, value)
is Int -> putInt(name, value)
is Boolean -> putBoolean(name, value)
is Float -> putFloat(name, value)
else -> throw IllegalArgumentException("This type can't be saved into Preferences")
}.apply()
}
}

View file

@ -46,4 +46,18 @@
<string name="priority_important">重要</string>
<string name="priority_urgent">紧急</string>
<string name="label_priority">优先级</string>
<string name="pref_appearance">外观和个性化</string>
<string name="pref_appearance_desc">主题、色彩样式</string>
<string name="pref_appearance_dynamic_color">动态配色</string>
<string name="pref_appearance_dynamic_color_desc">使用系统壁纸的主题颜色,仅在 Android 12+ 上生效</string>
<string name="pref_palette_style">主题样式</string>
<string name="palette_tonal_spot">色调点</string>
<string name="palette_neutral">中性</string>
<string name="palette_vibrant">鲜艳</string>
<string name="palette_expressive">表现力</string>
<string name="palette_rainbow">彩虹</string>
<string name="palette_fruit_salad">水果沙拉</string>
<string name="palette_monochrome">单色</string>
<string name="palette_fidelity">高保真</string>
<string name="palette_content">内容</string>
</resources>

View file

@ -47,4 +47,18 @@
<string name="priority_important">Important</string>
<string name="priority_urgent">Urgent</string>
<string name="label_priority">Priority</string>
<string name="pref_appearance">Appearance</string>
<string name="pref_appearance_desc">Theme, color style</string>
<string name="pref_appearance_dynamic_color">Dynamic Color</string>
<string name="pref_appearance_dynamic_color_desc">Use the system wallpaper\'s theme color, available on Android 12+</string>
<string name="pref_palette_style">Palette Style</string>
<string name="palette_tonal_spot">Tonal Spot</string>
<string name="palette_neutral">Neutral</string>
<string name="palette_vibrant">Vibrant</string>
<string name="palette_expressive">Expressive</string>
<string name="palette_rainbow">Rainbow</string>
<string name="palette_fruit_salad">Fruit Salad</string>
<string name="palette_monochrome">Monochrome</string>
<string name="palette_fidelity">Fidelity</string>
<string name="palette_content">Content</string>
</resources>

View file

@ -2,8 +2,8 @@
# Android X
coreKtx = "1.15.0"
splashScreen = "1.2.0-alpha02"
# security = "1.1.0-alpha06"
lifecycleRuntimeKtx = "2.8.7"
# security = "1.1.0-alpha06"
# Compose
activityCompose = "1.9.3"
composeBom = "2024.12.01"