feat: 初步实现添加待办功能
有待后续进行国际化和无障碍适配
This commit is contained in:
parent
0054652044
commit
52c9ce58ae
3 changed files with 226 additions and 7 deletions
|
|
@ -16,11 +16,16 @@ import androidx.compose.material3.IconButton
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
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
|
||||
|
|
@ -28,6 +33,7 @@ import androidx.compose.ui.unit.dp
|
|||
import cn.super12138.todo.R
|
||||
import cn.super12138.todo.logic.database.TodoEntity
|
||||
import cn.super12138.todo.ui.viewmodels.MainViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -40,6 +46,10 @@ fun MainPage(viewModel: MainViewModel, modifier: Modifier = Modifier) {
|
|||
}
|
||||
}
|
||||
|
||||
var openBottomSheet by rememberSaveable { mutableStateOf(false) }
|
||||
val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
|
|
@ -61,12 +71,7 @@ fun MainPage(viewModel: MainViewModel, modifier: Modifier = Modifier) {
|
|||
floatingActionButton = {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
viewModel.addTodo(
|
||||
TodoEntity(
|
||||
content = "测试内容",
|
||||
subject = "测试学科"
|
||||
)
|
||||
)
|
||||
openBottomSheet = true
|
||||
}
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -99,7 +104,9 @@ fun MainPage(viewModel: MainViewModel, modifier: Modifier = Modifier) {
|
|||
ManagerFragment(
|
||||
state = listState,
|
||||
list = toDoList.value.filter { item -> !item.isCompleted },
|
||||
onItemClick = {},
|
||||
onItemClick = {
|
||||
|
||||
},
|
||||
onItemChecked = { item ->
|
||||
item.apply {
|
||||
viewModel.updateTodo(
|
||||
|
|
@ -116,6 +123,34 @@ fun MainPage(viewModel: MainViewModel, modifier: Modifier = Modifier) {
|
|||
.weight(3f)
|
||||
.fillMaxSize()
|
||||
)
|
||||
|
||||
if (openBottomSheet) {
|
||||
TodoBottomSheet(
|
||||
sheetState = bottomSheetState,
|
||||
onDismissRequest = {
|
||||
openBottomSheet = false
|
||||
},
|
||||
onSave = { toDo ->
|
||||
viewModel.addTodo(toDo)
|
||||
scope
|
||||
.launch { bottomSheetState.hide() }
|
||||
.invokeOnCompletion {
|
||||
if (!bottomSheetState.isVisible) {
|
||||
openBottomSheet = false
|
||||
}
|
||||
}
|
||||
},
|
||||
onClose = {
|
||||
scope
|
||||
.launch { bottomSheetState.hide() }
|
||||
.invokeOnCompletion {
|
||||
if (!bottomSheetState.isVisible) {
|
||||
openBottomSheet = false
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
package cn.super12138.todo.ui.pages.main
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.SheetState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
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.compose.ui.unit.dp
|
||||
import cn.super12138.todo.R
|
||||
import cn.super12138.todo.logic.database.TodoEntity
|
||||
import cn.super12138.todo.ui.pages.main.components.FilterChipGroup
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun TodoBottomSheet(
|
||||
sheetState: SheetState,
|
||||
onDismissRequest: () -> Unit,
|
||||
onSave: (TodoEntity) -> Unit,
|
||||
onClose: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
ModalBottomSheet(
|
||||
sheetState = sheetState,
|
||||
onDismissRequest = onDismissRequest,
|
||||
modifier = modifier
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.action_add_todo),
|
||||
style = MaterialTheme.typography.headlineMedium
|
||||
)
|
||||
|
||||
Spacer(Modifier.size(25.dp))
|
||||
var text by rememberSaveable { mutableStateOf("") }
|
||||
var isError by rememberSaveable { mutableStateOf(false) }
|
||||
TextField(
|
||||
value = text,
|
||||
onValueChange = { text = it },
|
||||
label = { Text("待办内容") },
|
||||
isError = isError,
|
||||
supportingText = {
|
||||
AnimatedVisibility(isError) {
|
||||
Text("没有内容")
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Spacer(Modifier.size(5.dp))
|
||||
val subjects =
|
||||
listOf(
|
||||
"语文",
|
||||
"数学",
|
||||
"英语",
|
||||
"生物",
|
||||
"地理",
|
||||
"物理",
|
||||
"化学",
|
||||
"道法",
|
||||
"历史",
|
||||
"其它"
|
||||
)
|
||||
|
||||
var selectedItemIndex by rememberSaveable { mutableIntStateOf(0) }
|
||||
FilterChipGroup(
|
||||
items = subjects,
|
||||
onSelectedChanged = {
|
||||
selectedItemIndex = it
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Spacer(Modifier.size(20.dp))
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
OutlinedButton(
|
||||
onClick = onClose
|
||||
) {
|
||||
Text("取消")
|
||||
}
|
||||
FilledTonalButton(
|
||||
onClick = {
|
||||
if (text.trim().isEmpty()) {
|
||||
isError = true
|
||||
return@FilledTonalButton
|
||||
}
|
||||
isError = false
|
||||
onSave(
|
||||
TodoEntity(
|
||||
content = text,
|
||||
subject = subjects[selectedItemIndex]
|
||||
)
|
||||
)
|
||||
}
|
||||
) {
|
||||
Text("添加")
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.size(30.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package cn.super12138.todo.ui.pages.main.components
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Check
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.FilterChipDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* 部分参考:https://github.com/Rhythamtech/FilterChipGroup-Compose-Android/blob/main/FilterChipGroup.kt
|
||||
*/
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun FilterChipGroup(
|
||||
items: List<String>,
|
||||
defaultSelectedItemIndex: Int = 0,
|
||||
onSelectedChanged: (Int) -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var selectedItemIndex by rememberSaveable { mutableIntStateOf(defaultSelectedItemIndex) }
|
||||
|
||||
FlowRow(modifier = modifier) {
|
||||
items.forEachIndexed { index, item ->
|
||||
FilterChip(
|
||||
selected = items[selectedItemIndex] == items[index],
|
||||
onClick = {
|
||||
selectedItemIndex = index
|
||||
onSelectedChanged(index)
|
||||
},
|
||||
leadingIcon = {
|
||||
AnimatedVisibility(
|
||||
visible = items[selectedItemIndex] == items[index]
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Check,
|
||||
contentDescription = "", // TODO: 添加字符串
|
||||
modifier = Modifier.size(FilterChipDefaults.IconSize)
|
||||
)
|
||||
}
|
||||
},
|
||||
label = {
|
||||
Text(item)
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 5.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue