Files
TaskTTL/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownDetailScreen.kt

260 lines
10 KiB
Kotlin
Raw Normal View History

2025-10-08 18:08:15 +08:00
package com.taskttl.presentation.countdown
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CalendarToday
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.taskttl.core.ui.Chip
2025-10-12 22:08:39 +08:00
import com.taskttl.core.ui.LoadingScreen
2025-10-08 18:08:15 +08:00
import com.taskttl.core.utils.DateUtils
import com.taskttl.data.state.CountdownEffect
import com.taskttl.data.viewmodel.CountdownViewModel
import com.taskttl.ui.components.AppHeader
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
import taskttl.composeapp.generated.resources.Res
import taskttl.composeapp.generated.resources.countdown_not_found
import taskttl.composeapp.generated.resources.detail_information
import taskttl.composeapp.generated.resources.event_description
2025-10-12 22:08:39 +08:00
import taskttl.composeapp.generated.resources.label_created_at
2025-10-08 18:08:15 +08:00
import taskttl.composeapp.generated.resources.label_days
import taskttl.composeapp.generated.resources.reminder
import taskttl.composeapp.generated.resources.title_countdown_info
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CountdownDetailScreen(
countdownId: String,
onNavigateBack: () -> Unit,
onNavigateToEdit: () -> Unit,
viewModel: CountdownViewModel = koinViewModel()
) {
val state by viewModel.state.collectAsState()
val countdown = state.countdowns.find { it.id == countdownId }
LaunchedEffect(Unit) {
viewModel.effects.collect { effect ->
when (effect) {
is CountdownEffect.NavigateBack -> {
onNavigateBack()
}
else -> {}
}
}
}
if (countdown == null) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(stringResource(Res.string.countdown_not_found))
}
return
}
// 剩余天数
val daysRemaining = DateUtils.daysRemaining(countdown.targetDate)
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
Column(
modifier = Modifier.fillMaxSize()
) {
AppHeader(
title = Res.string.title_countdown_info,
showBack = true,
onBackClick = { onNavigateBack.invoke() },
trailingIcon = Icons.Default.Edit,
onTrailingClick = { onNavigateToEdit.invoke() }
)
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFFF5F5F5))
.padding(16.dp)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(20.dp))
.background(
brush = androidx.compose.ui.graphics.Brush.linearGradient(
colors = listOf(
countdown.category.color.backgroundColor,
Color.Transparent
)
)
)
.padding(20.dp)
) {
Column(modifier = Modifier.align(Alignment.CenterStart)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = countdown.title,
fontSize = 18.sp,
fontWeight = FontWeight.ExtraBold,
color = Color(0xFF111111)
)
Spacer(modifier = Modifier.width(6.dp))
Chip(text = countdown.category.name)
}
Spacer(modifier = Modifier.height(6.dp))
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
imageVector = Icons.Default.CalendarToday,
contentDescription = null
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = countdown.targetDate.toString(),
fontSize = 14.sp,
color = Color(0xFF444444)
)
}
}
Column(
modifier = Modifier.align(Alignment.TopEnd),
horizontalAlignment = Alignment.End
) {
Text(
text = daysRemaining.toString(),
fontSize = 44.sp,
fontWeight = FontWeight.ExtraBold,
color = Color(0xFF111111)
)
Text(
text = stringResource(Res.string.label_days),
fontSize = 12.sp,
fontWeight = FontWeight.SemiBold,
color = Color(0xFF666666)
)
}
}
countdown.description.let {
Spacer(modifier = Modifier.height(16.dp))
Column(modifier = Modifier.fillMaxWidth()) {
Text(
text = stringResource(Res.string.event_description),
fontWeight = FontWeight.SemiBold,
fontSize = 14.sp,
color = Color(0xFF333333)
)
Spacer(modifier = Modifier.height(10.dp))
Box(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(12.dp))
.background(Color.White)
.padding(12.dp)
) {
Column {
Text(
text = countdown.description,
color = countdown.category.color.textColor,
lineHeight = 20.sp
)
}
}
}
}
Spacer(modifier = Modifier.height(12.dp))
Column(modifier = Modifier.fillMaxWidth()) {
Text(
text = stringResource(Res.string.detail_information),
fontWeight = FontWeight.SemiBold,
fontSize = 14.sp,
color = Color(0xFF333333)
)
Spacer(modifier = Modifier.height(10.dp))
Column {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(10.dp)
) {
InfoItem(
iconTint = Color(0xFF667EEA),
text = "${stringResource(Res.string.reminder)}${
stringResource(countdown.notificationEnabled.displayNameRes)
}",
modifier = Modifier.weight(1f)
)
}
Spacer(modifier = Modifier.height(10.dp))
Row(modifier = Modifier.fillMaxWidth()) {
InfoItem(
iconTint = Color(0xFF999999),
2025-10-12 22:08:39 +08:00
text = "${stringResource(Res.string.label_created_at)}${countdown.createdAt}",
2025-10-08 18:08:15 +08:00
modifier = Modifier.fillMaxWidth()
)
}
}
}
}
}
2025-10-12 22:08:39 +08:00
if (state.isLoading) LoadingScreen()
2025-10-08 18:08:15 +08:00
}
}
@Composable
private fun InfoItem(iconTint: Color, text: String, modifier: Modifier = Modifier) {
Row(
modifier = modifier
.clip(RoundedCornerShape(10.dp))
.background(Color.White)
.padding(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(18.dp)
.clip(RoundedCornerShape(6.dp))
.background(iconTint)
) {}
Spacer(modifier = Modifier.width(10.dp))
Text(text = text, fontSize = 13.sp, color = Color(0xFF555555))
}
}