diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d350124..509e92f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -113,7 +113,9 @@ dependencies { implementation(libs.aboutlibraries.core) implementation(libs.aboutlibraries.compose) // M3 Color - implementation(libs.com.kyant0.m3color) + implementation(libs.kyant0.m3color) + // Capsule + implementation(libs.kyant0.capsule) // Konfetti implementation(libs.nl.dionsegijn.konfetti.compose) // Lazy Column Scrollbar diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/components/Dialogs.kt b/app/src/main/kotlin/cn/super12138/todo/ui/components/Dialogs.kt index adf81e4..a22a290 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/components/Dialogs.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/components/Dialogs.kt @@ -17,9 +17,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogProperties import cn.super12138.todo.R import cn.super12138.todo.utils.VibrationUtils +import com.kyant.capsule.ContinuousRoundedRectangle @Composable fun ConfirmDialog( @@ -87,7 +89,10 @@ fun BasicDialog( VibrationUtils.performHapticFeedback(view) onConfirm() }, - shapes = ButtonDefaults.shapes() + shapes = ButtonDefaults.shapes( + /*shape = ContinuousRoundedRectangle(50.dp), + pressedShape = ContinuousRoundedRectangle(12.dp)*/ + ) ) { Text(confirmButton) } diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/MainPage.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/MainPage.kt index bdf86f8..8ec35a1 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/MainPage.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/MainPage.kt @@ -1,14 +1,9 @@ package cn.super12138.todo.ui.pages.main import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.animation.SharedTransitionScope -import androidx.compose.animation.expandIn -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkOut import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets @@ -24,6 +19,7 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.SmallExtendedFloatingActionButton import androidx.compose.material3.Text import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.material3.animateFloatingActionButton import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf @@ -32,12 +28,12 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.window.core.layout.WindowWidthSizeClass +import androidx.window.core.layout.WindowSizeClass import cn.super12138.todo.R import cn.super12138.todo.constants.Constants -import cn.super12138.todo.logic.database.TodoEntity import cn.super12138.todo.logic.datastore.DataStoreManager import cn.super12138.todo.ui.components.ConfirmDialog import cn.super12138.todo.ui.pages.main.components.TodoTopAppBar @@ -46,17 +42,17 @@ import cn.super12138.todo.ui.viewmodels.MainViewModel @OptIn(ExperimentalSharedTransitionApi::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun MainPage( + modifier: Modifier = Modifier, viewModel: MainViewModel, toTodoEditPage: () -> Unit, toSettingsPage: () -> Unit, sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, - modifier: Modifier = Modifier + windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass, ) { val toDos = viewModel.sortedTodos.collectAsState(initial = emptyList()) val selectedTodos = viewModel.selectedTodoIds.collectAsState() val showCompleted by DataStoreManager.showCompletedFlow.collectAsState(initial = Constants.PREF_SHOW_COMPLETED_DEFAULT) - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass val listState = rememberLazyListState() var showDeleteConfirmDialog by rememberSaveable { mutableStateOf(false) } @@ -86,99 +82,37 @@ fun MainPage( }, floatingActionButton = { with(sharedTransitionScope) { - AnimatedVisibility( - visible = !inSelectedMode, - enter = fadeIn() + expandIn(), - exit = shrinkOut() + fadeOut() - ) { - // TODO: 修复在滑动列表时FAB位移导致的动画不连贯(临时方案为底部加padding) - /*AnimatedExtendedFloatingActionButton( - icon = Icons.Outlined.Add, - text = stringResource(R.string.action_add_task), - expanded = true, - onClick = { - viewModel.setEditTodoItem(null) // 每次添加待办前清除上一次已选待办 - toTodoEditPage() - }, - modifier = Modifier.sharedElement( + SmallExtendedFloatingActionButton( + text = { Text(stringResource(R.string.action_add_task)) }, + icon = { + Icon( + imageVector = Icons.Outlined.Add, + contentDescription = null + ) + }, + expanded = expandedFab, + onClick = { + viewModel.setEditTodoItem(null) // 每次添加待办前清除上一次已选待办 + toTodoEditPage() + }, + modifier = Modifier + .sharedElement( sharedContentState = rememberSharedContentState(key = Constants.KEY_TODO_FAB_TRANSITION), animatedVisibilityScope = animatedVisibilityScope ) - )*/ - SmallExtendedFloatingActionButton( - text = { Text(stringResource(R.string.action_add_task)) }, - icon = { - Icon( - imageVector = Icons.Outlined.Add, - contentDescription = null - ) - }, - expanded = expandedFab, - onClick = { - viewModel.setEditTodoItem(null) // 每次添加待办前清除上一次已选待办 - toTodoEditPage() - }, - modifier = Modifier.sharedElement( - sharedContentState = rememberSharedContentState(key = Constants.KEY_TODO_FAB_TRANSITION), - animatedVisibilityScope = animatedVisibilityScope + .animateFloatingActionButton( + visible = !inSelectedMode, + alignment = Alignment.BottomEnd, ) - ) - } + ) } }, contentWindowInsets = WindowInsets(0, 0, 0, 0), modifier = modifier ) { innerPadding -> - if (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT) { - Column( - modifier = Modifier.padding( - top = innerPadding.calculateTopPadding(), - bottom = innerPadding.calculateBottomPadding() - ) - ) { - ProgressFragment( - totalTasks = totalTasks, - completedTasks = completedTasks, - modifier = Modifier - .weight(2f) - .fillMaxSize() - ) - - ManagerFragment( - state = listState, - list = filteredTodoList, - onItemClick = { item -> - if (inSelectedMode) { - viewModel.toggleTodoSelection(item) - } else { - viewModel.setEditTodoItem(item) - toTodoEditPage() - } - }, - onItemLongClick = { viewModel.toggleTodoSelection(it) }, - onItemChecked = { item -> - item.apply { - viewModel.updateTodo( - TodoEntity( - content = content, - category = category, - isCompleted = true, - priority = priority, - id = id - ) - ) - viewModel.playConfetti() - } - }, - selectedTodoIds = selectedTodoIds, - // sharedTransitionScope = sharedTransitionScope, - // animatedVisibilityScope = animatedVisibilityScope, - modifier = Modifier - .weight(3f) - .fillMaxSize() - ) - } - } else { + val isMediumScreen = + windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) + if (isMediumScreen) { Row( modifier = Modifier.padding( top = innerPadding.calculateTopPadding(), @@ -204,20 +138,48 @@ fun MainPage( } }, onItemLongClick = { viewModel.toggleTodoSelection(it) }, - onItemChecked = { item -> - item.apply { - viewModel.updateTodo( - TodoEntity( - content = content, - category = category, - isCompleted = true, - priority = priority, - id = id - ) - ) - viewModel.playConfetti() + onItemChecked = { + viewModel.updateTodo(it.copy(isCompleted = true)) + viewModel.playConfetti() + }, + selectedTodoIds = selectedTodoIds, + // sharedTransitionScope = sharedTransitionScope, + // animatedVisibilityScope = animatedVisibilityScope, + modifier = Modifier + .weight(3f) + .fillMaxSize() + ) + } + } else { + Column( + modifier = Modifier.padding( + top = innerPadding.calculateTopPadding(), + bottom = innerPadding.calculateBottomPadding() + ) + ) { + ProgressFragment( + totalTasks = totalTasks, + completedTasks = completedTasks, + modifier = Modifier + .weight(2f) + .fillMaxSize() + ) + ManagerFragment( + state = listState, + list = filteredTodoList, + onItemClick = { item -> + if (inSelectedMode) { + viewModel.toggleTodoSelection(item) + } else { + viewModel.setEditTodoItem(item) + toTodoEditPage() } }, + onItemLongClick = { viewModel.toggleTodoSelection(it) }, + onItemChecked = { + viewModel.updateTodo(it.copy(isCompleted = true)) + viewModel.playConfetti() + }, selectedTodoIds = selectedTodoIds, // sharedTransitionScope = sharedTransitionScope, // animatedVisibilityScope = animatedVisibilityScope, diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/ManagerFragment.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/ManagerFragment.kt index 0449b24..1517d59 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/ManagerFragment.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/ManagerFragment.kt @@ -45,6 +45,14 @@ fun ManagerFragment( bottom = TodoDefaults.toDoCardHeight / 2, end = TodoDefaults.screenPadding ), + /*modifier = Modifier + .clip( + MaterialTheme.shapes.extraLarge.copy( + bottomEnd = CornerSize(0.dp), + bottomStart = CornerSize(0.dp) + ) + ) + .background(MaterialTheme.colorScheme.surfaceContainerHighest)*/ // verticalArrangement = Arrangement.spacedBy(10.dp) ) { if (list.isEmpty()) { 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 6a2a6e1..e726ec4 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 @@ -1,7 +1,9 @@ package cn.super12138.todo.ui.pages.settings import android.widget.Toast +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons @@ -10,6 +12,8 @@ import androidx.compose.material.icons.outlined.DeveloperMode import androidx.compose.material.icons.outlined.Numbers import androidx.compose.material.icons.outlined.Person4 import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -19,19 +23,22 @@ import androidx.compose.runtime.mutableLongStateOf 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.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler 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.ui.TodoDefaults import cn.super12138.todo.ui.components.LargeTopAppBarScaffold import cn.super12138.todo.ui.icons.GitHubIcon import cn.super12138.todo.ui.pages.settings.components.SettingsItem import cn.super12138.todo.utils.SystemUtils import kotlinx.coroutines.delay -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun SettingsAbout( //toSpecialPage: () -> Unit, @@ -51,9 +58,12 @@ fun SettingsAbout( val uriHandler = LocalUriHandler.current LazyColumn( + verticalArrangement = Arrangement.spacedBy(2.dp), modifier = Modifier - .fillMaxSize() + .fillMaxWidth() .padding(innerPadding) + .padding(horizontal = TodoDefaults.screenPadding) + .clip(MaterialTheme.shapes.extraExtraLarge) ) { item { var clickCount by remember { mutableIntStateOf(0) } diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsData.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsData.kt index b98852a..15b3400 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsData.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsData.kt @@ -4,15 +4,18 @@ import android.content.Context import android.content.Intent import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Category import androidx.compose.material.icons.outlined.FileDownload import androidx.compose.material.icons.outlined.FileUpload import androidx.compose.material.icons.outlined.RestartAlt import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.TopAppBarDefaults @@ -29,9 +32,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.window.DialogProperties import cn.super12138.todo.R +import cn.super12138.todo.ui.TodoDefaults import cn.super12138.todo.ui.activities.MainActivity import cn.super12138.todo.ui.components.ConfirmDialog import cn.super12138.todo.ui.components.LargeTopAppBarScaffold +import cn.super12138.todo.ui.pages.settings.components.Settings import cn.super12138.todo.ui.pages.settings.components.SettingsCategory import cn.super12138.todo.ui.pages.settings.components.SettingsItem import cn.super12138.todo.ui.viewmodels.MainViewModel @@ -39,7 +44,7 @@ import cn.super12138.todo.utils.SystemUtils import kotlinx.coroutines.launch import kotlin.system.exitProcess -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun SettingsData( viewModel: MainViewModel, @@ -111,13 +116,15 @@ fun SettingsData( snackbarHost = { SnackbarHost(snackbarHostState) }, modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), ) { innerPadding -> - LazyColumn( - modifier = Modifier + Column( + Modifier .fillMaxSize() .padding(innerPadding) + .padding(horizontal = TodoDefaults.screenPadding) + .verticalScroll(rememberScrollState()) ) { - item { - SettingsCategory(stringResource(R.string.pref_category_data_management)) + SettingsCategory(stringResource(R.string.pref_category_data_management)) + Settings { SettingsItem( leadingIcon = Icons.Outlined.FileDownload, title = stringResource(R.string.pref_backup), @@ -126,8 +133,6 @@ fun SettingsData( backupLauncher.launch("Todo-backup-${SystemUtils.getTime()}.zip") } ) - } - item { SettingsItem( leadingIcon = Icons.Outlined.FileUpload, title = stringResource(R.string.pref_restore), @@ -137,8 +142,8 @@ fun SettingsData( } ) } - item { - SettingsCategory(stringResource(R.string.pref_category_category_management)) + SettingsCategory(stringResource(R.string.pref_category_category_management)) + Settings { SettingsItem( leadingIcon = Icons.Outlined.Category, title = stringResource(R.string.pref_category_category_management), @@ -147,17 +152,17 @@ fun SettingsData( ) } } - ConfirmDialog( - visible = showRestoreDialog, - icon = Icons.Outlined.RestartAlt, - title = stringResource(R.string.tip_tips), - text = stringResource(R.string.tip_restore_success), - showDismissButton = false, - onConfirm = { restartApp(context) }, - onDismiss = { showRestoreDialog = false }, - properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) - ) } + ConfirmDialog( + visible = showRestoreDialog, + icon = Icons.Outlined.RestartAlt, + title = stringResource(R.string.tip_tips), + text = stringResource(R.string.tip_restore_success), + showDismissButton = false, + onConfirm = { restartApp(context) }, + onDismiss = { showRestoreDialog = false }, + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) + ) } /** diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsInterfaceInteraction.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsInterfaceInteraction.kt index bb6e57b..785ab7b 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsInterfaceInteraction.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsInterfaceInteraction.kt @@ -1,14 +1,17 @@ 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.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.Sort import androidx.compose.material.icons.outlined.Checklist import androidx.compose.material.icons.outlined.Shield import androidx.compose.material.icons.outlined.Vibration import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -26,7 +29,9 @@ import cn.super12138.todo.R import cn.super12138.todo.constants.Constants import cn.super12138.todo.logic.datastore.DataStoreManager import cn.super12138.todo.logic.model.SortingMethod +import cn.super12138.todo.ui.TodoDefaults import cn.super12138.todo.ui.components.LargeTopAppBarScaffold +import cn.super12138.todo.ui.pages.settings.components.Settings import cn.super12138.todo.ui.pages.settings.components.SettingsCategory import cn.super12138.todo.ui.pages.settings.components.SettingsItem import cn.super12138.todo.ui.pages.settings.components.SettingsPlainBox @@ -35,7 +40,7 @@ import cn.super12138.todo.ui.pages.settings.components.SettingsRadioOptions import cn.super12138.todo.ui.pages.settings.components.SwitchSettingsItem import kotlinx.coroutines.launch -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun SettingsInterface( onNavigateUp: () -> Unit, @@ -56,16 +61,15 @@ fun SettingsInterface( scrollBehavior = scrollBehavior, modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), ) { innerPadding -> - - LazyColumn( - modifier = Modifier + Column( + Modifier .fillMaxSize() .padding(innerPadding) + .padding(horizontal = TodoDefaults.screenPadding) + .verticalScroll(rememberScrollState()) ) { - item { - SettingsCategory(stringResource(R.string.pref_category_todo_list)) - } - item { + SettingsCategory(stringResource(R.string.pref_category_todo_list)) + Settings { SwitchSettingsItem( checked = showCompleted, leadingIcon = Icons.Outlined.Checklist, @@ -73,8 +77,6 @@ fun SettingsInterface( description = stringResource(R.string.pref_show_completed_desc), onCheckedChange = { scope.launch { DataStoreManager.setShowCompleted(it) } }, ) - } - item { SettingsItem( leadingIcon = Icons.AutoMirrored.Outlined.Sort, title = stringResource(R.string.pref_sorting_method), @@ -82,11 +84,8 @@ fun SettingsInterface( onClick = { showSortingMethodDialog = true } ) } - - item { - SettingsCategory(stringResource(R.string.pref_category_global)) - } - item { + SettingsCategory(stringResource(R.string.pref_category_global)) + Settings { SwitchSettingsItem( checked = secureMode, leadingIcon = Icons.Outlined.Shield, @@ -94,8 +93,6 @@ fun SettingsInterface( description = stringResource(R.string.pref_secure_mode_desc), onCheckedChange = { scope.launch { DataStoreManager.setSecureMode(it) } } ) - } - item { SwitchSettingsItem( checked = hapticFeedback, leadingIcon = Icons.Outlined.Vibration, @@ -103,9 +100,10 @@ fun SettingsInterface( description = stringResource(R.string.pref_haptic_feedback_desc), onCheckedChange = { scope.launch { DataStoreManager.setHapticFeedback(it) } } ) - SettingsPlainBox(stringResource(R.string.pref_haptic_feedback_more_info)) } + SettingsPlainBox(stringResource(R.string.pref_haptic_feedback_more_info)) } + } val sortingList = remember { 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 55ef93c..27ebe88 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 @@ -1,24 +1,29 @@ 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.lazy.LazyColumn +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.Dns import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.ViewComfy import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi 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.ui.TodoDefaults import cn.super12138.todo.ui.components.LargeTopAppBarScaffold +import cn.super12138.todo.ui.pages.settings.components.Settings import cn.super12138.todo.ui.pages.settings.components.SettingsItem -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun SettingsMain( toAppearancePage: () -> Unit, @@ -35,42 +40,39 @@ fun SettingsMain( onBack = onNavigateUp, modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection) ) { innerPadding -> - LazyColumn( - modifier = Modifier + Column( + Modifier .fillMaxSize() .padding(innerPadding) + .padding(horizontal = TodoDefaults.screenPadding) + .verticalScroll(rememberScrollState()) ) { - item { + Settings { SettingsItem( leadingIcon = Icons.Outlined.ColorLens, title = stringResource(R.string.pref_appearance), description = stringResource(R.string.pref_appearance_desc), onClick = toAppearancePage ) - } - item { SettingsItem( leadingIcon = Icons.Outlined.ViewComfy, title = stringResource(R.string.pref_interface_interaction), description = stringResource(R.string.pref_interface_interaction_desc), onClick = toInterfacePage ) - } - item { SettingsItem( leadingIcon = Icons.Outlined.Dns, title = stringResource(R.string.pref_data), description = stringResource(R.string.pref_data_desc), onClick = toDataPage ) - } - item { SettingsItem( leadingIcon = Icons.Outlined.Info, title = stringResource(R.string.pref_about), description = stringResource(R.string.pref_about_desc), onClick = toAboutPage ) + } } } diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsContainer.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsContainer.kt new file mode 100644 index 0000000..dd746d0 --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsContainer.kt @@ -0,0 +1,24 @@ +package cn.super12138.todo.ui.pages.settings.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp + +@OptIn(ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun Settings( + modifier: Modifier = Modifier, + content: @Composable ColumnScope.() -> Unit, +) { + Column( + verticalArrangement = Arrangement.spacedBy(2.dp), + modifier = modifier.clip(MaterialTheme.shapes.extraExtraLarge), + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsItem.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsItem.kt index c4f4c35..55e8b75 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsItem.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/SettingsItem.kt @@ -1,11 +1,13 @@ package cn.super12138.todo.ui.pages.settings.components +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -13,6 +15,7 @@ import androidx.compose.runtime.Composable 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.graphics.Shape import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalView @@ -48,6 +51,7 @@ fun SettingsItem( title: String, description: String? = null, trailingContent: (@Composable () -> Unit)? = null, + background: Color = MaterialTheme.colorScheme.surfaceContainerHighest, enableClick: Boolean = true, onClick: () -> Unit = {} ) { @@ -65,12 +69,14 @@ fun SettingsItem( title = title, description = description, trailingContent = trailingContent, + background = background, enableClick = enableClick, onClick = onClick, modifier = modifier ) } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun SettingsItem( modifier: Modifier = Modifier, @@ -78,9 +84,10 @@ fun SettingsItem( title: String, description: String? = null, trailingContent: (@Composable () -> Unit)? = null, - shape: Shape = MaterialTheme.shapes.large, + shape: Shape = MaterialTheme.shapes.small, + background: Color = MaterialTheme.colorScheme.surfaceContainerHighest, enableClick: Boolean = true, - onClick: () -> Unit = {} + onClick: () -> Unit = {}, ) { val view = LocalView.current Row( @@ -95,6 +102,7 @@ fun SettingsItem( onClick() } ) + .background(background) .padding( horizontal = TodoDefaults.settingsItemHorizontalPadding, vertical = TodoDefaults.settingsItemVerticalPadding diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceList.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceList.kt index eb338c7..fc921d0 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceList.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceList.kt @@ -8,6 +8,8 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -26,6 +28,7 @@ import cn.super12138.todo.utils.VibrationUtils import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.ui.compose.util.htmlReadyLicenseContent +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun LicenceList( modifier: Modifier = Modifier, @@ -80,7 +83,8 @@ fun LicenceList( onClick = { openDialog = false VibrationUtils.performHapticFeedback(view) - } + }, + shapes = ButtonDefaults.shapes() ) { Text(stringResource(R.string.action_confirm)) } }, onDismissRequest = { openDialog = false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index def5312..7fb7d26 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,6 +18,8 @@ aboutLibsRelease = "13.1.0" aboutLibsReleasePlugin = "13.1.0" # M3 Color m3color = "2025.4" +# Capsule +capsule = "2.1.1" # Konfetti konfetti = "2.0.5" # Lazy Column Scrollbar @@ -70,7 +72,9 @@ aboutlibraries-core = { group = "com.mikepenz", name = "aboutlibraries-core", ve aboutlibraries-compose = { group = "com.mikepenz", name = "aboutlibraries-compose-m3", version.ref = "aboutLibsRelease" } # M3 Color -com-kyant0-m3color = { group = "com.github.Kyant0", name = "m3color", version.ref = "m3color" } +kyant0-m3color = { group = "com.github.Kyant0", name = "m3color", version.ref = "m3color" } +# Capsule +kyant0-capsule = { group = "io.github.kyant0", name = "capsule", version.ref = "capsule" } # Konfetti nl-dionsegijn-konfetti-compose = { group = "nl.dionsegijn", name = "konfetti-compose", version.ref = "konfetti" }