Compare commits

..

30 Commits

Author SHA1 Message Date
xfy
5bf8a85f7a Merge branch 'feature-birthday-crown' 2026-06-15 16:48:24 +08:00
xfy
3ca0d334e7 refactor: remove redundant icon content description and reorder DayCellImpl params 2026-06-15 16:45:58 +08:00
xfy
94861dc2f7 style: apply spotless formatting 2026-06-15 16:41:07 +08:00
xfy
de47509a32 feat: show tilted birthday crown with click bounce animation 2026-06-15 16:36:13 +08:00
xfy
564e4e3960 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) 均成功
2026-06-15 16:24:38 +08:00
xfy
f33e68d1db feat: compute birthday flag in LunarCache 2026-06-15 16:22:47 +08:00
xfy
ef785a3ca7 docs: correct tyme4kt API details in birthday crown spec and plan 2026-06-15 16:18:38 +08:00
xfy
06ac30e6d2 feat: compute birthday flag in LunarCache 2026-06-15 16:10:22 +08:00
xfy
7404bdfc28 feat: add birthday crown vector drawable 2026-06-15 16:03:41 +08:00
xfy
5c8839dea2 chore: ignore .worktrees directory 2026-06-15 16:01:38 +08:00
xfy
2427ae18a4 docs: add birthday crown implementation plan 2026-06-15 15:59:17 +08:00
xfy
c82ab26944 docs: add birthday crown feature design spec 2026-06-15 15:53:37 +08:00
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
9d1999661c refactor(app): 缩小 Adaptive Icon 前景鸭子尺寸
- 将鸭子+日历缩放至 60dp 安全圆内,留出更多浅蓝背景边距
- 保持透明前景,背景由 @drawable/ic_launcher_background 单独提供
2026-06-15 14:51:10 +08:00
xfy
3f8eb1db05 fix(app): 修复 Adaptive Icon 前景加载失败及前景含背景问题
- mipmap-anydpi-v26 XML 直接引用 @mipmap/ic_launcher_foreground
- 删除非法的 drawable/ic_launcher_foreground.xml(<mipmap> 不是合法 drawable 根元素)
- 移除无效的 <monochrome> 引用(彩色位图不能用作主题化单色层)
- 重新生成带透明通道的前景 WebP,仅保留鸭子+日历
2026-06-15 14:46:12 +08:00
xfy
aba2086c22 Merge branch 'fix/image-management-cleanup' into main
图片资源管理优化: 清理无用资源、消除硬编码、补齐 Adaptive Icon、校正文档

7 个提交:
- 删除 app/assets 中无引用的 app_icon PNG (设备 -516KB)
- 删除 core/assets/gifs/.omc 工具残留 (gitignored, 物理清理)
- gifs/→animations/、AnimatedGif→AnimatedWebp (名实相符)
- WebP 文件列表改构建期 BuildConfig 注入 + 测试守卫 (消除 (1..152) 硬编码)
- 新增 Adaptive Icon (anydpi-v26, 修复 API 26+ 启动器裁切)
- 校正 4 份 assets/AGENTS.md (消除 GIF/镜像错误描述)
- 修复审查发现 (README 坏链 + 原图归宿说明)

验证:
- 146 单元测试 0 失败
- :app:assembleDebug + spotlessCheck 全过
- APK -489KB (24,416,752 → 23,915,583)
- Adaptive Icon 模拟器实机验证 (圆形遮罩下背景填满、主体居中无裁切)
- Task 4 守卫突变验证 (硬编码 1..150 时测试立即 FAIL)
2026-06-15 14:15:49 +08:00
xfy
c591bc389b docs: 修复代码审查发现的问题(README 坏链 + 原图归宿说明)
审查发现 2 个问题:

1. README.md:6 坏链 [必须修]
   - <img src="app/src/main/assets/app_icon.png"> 指向 Task 1 已删的 PNG
   - 改为 core/src/main/assets/app_icon.webp (现存的应用内图标, 512px)
   - 加 width/height=128 限制展示尺寸 (原图无尺寸约束会撑满)

