171 lines
9.3 KiB
Markdown
171 lines
9.3 KiB
Markdown
# K2 客户端第二批:分类 + 观看记录 + 收藏列表 + 下载授权管理
|
||
|
||
> 依据:`docs/plans/INBOX.md` 2026-10-17 `[待处理] K2` 条目。
|
||
> 客户端基线:`ReelShort` `develop` / `00280ca`。
|
||
> 接口唯一权威:`FruitServer/docs/api-phase1.md` §0、§1.3、§1.5、§1.6。
|
||
> 本批只做 K2,完成后停下写回执,不连做 K3/K4。
|
||
|
||
## 一、范围与完成口径
|
||
|
||
### K2-A 分类
|
||
|
||
- 接 `GET /app/categories`,分类 id 全程按字符串处理。
|
||
- 发现页分类条改为服务端分类;保留现有分类条样式。
|
||
- 分类内容只从 `GET /app/discover/feed` 的 `sections[]` 中读取
|
||
`code == "category-{id}"` 的分区,不在客户端拼装分类请求。
|
||
- 分类在发现 feed 中没有对应分区时显示空态。
|
||
- 保留 `hot` / `new` 入口与既有样式;其内容同样只按发现 feed 中对应 `code`
|
||
分区读取,缺失时显示空态。
|
||
|
||
### K2-B 观看记录页
|
||
|
||
- 接 `GET /app/watch/recent?limit=20`、`DELETE /app/watch/progress/{dramaId}`、
|
||
`DELETE /app/watch/progress`。
|
||
- 最近记录先去重 `dramaId`,再按 id 补 `GET /app/dramas/{id}` 卡片数据。
|
||
- 详情补取并发上限 4,同页按 `dramaId` 只请求一次。
|
||
- 单条详情失败只影响该条:显示“加载失败”占位与单项重试,其余记录正常渲染。
|
||
- 独立“观看记录”页:封面、剧名、集号、进度、更新时间;点击详情并续看;
|
||
单条删除、清空均有二次确认;删除采用乐观更新,失败回滚并提示。
|
||
- 加载 / 空 / 失败可重试三态;未登录使用现有登录引导。
|
||
|
||
### K2-C 收藏列表页
|
||
|
||
- 复用 `GET /app/favorites`、`DELETE /app/favorites/{dramaId}`、
|
||
`POST /app/favorites/toggle`,不增加分页参数。
|
||
- 独立“我的收藏”页,复用卡片数据模型与列表卡片视觉;点击进详情。
|
||
- 取消收藏采用乐观更新,失败回滚并提示。
|
||
- 加载 / 空 / 失败可重试三态;未登录使用现有登录引导。
|
||
|
||
### K2-D 下载授权管理
|
||
|
||
- 接契约 §1.6 全部 8 个接口:
|
||
`GET /app/downloads/policy`、`PUT /app/downloads/settings`、
|
||
`POST /app/downloads`、`GET /app/downloads`、
|
||
`GET /app/downloads/{episodeId}/url`、`POST /app/downloads/{episodeId}/progress`、
|
||
`DELETE /app/downloads/{episodeId}`、`DELETE /app/downloads`。
|
||
- 详情页与播放页增加下载入口;后端拒绝时直接展示后端 `message`。
|
||
- 独立“我的下载”页:策略卡、授权列表、单条删除、清空、仅 Wi-Fi、最高清晰度。
|
||
- 授权状态与任务状态完全使用后端字符串,客户端不新增状态枚举、不自行判断付费/配额。
|
||
- 加载 / 空 / 失败可重试三态;未登录使用现有登录引导。
|
||
- 明确不做:文件分片落盘、断点续传、离线播放、`licenseKey` 本地校验。
|
||
`url` 与 `progress` 本批只提供并测试 API 方法,不驱动实际下载任务。
|
||
|
||
## 二、实施顺序与 TDD
|
||
|
||
1. 基线:从 `ReelShort/develop` 建 `feature/flutter-k2-library`。
|
||
2. K2-A:先写分类解析、`category-{id}` 映射、无分区空态和筛选状态测试,
|
||
确认红灯后实现;再跑该块门禁。
|
||
3. K2-B:先写控制器测试覆盖详情去重、并发上限 4、单条失败降级、
|
||
删除/清空乐观更新与回滚;确认红灯后实现 API、repository、controller、页面;
|
||
再跑门禁。
|
||
4. K2-C:先写独立收藏页取消收藏失败回滚、三态与登录引导测试,
|
||
确认红灯后实现页面与导航;再跑门禁。
|
||
5. K2-D:先写 DTO 字符串 ID/时间解析、策略/列表渲染、授权失败透传、
|
||
设置更新、删除/清空和未登录测试;确认红灯后实现;
|
||
`ApiClient` 仅补契约所需的 `PUT` 能力;再跑门禁。
|
||
6. 三份 ARB 一次补齐并生成 l10n;全量跑
|
||
`dart analyze lib test`、`flutter test`、`flutter build apk --debug`。
|
||
7. 门禁全绿后合并回 `develop` 并 push;不动 `main`。
|
||
8. 在 `PROGRESS.md` 与 INBOX K2 条目追加回执;真机验证交用户执行。
|
||
|
||
## 三、预计影响文件
|
||
|
||
### 数据层
|
||
|
||
- 修改:`lib/core/data/remote/api_client.dart`(补 `put`)
|
||
- 修改:`lib/core/data/models/watch_progress.dart`(补 `updatedAt`)
|
||
- 修改:`lib/core/data/remote/watch_api.dart`(补清空)
|
||
- 修改:`lib/core/data/repositories/watch_history_repository.dart`(补清空)
|
||
- 新增:`lib/core/data/models/content_category.dart`
|
||
- 新增:`lib/core/data/remote/category_api.dart`
|
||
- 新增:`lib/core/data/repositories/category_repository.dart`
|
||
- 新增:`lib/core/data/services/category_controller.dart`
|
||
- 新增:`lib/core/data/models/watch_record.dart`
|
||
- 新增:`lib/core/data/services/watch_records_controller.dart`
|
||
- 新增:`lib/core/data/models/download_policy.dart`
|
||
- 新增:`lib/core/data/models/download_license.dart`
|
||
- 新增:`lib/core/data/remote/download_api.dart`
|
||
- 新增:`lib/core/data/repositories/download_repository.dart`
|
||
- 新增:`lib/core/data/services/download_controller.dart`
|
||
|
||
### 页面与共享 UI
|
||
|
||
- 修改:`lib/app.dart`(新仓库/控制器注入)
|
||
- 修改:`lib/core/widgets/auth_gate.dart`(页面级登录引导复用)
|
||
- 修改:`lib/pages/discover/discover_logic.dart`
|
||
- 修改:`lib/pages/discover/discover_view.dart`
|
||
- 修改:`lib/pages/home/home_view.dart`(我的页入口接线)
|
||
- 修改:`lib/pages/mine/mine_view.dart`(观看记录、收藏、下载入口)
|
||
- 修改:`lib/pages/drama_detail/drama_detail_view.dart`(下载入口)
|
||
- 修改:`lib/pages/player/player_view.dart`(当前集下载入口)
|
||
- 新增:`lib/pages/watch_records/watch_records_binding.dart`
|
||
- 新增:`lib/pages/watch_records/watch_records_view.dart`
|
||
- 新增:`lib/pages/favorites/favorites_binding.dart`
|
||
- 新增:`lib/pages/favorites/favorites_view.dart`
|
||
- 新增:`lib/pages/downloads/downloads_binding.dart`
|
||
- 新增:`lib/pages/downloads/downloads_view.dart`
|
||
- 视复用需要新增列表卡片/状态组件,预计位于 `lib/core/widgets/` 或各页面 `widgets/`。
|
||
|
||
### 文案
|
||
|
||
- 修改:`lib/l10n/app_en.arb`
|
||
- 修改:`lib/l10n/app_zh.arb`
|
||
- 修改:`lib/l10n/app_id.arb`
|
||
- 重新生成:`lib/l10n/app_localizations*.dart`
|
||
|
||
### 测试
|
||
|
||
- 修改:`test/catalog/catalog_controller_test.dart` 及分类筛选相关测试
|
||
- 修改:`test/discover/discover_logic_test.dart`
|
||
- 修改:`test/mine/mine_logic_test.dart`
|
||
- 修改:`test/library/favorite_controller_test.dart`
|
||
- 新增:分类 API/控制器与 section 映射测试
|
||
- 新增:观看记录 API、并发加载、单项降级、删除/清空回滚和页面三态测试
|
||
- 新增:收藏独立页、取消收藏回滚、三态和登录引导测试
|
||
- 新增:下载 DTO/API/controller/page 测试
|
||
- 新增:未登录 `AuthGate` 页面测试
|
||
|
||
## 四、契约缺口(本批登记,不改契约/后端)
|
||
|
||
1. `GET /app/watch/recent` 未返回剧名与封面,客户端只能先取最近记录,
|
||
再对去重后的 `dramaId` 调详情补齐卡片;代价是 N+1 请求。
|
||
建议后续在 `ProgressRespVO` 补卡片字段(需 specs 负责人改契约)。
|
||
2. `GET /app/favorites` 没有分页参数并返回全量数组,与
|
||
`TC-RECORD-04` 的“分页正确”不一致。本批按全量列表实现,
|
||
不自造 `page/size`。
|
||
3. `api-phase1.md` 没有搜索接口,本批不做搜索,也不以本地模糊匹配冒充搜索接口。
|
||
|
||
## 五、风险与控制
|
||
|
||
1. 记录页 N+1 详情请求可能放大流量和延迟:严格去重、并发上限 4、页内缓存,
|
||
单项失败降级,不在失败后自动无限重试。
|
||
2. 页面销毁时异步详情仍可能返回:controller 的 `notify` 做 disposed 保护,
|
||
不把迟到结果写回已退出页面。
|
||
3. `updatedAt` 为后端 `LocalDateTime` 字符串,解析失败只能显示占位,
|
||
不能让整条记录解析失败。
|
||
4. 下载契约里授权与任务状态均为字符串,客户端只原样展示/映射现有文案,
|
||
不根据未知值猜测业务状态。
|
||
5. 下载地址字段 `playUrl` 后端当前未填充,本批不做实际下载;不能据此宣称
|
||
“可离线播放”。
|
||
6. 本机可能缺少 Android SDK,`flutter build apk --debug` 若失败将保留原始输出,
|
||
回执标记“未验证”,不静默跳过。
|
||
7. 真机/模拟器可达性由用户验证;开发机 `curl` 不作为设备证据。
|
||
|
||
## 六、待确认(不阻塞本批)
|
||
|
||
1. 发现页 `hot` / `new` 入口保留,但当前后端 `discoverFeed()` 只生成
|
||
`category-{id}` 分区。若后续要展示热门/最新内容,需要后端在发现 feed 下发
|
||
对应分区;在此之前按契约显示空态。
|
||
2. 收藏分页与观看记录卡片字段待契约负责人后续补足;本批按 INBOX 降级方案执行。
|
||
3. 下载真实落盘、断点续传与离线播放需要存储、权限、加密播放方案,另立批次。
|
||
|
||
## 七、完成定义
|
||
|
||
- 四块均有“红 → 绿”测试证据。
|
||
- `dart analyze lib test` 零告警,`flutter test` 全过。
|
||
- `flutter build apk --debug` 通过,或保留缺 SDK 的原始失败输出并标记未验证。
|
||
- 三语言 ARB 齐全且生成物已更新。
|
||
- 独立记录、收藏、下载页和分类条均接契约接口;未登录入口可完成登录引导。
|
||
- 不改 `main`、不改 specs、不改 FruitServer 后端、不做搜索。
|
||
- `PROGRESS.md` 与 INBOX K2 回执包含验证步骤、预期结果、提交号与原始门禁输出。
|