From 829f89eb7c480058692ecb285aecffb7b39c7b05 Mon Sep 17 00:00:00 2001 From: xfy Date: Mon, 1 Jun 2026 18:03:27 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=88=A0=E9=99=A4=20P0=20=E5=86=97?= =?UTF-8?q?=E4=BD=99=E4=BB=A3=E7=A0=81=EF=BC=88=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?combine/=E6=AD=BBStateFlow/=E7=BD=91=E6=A0=BC=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E7=AE=97=E6=B3=95/runBlocking=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除自定义 6 参数 combine + Quintuple,改用标准库嵌套 combine + Triple - 删除 yearViewProgress 死 StateFlow 及关联测试 - generateMonthDays/generateMiniMonthDays 复用 getMonthGridInfo - WeekPager 移除 runBlocking,交由 DayCell 自行异步计算 - 修复 AnimLog 在 JVM 单元测试中因 android.util.Log 不可用而崩溃 --- .../plus/rua/project/CalendarViewModel.kt | 50 ++----------------- .../plus/rua/project/ui/CalendarMonthPage.kt | 13 ++--- .../kotlin/plus/rua/project/ui/WeekPager.kt | 11 +--- .../plus/rua/project/ui/YearGridView.kt | 13 ++--- .../kotlin/plus/rua/project/util/AnimLog.kt | 13 ++++- .../rua/project/CalendarViewModelStateTest.kt | 7 --- 6 files changed, 21 insertions(+), 86 deletions(-) diff --git a/core/src/main/kotlin/plus/rua/project/CalendarViewModel.kt b/core/src/main/kotlin/plus/rua/project/CalendarViewModel.kt index ca91e4a..4190d6b 100644 --- a/core/src/main/kotlin/plus/rua/project/CalendarViewModel.kt +++ b/core/src/main/kotlin/plus/rua/project/CalendarViewModel.kt @@ -56,37 +56,6 @@ data class CalendarUiState( val showLegalHoliday: Boolean ) -/** - * 将六个 [Flow] 合并为一个 [Flow],使用 [transform] 处理最新值。 - * - * kotlinx-coroutines 1.11 仅内置到 5 参数的 [combine] 重载, - * 此扩展用于扁平化 6 个 StateFlow 的合并,避免多层嵌套产生的中间流。 - */ -private inline fun combine( - flow: Flow, - flow2: Flow, - flow3: Flow, - flow4: Flow, - flow5: Flow, - flow6: Flow, - crossinline transform: suspend (T1, T2, T3, T4, T5, T6) -> R -): Flow = combine( - combine(flow, flow2, flow3, flow4, flow5) { t1, t2, t3, t4, t5 -> - Quintuple(t1, t2, t3, t4, t5) - }, - flow6 -) { quintuple, t6 -> - transform(quintuple.first, quintuple.second, quintuple.third, quintuple.fourth, quintuple.fifth, t6) -} - -private data class Quintuple( - val first: T1, - val second: T2, - val third: T3, - val fourth: T4, - val fifth: T5 -) - /** * 日历状态管理,持有选中日期、折叠状态和 ISO 周号计算逻辑。 * @@ -141,9 +110,6 @@ class CalendarViewModel( private val _isYearView = MutableStateFlow(false) val isYearView: StateFlow = _isYearView.asStateFlow() - private val _yearViewProgress = MutableStateFlow(0f) - val yearViewProgress: StateFlow = _yearViewProgress.asStateFlow() - private val _yearViewYear = MutableStateFlow(today.year) val yearViewYear: StateFlow = _yearViewYear.asStateFlow() @@ -170,13 +136,9 @@ class CalendarViewModel( /** 聚合 UI 状态,减少 Compose 层分散订阅导致的重组。 */ val uiState: StateFlow = combine( - _selectedDate, - _isCollapsed, - _isYearView, - _yearViewYear, - _collapseProgress, - _showLegalHoliday - ) { selectedDate, isCollapsed, isYearView, yearViewYear, collapseProgress, showLegalHoliday -> + combine(_selectedDate, _isCollapsed, _isYearView) { s, c, y -> Triple(s, c, y) }, + combine(_yearViewYear, _collapseProgress, _showLegalHoliday) { y, p, h -> Triple(y, p, h) } + ) { (selectedDate, isCollapsed, isYearView), (yearViewYear, collapseProgress, showLegalHoliday) -> CalendarUiState( selectedDate = selectedDate, isCollapsed = isCollapsed, @@ -212,8 +174,6 @@ class CalendarViewModel( if (_isYearView.value) { logd(TAG_VM, "[toggleYearView] ===== START Year→Month t=$t0 =====") composeTraceBeginSection("YearView→MonthView") - _yearViewProgress.value = 0f - logd(TAG_VM, "[toggleYearView] yearViewProgress=0 dt=${(System.nanoTime() - t0) / 1_000_000}ms") _isYearView.value = false logd(TAG_VM, "[toggleYearView] isYearView=false dt=${(System.nanoTime() - t0) / 1_000_000}ms") composeTraceEndSection() @@ -223,8 +183,6 @@ class CalendarViewModel( composeTraceBeginSection("MonthView→YearView") _yearViewYear.value = _selectedDate.value.year logd(TAG_VM, "[toggleYearView] yearViewYear=${_yearViewYear.value} dt=${(System.nanoTime() - t0) / 1_000_000}ms") - _yearViewProgress.value = 1f - logd(TAG_VM, "[toggleYearView] yearViewProgress=1 dt=${(System.nanoTime() - t0) / 1_000_000}ms") _isYearView.value = true logd(TAG_VM, "[toggleYearView] isYearView=true dt=${(System.nanoTime() - t0) / 1_000_000}ms") composeTraceEndSection() @@ -253,8 +211,6 @@ class CalendarViewModel( logd(TAG_VM, "[selectMonthFromYearView] selectedDate set dt=${(System.nanoTime() - t0) / 1_000_000}ms") _isYearView.value = false logd(TAG_VM, "[selectMonthFromYearView] isYearView=false dt=${(System.nanoTime() - t0) / 1_000_000}ms") - _yearViewProgress.value = 0f - logd(TAG_VM, "[selectMonthFromYearView] yearViewProgress=0 dt=${(System.nanoTime() - t0) / 1_000_000}ms") composeTraceEndSection() logd(TAG_VM, "[selectMonthFromYearView] ===== END total=${(System.nanoTime() - t0) / 1_000_000}ms =====") } diff --git a/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthPage.kt b/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthPage.kt index 497093b..280692f 100644 --- a/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthPage.kt +++ b/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthPage.kt @@ -292,16 +292,9 @@ data class HolidayEdgeInfo( ) private fun generateMonthDays(year: Int, month: Int): List { - val firstOfMonth = LocalDate(year, Month(month), 1) - val offset = firstOfMonth.dayOfWeek.ordinal - val startDate = firstOfMonth.minus(DatePeriod(days = offset)) - val nextMonth = if (month == 12) LocalDate(year + 1, 1, 1) else LocalDate(year, Month(month + 1), 1) - val daysInMonth = nextMonth.minus(DatePeriod(days = 1)).day - val rows = ((offset + daysInMonth - 1) / 7) + 1 - val totalDays = rows * 7 - - return (0 until totalDays).map { i -> - val date = startDate.plus(DatePeriod(days = i)) + val info = getMonthGridInfo(year, month) + return (0 until info.totalDays).map { i -> + val date = info.startDate.plus(DatePeriod(days = i)) DayData( date = date, isCurrentMonth = date.month.number == month && date.year == year diff --git a/core/src/main/kotlin/plus/rua/project/ui/WeekPager.kt b/core/src/main/kotlin/plus/rua/project/ui/WeekPager.kt index b5f0f46..bcf5b3e 100644 --- a/core/src/main/kotlin/plus/rua/project/ui/WeekPager.kt +++ b/core/src/main/kotlin/plus/rua/project/ui/WeekPager.kt @@ -18,13 +18,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.unit.dp import kotlinx.coroutines.flow.drop -import kotlinx.coroutines.runBlocking import kotlinx.datetime.DatePeriod import kotlinx.datetime.LocalDate import kotlinx.datetime.daysUntil import kotlinx.datetime.plus -import plus.rua.project.DayCellInfo -import plus.rua.project.LunarCache import plus.rua.project.ShiftKind import plus.rua.project.composeTraceBeginSection import plus.rua.project.composeTraceEndSection @@ -99,11 +96,6 @@ fun WeekPager( ) { (0 until 7).forEach { dayOffset -> val date = weekMonday.plus(DatePeriod(days = dayOffset)) - val lunarData = remember(date) { - runBlocking { - LunarCache.default.getOrCompute(date) - } - } DayCell( date = date, isCurrentMonth = date.month == selectedDate.month @@ -115,8 +107,7 @@ fun WeekPager( cellIndex = dayOffset, onClick = { onDateClick(date) }, modifier = Modifier.weight(1f), - interactionSource = interactionSource, - lunarData = lunarData + interactionSource = interactionSource ) } } diff --git a/core/src/main/kotlin/plus/rua/project/ui/YearGridView.kt b/core/src/main/kotlin/plus/rua/project/ui/YearGridView.kt index 5082ff2..969d1cd 100644 --- a/core/src/main/kotlin/plus/rua/project/ui/YearGridView.kt +++ b/core/src/main/kotlin/plus/rua/project/ui/YearGridView.kt @@ -307,16 +307,9 @@ private data class MiniDayData( private fun generateMiniMonthDays(year: Int, month: Int): List { composeTraceBeginSection("generateMiniMonthDays:$year-$month") - val firstOfMonth = LocalDate(year, Month(month), 1) - val offset = firstOfMonth.dayOfWeek.ordinal - val startDate = firstOfMonth.minus(DatePeriod(days = offset)) - val nextMonth = if (month == 12) LocalDate(year + 1, 1, 1) else LocalDate(year, Month(month + 1), 1) - val daysInMonth = nextMonth.minus(DatePeriod(days = 1)).day - val rows = ((offset + daysInMonth - 1) / 7) + 1 - val totalDays = rows * 7 - - val result = (0 until totalDays).map { i -> - val date = startDate.plus(DatePeriod(days = i)) + val info = getMonthGridInfo(year, month) + val result = (0 until info.totalDays).map { i -> + val date = info.startDate.plus(DatePeriod(days = i)) MiniDayData( date = date, isCurrentMonth = date.month.number == month && date.year == year diff --git a/core/src/main/kotlin/plus/rua/project/util/AnimLog.kt b/core/src/main/kotlin/plus/rua/project/util/AnimLog.kt index 432be1a..813b44b 100644 --- a/core/src/main/kotlin/plus/rua/project/util/AnimLog.kt +++ b/core/src/main/kotlin/plus/rua/project/util/AnimLog.kt @@ -6,13 +6,22 @@ import plus.rua.project.shared.BuildConfig @Suppress("NOTHING_TO_INLINE") inline fun logd(tag: String, message: () -> String) { if (BuildConfig.DEBUG) { - Log.d(tag, message()) + try { + Log.d(tag, message()) + } catch (_: RuntimeException) { + // Android Log not available in JVM unit tests; fallback to stdout + println("D/$tag: ${message()}") + } } } @Suppress("NOTHING_TO_INLINE") inline fun logd(tag: String, message: String) { if (BuildConfig.DEBUG) { - Log.d(tag, message) + try { + Log.d(tag, message) + } catch (_: RuntimeException) { + println("D/$tag: $message") + } } } diff --git a/core/src/test/kotlin/plus/rua/project/CalendarViewModelStateTest.kt b/core/src/test/kotlin/plus/rua/project/CalendarViewModelStateTest.kt index 3d1aea5..1b56a45 100644 --- a/core/src/test/kotlin/plus/rua/project/CalendarViewModelStateTest.kt +++ b/core/src/test/kotlin/plus/rua/project/CalendarViewModelStateTest.kt @@ -52,11 +52,6 @@ class CalendarViewModelStateTest { assertFalse(createViewModel().isYearView.value) } - @Test - fun init_yearViewProgressDefaultsZero() { - assertEquals(0f, createViewModel().yearViewProgress.value, 0.001f) - } - @Test fun init_yearViewYearDefaultsToTodayYear() { assertEquals(2026, createViewModel().yearViewYear.value) @@ -375,7 +370,6 @@ class CalendarViewModelStateTest { assertFalse(vm.isYearView.value) vm.toggleYearView() assertTrue(vm.isYearView.value) - assertEquals(1f, vm.yearViewProgress.value, 0.001f) } @Test @@ -385,7 +379,6 @@ class CalendarViewModelStateTest { assertTrue(vm.isYearView.value) vm.toggleYearView() assertFalse(vm.isYearView.value) - assertEquals(0f, vm.yearViewProgress.value, 0.001f) } @Test