7.2 KiB
7.2 KiB
最终交付代码审查反馈(isFirstNodeInChapter 完全回滚版)
审查对象:您提供的「CompletionView 全量替换 + VerticalScreenPlayerView 仅替换 Struct」的最终交付代码,并已恢复 isFirstNodeInChapter 为含 .sorted { $0.order < $1.order } 的写法。
结论:仅反馈,不应用、不修改仓库内任何文件。
参数说明(白话)
| 说法 | 指什么 | 作用 |
|---|---|---|
| CompletionView 仍为 3 个参数 | 构造时仍是 (courseId, courseTitle, completedLessonCount) |
GrowthView / ProfileView / DiscoveryView 里已有 CompletionView(courseId: ..., courseTitle: ..., completedLessonCount: ...) 的调用不用改;替换成新 UI 后接口不变,不会报错。 |
| VerticalScreenPlayerView init 6 参 | 构造时仍是 (courseId, nodeId, initialScrollIndex?, navigationPath?, isLastNode?, courseTitle?) |
MapView / GrowthView / DiscoveryView / ProfileView 等传入的 6 个参数(或只传前几项、后几项用默认值)都不用改;只改播放器内部实现,调用方零改动。 |
应用后仅实现以下三点、且无多余修改
若您只做这两步:① 全量替换 CompletionView.swift;② 仅替换 VerticalScreenPlayerView.swift 里的 struct VerticalScreenPlayerView(保留同文件内 HeaderConfig、LessonPageView 等其余代码),则:
| # | 需求 | 是否由本交付代码实现 | 说明 |
|---|---|---|---|
| 1 | 播放器最后一个小节左滑进入完结页,从完结页右滑回到最后一个小节页 | ✅ 是 | 完结页作为 TabView 的最后一页内嵌在播放器内,左滑最后一节→完结页,右滑完结页→最后一节,无 push/pop。 |
| 2 | 完结页的 UI,以及从接口/数据获取「共完成多少个小节」 | ✅ 是 | 新 UI(粉紫勋章、点击点亮);数量来自 UserManager.shared.studyStats.lessons(应用内统计,通常由学习进度接口或本地完成逻辑更新)。 |
| 3 | 底部一个按钮,点击回到技能 Tab(我的课程列表) | ✅ 是 | 按钮「回到我的内容」仅调用 navStore.switchToGrowthTab(),切到技能 Tab。 |
其他没有任何多余修改:
- 只动 2 个文件:
CompletionView.swift(全量)、VerticalScreenPlayerView.swift(仅主 struct)。 - 不改动:CourseNavigation、MainTabView、MapView、ProfileView、DiscoveryView、GrowthView、NoteTreeView、NoteListView 等所有其他页面与类型;不增删导航枚举、不改 Tab 结构、不改地图/发现/个人/技能页逻辑。
- 完结页不再通过「占位页 + onChange push .completion」出现,而是作为播放器 TabView 最后一页展示,因此无需也不会去改各 Tab 的
navigationDestination(for: .completion)的写法(它们保留不动,只是从播放器内不再 push .completion)。
结论:应用本交付代码后,行为严格限于上述 1、2、3 三点,无其他多余修改。
一、isFirstNodeInChapter:与当前仓库 100% 一致 ✅
| 对比项 | 当前仓库实现 | 您提供的交付代码 | 结论 |
|---|---|---|---|
| 章节内节点 | 先找到包含 nodeId 的 chapter,再在该章内取 validNodes |
遍历每个 chapter,取 validNodes |
语义等价 |
| 排序 | chapter.nodes.filter { $0.status != .locked }.sorted { $0.order < $1.order } |
chapter.nodes.filter { $0.status != .locked }.sorted { $0.order < $1.order } |
✅ 完全一致 |
| 首节判定 | validNodes.first?.id == nodeId |
validNodes.first?.id == nodeId(在含该 node 的章内) |
✅ 完全一致 |
结论:章节判定逻辑已完全回滚到与当前仓库一致的写法(含 .sorted { $0.order < $1.order }),不会改变现有「按 order 的章节首节」展示行为。
二、loadMapData:无全局排序,与当前一致 ✅
- 当前仓库:
allCourseNodes = data.chapters.flatMap { $0.nodes }.filter { $0.status != .locked },无.sorted。 - 交付代码:
realNodes = data.chapters.flatMap { $0.nodes }.filter { $0.status != .locked },仅 UI 层items = realNodes.map { .lesson($0) }再append(.completion),无全局排序。
结论:数据顺序与当前一致,未引入按 order 的整课排序。
三、CompletionView:仅 UI 更新,接口兼容 ✅
| 项目 | 说明 |
|---|---|
| 构造参数 | 仍为 (courseId, courseTitle, completedLessonCount),GrowthView/ProfileView/DiscoveryView 等处已有调用无需改 |
| 依赖 | 仍使用 @EnvironmentObject private var navStore: NavigationStore |
| 按钮 | 「回到我的内容」仅调用 navStore.switchToGrowthTab(),未调用 dismiss() |
| 说明 | 在统一分页方案下,完结页作为 TabView 最后一页内嵌展示,无 push 栈,不调用 dismiss() 是正确行为 |
结论:可全量替换 CompletionView.swift,仅 UI 从「翻牌 + 打字机」改为「粉紫勋章 + 点击点亮」,对外接口与行为符合预期。
四、VerticalScreenPlayerView:仅替换 Struct,其余保留 ✅
| 项目 | 结论 |
|---|---|
| init | 6 个构造参数完整保留(courseId, nodeId, initialScrollIndex?, navigationPath?, isLastNode?, courseTitle?),MapView/GrowthView 等调用方无需改 ✅ |
| PlayerItem | 枚举 .lesson(MapNode) / .completion 仅用于 UI 数据源,不参与完成数等业务逻辑 ✅ |
| allItems | 由 realNodes + 末尾 .completion 构成,无全局排序 ✅ |
| currentPositionProgress | 仅用 lesson 项计算,排除完结页,进度条正确 ✅ |
| 完结页展示 | 顶部进度条在 currentNodeId == "COMPLETION_PAGE" 时隐藏,逻辑正确 ✅ |
| LessonPageView | courseTitle: self.courseTitle ?? mapData?.courseTitle 可减少标题闪烁 ✅ |
| 错误态 | 保留加载失败 + 重试;交付代码中错误文案为 .foregroundColor(.gray),当前为 .inkSecondary,属风格差异,可酌情统一 |
| 合并范围 | 仅替换 struct VerticalScreenPlayerView { ... } 及其内部的 enum PlayerItem;必须保留同文件内 HeaderConfig、DuolingoProgressBar、CourseProgressNavBar、LessonPageView、LessonSkeletonView 等所有其他类型,不得整文件覆盖 ✅ |
五、对其他页面的影响
- CourseNavigation、MainTabView、MapView、ProfileView、DiscoveryView、GrowthView 等无需因本交付代码而改动。
- 调用方仍按现有方式传入 6 参(含
navigationPath?、isLastNode、courseTitle);完结页由 TabView 内嵌展示,不再依赖 push.completion或占位页onChange。
六、审查结论汇总
| 项目 | 结论 |
|---|---|
| isFirstNodeInChapter | 已完全回滚为含 .sorted { $0.order < $1.order } 的写法,与当前仓库 100% 一致 ✅ |
| loadMapData | 无全局排序,与当前一致 ✅ |
| CompletionView | 仅 UI 更新,可全量替换 ✅ |
| VerticalScreenPlayerView | 仅替换主视图 Struct,保留同文件其余代码;逻辑与展示符合「逻辑回滚 + 统一分页」目标 ✅ |
| 其他页面 | 无需改动,零影响 ✅ |
未对仓库内任何文件进行修改。