feat: 进一步实现临近任务卡片
This commit is contained in:
parent
2f3e84b8f9
commit
b585565459
5 changed files with 132 additions and 40 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 -> "今天"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue