153 lines
7.5 KiB
Markdown
153 lines
7.5 KiB
Markdown
# 「随心」主题(Suixin Theme)任务清单(tasks)
|
||
|
||
> 说明:
|
||
>
|
||
> - 本清单基于 `spec_kit/SuixinTheme/plan.md` 拆分为可执行任务。
|
||
> - 执行过程中:完成一项就在对应条目打勾(`[x]`),并补充必要的实现备注/PR 链接(如有)。
|
||
> - **当本 tasks 全部完成后**,需要回到 `spec_kit/overview.md` 在 `SuixinTheme` 条目下标记“已完成编码(阶段性/全部)”。
|
||
|
||
## 0. 准备与基线确认
|
||
|
||
- [x] **T0.1 确认现有主题切换链路位置与文件**
|
||
- **涉及文件**:`client/components/home/ThemeModal.tsx`、`client/app/(app)/home.tsx`、`client/src/storage/appStorage.ts`
|
||
- **验收**:确认 `ThemeMode` 当前仅 `scenery/color`,并确认 `Home` 背景分支逻辑位置(方便插入 `suixin` 分支)
|
||
|
||
- [x] **T0.2 确认用户画像可在 Home 获取**
|
||
- **涉及文件**:`client/src/storage/appStorage.ts`、`client/src/features/userProfileScoring/*`
|
||
- **验收**:`getUserProfileScoring()` 在 Home 已可读到 `stage/need/emotion_score/profile_confidence/profile_answered`
|
||
|
||
## 1. 数据与存储层改造(ThemeMode + suixin state)
|
||
|
||
- [x] **T1.1 扩展 `ThemeMode` 枚举支持 `suixin`**
|
||
- **涉及文件**:`client/src/storage/appStorage.ts`(类型 + `getThemeMode/setThemeMode` 兼容)
|
||
- **要点**:
|
||
- 新类型:`'scenery' | 'color' | 'suixin'`
|
||
- `getThemeMode()` 读取到未知值时回退 `scenery`(保持兼容)
|
||
- **验收**:TypeScript 编译无类型报错;旧存储值仍可正常读取
|
||
|
||
- [x] **T1.2 新增本地存储:`ui.theme.suixin.state`**
|
||
- **涉及文件**:`client/src/storage/appStorage.ts`
|
||
- **新增内容**:
|
||
- `type SuixinThemeStateV1`
|
||
- `getSuixinThemeState()` / `setSuixinThemeState()`(建议)
|
||
- **验收**:能读写该 key;结构包含 `base_theme_id/seed/step_index/last_color`
|
||
|
||
## 2. 「随心」颜色算法模块(纯函数 + 可测试)
|
||
|
||
- [x] **T2.1 新增 `suixinTheme` 模块目录与色盘常量**
|
||
- **建议路径**:`client/src/features/suixinTheme/`
|
||
- **新增文件建议**:
|
||
- `palette.ts`:Base Theme(5)+ Neutral(1)常量
|
||
- `types.ts`:`BaseThemeId`、`SuixinThemeStateV1`(若不放在 storage)
|
||
- **验收**:色值与 `设计说明文档/个性化背景颜色推荐算法.md` 完全一致
|
||
|
||
- [x] **T2.2 实现 Base Theme 选择(Theme Picking)**
|
||
- **建议文件**:`client/src/features/suixinTheme/pickTheme.ts`
|
||
- **规则**(必须对齐文档 Hard Rules):
|
||
- `stage.unknown === 1` → `neutral`
|
||
- `need` 为空 `{}` → `neutral`
|
||
- 否则取 `Object.keys(need)[0]`,未知 key → `neutral`
|
||
- **验收**:不同画像输入下输出主题 id 符合预期
|
||
|
||
- [x] **T2.3 实现线性 `lerp`(仅线性,禁止 easing)**
|
||
- **建议文件**:`client/src/features/suixinTheme/colorMath.ts`
|
||
- **要求**:
|
||
- `hex ↔ rgb` 转换
|
||
- `lerpRgb(a,b,t)`:\(t\in[0,1]\) clamp
|
||
- 输出标准 `#RRGGBB`
|
||
- **验收**:插值边界 t=0/1 输出正确;中间值可复现、无跳段
|
||
|
||
- [x] **T2.4 实现 \(t\) 生成(切文案步进 + 往返波形)**
|
||
- **建议文件**:`client/src/features/suixinTheme/progress.ts`
|
||
- **要求**:
|
||
- `N=12` 可配置常量
|
||
- 采用往返波形,避免回卷突跳
|
||
- **验收**:连续 step_index 下 \(t\) 始终在 \([0,1]\),且相邻变化幅度稳定
|
||
|
||
- [x] **T2.5(可选增强)按 emotion/confidence 控制“动态增强开关”**
|
||
- **说明**:一期允许先不做亮度微扰,只实现“禁动态开关”
|
||
- **对齐点**:
|
||
- 文档:`emotion_score ≤ 0.2` 禁止任何扰动
|
||
- `emotion_score=null` 视为不确定,同样禁止扰动
|
||
- **验收**:低情绪/不确定时不触发增强分支(一期未实现亮度微扰,默认不启用任何扰动)
|
||
|
||
## 3. UI:ThemeModal 增加「随心」入口
|
||
|
||
- [x] **T3.1 ThemeModal 新增第三个主题卡片**
|
||
- **涉及文件**:`client/components/home/ThemeModal.tsx`
|
||
- **要点**:
|
||
- `ThemeMode` 类型同步为包含 `suixin`
|
||
- 新增 `ThemeCard`:`onPress={() => onSelect('suixin')}`
|
||
- 布局改为 3 卡可展示(`flexWrap`/调整 gap/尺寸),避免小屏溢出
|
||
- 预览图占位(可先复用 `theme_color.png` 或新增 `theme_suixin.png`)
|
||
- **验收**:弹窗可见第三项;选中态边框正确;无布局溢出
|
||
|
||
## 4. i18n:新增主题文案(TC/EN)
|
||
|
||
- [x] **T4.1 增加 `theme.suixin` 翻译键**
|
||
- **涉及文件**:`client/src/i18n/locales/all.json`
|
||
- **文案建议**:
|
||
- `zh-TW`: `隨心`
|
||
- `en`: `Ease`(语义化命名;如需改音译,后续可替换)
|
||
- **验收**:切换语言后 ThemeModal 的第三项标题正确显示,不出现缺失 key
|
||
|
||
## 5. Home:随心主题渲染 + 冷启动/切文案计算
|
||
|
||
- [x] **T5.1 Home 增加 `suixin` 分支并使用 `backgroundColor`**
|
||
- **涉及文件**:`client/app/(app)/home.tsx`
|
||
- **要点**:
|
||
- `themeMode === 'suixin'` 时,不渲染风景图
|
||
- 背景色来自 suixin 状态(`last_color`)或初始化计算结果
|
||
- **验收**:选择随心主题后背景变为算法输出色;切回风景/纯色逻辑不受影响
|
||
|
||
- [x] **T5.2 冷启动(进程级)计算并锁定 Base Theme**
|
||
- **涉及文件**:`client/app/_layout.tsx`(或新增全局单例模块)、`client/app/(app)/home.tsx`
|
||
- **要点**:
|
||
- 生成一次 `boot_id`(仅内存)用于判断“本次进程首次进入 Home”
|
||
- 首次进入 Home 且 theme=suixin:根据画像选 `base_theme_id` 并初始化 `seed/step_index/last_color`
|
||
- 写入 `ui.theme.suixin.state` 持久化
|
||
- **验收**:同一次运行内多次进入 Home 不重复“冷启动重算”;重启 App 后会重算一次
|
||
|
||
- [x] **T5.3 切换文案时更新 suixin 颜色(不跨主题)**
|
||
- **涉及文件**:`client/app/(app)/home.tsx`
|
||
- **要点**:
|
||
- 在 `triggerNextContent` 切换 index 后:若 theme=suixin,`step_index += 1` → 计算 \(t\) → `lerp` 得到新 `last_color`
|
||
- 持久化更新 state
|
||
- **验收**:上滑切下一条文案时背景色小幅变化;Base Theme 不变(同一色系内变化)
|
||
|
||
## 6. 收藏背景记录兼容
|
||
|
||
- [x] **T6.1 收藏逻辑兼容 suixin**
|
||
- **涉及文件**:`client/app/(app)/home.tsx`(`favItem.background` 写入)
|
||
- **规则**:
|
||
- `suixin` 与 `color` 一致:保存 `hex` 到 `background`
|
||
- **验收**:收藏后在 Favorites 列表缩略卡片可正确显示背景色
|
||
|
||
## 7. 测试与回归
|
||
|
||
- [x] **T7.1(推荐)为 suixin 模块补单测**
|
||
- **建议路径**:`client/src/features/suixinTheme/__tests__/`
|
||
- **覆盖点**:
|
||
- `stage.unknown=1` → neutral
|
||
- `need={}` → neutral
|
||
- `need={rest_balance:1}` → rest_balance
|
||
- 往返波形 \(t\) 的边界与范围
|
||
- `lerp` 边界与格式
|
||
- **验收**:测试通过,避免回归
|
||
|
||
- [x] **T7.2 手动验收(按 spec)**
|
||
- **验收清单**:
|
||
- ThemeModal:三主题可切换,选中态正确
|
||
- 随心:冷启动首次进入 Home 生效;切文案时同主题内变色
|
||
- Hard Rules:unknown / need 跳过 → Neutral
|
||
- 多语言:TC/EN 标题正确
|
||
- **备注**:已完成自动化回归(`vitest` + `tsc`);如需视觉确认可在模拟器/真机打开 ThemeModal 与 Home 做肉眼验收
|
||
|
||
## 8. 收尾:overview.md 标记
|
||
|
||
- [x] **T8.1 tasks 全部完成后更新 `spec_kit/overview.md`**
|
||
- **位置**:`## SuixinTheme` 条目
|
||
- **内容**:补充“已完成编码(全部)”与关键变更文件清单(可选)
|
||
- **验收**:overview 总览可读、可追踪
|
||
|