feat: 支持在分类管理页面修改已有分类

This commit is contained in:
Super12138 2025-08-01 11:15:11 +08:00
parent 839b2a02e1
commit b92a62e57f
3 changed files with 59 additions and 34 deletions

View file

@ -47,13 +47,14 @@ fun SettingsDataCategory(
modifier: Modifier = Modifier
) {
// TODO: 本页及其相关组件重组性能检查优化
// TODO: 优化内部项目样式
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
val listState = rememberLazyListState()
var initialCategory by rememberSaveable { mutableStateOf("") }
var showDialog by rememberSaveable { mutableStateOf(false) }
val categories by DataStoreManager.categoriesFlow.collectAsState(initial = emptyList())
val isExpanded by remember { derivedStateOf { listState.firstVisibleItemIndex == 0 } }
@ -68,7 +69,10 @@ fun SettingsDataCategory(
icon = Icons.Outlined.Add,
text = stringResource(R.string.action_add_category),
expanded = isExpanded,
onClick = { showDialog = true }
onClick = {
initialCategory = ""
showDialog = true
}
)
},
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
@ -92,8 +96,12 @@ fun SettingsDataCategory(
items(items = categories, key = { it }) {
CategoryItem(
name = it,
onDelete = { it ->
scope.launch { DataStoreManager.setCategories(categories - it) }
onClick = { category ->
initialCategory = category
showDialog = true
},
onDelete = { category ->
scope.launch { DataStoreManager.setCategories(categories - category) }
},
modifier = Modifier.animateItem(
fadeInSpec = tween(100),
@ -110,20 +118,29 @@ fun SettingsDataCategory(
CategoryPromptDialog(
visible = showDialog,
text = stringResource(R.string.tip_enter_category),
onSave = {
if (!categories.contains(it)) {
scope.launch {
DataStoreManager.setCategories(categories + it)
}
} else {
scope.launch {
/*snackbarHostState.showSnackbar(
initialCategory = initialCategory,
onSave = { oldCategory, newCategory ->
if (oldCategory.isEmpty()) {
if (!categories.contains(newCategory)) {
scope.launch {
DataStoreManager.setCategories(categories + newCategory)
}
} else {
scope.launch {
/*snackbarHostState.showSnackbar(
message = context.getString(R.string.error_category_duplicate)
)*/
// 调换分类位置
val tempList = categories - it
DataStoreManager.setCategories(tempList + it)
// 调换分类位置
val tempList = categories - newCategory
DataStoreManager.setCategories(tempList + newCategory)
}
}
} else {
if (oldCategory != newCategory) {
scope.launch {
val tempList = categories - oldCategory
DataStoreManager.setCategories(tempList + newCategory)
}
}
}
},

View file

@ -6,18 +6,19 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.input.TextFieldLineLimits
import androidx.compose.foundation.text.input.clearText
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
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.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
@ -28,19 +29,20 @@ import cn.super12138.todo.ui.components.BasicDialog
fun CategoryPromptDialog(
modifier: Modifier = Modifier,
visible: Boolean,
icon: ImageVector = Icons.Outlined.Info,
title: String = stringResource(R.string.tip_tips),
text: String,
confirmButtonText: String = stringResource(R.string.action_save),
showDismissButton: Boolean = true,
dismissButtonText: String = stringResource(R.string.action_cancel),
properties: DialogProperties = DialogProperties(),
onSave: (String) -> Unit,
initialCategory: String = "",
onSave: (oldValue: String, newValue: String) -> Unit,
onDismiss: () -> Unit
) {
val textFieldState = rememberTextFieldState()
val textFieldState = rememberTextFieldState(initialText = initialCategory)
var isError by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(visible) {
if (visible) {
textFieldState.setTextAndPlaceCursorAtEnd(initialCategory)
isError = false
}
}
val supportingText = listOf(
stringResource(R.string.tip_max_length_5),
stringResource(R.string.error_no_content_entered),
@ -51,11 +53,11 @@ fun CategoryPromptDialog(
BasicDialog(
visible = visible,
icon = icon,
title = title,
icon = Icons.Outlined.Info,
title = stringResource(R.string.tip_tips),
text = {
// 已经是实现好滚动的Column布局
Text(text)
Text(stringResource(R.string.tip_enter_category))
Spacer(Modifier.size(3.dp))
OutlinedTextField(
state = textFieldState,
@ -65,8 +67,8 @@ fun CategoryPromptDialog(
isError = isError
)
},
confirmButton = confirmButtonText,
dismissButton = if (showDismissButton) dismissButtonText else null,
confirmButton = stringResource(R.string.action_save),
dismissButton = stringResource(R.string.action_cancel),
onConfirm = {
val trimmedText = textFieldState.text.trim()
when {
@ -83,7 +85,7 @@ fun CategoryPromptDialog(
}
else -> {
onSave(trimmedText.toString())
onSave(initialCategory, trimmedText.toString())
isError = false
currentSupportingText = supportingText[0]
textFieldState.clearText()
@ -92,7 +94,7 @@ fun CategoryPromptDialog(
}
},
onDismiss = onDismiss,
properties = properties,
properties = DialogProperties(),
modifier = modifier
)
}

View file

@ -18,7 +18,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.sp
import cn.super12138.todo.R
import cn.super12138.todo.ui.TodoDefaults
import cn.super12138.todo.utils.VibrationUtils
@ -27,6 +26,7 @@ import cn.super12138.todo.utils.VibrationUtils
fun CategoryItem(
modifier: Modifier = Modifier,
name: String,
onClick: (String) -> Unit = {},
onDelete: (String) -> Unit = {}
) {
val view = LocalView.current
@ -35,6 +35,12 @@ fun CategoryItem(
.fillMaxWidth()
.wrapContentHeight()
.clip(MaterialTheme.shapes.large)
.clickable(
onClick = {
VibrationUtils.performHapticFeedback(view)
onClick(name)
}
)
.padding(
horizontal = TodoDefaults.settingsItemHorizontalPadding,
vertical = TodoDefaults.settingsItemVerticalPadding / 2