diff --git a/app/src/main/kotlin/cn/super12138/todo/TodoApp.kt b/app/src/main/kotlin/cn/super12138/todo/TodoApp.kt index c13057f..b2397d5 100644 --- a/app/src/main/kotlin/cn/super12138/todo/TodoApp.kt +++ b/app/src/main/kotlin/cn/super12138/todo/TodoApp.kt @@ -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) diff --git a/app/src/main/kotlin/cn/super12138/todo/constants/Constants.kt b/app/src/main/kotlin/cn/super12138/todo/constants/Constants.kt new file mode 100644 index 0000000..4ebdacb --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/constants/Constants.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/constants/GlobalValues.kt b/app/src/main/kotlin/cn/super12138/todo/constants/GlobalValues.kt new file mode 100644 index 0000000..4520c8c --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/constants/GlobalValues.kt @@ -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 + ) +} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TodoNavigation.kt b/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TodoNavigation.kt index 083e0cb..3a071d8 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TodoNavigation.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TodoNavigation.kt @@ -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() }, diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TodoScreen.kt b/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TodoScreen.kt index 071f32f..c7b4a2d 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TodoScreen.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TodoScreen.kt @@ -4,6 +4,7 @@ enum class TodoScreen { Main, TodoEditor, SettingsMain, + SettingsAppearance, SettingsAbout, SettingsAboutLicence } \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAbout.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAbout.kt index 64e7823..a87d816 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAbout.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAbout.kt @@ -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 diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAppearance.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAppearance.kt new file mode 100644 index 0000000..b53a235 --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAppearance.kt @@ -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 }) + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsMain.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsMain.kt index af08e61..594011a 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsMain.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsMain.kt @@ -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), diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/DefaultSettingsItem.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsItem.kt similarity index 96% rename from app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/DefaultSettingsItem.kt rename to app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsItem.kt index 9c7da3b..3b1bb74 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/DefaultSettingsItem.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsItem.kt @@ -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, diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SwitchSettingsItem.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SwitchSettingsItem.kt index 636ab5d..85d8e28 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SwitchSettingsItem.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SwitchSettingsItem.kt @@ -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 ) } \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/palette/PaletteItem.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/palette/PaletteItem.kt new file mode 100644 index 0000000..c595981 --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/palette/PaletteItem.kt @@ -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 + ) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/palette/PalettePicker.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/palette/PalettePicker.kt new file mode 100644 index 0000000..7bf7877 --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/palette/PalettePicker.kt @@ -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) + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/state/PrefMutableState.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/state/PrefMutableState.kt new file mode 100644 index 0000000..0949a59 --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/state/PrefMutableState.kt @@ -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 { + 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 { + 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 + ) + } \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/theme/PaletteStyle.kt b/app/src/main/kotlin/cn/super12138/todo/ui/theme/PaletteStyle.kt index 73158c7..1205ff2 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/theme/PaletteStyle.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/theme/PaletteStyle.kt @@ -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 + } + } } \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/theme/Theme.kt b/app/src/main/kotlin/cn/super12138/todo/ui/theme/Theme.kt index cfbd8c7..e97059c 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/theme/Theme.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/theme/Theme.kt @@ -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) { diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/viewmodels/MainViewModel.kt b/app/src/main/kotlin/cn/super12138/todo/ui/viewmodels/MainViewModel.kt index 2ee1ce4..f57c493 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/viewmodels/MainViewModel.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/viewmodels/MainViewModel.kt @@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch class MainViewModel : ViewModel() { + // 待办 val toDos: Flow> = Repository.getAllTodos() var selectedEditTodo by mutableStateOf(null) private set diff --git a/app/src/main/kotlin/cn/super12138/todo/utils/SPDelegates.kt b/app/src/main/kotlin/cn/super12138/todo/utils/SPDelegates.kt new file mode 100644 index 0000000..5af97cd --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/utils/SPDelegates.kt @@ -0,0 +1,14 @@ +package cn.super12138.todo.utils + +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +class SPDelegates(private val key: String, private val default: T) : ReadWriteProperty { + 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) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/utils/SPUtils.kt b/app/src/main/kotlin/cn/super12138/todo/utils/SPUtils.kt new file mode 100644 index 0000000..453627f --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/utils/SPUtils.kt @@ -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 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 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() + } +} + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 2772a14..56f34b8 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -46,4 +46,18 @@ 重要 紧急 优先级 + 外观和个性化 + 主题、色彩样式 + 动态配色 + 使用系统壁纸的主题颜色,仅在 Android 12+ 上生效 + 主题样式 + 色调点 + 中性 + 鲜艳 + 表现力 + 彩虹 + 水果沙拉 + 单色 + 高保真 + 内容 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8e059ca..9e657a3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -47,4 +47,18 @@ Important Urgent Priority + Appearance + Theme, color style + Dynamic Color + Use the system wallpaper\'s theme color, available on Android 12+ + Palette Style + Tonal Spot + Neutral + Vibrant + Expressive + Rainbow + Fruit Salad + Monochrome + Fidelity + Content \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7bffb73..04dd2b0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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"