001project_wildgrowth/ios/WildGrowth/COMPLETION_迭代_审查报告.md

85 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 完成页迭代方案 — 审查报告(禁止应用)
**审查对象**:左滑进完成页、右滑回最后一节;无顶部返回;无打字机金句;底部「回到我的内容」回到技能页 Tab。
**结论**:只做审查与完整代码输出,不修改仓库文件。
---
## 一、需求与方案对照
| 需求 | 方案 | 审查结论 |
|------|------|----------|
| 不想要点开页面导航栏的返回按钮 | 移除顶部导航栏和返回按钮,仅顶部留白 | ✅ 一致 |
| 右滑回到最后一个小节 | `.enableSwipeBack()` + `SwipeBackEnabler` 强制开启侧滑返回 | ⚠️ 见下文「侧滑返回」 |
| 最后小节左滑进完成页,右滑回最后小节 | 播放器最后一节挂 `LastPageSwipeModifier` 左滑 push完成页右滑 = 系统 pop | ✅ 一致 |
| 不要打字机金句 | 移除打字机区域 | ✅ 一致 |
| 底部「回到我的内容」回到技能页 Tab | 方案写的是 `navigationPath = NavigationPath()` | ❌ **逻辑错误**,见下 |
---
## 二、关键问题:底部按钮语义
**需求**:底部「回到我的内容」要回到**技能页 Tab**(即技能 Tab 根:课程列表)。
**方案中的实现**`handleReturnToRoot()` 里写的是 `navigationPath = NavigationPath()`,即清空**当前传入的 path**。
- 若从**技能 Tab**进入:传的是 `growthPath`,清空后 = 技能 Tab 根 ✅
- 若从**发现 Tab**进入:传的是 `homePath`,清空后 = **发现 Tab 根**,不会切到技能 Tab ❌
- 若从**我的 Tab**进入:传的是 `profilePath`,清空后 = **我的 Tab 根**,不会切到技能 Tab ❌
因此:**仅清空当前 path 无法满足「无论从哪个 Tab 进,都回到技能页 Tab」**。
**正确做法**:底部按钮应调用 **`navStore.switchToGrowthTab()`**(切到技能 Tab + 清空 `growthPath`),与当前线上 CompletionView 的「继续学习」一致。
- CompletionView 需保留 **`@EnvironmentObject var navStore`**
- 不需要为「回到我的内容」传入 **`@Binding var navigationPath`**(调用方无需改传参)
**完整代码中已按此修正**:底部按钮调用 `navStore.switchToGrowthTab()`,不传 `navigationPath`
---
## 三、侧滑返回SwipeBackEnabler
- 方案用 **`SwipeBackEnabler`**`UIViewControllerRepresentable`)在 `.background` 里查找 `navigationController` 并打开 `interactivePopGestureRecognizer`,以在隐藏导航栏时恢复右滑返回。
- **风险**`makeUIViewController` 返回的是一颗裸 `UIViewController()`,其 `navigationController` 在部分时机可能仍为 nil例如尚未挂到 NavigationStack 上),`DispatchQueue.main.async` 能缓解但无法完全保证。若遇真机偶发无效,可考虑:
-`updateUIViewController` 中轮询/延迟再取一次 `navigationController`,或
- 使用 `UINavigationController` 子类 / 注入方式保证拿到的必为当前栈。
- **结论**:实现可保留,建议在真机多场景(从三个 Tab 进入完成页后右滑)验证;若失效再加强时机或注入方式。
---
## 四、VerticalScreenPlayerView 与占位页
- 方案采用「**不使用占位页**,仅最后一节左滑手势 push 完成页」TabView 只渲染 `ForEach(allCourseNodes)`,不再多一页 `CompletionPlaceholderPage`
- **影响**
- 进入完成页**仅剩**「在最后一节左滑」这一种方式;「滑到下一空白页再进完成页」的路径被移除。
- 从完成页右滑或 dismiss 后,播放器不再存在「当前是占位页、需在 onAppear 里切回最后一节」的状态,可删除 `onAppear` 里对 `currentNodeId == "wg://completion"` 的处理。
- **与现有调用方**NoteTreeView / NoteListView 不传 `navigationPath``triggerCompletionNavigation` 里需 `guard let path = navigationPath else { return }`,从笔记进的播放器仍不会 push 完成页,行为不变。
---
## 五、CompletionView 视觉与接口
- **视觉**:从当前 3D 翻转卡片 + 打字机,改为「赛博印章」:圆环 + 未盖章「完」/ 盖章后「已完成的第 N 节」+ 底部「回到我的内容」。
- **接口**
- 保留:`courseId`, `courseTitle`, `completedLessonCount`
- 不增加 `@Binding var navigationPath`(底部用 `navStore.switchToGrowthTab()`)。
- 保留 `@EnvironmentObject var navStore`
- **调用方**GrowthView / ProfileView / DiscoveryView 的 `.completion` 分支**无需**新增参数,仍为三参构造。
---
## 六、审查结论汇总
| 项 | 结论 |
|----|------|
| 顶部去掉返回按钮 | ✅ 方案正确 |
| 右滑回最后一节 | ✅ 思路正确SwipeBackEnabler 需真机验证,偶发需加强时机 |
| 最后小节左滑进完成页 | ✅ 保留 LastPageSwipeModifier 即可 |
| 去掉打字机金句 | ✅ 方案正确 |
| 底部回到技能页 Tab | ❌ 方案用「清空当前 path」会错应用 `navStore.switchToGrowthTab()`,完整代码已改 |
| 调用方改动 | ✅ CompletionView 不需新参数VerticalScreenPlayerView 保持可选 `navigationPath`,笔记流不受影响 |
---
**完整代码见下(仅作交付,不写入仓库)。**