feat: 设置面板与章节运行时联动优化

- 设置页打开时仅重新计算当前章节预览,关闭后触发完整补全
- 新增 preview 加载优先级,支持设置页内当前章预览
- 添加设置页防抖机制,合并连续字号/行距变更
- 支持下滑手势关闭设置页,通过 presentation delegate 通知运行时
- 重新分页时跳过导航和尺寸校验,避免状态冲突
- currentTextPageSize 线程安全优化,后台线程使用缓存尺寸
- 更新 CocoaPods 依赖

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-06-17 09:47:50 +08:00
co-authored by Claude Opus 4.7
parent c64460988a
commit 6ed3fcb071
10 changed files with 1626 additions and 1430 deletions
@@ -27,6 +27,19 @@ final class RDEPUBReaderRuntime {
lazy var backgroundCoverageStore = RDEPUBBackgroundCoverageStore(context: context)
lazy var reconciliationCoordinator = RDEPUBPageMapReconciliationCoordinator(context: context)
///
var isSettingsPanelOpen: Bool = false
///
var needsFullRepaginationAfterSettingsClose: Bool = false
///
private var settingsPreviewGeneration: Int = 0
/// preview
private var pendingSettingsPreviewWorkItem: DispatchWorkItem?
/// preview
private let settingsPreviewDebounceDelay: TimeInterval = 0.2
init(context: RDEPUBReaderContext) {
self.context = context
}
@@ -330,6 +343,9 @@ final class RDEPUBReaderRuntime {
let readerView = context.readerView,
let controller = context.controller else { return }
//
guard !controller.isRepaginating else { return }
// 使
let decision = reconciliationCoordinator.evaluateTakeover(
candidatePageMap: pendingMap,
@@ -401,7 +417,111 @@ final class RDEPUBReaderRuntime {
///
func repaginatePreservingCurrentLocation() {
paginationCoordinator.repaginatePreservingCurrentLocation()
//
if isSettingsPanelOpen {
needsFullRepaginationAfterSettingsClose = true
paginationCoordinator.cancelActiveMetadataParseWork()
scheduleSettingsPreviewRepagination()
} else {
paginationCoordinator.repaginatePreservingCurrentLocation()
}
}
/// preview
private func scheduleSettingsPreviewRepagination() {
pendingSettingsPreviewWorkItem?.cancel()
settingsPreviewGeneration += 1
let previewGeneration = settingsPreviewGeneration
let workItem = DispatchWorkItem { [weak self] in
guard let self,
self.isSettingsPanelOpen,
previewGeneration == self.settingsPreviewGeneration else {
return
}
self.pendingSettingsPreviewWorkItem = nil
self.chapterRuntimeStore.invalidateAllForSettingsChange()
self.repaginateCurrentChapterOnly(previewGeneration: previewGeneration)
}
pendingSettingsPreviewWorkItem = workItem
DispatchQueue.main.asyncAfter(
deadline: .now() + settingsPreviewDebounceDelay,
execute: workItem
)
}
/// 使
private func repaginateCurrentChapterOnly(previewGeneration: Int) {
guard 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
}
let previewLocation = locationCoordinator.currentVisibleLocation() ?? context.persistenceLocation()
RDEPUBBackgroundTrace.log(
"Runtime",
"repaginateCurrentChapterOnly spine=\(currentSpineIndex) generation=\(previewGeneration)"
)
chapterLoader.loadChapter(
spineIndex: currentSpineIndex,
store: chapterRuntimeStore,
priority: .preview
) { [weak self] result in
guard let self,
self.isSettingsPanelOpen,
previewGeneration == self.settingsPreviewGeneration,
let readerView = self.context.readerView else {
return
}
switch result {
case .success(let chapter):
let partialMap = self.makePartialPageMap(from: [chapter])
self.context.bookPageMap = partialMap
self.context.replaceActiveSnapshot(self.makeSnapshot(from: partialMap))
readerView.reloadData()
if let previewLocation,
self.locationCoordinator.restoreReadingLocation(previewLocation, animated: false) {
return
}
readerView.transitionToPage(pageNum: 0, animated: false)
case .failure(let error):
RDEPUBBackgroundTrace.log(
"Runtime",
"repaginateCurrentChapterOnly FAILED spine=\(currentSpineIndex) generation=\(previewGeneration) error=\(error)"
)
}
}
}
///
func settingsPanelWillAppear() {
pendingSettingsPreviewWorkItem?.cancel()
pendingSettingsPreviewWorkItem = nil
isSettingsPanelOpen = true
needsFullRepaginationAfterSettingsClose = false
settingsPreviewGeneration += 1
}
///
func settingsPanelDidDisappear() {
pendingSettingsPreviewWorkItem?.cancel()
pendingSettingsPreviewWorkItem = nil
isSettingsPanelOpen = false
settingsPreviewGeneration += 1
//
if needsFullRepaginationAfterSettingsClose {
needsFullRepaginationAfterSettingsClose = false
RDEPUBBackgroundTrace.log("Runtime", "settingsPanelDidDisappear: triggering full repagination")
paginationCoordinator.repaginatePreservingCurrentLocation()
}
}
///