diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 243c527..28a4570 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -37,7 +37,7 @@ android { applicationId = "cn.super12138.todo" minSdk = 24 targetSdk = 36 - versionCode = 791 + versionCode = 883 versionName = "2.3.3" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/components/FloatingActionButton.kt b/app/src/main/kotlin/cn/super12138/todo/ui/components/FloatingActionButton.kt index fb508e2..a1aa791 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/components/FloatingActionButton.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/components/FloatingActionButton.kt @@ -1,34 +1,29 @@ package cn.super12138.todo.ui.components -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.material3.FloatingActionButton +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.FloatingActionButtonElevation import androidx.compose.material3.Icon +import androidx.compose.material3.SmallExtendedFloatingActionButton import androidx.compose.material3.Text import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier 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 import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp import cn.super12138.todo.utils.VibrationUtils /** - * 带动画且比 Material 3 内置组件动画好看的的可扩展 FAB - * * (内置组件的动画总是卡一下。。。) + * 封装的内置组件 FAB,在点击时支持添加震动反馈 + * * (现在内置组件的动画好像好一点了) * * 将缩放部分转为最简单的`AnimatedVisibility`实现 * @param icon FAB 的前置图标 * @param text FAB 的文本 - * @param textOverflow FAB 文本溢出显示方案 * @param expanded 是否为展开状态 * @param containerColor FAB 容器的颜色 * @param contentColor FAB 文本和图标颜色,通常不需要自己指定,会自动依据容器颜色设置 @@ -36,20 +31,34 @@ import cn.super12138.todo.utils.VibrationUtils * @param onClick 点击 FAB 后的回调 * @param modifier `Modifier` 修改器 */ +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable -fun AnimatedExtendedFloatingActionButton( - modifier: Modifier = Modifier, - icon: ImageVector, +fun TodoFloatingActionButton( text: String, - textOverflow: TextOverflow = TextOverflow.Clip, - expanded: Boolean, + icon: ImageVector, + onClick: () -> Unit, + modifier: Modifier = Modifier, + expanded: Boolean = true, + shape: Shape = FloatingActionButtonDefaults.smallExtendedFabShape, containerColor: Color = FloatingActionButtonDefaults.containerColor, contentColor: Color = contentColorFor(containerColor), elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(), - onClick: () -> Unit + interactionSource: MutableInteractionSource? = null, ) { val view = LocalView.current - FloatingActionButton( + SmallExtendedFloatingActionButton( + text = { + Text( + text = text, + overflow = TextOverflow.Clip + ) + }, + icon = { + Icon( + imageVector = icon, + contentDescription = null + ) + }, onClick = { VibrationUtils.performHapticFeedback(view) onClick() @@ -57,27 +66,8 @@ fun AnimatedExtendedFloatingActionButton( elevation = elevation, containerColor = containerColor, contentColor = contentColor, + shape = shape, + interactionSource = interactionSource, modifier = modifier - ) { - Row( - modifier = Modifier.padding(horizontal = 16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector = icon, - contentDescription = null - ) - // Spacer(Modifier.width(if (expanded) 8.dp else 0.dp)) - AnimatedVisibility(expanded) { - Row { - Spacer(Modifier.width(8.dp)) - Text( - text = text, - maxLines = 1, - overflow = textOverflow - ) - } - } - } - } + ) } \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/TodoEditorPage.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/TodoEditorPage.kt index 9b40cc3..9f37c83 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/TodoEditorPage.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/editor/TodoEditorPage.kt @@ -23,9 +23,7 @@ import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Save import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.SmallExtendedFloatingActionButton import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults @@ -51,6 +49,7 @@ import cn.super12138.todo.ui.TodoDefaults import cn.super12138.todo.ui.components.ChipItem import cn.super12138.todo.ui.components.ConfirmDialog import cn.super12138.todo.ui.components.LargeTopAppBarScaffold +import cn.super12138.todo.ui.components.TodoFloatingActionButton import cn.super12138.todo.ui.pages.editor.components.TodoCategoryChip import cn.super12138.todo.ui.pages.editor.components.TodoCategoryTextField import cn.super12138.todo.ui.pages.editor.components.TodoContentTextField @@ -115,41 +114,33 @@ fun TodoEditorPage( } } - BackHandler { checkModifiedBeforeBack() } + BackHandler(onBack = ::checkModifiedBeforeBack) LargeTopAppBarScaffold( title = stringResource(if (toDo != null) R.string.title_edit_task else R.string.action_add_task), scrollBehavior = scrollBehavior, floatingActionButton = { with(sharedTransitionScope) { - Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp), + modifier = Modifier.imePadding() + ) { if (toDo !== null) { - SmallExtendedFloatingActionButton( - text = { Text(stringResource(R.string.action_delete)) }, - icon = { - Icon( - imageVector = Icons.Outlined.Delete, - contentDescription = null - ) - }, + TodoFloatingActionButton( + text = stringResource(R.string.action_delete), + icon = Icons.Outlined.Delete, expanded = true, containerColor = MaterialTheme.colorScheme.errorContainer, - onClick = { uiState.showDeleteConfirmDialog = true }, - modifier = Modifier.imePadding() + onClick = { uiState.showDeleteConfirmDialog = true } ) } - SmallExtendedFloatingActionButton( - text = { Text(stringResource(R.string.action_save)) }, - icon = { - Icon( - imageVector = Icons.Outlined.Save, - contentDescription = null - ) - }, + TodoFloatingActionButton( + text = stringResource(R.string.action_save), + icon = Icons.Outlined.Save, expanded = true, onClick = { if (uiState.setErrorIfNotValid()) { - return@SmallExtendedFloatingActionButton + return@TodoFloatingActionButton } else { uiState.clearError() val newTodo = TodoEntity( @@ -163,7 +154,6 @@ fun TodoEditorPage( } }, modifier = Modifier - .imePadding() .sharedElement( sharedContentState = rememberSharedContentState(key = Constants.KEY_TODO_FAB_TRANSITION), animatedVisibilityScope = animatedVisibilityScope @@ -172,7 +162,7 @@ fun TodoEditorPage( } } }, - onBack = { checkModifiedBeforeBack() }, + onBack = ::checkModifiedBeforeBack, modifier = modifier ) { innerPadding -> LazyColumn( @@ -183,19 +173,12 @@ fun TodoEditorPage( .fillMaxSize() ) { item { - // with(sharedTransitionScope) { TodoContentTextField( value = uiState.toDoContent, onValueChange = { uiState.toDoContent = it }, isError = uiState.isErrorContent, - modifier = Modifier - .fillMaxWidth() - /*.sharedBounds( - sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_CONTENT_TRANSITION}_${toDo?.id}"), - animatedVisibilityScope = animatedVisibilityScope - )*/ + modifier = Modifier.fillMaxWidth() ) - // } } item { @@ -217,20 +200,13 @@ fun TodoEditorPage( enter = fadeIn() + expandVertically(), exit = fadeOut() + shrinkVertically() ) { - // with(sharedTransitionScope) { TodoCategoryTextField( value = uiState.categoryContent, onValueChange = { uiState.categoryContent = it }, isError = uiState.isErrorCategory, supportingText = stringResource(uiState.categorySupportingText), - modifier = Modifier - .fillMaxWidth() - /*.sharedBounds( - sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_CATEGORY_TRANSITION}_${toDo?.id}"), - animatedVisibilityScope = animatedVisibilityScope - )*/ + modifier = Modifier.fillMaxWidth() ) - // } } } 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 caed89c..3eb2921 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 @@ -13,10 +13,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Add import androidx.compose.material.icons.outlined.Delete import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.Icon 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 @@ -37,6 +34,7 @@ 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.components.TodoFloatingActionButton import cn.super12138.todo.ui.pages.main.components.TodoTopAppBar import cn.super12138.todo.ui.viewmodels.MainViewModel @@ -84,14 +82,9 @@ fun MainPage( }, floatingActionButton = { with(sharedTransitionScope) { - SmallExtendedFloatingActionButton( - text = { Text(stringResource(R.string.action_add_task)) }, - icon = { - Icon( - imageVector = Icons.Outlined.Add, - contentDescription = null - ) - }, + TodoFloatingActionButton( + text = stringResource(R.string.action_add_task), + icon = Icons.Outlined.Add, expanded = expandedFab, onClick = { toTodoEditPage(null) }, modifier = Modifier diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsDataCategory.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsDataCategory.kt index 87dd959..d586fed 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsDataCategory.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsDataCategory.kt @@ -34,8 +34,8 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.IntOffset import cn.super12138.todo.R import cn.super12138.todo.logic.datastore.DataStoreManager -import cn.super12138.todo.ui.components.AnimatedExtendedFloatingActionButton import cn.super12138.todo.ui.components.LargeTopAppBarScaffold +import cn.super12138.todo.ui.components.TodoFloatingActionButton import cn.super12138.todo.ui.pages.settings.components.category.CategoryItem import cn.super12138.todo.ui.pages.settings.components.category.CategoryPromptDialog import kotlinx.coroutines.launch @@ -65,7 +65,7 @@ fun SettingsDataCategory( scrollBehavior = scrollBehavior, snackbarHost = { SnackbarHost(snackbarHostState) }, floatingActionButton = { - AnimatedExtendedFloatingActionButton( + TodoFloatingActionButton( icon = Icons.Outlined.Add, text = stringResource(R.string.action_add_category), expanded = isExpanded, @@ -81,7 +81,7 @@ fun SettingsDataCategory( state = listState, modifier = Modifier .fillMaxSize() - .padding(innerPadding) + .padding(innerPadding) //TODO: 可能需要清除屏幕边距 ) { if (categories.isEmpty()) { item {