From 2fbb6fd38cd925ee3caa6e137d4f6392c6272221 Mon Sep 17 00:00:00 2001 From: Super12138 <70494801+Super12138@users.noreply.github.com> Date: Sat, 7 Feb 2026 23:20:49 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E5=AF=BC?= =?UTF-8?q?=E8=88=AA=E6=A0=8F=E7=9A=84=E6=98=BE=E7=A4=BA=E6=95=88=E6=9E=9C?= =?UTF-8?q?=20&=20=E4=B8=BA=E5=AF=BC=E8=88=AA=E6=A0=8F=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=A7=A6=E6=84=9F=E5=8F=8D=E9=A6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 +- .../todo/ui/activities/MainActivity.kt | 40 +++++- .../super12138/todo/ui/components/Konfetti.kt | 7 +- .../todo/ui/navigation/SettingsNavigation.kt | 105 --------------- .../todo/ui/navigation/TopNavigation.kt | 125 ++++++++++++------ .../editor/components/TodoDueDateChooser.kt | 2 +- .../todo/ui/pages/editor/state/EditorState.kt | 7 + .../todo/ui/viewmodels/MainViewModel.kt | 2 - app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 10 files changed, 136 insertions(+), 156 deletions(-) delete mode 100644 app/src/main/kotlin/cn/super12138/todo/ui/navigation/SettingsNavigation.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ebadf15..d06ff25 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -38,7 +38,7 @@ android { applicationId = "cn.super12138.todo" minSdk = 24 targetSdk = 36 - versionCode = 969 + versionCode = 971 versionName = "2.3.3" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/activities/MainActivity.kt b/app/src/main/kotlin/cn/super12138/todo/ui/activities/MainActivity.kt index d63b6a4..bbbcd58 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/activities/MainActivity.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/activities/MainActivity.kt @@ -11,10 +11,13 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold +import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffoldValue +import androidx.compose.material3.adaptive.navigationsuite.rememberNavigationSuiteScaffoldState import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen @@ -40,8 +43,12 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { val mainViewModel: MainViewModel = viewModel() - val mainBackStack = mainViewModel.mainBackStack + val showConfetti = mainViewModel.showConfetti + + val mainBackStack = mainViewModel.mainBackStack + val navigationScaffoldState = rememberNavigationSuiteScaffoldState() + // 主题 val dynamicColor by DataStoreManager.dynamicColorFlow.collectAsState(initial = Constants.PREF_DYNAMIC_COLOR_DEFAULT) val paletteStyle by DataStoreManager.paletteStyleFlow.collectAsState(initial = Constants.PREF_PALETTE_STYLE_DEFAULT) @@ -81,14 +88,30 @@ class MainActivity : ComponentActivity() { VibrationUtils.setEnabled(hapticFeedback) } + // 当BackStack出现非顶层路由时,隐藏底部导航栏 + LaunchedEffect(mainBackStack.backStack.lastOrNull()) { + val isTopLevel = + mainBackStack.backStack.lastOrNull() in TodoDestinations.entries.map { it.route } + if (isTopLevel) { + if (navigationScaffoldState.currentValue != NavigationSuiteScaffoldValue.Visible) navigationScaffoldState.show() + } else { + if (navigationScaffoldState.currentValue != NavigationSuiteScaffoldValue.Hidden) navigationScaffoldState.hide() + } + } + ToDoTheme( darkTheme = darkTheme, style = PaletteStyle.fromId(paletteStyle), contrastLevel = contrastLevel.toDouble(), dynamicColor = dynamicColor ) { - Surface(color = TodoDefaults.BackgroundColor) { + Surface( + color = TodoDefaults.BackgroundColor, + modifier = Modifier.fillMaxSize() + ) { + val view = LocalView.current NavigationSuiteScaffold( + state = navigationScaffoldState, navigationSuiteItems = { TodoDestinations.entries.forEach { destination -> val selected = destination.route == mainBackStack.topLevelKey @@ -110,11 +133,15 @@ class MainActivity : ComponentActivity() { }, label = { Text(stringResource(destination.label)) }, selected = selected, - onClick = { mainBackStack.addTopLevel(destination.route) } + onClick = { + VibrationUtils.performHapticFeedback(view) + mainBackStack.addTopLevel(destination.route) + } ) } }, - containerColor = TodoDefaults.BackgroundColor + containerColor = TodoDefaults.BackgroundColor, + modifier = Modifier.fillMaxSize() ) { TopNavigation( backStack = mainBackStack, @@ -122,7 +149,10 @@ class MainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize() ) } - Konfetti(state = showConfetti) + Konfetti( + state = showConfetti, + modifier = Modifier.fillMaxSize() + ) } } } diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/components/Konfetti.kt b/app/src/main/kotlin/cn/super12138/todo/ui/components/Konfetti.kt index 130bcf3..0aa33fa 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/components/Konfetti.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/components/Konfetti.kt @@ -1,7 +1,6 @@ package cn.super12138.todo.ui.components import androidx.annotation.FloatRange -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -45,9 +44,9 @@ fun Konfetti( } } KonfettiView( - modifier = Modifier - .fillMaxSize() - .then(modifier), + modifier = modifier + /*.fillMaxSize() + .then(modifier)*/, parties = remember { particles(primary.toArgb()) }, updateListener = listener ) diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/navigation/SettingsNavigation.kt b/app/src/main/kotlin/cn/super12138/todo/ui/navigation/SettingsNavigation.kt deleted file mode 100644 index 11c38c9..0000000 --- a/app/src/main/kotlin/cn/super12138/todo/ui/navigation/SettingsNavigation.kt +++ /dev/null @@ -1,105 +0,0 @@ -package cn.super12138.todo.ui.navigation - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.navigation3.runtime.NavBackStack -import androidx.navigation3.runtime.NavKey -import androidx.navigation3.runtime.entryProvider -import androidx.navigation3.ui.NavDisplay -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.SettingsData -import cn.super12138.todo.ui.pages.settings.SettingsDataCategory -import cn.super12138.todo.ui.pages.settings.SettingsDeveloperOptions -import cn.super12138.todo.ui.pages.settings.SettingsDeveloperOptionsPadding -import cn.super12138.todo.ui.pages.settings.SettingsInterface -import cn.super12138.todo.ui.pages.settings.SettingsMain -import cn.super12138.todo.ui.theme.materialSharedAxisX -import cn.super12138.todo.ui.viewmodels.MainViewModel - -private const val INITIAL_OFFSET_FACTOR = 0.10f - -@Composable -fun SettingsNavigation( - backStack: NavBackStack, - viewModel: MainViewModel, - modifier: Modifier = Modifier -) { - fun onBack() { - backStack.removeLastOrNull() - } - - NavDisplay( - backStack = backStack, - onBack = ::onBack, - transitionSpec = { - materialSharedAxisX( - initialOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() }, - targetOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() }) - }, - popTransitionSpec = { - materialSharedAxisX( - initialOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() }, - targetOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() }) - }, - entryProvider = entryProvider { - entry { - SettingsMain( - toAppearancePage = { backStack.add(TodoScreen.Settings.Appearance) }, - toAboutPage = { backStack.add(TodoScreen.Settings.About) }, - toInterfacePage = { backStack.add(TodoScreen.Settings.Interface) }, - toDataPage = { backStack.add(TodoScreen.Settings.Data) }, - ) - } - - entry { - SettingsAppearance(onNavigateUp = ::onBack) - } - - entry { - SettingsInterface(onNavigateUp = ::onBack) - } - - entry { - SettingsData( - viewModel = viewModel, - toCategoryManager = { backStack.add(TodoScreen.Settings.DataCategory) }, - onNavigateUp = ::onBack - ) - } - - entry { - SettingsDataCategory(onNavigateUp = ::onBack) - } - - entry { - SettingsAbout( - //toSpecialPage = { backStack.add(TodoScreen.Settings.AboutSpecial) }, - toLicencePage = { backStack.add(TodoScreen.Settings.AboutLicence) }, - toDevPage = { backStack.add(TodoScreen.Settings.DeveloperOptions) }, - onNavigateUp = ::onBack, - ) - } - - /*entry { - SettingsAboutSpecial(viewModel = viewModel) - }*/ - - entry { - SettingsAboutLicence(onNavigateUp = ::onBack) - } - - entry { - SettingsDeveloperOptions( - toPaddingPage = { backStack.add(TodoScreen.Settings.DeveloperOptionsPadding) }, - onNavigateUp = ::onBack - ) - } - entry { - SettingsDeveloperOptionsPadding(onNavigateUp = ::onBack) - } - }, - modifier = modifier, - ) -} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TopNavigation.kt b/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TopNavigation.kt index 00d1c87..d3de435 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TopNavigation.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/navigation/TopNavigation.kt @@ -10,13 +10,39 @@ import androidx.navigation3.ui.NavDisplay import cn.super12138.todo.ui.pages.editor.TodoAddPage import cn.super12138.todo.ui.pages.editor.TodoEditPage import cn.super12138.todo.ui.pages.overview.OverviewPage +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.SettingsData +import cn.super12138.todo.ui.pages.settings.SettingsDataCategory +import cn.super12138.todo.ui.pages.settings.SettingsDeveloperOptions +import cn.super12138.todo.ui.pages.settings.SettingsDeveloperOptionsPadding +import cn.super12138.todo.ui.pages.settings.SettingsInterface +import cn.super12138.todo.ui.pages.settings.SettingsMain import cn.super12138.todo.ui.pages.tasks.TasksPage import cn.super12138.todo.ui.theme.fadeThrough +import cn.super12138.todo.ui.theme.materialSharedAxisX import cn.super12138.todo.ui.viewmodels.MainViewModel -/** - * 来自:https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/transition/MaterialFadeThrough.java#L33 - */ + +private const val INITIAL_OFFSET_FACTOR = 0.10f + +private fun settingsTransition() = NavDisplay.transitionSpec { + materialSharedAxisX( + initialOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() }, + targetOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() } + ) +} + NavDisplay.popTransitionSpec { + materialSharedAxisX( + initialOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() }, + targetOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() } + ) +} + NavDisplay.predictivePopTransitionSpec { + materialSharedAxisX( + initialOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() }, + targetOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() } + ) +} @OptIn(ExperimentalAnimationApi::class) @Composable @@ -28,29 +54,6 @@ fun TopNavigation( fun onBack() { backStack.removeLast() } - /* - * NavDisplay.transitionSpec { - * // Slide new content up, keeping the old content in place underneath - * slideInVertically( - * initialOffsetY = { it / 5 }, - * animationSpec = tween(200) - * ) + fadeIn(tween(200)) togetherWith ExitTransition.KeepUntilTransitionsFinished - * } + NavDisplay.popTransitionSpec { - * // Slide old content down, revealing the new content in place underneath - * EnterTransition.None togetherWith - * slideOutVertically( - * targetOffsetY = { it / 5 }, - * animationSpec = tween(200) - * ) + fadeOut(tween(200)) - * } + NavDisplay.predictivePopTransitionSpec { - * // Slide old content down, revealing the new content in place underneath - * EnterTransition.None togetherWith - * slideOutVertically( - * targetOffsetY = { it / 5 }, - * animationSpec = tween(200) - * ) + fadeOut(tween(200)) - * } - */ // val veilColor = MaterialTheme.colorScheme.surfaceDim SharedTransitionLayout { @@ -66,15 +69,12 @@ fun TopNavigation( predictivePopTransitionSpec = { unveilIn(initialColor = veilColor) togetherWith fadeOut() },*/ - transitionSpec = { - fadeThrough() - }, - popTransitionSpec = { - fadeThrough() - }, - predictivePopTransitionSpec = { - fadeThrough() - }, + /** + * 来自:https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/transition/MaterialFadeThrough.java#L33 + */ + transitionSpec = { fadeThrough() }, + popTransitionSpec = { fadeThrough() }, + predictivePopTransitionSpec = { fadeThrough() }, entryProvider = entryProvider { entry { OverviewPage(viewModel = viewModel) @@ -118,11 +118,60 @@ fun TopNavigation( } entry { - SettingsNavigation( - backStack = viewModel.settingsBackStack, - viewModel = viewModel + SettingsMain( + toAppearancePage = { backStack.add(TodoScreen.Settings.Appearance) }, + toAboutPage = { backStack.add(TodoScreen.Settings.About) }, + toInterfacePage = { backStack.add(TodoScreen.Settings.Interface) }, + toDataPage = { backStack.add(TodoScreen.Settings.Data) }, ) } + + entry(metadata = settingsTransition()) { + SettingsAppearance(onNavigateUp = ::onBack) + } + + entry(metadata = settingsTransition()) { + SettingsInterface(onNavigateUp = ::onBack) + } + + entry(metadata = settingsTransition()) { + SettingsData( + viewModel = viewModel, + toCategoryManager = { backStack.add(TodoScreen.Settings.DataCategory) }, + onNavigateUp = ::onBack + ) + } + + entry(metadata = settingsTransition()) { + SettingsDataCategory(onNavigateUp = ::onBack) + } + + entry(metadata = settingsTransition()) { + SettingsAbout( + //toSpecialPage = { backStack.add(TodoScreen.Settings.AboutSpecial) }, + toLicencePage = { backStack.add(TodoScreen.Settings.AboutLicence) }, + toDevPage = { backStack.add(TodoScreen.Settings.DeveloperOptions) }, + onNavigateUp = ::onBack, + ) + } + + /*entry(metadata = settingsTransition()) { + SettingsAboutSpecial(viewModel = viewModel) + }*/ + + entry(metadata = settingsTransition()) { + SettingsAboutLicence(onNavigateUp = ::onBack) + } + + entry(metadata = settingsTransition()) { + SettingsDeveloperOptions( + toPaddingPage = { backStack.add(TodoScreen.Settings.DeveloperOptionsPadding) }, + onNavigateUp = ::onBack + ) + } + entry(metadata = settingsTransition()) { + SettingsDeveloperOptionsPadding(onNavigateUp = ::onBack) + } }, modifier = modifier, ) diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/components/TodoDueDateChooser.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/components/TodoDueDateChooser.kt index 2d3fe13..e293cee 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/components/TodoDueDateChooser.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/components/TodoDueDateChooser.kt @@ -121,7 +121,7 @@ fun TodoDueDateChooser( }, shapes = ButtonDefaults.shapes() ) { - Text("清除") + Text(stringResource(R.string.action_clear)) } TextButton( onClick = { diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/state/EditorState.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/state/EditorState.kt index 3b9bfdd..0d6f109 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/state/EditorState.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/state/EditorState.kt @@ -12,6 +12,13 @@ import cn.super12138.todo.R import cn.super12138.todo.logic.database.TodoEntity class EditorState(val initialTodo: TodoEntity? = null) { + /* companion object{ + fun Saver() = + androidx.compose.runtime.saveable.Saver( + save = { it.initialTodo }, + restore = { EditorState(it) }, + ) + }*/ var toDoContent by mutableStateOf(initialTodo?.content ?: "") var isErrorContent by mutableStateOf(false) var selectedCategoryIndex by mutableIntStateOf(-1) 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 76525c9..199d388 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 @@ -5,7 +5,6 @@ import android.net.Uri import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import androidx.navigation3.runtime.NavBackStack import androidx.navigation3.runtime.NavKey import cn.super12138.todo.TodoApp import cn.super12138.todo.constants.Constants @@ -37,7 +36,6 @@ import java.util.zip.ZipOutputStream @OptIn(ExperimentalCoroutinesApi::class) class MainViewModel : ViewModel() { val mainBackStack = TopLevelBackStack(TodoScreen.Overview) - val settingsBackStack = NavBackStack(TodoScreen.Settings.Main) // 待办 private val toDos: Flow> = Repository.getAllTodos() diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 8c44870..de789b7 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -117,4 +117,5 @@ 待办 概览 尽量使用简短的分类名称 + 清除 \ 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 4488934..20a3aff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -118,4 +118,5 @@ Tasks Overview Keep category names concise + Clear \ No newline at end of file