feat: chapter runtime refactoring and related updates

- Refactor chapter runtime: replace window coordinator/snapshot with warmup orchestrator
- Update EPUB core: parser, reading session, JS bridge, navigator layout
- Update reader controller: data source, location resolution, persistence
- Update chapter runtime: data cache, loader, runtime store, disk cache, warmup orchestrator
- Remove deprecated navigation state machine and pagination state
- Update text rendering: book cache, HTML normalizer
- Update UI: text content view, dark image adjuster, text selection controller
- Update settings and reader configuration
- Add CODE_REVIEW.md and AUDIT_FINAL.md documentation
- Update pod dependencies (remove SSAlertSwift, SnapKit)
- Update podspec and pod configuration files

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-06-26 18:50:07 +09:00
co-authored by Claude
parent b8aa10c535
commit 22e7e44220
123 changed files with 3701 additions and 9118 deletions
@@ -8,7 +8,6 @@ enum RDEPUBPendingPageMapUpdateKind {
struct RDEPUBPendingPageMapUpdate {
let pageMap: RDEPUBBookPageMap
let source: RDEPUBPaginationStateSource
let kind: RDEPUBPendingPageMapUpdateKind
}
@@ -22,10 +21,6 @@ final class RDEPUBPresentationRuntime {
private unowned let reconciliationCoordinator: RDEPUBPageMapReconciliationCoordinator
let navigationStateMachine = RDEPUBNavigationStateMachine()
private(set) var paginationState = RDEPUBPaginationState()
init(
context: RDEPUBReaderContext,
locationCoordinator: RDEPUBReaderLocationCoordinator,
@@ -43,19 +38,14 @@ final class RDEPUBPresentationRuntime {
restoreLocation: RDEPUBLocation?,
finishPagination: (RDEPUBLocation?) -> Void
) {
navigationStateMachine.transition(to: .presentingWindow)
context.textBook = nil
context.bookPageMap = bookPageMap
context.pendingPageMapUpdates.removeAll()
context.replaceActiveSnapshot(makeSnapshot(from: bookPageMap))
paginationState.activePageMap = bookPageMap
paginationState.pendingPageMapUpdates.removeAll()
paginationState.source = .initialPartial
finishPagination(restoreLocation)
}
func refreshBookPageMapInPlace(_ bookPageMap: RDEPUBBookPageMap) {
navigationStateMachine.transition(to: .reconcilingFullMap)
RDEPUBBackgroundTrace.log(
"Reconciliation",
"refreshBookPageMapInPlace: enqueued reconcileFullMap chapters=\(bookPageMap.totalChapters) pages=\(bookPageMap.totalPages)"
@@ -63,7 +53,6 @@ final class RDEPUBPresentationRuntime {
enqueuePendingPageMapUpdate(
RDEPUBPendingPageMapUpdate(
pageMap: bookPageMap,
source: .pendingFullMap,
kind: .reconcileFullMap
)
)
@@ -99,7 +88,6 @@ final class RDEPUBPresentationRuntime {
enqueuePendingPageMapUpdate(
RDEPUBPendingPageMapUpdate(
pageMap: bookPageMap,
source: .asyncExtension,
kind: .extendPartial(
currentPageNumber: currentPageNumber,
currentLocation: currentLocation
@@ -109,28 +97,19 @@ final class RDEPUBPresentationRuntime {
}
func applySettingsPreviewPageMap(_ bookPageMap: RDEPUBBookPageMap) {
navigationStateMachine.transition(to: .presentingWindow)
context.bookPageMap = bookPageMap
context.replaceActiveSnapshot(makeSnapshot(from: bookPageMap))
paginationState.activePageMap = bookPageMap
paginationState.source = .settingsPreview
}
func queueForwardAppendedPageMap(_ bookPageMap: RDEPUBBookPageMap) {
enqueuePendingPageMapUpdate(
RDEPUBPendingPageMapUpdate(
pageMap: bookPageMap,
source: .asyncExtension,
kind: .appendForward
)
)
}
func clear() {
paginationState = RDEPUBPaginationState()
navigationStateMachine.transition(to: .idle)
}
func makeSnapshot(from bookPageMap: RDEPUBBookPageMap) -> RDEPUBReadingSession.PaginationSnapshot {
let pages = bookPageMap.entries.flatMap { entry in
(0..<entry.pageCount).map { localPageIndex in
@@ -162,7 +141,7 @@ final class RDEPUBPresentationRuntime {
let currentLocation = locationCoordinator.currentVisibleLocation()
context.textBook = nil
applyPageMapToLiveModel(newPageMap, source: .fullReplacement)
applyPageMapToLiveModel(newPageMap)
if let currentLocation {
if rebindVisibleLocation(currentLocation, readerView: readerView, controller: controller) == false {
@@ -201,7 +180,6 @@ final class RDEPUBPresentationRuntime {
updates.append(update)
}
context.pendingPageMapUpdates = updates
paginationState.pendingPageMapUpdates = updates
commitPendingPageMapUpdateIfNeeded()
}
@@ -219,7 +197,6 @@ final class RDEPUBPresentationRuntime {
) -> Bool {
switch update.kind {
case .reconcileFullMap:
navigationStateMachine.transition(to: .reconcilingFullMap)
let decision = reconciliationCoordinator.evaluateTakeover(
candidatePageMap: update.pageMap,
candidateSegment: nil,
@@ -248,7 +225,7 @@ final class RDEPUBPresentationRuntime {
case .extendPartial(_, let currentLocation):
removePendingPageMapUpdate(at: index)
applyPageMapToLiveModel(update.pageMap, source: update.source)
applyPageMapToLiveModel(update.pageMap)
if let currentLocation,
rebindVisibleLocation(currentLocation, readerView: readerView, controller: controller) {
return true
@@ -266,7 +243,7 @@ final class RDEPUBPresentationRuntime {
case .appendForward:
removePendingPageMapUpdate(at: index)
applyPageMapToLiveModel(update.pageMap, source: update.source)
applyPageMapToLiveModel(update.pageMap)
readerView.reloadPageCountOnly()
return true
}
@@ -305,7 +282,7 @@ final class RDEPUBPresentationRuntime {
if context.bookPageMap != nil,
context.runtime?.prepareOnDemandChapter(
forAbsolutePageNumber: targetPageNumber,
allowSynchronousLoad: true
allowSynchronousLoad: false
) == false {
return false
}
@@ -317,16 +294,10 @@ final class RDEPUBPresentationRuntime {
return true
}
private func applyPageMapToLiveModel(
_ pageMap: RDEPUBBookPageMap,
source: RDEPUBPaginationStateSource
) {
navigationStateMachine.transition(to: .presentingWindow)
private func applyPageMapToLiveModel(_ pageMap: RDEPUBBookPageMap) {
context.bookPageMap = pageMap
context.replaceActiveSnapshot(makeSnapshot(from: pageMap))
discardSupersededPendingPageMapUpdates(afterApplying: pageMap)
paginationState.activePageMap = pageMap
paginationState.source = source
}
private func removePendingPageMapUpdate(at index: Int) {
@@ -334,7 +305,6 @@ final class RDEPUBPresentationRuntime {
guard updates.indices.contains(index) else { return }
updates.remove(at: index)
context.pendingPageMapUpdates = updates
paginationState.pendingPageMapUpdates = updates
}
private func discardSupersededPendingPageMapUpdates(afterApplying liveMap: RDEPUBBookPageMap) {
@@ -346,7 +316,6 @@ final class RDEPUBPresentationRuntime {
)
}
context.pendingPageMapUpdates = updates
paginationState.pendingPageMapUpdates = updates
}
private func pendingPriority(for kind: RDEPUBPendingPageMapUpdateKind) -> Int {
@@ -384,4 +353,4 @@ final class RDEPUBPresentationRuntime {
&& candidate.pageMap.totalPages >= existing.pageMap.totalPages
)
}
}
}