单条烹饪会话的详情视图:顶部统计、温度曲线、关键事件时间线、可编辑笔记、删除入口。代码也处理 CookSessionStatus.active 且 endTime == null 的会话。
lib/features/thermometer/presentation/pages/cook_log_detail_page.dart(674 行)cookLogProvider(写入笔记 + 删除)、temperatureUnitProviderCookingSession(构造函数)app.dart 的 routes map);通过 navigateInstant(context, CookLogDetailPage(session: session)) 直接 push顶部返回箭头 + 居中标题 "Session Details"。下方滚动:开始时间 + 状态卡片、目标/峰值/时长统计行、温度曲线图(自绘 _CookLogGraphPainter,渲染 session.history 内 TemperatureReading 列表)、事件时间线(开始时间、温度交叉关键点、目标到达、报警等)、可编辑 3 行笔记输入框(带 hint),底部一个红色 "Delete entry" 按钮。
session.history 录入路径(b58946 / TAPD #1003099):由独立 cookSessionRecorderProvider(device_providers.dart 内,app.dart watch 保活)从 connectedBoostersProvider 监听遥测、对每个 active session 调 CookingSessionsNotifier.recordSample(...) 落盘,page-independent——用户没打开过的探针(CM2 White 等)也会被录到完整曲线,闭合「CM2 Black/CM1 只录到部分」、「White 全空」三类回归。Hybrid throttle:≤1 sample / 5 s、≥0.5 °F 或 30 s heartbeat、cap 500 点、超出按 2× decimation 保全 span(不掐头);ambient temp 真实落盘(之前 cooking-page-coupled addReading hardcoded 0)。详见 烹饪 §状态变化时如何更新。
X 轴 / 时间标签(b58946 / 问题 2):X 轴端点钉到 (session.startTime, session.endTime ?? history.last.timestamp)(active session fallback last sample),自适应 2–5 等距 tick(f332af7 / TAPD #1003179——固定 5 tick 在长 cook 下末两个 label 会撞在一起,如 298m27s 比 0s 宽很多;现按 TextPainter.layout 量宽、从 (durSec.floor()+1).clamp(2,5) 起递减挑能保证相邻 label 之间 ≥10 px 间距的最大 n,过不去就回退到端点-only 2 tick;首尾「0s」与累计耗时 label 始终保留,只丢中间 tick)、最后一个 tick 对齐 cook-end 时间、label 为累计耗时:不足 1 分钟时显示 Ss,1 分钟及以上时显示 NmSSs(中间无空格)。;之前用 intervals 数组 + 间距挑选算法的实现已撤回。同算法已镜像到 cooking 页实时 _TempGraphPainter(详见 §烹饪 Action #4 温度图)。
早期警告 marker(b58946 / 问题 3):遵循 session.earlyWarnLevel——0 不渲染 marker,1 走 AlarmThresholds.earlyWarn2DeltaF / earlyWarn2DeltaC(=5 °C / 9 °F),2 走 earlyWarn1DeltaF / earlyWarn1DeltaC(=10 °C / 18 °F);命名 inversely(level 1 → earlyWarn2…)来自 alarm_service 的历史延续,详见 告警与通知 §报警类型与优先级。之前 hardcoded 9 °F、与 alarm evaluator 实际门槛脱钩,且部分机型曲线不全时根本不画 marker——现 history 完整且按 level 渲染,所有机型一致。⚠️ 15e7e6d / TAPD #1003117 加竖向时间节点 marker:除了原有的横向 Y 轴参考线(28c930e 起由共享 drawCookGraphYNodes 渲染——amber 早期警告 + green 目标 dashed),now 在曲线首次穿越每个阈值的位置再多丢一条竖向虚线 + 实心点,由共享 helper drawCookGraphTimeMarker(cook_graph_axis.dart)绘制:early-warn 节点 amber(earlyWarnLevel == 0 时整条不画)、target 节点 green(无 earlyWarnLevel gate,但同样仅在曲线首次穿越 target 时画——从未达到目标则不画)。竖线与横线在曲线穿越点 正好 相交,时间轴 + 温度轴双向读数对齐。同 helper 同色方案也用于 cooking 页实时 _TempGraphPainter(详见 §烹饪 Action #4 温度图)。⚠️ 62621923 / TAPD #1003117 Layer B 起接进第 3 个 session-complete marker(蓝):钉在 endTime 处(曲线末端),由同一 drawCookGraphTimeMarker helper 绘制;Per Liang 2026-06-02 cook 达到目标后继续录制到 4-条件 session-complete 状态机收尾(详见 状态模型 §烹饪会话),所以 session-complete 节点与 green target 节点不再重合,三色节点(amber 早警 / green target / blue complete)一一独立。
IconButton.onPressed → Navigator.pop(context) → 回到烹饪日志列表TextField.onChanged: (_) => _saveNotes() —— 每次按键都触发持久化TextField.onChanged
→ _saveNotes()
→ cookLogProvider.notifier.updateNotes(session.id, _notesController.text.trim())
→ SharedPreferences 持久化
OutlinedButton.onPressed: _confirmAndDeleteOutlinedButton.onPressed → _confirmAndDelete
→ showDialog<bool>(...)
→ 用户确认 → cookLogProvider.notifier.deleteSession(session.id) → SharedPreferences 持久化
→ Navigator.pop(context)
Navigator.pop(ctx, bool)watch:temperatureUnitProvider(°C/°F 切换重建以更新数字)。read:cookLogProvider.notifier(写笔记 + 删除)。
会话本身(widget.session)是构造函数注入的快照 —— 不订阅 cookLogProvider,因此其他地方修改这条会话不会自动反映在本页(笔记修改通过本地 _notesController + _saveNotes 闭环)。删除后立即 pop,不存在「页面看到自己被删除」的歧义。
无显著差异。
onChanged: (_) => _saveNotes() 每次输入都触发 cookLogProvider.notifier.updateNotes → 持久化。Debounce 到失焦或 500ms 后写更合理。widget.session 是 stale snapshot:构造函数注入后不订阅 Provider,若同一会话在另一处被改了笔记或状态,本页不会同步。当前没有这种竞争场景,但未来若有 cloud sync 会有歧义。