xfy d7552e469f Add KDoc and inline comments per COMMENTS.md conventions
- Add KDoc to all public Composable functions with parameter descriptions
- Add inline comments for non-obvious algorithms (42-cell grid, pager mapping)
- Add @Suppress reason comments for monthNumber deprecation
- Document collapseProgress range and physical meaning
- Add named constant comments for START_PAGE
- Add Preview name to App()

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 15:22:49 +08:00

120 lines
4.1 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package plus.rua.project.ui
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.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import kotlinx.datetime.DatePeriod
import kotlinx.datetime.LocalDate
import kotlinx.datetime.minus
import kotlinx.datetime.plus
/**
* 月度日历网格页6×7 布局,支持折叠动画。
*
* 折叠时选中行保持原高,上方行向上收缩、下方行向下收缩,模拟"挤压"效果。
*
* @param year 年份
* @param month 月份1-12
* @param selectedDate 当前选中日期
* @param today 今天的日期,用于高亮标记
* @param onDateClick 日期点击回调
* @param collapseProgress 折叠进度0f=展开6行1f=折叠(仅选中行可见)
* @param modifier 外部布局修饰符
*/
@Composable
fun CalendarMonthPage(
year: Int,
month: Int,
selectedDate: LocalDate,
today: LocalDate,
onDateClick: (LocalDate) -> Unit,
collapseProgress: Float,
modifier: Modifier = Modifier
) {
val days = remember(year, month) {
generateMonthDays(year, month)
}
val density = LocalDensity.current
val weeks = days.chunked(7)
val selectedWeekIndex = remember(weeks, selectedDate) {
weeks.indexOfFirst { week -> week.any { it.date == selectedDate } }
}
var rowHeightPx by remember { mutableIntStateOf(0) }
Column(modifier = modifier) {
weeks.forEachIndexed { weekIndex, week ->
val isAboveSelected = weekIndex < selectedWeekIndex
val isBelowSelected = weekIndex > selectedWeekIndex
val rowScale = when {
isAboveSelected || isBelowSelected -> 1f - collapseProgress
else -> 1f
}
val rowHeightDp = if (rowHeightPx > 0 && rowScale > 0.01f) {
with(density) { (rowHeightPx * rowScale).toDp() }
} else {
0.dp
}
if (rowHeightDp > 0.dp) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(rowHeightDp)
.onSizeChanged { size ->
if (weekIndex == 0 && size.height > 0) {
rowHeightPx = size.height
}
}
.padding(vertical = 2.dp)
) {
week.forEach { dayData ->
DayCell(
date = dayData.date,
isCurrentMonth = dayData.isCurrentMonth,
isSelected = dayData.date == selectedDate,
isToday = dayData.date == today,
onClick = { onDateClick(dayData.date) },
modifier = Modifier.weight(1f)
)
}
}
}
}
}
}
private data class DayData(
val date: LocalDate,
val isCurrentMonth: Boolean
)
@Suppress("DEPRECATION") // monthNumber 无替代 APIkotlinx-datetime 尚未提供新接口
private fun generateMonthDays(year: Int, month: Int): List<DayData> {
val firstOfMonth = LocalDate(year, month, 1)
val offset = firstOfMonth.dayOfWeek.ordinal
val startDate = firstOfMonth.minus(DatePeriod(days = offset))
// 6行×7列=42格覆盖跨月首尾周保证网格完整
return (0 until 42).map { i ->
val date = startDate.plus(DatePeriod(days = i))
DayData(
date = date,
isCurrentMonth = date.monthNumber == month && date.year == year
)
}
}