Switch CalendarMonthPage from Column to Box with calculated y positions per row, enabling precise height computation that aligns with CalendarMonthView's BottomCard positioning. Simplify cardTopPx calculation by deriving grid height from the same formula instead of tracking expandedCalendarHeightPx separately. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
134 lines
5.3 KiB
Kotlin
134 lines
5.3 KiB
Kotlin
package plus.rua.project.ui
|
||
|
||
import androidx.compose.foundation.layout.Box
|
||
import androidx.compose.foundation.layout.Column
|
||
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.statusBarsPadding
|
||
import androidx.compose.runtime.Composable
|
||
import androidx.compose.runtime.getValue
|
||
import androidx.compose.runtime.mutableIntStateOf
|
||
import androidx.compose.runtime.remember
|
||
import androidx.compose.runtime.rememberCoroutineScope
|
||
import androidx.compose.runtime.setValue
|
||
import androidx.compose.ui.Alignment
|
||
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.TimeZone
|
||
import kotlinx.datetime.todayIn
|
||
import kotlin.time.Clock
|
||
import plus.rua.project.CalendarViewModel
|
||
|
||
/**
|
||
* 日历主界面,包含月/周视图切换和折叠动画。
|
||
*
|
||
* 折叠时日历从月视图(6行)收缩为周视图(1行),BottomCard 同步上移填充空间。
|
||
*
|
||
* @param modifier 外部布局修饰符
|
||
*/
|
||
@Composable
|
||
fun CalendarMonthView(
|
||
modifier: Modifier = Modifier
|
||
) {
|
||
val coroutineScope = rememberCoroutineScope()
|
||
val viewModel = remember { CalendarViewModel(coroutineScope) }
|
||
val today = remember { Clock.System.todayIn(TimeZone.currentSystemDefault()) }
|
||
var currentYear by remember { mutableIntStateOf(viewModel.currentYear) }
|
||
var currentMonth by remember { mutableIntStateOf(viewModel.currentMonth) }
|
||
val density = LocalDensity.current
|
||
|
||
var calendarHeightPx by remember { mutableIntStateOf(0) }
|
||
var monthHeaderHeightPx by remember { mutableIntStateOf(0) }
|
||
var weekdayHeaderHeightPx by remember { mutableIntStateOf(0) }
|
||
var screenHeightPx by remember { mutableIntStateOf(0) }
|
||
|
||
val p = viewModel.collapseProgress
|
||
val headerHeightPx = monthHeaderHeightPx + weekdayHeaderHeightPx
|
||
|
||
// 展开时网格高度 = 首次测量的日历总高度 - headers
|
||
val expandedGridHeightPx = calendarHeightPx - headerHeightPx
|
||
val weeksCount = 6
|
||
|
||
// 折叠时网格高度公式(与 CalendarMonthPage 一致):
|
||
// gridH = rowH × (1 + (weeks-1) × (1-p))
|
||
// 其中 rowH = expandedGridHeightPx / weeksCount
|
||
val gridHeightPx = if (expandedGridHeightPx > 0 && p > 0f) {
|
||
val rowH = expandedGridHeightPx.toFloat() / weeksCount
|
||
(rowH * (1 + (weeksCount - 1) * (1f - p))).toInt()
|
||
} else if (expandedGridHeightPx > 0) {
|
||
expandedGridHeightPx
|
||
} else 0
|
||
|
||
val cardTopPx = headerHeightPx + gridHeightPx
|
||
val cardHeightPx = screenHeightPx - cardTopPx
|
||
|
||
if (p > 0f) {
|
||
println("[View] p=$p monthH=$monthHeaderHeightPx weekdayH=$weekdayHeaderHeightPx expandedGridH=$expandedGridHeightPx gridH=$gridHeightPx cardTop=$cardTopPx cardH=$cardHeightPx screenH=$screenHeightPx calH=$calendarHeightPx isCollapsed=${viewModel.isCollapsed}")
|
||
}
|
||
|
||
Box(
|
||
modifier = modifier
|
||
.fillMaxSize()
|
||
.statusBarsPadding()
|
||
.onSizeChanged { size ->
|
||
screenHeightPx = size.height
|
||
}
|
||
) {
|
||
Column(modifier = Modifier.padding(horizontal = 16.dp).onSizeChanged { size ->
|
||
// 仅在展开时记录日历总高度(折叠时 HorizontalPager 不缩小)
|
||
if (p < 0.01f) {
|
||
calendarHeightPx = size.height
|
||
}
|
||
}) {
|
||
MonthHeader(
|
||
year = currentYear,
|
||
month = currentMonth,
|
||
weekNumber = viewModel.getIsoWeekNumber(viewModel.selectedDate),
|
||
modifier = Modifier.onSizeChanged { size ->
|
||
monthHeaderHeightPx = size.height
|
||
}
|
||
)
|
||
WeekdayHeader(
|
||
modifier = Modifier.fillMaxWidth().onSizeChanged { size ->
|
||
weekdayHeaderHeightPx = size.height
|
||
}
|
||
)
|
||
if (viewModel.isCollapsed) {
|
||
WeekPager(
|
||
selectedDate = viewModel.selectedDate,
|
||
today = today,
|
||
onDateClick = { date -> viewModel.selectDate(date) },
|
||
onWeekChanged = { weekMonday ->
|
||
currentYear = weekMonday.year
|
||
@Suppress("DEPRECATION") // monthNumber 无替代 API,kotlinx-datetime 尚未提供新接口
|
||
currentMonth = weekMonday.monthNumber
|
||
}
|
||
)
|
||
} else {
|
||
CalendarPager(
|
||
selectedDate = viewModel.selectedDate,
|
||
today = today,
|
||
onDateClick = { date -> viewModel.selectDate(date) },
|
||
onMonthChanged = { year, month ->
|
||
currentYear = year
|
||
currentMonth = month
|
||
},
|
||
collapseProgress = viewModel.collapseProgress
|
||
)
|
||
}
|
||
}
|
||
if (cardHeightPx > 0) {
|
||
BottomCard(
|
||
viewModel = viewModel,
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.height(with(density) { cardHeightPx.toDp() })
|
||
.align(Alignment.BottomCenter)
|
||
)
|
||
}
|
||
}
|
||
} |