97 Commits

Author SHA1 Message Date
xfy
825eb526de feat(about): 将关于页面背景图优化为 WebP 2026-06-15 15:40:34 +08:00
xfy
9a09be56ef feat(about): 将 xiaogou_bg1.jpg 设为关于页面背景 2026-06-15 15:04:58 +08:00
xfy
6e1c2a39ae docs: 校正 assets AGENTS.md,消除 GIF/镜像等错误描述
问题
- 4 份 assets/AGENTS.md 与 Task 1-5 后的实际状态全部相反:
  - 声称 core/app "内容同步/镜像" → 实际职责不同 (core 管 UI/WebP, app 管启动器)
  - 声称文件是 .gif → 实际是 .webp 动画
  - 声称由 AnimatedGif 加载 → 实际是 AnimatedWebp
  - app/assets/gifs/ 只剩过时 AGENTS.md (PNG 已被 Task 1 删)

改动
- core/assets/AGENTS.md: 移除"与 app 镜像"错误说法, 说明职责划分, 列 app_icon.webp
- core/assets/animations/AGENTS.md: GIF→WebP 正名, 说明构建期扫描机制 + 测试守卫,
  保留"历史命名曾为 gifs/"历史说明
- app/assets/AGENTS.md: 反映清理后为空, 警告勿再放图标源 PNG
- 删除 app/assets/gifs/ 过时空目录 (仅剩 1 个过时 AGENTS.md)

验证
- grep 全 assets 无真正错误描述 (剩余命中均为有意的纠正/历史说明)
- ./gradlew :app:assembleDebug → BUILD SUCCESSFUL
2026-06-15 14:08:18 +08:00
xfy
58a97d1725 refactor: WebP 文件列表改由构建期 BuildConfig 注入,消除 (1..152) 硬编码
问题
- AnimatedWebp.kt 原写死 WEBP_FILES = (1..152).map{...}, 与磁盘文件耦合却无校验
- 加 153.webp → 永远不会被随机到; 删某个 → random() 偶发命中不存在的资源
- 这是静默失败, 运行期无报错, 难排查

改动
- core/build.gradle.kts defaultConfig: 构建期扫描 assets/animations/ 生成
  buildConfigField("String[]", "WEBP_FILES", "new String[]{...}")
  含 require(webpFiles.isNotEmpty()) 防空目录构建
- AnimatedWebp.kt: WEBP_FILES 从 private 硬编码改为 internal val = BuildConfig.WEBP_FILES.toList()
  (internal 让同模块测试可访问)
- 新增 AnimatedWebpFilesTest: 2 个守卫测试
  1. webpFilesMatchDirectoryContents: WEBP_FILES 必须与 assets/animations/ 一一对应
  2. webpFilesUseZeroPaddedThreeDigitNames: 锁定 NNN.webp 命名约定

TDD 流程
- 先写测试 → 编译失败(WEBP_FILES 是 private) → 红灯成立
- 改实现 → 测试 PASS → 绿灯
- 突变验证: 临时改 WEBP_FILES = (1..150) 漏掉 151/152
  → webpFilesMatchDirectoryContents 立即 FAIL, 守卫有效
- 恢复后全量 146 个测试 0 失败

设计说明
- 当前实现里 WEBP_FILES 与目录都来自同一次构建期扫描, 二者天然一致
- 测试的核心价值是锁定「两者一致」不变量, 防止有人回退成硬编码
  (突变验证已证明: 回退后测试立即失败)
- BuildConfig 生成结果验证: String[] 含 152 个元素 001~152.webp

验证
- ./gradlew :core:testDebugUnitTest → 146 tests, 0 failures, 0 errors
- ./gradlew :app:assembleDebug → BUILD SUCCESSFUL
- BuildConfig.java: public static final String[] WEBP_FILES = new String[]{"001.webp",...,"152.webp"}
2026-06-15 14:02:21 +08:00
xfy
87d51b253a refactor: gifs/→animations/、AnimatedGif→AnimatedWebp, 名实相符
问题
- 目录名 gifs/ 与类名 AnimatedGif 长期描述 GIF, 但实际格式是 WebP 动画
  (依赖 sketch-animated-webp, 文件后缀也是 .webp)