2. app/assets/AGENTS.md 原图归宿说明模糊 [建议修]
   - 原写"源文件放仓库外或 .assets-source/" 但两者都不存在, 误导
   - 改为明确: 原图 app_icon_original.png (2048px) 保留在 git 历史
     commit a36f6c4, 用 git show 恢复, 生成脚本见实施计划 Task 5

审查驳回的建议 (附理由):
- <mipmap> 间接引用: 审查自承"通常能工作", 且 Task 5 已模拟器实机
  验证渲染正常 (analyze_image 确认黄色主体居中无裁切)。
  <mipmap> 标签按密度选桶是启动器前景的标准做法, 不改。
- baseline-prof lambda hash: Task 3 commit 已说明"下次 updateBaselineProfile
  校准", 且 hash 失效是静默降级不报错, 不阻塞合并。

验证: ./gradlew :app:assembleDebug → BUILD SUCCESSFUL
2026-06-15 14:13:26 +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
ac41eef37b feat: 新增 Adaptive Icon(anydpi-v26),修复 API 26+ 启动器裁切
问题
- minSdk 24, 但只有 mipmap-*/ic_launcher.png (无 anydpi-v26)
- ic_launcher.png 与 ic_launcher_round.png MD5 完全相同, 圆形版只是方形副本
- API 26+ 用户在 OEM 圆形/水滴/方形启动器上图标会被硬切, 主体缺失

新增资源
- drawable/ic_launcher_background.xml: 矢量色块 #83D0F1 (原图四角采样 RGB 131,208,241)
- drawable/ic_launcher_foreground.xml: <mipmap> 引用密度分桶位图
- mipmap-anydpi-v26/ic_launcher.xml + ic_launcher_round.xml: adaptive-icon 定义
  (含 <monochrome> 支持 Android 13+ 主题化图标)
- mipmap-{xhdpi,xxhdpi,xxxhdpi}/ic_launcher_foreground.webp:
  从 app_icon_original.png (2048px) 中心裁 80% + cwebp -q 90 生成
  体积比对应 ic_launcher.png 小 60-70% (xxhdpi: 7.4KB vs 22.5KB)

设计决策
- foreground 用位图而非矢量: 原图主体是写实风格, 矢量化会损失质量
- foreground 源图用 git 历史临时恢复生成, 不重新入库 (保持 Task 1 清理成果)
- 保留 mipmap-*/ic_launcher.png 作 API 24-25 回退 (不删)
- AndroidManifest.xml 无需改: @mipmap/ic_launcher 在 API 26+ 自动取 anydpi-v26

