Skip to content

Commit

Permalink
feat(settings): 支持自定义待办列表排序
Browse files Browse the repository at this point in the history
  • Loading branch information
Super12138 committed Feb 6, 2025
1 parent 47885db commit a0f385e
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 14 deletions.
3 changes: 3 additions & 0 deletions app/src/main/kotlin/cn/super12138/todo/constants/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ object Constants {

const val PREF_SHOW_COMPLETED = "show_completed"
const val PREF_SHOW_COMPLETED_DEFAULT = true

const val PREF_SORTING_METHOD = "sorting_method"
const val PREF_SORTING_METHOD_DEFAULT = 1
}
24 changes: 14 additions & 10 deletions app/src/main/kotlin/cn/super12138/todo/constants/GlobalValues.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,27 @@ import cn.super12138.todo.utils.SPDelegates

object GlobalValues {
var dynamicColor: Boolean by SPDelegates(
Constants.PREF_DYNAMIC_COLOR,
Constants.PREF_DYNAMIC_COLOR_DEFAULT
key = Constants.PREF_DYNAMIC_COLOR,
default = Constants.PREF_DYNAMIC_COLOR_DEFAULT
)
var paletteStyle: Int by SPDelegates(
Constants.PREF_PALETTE_STYLE,
Constants.PREF_PALETTE_STYLE_DEFAULT
key = Constants.PREF_PALETTE_STYLE,
default = Constants.PREF_PALETTE_STYLE_DEFAULT
)
var darkMode: Int by SPDelegates(
Constants.PREF_DARK_MODE,
Constants.PREF_DARK_MODE_DEFAULT
key = Constants.PREF_DARK_MODE,
default = Constants.PREF_DARK_MODE_DEFAULT
)
var contrastLevel: Float by SPDelegates(
Constants.PREF_CONTRAST_LEVEL,
Constants.PREF_CONTRAST_LEVEL_DEFAULT
key = Constants.PREF_CONTRAST_LEVEL,
default = Constants.PREF_CONTRAST_LEVEL_DEFAULT
)
var showCompleted: Boolean by SPDelegates(
Constants.PREF_SHOW_COMPLETED,
Constants.PREF_SHOW_COMPLETED_DEFAULT
key = Constants.PREF_SHOW_COMPLETED,
default = Constants.PREF_SHOW_COMPLETED_DEFAULT
)
var sortingMethod: Int by SPDelegates(
key = Constants.PREF_SORTING_METHOD,
default = Constants.PREF_SORTING_METHOD_DEFAULT
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cn.super12138.todo.logic.model

import android.content.Context
import cn.super12138.todo.R

enum class SortingMethod(val id: Int) {
Date(1),
Priority(2),
Completion(3),
AlphabeticalAscending(4),
AlphabeticalDescending(5);

fun getDisplayName(context: Context): String {
val resId = when (this) {
Date -> R.string.sorting_date
Priority -> R.string.sorting_priority
Completion -> R.string.sorting_completion
AlphabeticalAscending -> R.string.sorting_alphabetical_ascending
AlphabeticalDescending -> R.string.sorting_alphabetical_descending
}
return context.getString(resId)
}

companion object {
fun fromId(id: Int): SortingMethod {
return SortingMethod.entries.find { it.id == id } ?: Date
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
Expand All @@ -37,7 +36,6 @@ import androidx.window.core.layout.WindowWidthSizeClass
import cn.super12138.todo.R
import cn.super12138.todo.constants.Constants
import cn.super12138.todo.logic.database.TodoEntity
import cn.super12138.todo.ui.components.BasicDialog
import cn.super12138.todo.ui.components.WarningDialog
import cn.super12138.todo.ui.pages.main.components.TodoFAB
import cn.super12138.todo.ui.pages.main.components.TodoTopAppBar
Expand All @@ -53,7 +51,7 @@ fun MainPage(
animatedVisibilityScope: AnimatedVisibilityScope,
modifier: Modifier = Modifier
) {
val toDoList = viewModel.toDos.collectAsState(initial = emptyList())
val toDoList = viewModel.sortedTodos.collectAsState(initial = emptyList())
val listState = rememberLazyListState()
val isExpanded by remember {
derivedStateOf {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,28 @@ 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.automirrored.outlined.Sort
import androidx.compose.material.icons.outlined.Checklist
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
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.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import cn.super12138.todo.R
import cn.super12138.todo.constants.Constants
import cn.super12138.todo.logic.model.SortingMethod
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
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.SettingsRadioDialog
import cn.super12138.todo.ui.pages.settings.components.SettingsRadioOptions
import cn.super12138.todo.ui.pages.settings.components.SwitchSettingsItem
import cn.super12138.todo.ui.viewmodels.MainViewModel

Expand All @@ -27,13 +38,16 @@ fun SettingsInterface(
onNavigateUp: () -> Unit,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
var showSortingMethodDialog by rememberSaveable { mutableStateOf(false) }
LargeTopAppBarScaffold(
title = stringResource(R.string.pref_interface),
onBack = onNavigateUp,
scrollBehavior = scrollBehavior,
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
) { innerPadding ->

Column(
modifier = Modifier
.fillMaxSize()
Expand All @@ -50,6 +64,32 @@ fun SettingsInterface(
description = stringResource(R.string.pref_show_completed_desc),
onCheckedChange = { viewModel.setShowCompleted(it) },
)
SettingsItem(
leadingIcon = Icons.AutoMirrored.Outlined.Sort,
title = stringResource(R.string.pref_sorting_method),
description = viewModel.appSortingMethod.getDisplayName(context),
onClick = { showSortingMethodDialog = true }
)
}
}

val sortingList = remember {
SortingMethod.entries.map {
SettingsRadioOptions(
id = it.id,
text = it.getDisplayName(context)
)
}
}
SettingsRadioDialog(
key = Constants.PREF_SORTING_METHOD,
defaultIndex = Constants.PREF_SORTING_METHOD_DEFAULT,
visible = showSortingMethodDialog,
title = stringResource(R.string.pref_sorting_method),
options = sortingList,
onSelect = { id ->
viewModel.setSortingMethod(SortingMethod.fromId(id))
},
onDismiss = { showSortingMethodDialog = false }
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package cn.super12138.todo.ui.pages.settings.components

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import cn.super12138.todo.ui.components.BasicDialog
import cn.super12138.todo.ui.pages.settings.state.rememberPrefIntState

@Composable
fun SettingsRadioDialog(
key: String,
defaultIndex: Int,
visible: Boolean,
title: String,
options: List<SettingsRadioOptions>,
onSelect: (id: Int) -> Unit,
onDismiss: () -> Unit,
modifier: Modifier = Modifier,
) {
SettingsDialog(
visible = visible,
title = title,
text = {
var selectedItemIndex by rememberPrefIntState(key, defaultIndex)
// Modifier.selectableGroup() 用来确保无障碍功能运行正确
Column(Modifier.selectableGroup()) {
options.forEach { option ->
Row(
Modifier
.fillMaxWidth()
.height(56.dp)
.selectable(
selected = option.id == selectedItemIndex,
onClick = {
selectedItemIndex = option.id
onSelect(option.id)
onDismiss()
},
role = Role.RadioButton
)
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
selected = option.id == selectedItemIndex,
onClick = null // 设置为 null 有利于屏幕阅读器
)
Text(
text = option.text,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(start = 16.dp)
)
}
}
}
},
onDismissRequest = onDismiss,
modifier = modifier
)
}

data class SettingsRadioOptions(
val id: Int,
val text: String,
)

@Composable
fun SettingsDialog(
visible: Boolean,
title: String,
text: @Composable (() -> Unit)? = null,
onDismissRequest: () -> Unit = {},
modifier: Modifier = Modifier
) {
BasicDialog(
visible = visible,
title = { Text(title) },
text = text,
confirmButton = {},
dismissButton = {},
onDismissRequest = onDismissRequest,
modifier = modifier
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,28 @@ import cn.super12138.todo.logic.Repository
import cn.super12138.todo.logic.database.TodoEntity
import cn.super12138.todo.logic.model.ContrastLevel
import cn.super12138.todo.logic.model.DarkMode
import cn.super12138.todo.logic.model.SortingMethod
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

class MainViewModel : ViewModel() {
// 待办
val toDos: Flow<List<TodoEntity>> = Repository.getAllTodos()
private val toDos: Flow<List<TodoEntity>> = Repository.getAllTodos()
var appSortingMethod by mutableStateOf(SortingMethod.fromId(GlobalValues.sortingMethod))
val sortedTodos: Flow<List<TodoEntity>> = toDos.map { list ->
when (appSortingMethod) {
SortingMethod.Date -> list.sortedBy { it.id }
SortingMethod.Priority -> list.sortedByDescending { it.priority } // 优先级高的在前
SortingMethod.Completion -> list.sortedBy { it.isCompleted } // 未完成的在前
SortingMethod.AlphabeticalAscending -> list.sortedBy { it.content }
SortingMethod.AlphabeticalDescending -> list.sortedByDescending { it.content }
}
}
val showConfetti = mutableStateOf(false)
var selectedEditTodo by mutableStateOf<TodoEntity?>(null)
private set
Expand Down Expand Up @@ -133,4 +145,8 @@ class MainViewModel : ViewModel() {
fun setShowCompleted(show: Boolean) {
showCompletedTodos = show
}

fun setSortingMethod(sortingMethod: SortingMethod) {
appSortingMethod = sortingMethod
}
}
6 changes: 6 additions & 0 deletions app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,10 @@
<string name="pref_view_on_github">在 GitHub 上查看</string>
<string name="pref_view_on_github_desc">查看源代码、提交错误报告和改进建议</string>
<string name="tip_discard_changes">退出编辑后将无法找回你修改过的数据。确定退出编辑吗?</string>
<string name="sorting_date">日期</string>
<string name="sorting_priority">优先级</string>
<string name="sorting_completion">完成状态</string>
<string name="sorting_alphabetical_ascending">首字母(升序)</string>
<string name="sorting_alphabetical_descending">首字母(降序)</string>
<string name="pref_sorting_method">排序方式</string>
</resources>
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,10 @@
<string name="pref_view_on_github">View On GitHub</string>
<string name="pref_view_on_github_desc">View source code, submit bug reports, and improvement suggestions</string>
<string name="tip_discard_changes">After exiting edit mode, you will not be able to retrieve the data you have modified. Are you sure you want to exit editing?</string>
<string name="sorting_date">Date</string>
<string name="sorting_priority">Priority</string>
<string name="sorting_completion">Completion</string>
<string name="sorting_alphabetical_ascending">Alphabetical (Ascending)</string>
<string name="sorting_alphabetical_descending">Alphabetical (Descending)</string>
<string name="pref_sorting_method">Sorting Method</string>
</resources>

0 comments on commit a0f385e

Please sign in to comment.