feat: 实现大书远距目录跳转与后台补全优化方案

Phase 1: 稳定性优先
- 新增 RDEPUBJumpSession 保护机制,防止远距跳转后翻页串章
- 升级页图接管条件,增加 JumpSession 保护区检查
- 窗口扩展改为基于当前权威窗口方向

Phase 2: 补全优先级重排
- 新增 RDEPUBBackgroundPriorityPolicy 策略配置
- 实现 hot/warm/cold zone 优先级排序
- 添加失败重试机制(指数退避,最多3次)

Phase 3: 分段覆盖与最终收敛
- 新增 RDEPUBBackgroundCoverageStore 分段存储
- 新增 RDEPUBPageMapReconciliationCoordinator 页图接管仲裁
- 实现 LRU 淘汰和内存警告处理

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-06-15 16:28:11 +08:00
co-authored by Claude Opus 4.7
parent e976ceebd5
commit c64460988a
13 changed files with 2797 additions and 92 deletions
@@ -10,6 +10,9 @@ import Foundation
final class RDEPUBReaderLocationCoordinator {
private unowned let context: RDEPUBReaderContext
/// spineIndex
private var lastPageChangeSpineIndex: Int?
init(context: RDEPUBReaderContext) {
self.context = context
}
@@ -23,6 +26,9 @@ final class RDEPUBReaderLocationCoordinator {
) -> Bool {
guard let controller = context.controller,
let readerView = context.readerView else { return false }
if context.bookPageMap != nil {
_ = context.runtime?.ensureOnDemandNavigationTargetAvailable(for: location)
}
guard let targetPageNumber = controller.pageNumber(for: location) else {
readerView.transitionToPage(pageNum: 0)
context.readingSession?.transition(to: .idle)
@@ -50,6 +56,10 @@ final class RDEPUBReaderLocationCoordinator {
context.readingSession?.transition(to: .jumping)
}
readerView.transitionToPage(pageNum: max(targetPageNumber - 1, 0), animated: animated)
// JumpSession
recordPageChangeIfNeeded()
return true
}
@@ -95,4 +105,40 @@ final class RDEPUBReaderLocationCoordinator {
controller.delegate?.epubReader(controller, didUpdateCurrentTableOfContentsItem: controller.currentTableOfContentsItem)
controller.updateReaderChrome()
}
/// JumpSession
func recordPageChangeIfNeeded() {
guard let runtime = context.runtime,
let bookPageMap = context.bookPageMap,
let readerView = context.readerView else { return }
let currentPageNumber = readerView.currentPage + 1
guard let currentSpineIndex = bookPageMap.spineIndex(forAbsolutePage: currentPageNumber - 1) else {
return
}
if let lastSpineIndex = lastPageChangeSpineIndex,
lastSpineIndex != currentSpineIndex {
runtime.jumpSessionManager.recordPageChange(
fromSpineIndex: lastSpineIndex,
toSpineIndex: currentSpineIndex
)
}
lastPageChangeSpineIndex = currentSpineIndex
// JumpSession
let isIdle = context.secondsSinceLastUserNavigation() > 2.0
if let endReason = runtime.jumpSessionManager.checkSessionEnd(
currentSpineIndex: currentSpineIndex,
isIdle: isIdle
) {
runtime.jumpSessionManager.endSession(endReason)
}
}
///
func resetPageChangeState() {
lastPageChangeSpineIndex = nil
}
}