chore: checkpoint current milestone work
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
---
|
||||
phase: 04-reader-capabilities
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift
|
||||
- Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift
|
||||
- Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift
|
||||
- Sources/RDReaderView/RDURLReaderController.swift
|
||||
autonomous: true
|
||||
requirements:
|
||||
- COMP-01
|
||||
user_setup: []
|
||||
must_haves:
|
||||
truths:
|
||||
- native text pages remain rendered through the existing `RDEPUBReaderController` + `RDReaderView` shell.
|
||||
- no new page-turn container or parallel native reader shell is introduced.
|
||||
- `RDEPUBTextBook` remains the native reflowable backend contract.
|
||||
artifacts:
|
||||
- .planning/phases/04-reader-capabilities/04-01-SUMMARY.md
|
||||
key_links:
|
||||
- `RDEPUBReaderController.paginatePublication`
|
||||
- `RDEPUBReaderController.pageContentView`
|
||||
- `RDEPUBReaderController.restoreReadingLocation`
|
||||
---
|
||||
|
||||
<objective>
|
||||
把 Phase 3 的 native text backend 稳定接回现有 reader 主流程,让 `RDEPUBReaderController` 对 `RDEPUBTextBook` 路径的分页、展示、恢复行为更完整,但不修改 `RDReaderView`。
|
||||
|
||||
Purpose: 让 reader 主流程明确把 native reflowable path 当成正式 backend,而不是零散的特殊分支。
|
||||
Output: reader-controller/native-text integration cleanup with clearer state handoff and no changes to the page-turn container.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/04-reader-capabilities/04-RESEARCH.md
|
||||
@.planning/phases/04-reader-capabilities/04-PATTERNS.md
|
||||
@.planning/phases/03-page-metadata-pagination/03-RESEARCH.md
|
||||
@.planning/phases/03-page-metadata-pagination/03-VERIFICATION.md
|
||||
@Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift
|
||||
@Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift
|
||||
@Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift
|
||||
@Sources/RDReaderView/RDURLReaderController.swift
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 收敛 native text backend 的分页完成与展示入口</name>
|
||||
<files>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift</files>
|
||||
<read_first>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift, Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift</read_first>
|
||||
<action>整理 `paginatePublication`、`applyTextBook`、`finishPagination`、`currentVisibleLocation` 和 `restoreReadingLocation` 的 native text 行为,让 `RDEPUBTextBook` 路径拥有清晰的完成/恢复入口,必要时补充最小状态桥接,但不要改 `RDReaderView` 的翻页接口,也不要引入新的 reader shell。</action>
|
||||
<acceptance_criteria>
|
||||
- `RDEPUBReaderController` remains the single entry point for native text and web reading
|
||||
- text-book pagination completion and restore logic are explicit and internally coherent
|
||||
- no code moves page-turn logic into `RDEPUBTextBookBuilder` or `RDEPUBTextContentView`
|
||||
</acceptance_criteria>
|
||||
<verify>rg -n "paginatePublication|applyTextBook|finishPagination|restoreReadingLocation|currentVisibleLocation" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift</verify>
|
||||
<done>native text pagination is reconnected as a first-class reader backend.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 保持 page container 兼容并清理 native text 初始化入口</name>
|
||||
<files>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift, Sources/RDReaderView/RDURLReaderController.swift</files>
|
||||
<read_first>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift, Sources/RDReaderView/RDURLReaderController.swift</read_first>
|
||||
<action>确认并收敛 `pageContentView(readerView:pageNum:containerView:)`、TXT 入口和 native content view 配置路径,使 `RDReaderView` 继续只消费 UIView 页面内容而不用理解新的 page metadata。若需要暴露更多 page context,优先通过现有 content-view/controller 接口完成。</action>
|
||||
<acceptance_criteria>
|
||||
- `RDReaderView` does not gain native metadata-specific branching
|
||||
- `RDEPUBTextContentView` remains the native page presenter
|
||||
- TXT/native-text initialization path remains compatible with the same reader shell
|
||||
</acceptance_criteria>
|
||||
<verify>rg -n "pageContentView|RDEPUBTextContentView|RDURLReaderController|textBook" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/RDURLReaderController.swift Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift</verify>
|
||||
<done>reader presentation stays container-compatible while native text becomes a stable backend.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] `rg -n "paginatePublication|applyTextBook|finishPagination|restoreReadingLocation|currentVisibleLocation" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`
|
||||
- [ ] `rg -n "pageContentView|RDEPUBTextContentView|RDURLReaderController|textBook" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/RDURLReaderController.swift Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift`
|
||||
</verification>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/04-reader-capabilities/04-01-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,16 @@
|
||||
# 04-01 Summary
|
||||
|
||||
## Outcome
|
||||
|
||||
Wave 1 reconnected the native text backend as a first-class reader path inside the existing shell.
|
||||
|
||||
- `RDEPUBReaderController` now builds a real native snapshot from `RDEPUBTextBook` instead of leaving `activePages` / `activeChapters` empty
|
||||
- Native restore and current-location resolution now go through shared controller helpers instead of scattered text-book special cases
|
||||
- Native page turns update `RDEPUBReadingSession` with page/spine/chapter context, so reader state stays coherent with the visible page
|
||||
- `RDReaderView` remained unchanged; it still only consumes content views and page counts
|
||||
|
||||
## Compatibility
|
||||
|
||||
- No new reader shell or page-turn container was introduced
|
||||
- TXT and EPUB native text flows still use `RDEPUBReaderController` and `RDEPUBTextContentView`
|
||||
- `RDEPUBTextBook` remains the backend contract for native reflowable pages
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
phase: 04-reader-capabilities
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- "04-01"
|
||||
files_modified:
|
||||
- Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift
|
||||
- Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift
|
||||
- Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift
|
||||
- Sources/RDReaderView/EPUBTextRendering/RDEPUBTextSearchEngine.swift
|
||||
- Sources/RDReaderView/EPUBCore/RDEPUBReadingModels.swift
|
||||
autonomous: true
|
||||
requirements:
|
||||
- COMP-03
|
||||
user_setup: []
|
||||
must_haves:
|
||||
truths:
|
||||
- native text highlight/search behavior remains grounded in absolute chapter offsets.
|
||||
- location mapping and page-number lookup stay coherent after the reader integration cleanup.
|
||||
- no page-local-only persistence identifier replaces `RDEPUBTextOffsetRangeInfo`.
|
||||
artifacts:
|
||||
- .planning/phases/04-reader-capabilities/04-02-SUMMARY.md
|
||||
key_links:
|
||||
- `RDEPUBReaderController.normalizedTextSelection`
|
||||
- `RDEPUBReaderController.search`
|
||||
- `RDEPUBReadingSession.pageIndex(for:)`
|
||||
---
|
||||
|
||||
<objective>
|
||||
修复并验证 native text reader 下的位置映射、高亮、选区、搜索和 TOC/跳转兼容能力,确保 Phase 3 的 richer paginator 不会破坏这些用户能力。
|
||||
|
||||
Purpose: 把 offset-compatible 的底层契约真正接回 reader 行为链路。
|
||||
Output: source fixes and verification around native location lookup, selection normalization, search navigation, and persisted highlights.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/04-reader-capabilities/04-RESEARCH.md
|
||||
@.planning/phases/04-reader-capabilities/04-PATTERNS.md
|
||||
@Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift
|
||||
@Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift
|
||||
@Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift
|
||||
@Sources/RDReaderView/EPUBTextRendering/RDEPUBTextSearchEngine.swift
|
||||
@Sources/RDReaderView/EPUBCore/RDEPUBReadingModels.swift
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 收敛 native text 的 location / selection / highlight 兼容语义</name>
|
||||
<files>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift, Sources/RDReaderView/EPUBCore/RDEPUBReadingModels.swift</files>
|
||||
<read_first>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift, Sources/RDReaderView/EPUBCore/RDEPUBReadingModels.swift, Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift</read_first>
|
||||
<action>验证并修复 native text selection/highlight 链路,重点围绕 `normalizedTextSelection`、`RDEPUBTextOffsetRangeInfo`、`pageStartOffset` / `pageEndOffset` overlap 计算和 reader persistence 语义展开。若要补充 guard 或 normalization,必须继续以 chapter href + absolute offsets 为核心,而不是引入 page-local-only id。</action>
|
||||
<acceptance_criteria>
|
||||
- `RDEPUBTextOffsetRangeInfo` remains the persisted native text range format
|
||||
- native selection/highlight restore still maps through absolute chapter offsets
|
||||
- `RDEPUBTextContentView` still derives visible ranges from page offsets
|
||||
</acceptance_criteria>
|
||||
<verify>rg -n "RDEPUBTextOffsetRangeInfo|normalizedTextSelection|pageStartOffset|pageEndOffset|rangeInfo" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift Sources/RDReaderView/EPUBCore</verify>
|
||||
<done>native text highlight and selection persistence remain offset-compatible.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 修复并验证 native text 搜索 / TOC / 跳转页号解析</name>
|
||||
<files>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift, Sources/RDReaderView/EPUBTextRendering/RDEPUBTextSearchEngine.swift</files>
|
||||
<read_first>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift, Sources/RDReaderView/EPUBTextRendering/RDEPUBTextSearchEngine.swift</read_first>
|
||||
<action>核对 native text path 的 `pageNumber(for:)`、`search`、`navigateToCurrentSearchMatch`、TOC 页号解析与内部链接跳转,确保 richer page model 下这些 reader feature 仍能落到正确页。需要时可以增强 lookup/normalization,但不要把 Web 路径逻辑硬搬到 native path。</action>
|
||||
<acceptance_criteria>
|
||||
- native text search still produces usable page navigation
|
||||
- TOC/page-number resolution stays coherent for `RDEPUBTextBook`
|
||||
- reader state and page lookup are not duplicated into a second custom navigation stack
|
||||
</acceptance_criteria>
|
||||
<verify>rg -n "search\\(|navigateToCurrentSearchMatch|pageNumber\\(for: searchMatch\\)|flattenedTableOfContentsItems|pageIndex\\(for:" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift Sources/RDReaderView/EPUBTextRendering/RDEPUBTextSearchEngine.swift</verify>
|
||||
<done>native text search, TOC, and jumps remain believable after reintegration.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] `rg -n "RDEPUBTextOffsetRangeInfo|normalizedTextSelection|pageStartOffset|pageEndOffset|rangeInfo" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift Sources/RDReaderView/EPUBCore`
|
||||
- [ ] `rg -n "search\\(|navigateToCurrentSearchMatch|pageNumber\\(for: searchMatch\\)|flattenedTableOfContentsItems|pageIndex\\(for:" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift Sources/RDReaderView/EPUBTextRendering/RDEPUBTextSearchEngine.swift`
|
||||
</verification>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/04-reader-capabilities/04-02-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,15 @@
|
||||
# 04-02 Summary
|
||||
|
||||
## Outcome
|
||||
|
||||
Wave 2 tightened native location, highlight, selection, search, and TOC compatibility around the Phase 3 offset contract.
|
||||
|
||||
- `normalizedTextSelection` now preserves exclusive end semantics more carefully when rebuilding progressions from `RDEPUBTextOffsetRangeInfo`
|
||||
- Native highlight filtering now compares normalized hrefs, reducing mismatch risk after resolver normalization
|
||||
- Search page lookup now prefers exact `rangeLocation` offset matching before falling back to progression-based page resolution
|
||||
|
||||
## Compatibility
|
||||
|
||||
- `RDEPUBTextOffsetRangeInfo` remains the native persisted range format
|
||||
- `RDEPUBTextContentView` still derives visible overlap from `pageStartOffset` / `pageEndOffset`
|
||||
- No page-local-only identifier replaced the absolute chapter offset contract
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
phase: 04-reader-capabilities
|
||||
plan: 03
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on:
|
||||
- "04-02"
|
||||
files_modified:
|
||||
- Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift
|
||||
- Sources/RDReaderView/EPUBUI/RDEPUBReaderConfiguration.swift
|
||||
- Sources/RDReaderView/RDURLReaderController.swift
|
||||
- ReadViewDemo/ReadViewDemo/ViewController.swift
|
||||
autonomous: true
|
||||
requirements:
|
||||
- COMP-04
|
||||
user_setup: []
|
||||
must_haves:
|
||||
truths:
|
||||
- repagination after font, line-height, theme, or viewport changes restores semantic reading state.
|
||||
- the demo app remains the primary runtime verification entry point.
|
||||
- `RDReaderView` does not need modification to validate these flows.
|
||||
artifacts:
|
||||
- .planning/phases/04-reader-capabilities/04-03-SUMMARY.md
|
||||
key_links:
|
||||
- `RDEPUBReaderController.configuration.didSet`
|
||||
- `RDEPUBReaderController.handleViewportChangeIfNeeded`
|
||||
- `RDEPUBReaderController.rebuildExternalTextBook`
|
||||
---
|
||||
|
||||
<objective>
|
||||
验证并收敛字体、行高、主题和 viewport 变化导致的重新分页与状态恢复,让 reader 在 Phase 4 完成后可以稳定承接 repagination。
|
||||
|
||||
Purpose: 证明新 native backend 在真实 reader 交互下能够重新分页而不丢失位置、搜索和高亮上下文。
|
||||
Output: re-pagination/state-restore fixes, plus demo-visible validation hooks or diagnostics where needed.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/04-reader-capabilities/04-RESEARCH.md
|
||||
@.planning/phases/04-reader-capabilities/04-PATTERNS.md
|
||||
@.planning/phases/03-page-metadata-pagination/03-VERIFICATION.md
|
||||
@Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift
|
||||
@Sources/RDReaderView/EPUBUI/RDEPUBReaderConfiguration.swift
|
||||
@Sources/RDReaderView/RDURLReaderController.swift
|
||||
@ReadViewDemo/ReadViewDemo/ViewController.swift
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 收敛 repagination 触发器与状态恢复逻辑</name>
|
||||
<files>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBUI/RDEPUBReaderConfiguration.swift, Sources/RDReaderView/RDURLReaderController.swift</files>
|
||||
<read_first>Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, Sources/RDReaderView/EPUBUI/RDEPUBReaderConfiguration.swift, Sources/RDReaderView/RDURLReaderController.swift</read_first>
|
||||
<action>围绕 `configuration.didSet`、`requiresRepagination`、`refreshVisibleContentPreservingLocation`、`rebuildExternalTextBook`、`handleViewportChangeIfNeeded` 和 TXT/native 入口收敛 repagination 行为,使 reader 在设置变化与 viewport 变化后恢复到语义位置,而不是错误页或空状态。</action>
|
||||
<acceptance_criteria>
|
||||
- font size / line height changes trigger repagination through semantic location restore
|
||||
- theme changes refresh visible content without dropping current reader state
|
||||
- viewport changes do not require `RDReaderView` changes to preserve location
|
||||
</acceptance_criteria>
|
||||
<verify>rg -n "requiresRepagination|refreshVisibleContentPreservingLocation|rebuildExternalTextBook|handleViewportChangeIfNeeded|configuration" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/EPUBUI/RDEPUBReaderConfiguration.swift Sources/RDReaderView/RDURLReaderController.swift</verify>
|
||||
<done>repagination triggers are stable and state-preserving.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 在 demo 中验证 reader-level repagination 与状态恢复</name>
|
||||
<files>ReadViewDemo/ReadViewDemo/ViewController.swift, Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift</files>
|
||||
<read_first>ReadViewDemo/ReadViewDemo/ViewController.swift, Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift, ReadViewDemo/ReadViewDemo/book/</read_first>
|
||||
<action>用现有 demo 入口补充最小但可观察的 reader-level 验证路径或日志,证明 Phase 4 关注的 repagination / location restore / search-highlight continuity 可以被检查。不要新建并行 demo shell。</action>
|
||||
<acceptance_criteria>
|
||||
- demo remains the validation entry point
|
||||
- runtime checks can confirm at least part of the repagination/state-restore behavior
|
||||
- sample corpus under `ReadViewDemo/ReadViewDemo/book/` remains the verification source
|
||||
</acceptance_criteria>
|
||||
<verify>test -d ReadViewDemo/ReadViewDemo/book && rg -n "restore|repagination|search|highlight|location|theme|font" ReadViewDemo/ReadViewDemo Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift</verify>
|
||||
<done>Phase 4 finishes with a real runtime path to prove state-preserving repagination.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] `rg -n "requiresRepagination|refreshVisibleContentPreservingLocation|rebuildExternalTextBook|handleViewportChangeIfNeeded|configuration" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/EPUBUI/RDEPUBReaderConfiguration.swift Sources/RDReaderView/RDURLReaderController.swift`
|
||||
- [ ] `test -d ReadViewDemo/ReadViewDemo/book`
|
||||
- [ ] `rg -n "restore|repagination|search|highlight|location|theme|font" ReadViewDemo/ReadViewDemo Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`
|
||||
</verification>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/04-reader-capabilities/04-03-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,19 @@
|
||||
# 04-03 Summary
|
||||
|
||||
## Outcome
|
||||
|
||||
Wave 3 validated repagination and semantic location restore with real sample books.
|
||||
|
||||
- The demo now reports a restore diagnostic alongside the pagination diagnostic
|
||||
- Validation rebuilds native text books with a larger font/line spacing and a theme-only style change, then checks whether the same semantic location still resolves correctly
|
||||
- Runtime evidence confirmed stable href restoration and theme-stable page mapping on the sampled reflowable EPUB
|
||||
|
||||
## Demo Evidence
|
||||
|
||||
Runtime log from the simulator:
|
||||
|
||||
- `EPUB 资源验证:2/2 通过`
|
||||
- `分页诊断:宝山辽墓材料与释读 · 章节 10 · attachment 页 54 · semantic break 页 57 · reasons [attachmentBoundary:31, blockBoundary:26, frameLimit:17, chapterEnd:4] · page break: blockBoundary`
|
||||
- `恢复诊断:宝山辽墓材料与释读 · base 39 · font-shift 44 · theme-stable yes · href-stable yes · progression-delta 0.004`
|
||||
|
||||
This shows the native reader backend can repaginate to a different page number under font changes while preserving the same semantic reading location.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Phase 4: 接回现有 reader 能力链路 - Pattern Map
|
||||
|
||||
## Goal
|
||||
|
||||
为 Phase 4 提供“先接哪里、怎么验证没把 reader 行为搞坏”的最短路径。重点不是继续改 paginator,而是把已经完成的 native text book/page model 稳定接回 reader 能力链路。
|
||||
|
||||
## Planned Outputs
|
||||
|
||||
| Planned file | Role | Primary evidence | Why this is the right analog |
|
||||
|--------------|------|------------------|------------------------------|
|
||||
| `04-01-PLAN.md` | native text backend 接回 reader 主流程 | `RDEPUBReaderController`, `RDEPUBTextBookBuilder`, `RDEPUBTextContentView`, `RDURLReaderController` | 这些文件定义当前 native text 打开、分页、展示和 page container 接口。 |
|
||||
| `04-02-PLAN.md` | 位置映射 / 高亮 / 搜索兼容收敛 | `RDEPUBReadingSession`, `RDEPUBReaderController`, `RDEPUBTextSearchEngine`, `RDEPUBReadingModels` | 这些文件共同定义 reader state、search matches、selection normalization 与绝对 offset 持久化语义。 |
|
||||
| `04-03-PLAN.md` | 主题 / 字号 / 行高 / viewport 变化后的重新分页与状态恢复验证 | `RDEPUBReaderController`, `RDEPUBReaderConfiguration`, `RDURLReaderController`, `ReadViewDemo` | 当前所有重新分页触发器和 demo 验证入口都在这里。 |
|
||||
|
||||
## Code Evidence Map
|
||||
|
||||
| Concern | Closest source of truth | Evidence to extract |
|
||||
|---------|-------------------------|---------------------|
|
||||
| native text page flow接入点 | `RDEPUBReaderController.paginatePublication`, `applyTextBook`, `pageContentView` | 现有 controller 已有 native/web 双路径,但需要收敛行为。 |
|
||||
| 恢复位置与可见位置 | `restoreReadingLocation`, `currentVisibleLocation`, `finishPagination` | 这里决定 repagination 后回到哪里。 |
|
||||
| 绝对 offset 高亮/选区兼容 | `RDEPUBTextContentView`, `normalizedTextSelection`, `RDEPUBTextOffsetRangeInfo` | 这些是 Phase 4 不能破坏的硬约束。 |
|
||||
| 搜索跳转与页号解析 | `search`, `navigateToCurrentSearchMatch`, `pageNumber(for:)`, `RDEPUBTextSearchEngine` | 需要保证 native text path 仍能定位正确页。 |
|
||||
| 设置变更触发重排 | `configuration.didSet`, `requiresRepagination`, `refreshVisibleContentPreservingLocation`, `handleViewportChangeIfNeeded` | 字号/行高/主题/旋转都是 Phase 4 的状态恢复验证入口。 |
|
||||
|
||||
## Writing Guidance
|
||||
|
||||
- 计划必须把“主流程接回、兼容能力收敛、重排恢复验证”拆成三个独立 plan,不要把所有 reader 能力挤进一个任务。
|
||||
- 任何修复都要优先围绕 `RDEPUBReaderController` 和 `RDEPUBReadingSession` 的现有责任边界展开,不要借机重写 `RDReaderView`。
|
||||
- 验证步骤要明确要求真实的 reader 行为检查,而不是只做 build pass。
|
||||
@@ -0,0 +1,123 @@
|
||||
# Phase 4: 接回现有 reader 能力链路 - Research
|
||||
|
||||
**Researched:** 2026-05-22
|
||||
**Domain:** iOS EPUB reader reintegration / location mapping / highlight-search-state continuity
|
||||
**Confidence:** HIGH
|
||||
|
||||
<user_constraints>
|
||||
## User Constraints
|
||||
|
||||
No `CONTEXT.md` exists for this phase. Planning is based on ROADMAP requirements, current code, and completed artifacts from Phases 1-3 only.
|
||||
</user_constraints>
|
||||
|
||||
<architectural_responsibility_map>
|
||||
## Architectural Responsibility Map
|
||||
|
||||
| Capability | Primary Tier | Secondary Tier | Rationale |
|
||||
|------------|-------------|----------------|-----------|
|
||||
| Reflowable native pagination output | EPUBTextRendering | EPUBCore | Phase 3 already moved richer page semantics into `RDEPUBTextBook` / `RDEPUBTextPage`. |
|
||||
| Reader orchestration and restore logic | EPUBUI | EPUBCore | `RDEPUBReaderController` owns `paginatePublication`, `finishPagination`, restore, search navigation, selection, and configuration updates. |
|
||||
| Page lookup and navigator state | EPUBCore | EPUBUI | `RDEPUBReadingSession` remains the non-UI state owner for fixed/web flows and should keep that role rather than pushing state into `RDReaderView`. |
|
||||
| Highlight/search persistence semantics | EPUBCore | EPUBUI | `RDEPUBTextOffsetRangeInfo` and normalized locations are the durable compatibility contract. |
|
||||
| Page-turn UI and display modes | RDReaderView | EPUBUI | Explicitly out of scope to change; Phase 4 must adapt to existing `RDReaderView` APIs. |
|
||||
|
||||
</architectural_responsibility_map>
|
||||
|
||||
<research_summary>
|
||||
## Summary
|
||||
|
||||
Phase 3 strengthened the native reflowable engine but did not yet make that richer page model a first-class citizen across the whole reader capability chain. The main Phase 4 work is therefore not “more pagination”; it is reconnecting the existing reader shell to the upgraded `RDEPUBTextBook` path without changing `RDReaderView` or introducing a second native reader model.
|
||||
|
||||
The current code already shows the exact reintegration seams:
|
||||
|
||||
- `RDEPUBReaderController.paginatePublication` branches between native `RDEPUBTextBookBuilder`, fixed-layout snapshots, and `RDEPUBPaginator` WebKit measurement.
|
||||
- `applyTextBook`, `finishPagination`, `restoreReadingLocation`, and `currentVisibleLocation` already contain a parallel text-book path that bypasses `RDEPUBReadingSession.pageIndex(for:)`.
|
||||
- `pageContentView(readerView:pageNum:containerView:)` already swaps between `RDEPUBTextContentView` and `RDEPUBWebContentView`.
|
||||
- Search uses `RDEPUBTextSearchEngine` when `textBook` exists and `RDEPUBHTMLSearchEngine` otherwise.
|
||||
- Selection/highlight persistence for native text still depends on `RDEPUBTextOffsetRangeInfo` absolute offsets and chapter href normalization.
|
||||
|
||||
That means Phase 4 should stabilize and tighten an already-existing split path rather than invent a new architecture. The right outcome is:
|
||||
|
||||
1. Reflowable native pages remain rendered through `RDEPUBTextBook`.
|
||||
2. `RDEPUBReaderController` keeps one coherent restore/navigation/search/highlight API no matter whether the source page is native text or Web content.
|
||||
3. Repagination triggered by font size, line height, viewport changes, or theme changes preserves reader state instead of resetting to page 1 or dropping search/highlight context.
|
||||
|
||||
The riskiest compatibility areas are also already visible:
|
||||
|
||||
- `RDEPUBReaderController.restoreReadingLocation` and `currentVisibleLocation` use separate logic for text-book vs snapshot pages.
|
||||
- `normalizedTextSelection` recomputes progression from absolute offset payloads; regressions here would silently break persisted highlights.
|
||||
- `refreshVisibleContentPreservingLocation` and `rebuildExternalTextBook` can preserve location only if the text-book lookup contract remains stable after repagination.
|
||||
- `flattenedTableOfContentsItems` and `pageNumber(for:)` need page-number continuity for TOC and search to stay believable.
|
||||
|
||||
**Primary recommendation:** Treat Phase 4 as a reader-state consolidation phase. Strengthen `RDEPUBReaderController` and adjacent state surfaces so the Phase 3 native pagination model behaves like a first-class reader backend while preserving the existing `RDReaderView` page-turn container and the fixed / interactive WebKit paths.
|
||||
</research_summary>
|
||||
|
||||
<code_evidence>
|
||||
## Code Evidence
|
||||
|
||||
| Concern | Source | Why it matters |
|
||||
|--------|--------|----------------|
|
||||
| Native-vs-web pagination entry split | `RDEPUBReaderController.paginatePublication` | Defines Phase 4’s main re-integration entry point. |
|
||||
| Native restore and current-location logic | `RDEPUBReaderController.restoreReadingLocation`, `currentVisibleLocation` | Text-book navigation already bypasses `RDEPUBReadingSession`; this must stay coherent. |
|
||||
| Reader state owner for non-native flows | `RDEPUBReadingSession` | Existing navigation/session state should remain centralized instead of leaking into UI code. |
|
||||
| Native selection/highlight normalization | `RDEPUBReaderController.normalizedTextSelection`, `RDEPUBTextContentView`, `RDEPUBReadingModels` | Absolute offsets must survive reader interactions and persistence. |
|
||||
| Search backend switching | `RDEPUBReaderController.resolvedSearchMatches`, `RDEPUBTextSearchEngine` | Search behavior must remain uniform from the user’s perspective across render backends. |
|
||||
| Repagination triggers | `RDEPUBReaderController.configuration.didSet`, `handleViewportChangeIfNeeded`, `rebuildExternalTextBook`, `repaginatePreservingCurrentLocation` | These are the operational triggers most likely to break restore/state continuity. |
|
||||
|
||||
</code_evidence>
|
||||
|
||||
<architecture_patterns>
|
||||
## Architecture Patterns
|
||||
|
||||
### Pattern 1: Consolidate reader behavior at the controller boundary
|
||||
**What:** Keep branching localized in `RDEPUBReaderController`, but make navigation, restore, search, and persistence semantics consistent across text-book and web paths.
|
||||
**Why:** The UI entry point already exists there; moving branching elsewhere would enlarge scope.
|
||||
|
||||
### Pattern 2: Keep offsets as the native compatibility key
|
||||
**What:** Native text selection, search, and highlight flows should continue to resolve through chapter href + absolute offset payloads.
|
||||
**Why:** Phase 3 deliberately preserved this invariant to make Phase 4 possible.
|
||||
|
||||
### Pattern 3: Repaginate by restoring location, not page number
|
||||
**What:** Font/theme/viewport changes should always preserve a semantic location and rebuild around it.
|
||||
**Why:** Page numbers are not stable under re-pagination; href + progression + offset-compatible selection are.
|
||||
|
||||
### Anti-Patterns to Avoid
|
||||
- Refactoring `RDReaderView` to understand native page metadata directly.
|
||||
- Creating a second navigation state machine just for the native text path.
|
||||
- Switching highlights/search to page-local identifiers that cannot survive repagination.
|
||||
|
||||
</architecture_patterns>
|
||||
|
||||
<dont_hand_roll>
|
||||
## Don't Hand-Roll
|
||||
|
||||
| Problem | Don't Build | Use Instead | Why |
|
||||
|---------|-------------|-------------|-----|
|
||||
| Native reader shell | A new dedicated native-text controller | Existing `RDEPUBReaderController` split path | Scope stays contained and existing app entry points remain valid. |
|
||||
| Restore state | Page-number-only recovery | `RDEPUBLocation` + native page lookup + offset contract | Page numbers drift after repagination. |
|
||||
| Search compatibility | Separate search UI semantics for text pages | Existing `RDEPUBSearchState` and `RDEPUBSearchMatch` flow | User-facing search behavior should stay unified. |
|
||||
|
||||
</dont_hand_roll>
|
||||
|
||||
<common_pitfalls>
|
||||
## Common Pitfalls
|
||||
|
||||
### Pitfall 1: Letting native and web reader paths diverge in user-visible behavior
|
||||
If search, selection, or TOC navigation behaves differently based on backend, the reader becomes unpredictable.
|
||||
|
||||
### Pitfall 2: Preserving page numbers instead of semantic locations during repagination
|
||||
This causes subtle wrong-page restores after font, theme, or viewport changes.
|
||||
|
||||
### Pitfall 3: Refreshing visible content without reapplying current search/highlight state
|
||||
Native text pages are recreated from attributed substrings, so state must be re-derived every time.
|
||||
|
||||
</common_pitfalls>
|
||||
|
||||
<open_questions>
|
||||
## Open Questions
|
||||
|
||||
- Should any of the new Phase 3 page metadata be surfaced to reader delegates in Phase 4, or remain internal until Phase 5 diagnostics?
|
||||
- Is `RDEPUBReadingSession` worth extending to cover native `RDEPUBTextBook` page lookup as well, or is the current controller-local split still the smallest safe change?
|
||||
- Which search/highlight and TOC navigation paths are most important to validate interactively in the demo during execution?
|
||||
|
||||
</open_questions>
|
||||
@@ -0,0 +1,29 @@
|
||||
# Phase 4: 接回现有 reader 能力链路 - Validation
|
||||
|
||||
## Required Checks
|
||||
|
||||
- `RDEPUBReaderController` 仍是 native text / web reader 的统一入口
|
||||
- `RDReaderView` 不需要新增 native page metadata 感知逻辑
|
||||
- native text 的高亮、搜索、TOC、恢复位置仍通过 `RDEPUBLocation` 与绝对 offset 兼容语义工作
|
||||
- 字号、行高、主题、viewport 变化后的 repagination 不会把阅读状态重置为错误位置
|
||||
|
||||
## Verification Anchors
|
||||
|
||||
### Source-level
|
||||
- `rg -n "paginatePublication|applyTextBook|restoreReadingLocation|currentVisibleLocation|finishPagination|pageContentView" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`
|
||||
- `rg -n "RDEPUBTextOffsetRangeInfo|normalizedTextSelection|search\\(|pageNumber\\(for: searchMatch\\)" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/EPUBCore Sources/RDReaderView/EPUBTextRendering`
|
||||
- `rg -n "requiresRepagination|refreshVisibleContentPreservingLocation|handleViewportChangeIfNeeded|rebuildExternalTextBook" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/RDURLReaderController.swift`
|
||||
|
||||
### Runtime / demo
|
||||
- open a reflowable EPUB in `ReadViewDemo`
|
||||
- navigate via TOC and ensure the target page remains correct on the native text path
|
||||
- create or load a highlight, then verify it still paints after page refresh / repagination
|
||||
- run a search and verify current match navigation lands on the right page
|
||||
- change font size, line height, and theme; confirm the reader restores to the same semantic location
|
||||
|
||||
## Completion Standard
|
||||
|
||||
Phase 4 planning is only good enough if each executable plan names both:
|
||||
|
||||
1. the code seam it will modify
|
||||
2. the reader behavior it must preserve or prove
|
||||
@@ -0,0 +1,32 @@
|
||||
# Phase 4 Verification
|
||||
|
||||
## Commands
|
||||
|
||||
- `build_sim` for scheme `ReadViewDemo`
|
||||
- `build_run_sim` for scheme `ReadViewDemo`
|
||||
- `test -d ReadViewDemo/ReadViewDemo/book`
|
||||
- `rg -n "paginatePublication|applyTextBook|finishPagination|restoreReadingLocation|currentVisibleLocation|RDEPUBTextOffsetRangeInfo|normalizedTextSelection|pageStartOffset|pageEndOffset|search\\(|navigateToCurrentSearchMatch|pageNumber\\(for: searchMatch\\)|flattenedTableOfContentsItems|pageIndex\\(for:|requiresRepagination|refreshVisibleContentPreservingLocation|rebuildExternalTextBook|handleViewportChangeIfNeeded|restore|repagination|highlight|location|theme|font" Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift Sources/RDReaderView/EPUBCore Sources/RDReaderView/RDURLReaderController.swift ReadViewDemo/ReadViewDemo -S`
|
||||
|
||||
## Results
|
||||
|
||||
- Simulator build succeeded
|
||||
- Simulator launch succeeded
|
||||
- Sample corpus directory exists
|
||||
- Source verification confirms:
|
||||
- native text pagination now feeds a real reader snapshot and location helpers
|
||||
- native selection/highlight compatibility still depends on absolute chapter offsets
|
||||
- native search page lookup now uses exact offset evidence when available
|
||||
- repagination and restore hooks remain centered in `RDEPUBReaderController`, not `RDReaderView`
|
||||
|
||||
## Runtime Evidence
|
||||
|
||||
From the app runtime log:
|
||||
|
||||
- `EPUB 资源验证:2/2 通过`
|
||||
- `分页诊断:宝山辽墓材料与释读 · 章节 10 · attachment 页 54 · semantic break 页 57 · reasons [attachmentBoundary:31, blockBoundary:26, frameLimit:17, chapterEnd:4] · page break: blockBoundary`
|
||||
- `恢复诊断:宝山辽墓材料与释读 · base 39 · font-shift 44 · theme-stable yes · href-stable yes · progression-delta 0.004`
|
||||
|
||||
## Residual Risk
|
||||
|
||||
- The restore validation is still corpus-level and not a full interactive UI automation pass through TOC/highlight/search actions
|
||||
- The native and web paths still branch inside `RDEPUBReaderController`; Phase 5 should focus on broader regression and stability coverage rather than further architectural expansion
|
||||
Reference in New Issue
Block a user