全量换表前用旧页表回环验证当前位置
初始 partial 窗口被全书页表接管时,live 页码(窗口坐标)与新表解析 页码(全书坐标)不可比,±1 启发式误判后 preserveLivePage 会把模型 位置钉在全书第 1 页,导致位置错乱并级联阻塞后续全表提交。改为换表 前先用旧表解析 currentLocation:回环等于 live 页说明位置忠实反映 屏幕内容,换表后无条件信任新表解析结果;不等时才退回 ±1 门槛,保留 对 stale 持久化位置的防护。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
bd6e915fbd
commit
5ae7823ef8
@ -160,6 +160,11 @@ final class RDEPUBPresentationRuntime {
|
|||||||
) {
|
) {
|
||||||
let currentLocation = locationCoordinator.currentVisibleLocation()
|
let currentLocation = locationCoordinator.currentVisibleLocation()
|
||||||
let livePageBeforeApply = readerView.currentPage + 1
|
let livePageBeforeApply = readerView.currentPage + 1
|
||||||
|
// Resolved against the outgoing page map. When it round-trips to the live
|
||||||
|
// page, the location faithfully describes what is on screen, so whatever
|
||||||
|
// page it resolves to in the new map is authoritative even if the two maps
|
||||||
|
// number pages differently (partial-window -> full-book takeover).
|
||||||
|
let oldResolvedPage = currentLocation.flatMap { controller.pageNumber(for: $0) }
|
||||||
|
|
||||||
context.textBook = nil
|
context.textBook = nil
|
||||||
applyPageMapToLiveModel(newPageMap)
|
applyPageMapToLiveModel(newPageMap)
|
||||||
@ -172,11 +177,12 @@ final class RDEPUBPresentationRuntime {
|
|||||||
let resolvedTargetPage = controller.pageNumber(for: currentLocation)
|
let resolvedTargetPage = controller.pageNumber(for: currentLocation)
|
||||||
let shouldTrustResolvedLocation = shouldTrustFullReplaceResolvedPage(
|
let shouldTrustResolvedLocation = shouldTrustFullReplaceResolvedPage(
|
||||||
resolvedTargetPage,
|
resolvedTargetPage,
|
||||||
livePageBeforeApply: livePageBeforeApply
|
livePageBeforeApply: livePageBeforeApply,
|
||||||
|
locationMatchesLivePage: oldResolvedPage == livePageBeforeApply
|
||||||
)
|
)
|
||||||
RDEPUBBackgroundTrace.log(
|
RDEPUBBackgroundTrace.log(
|
||||||
"Reconciliation",
|
"Reconciliation",
|
||||||
"applyFullPageMapReplacement decision livePage=\(livePageBeforeApply) resolvedTargetPage=\(resolvedTargetPage ?? -1) trustResolved=\(shouldTrustResolvedLocation) href=\(currentLocation.href)"
|
"applyFullPageMapReplacement decision livePage=\(livePageBeforeApply) oldResolvedPage=\(oldResolvedPage ?? -1) resolvedTargetPage=\(resolvedTargetPage ?? -1) trustResolved=\(shouldTrustResolvedLocation) href=\(currentLocation.href)"
|
||||||
)
|
)
|
||||||
|
|
||||||
if shouldTrustResolvedLocation,
|
if shouldTrustResolvedLocation,
|
||||||
@ -433,9 +439,16 @@ final class RDEPUBPresentationRuntime {
|
|||||||
|
|
||||||
private func shouldTrustFullReplaceResolvedPage(
|
private func shouldTrustFullReplaceResolvedPage(
|
||||||
_ resolvedTargetPage: Int?,
|
_ resolvedTargetPage: Int?,
|
||||||
livePageBeforeApply: Int
|
livePageBeforeApply: Int,
|
||||||
|
locationMatchesLivePage: Bool
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard let resolvedTargetPage else { return false }
|
guard let resolvedTargetPage else { return false }
|
||||||
|
if locationMatchesLivePage {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// The location did not round-trip to the live page in the outgoing map
|
||||||
|
// (stale persisted location or mid-transition), so only follow it when it
|
||||||
|
// stays next to the page the user is actually looking at.
|
||||||
return abs(resolvedTargetPage - livePageBeforeApply) <= 1
|
return abs(resolvedTargetPage - livePageBeforeApply) <= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user