refactor: 对组件进行 Material 3 Expressive 适配
This commit is contained in:
parent
bc189c9b9c
commit
96fdb86e91
11 changed files with 177 additions and 85 deletions
|
|
@ -6,14 +6,19 @@ import cn.super12138.todo.R
|
||||||
enum class SortingMethod(val id: Int) {
|
enum class SortingMethod(val id: Int) {
|
||||||
// 按添加先后顺序
|
// 按添加先后顺序
|
||||||
Sequential(1),
|
Sequential(1),
|
||||||
|
|
||||||
// 按学科
|
// 按学科
|
||||||
Category(2),
|
Category(2),
|
||||||
|
|
||||||
// 按优先级
|
// 按优先级
|
||||||
Priority(3),
|
Priority(3),
|
||||||
|
|
||||||
// 按完成情况
|
// 按完成情况
|
||||||
Completion(4),
|
Completion(4),
|
||||||
|
|
||||||
// 按字母升序
|
// 按字母升序
|
||||||
AlphabeticalAscending(5),
|
AlphabeticalAscending(5),
|
||||||
|
|
||||||
// 按字母降序
|
// 按字母降序
|
||||||
AlphabeticalDescending(6);
|
AlphabeticalDescending(6);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,24 @@ object TodoDefaults {
|
||||||
* 设置项垂直边距
|
* 设置项垂直边距
|
||||||
*/
|
*/
|
||||||
val settingsItemVerticalPadding = 20.dp
|
val settingsItemVerticalPadding = 20.dp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办进度条粗度
|
||||||
|
*/
|
||||||
|
val trackThickness = 7.0.dp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办进度条波长
|
||||||
|
*/
|
||||||
|
val waveLength = 35.dp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办进度条波速
|
||||||
|
*/
|
||||||
|
val waveSpeed = 3.dp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办进度条波幅
|
||||||
|
*/
|
||||||
|
const val waveAmplitude = 0.6f
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,5 @@
|
||||||
package cn.super12138.todo.ui.components
|
package cn.super12138.todo.ui.components
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
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.ExperimentalLayoutApi
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -18,19 +12,16 @@ import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.SideEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import cn.super12138.todo.R
|
import cn.super12138.todo.R
|
||||||
import cn.super12138.todo.utils.VibrationUtils
|
import cn.super12138.todo.utils.VibrationUtils
|
||||||
import kotlin.math.log
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部分参考:https://github.com/Rhythamtech/FilterChipGroup-Compose-Android/blob/main/FilterChipGroup.kt
|
* 部分参考:https://github.com/Rhythamtech/FilterChipGroup-Compose-Android/blob/main/FilterChipGroup.kt
|
||||||
|
|
@ -75,20 +66,19 @@ private fun FilterChipItem(
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = selected,
|
selected = selected,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
leadingIcon = {
|
|
||||||
AnimatedVisibility(
|
|
||||||
visible = selected,
|
|
||||||
enter = expandIn(expandFrom = Alignment.CenterStart) + fadeIn(),
|
|
||||||
exit = shrinkOut(shrinkTowards = Alignment.CenterStart) + fadeOut()
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Outlined.Check,
|
|
||||||
contentDescription = stringResource(R.string.tip_select_this),
|
|
||||||
modifier = Modifier.size(FilterChipDefaults.IconSize)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
label = { Text(text) },
|
label = { Text(text) },
|
||||||
|
leadingIcon =
|
||||||
|
if (selected) {
|
||||||
|
{
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Check,
|
||||||
|
contentDescription = stringResource(R.string.tip_select_this),
|
||||||
|
modifier = Modifier.size(FilterChipDefaults.IconSize)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
modifier = modifier.padding(end = 10.dp)
|
modifier = modifier.padding(end = 10.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.ErrorOutline
|
import androidx.compose.material.icons.outlined.ErrorOutline
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.FilledTonalButton
|
import androidx.compose.material3.FilledTonalButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
|
@ -50,6 +52,7 @@ fun ConfirmDialog(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun BasicDialog(
|
fun BasicDialog(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|
@ -83,7 +86,8 @@ fun BasicDialog(
|
||||||
onClick = {
|
onClick = {
|
||||||
VibrationUtils.performHapticFeedback(view)
|
VibrationUtils.performHapticFeedback(view)
|
||||||
onConfirm()
|
onConfirm()
|
||||||
}
|
},
|
||||||
|
shapes = ButtonDefaults.shapes()
|
||||||
) {
|
) {
|
||||||
Text(confirmButton)
|
Text(confirmButton)
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +98,8 @@ fun BasicDialog(
|
||||||
onClick = {
|
onClick = {
|
||||||
VibrationUtils.performHapticFeedback(view)
|
VibrationUtils.performHapticFeedback(view)
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
},
|
||||||
|
shapes = ButtonDefaults.shapes()
|
||||||
) {
|
) {
|
||||||
Text(it)
|
Text(it)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,47 @@
|
||||||
package cn.super12138.todo.ui.components
|
package cn.super12138.todo.ui.components
|
||||||
|
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularWavyProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.ProgressIndicatorDefaults
|
import androidx.compose.material3.ProgressIndicatorDefaults
|
||||||
|
import androidx.compose.material3.WavyProgressIndicatorDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AnimatedCircularProgressIndicator(
|
fun AnimatedCircularWavyProgressIndicator(
|
||||||
progress: Float,
|
progress: Float,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
color: Color = ProgressIndicatorDefaults.circularColor,
|
color: Color = WavyProgressIndicatorDefaults.indicatorColor,
|
||||||
strokeWidth: Dp = ProgressIndicatorDefaults.CircularStrokeWidth,
|
trackColor: Color = WavyProgressIndicatorDefaults.trackColor,
|
||||||
trackColor: Color = ProgressIndicatorDefaults.circularDeterminateTrackColor,
|
stroke: Stroke = WavyProgressIndicatorDefaults.circularIndicatorStroke,
|
||||||
strokeCap: StrokeCap = ProgressIndicatorDefaults.CircularDeterminateStrokeCap,
|
trackStroke: Stroke = WavyProgressIndicatorDefaults.circularTrackStroke,
|
||||||
gapSize: Dp = ProgressIndicatorDefaults.CircularIndicatorTrackGapSize
|
gapSize: Dp = WavyProgressIndicatorDefaults.CircularIndicatorTrackGapSize,
|
||||||
|
amplitude: (progress: Float) -> Float = WavyProgressIndicatorDefaults.indicatorAmplitude,
|
||||||
|
wavelength: Dp = WavyProgressIndicatorDefaults.CircularWavelength,
|
||||||
|
waveSpeed: Dp = wavelength,
|
||||||
) {
|
) {
|
||||||
val animatedProgress by animateFloatAsState(
|
val animatedProgress by animateFloatAsState(
|
||||||
targetValue = progress,
|
targetValue = progress,
|
||||||
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec
|
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec
|
||||||
)
|
)
|
||||||
|
|
||||||
CircularProgressIndicator(
|
CircularWavyProgressIndicator(
|
||||||
progress = { animatedProgress },
|
progress = { animatedProgress },
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
color = color,
|
color = color,
|
||||||
strokeWidth = strokeWidth,
|
|
||||||
trackColor = trackColor,
|
trackColor = trackColor,
|
||||||
strokeCap = strokeCap,
|
stroke = stroke,
|
||||||
gapSize = gapSize
|
trackStroke = trackStroke,
|
||||||
|
gapSize = gapSize,
|
||||||
|
amplitude = amplitude,
|
||||||
|
wavelength = wavelength,
|
||||||
|
waveSpeed = waveSpeed,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -13,9 +13,12 @@ import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.outlined.ExitToApp
|
import androidx.compose.material.icons.automirrored.outlined.ExitToApp
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LargeTopAppBar
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SmallExtendedFloatingActionButton
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -40,12 +43,11 @@ import cn.super12138.todo.ui.activities.CrashActivity.Companion.BRAND_PREFIX
|
||||||
import cn.super12138.todo.ui.activities.CrashActivity.Companion.CRASH_TIME_PREFIX
|
import cn.super12138.todo.ui.activities.CrashActivity.Companion.CRASH_TIME_PREFIX
|
||||||
import cn.super12138.todo.ui.activities.CrashActivity.Companion.DEVICE_SDK_PREFIX
|
import cn.super12138.todo.ui.activities.CrashActivity.Companion.DEVICE_SDK_PREFIX
|
||||||
import cn.super12138.todo.ui.activities.CrashActivity.Companion.MODEL_PREFIX
|
import cn.super12138.todo.ui.activities.CrashActivity.Companion.MODEL_PREFIX
|
||||||
import cn.super12138.todo.ui.components.AnimatedExtendedFloatingActionButton
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun CrashPage(
|
fun CrashPage(
|
||||||
crashLog: String,
|
crashLog: String,
|
||||||
|
|
@ -77,11 +79,16 @@ fun CrashPage(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
AnimatedExtendedFloatingActionButton(
|
SmallExtendedFloatingActionButton(
|
||||||
onClick = exitApp,
|
text = { Text(stringResource(R.string.action_exit_app)) },
|
||||||
icon = Icons.AutoMirrored.Outlined.ExitToApp,
|
icon = {
|
||||||
text = stringResource(R.string.action_exit_app),
|
Icon(
|
||||||
expanded = isExpanded
|
imageVector = Icons.AutoMirrored.Outlined.ExitToApp,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
},
|
||||||
|
expanded = isExpanded,
|
||||||
|
onClick = exitApp
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
contentWindowInsets = WindowInsets(0, 0, 0, 0)
|
contentWindowInsets = WindowInsets(0, 0, 0, 0)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,10 @@ import androidx.compose.material.icons.automirrored.outlined.Undo
|
||||||
import androidx.compose.material.icons.outlined.Delete
|
import androidx.compose.material.icons.outlined.Delete
|
||||||
import androidx.compose.material.icons.outlined.Save
|
import androidx.compose.material.icons.outlined.Save
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.SmallExtendedFloatingActionButton
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
|
@ -45,7 +48,6 @@ import cn.super12138.todo.constants.Constants
|
||||||
import cn.super12138.todo.logic.database.TodoEntity
|
import cn.super12138.todo.logic.database.TodoEntity
|
||||||
import cn.super12138.todo.logic.datastore.DataStoreManager
|
import cn.super12138.todo.logic.datastore.DataStoreManager
|
||||||
import cn.super12138.todo.ui.TodoDefaults
|
import cn.super12138.todo.ui.TodoDefaults
|
||||||
import cn.super12138.todo.ui.components.AnimatedExtendedFloatingActionButton
|
|
||||||
import cn.super12138.todo.ui.components.ChipItem
|
import cn.super12138.todo.ui.components.ChipItem
|
||||||
import cn.super12138.todo.ui.components.ConfirmDialog
|
import cn.super12138.todo.ui.components.ConfirmDialog
|
||||||
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
|
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
|
||||||
|
|
@ -56,7 +58,10 @@ import cn.super12138.todo.ui.pages.editor.components.TodoPrioritySlider
|
||||||
import cn.super12138.todo.ui.pages.editor.state.rememberEditorState
|
import cn.super12138.todo.ui.pages.editor.state.rememberEditorState
|
||||||
import cn.super12138.todo.utils.VibrationUtils
|
import cn.super12138.todo.utils.VibrationUtils
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalSharedTransitionApi::class)
|
@OptIn(
|
||||||
|
ExperimentalMaterial3Api::class, ExperimentalSharedTransitionApi::class,
|
||||||
|
ExperimentalMaterial3ExpressiveApi::class
|
||||||
|
)
|
||||||
@Composable
|
@Composable
|
||||||
fun TodoEditorPage(
|
fun TodoEditorPage(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|
@ -119,22 +124,32 @@ fun TodoEditorPage(
|
||||||
with(sharedTransitionScope) {
|
with(sharedTransitionScope) {
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||||
if (toDo !== null) {
|
if (toDo !== null) {
|
||||||
AnimatedExtendedFloatingActionButton(
|
SmallExtendedFloatingActionButton(
|
||||||
icon = Icons.Outlined.Delete,
|
text = { Text(stringResource(R.string.action_delete)) },
|
||||||
text = stringResource(R.string.action_delete),
|
icon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Delete,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
},
|
||||||
expanded = true,
|
expanded = true,
|
||||||
containerColor = MaterialTheme.colorScheme.errorContainer,
|
containerColor = MaterialTheme.colorScheme.errorContainer,
|
||||||
onClick = { uiState.showDeleteConfirmDialog = true },
|
onClick = { uiState.showDeleteConfirmDialog = true },
|
||||||
modifier = Modifier.imePadding()
|
modifier = Modifier.imePadding()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
AnimatedExtendedFloatingActionButton(
|
SmallExtendedFloatingActionButton(
|
||||||
icon = Icons.Outlined.Save,
|
text = { Text(stringResource(R.string.action_save)) },
|
||||||
text = stringResource(R.string.action_save),
|
icon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Save,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
},
|
||||||
expanded = true,
|
expanded = true,
|
||||||
onClick = {
|
onClick = {
|
||||||
if (uiState.setErrorIfNotValid()) {
|
if (uiState.setErrorIfNotValid()) {
|
||||||
return@AnimatedExtendedFloatingActionButton
|
return@SmallExtendedFloatingActionButton
|
||||||
} else {
|
} else {
|
||||||
uiState.clearError()
|
uiState.clearError()
|
||||||
val newTodo = TodoEntity(
|
val newTodo = TodoEntity(
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,11 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Add
|
import androidx.compose.material.icons.outlined.Add
|
||||||
import androidx.compose.material.icons.outlined.Delete
|
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.Scaffold
|
||||||
|
import androidx.compose.material3.SmallExtendedFloatingActionButton
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
|
@ -35,12 +39,11 @@ import cn.super12138.todo.R
|
||||||
import cn.super12138.todo.constants.Constants
|
import cn.super12138.todo.constants.Constants
|
||||||
import cn.super12138.todo.logic.database.TodoEntity
|
import cn.super12138.todo.logic.database.TodoEntity
|
||||||
import cn.super12138.todo.logic.datastore.DataStoreManager
|
import cn.super12138.todo.logic.datastore.DataStoreManager
|
||||||
import cn.super12138.todo.ui.components.AnimatedExtendedFloatingActionButton
|
|
||||||
import cn.super12138.todo.ui.components.ConfirmDialog
|
import cn.super12138.todo.ui.components.ConfirmDialog
|
||||||
import cn.super12138.todo.ui.pages.main.components.TodoTopAppBar
|
import cn.super12138.todo.ui.pages.main.components.TodoTopAppBar
|
||||||
import cn.super12138.todo.ui.viewmodels.MainViewModel
|
import cn.super12138.todo.ui.viewmodels.MainViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalSharedTransitionApi::class)
|
@OptIn(ExperimentalSharedTransitionApi::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MainPage(
|
fun MainPage(
|
||||||
viewModel: MainViewModel,
|
viewModel: MainViewModel,
|
||||||
|
|
@ -65,6 +68,7 @@ fun MainPage(
|
||||||
val completedTasks by remember { derivedStateOf { toDoList.count { it.isCompleted } } }
|
val completedTasks by remember { derivedStateOf { toDoList.count { it.isCompleted } } }
|
||||||
val filteredTodoList =
|
val filteredTodoList =
|
||||||
if (showCompleted) toDoList else toDoList.filter { item -> !item.isCompleted }
|
if (showCompleted) toDoList else toDoList.filter { item -> !item.isCompleted }
|
||||||
|
val expandedFab by remember { derivedStateOf { listState.firstVisibleItemIndex == 0 } }
|
||||||
|
|
||||||
// 当按下返回键(或进行返回操作)时清空选择,仅在非选择模式下生效
|
// 当按下返回键(或进行返回操作)时清空选择,仅在非选择模式下生效
|
||||||
BackHandler(inSelectedMode) { viewModel.clearAllTodoSelection() }
|
BackHandler(inSelectedMode) { viewModel.clearAllTodoSelection() }
|
||||||
|
|
@ -88,7 +92,7 @@ fun MainPage(
|
||||||
exit = shrinkOut() + fadeOut()
|
exit = shrinkOut() + fadeOut()
|
||||||
) {
|
) {
|
||||||
// TODO: 修复在滑动列表时FAB位移导致的动画不连贯(临时方案为底部加padding)
|
// TODO: 修复在滑动列表时FAB位移导致的动画不连贯(临时方案为底部加padding)
|
||||||
AnimatedExtendedFloatingActionButton(
|
/*AnimatedExtendedFloatingActionButton(
|
||||||
icon = Icons.Outlined.Add,
|
icon = Icons.Outlined.Add,
|
||||||
text = stringResource(R.string.action_add_task),
|
text = stringResource(R.string.action_add_task),
|
||||||
expanded = true,
|
expanded = true,
|
||||||
|
|
@ -100,6 +104,24 @@ fun MainPage(
|
||||||
sharedContentState = rememberSharedContentState(key = Constants.KEY_TODO_FAB_TRANSITION),
|
sharedContentState = rememberSharedContentState(key = Constants.KEY_TODO_FAB_TRANSITION),
|
||||||
animatedVisibilityScope = animatedVisibilityScope
|
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
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,18 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.StrokeCap
|
||||||
|
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import cn.super12138.todo.R
|
import cn.super12138.todo.R
|
||||||
import cn.super12138.todo.ui.components.AnimatedCircularProgressIndicator
|
import cn.super12138.todo.ui.TodoDefaults
|
||||||
|
import cn.super12138.todo.ui.components.AnimatedCircularWavyProgressIndicator
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ProgressFragment(
|
fun ProgressFragment(
|
||||||
|
|
@ -25,6 +29,11 @@ fun ProgressFragment(
|
||||||
completedTasks: Int,
|
completedTasks: Int,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
val stroke = Stroke(
|
||||||
|
width = with(LocalDensity.current) { TodoDefaults.trackThickness.toPx() },
|
||||||
|
cap = StrokeCap.Round,
|
||||||
|
)
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val remainTasks = totalTasks - completedTasks
|
val remainTasks = totalTasks - completedTasks
|
||||||
|
|
@ -39,10 +48,19 @@ fun ProgressFragment(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
AnimatedCircularProgressIndicator(
|
AnimatedCircularWavyProgressIndicator(
|
||||||
progress = progress,
|
progress = progress,
|
||||||
strokeWidth = 10.dp,
|
stroke = stroke,
|
||||||
gapSize = 10.dp,
|
trackStroke = stroke,
|
||||||
|
amplitude = { progress ->
|
||||||
|
if (progress <= 0.1f || progress >= 0.95f) {
|
||||||
|
0f
|
||||||
|
} else {
|
||||||
|
TodoDefaults.waveAmplitude
|
||||||
|
}
|
||||||
|
},
|
||||||
|
wavelength = TodoDefaults.waveLength,
|
||||||
|
waveSpeed = TodoDefaults.waveSpeed,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(175.dp)
|
.size(175.dp)
|
||||||
.clearAndSetSemantics {}
|
.clearAndSetSemantics {}
|
||||||
|
|
|
||||||
|
|
@ -120,33 +120,33 @@ fun TodoCard(
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
// with(sharedTransitionScope) {
|
// with(sharedTransitionScope) {
|
||||||
Text(
|
Text(
|
||||||
text = content,
|
text = content,
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
textDecoration = if (completed) TextDecoration.LineThrough else TextDecoration.None,
|
textDecoration = if (completed) TextDecoration.LineThrough else TextDecoration.None,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
/*.sharedBounds(
|
/*.sharedBounds(
|
||||||
sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_CONTENT_TRANSITION}_$id"),
|
sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_CONTENT_TRANSITION}_$id"),
|
||||||
animatedVisibilityScope = animatedVisibilityScope
|
animatedVisibilityScope = animatedVisibilityScope
|
||||||
)*/
|
)*/
|
||||||
.basicMarquee() // TODO: 后续评估性能影响
|
.basicMarquee() // TODO: 后续评估性能影响
|
||||||
)
|
)
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// with(sharedTransitionScope) {
|
// with(sharedTransitionScope) {
|
||||||
Text(
|
Text(
|
||||||
text = category.ifEmpty { stringResource(R.string.tip_default_category) },
|
text = category.ifEmpty { stringResource(R.string.tip_default_category) },
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
textDecoration = if (completed) TextDecoration.LineThrough else TextDecoration.None,
|
textDecoration = if (completed) TextDecoration.LineThrough else TextDecoration.None,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
/*modifier = Modifier.sharedBounds(
|
/*modifier = Modifier.sharedBounds(
|
||||||
sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_CATEGORY_TRANSITION}_$id"),
|
sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_CATEGORY_TRANSITION}_$id"),
|
||||||
animatedVisibilityScope = animatedVisibilityScope
|
animatedVisibilityScope = animatedVisibilityScope
|
||||||
)*/
|
)*/
|
||||||
)
|
)
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ package cn.super12138.todo.ui.theme
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.MaterialExpressiveTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.colorResource
|
import androidx.compose.ui.res.colorResource
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ToDoTheme(
|
fun ToDoTheme(
|
||||||
color: Color? = null,
|
color: Color? = null,
|
||||||
|
|
@ -33,7 +35,7 @@ fun ToDoTheme(
|
||||||
contrastLevel = contrastLevel
|
contrastLevel = contrastLevel
|
||||||
)
|
)
|
||||||
|
|
||||||
MaterialTheme(
|
MaterialExpressiveTheme(
|
||||||
colorScheme = colorScheme,
|
colorScheme = colorScheme,
|
||||||
typography = Typography,
|
typography = Typography,
|
||||||
content = content
|
content = content
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue