diff --git a/superpowers/plans/2026-09-10-ring-health-app-m0-m1.md b/superpowers/plans/2026-09-10-ring-health-app-m0-m1.md index 34175f9..39a8307 100644 --- a/superpowers/plans/2026-09-10-ring-health-app-m0-m1.md +++ b/superpowers/plans/2026-09-10-ring-health-app-m0-m1.md @@ -37,6 +37,18 @@ - **不做 `installDebug`**:本机没有模拟器镜像、也没有连接真机,各 Task 的构建步骤**只跑 `./gradlew assembleDebug`** (ledger Ruling R21)。运行时的界面/交互验证统一顺延到 Task 14 Step 3 的人工验收清单,交人在有设备时执行。 执行 agent 不要尝试 `installDebug`,也不要临时下载模拟器镜像。 +- **每个页面必须拆成「有状态外壳 + 无状态内容」并给内容加 `@Preview`**(ledger Ruling R26): + 公开的 `XScreen(modifier, viewModel)` 只负责 `collectAsStateWithLifecycle` 并委托, + 真正渲染的是 `private fun XContent(state, …, modifier)`,`@Preview` 挂在后者上、传入手写的示例 state。 + Task 8 的 `HomeScreen` / `HomeContent` / `HomeContentPreview` 是样板。 + 理由不只是惯例:本机**没有任何设备**(见上一条),IDE Preview 是 Task 14 人工验收之前 + **唯一**能让人看见界面的手段;没有它,Task 9–12 四个页面到验收前都只有编译期保证。 + 同时这天然把「渲染」与「取数」分开,`XContent` 可以直接拿假数据测。 +- **次要文字一律用 `core/designsystem/` 的 `TextSecondary`**,不要用 `MaterialTheme.colorScheme.onSurfaceVariant` + (ledger Ruling R26):主题只覆写了 `surface`/`background`/`surfaceVariant` 等槽位, + `onSurfaceVariant` 仍是 Material 默认的 `#FF49454F`,而 `TextSecondary` 是 `#FF8E8E93` —— + 两者都是灰但深浅明显不同,混用会让同一屏里的次要文字深浅不一。 + 这是「禁止行内样式散落」的延伸:槽位不是字面量,所以编译器拦不住,只能靠这条约定。 ## File Structure @@ -4244,6 +4256,12 @@ Expected: `BUILD SUCCESSFUL`,生成 `app/build/outputs/apk/debug/app-debug.apk - [ ] 应用启动无崩溃,底部四个 Tab 显示为 健康 / 运动 / 设备 / 我的 - [ ] 四个 Tab 可自由切换,切换后状态保留、无闪烁 +- [ ] **重按已高亮的父 Tab 的行为**(Task 7 用 `popUpTo(start){saveState}` + `restoreState` 实现, + 推测会**恢复到该 Tab 保存的子页栈**,即停在子页而不是回到 Tab 根 —— 请实测并记录实际行为)。 + 若实测是「停在子页」而产品希望「回到根」,那是一个独立的小改动,记下来即可,不算本任务失败 +- [ ] 每个页面的 `@Preview` 能在 Android Studio 中正常渲染(R26;这是没有设备时唯一的界面检查手段) +- [ ] 次要文字的灰度一致:同一屏内不应出现深浅两种灰(`TextSecondary` #8E8E93 + 与 Material 默认 `onSurfaceVariant` #49454F 混用会很明显,R26) - [ ] 首页:设备状态条显示“RingHealth 智能戒指 · 已连接 / 电量 78%” - [ ] 首页:步数大环显示 8,426,目标 10,000,环按比例填充 - [ ] 首页:六个指标卡正常显示,**血压显示“未开启”**