diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/TodoDefaults.kt b/app/src/main/kotlin/cn/super12138/todo/ui/TodoDefaults.kt index ad31b96..73bcfa1 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/TodoDefaults.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/TodoDefaults.kt @@ -38,25 +38,7 @@ object TodoDefaults { val settingsItemPadding = 4.dp - /** - * 待办进度条粗度 - */ - val trackThickness = 7.0.dp - - /** - * 待办进度条波长 - */ - val waveLength = 35.dp - - /** - * 待办进度条波速 - */ - val waveSpeed = 3.dp - - /** - * 待办进度条波幅 - */ - const val waveAmplitude = 0.6f + val overviewCardHeight = 120.dp val ScreenContainerShape: Shape @Composable diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/OverviewPage.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/OverviewPage.kt index 414a169..074fa73 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/OverviewPage.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/OverviewPage.kt @@ -59,7 +59,7 @@ fun OverviewPage( Column { LazyVerticalStaggeredGrid( modifier = Modifier.fillMaxSize(), - columns = StaggeredGridCells.Adaptive(150.dp), + columns = StaggeredGridCells.Adaptive(160.dp), horizontalArrangement = Arrangement.spacedBy(10.dp), verticalItemSpacing = 10.dp ) { diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/components/StatusCard.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/components/StatusCard.kt index a6ec03e..3523c8d 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/components/StatusCard.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/components/StatusCard.kt @@ -7,9 +7,13 @@ import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.text.BasicText +import androidx.compose.foundation.text.TextAutoSize import androidx.compose.material3.ButtonShapes import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults @@ -23,6 +27,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorProducer import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -44,14 +49,15 @@ fun RoundedCornerCardLarge( val pressed by interactionSource.collectIsPressedAsState() val animatedShape = shapeByInteraction(shapes, pressed, TodoDefaults.shapesDefaultAnimationSpec) + val cardColors = CardDefaults.cardColors(containerColor = containerColor) Card( - modifier = modifier.wrapContentHeight(), - colors = CardDefaults.cardColors(containerColor = containerColor), + modifier = modifier.height(TodoDefaults.overviewCardHeight), + colors = cardColors, shape = animatedShape ) { Row( modifier = Modifier - .fillMaxWidth() + .fillMaxSize() .clickable( enabled = true, onClick = onClick, @@ -63,18 +69,29 @@ fun RoundedCornerCardLarge( ) { Icon( painter = painterResource(iconRes), - contentDescription = null + contentDescription = null, + modifier = Modifier.size(30.dp) ) - Column(horizontalAlignment = Alignment.Start) { + Column( + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.SpaceBetween, + modifier = Modifier + .fillMaxHeight() + .padding(vertical = 8.dp) + ) { Text( text = title, style = MaterialTheme.typography.bodyMedium ) - Text( + + BasicText( text = count.toString(), - style = MaterialTheme.typography.headlineLarge.copy( - fontWeight = FontWeight.ExtraBold - ) + style = MaterialTheme.typography.headlineLarge.copy(fontWeight = FontWeight.Bold), + color = ColorProducer { cardColors.contentColor }, + autoSize = TextAutoSize.StepBased( + MaterialTheme.typography.headlineSmall.fontSize, + MaterialTheme.typography.displayMedium.fontSize + ), ) } } diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/components/UpcomingTaskCard.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/components/UpcomingTaskCard.kt index 51daa3e..b9c6ea0 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/components/UpcomingTaskCard.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/overview/components/UpcomingTaskCard.kt @@ -2,11 +2,14 @@ package cn.super12138.todo.ui.pages.overview.components import androidx.compose.foundation.layout.Arrangement 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.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Badge import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme @@ -16,12 +19,15 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import cn.super12138.todo.R import cn.super12138.todo.logic.database.TodoEntity +import cn.super12138.todo.logic.model.Priority import cn.super12138.todo.ui.TodoDefaults -import cn.super12138.todo.ui.pages.settings.components.SettingsItem -import cn.super12138.todo.utils.toLocalDateString +import cn.super12138.todo.utils.containerColor +import cn.super12138.todo.utils.toRelativeTimeString @Composable fun UpcomingTaskCard( @@ -30,7 +36,7 @@ fun UpcomingTaskCard( containerColor: Color = TodoDefaults.ContainerColor ) { Card( - modifier = modifier.height(300.dp), + modifier = modifier.height(TodoDefaults.overviewCardHeight * 2), colors = CardDefaults.cardColors(containerColor = containerColor), shape = TodoDefaults.defaultShape ) { @@ -39,11 +45,11 @@ fun UpcomingTaskCard( .fillMaxWidth() .padding(TodoDefaults.screenHorizontalPadding), horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(16.dp) + verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text( text = stringResource(R.string.title_upcoming_task), - style = MaterialTheme.typography.titleMedium + style = MaterialTheme.typography.titleLarge ) LazyColumn( @@ -53,13 +59,72 @@ fun UpcomingTaskCard( items = nextWeekTodo, key = { it.id } ) { - SettingsItem( - title = it.content, - description = it.dueDate.toLocalDateString(), - enableClick = false + UpcomingTaskItem( + content = it.content, + category = it.category, + priority = Priority.fromFloat(it.priority), + dueDate = it.dueDate ) } } } } +} + +@Composable +fun UpcomingTaskItem( + content: String, + category: String, + priority: Priority, + dueDate: Long?, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(vertical = TodoDefaults.settingsItemVerticalPadding / 4), + horizontalAlignment = Alignment.Start + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = content, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + style = MaterialTheme.typography.titleMedium, + modifier = Modifier.weight(1f) + ) + + Text( + text = dueDate.toRelativeTimeString(), + style = MaterialTheme.typography.labelMedium.copy( + color = MaterialTheme.colorScheme.onSurfaceVariant, + fontWeight = FontWeight.Bold + ), + modifier = Modifier.padding(start = TodoDefaults.screenVerticalPadding) + ) + } + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(5.dp) + ) { + Badge(containerColor = MaterialTheme.colorScheme.primary) { + Text( + text = category.ifEmpty { stringResource(R.string.tip_default_category) }, + style = MaterialTheme.typography.labelMedium, + maxLines = 1 + ) + } + + Text( + text = stringResource(priority.nameRes), + style = MaterialTheme.typography.labelMedium.copy(priority.containerColor()), + ) + } + } } \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/utils/TodoExt.kt b/app/src/main/kotlin/cn/super12138/todo/utils/TodoExt.kt index c767bca..c04fe9d 100644 --- a/app/src/main/kotlin/cn/super12138/todo/utils/TodoExt.kt +++ b/app/src/main/kotlin/cn/super12138/todo/utils/TodoExt.kt @@ -13,7 +13,10 @@ import androidx.compose.ui.graphics.drawscope.ContentDrawScope import androidx.compose.ui.unit.Dp import cn.super12138.todo.logic.model.Priority import java.text.SimpleDateFormat +import java.util.Calendar import java.util.Date +import kotlin.time.Duration.Companion.days +import kotlin.time.Duration.Companion.milliseconds @Composable @Stable @@ -83,4 +86,29 @@ fun Long?.toLocalDateString(): String { val date = Date(this) val format = SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault()) return format.format(date) +} + +// 未来相对时间(如“3天后”)的实现,最小层级为天 +fun Long?.toRelativeTimeString(): String { + if (this == null) return "" + val today = Calendar.getInstance().apply { + // 将时间设置为当天的开始(00:00:00.000) + // 兼容API24 + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + val diff = (this - today).milliseconds + + return diff.toComponents { days, _, _, _, _ -> + when { + days.days == 1.days -> "明天" + days.days > 1.days && days.days < 7.days -> "${days}天后" + days.days in 7.days..<30.days -> "${days / 7}周后" + days.days in 30.days..<365.days -> "${days / 30}个月后" + days.days >= 365.days -> "${days / 365}年后" + else -> "今天" + } + } } \ No newline at end of file