From 698bb78aebc4f410a864d3d3fd1da0bc5fd82726 Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Sat, 17 Oct 2026 14:50:51 +0800 Subject: [PATCH] =?UTF-8?q?docs(plans):=20=E8=AE=B0=E5=BD=95=20K2=20?= =?UTF-8?q?=E5=AE=9E=E6=96=BD=E4=B8=8E=E9=AA=8C=E6=94=B6=E5=9B=9E=E6=89=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/plans/2026-10-17-K2.md | 170 ++++++++++++++++ docs/plans/INBOX.md | 82 +++++++- docs/plans/PROGRESS.md | 382 ++++++++++++++++++++++++++++++++++++ 3 files changed, 633 insertions(+), 1 deletion(-) create mode 100644 docs/plans/2026-10-17-K2.md diff --git a/docs/plans/2026-10-17-K2.md b/docs/plans/2026-10-17-K2.md new file mode 100644 index 0000000..9b49d76 --- /dev/null +++ b/docs/plans/2026-10-17-K2.md @@ -0,0 +1,170 @@ +# 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 回执包含验证步骤、预期结果、提交号与原始门禁输出。 diff --git a/docs/plans/INBOX.md b/docs/plans/INBOX.md index 8e42479..ea73a05 100644 --- a/docs/plans/INBOX.md +++ b/docs/plans/INBOX.md @@ -20,7 +20,7 @@ --- -## [待处理] 2026-10-17 | K2 客户端第二批:分类 + 观看记录 + 收藏列表 + 下载授权(A3/A5 剩余)+ UI +## [已处理·待用户验收] 2026-10-17 | K2 客户端第二批:分类 + 观看记录 + 收藏列表 + 下载授权(A3/A5 剩余)+ UI **用户指令(2026-10-17)**:「现在先做客户端 对接相关接口 及ui 严格执行specs 内的要求」。 @@ -149,6 +149,86 @@ > **用户裁定(2026-10-17)**:**先按现状契约执行,上述缺口后期再补**。本批不得因缺口停工,也不得临时改后端或自造接口;按第二节的降级方案实现,缺口留到后续批次。 +### 七、Codex 回执(2026-10-17) + +**状态**:K2-A/B/C/D 代码、自动化测试、Android debug 构建与 develop 推送已完成; +真机/模拟器侧业务验证**未验证**,按红线交用户执行。K3/K4 未开始。 + +**提交** + +``` +feature: cc4d7c5a9dc6a4f6f0565a32503cce5973af703c +merge: 45f5f25640a274edb51bd90b3b5e52c43ba9d9cd +branch: feature/flutter-k2-library -> develop(--no-ff,已 push,feature 已删除) +main: 未改动 +``` + +**已接真实契约数据** + +- 发现页分类:`GET /app/categories` + `GET /app/discover/feed`; + 服务端分类只匹配 `category-{id}`,无分区显示空态。 +- 独立观看记录页:`GET /app/watch/recent?limit=20`、按 dramaId 去重并发上限 4 补详情、 + `DELETE /app/watch/progress/{dramaId}`、`DELETE /app/watch/progress`。 +- 独立我的收藏页:`GET /app/favorites`、`POST /app/favorites/toggle`、 + `DELETE /app/favorites/{dramaId}`。 +- 我的下载页:§1.6 全部 8 个 `/app/downloads*` 接口;详情页/播放页下载入口调用 + `POST /app/downloads`,拒绝时直接展示后端 `message`。 +- 三页面均为加载 / 空 / 失败可重试三态;未登录显示登录引导。 + +**仍本地或未做** + +- 搜索未做:契约没有搜索接口。 +- 文件分片落盘、断点续传、离线播放、`licenseKey` 本地校验未做;本批只交付授权与状态管理。 +- 点赞/评论仍沿用既有本地状态,属 K3,不在本批。 +- 发现 feed 当前只下发 `category-{id}`;若后端没有 `hot`/`new` 分区,保留的入口显示空态。 +- 收藏接口仍返回全量数组,本批未发送 `page/size`。 + +**门禁原始输出** + +``` +$ dart analyze lib test +Analyzing lib, test... +No issues found! + +$ flutter test +00:11 +220 ~1: All tests passed! + +$ flutter build apk --debug +Running Gradle task 'assembleDebug'... 2,377ms +✓ Built build/app/outputs/flutter-apk/app-debug.apk +``` + +`~1` 是既有真实后端联调用例因本机 8081 服务未启动而按设计跳过,不是失败。 +首次冷构建也成功,耗时 `705.7s`;最终修复后缓存构建 `2,377ms`。 + +**用户验证步骤与预期** + +1. 在 ReelShort 执行 `git checkout develop && git pull origin develop`,确认 HEAD 为 + `45f5f25`;后端 8081 已启动,手机与开发机在同一局域网。 +2. 取局域网地址并运行:`IP=$(ipconfig getifaddr en0)`, + `flutter run -d --dart-define=API_BASE_URL=http://$IP:8081`。 + 预期:App 启动、首页/发现能加载;地址必须按当前网络重新获取。 +3. 打开发现页:分类条应出现 `/app/categories` 返回的分类。选择一个有内容分类, + 预期显示 discover feed 对应 `code=category-{id}` 的剧;选择无分区分类显示空态。 +4. 播放任意免费集约 10 秒后返回,进入“我的 → 观看记录”。 + 预期:出现该剧封面/剧名/集号/进度/更新时间;即使该剧不在首页分区也能显示。 + 单条删除先立即消失;断网重试删除时,记录应恢复并提示失败。清空应先弹二次确认。 +5. 在详情或播放页收藏一部剧,进入“我的 → 我的收藏”。 + 预期:卡片来自服务端;点粉色收藏按钮取消后立即消失;断网取消应恢复卡片并提示失败。 +6. 登录后在详情页/播放页点下载入口。 + 预期:成功时提示“下载授权已就绪”;付费、未解锁或配额满时,直接出现后端 `message`。 + 进入“我的 → 下载”,预期策略卡显示剩余配额/授权天数/`expirePolicyText`; + 列表显示后端 `status`、`taskStatus`、`progressPercent`、到期时间; + 仅 Wi-Fi、清晰度、单删、清空可操作。 +7. 退出登录后分别进入观看记录、我的收藏、我的下载。 + 预期:三页都显示登录引导,不显示网络错误或白屏。 + +**证据口径** + +- 以上设备侧步骤尚未执行,因此真机/模拟器验证统一标记「未验证」。 +- 没有用开发机 `curl` 冒充设备可达证据。 +- 本批不包含实际文件下载,因此不能据此验收“离线播放”。 + --- ## [已处理] 2026-10-17 | 三库全量拉取 + `main` → `develop` 同步(Trae 执行,无代码改动) diff --git a/docs/plans/PROGRESS.md b/docs/plans/PROGRESS.md index 9149b9f..793c2f0 100644 --- a/docs/plans/PROGRESS.md +++ b/docs/plans/PROGRESS.md @@ -489,3 +489,385 @@ $ pgrep -fl "flutter_tools|xcodebuild|k1v_poller" - 动作 3 那次是**真实的设备侧输出且全过**,但随后两次执行失败(一次 VM service 未 attach、一次构建产物缺失), 所以在用户重跑之前**不把它当作最终结论**;它作为历史记录保留在这里。 - 我**没有**用任何"开发机 curl"作为设备可达证据。 + +--- + +## 2026-10-17 K2:分类 + 观看记录 + 收藏列表 + 下载授权管理 + +### 动作 1:按 INBOX 指定顺序读取规范与契约 + +叙述:开工前先完整核对 INBOX K2 条目、项目约束、Git 流程、接口 §0/§1.3/§1.5/§1.6, +再读 A3/A5、CONTENT/RECORD 用例与测试计划。当前没有启动客户端构建,也没有改业务代码。 + +``` +$ sed -n '1,260p' docs/plans/INBOX.md +# INBOX — 给 Codex 的指令队列(FruitServer 仓库内) +## [待处理] 2026-10-17 | K2 客户端第二批:分类 + 观看记录 + 收藏列表 + 下载授权(A3/A5 剩余)+ UI +本批只做 K2,做完停下写回执,不要连做 K3/K4。 +接口只认 FruitServer/docs/api-phase1.md §1.3 / §1.5 / §1.6 + +$ sed -n '1,260p' /Users/jianghaifeng/Desktop/ReelShort/AGENTS.md +# 水果短剧(FruitShorts)— Codex 项目上下文 +## 强制约束(不可违反) +## 自主执行原则(Autonomy — 最高优先级) + +$ sed -n '1,340p' /Users/jianghaifeng/Desktop/ReelShort/CODING_STANDARDS.md +## 3. Dart / Flutter(ReelShort) +TDD 强制:先写测试(红灯)→ 实现(绿灯)→ 重构 +门禁:dart analyze lib test 零告警 + flutter test 全过 + +$ sed -n '1,300p' /Users/jianghaifeng/Desktop/ReelShort/GIT_WORKFLOW.md +## 一、分支模型(Git Flow) +feature/*:具体功能开发,来源 develop +合并一律 --no-ff(禁用 fast-forward) + +$ sed -n '1,64p;150,158p;186,222p' docs/api-phase1.md +## 0. 通用约定 +所有 ID 字段(主键与外键)在 JSON 里都是字符串 +### 1.3 内容浏览(已实现) +GET /app/categories | 分类列表 +### 1.5 观看记录与收藏(已实现) +GET /app/watch/recent?limit=20 | 最近观看 +DELETE /app/watch/progress/{dramaId} | 删除某剧记录 +DELETE /app/watch/progress | 清空记录 +### 1.6 离线下载(已实现) +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 + +$ sed -n '1,90p' /Users/jianghaifeng/Desktop/ReelShort/docs/plans/codex-研发任务清单.md +- A3 内容(03):首页 feed、发现 feed、分类、详情(一次请求渲染详情页)、搜索。 +- A5 记录/收藏(05):观看记录、最近观看、收藏切换与列表、下载授权。 + +$ sed -n '1,135p' /Users/jianghaifeng/Desktop/ReelShort/docs/16-测试用例库.md +TC-CONTENT-09 | 分类题材 | 有分类 | 查看分类 | 分类列表正确 | P2 +TC-RECORD-01 | 观看历史 | 有播放 | 查看历史 | 按时间倒序,可删除 | P0 +TC-RECORD-03 | 取消收藏 | 已收藏 | 取消 | 状态反转 | P0 +TC-RECORD-04 | 收藏列表 | 有收藏 | 查看 | 分页正确 | P1 +TC-RECORD-09 | 历史清空 | 有历史 | 清空 | 全部清空 | P2 + +$ sed -n '1,100p' /Users/jianghaifeng/Desktop/ReelShort/docs/09-测试计划.md +单元测试 | Dart 核心类 | flutter test | 核心模块 ≥80% +UI 测试 | 关键页面 | Flutter widget test | 核心页面 +``` + +解读:K2 范围、TDD 顺序、接口白名单、三语言文案、三态、登录闸、门禁与设备验证边界均已确认。 +搜索没有契约接口,本批不做;收藏分页和观看记录卡片字段按 INBOX 的降级方案处理。 + +### 动作 2:只读核对两个仓库基线与客户端现状 + +叙述:确认客户端从干净 `develop` 开工,并核对现有网络层、记录/收藏实现和页面入口, +用于计划中的真实文件清单。 + +``` +$ git status --short --branch && git log -5 --oneline --decorate +## develop...origin/develop +00280ca (HEAD -> develop, origin/develop) merge: 同步 main 的作者标识提交到 develop +84a1f58 test(client): 新增设备侧集成测试(真机跑通后端可达性) +d7eff4c feat(client): 对接详情/播放/进度续看/收藏(K1 看剧闭环)+ 三态 UI + +$ git status --short --branch && git log -5 --oneline --decorate # FruitServer +## develop...origin/develop +4118efd (HEAD -> develop, origin/develop) docs(inbox): 按 specs 补全 K2 执行规范与门禁 +096e90c docs(inbox): 记录用户裁定——K2 先按现状契约执行,契约缺口后期再补 +582453f docs(inbox): 下发 K2 客户端第二批(分类/记录/收藏/下载授权 + UI) + +$ find lib -maxdepth 4 -type f | sort +lib/core/data/remote/catalog_api.dart +lib/core/data/remote/library_api.dart +lib/core/data/remote/watch_api.dart +lib/pages/discover/discover_view.dart +lib/pages/mine/mine_view.dart +... +``` + +解读:两仓均无未提交改动。分类 API、下载 API/page/controller 不存在; +观看记录删除只有单条,没有清空;收藏数据层已有但无独立页面; +`ApiClient` 只有 GET/POST/DELETE,下载设置所需的 PUT 需最小补齐。 + +### 动作 3:写 K2 计划 + +叙述:先落计划再动业务代码,明确四块范围、实施顺序、影响文件、三个契约缺口、 +风险和待确认项。 + +``` +文件:docs/plans/2026-10-17-K2.md +章节:范围与完成口径 / 实施顺序与 TDD / 预计影响文件 / + 契约缺口 / 风险与控制 / 待确认 / 完成定义 +``` + +解读:后续实现按 K2-A → K2-B → K2-C → K2-D 推进;每块先红后绿并单独跑门禁。 +真机与 Android 构建结果按实际证据记录,缺失时明确标“未验证”。 + +### 动作 4:创建功能分支并跑存量基线门禁 + +叙述:客户端从 `develop` 创建任务指定分支;沙箱不允许写 `.git/index.lock`, +Git 与 Flutter 工具链缓存写操作按权限流程在受控环境执行。先确认存量门禁本身是绿的。 + +``` +$ git checkout -b feature/flutter-k2-library develop +Switched to a new branch 'feature/flutter-k2-library' +## feature/flutter-k2-library + +$ dart analyze lib test +Analyzing lib, test... +No issues found! + +$ flutter test +00:10 +188: All tests passed! +``` + +解读:客户端基线 188 个测试全过、静态检查零告警,可以开始 K2-A。 + +### 动作 5:K2-A 测试红灯 + +叙述:先新增分类模型/API/控制器的契约测试,覆盖雪花 ID 字符串、分类到 +`category-{id}` 分区映射、缺失分区空态、hot/new 入口、全量去重和失败重试。 + +``` +$ flutter test test/category/category_controller_test.dart +test/category/category_controller_test.dart:6:8: Error: Error when reading + 'lib/core/data/models/content_category.dart': No such file or directory +test/category/category_controller_test.dart:10:8: Error: Error when reading + 'lib/core/data/remote/category_api.dart': No such file or directory +test/category/category_controller_test.dart:11:8: Error: Error when reading + 'lib/core/data/repositories/category_repository.dart': No such file or directory +test/category/category_controller_test.dart:12:8: Error: Error when reading + 'lib/core/data/services/category_controller.dart': No such file or directory +00:00 +0 -1: Some tests failed. +``` + +解读:红灯原因符合预期,目标实现尚不存在。下一步实现分类数据层与控制器。 + +### 动作 6:K2-A 实现绿灯与门禁 + +叙述:实现 `ContentCategory`、`CategoryApi`、`CategoryRepository`、 +`CategoryController`,发现页改为读取 `/app/categories` 与 `/app/discover/feed`; +保留 For You / Hot / New 样式,服务端分类只匹配 `category-{id}`。 + +``` +$ flutter test test/category/category_controller_test.dart +00:00 +5: All tests passed! + +$ dart analyze lib test +Analyzing lib, test... +No issues found! + +$ flutter test +00:08 +191 ~1: All tests passed! +``` + +解读:分类块绿。`~1` 是既有真实后端联调用例因本机 8081 未启动而按设计跳过, +不是失败。分类 UI 仍保留 hot/new 入口;后端发现 feed 未下发对应分区时显示空态。 + +### 动作 7:K2-B 测试红灯 + +叙述:先固定观看记录页核心逻辑:`updatedAt` 解析、recent 按 dramaId 去重、 +详情并发上限 4、单条详情失败降级与单项重试、删除/清空乐观回滚、recent 失败态。 + +``` +$ flutter test test/watch/watch_records_controller_test.dart +test/watch/watch_records_controller_test.dart:11:8: Error: Error when reading + 'lib/core/data/services/watch_records_controller.dart': No such file or directory +test/watch/watch_records_controller_test.dart:23:3: Error: No named parameter + with the name 'updatedAt'. +test/watch/watch_records_controller_test.dart:49:21: Error: The getter + 'updatedAt' isn't defined for the type 'WatchProgress'. +00:00 +0 -1: Some tests failed. +``` + +解读:红灯符合预期,观看记录控制器与更新时间字段尚不存在。 + +### 动作 8:K2-B 实现与门禁 + +叙述:增加 `updatedAt`、观看记录清空 API/repository,新增独立 +`WatchRecordsController` 与 `WatchRecordsPage`。“我的 → 观看记录”已改为打开独立页。 +详情请求按 dramaId 去重、最多 4 个并发;单条详情失败显示占位与单项重试; +单删和清空先更新 UI,失败回滚并提示;清空有二次确认。 + +``` +$ flutter test test/watch/watch_records_controller_test.dart test/watch/watch_records_page_test.dart +00:00 +10: All tests passed! + +$ dart analyze lib test +Analyzing lib, test... +No issues found! + +$ flutter test +00:08 +201 ~1: All tests passed! +``` + +解读:K2-B 绿。`~1` 仍是既有真实后端联调用例跳过;本轮新增 10 个记录相关测试。 + +### 动作 9:K2-C 测试红灯 + +叙述:先补收藏取消失败的原位回滚测试,再新增独立收藏页的卡片、取消失败、 +空态、失败重试与未登录闸测试。 + +``` +$ flutter test test/library/favorite_controller_test.dart test/library/favorites_page_test.dart +test/library/favorite_controller_test.dart:80:8: Error: The setter 'failRemove' + isn't defined for the type 'InMemoryFavoriteRepository'. +test/library/favorites_page_test.dart:13:8: Error: Error when reading + 'lib/pages/favorites/favorites_page.dart': No such file or directory +test/library/favorites_page_test.dart:108:23: Error: The getter 'listCalls' + isn't defined for the type 'InMemoryFavoriteRepository'. +00:00 +0 -2: Some tests failed. +``` + +解读:红灯符合预期:独立收藏页不存在,测试仓库也还不能模拟删除失败。 + +### 动作 10:K2-C 实现与门禁 + +叙述:新增独立 `FavoritesPage` 和复用列表卡片,服务端列表三态齐全; +取消收藏采用乐观更新,失败时按原索引回滚;我的页增加“我的收藏”入口。 + +``` +$ flutter test test/library/favorite_controller_test.dart test/library/favorites_page_test.dart +00:00 +13: All tests passed! + +$ dart analyze lib test +Analyzing lib, test... +No issues found! + +$ flutter test +00:10 +207 ~1: All tests passed! +``` + +解读:K2-C 绿。收藏页按契约全量读取,不发送 `page/size`;真实后端联调用例仍按设计跳过。 + +### 动作 11:K2-D 测试红灯 + +叙述:先用 API 契约测试钉住 §1.6 全部 8 个下载接口与字符串 ID; +再用控制器测试固定策略/授权加载、后端 message 透传、设置回滚、删除和清空回滚。 + +``` +$ flutter test test/download/download_api_test.dart test/download/download_controller_test.dart +test/download/download_api_test.dart:7:8: Error: Error when reading + 'lib/core/data/remote/download_api.dart': No such file or directory +test/download/download_controller_test.dart:4:8: Error: Error when reading + 'lib/core/data/models/download_license.dart': No such file or directory +test/download/download_controller_test.dart:9:31: Error: Type + 'DownloadController' not found. +00:00 +0 -2: Some tests failed. +``` + +解读:红灯符合预期,下载模型、API、仓库与控制器尚未实现。 + +### 动作 12:K2-D 数据层与页面实现 + +叙述:实现下载策略/授权模型、8 个接口的 `DownloadApi`、仓库与控制器; +`ApiClient` 仅补契约需要的 `PUT`。新增“我的下载”页,展示策略、配额、 +授权/任务原始状态、进度、有效期,并提供仅 Wi-Fi、清晰度、单删和清空; +详情页与播放页接入真实授权申请。授权失败直接展示后端 `message`。 + +``` +$ flutter test test/download/download_api_test.dart test/download/download_controller_test.dart test/download/downloads_page_test.dart +00:00 +10: All tests passed! + +$ dart analyze lib test +Analyzing lib, test... +No issues found! + +$ flutter test +00:10 +219 ~1: All tests passed! +``` + +解读:K2-D 首轮绿。文件分片落盘、断点续传、离线播放、`licenseKey` 本地校验未做, +`url` 与 `progress` 只交付 API 方法;这些边界不会写成“已完成”。 + +### 动作 13:提交前边界审查(清晰度下拉修复) + +叙述:审查发现当后端策略 `maxQuality` 已是 `720P/1080P` 时, +下拉选项会重复同一值并触发 Flutter 断言。先补测试得到红灯,再去重选项; +同时处理退出后重新登录页面不刷新、登录闸文案覆盖观看记录/下载的问题。 + +``` +$ flutter test test/download/downloads_page_test.dart +Failed assertion: There should be exactly one item with +[DropdownButton]'s value: 720P. +Either zero or 2 or more [DropdownMenuItem]s were detected with the same value +00:01 +6 -1: Some tests failed. + +$ flutter test test/download/downloads_page_test.dart +00:00 +7: All tests passed! +``` + +解读:边界缺陷已由测试固定并修复,避免特定后端清晰度值导致下载页崩溃。 + +### 动作 14:最终门禁与 Android 构建 + +叙述:整理掉格式化造成的无关测试 diff 后,在 develop 合并前后都复跑门禁。 +首次 Android 构建因本机 Gradle 依赖经代理下载持续约 12 分钟,但最终成功; +修复后二次构建命中缓存(2.377 秒)。 + +``` +$ dart analyze lib test +Analyzing lib, test... +No issues found! + +$ flutter test +00:11 +220 ~1: All tests passed! + +$ flutter build apk --debug +Running Gradle task 'assembleDebug'... 705.7s +✓ Built build/app/outputs/flutter-apk/app-debug.apk + +$ flutter build apk --debug # 最终修复后 +Running Gradle task 'assembleDebug'... 2,377ms +✓ Built build/app/outputs/flutter-apk/app-debug.apk +``` + +解读:静态检查零告警、220 个测试通过;`~1` 是既有真实后端联调用例因本机未启动 +8081 服务按设计跳过。Android debug APK 构建通过。 + +### 动作 15:Git 提交、合并与推送 + +叙述:客户端从干净 develop 建功能分支,功能提交与 `--no-ff` 合并提交均使用 +项目规定作者。合并前确认 `origin/develop` 无新提交;合并后在 develop 复跑门禁, +再 push,最后删除已完成 feature 分支。未改 main。 + +``` +commit=cc4d7c5a9dc6a4f6f0565a32503cce5973af703c +author=Zhou Weidong <502333560@qq.com> +subject=feat(flutter): 接入分类记录收藏与下载授权 + +merge=45f5f25640a274edb51bd90b3b5e52c43ba9d9cd +author=Zhou Weidong <502333560@qq.com> +subject=merge: 合并 K2 客户端分类记录收藏与下载授权 + +$ git push origin develop +To http://git.reelshort2.com/jianghaifeng/ReelShort.git + 00280ca..45f5f25 develop -> develop + +$ git branch -d feature/flutter-k2-library +Deleted branch feature/flutter-k2-library (was cc4d7c5). +``` + +解读:客户端 develop 已与 origin/develop 对齐,工作区干净。 + +### 动作 16:真实数据与未验证边界 + +叙述:生产环境注入的发现分类、观看记录、收藏、下载授权均调用契约 HTTP 接口, +不再用本地演示目录补齐。由于设备侧验证归用户执行,本轮没有把任何开发机请求 +当作“设备可达”证据。 + +``` +已接生产 HTTP 链路: +- GET /app/categories + GET /app/discover/feed +- GET /app/watch/recent + DELETE /app/watch/progress/{dramaId} + DELETE /app/watch/progress +- GET /app/favorites + DELETE /app/favorites/{dramaId} + POST /app/favorites/toggle +- §1.6 全部 8 个 /app/downloads* 契约接口 + +仍未做: +- 搜索(契约无接口) +- 下载文件分片落盘 / 断点续传 / 离线播放 / licenseKey 本地校验 +- 真机 / 模拟器侧验证(未验证,由用户执行) +``` + +解读:功能代码和构建门禁已完成;设备网络、实际授权状态与 UI 交互需用户按回执步骤验证。