feat: 让更多组件适配 MD3E

This commit is contained in:
Super12138 2025-11-13 19:49:05 +08:00
parent 3b84fcd1f0
commit 24a90ea5f8
9 changed files with 73 additions and 115 deletions

View file

@ -1,47 +0,0 @@
package cn.super12138.todo.ui.components
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.material3.CircularWavyProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.ProgressIndicatorDefaults
import androidx.compose.material3.WavyProgressIndicatorDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.unit.Dp
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun AnimatedCircularWavyProgressIndicator(
progress: Float,
modifier: Modifier = Modifier,
color: Color = WavyProgressIndicatorDefaults.indicatorColor,
trackColor: Color = WavyProgressIndicatorDefaults.trackColor,
stroke: Stroke = WavyProgressIndicatorDefaults.circularIndicatorStroke,
trackStroke: Stroke = WavyProgressIndicatorDefaults.circularTrackStroke,
gapSize: Dp = WavyProgressIndicatorDefaults.CircularIndicatorTrackGapSize,
amplitude: (progress: Float) -> Float = WavyProgressIndicatorDefaults.indicatorAmplitude,
wavelength: Dp = WavyProgressIndicatorDefaults.CircularWavelength,
waveSpeed: Dp = wavelength,
) {
val animatedProgress by animateFloatAsState(
targetValue = progress,
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec
)
CircularWavyProgressIndicator(
progress = { animatedProgress },
modifier = modifier,
color = color,
trackColor = trackColor,
stroke = stroke,
trackStroke = trackStroke,
gapSize = gapSize,
amplitude = amplitude,
wavelength = wavelength,
waveSpeed = waveSpeed,
)
}

View file