设备验证 (emulator API 37, Pixel Launcher)
- 安装 + 回桌面, hotseat 最右 YaYa 图标显示正常
- analyze_image 确认: 圆形遮罩下背景填满, 黄色主体居中无裁切
- 颜色与原设计一致 (主体 RGB~254,213,74, 背景 #83D0F1)

构建验证
- unzip -l 确认 APK 含 anydpi-v26/*.xml + drawable/ic_launcher_*.xml + 各密度 foreground.webp
- ./gradlew :app:assembleDebug → BUILD SUCCESSFUL
- APK 累计 -489KB (baseline 24,416,752 → 23,915,694, 主要是 Task 1 删 PNG)
2026-06-15 14:06:21 +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
4c8084c176 fix: 恢复 scripts/profile.sh 可执行权限
上一个提交 (87d51b2) 编辑该文件时丢失了 100755 → 100644 的 mode 位,
纯 mode 修正, 无内容变更。
2026-06-15 13:57:20 +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
3d39e609df chore(app): 删除 app/assets 中无引用的 app_icon PNG 图标
问题
- app/src/main/assets/app_icon.png (61KB) 与 app_icon_original.png (468KB)
  无任何代码引用(grep 全仓库确认),但作为 assets/ 文件会被原样打进 APK
- 实际应用内图标用的是 core/src/main/assets/app_icon.webp
  (Platform.kt:15 getAppIconUri() 引用),与这两个 PNG 无关

验证
- grep -rn "app_icon_original\|assets/app_icon\.png" app/src core/src
  → 无输出(仅 AGENTS.md 提及,已排除)
- unzip -l 对比: assets/ 总量 4,286,121 → 3,757,710 字节(-528,411B ≈ 516KB)
- ./gradlew :app:assembleDebug → BUILD SUCCESSFUL

影响
- 设备安装体积减少 ~516KB(APK 是 ZIP, PNG 已压缩, 故 APK 文件本身仅 -139B;
  但 assets 安装时解压展开, 设备占用是实打实少 516KB)
- 不影响任何运行时行为
2026-06-15 13:52:21 +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
1cb35d2752 Merge branch 'fix/date-checker-negative-days'
修复日期检查器保质期天数负数 bug: clampExpiryDays 纯函数钳制非负(含 4 单测);两个日期写入路径(选择器确认+行内输入)兜底;DatePicker SelectableDates 禁选早于生产日期(仅 Row);加载清理历史持久化负数旧数据
2026-06-15 11:43: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
192 changed files with 1016 additions and 434 deletions

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ node_modules/
logs/
.claude/
docs/superpowers/
.worktrees/

View File

@ -2,8 +2,6 @@
纯 Android + Jetpack Compose 日历应用。功能:农历/节气/节日、个人班次排期WORK/OFF 循环)、月/周/年三视图。
> **README 与实际不符**README 提及 "Kotlin Multiplatform / iOS",实际为纯 Android 项目。模块名为 `:core``:app`,无 `:shared``:androidApp`
## 模块结构
| 模块 | 类型 | 职责 |

View File

@ -3,7 +3,7 @@
纯 Android + Jetpack Compose 日历应用,支持农历/节气/节日、个人班次排期,提供月/周/年三种视图。
<div>
<img src="app/src/main/assets/app_icon.png" />
<img src="core/src/main/assets/app_icon.webp" width="128" height="128" />
</div>
## 特性
@ -19,8 +19,8 @@
- Kotlin 2.3 · Jetpack Compose · Material 3
- `kotlinx-datetime` 处理所有日期逻辑
- `tyme4kt` 提供农历、节气与传统节日
- `sketch` 渲染 GIF 动画
- 模块:`:core`UI + 逻辑) · `:app`(薄壳)
- `sketch` 渲染动画 WebP
- 模块:`:core`UI + 逻辑) · `:app`(薄壳) · `:macrobenchmark`Baseline Profile 生成)
## 构建

View File

@ -1,25 +1,25 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-05-22 | Updated: 2026-05-22 -->
<!-- Generated: 2026-05-22 | Updated: 2026-06-15 -->
# assets
## Purpose
原始资产文件目录,存放不需要 Android 资源系统处理的二进制文件。当前包含 GIF 动画资源
`:app` 模块原始资产文件目录。当前为空2026-06 清理后)
## Key Files
顶层文件
## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `gifs/` | GIF 动画资源(见 `gifs/AGENTS.md` |
无(原 `gifs/` 子目录的镜像说明已删除 —— 实际 UI/WebP 资源只在 `:core`
## For AI Agents
### Working In This Directory
- 新增原始资源文件直接放入此目录或其子目录
- 通过 `AssetManager` 在运行时访问
- 历史上此目录曾放 `app_icon.png`/`app_icon_original.png` 作图标源,因无代码引用已于 2026-06 删除
- 应用内图标用 `core/src/main/assets/app_icon.webp``Platform.kt`
- 启动器图标用 `app/src/main/res/mipmap-*/`(含 Adaptive Icon
- **不要再把图标源 PNG 放这里**:会被打进 APK。原图 `app_icon_original.png` (2048px) 保留在 git 历史commit `a36f6c4`),重新生成 foreground 时用 `git show a36f6c4:app/src/main/assets/app_icon_original.png` 恢复,生成脚本见 `docs/superpowers/plans/2026-06-15-image-management-optimization.md` Task 5
<!-- MANUAL: -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 KiB

View File

@ -1,33 +0,0 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-05-22 | Updated: 2026-05-22 -->
# gifs
## Purpose
GIF 动画资源目录,存放应用使用的动画 GIF 文件001.gif ~ 152.gif`AnimatedGif` Composable 组件通过 `sketch` 库加载显示。
## Key Files
| File | Description |
|------|-------------|
| `001.gif` ~ `152.gif` | 应用动画 GIF 资源 |
## Subdirectories
## For AI Agents
### Working In This Directory
- 替换或新增 GIF 时保持连续编号
- GIF 文件较大,注意 APK 体积影响
- `AnimatedGif` 组件使用 `sketch` 库异步加载和播放
## Dependencies
### Internal
- `core/src/main/kotlin/plus/rua/project/ui/AnimatedGif.kt` — GIF 显示组件
### External
- `sketch` 4.4.0GIF 解码和播放)
<!-- MANUAL: -->

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Adaptive Icon 背景: 纯色块, 取自原图四角采样 RGB(131,208,241) -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#83D0F1"
android:pathData="M0,0h108v108h-108z" />
</vector>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Adaptive Icon (API 26+): 系统按 OEM 启动器形状自动裁切背景+前景。
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Adaptive Icon 圆形版 (API 26+), 内容与 ic_launcher.xml 一致 -->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -12,6 +12,21 @@ android {
defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
consumerProguardFiles("proguard-rules.pro")
// 构建期扫描 assets/animations/ 生成 WebP 文件列表,避免运行期硬编码 (1..152)
// 与 assets/ 目录耦合却不校验,导致增删文件后隐性 bug
val webpFiles = layout.projectDirectory
.dir("src/main/assets/animations")
.asFile
.listFiles { f -> f.extension.equals("webp", ignoreCase = true) }
?.map { it.name }
?.sorted()
?: emptyList()
require(webpFiles.isNotEmpty()) { "assets/animations/ 不应为空,请检查目录" }
// 拼成 Java 数组字面量: new String[]{"001.webp","002.webp",...}
val quoted = webpFiles.joinToString(",") { name -> "\"$name\"" }
val arrayLiteral = "new String[]{$quoted}"
buildConfigField("String[]", "WEBP_FILES", arrayLiteral)
}
buildTypes {
@ -20,7 +35,6 @@ android {
}
release {
isMinifyEnabled = false
consumerProguardFiles("proguard-rules.pro")
buildConfigField("boolean", "ENABLE_TRACE", "false")
}
create("trace") {

View File

@ -1,34 +1,6 @@
# Baseline Profiles 保留规则:确保方法名不被 R8 混淆,使 profile 规则匹配正确
-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 cn.tyme.** { *; }

View File

@ -1,25 +1,28 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-05-22 | Updated: 2026-05-22 -->
<!-- Generated: 2026-05-22 | Updated: 2026-06-15 -->
# assets
## Purpose
核心模块原始资产文件目录,`app/src/main/assets/` 镜像,包含 GIF 动画资源供 `AnimatedGif` Composable 组件加载
核心模块原始资产文件目录,通过 `AssetManager` 在运行时访问。包含应用内图标和动画 WebP 资源
## Key Files
无顶层文件
| File | Description |
|------|-------------|
| `app_icon.webp` | 应用内展示用的图标(`Platform.kt``getAppIconUri()` 引用) |
## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `gifs/` | GIF 动画资源(见 `gifs/AGENTS.md` |
| `animations/` | 动画 WebP 资源(见 `animations/AGENTS.md` |
## For AI Agents
### Working In This Directory
- 此目录与 `app/src/main/assets/` 内容同步
- 通过 `AssetManager` 在运行时访问
- 新增原始资源文件直接放入此目录或其子目录
- **不与 `app/src/main/assets/` 镜像**:启动器图标在 `:app`UI/WebP 资源在 `:core`
- 通过 `file:///android_asset/<path>` URI 在运行时访问
<!-- MANUAL: -->

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Some files were not shown because too many files have changed in this diff Show More