- 名实不符持续误导阅读者, 也让 GIF 相关搜索返回错误结果

改动(仅重命名, 不改运行时行为)
- core/src/main/assets/gifs/ → animations/ (git mv, 152 个 webp + AGENTS.md)
- core/.../ui/AnimatedGif.kt → AnimatedWebp.kt, 函数 AnimatedGif() → AnimatedWebp()
- Platform.kt:13 getWebpUri 路径 gifs/ → animations/
- BottomCard.kt:175 调用点 AnimatedGif( → AnimatedWebp(
- CalendarMonthView.kt:583 注释同步
- scripts/profile.sh:228,1103 两处场景描述/trace 文档同步
- baseline-prof.txt: 19 处 AnimatedGifKt → AnimatedWebpKt (R8 类名)
  注: lambda hash 可能需下次 updateBaselineProfile 重新生成校准, 当前不影响构建

验证
- grep 全仓库 (排除 build/AGENTS.md/baseline-prof) 无 AnimatedGif/ 残留
- ./gradlew :app:assembleDebug → BUILD SUCCESSFUL

备注
- WEBP_FILES = (1..152) 硬编码暂保留, 下一个提交替换为构建期 BuildConfig
- AGENTS.md 文档校正留待 Task 6 统一处理
2026-06-15 13:57:09 +08:00
xfy
7d6ed1428e refactor: 日期检查器 Canvas 手绘图标替换为 Material Icons
CalendarIcon/ArrowRightIcon 改用 Icons.Filled.DateRange 和
Icons.AutoMirrored.Filled.ArrowForward,统一图标风格并支持
RTL 自动镜像;删除冗余 Canvas 绘制代码及关联 import(Offset/
StrokeCap/Stroke)。
2026-06-15 13:26:34 +08:00
xfy
7628f299c2 fix: 加载保质期列表时钳制旧数据,清理历史持久化的负数天数 2026-06-15 11:40:26 +08:00
xfy
1438b405a9 feat: 日期检查器 Row 日期选择器禁选早于生产日期 2026-06-15 11:30:43 +08:00
xfy
2085c22987 fix: 日期检查器写入保质期天数前钳制为非负,防止负数落库 2026-06-15 11:27:35 +08:00
xfy
55d50c3e1d feat: 添加 clampExpiryDays 纯函数钳制保质期天数为非负 2026-06-15 11:24:38 +08:00
xfy
0868522741 feat: 为版本号添加可点击效果 2026-06-08 13:43:29 +08:00
xfy
c2c8b1c321 feat: 保质期列表添加空状态提示 2026-06-08 13:36:56 +08:00
xfy
4805bd1f0e fix: 修复日期检查器右滑删除卡住问题,列表底部添加间距防止FAB遮挡 2026-06-08 13:30:04 +08:00
xfy
62d3bbabea refactor: 首页 FAB 菜单图标替换为 Material Icons,展开时切换 Close 并添加过渡动画 2026-06-08 13:20:33 +08:00
xfy
a5a4173cc2 refactor: 返回图标从 Canvas 手绘替换为 Material Icons ChevronLeft 2026-06-08 13:10:44 +08:00
xfy
6b15c4b88b feat: 日期检查器 FAB 图标替换为 Material Icons 2026-06-08 11:36:58 +08:00
xfy
0560e81fb2 feat: 日期检查器添加数据持久化和恢复默认按钮
- 新增 DateCheckerStorage,SharedPreferences 持久化生产日期和保质期列表
- 添加 DateCheckerStorageTest 单元测试(含 InMemorySharedPreferences stub)
- 页面退出后保留数据,重新打开自动恢复
- 左下角新增恢复默认 FAB,点击弹出确认弹窗后重置全部数据
- 双 FAB 样式统一(FloatingActionButton + CircleShape + primary 配色)
2026-06-08 11:08:48 +08:00
xfy
b3abe92b2c feat: 更新 Baseline Profile,覆盖日期检查器/调休/工具页等场景 2026-06-02 13:10:49 +08:00
xfy
829f89eb7c refactor: 删除 P0 冗余代码(自定义combine/死StateFlow/网格重复算法/runBlocking)
- 删除自定义 6 参数 combine + Quintuple,改用标准库嵌套 combine + Triple
- 删除 yearViewProgress 死 StateFlow 及关联测试
- generateMonthDays/generateMiniMonthDays 复用 getMonthGridInfo
- WeekPager 移除 runBlocking,交由 DayCell 自行异步计算
- 修复 AnimLog 在 JVM 单元测试中因 android.util.Log 不可用而崩溃
2026-06-01 18:03:27 +08:00
xfy
e249700ee5 refactor: 清理不必要的 @Suppress 注解并替换弃用 API
移除 23 处不必要或可通过改写避免的 @Suppress。
- 删除 12 处完全不必要(误加/重构遗留)
- 替换 9 处 monthNumber/dayOfMonth → month.number/day
- 替换 4 处弃用构造函数 LocalDate(year,month,1) → LocalDate(year,Month(month),1)
- 保留 6 处必要 @Suppress(NOTHING_TO_INLINE、Android API 兼容等)
2026-06-01 17:55:18 +08:00
xfy
484045950f fix: 修复日期检查器滑动删除 state 错位并消除 deprecation warning
- 将 dismissState 移入 key(row.id) 内部,修复删除后 state 被错误复用的问题
- 新增 pendingDeleteIds 延迟删除机制,滑动删除播放 shrinkVertically + fadeOut 退场动画
- 移除废弃的 confirmValueChange 参数,改用 LaunchedEffect 监听 dismissState.currentValue
2026-06-01 17:21:42 +08:00
xfy
877a3f9aa4 refactor: 日期检查器滑动删除添加动画等待完成后移除数据 2026-06-01 17:15:14 +08:00
xfy
aeb147c6a7 feat: 日期检查器添加行级入场/出场动画与 animateContentSize 2026-06-01 16:56:19 +08:00
xfy
24cb8fd3fe refactor: 移除日期检查器新行入场动画与高亮动画
- 移除 ExpiryRow.isNew 字段及相关入场淡入+上滑动效
- 移除 highlightedRowId 高亮逻辑及相关动画
- simplify animateItem() 为默认参数
- 用 Spacer 替代 verticalArrangement 实现行间距
- 用 animateScrollToItem 替代 scrollToItem + delay 模式
2026-06-01 16:41:33 +08:00
xfy
f0975f119d feat: 日期检查器新行添加入场动画(淡入+上滑)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 15:54:40 +08:00
xfy
bc9c10d82e feat: 日期检查器添加新行自动滚动与高亮动画
- 点击 FAB 添加新行后自动滚动到列表底部
- 新增行短暂高亮显示(primaryContainer 背景色)
- LazyColumn 添加 animateItem() 提升列表动画体验

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 15:39:43 +08:00
xfy
b12206dc88 feat: 日期检查器 UI 改版,添加过期状态显示
- 生产日期改为渐变卡片展示,支持点击切换日期
- 保质期条目改为 ExpiryCard,显示过期状态标签
- 新增 ExpiryStatus 枚举(SAFE/WARNING/URGENT/EXPIRED)
- 新增 ArrowRightIcon 自定义图标
- 添加中文日期格式化辅助函数
- 改进 TopAppBar 和 FAB 样式

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 14:12:41 +08:00
xfy
23909e855f refactor: 简化 BottomCard 年视图切换动画并移除调试日志
- 将 slideAnim 初始值固定为 1f(屏幕外),简化年↔月切换逻辑
- 移除 BottomCard 区域的调试 logd 日志
- fadeIn easing 从 FastOutSlowInEasing 改为 LinearOutSlowInEasing

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 14:00:18 +08:00
xfy
be023a00a9 refactor: 优化年份视图切换动画,使用 Animatable 精确控制
- 用 Animatable + LaunchedEffect 替换 animateFloatAsState
  实现滑出/滑入分阶段动画序列(先滑出再滑入)
- 统一缩放/淡入淡出动画时长为 350ms
- 底部卡片滑出偏移从 200.dp 增加到 300.dp

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 13:47:36 +08:00
xfy
f34e34e5ae feat: 引入 YaYaTheme 并应用到所有 Activity
新增 Theme.kt 提供 Android 12+ 动态颜色支持,
为全部 5 个 Activity 的 setContent 包裹 YaYaTheme。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 13:25:27 +08:00
xfy
a8717dec7d refactor: MenuItem 和 ToolItem 统一使用 Card(onClick) 2026-06-01 13:18:27 +08:00
xfy
6446d6636e refactor: 移除 LicensesScreen 调试日志
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 11:44:15 +08:00
xfy
c72120ee0a fix: 开源许可列表项改用 Card(onClick) 以支持点击动画
原实现使用 Column + Modifier.clickable 在 LazyColumn 中无法显示
ripple 反馈。改用 Material3 Card 的 onClick 参数后,点击水波纹
动画正常显示。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 11:42:49 +08:00
xfy
acb737dd25 refactor: 简化 holiday badge 空值检查为 Elvis 运算符 2026-06-01 11:18:10 +08:00
xfy
4a8480be64 feat: 移除共享元素转场,月/年视图切换改用缩放+淡入淡出动画 2026-06-01 11:11:45 +08:00
xfy
6dffaf4c91 feat: 法定假日背景添加波浪缩放动画
点击"显示调休"后,假日格子背景从左上到右下依次缩放弹出(每格延迟15ms),
关闭时反向缩放消失,使用 graphicsLayer 实现高性能动画。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 17:41:18 +08:00
xfy
3c1a04580c 更新 baseline profile 和优化基准测试生成器 2026-05-27 17:13:16 +08:00
xfy
281abcf66b perf: 添加性能追踪标记并改进基线配置文件生成器 2026-05-27 16:06:05 +08:00
xfy
4de00e35dc Update baseline profile for performance optimization 2026-05-27 11:14:07 +08:00
xfy
4eadc479eb feat: 添加 testTag 基础设施,扩展 Baseline Profile 覆盖路径
为 CalendarPager、BottomCard、FAB、工具页、日期检查器等关键 UI 元素添加 testTag,
启用 testTagsAsResourceId 支持 UI Automator 通过 resource-id 定位。
BaselineProfileGenerator 使用 testTag 选择器重写,覆盖工具页、日期检查器、
DatePicker 等更多导航路径。清理 DEVELOPMENT.md 移除已过时的性能瓶颈描述。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 10:03:16 +08:00
xfy
9a0222b4a2 perf: 引入 logd 条件日志工具,增强动画调试并优化 sharedElement 缓存
- 新增 AnimLog.kt,提供 BuildConfig.DEBUG 条件控制的 logd 日志工具,
  支持 lambda 延迟求值以避免 release 模式下的字符串拼接开销
- 全模块替换 android.util.Log.d 为 logd,并将日志重构为 lambda 形式
- CalendarViewModel: toggleYearView / selectMonthFromYearView 添加纳秒级
  耗时追踪日志
- CalendarMonthView / CalendarMonthPage / CalendarPager / YearGridView:
  增加重组/进入/离开/页面切换/动画状态变化的详细调试日志
- 折叠动画/滑动进度日志添加状态去重,避免频繁重复输出
- P0: 缓存 sharedElement tween 实例(CalendarMonthView + YearGridView),
  避免每次重组创建新实例导致动画重新计算
- P0: YearPager pageYear 使用 remember 稳定计算,避免 settledPage 与
  yearViewYear 不同步导致抖动
- 移除 YearPager crossFadeAlpha,改为无透明度渐变
- app/build.gradle.kts 添加 profileinstaller 依赖

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 18:27:07 +08:00
xfy
20425e392c fix: 恢复折叠动画 Phase 2 下方行偏移,移除 showWeekPager 切换
- 恢复 CalendarMonthPage 中 isBelow 行的 `- phase2 * belowRowsHeight`
  (2592a5f 误删导致展开时下方行原地淡入而非滑出)
- 移除 CalendarMonthView 的 showWeekPager + AnimatedContent 切换
  (完全折叠后下拉拖拽时只显示 WeekPager 单周,上下空白)
- 回退到始终显示 CalendarPager,由 CalendarMonthPage 处理折叠动画
- 添加详细动画调试日志(Page/WeekRow/View 三层)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 17:39:40 +08:00
xfy
2592a5fa55 feat: 使用 AnimatedContent 平滑切换 CalendarPager ↔ WeekPager
- 用 AnimatedContent 包装 pager 切换,添加 fadeIn/fadeOut 过渡
- 延迟 50ms 切换避免折叠 spring 动画期间的视觉跳跃
- 修复 WeekRow 下方行的 yOffset 计算(移除 phase2 项)
- WeekPager 添加农历缓存支持
- 添加折叠动画调试日志

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 14:18:50 +08:00
xfy
4c53f234cf fix: 去掉 CalendarPager ↔ WeekPager 切换,修复折叠闪烁
CalendarPager 在 collapseProgress=1.0 时只渲染 anchor 行,
效果和 WeekPager 相同,但避免了切换导致的视觉跳跃。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 13:54:02 +08:00
meyou
dfb820d610
Revert "feat: 添加年月滚轮选择器,支持触觉反馈"
This reverts commit bbe51051ae83d56fda8ad965f7b73a014ddea7b8.
2026-05-26 07:33:15 +08:00
meyou
0b6d9ea87a
fix: 滚轮选择器仅在滚动停止后触发选中变更和触觉反馈
快速滑动时不再每帧更新 selectedIndex,改为等滚动停止后
计算最终中心项再触发回调,消除来回抽搐问题。
2026-05-25 23:38:59 +08:00
meyou
bbe51051ae
feat: 添加年月滚轮选择器,支持触觉反馈
- 新增 WheelPicker composable:惯性吸附 + 触觉反馈滚轮
- 新增 MonthYearPickerDialog:年月双滚轮选择弹窗
- 新增 YearPickerDialog:年份滚轮选择弹窗
- MonthHeader:点击年月文字弹出年月选择器
- YearHeader:点击年份文字弹出年份选择器
- 滚动时触发 HapticFeedbackConstants.CLOCK_TICK 触觉反馈
2026-05-25 23:34:25 +08:00
meyou
6fac313fdf
perf: 延迟 YearGridView 文本测量到第二帧,补充性能分析文档
YearGridView 首帧 168ms 中约 24ms 来自 remember 同步文本测量。
将 dayLayouts/titleLayouts/weekdayLayouts 改为 produceState,
首帧 Canvas 渲染为空(sharedElement 结构不变),第二帧填充内容。

DEVELOPMENT.md 补充已知性能瓶颈分析和 Baseline Profile 覆盖建议。
2026-05-25 23:19:58 +08:00
meyou
ce84c614de
fix: 恢复 AnimatedGif 弹跳动画和 YearGridView 全量 sharedElement
- AnimatedGif: 恢复原始 scale 弹跳入场动画,仅保留 repeatCount 限制
- YearGridView: 恢复所有 12 个月的 sharedElement,保证点击任意
  月份都有正确的共享元素转场动画
- CalendarPager: beyondViewportPageCount 1→0 保留(无视觉影响)
2026-05-25 23:06:15 +08:00
meyou
5158b99800
perf: 优化年月切换卡顿
Perfetto trace 分析:
- YearGridView 首帧 168ms: 12 个 MiniMonth 各创建 sharedElement
  节点,但仅 1 个 key 匹配 CalendarPager
- compose:lazy:prefetch 最长 703ms: CalendarPager 预加载相邻页

修复:
- YearGridView: 仅选中的月份使用 sharedElement(11→1 个),
  减少首次组合的 modifier 节点创建开销
- CalendarPager: beyondViewportPageCount 1→0,消除预加载卡顿
2026-05-25 22:57:18 +08:00