@ -4,9 +4,8 @@ import androidx.activity.compose.BackHandler
import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionScope import androidx.compose.animation.SharedTransitionScope
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -14,7 +13,6 @@ 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.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.material3.animateFloatingActionButton import androidx.compose.material3.animateFloatingActionButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -26,9 +24,9 @@ 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.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.navigation3.ui.LocalNavAnimatedContentScope import androidx.navigation3.ui.LocalNavAnimatedContentScope
import androidx.window.core.layout.WindowSizeClass
import cn.super12138.todo.R 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
@ -46,7 +44,7 @@ fun MainPage(
toTodoEditPage: (TodoEntity?) -> Unit, toTodoEditPage: (TodoEntity?) -> Unit,
toSettingsPage: () -> Unit, toSettingsPage: () -> Unit,
sharedTransitionScope: SharedTransitionScope, sharedTransitionScope: SharedTransitionScope,
windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass, // windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass,
) { ) {
val animatedVisibilityScope = LocalNavAnimatedContentScope.current val animatedVisibilityScope = LocalNavAnimatedContentScope.current
@ -102,7 +100,7 @@ fun MainPage(
contentWindowInsets = WindowInsets(0, 0, 0, 0), contentWindowInsets = WindowInsets(0, 0, 0, 0),
modifier = modifier modifier = modifier
) { innerPadding -> ) { innerPadding ->
val isMediumScreen = /*val isMediumScreen =
windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND)
if (isMediumScreen) { if (isMediumScreen) {
Row( Row(
@ -141,44 +139,40 @@ fun MainPage(
.fillMaxSize() .fillMaxSize()
) )
} }
} else { } else {*/
Column( Column(
modifier = Modifier.padding( modifier = Modifier.padding(
top = innerPadding.calculateTopPadding(), top = innerPadding.calculateTopPadding(),
bottom = innerPadding.calculateBottomPadding() bottom = innerPadding.calculateBottomPadding()
) )
) { ) {
ProgressFragment( ProgressFragment(
totalTasks = totalTasks, totalTasks = totalTasks,
completedTasks = completedTasks, completedTasks = completedTasks,
modifier = Modifier modifier = Modifier.fillMaxWidth()
.weight(2f) )
.fillMaxSize() ManagerFragment(
) state = listState,
ManagerFragment( list = filteredTodoList,
state = listState, onItemClick = { item ->
list = filteredTodoList, if (inSelectedMode) {
onItemClick = { item -> viewModel.toggleTodoSelection(item)
if (inSelectedMode) { } else {
viewModel.toggleTodoSelection(item) toTodoEditPage(item)
} else { }
toTodoEditPage(item) },
} onItemLongClick = { viewModel.toggleTodoSelection(it) },
}, onItemChecked = {
onItemLongClick = { viewModel.toggleTodoSelection(it) }, viewModel.updateTodo(it.copy(isCompleted = true))
onItemChecked = { viewModel.playConfetti()
viewModel.updateTodo(it.copy(isCompleted = true)) },
viewModel.playConfetti() selectedTodoIds = selectedTodoIds,
}, modifier = Modifier.fillMaxWidth()
selectedTodoIds = selectedTodoIds, // sharedTransitionScope = sharedTransitionScope,
// sharedTransitionScope = sharedTransitionScope, // animatedVisibilityScope = animatedVisibilityScope,
// animatedVisibilityScope = animatedVisibilityScope, )
modifier = Modifier
.weight(3f)
.fillMaxSize()
)
}
} }
/*}*/
ConfirmDialog( ConfirmDialog(
visible = showDeleteConfirmDialog, visible = showDeleteConfirmDialog,
icon = Icons.Outlined.Delete, icon = Icons.Outlined.Delete,

View file

@ -1,13 +1,20 @@
package cn.super12138.todo.ui.pages.main package cn.super12138.todo.ui.pages.main
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material3.CircularWavyProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProgressIndicatorDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
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.StrokeCap
@ -21,21 +28,21 @@ 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.TodoDefaults import cn.super12138.todo.ui.TodoDefaults
import cn.super12138.todo.ui.components.AnimatedCircularWavyProgressIndicator
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
fun ProgressFragment( fun ProgressFragment(
totalTasks: Int, totalTasks: Int,
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 thickStrokeWidth = with(LocalDensity.current) { TodoDefaults.trackThickness.toPx() }
val thickStroke = remember(thickStrokeWidth) {
Stroke(width = thickStrokeWidth, cap = StrokeCap.Round)
}
val remainTasks = totalTasks - completedTasks val remainTasks = totalTasks - completedTasks
val progress = if (totalTasks != 0) { val progress = if (totalTasks != 0) {
completedTasks / totalTasks.toFloat() completedTasks / totalTasks.toFloat()
@ -45,13 +52,18 @@ fun ProgressFragment(
} }
Box( Box(
modifier = modifier, modifier = modifier.padding(20.dp),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
AnimatedCircularWavyProgressIndicator( val animatedProgress by animateFloatAsState(
progress = progress, targetValue = progress,
stroke = stroke, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec
trackStroke = stroke, )
CircularWavyProgressIndicator(
progress = { animatedProgress },
stroke = thickStroke,
trackStroke = thickStroke,
amplitude = { progress -> amplitude = { progress ->
if (progress <= 0.1f || progress >= 0.95f) { if (progress <= 0.1f || progress >= 0.95f) {
0f 0f

View file

@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
@ -38,12 +37,7 @@ fun SettingsAboutLicence(
.fillMaxSize() .fillMaxSize()
.padding(innerPadding) .padding(innerPadding)
.padding(horizontal = TodoDefaults.screenHorizontalPadding) .padding(horizontal = TodoDefaults.screenHorizontalPadding)
.clip( .clip(MaterialTheme.shapes.extraLarge)
MaterialTheme.shapes.extraLarge.copy(
bottomEnd = CornerSize(0f),
bottomStart = CornerSize(0f)
)
)
) { ) {
val listState = rememberLazyListState() val listState = rememberLazyListState()
LicenceList( LicenceList(

View file

@ -37,7 +37,7 @@ fun SettingsDeveloperOptions(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(innerPadding) .padding(innerPadding)
.padding(horizontal = TodoDefaults.screenHorizontalPadding,) .padding(horizontal = TodoDefaults.screenHorizontalPadding)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
Settings { Settings {

View file

@ -22,7 +22,6 @@ fun SettingsCategory(
top = TodoDefaults.settingsItemVerticalPadding / 2, top = TodoDefaults.settingsItemVerticalPadding / 2,
start = TodoDefaults.settingsItemHorizontalPadding, start = TodoDefaults.settingsItemHorizontalPadding,
end = TodoDefaults.settingsItemHorizontalPadding, end = TodoDefaults.settingsItemHorizontalPadding,
bottom = TodoDefaults.settingsItemVerticalPadding / 4,
) )
) { ) {
Text( Text(

View file

@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -22,9 +21,8 @@ fun Settings(
Column( Column(
verticalArrangement = Arrangement.spacedBy(2.dp), verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = modifier modifier = modifier
.padding(vertical = TodoDefaults.screenVerticalPadding).clip( .padding(vertical = TodoDefaults.screenVerticalPadding)
shape = MaterialTheme.shapes.extraLarge .clip(MaterialTheme.shapes.extraLarge),
),
content = content content = content
) )
} }

View file

@ -1,5 +1,7 @@
package cn.super12138.todo.ui.pages.settings.components package cn.super12138.todo.ui.pages.settings.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -39,7 +41,9 @@ fun SettingsRadioDialog(
text = { text = {
// Modifier.selectableGroup() 用来确保无障碍功能运行正确 // Modifier.selectableGroup() 用来确保无障碍功能运行正确
Column( Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier modifier = Modifier
.clip(MaterialTheme.shapes.extraLarge)
.selectableGroup() .selectableGroup()
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
@ -72,7 +76,8 @@ fun RadioItem(
modifier modifier
.fillMaxWidth() .fillMaxWidth()
.height(56.dp) .height(56.dp)
.clip(MaterialTheme.shapes.large) .clip(MaterialTheme.shapes.small)
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
.selectable( .selectable(
selected = selected, selected = selected,
onClick = { onClick = {

View file

@ -2,6 +2,7 @@ package cn.super12138.todo.ui.pages.settings.components.licence
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@ -24,6 +25,7 @@ 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.ui.TodoDefaults
import cn.super12138.todo.ui.components.BasicDialog import cn.super12138.todo.ui.components.BasicDialog
import cn.super12138.todo.ui.components.LazyColumnCustomScrollBar import cn.super12138.todo.ui.components.LazyColumnCustomScrollBar
import cn.super12138.todo.utils.VibrationUtils import cn.super12138.todo.utils.VibrationUtils
@ -47,6 +49,7 @@ fun LicenceList(
LazyColumn( LazyColumn(
state = state, state = state,
verticalArrangement = Arrangement.spacedBy(2.dp), verticalArrangement = Arrangement.spacedBy(2.dp),
contentPadding = PaddingValues(vertical = TodoDefaults.screenVerticalPadding),
modifier = modifier modifier = modifier
) { ) {
items(items = libraries?.libraries ?: listOf(), key = { it.artifactId }) { library -> items(items = libraries?.libraries ?: listOf(), key = { it.artifactId }) { library ->