From 995693cb5d0ef9ee970b98008ea03ce506b8d6ee Mon Sep 17 00:00:00 2001 From: meyou <2636699780@qq.com> Date: Sat, 16 May 2026 16:29:17 +0800 Subject: [PATCH] Add year view with Hero Zoom transition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CalendarViewModel: add isYearView, yearViewProgress, yearViewYear state with toggleYearView(), selectMonthFromYearView(), year navigation methods - YearGridView: new 4x3 month grid with year navigation header - MonthHeader: onClick now toggles year view, added "今天" button - CalendarMonthView: overlay year view with graphicsLayer anchor-based scale transition, hide BottomCard during year view --- .../plus/rua/project/ui/YearGridView.kt | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt diff --git a/shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt b/shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt new file mode 100644 index 0000000..720cf0c --- /dev/null +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt @@ -0,0 +1,154 @@ +package plus.rua.project.ui + +import androidx.compose.foundation.clickable +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.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +/** + * 年度网格视图,显示 4×3 月份网格,支持年份切换。 + * + * @param year 显示的年份 + * @param selectedMonth 当前选中月份(1-12) + * @param onMonthClick 月份点击回调 + * @param onYearChange 年份切换回调 + * @param modifier 外部布局修饰符 + */ +@Composable +fun YearGridView( + year: Int, + selectedMonth: Int, + onMonthClick: (Int) -> Unit, + onYearChange: (Int) -> Unit, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // 年份导航行 + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "‹", + fontSize = 24.sp, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier + .clip(CircleShape) + .clickable { onYearChange(year - 1) } + .padding(horizontal = 16.dp, vertical = 8.dp) + ) + Spacer(modifier = Modifier.weight(1f)) + Text( + text = "${year}年", + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold + ) + Spacer(modifier = Modifier.weight(1f)) + Text( + text = "›", + fontSize = 24.sp, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier + .clip(CircleShape) + .clickable { onYearChange(year + 1) } + .padding(horizontal = 16.dp, vertical = 8.dp) + ) + } + + // 4×3 月份网格 + Column( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .padding(horizontal = 16.dp), + verticalArrangement = Arrangement.SpaceEvenly + ) { + (0 until 4).forEach { row -> + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + (0 until 3).forEach { col -> + val month = row * 3 + col + 1 + MonthCell( + month = month, + isSelected = month == selectedMonth, + onClick = { onMonthClick(month) }, + modifier = Modifier.weight(1f) + ) + } + } + } + } + } +} + +/** + * 年视图中的月份单元格。 + */ +@Composable +private fun MonthCell( + month: Int, + isSelected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + val contentColor = if (isSelected) { + MaterialTheme.colorScheme.onPrimary + } else { + MaterialTheme.colorScheme.onSurface + } + val bgColor = MaterialTheme.colorScheme.primary + + Box( + modifier = modifier + .aspectRatio(1f) + .padding(6.dp) + .clip(CircleShape) + .drawBehind { + if (isSelected) { + drawCircle( + color = bgColor, + radius = size.minDimension / 2f, + center = Offset(size.width / 2f, size.height / 2f) + ) + } + } + .clickable(onClick = onClick), + contentAlignment = Alignment.Center + ) { + Text( + text = "${month}月", + color = contentColor, + fontSize = 16.sp, + fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal, + textAlign = TextAlign.Center + ) + } +}