11 KiB
M1 静态页面验收记录
环境
- 记录日期:2026-09-10
- 构建版本:0.1.0 (versionCode 1)
- 构建机:Windows 11,JDK 17.0.12,Android SDK
D:\Android\Sdk(仅platform-tools/platforms;android-36/build-tools;36.1.0) - 测试设备:无 —— 本机没有安装任何模拟器镜像,也没有连接真机
补充证据(说明「无设备」不是随口一说,而是逐项查过的):
$ ls D:\Android\Sdk
build-tools cmdline-tools licenses platform-tools platforms
# 没有 emulator/,也没有 system-images/
$ adb devices
List of devices attached
# 空列表,没有连接真机
C:\Users\10314\.android\avd\ 下残留着两个 AVD 定义(Medium_Phone_API_36.1、
Pixel_9_Pro),但它们是不可用的空壳:二者都指向已删除的旧 SDK
C:\Users\10314\AppData\Local\Android\Sdk(其 emulator\emulator.exe 与
system-images\android-36.1\google_apis_playstore\x86_64\ 均已不存在),且属于另一个项目
(D:\work\xiangmu\mediq-app)。不要因为看到 AVD 目录就以为本机可以起模拟器。
另注:当前 shell 的 ANDROID_HOME 仍指向那个已删除的旧路径,构建实际靠
local.properties 的 sdk.dir=D:\Android\Sdk 生效。
自动化验证(已执行)
- 单元测试:
./gradlew :app:testDebugUnitTest—— 21 项全绿 (FormattersTest7 +MockDataProviderTest5 +HomeViewModelTest1 +WorkoutViewModelTest1DeviceViewModelTest2 +MetricDetailViewModelTest3 +RoutesTest2)
- 构建:
./gradlew clean assembleDebug——BUILD SUCCESSFUL, 产物app/build/outputs/apk/debug/app-debug.apk(18,907,329 字节) - 未执行:各页面的
@Preview在 Android Studio 中渲染。本机没有 IDE GUI,agent 无法打开 Preview 面板,这一项与人工验收一样是未执行的 —— 不要把它写进「已执行」段落 (旧稿把它列在上面这一节里,那等于声称验证过一件没做过的事)。
终审修复轮(5fe0d4a)各项改动的可验证性
终审后又有一轮修复,共 6 处改动。不要把这 6 处一律当成「已验证」 —— 它们能验到什么程度 差别很大,逐项列明:
| 改动 | 实际验到了什么 |
|---|---|
| 详情页按指标取色(原先一律绿) | when 穷尽七个 MetricType,代码可确认;配色是否好看/是否与首页一致,未经渲染验证 |
详情页空数据态(原先渲染全 0 柱状图 + 三行 0.0) |
无测试覆盖,仅代码推理。且血压卡改为不可点后,该路径在当前 Mock 下实际不可达(metricHistory 恒返回 7 或 30 个点)—— 属防御性代码 |
| 血压卡不可点击(原先显示「未开启」却能点进一张有数据的图表) | onClick 改为可空并传 null,代码可确认;点击涟漪是否真的消失,未经渲染验证 |
压力卡 unit 接线(4 条字符串此前无调用点) |
调用点已存在,代码可确认;文字是否在卡片里溢出,未经渲染验证 |
RingHealthApp NavHost 补 consumeWindowInsets(innerPadding) |
推理得出,未经设备验证 —— 见下方人工验收第 1 项 |
README 注明 installDebug 需设备 |
文档,无需验证 |
结论不变:这几处里凡带「视觉」二字的,本机都没验过。
人工验收(未执行 —— 无设备)
下表全部未打勾。这份清单已原样保留,交给有设备的人执行;不要在没有实测的情况下填入结果。
| 项 | 结果 | 备注 |
|---|---|---|
| 应用启动无崩溃 | 未执行 | 无设备 |
| 四 Tab 切换 | 未执行 | 无设备 |
| 重按已高亮的父 Tab 的行为 | 未执行 | 需实测:推测会停在子页而非回到 Tab 根 |
每个页面的 @Preview 可渲染 |
未执行 | 需在 Android Studio 中逐个打开确认 |
| 次要文字灰度一致 | 未执行 | 不得出现 TextSecondary 与 onSurfaceVariant 混用 |
| 首页:设备状态条 / 步数大环 8,426 / 六个指标卡(血压“未开启”) | 未执行 | 无设备 |
| 指标详情页:周/月切换(7 根 / 30 根柱子) | 未执行 | 无设备 |
| 睡眠详情:分期卡片只在睡眠指标出现,入睡/起床读起来像「一晚」 | 未执行 | 无设备 |
| 运动页 / 运动历史页 | 未执行 | 无设备 |
| 设备页 / 设备设置开关(返回后状态保持) | 未执行 | 无设备 |
| 我的页 | 未执行 | 无设备 |
| 旋转屏幕、深色系统设置下不崩溃 | 未执行 | 无设备 |
需在有设备时重点确认的项(原清单细目,逐条保留)
- 【第 1 优先】内边距是否正确(终审 fix 5,本表最可能出问题的一项):
RingHealthApp的 NavHost 现为Modifier.padding(innerPadding).consumeWindowInsets(innerPadding)。 原因是详情页/设备设置页自带Scaffold+TopAppBar,而外层的Modifier.padding不消费 window insets,于是状态栏高度被上下叠加两次。补consumeWindowInsets是标准修法, 但这一改动从未在设备上看过一眼。请优先确认两件事: ① 详情页、设备设置页的返回箭头与标题没有被状态栏遮住; ② 顶部也没有多出一条无意义的空白。 若仍有多余留白,问题在 insets 的消费方式而不在这行代码本身 - 应用启动无崩溃,底部四个 Tab 显示为 健康 / 运动 / 设备 / 我的
- 四个 Tab 可自由切换,切换后状态保留、无闪烁
- 重按已高亮的父 Tab 的行为:实现为
popUpTo(start){saveState}+restoreState, 推测会恢复到该 Tab 保存的子页栈(停在子页而非回到 Tab 根)。请实测并记录实际行为; 若实测是「停在子页」而产品希望「回到根」,那是一个独立的小改动,记下来即可 - 首页:步数大环显示 8,426,目标 10,000,环按比例填充
- 首页:点击任一指标卡进入详情页,标题为该指标中文名
- 详情页:返回后回到首页
- 运动页:显示“开始运动”卡片 + 5 条运动记录;「查看全部」进入历史页后底部导航栏仍可见
- 设备页:戒指卡片显示电量 78%、固件版本 1.0.5
- 睡眠卡片的入睡/起床时间读起来像「一晚」(如 入睡 22:41 / 起床 06:41),而不是跨好几天。
阶段一按「最后一个数据点往前 8 小时」演示(R29);若显示成跨天,说明
DEMO_SLEEP_WINDOW_MILLIS那段被改坏了
已知限制(阶段一有意为之)
- 数据全部为 Mock,不连蓝牙、不连后端
- 血压恒为“未开启”占位(
HealthSummary.bloodPressure = null) - 设备设置页的开关只改内存状态,重启即重置(对应 M2 的协议 0502/0504)
- 睡眠分期条与入睡/起床时间是演示值(固定比例 + 最后一个数据点往前 8 小时),无真实分期数据
- 详情页统计摘要一律保留一位小数(步数因此显示为「平均 7512.3」这类精度过剩的形式)
- 仅浅色模式
- 血压卡不可点击(
value == null时onClick传null)—— 阶段一没有血压数据, 点进去只会看到一张编出来的图表,不如不点 - 详情页的周/月切换常驻,空数据时只把切换条下方的图表与统计换成一行空态文案。 切换条属于页头而非数据区:数据显示为空时,切换区间正是用户的第一反应,它也是判断 「哪个区间是空的」的唯一线索
与设计文档 §6 的偏差(有意收窄,非遗漏)
- 设备页少了四项:查找戒指(050B)、智能提醒/闹钟占位、固件升级占位(OTA 17xx)、佩戴检测。 阶段一没有真实协议可对接,摆一排点不动的入口不如不摆(ledger R27)。这些能力仍属产品范围, 将于后续里程碑回归;设计文档 §6 的设备页一行已用删除线标注。
- 详情页由「四个专属设计」收敛为一个模板:
detail/step、detail/heart_rate、detail/sleep、detail/blood_oxygen四条路由合并为detail/{metric},七个指标共用同一模板(柱状趋势图 + 周/月切换 + 平均/最高/最低)。仅睡眠保留了专属区块(SleepStagesCard)。 未实现的是:步数的大环、心率的折线/静息-运动区间、血氧的正常范围说明文案。 收敛本身是有意的(避免七套几乎相同的页面代码),详见设计文档 §6 下的注记。
M2 接入时的已知接缝(交接用,本阶段不修)
RingDeviceRepository 目前不足以承载 M2 的设备控制:
refreshDeviceState()零调用者 —— 接口定义了,UI 从不触发。M2 需要接上「下拉刷新」或 进入设备页时刷新,否则真机断连后界面不会更新。setFunctionEnabled是非suspend的 —— Mock 只改内存态所以无所谓,但 M2 写向 BLE 必然是挂起操作,接口签名届时需要改,连带DeviceViewModel的调用点。- 预计 M2 的改动面:
domain/repository/Repositories.kt、data/mock/*、di/AppContainer.kt、AndroidManifest.xml(BLE 权限)、app/build.gradle.kts+gradle/libs.versions.toml(厂商 Java 依赖,很可能需要 Jetifier)、feature/device/DeviceScreen.kt。 完整清单见实施计划的「M2 交接提示」一节。
覆盖缺口声明
M1 的全部运行时行为目前只有编译期与单元测试保证,没有任何一次真机/模拟器运行。
assembleDebug 成功只说明代码能编译、能打包,不说明界面正确、不说明不会崩溃。
这是本机没有设备导致的已知缺口(ledger Ruling R21),不是「已验证通过」。
首次拿到设备时,请从上面那张人工验收表开始逐项补齐。
具体而言,没有任何一行 M1 的 Compose 界面代码被真正渲染过:导航图能否起来、
四个 Tab 是否显示正确文案、MetricBarChart 的柱子数量、RingProgress 的填充比例、
睡眠分期卡片是否只在睡眠指标下出现、次要文字灰度是否统一 —— 这些全部未经运行时检验。
单元测试覆盖的是 Formatters 的纯函数、MockDataProvider 的数据形状,以及七个 ViewModel
的状态流;它们不经过 Compose 渲染管线,也不能发现布局、主题或导航层面的错误。
终审修复轮新改的几处尤其如此:按指标取色、血压卡不可点、空数据态、压力卡的单位接线、
以及 consumeWindowInsets —— 这五处全部是界面行为,而 21 项单测一项都没有、也不可能
碰到它们。它们的依据是代码阅读与 Compose 的既有语义,不是运行结果。