refactor: 清理无效 ProGuard 规则、调试日志,trace 解耦 VM
P0 正确性与工程卫生修复:
- 删除 core/proguard-rules.pro 中全部无效的 -keepclassmembers 规则
(LunarCache.getOrCompute 实为实例 suspend 方法,generateMonthDays 实为
private,签名均不匹配,属 placebo);同时移除 core/build.gradle.kts
release block 内重复的 consumerProguardFiles 声明
- 将 7 处 composeTrace 调用从 CalendarViewModel 移至 Compose 层
(MenuItem.onClick / onMonthClick / BottomCard 回调),VM 不再依赖
android.os.Trace,可在纯 JVM 环境测试无需兜底
- 删除 CalendarViewModel 与 4 个 UI 文件中约 30 处 logd 调用及其辅助
变量/ SideEffect/ DisposableEffect (AnimLog.kt 工具函数保留)
- 删除 CalendarViewModel.getIsoWeekNumber 不可达的 weekNumber < 1 递归分支
- 修正 MainActivity.kt setContent 块缩进错位
- 同步 README: sketch 渲染 GIF→动画 WebP,补提 :macrobenchmark 模块;
删除 AGENTS.md 顶部过时的「README 与实际不符」注释
验证: spotlessApply UP-TO-DATE, testDebugUnitTest 全过,
assembleDebug + assembleRelease (R8) 均成功
This commit is contained in:
parent
ef785a3ca7
commit
564e4e3960
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
纯 Android + Jetpack Compose 日历应用。功能:农历/节气/节日、个人班次排期(WORK/OFF 循环)、月/周/年三视图。
|
纯 Android + Jetpack Compose 日历应用。功能:农历/节气/节日、个人班次排期(WORK/OFF 循环)、月/周/年三视图。
|
||||||
|
|
||||||
> **README 与实际不符**:README 提及 "Kotlin Multiplatform / iOS",实际为纯 Android 项目。模块名为 `:core` 和 `:app`,无 `:shared` 或 `:androidApp`。
|
|
||||||
|
|
||||||
## 模块结构
|
## 模块结构
|
||||||
|
|
||||||
| 模块 | 类型 | 职责 |
|
| 模块 | 类型 | 职责 |
|
||||||
|
|||||||
@ -19,8 +19,8 @@
|
|||||||
- Kotlin 2.3 · Jetpack Compose · Material 3
|
- Kotlin 2.3 · Jetpack Compose · Material 3
|
||||||
- `kotlinx-datetime` 处理所有日期逻辑
|
- `kotlinx-datetime` 处理所有日期逻辑
|
||||||
- `tyme4kt` 提供农历、节气与传统节日
|
- `tyme4kt` 提供农历、节气与传统节日
|
||||||
- `sketch` 渲染 GIF 动画
|
- `sketch` 渲染动画 WebP
|
||||||
- 双模块:`:core`(UI + 逻辑) · `:app`(薄壳)
|
- 三模块:`:core`(UI + 逻辑) · `:app`(薄壳) · `:macrobenchmark`(Baseline Profile 生成)
|
||||||
|
|
||||||
## 构建
|
## 构建
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,6 @@ android {
|
|||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
isMinifyEnabled = false
|
isMinifyEnabled = false
|
||||||
consumerProguardFiles("proguard-rules.pro")
|
|
||||||
buildConfigField("boolean", "ENABLE_TRACE", "false")
|
buildConfigField("boolean", "ENABLE_TRACE", "false")
|
||||||
}
|
}
|
||||||
create("trace") {
|
create("trace") {
|
||||||
|
|||||||
28
core/proguard-rules.pro
vendored
28
core/proguard-rules.pro
vendored
@ -1,34 +1,6 @@
|
|||||||
# Baseline Profiles 保留规则:确保方法名不被 R8 混淆,使 profile 规则匹配正确
|
# Baseline Profiles 保留规则:确保方法名不被 R8 混淆,使 profile 规则匹配正确
|
||||||
-keepattributes SourceFile,LineNumberTable
|
-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
# ========== 启动热点路径保留 ==========
|
|
||||||
|
|
||||||
# DayCell — 启动最热点
|
|
||||||
-keepclassmembers class plus.rua.project.ui.DayCellKt {
|
|
||||||
public static void DayCell(...);
|
|
||||||
}
|
|
||||||
|
|
||||||
# LunarCache — 日期计算缓存
|
|
||||||
-keepclassmembers class plus.rua.project.LunarCache {
|
|
||||||
public static plus.rua.project.DayCellInfo getOrCompute(kotlinx.datetime.LocalDate);
|
|
||||||
public static java.lang.String formatLunarDate(kotlinx.datetime.LocalDate);
|
|
||||||
public static void precompute(...);
|
|
||||||
}
|
|
||||||
|
|
||||||
# DayCellInfo 数据类
|
|
||||||
-keepclassmembers class plus.rua.project.DayCellInfo {
|
|
||||||
public java.lang.String getAnnotationText();
|
|
||||||
public boolean getIsAnnotationHighlight();
|
|
||||||
public java.lang.String getHolidayBadge();
|
|
||||||
public java.lang.String getLunarMonthName();
|
|
||||||
}
|
|
||||||
|
|
||||||
# CalendarMonthPage
|
|
||||||
-keepclassmembers class plus.rua.project.ui.CalendarMonthPageKt {
|
|
||||||
public static void CalendarMonthPage(...);
|
|
||||||
public static java.util.List generateMonthDays(...);
|
|
||||||
}
|
|
||||||
|
|
||||||
# ========== 第三方库保留 ==========
|
# ========== 第三方库保留 ==========
|
||||||
-keep class kotlinx.datetime.** { *; }
|
-keep class kotlinx.datetime.** { *; }
|
||||||
-keep class cn.tyme.** { *; }
|
-keep class cn.tyme.** { *; }
|
||||||
|
|||||||
@ -21,11 +21,8 @@ import kotlinx.datetime.plus
|
|||||||
import kotlinx.datetime.todayIn
|
import kotlinx.datetime.todayIn
|
||||||
import plus.rua.project.ui.COLLAPSE_THRESHOLD
|
import plus.rua.project.ui.COLLAPSE_THRESHOLD
|
||||||
import plus.rua.project.ui.getMonthGridInfo
|
import plus.rua.project.ui.getMonthGridInfo
|
||||||
import plus.rua.project.util.logd
|
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
private const val TAG_VM = "CalendarExpand"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日历日期数据,用于网格单元格渲染。
|
* 日历日期数据,用于网格单元格渲染。
|
||||||
*
|
*
|
||||||
@ -170,23 +167,11 @@ class CalendarViewModel(
|
|||||||
* 当前视图被直接移除;动画只作用在目标视图的 scale/alpha 上。
|
* 当前视图被直接移除;动画只作用在目标视图的 scale/alpha 上。
|
||||||
*/
|
*/
|
||||||
fun toggleYearView() {
|
fun toggleYearView() {
|
||||||
val t0 = System.nanoTime()
|
|
||||||
if (_isYearView.value) {
|
if (_isYearView.value) {
|
||||||
logd(TAG_VM, "[toggleYearView] ===== START Year→Month t=$t0 =====")
|
|
||||||
composeTraceBeginSection("YearView→MonthView")
|
|
||||||
_isYearView.value = false
|
_isYearView.value = false
|
||||||
logd(TAG_VM, "[toggleYearView] isYearView=false dt=${(System.nanoTime() - t0) / 1_000_000}ms")
|
|
||||||
composeTraceEndSection()
|
|
||||||
logd(TAG_VM, "[toggleYearView] ===== END Year→Month total=${(System.nanoTime() - t0) / 1_000_000}ms =====")
|
|
||||||
} else {
|
} else {
|
||||||
logd(TAG_VM, "[toggleYearView] ===== START Month→Year t=$t0 =====")
|
|
||||||
composeTraceBeginSection("MonthView→YearView")
|
|
||||||
_yearViewYear.value = _selectedDate.value.year
|
_yearViewYear.value = _selectedDate.value.year
|
||||||
logd(TAG_VM, "[toggleYearView] yearViewYear=${_yearViewYear.value} dt=${(System.nanoTime() - t0) / 1_000_000}ms")
|
|
||||||
_isYearView.value = true
|
_isYearView.value = true
|
||||||
logd(TAG_VM, "[toggleYearView] isYearView=true dt=${(System.nanoTime() - t0) / 1_000_000}ms")
|
|
||||||
composeTraceEndSection()
|
|
||||||
logd(TAG_VM, "[toggleYearView] ===== END Month→Year total=${(System.nanoTime() - t0) / 1_000_000}ms =====")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,18 +186,10 @@ class CalendarViewModel(
|
|||||||
* 从年视图选择月份后返回月视图。
|
* 从年视图选择月份后返回月视图。
|
||||||
*/
|
*/
|
||||||
fun selectMonthFromYearView(month: Int) {
|
fun selectMonthFromYearView(month: Int) {
|
||||||
val t0 = System.nanoTime()
|
|
||||||
logd(TAG_VM, "[selectMonthFromYearView] ===== START month=$month t=$t0 =====")
|
|
||||||
composeTraceBeginSection("YearView:SelectMonth")
|
|
||||||
val date = if (_yearViewYear.value == today.year && today.month.number == month) today
|
val date = if (_yearViewYear.value == today.year && today.month.number == month) today
|
||||||
else LocalDate(_yearViewYear.value, Month(month), 1)
|
else LocalDate(_yearViewYear.value, Month(month), 1)
|
||||||
logd(TAG_VM, "[selectMonthFromYearView] targetDate=$date dt=${(System.nanoTime() - t0) / 1_000_000}ms")
|
|
||||||
_selectedDate.value = date
|
_selectedDate.value = date
|
||||||
logd(TAG_VM, "[selectMonthFromYearView] selectedDate set dt=${(System.nanoTime() - t0) / 1_000_000}ms")
|
|
||||||
_isYearView.value = false
|
_isYearView.value = false
|
||||||
logd(TAG_VM, "[selectMonthFromYearView] isYearView=false dt=${(System.nanoTime() - t0) / 1_000_000}ms")
|
|
||||||
composeTraceEndSection()
|
|
||||||
logd(TAG_VM, "[selectMonthFromYearView] ===== END total=${(System.nanoTime() - t0) / 1_000_000}ms =====")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun incrementYear() {
|
fun incrementYear() {
|
||||||
@ -233,9 +210,7 @@ class CalendarViewModel(
|
|||||||
* @param delta 拖拽增量,已归一化到 [0,1] 区间
|
* @param delta 拖拽增量,已归一化到 [0,1] 区间
|
||||||
*/
|
*/
|
||||||
fun onDrag(delta: Float) {
|
fun onDrag(delta: Float) {
|
||||||
composeTraceBeginSection("VM:collapseProgress:onDrag")
|
|
||||||
_collapseProgress.value = (_collapseProgress.value + delta).coerceIn(0f, 1f)
|
_collapseProgress.value = (_collapseProgress.value + delta).coerceIn(0f, 1f)
|
||||||
composeTraceEndSection()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,7 +219,6 @@ class CalendarViewModel(
|
|||||||
* 拖拽超过阈值时自动折叠到周视图,否则回弹到月视图。
|
* 拖拽超过阈值时自动折叠到周视图,否则回弹到月视图。
|
||||||
*/
|
*/
|
||||||
fun onDragEnd() {
|
fun onDragEnd() {
|
||||||
composeTraceBeginSection("VM:collapseProgress:onDragEnd")
|
|
||||||
val progress = _collapseProgress.value
|
val progress = _collapseProgress.value
|
||||||
if (progress > COLLAPSE_THRESHOLD) {
|
if (progress > COLLAPSE_THRESHOLD) {
|
||||||
_isCollapsed.value = true
|
_isCollapsed.value = true
|
||||||
@ -253,7 +227,6 @@ class CalendarViewModel(
|
|||||||
_isCollapsed.value = false
|
_isCollapsed.value = false
|
||||||
_collapseProgress.value = 0f
|
_collapseProgress.value = 0f
|
||||||
}
|
}
|
||||||
composeTraceEndSection()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -262,11 +235,7 @@ class CalendarViewModel(
|
|||||||
* @param delta 拖拽增量,已归一化到 [0,1] 区间
|
* @param delta 拖拽增量,已归一化到 [0,1] 区间
|
||||||
*/
|
*/
|
||||||
fun onExpandDrag(delta: Float) {
|
fun onExpandDrag(delta: Float) {
|
||||||
composeTraceBeginSection("VM:collapseProgress:onExpandDrag")
|
|
||||||
val old = _collapseProgress.value
|
|
||||||
_collapseProgress.value = (_collapseProgress.value + delta).coerceIn(0f, 1f)
|
_collapseProgress.value = (_collapseProgress.value + delta).coerceIn(0f, 1f)
|
||||||
logd(TAG_VM, "onExpandDrag: delta=$delta old=$old new=${_collapseProgress.value}")
|
|
||||||
composeTraceEndSection()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -275,19 +244,14 @@ class CalendarViewModel(
|
|||||||
* 下拉超过阈值时自动展开到月视图,否则回弹到周视图。
|
* 下拉超过阈值时自动展开到月视图,否则回弹到周视图。
|
||||||
*/
|
*/
|
||||||
fun onExpandDragEnd() {
|
fun onExpandDragEnd() {
|
||||||
composeTraceBeginSection("VM:collapseProgress:onExpandDragEnd")
|
|
||||||
val progress = _collapseProgress.value
|
val progress = _collapseProgress.value
|
||||||
val result = if (progress < (1 - COLLAPSE_THRESHOLD)) {
|
if (progress < (1 - COLLAPSE_THRESHOLD)) {
|
||||||
_isCollapsed.value = false
|
_isCollapsed.value = false
|
||||||
_collapseProgress.value = 0f
|
_collapseProgress.value = 0f
|
||||||
"EXPANDED"
|
|
||||||
} else {
|
} else {
|
||||||
_isCollapsed.value = true
|
_isCollapsed.value = true
|
||||||
_collapseProgress.value = 1f
|
_collapseProgress.value = 1f
|
||||||
"COLLAPSED (bounce back)"
|
|
||||||
}
|
}
|
||||||
logd(TAG_VM, "onExpandDragEnd: progress=$progress threshold=${1 - COLLAPSE_THRESHOLD} result=$result")
|
|
||||||
composeTraceEndSection()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -302,9 +266,7 @@ class CalendarViewModel(
|
|||||||
val week1Monday = jan4.minus(DatePeriod(days = jan4DayOfWeek))
|
val week1Monday = jan4.minus(DatePeriod(days = jan4DayOfWeek))
|
||||||
val diff = week1Monday.daysUntil(date)
|
val diff = week1Monday.daysUntil(date)
|
||||||
val weekNumber = diff / 7 + 1
|
val weekNumber = diff / 7 + 1
|
||||||
return if (weekNumber < 1) {
|
return if (weekNumber > getIsoWeeksInYear(date.year)) {
|
||||||
getIsoWeekNumber(LocalDate(date.year - 1, 12, 28))
|
|
||||||
} else if (weekNumber > getIsoWeeksInYear(date.year)) {
|
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
weekNumber
|
weekNumber
|
||||||
@ -325,14 +287,16 @@ class CalendarViewModel(
|
|||||||
*
|
*
|
||||||
* 网格行数按实际需要计算(4/5/6行),每行7格,首行从该月1号所在周的周一开始。
|
* 网格行数按实际需要计算(4/5/6行),每行7格,首行从该月1号所在周的周一开始。
|
||||||
*
|
*
|
||||||
|
* 注意:此方法当前无 UI 调用方,UI 层使用 [CalendarMonthPage] 内的 generateMonthDays;
|
||||||
|
* 保留此方法供测试覆盖和未来复用(含 isToday/isSelected 字段语义)。
|
||||||
|
*
|
||||||
* @param year 年份
|
* @param year 年份
|
||||||
* @param month 月份(1-12)
|
* @param month 月份(1-12)
|
||||||
* @return 日历网格列表,每项包含日期、是否当月、是否今天、是否选中
|
* @return 日历网格列表,每项包含日期、是否当月、是否今天、是否选中
|
||||||
*/
|
*/
|
||||||
fun getMonthDays(year: Int, month: Int): List<CalendarDay> {
|
fun getMonthDays(year: Int, month: Int): List<CalendarDay> {
|
||||||
composeTraceBeginSection("getMonthDays:$year-$month")
|
|
||||||
val info = getMonthGridInfo(year, month)
|
val info = getMonthGridInfo(year, month)
|
||||||
val result = (0 until info.totalDays).map { i ->
|
return (0 until info.totalDays).map { i ->
|
||||||
val date = info.startDate.plus(DatePeriod(days = i))
|
val date = info.startDate.plus(DatePeriod(days = i))
|
||||||
CalendarDay(
|
CalendarDay(
|
||||||
date = date,
|
date = date,
|
||||||
@ -341,7 +305,5 @@ class CalendarViewModel(
|
|||||||
isSelected = date == selectedDate.value
|
isSelected = date == selectedDate.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composeTraceEndSection()
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,6 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import plus.rua.project.composeTraceBeginSection
|
import plus.rua.project.composeTraceBeginSection
|
||||||
import plus.rua.project.composeTraceEndSection
|
import plus.rua.project.composeTraceEndSection
|
||||||
import plus.rua.project.util.logd
|
|
||||||
import kotlinx.datetime.DatePeriod
|
import kotlinx.datetime.DatePeriod
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.datetime.Month
|
import kotlinx.datetime.Month
|
||||||
@ -34,8 +33,6 @@ import plus.rua.project.DayCellInfo
|
|||||||
import plus.rua.project.LunarCache
|
import plus.rua.project.LunarCache
|
||||||
import plus.rua.project.ShiftKind
|
import plus.rua.project.ShiftKind
|
||||||
|
|
||||||
private const val TAG_CMP = "CalendarExpandAnim"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 月度日历网格页面,支持两阶段折叠动画。
|
* 月度日历网格页面,支持两阶段折叠动画。
|
||||||
@ -110,16 +107,6 @@ fun CalendarMonthPage(
|
|||||||
weeks.indexOfFirst { week -> week.any { it.date == selectedDate } }
|
weeks.indexOfFirst { week -> week.any { it.date == selectedDate } }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全局动画参数日志(每次重组)
|
|
||||||
val pageFrameNs = System.nanoTime()
|
|
||||||
val totalCells = weeks.size * 7
|
|
||||||
logd(TAG_CMP) {
|
|
||||||
"Page[$year-$month]: anchorIndex=$anchorIndex weeksSize=${weeks.size} totalCells=$totalCells " +
|
|
||||||
"phase1End=${if (anchorIndex > 0 && weeks.size > 1) anchorIndex.toFloat() / (weeks.size - 1) else 0f} " +
|
|
||||||
"effectiveWeeks=$effectiveWeeks rowHeightPx=$rowHeightPx " +
|
|
||||||
"collapseProgress=$collapseProgress lunarMapSize=${lunarDataMap.size} frameNs=$pageFrameNs"
|
|
||||||
}
|
|
||||||
|
|
||||||
val totalHeightDp = if (rowHeightPx > 0) {
|
val totalHeightDp = if (rowHeightPx > 0) {
|
||||||
val h = rowHeightPx.toFloat()
|
val h = rowHeightPx.toFloat()
|
||||||
val totalPx = h * (1 + (effectiveWeeks - 1) * (1f - collapseProgress))
|
val totalPx = h * (1 + (effectiveWeeks - 1) * (1f - collapseProgress))
|
||||||
@ -216,17 +203,6 @@ private fun WeekRow(
|
|||||||
else -> 1f
|
else -> 1f
|
||||||
}
|
}
|
||||||
|
|
||||||
val frameTimeNs = System.nanoTime()
|
|
||||||
logd(TAG_CMP) {
|
|
||||||
"WeekRow[$weekIndex]: " +
|
|
||||||
"isAnchor=$isAnchor isAbove=$isAbove isBelow=$isBelow " +
|
|
||||||
"phase1=$phase1 phase2=$phase2 phase1End=$phase1End " +
|
|
||||||
"belowRowsHeight=$belowRowsHeight rowHeightPx=$rowHeightPx " +
|
|
||||||
"yOffsetPx=$yOffsetPx rowAlpha=$rowAlpha " +
|
|
||||||
"collapseProgress=$collapseProgress " +
|
|
||||||
"frameNs=$frameTimeNs"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rowAlpha > 0.01f) {
|
if (rowAlpha > 0.01f) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@ -49,7 +49,6 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.SideEffect
|
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
@ -85,7 +84,6 @@ import plus.rua.project.composeTraceEndSection
|
|||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import plus.rua.project.util.logd
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日历主界面,包含月/周视图切换、折叠动画和年视图转场。
|
* 日历主界面,包含月/周视图切换、折叠动画和年视图转场。
|
||||||
@ -120,14 +118,6 @@ fun CalendarMonthView(
|
|||||||
animationSpec = spring(stiffness = Spring.StiffnessMedium),
|
animationSpec = spring(stiffness = Spring.StiffnessMedium),
|
||||||
label = "collapseProgress"
|
label = "collapseProgress"
|
||||||
)
|
)
|
||||||
var lastLoggedCollapse by remember { mutableStateOf(-1f) }
|
|
||||||
SideEffect {
|
|
||||||
if (kotlin.math.abs(lastLoggedCollapse - collapseProgress) > 0.001f) {
|
|
||||||
lastLoggedCollapse = collapseProgress
|
|
||||||
logd("AnimLog", "[Collapse] target=$collapseProgress animated=$animatedCollapseProgress isCollapsed=$isCollapsed")
|
|
||||||
}
|
|
||||||
logd("AnimLog", "[MonthView] isYearView=$isYearView isCollapsed=$isCollapsed collapseProgress=$collapseProgress animated=$animatedCollapseProgress selectedDate=$selectedDate yearViewYear=$yearViewYear")
|
|
||||||
}
|
|
||||||
|
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
@ -182,13 +172,6 @@ fun CalendarMonthView(
|
|||||||
screenWidthPx = size.width
|
screenWidthPx = size.width
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
var lastLoggedTargetState by remember { mutableStateOf(false) }
|
|
||||||
SideEffect {
|
|
||||||
if (lastLoggedTargetState != isYearView) {
|
|
||||||
lastLoggedTargetState = isYearView
|
|
||||||
logd("AnimLog", "[AnimatedContent] ★ targetState CHANGE isYearView=$isYearView t=${System.nanoTime()}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
targetState = isYearView,
|
targetState = isYearView,
|
||||||
label = "month_year_transition",
|
label = "month_year_transition",
|
||||||
@ -206,13 +189,6 @@ fun CalendarMonthView(
|
|||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) { yearViewActive ->
|
) { yearViewActive ->
|
||||||
if (!yearViewActive) {
|
if (!yearViewActive) {
|
||||||
androidx.compose.runtime.DisposableEffect(Unit) {
|
|
||||||
val t = System.nanoTime()
|
|
||||||
logd("AnimLog", "[MonthView] ★★★ ENTER composable t=$t")
|
|
||||||
onDispose {
|
|
||||||
logd("AnimLog", "[MonthView] ★★★ LEAVE composable alive=${(System.nanoTime() - t) / 1_000_000}ms")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
composeTraceBeginSection("MonthView:Compose")
|
composeTraceBeginSection("MonthView:Compose")
|
||||||
composeTraceBeginSection("CalendarPagerArea")
|
composeTraceBeginSection("CalendarPagerArea")
|
||||||
val layoutReady = rowHeightPx > 0
|
val layoutReady = rowHeightPx > 0
|
||||||
@ -285,13 +261,6 @@ fun CalendarMonthView(
|
|||||||
composeTraceEndSection()
|
composeTraceEndSection()
|
||||||
composeTraceEndSection()
|
composeTraceEndSection()
|
||||||
} else {
|
} else {
|
||||||
androidx.compose.runtime.DisposableEffect(Unit) {
|
|
||||||
val t = System.nanoTime()
|
|
||||||
logd("AnimLog", "[YearView] ★★★ ENTER composable t=$t")
|
|
||||||
onDispose {
|
|
||||||
logd("AnimLog", "[YearView] ★★★ LEAVE composable alive=${(System.nanoTime() - t) / 1_000_000}ms")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
composeTraceBeginSection("YearView:Compose")
|
composeTraceBeginSection("YearView:Compose")
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -310,13 +279,6 @@ fun CalendarMonthView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
var lastLoggedYearPage by remember { mutableIntStateOf(-1) }
|
|
||||||
SideEffect {
|
|
||||||
if (lastLoggedYearPage != yearPagerState.currentPage) {
|
|
||||||
lastLoggedYearPage = yearPagerState.currentPage
|
|
||||||
logd("AnimLog", "[YearPager] page=${yearPagerState.currentPage} settledPage=${yearPagerState.settledPage} offset=${yearPagerState.currentPageOffsetFraction}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
state = yearPagerState,
|
state = yearPagerState,
|
||||||
beyondViewportPageCount = 0,
|
beyondViewportPageCount = 0,
|
||||||
@ -329,26 +291,21 @@ fun CalendarMonthView(
|
|||||||
val pageYear = remember(page, yearViewYear, yearPagerState.settledPage) {
|
val pageYear = remember(page, yearViewYear, yearPagerState.settledPage) {
|
||||||
yearViewYear + (page - yearPagerState.settledPage)
|
yearViewYear + (page - yearPagerState.settledPage)
|
||||||
}
|
}
|
||||||
val isCurrentPage = page == yearPagerState.currentPage
|
|
||||||
if (isCurrentPage) {
|
|
||||||
logd("AnimLog") { "[YearPager] Compose page=$page year=$pageYear" }
|
|
||||||
}
|
|
||||||
YearGridView(
|
YearGridView(
|
||||||
year = pageYear,
|
year = pageYear,
|
||||||
selectedMonth = if (pageYear == currentYear) currentMonth else 0,
|
selectedMonth = if (pageYear == currentYear) currentMonth else 0,
|
||||||
today = today,
|
today = today,
|
||||||
onMonthClick = { month ->
|
onMonthClick = { month ->
|
||||||
val clickT = System.nanoTime()
|
composeTraceBeginSection("YearView:SelectMonth")
|
||||||
logd("AnimLog") { "[YearGridView] MonthClick month=$month year=$pageYear t=$clickT" }
|
|
||||||
viewModel.selectMonthFromYearView(month)
|
viewModel.selectMonthFromYearView(month)
|
||||||
val targetPage = yearMonthToPage(
|
val targetPage = yearMonthToPage(
|
||||||
yearViewYear, month,
|
yearViewYear, month,
|
||||||
today.year, today.month.number
|
today.year, today.month.number
|
||||||
)
|
)
|
||||||
if (targetPage != pagerState.currentPage) {
|
if (targetPage != pagerState.currentPage) {
|
||||||
logd("AnimLog") { "[YearPager] scrollToPage target=$targetPage" }
|
|
||||||
coroutineScope.launch { pagerState.scrollToPage(targetPage) }
|
coroutineScope.launch { pagerState.scrollToPage(targetPage) }
|
||||||
}
|
}
|
||||||
|
composeTraceEndSection()
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
)
|
)
|
||||||
@ -426,7 +383,11 @@ fun CalendarMonthView(
|
|||||||
selected = !isYearView,
|
selected = !isYearView,
|
||||||
onClick = {
|
onClick = {
|
||||||
isMenuExpanded = false
|
isMenuExpanded = false
|
||||||
if (isYearView) viewModel.toggleYearView()
|
if (isYearView) {
|
||||||
|
composeTraceBeginSection("YearView→MonthView")
|
||||||
|
viewModel.toggleYearView()
|
||||||
|
composeTraceEndSection()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
MenuItem(
|
MenuItem(
|
||||||
@ -434,7 +395,11 @@ fun CalendarMonthView(
|
|||||||
selected = isYearView,
|
selected = isYearView,
|
||||||
onClick = {
|
onClick = {
|
||||||
isMenuExpanded = false
|
isMenuExpanded = false
|
||||||
if (!isYearView) viewModel.toggleYearView()
|
if (!isYearView) {
|
||||||
|
composeTraceBeginSection("MonthView→YearView")
|
||||||
|
viewModel.toggleYearView()
|
||||||
|
composeTraceEndSection()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
HorizontalDivider(
|
HorizontalDivider(
|
||||||
@ -492,13 +457,12 @@ private fun CalendarPagerArea(
|
|||||||
pagerState: PagerState,
|
pagerState: PagerState,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val t0 = System.nanoTime()
|
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
|
|
||||||
val interpolatedWeeks by remember {
|
val interpolatedWeeks by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
val fraction = pagerState.currentPageOffsetFraction
|
val fraction = pagerState.currentPageOffsetFraction
|
||||||
val result = if (abs(fraction) > OFFSET_FRACTION_THRESHOLD) {
|
if (abs(fraction) > OFFSET_FRACTION_THRESHOLD) {
|
||||||
val cp = pagerState.currentPage
|
val cp = pagerState.currentPage
|
||||||
val baseWeeks = calculateWeeksCountForPage(cp, today)
|
val baseWeeks = calculateWeeksCountForPage(cp, today)
|
||||||
val targetPage = cp + if (fraction > 0) 1 else -1
|
val targetPage = cp + if (fraction > 0) 1 else -1
|
||||||
@ -507,8 +471,6 @@ private fun CalendarPagerArea(
|
|||||||
} else {
|
} else {
|
||||||
calculateWeeksCountForPage(pagerState.currentPage, today).toFloat()
|
calculateWeeksCountForPage(pagerState.currentPage, today).toFloat()
|
||||||
}
|
}
|
||||||
logd("AnimLog", "[PagerArea] interpolatedWeeks=$result fraction=$fraction page=${pagerState.currentPage}")
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,8 +494,6 @@ private fun CalendarPagerArea(
|
|||||||
}
|
}
|
||||||
} else 0
|
} else 0
|
||||||
|
|
||||||
logd("AnimLog", "[PagerArea] gridHeightPx=$gridHeightPx effectiveRowHeightPx=$effectiveRowHeightPx effectiveWeeks=$effectiveWeeks collapseProgress=$collapseProgress screenW=$screenWidthPx rowH=$rowHeightPx dt=${(System.nanoTime() - t0) / 1_000_000}ms")
|
|
||||||
|
|
||||||
val pagerModifier = if (rowHeightPx > 0 && gridHeightPx > 0) {
|
val pagerModifier = if (rowHeightPx > 0 && gridHeightPx > 0) {
|
||||||
Modifier
|
Modifier
|
||||||
.height(with(density) { gridHeightPx.toDp() })
|
.height(with(density) { gridHeightPx.toDp() })
|
||||||
@ -597,10 +557,26 @@ private fun BottomCardArea(
|
|||||||
selectedDate = uiState.selectedDate,
|
selectedDate = uiState.selectedDate,
|
||||||
today = today,
|
today = today,
|
||||||
shiftKind = shiftKind,
|
shiftKind = shiftKind,
|
||||||
onDrag = { delta -> viewModel.onDrag(delta) },
|
onDrag = { delta ->
|
||||||
onDragEnd = { viewModel.onDragEnd() },
|
composeTraceBeginSection("VM:collapseProgress:onDrag")
|
||||||
onExpandDrag = { delta -> viewModel.onExpandDrag(delta) },
|
viewModel.onDrag(delta)
|
||||||
onExpandDragEnd = { viewModel.onExpandDragEnd() },
|
composeTraceEndSection()
|
||||||
|
},
|
||||||
|
onDragEnd = {
|
||||||
|
composeTraceBeginSection("VM:collapseProgress:onDragEnd")
|
||||||
|
viewModel.onDragEnd()
|
||||||
|
composeTraceEndSection()
|
||||||
|
},
|
||||||
|
onExpandDrag = { delta ->
|
||||||
|
composeTraceBeginSection("VM:collapseProgress:onExpandDrag")
|
||||||
|
viewModel.onExpandDrag(delta)
|
||||||
|
composeTraceEndSection()
|
||||||
|
},
|
||||||
|
onExpandDragEnd = {
|
||||||
|
composeTraceBeginSection("VM:collapseProgress:onExpandDragEnd")
|
||||||
|
viewModel.onExpandDragEnd()
|
||||||
|
composeTraceEndSection()
|
||||||
|
},
|
||||||
dragRangePx = dragRangePx,
|
dragRangePx = dragRangePx,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.offset(y = with(density) { (slideProgress * 300).dp })
|
.offset(y = with(density) { (slideProgress * 300).dp })
|
||||||
|
|||||||
@ -5,19 +5,15 @@ import androidx.compose.foundation.pager.PagerDefaults
|
|||||||
import androidx.compose.foundation.pager.PagerState
|
import androidx.compose.foundation.pager.PagerState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.SideEffect
|
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import plus.rua.project.composeTraceBeginSection
|
import plus.rua.project.composeTraceBeginSection
|
||||||
import plus.rua.project.composeTraceEndSection
|
import plus.rua.project.composeTraceEndSection
|
||||||
import plus.rua.project.util.logd
|
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -80,14 +76,6 @@ fun CalendarPager(
|
|||||||
derivedStateOf { pagerState.currentPage }
|
derivedStateOf { pagerState.currentPage }
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastLoggedPage by remember { mutableIntStateOf(-1) }
|
|
||||||
SideEffect {
|
|
||||||
if (lastLoggedPage != pagerState.currentPage) {
|
|
||||||
lastLoggedPage = pagerState.currentPage
|
|
||||||
logd("AnimLog", "[CalendarPager] page=${pagerState.currentPage} settledPage=${pagerState.settledPage} offsetFraction=${pagerState.currentPageOffsetFraction}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
beyondViewportPageCount = 0,
|
beyondViewportPageCount = 0,
|
||||||
@ -102,9 +90,6 @@ fun CalendarPager(
|
|||||||
pageOffset
|
pageOffset
|
||||||
}
|
}
|
||||||
val (year, month) = pageToYearMonth(page, initialYear, initialMonth)
|
val (year, month) = pageToYearMonth(page, initialYear, initialMonth)
|
||||||
if (isCurrentPage) {
|
|
||||||
logd("AnimLog", "[CalendarPager] Compose page=$page ($year-$month) alpha=$alpha pageOffset=$pageOffset")
|
|
||||||
}
|
|
||||||
composeTraceBeginSection("CalendarPager:Page:$year-$month")
|
composeTraceBeginSection("CalendarPager:Page:$year-$month")
|
||||||
CalendarMonthPage(
|
CalendarMonthPage(
|
||||||
year = year,
|
year = year,
|
||||||
@ -112,7 +97,6 @@ fun CalendarPager(
|
|||||||
selectedDate = selectedDate,
|
selectedDate = selectedDate,
|
||||||
today = today,
|
today = today,
|
||||||
onDateClick = { date ->
|
onDateClick = { date ->
|
||||||
val clickT = System.nanoTime()
|
|
||||||
onDateClick(date)
|
onDateClick(date)
|
||||||
// 点击跨月日期时,滚动到该月对应的页
|
// 点击跨月日期时,滚动到该月对应的页
|
||||||
val clickedYear = date.year
|
val clickedYear = date.year
|
||||||
@ -121,7 +105,6 @@ fun CalendarPager(
|
|||||||
val targetPage =
|
val targetPage =
|
||||||
yearMonthToPage(clickedYear, clickedMonth, initialYear, initialMonth)
|
yearMonthToPage(clickedYear, clickedMonth, initialYear, initialMonth)
|
||||||
if (targetPage != pagerState.currentPage) {
|
if (targetPage != pagerState.currentPage) {
|
||||||
logd("AnimLog", "[CalendarPager] Cross-month click date=$date targetPage=$targetPage t=$clickT")
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
pagerState.animateScrollToPage(targetPage)
|
pagerState.animateScrollToPage(targetPage)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,11 +23,8 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.produceState
|
import androidx.compose.runtime.produceState
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import plus.rua.project.util.logd
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@ -82,14 +79,6 @@ fun YearGridView(
|
|||||||
onMonthClick: (Int) -> Unit,
|
onMonthClick: (Int) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val enterT = System.nanoTime()
|
|
||||||
logd("AnimLog", "[YearGridView] ★★★ ENTER year=$year selectedMonth=$selectedMonth t=$enterT")
|
|
||||||
androidx.compose.runtime.DisposableEffect(year) {
|
|
||||||
logd("AnimLog", "[YearGridView] DisposableEffect attached year=$year")
|
|
||||||
onDispose {
|
|
||||||
logd("AnimLog", "[YearGridView] ★★★ LEAVE year=$year alive=${(System.nanoTime() - enterT) / 1_000_000}ms")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
composeTraceBeginSection("YearGridView:$year")
|
composeTraceBeginSection("YearGridView:$year")
|
||||||
|
|
||||||
// P0-F: 主题色在 YearGridView 级别一次性读取并缓存
|
// P0-F: 主题色在 YearGridView 级别一次性读取并缓存
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user