feat: EPUB 阅读器搜索、选中注释、书签 chrome 状态及大量重构优化
- 新增 RDEPUBReaderSearchCoordinator 与 RDEPUBSelectionState 管理搜索和选中状态 - 新增 BookmarkChromeStateTests、NavigationBackwardTests、SelectionAnnotateTests 等 UI 测试 - 新增多个边界测试 epub 样本(损坏结构、空归档、缺失文件、流式外链验证) - 重构阅读器 chrome 状态管理,统一 tool bar 与 search bar 交互 - 优化大书分页缓存策略(RDEPUBChapterSummaryDiskCache、RDEPUBPageCountCache) - 移除废弃的 RDEPUBLocationConverter 和 RDEPUBPageBreakPolicy - 更新 epub-bridge.js 与 JS bridge 通信协议 - 全面更新现有 UI 测试以适配新的 helper 和状态管理
This commit is contained in:
@@ -31,6 +31,8 @@ public final class RDEPUBReadingSession {
|
||||
public private(set) var pendingNavigationLocation: RDEPUBLocation?
|
||||
/// 挂起的导航目标页码
|
||||
public private(set) var pendingNavigationPageNum: Int?
|
||||
/// 挂起的高亮 Range 信息(仅 Web 渲染路径使用)
|
||||
public private(set) var pendingNavigationHighlightRangeInfo: String?
|
||||
/// 当前视口信息
|
||||
public private(set) var currentViewport: RDEPUBViewport?
|
||||
/// 当前阅读上下文(位置 + 视口 + 页码 + 章节)
|
||||
@@ -105,6 +107,7 @@ public final class RDEPUBReadingSession {
|
||||
public func clearPendingNavigation() {
|
||||
pendingNavigationLocation = nil
|
||||
pendingNavigationPageNum = nil
|
||||
pendingNavigationHighlightRangeInfo = nil
|
||||
}
|
||||
|
||||
/// 检查指定页码和 spine 索引是否有挂起的导航位置
|
||||
@@ -123,6 +126,26 @@ public final class RDEPUBReadingSession {
|
||||
return pendingNavigationLocation
|
||||
}
|
||||
|
||||
/// 查询指定页是否存在待消费的高亮 Range 信息。
|
||||
public func pendingHighlightRangeInfo(forPageNumber pageNumber: Int, spineIndex: Int?) -> String? {
|
||||
guard pendingNavigationPageNum == pageNumber,
|
||||
let pendingNavigationHighlightRangeInfo,
|
||||
!pendingNavigationHighlightRangeInfo.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
guard let pendingNavigationLocation else {
|
||||
return pendingNavigationHighlightRangeInfo
|
||||
}
|
||||
guard let spineIndex else {
|
||||
return pendingNavigationHighlightRangeInfo
|
||||
}
|
||||
let pageHref = resourceResolver.href(forSpineIndex: spineIndex)
|
||||
guard resourceResolver.normalizedHref(pageHref ?? "") == resourceResolver.normalizedHref(pendingNavigationLocation.href) else {
|
||||
return nil
|
||||
}
|
||||
return pendingNavigationHighlightRangeInfo
|
||||
}
|
||||
|
||||
/// 判断指定页面是否包含给定的 spine 索引(固定版式需检查 spread 内所有资源)
|
||||
public func pageContains(spineIndex: Int, in page: EPUBPage) -> Bool {
|
||||
if let fixedSpread = page.fixedSpread {
|
||||
@@ -225,7 +248,8 @@ public final class RDEPUBReadingSession {
|
||||
public func queueNavigation(
|
||||
to location: RDEPUBLocation,
|
||||
relativeToSpineIndex spineIndex: Int? = nil,
|
||||
bookIdentifier: String?
|
||||
bookIdentifier: String?,
|
||||
targetHighlightRangeInfo: String? = nil
|
||||
) -> Int? {
|
||||
guard let normalizedLocation = resourceResolver.normalizedLocation(
|
||||
location,
|
||||
@@ -235,8 +259,14 @@ public final class RDEPUBReadingSession {
|
||||
return nil
|
||||
}
|
||||
|
||||
pendingNavigationLocation = normalizedLocation.fragment == nil ? nil : normalizedLocation
|
||||
pendingNavigationPageNum = normalizedLocation.fragment == nil ? nil : pageIndex + 1
|
||||
let hasTargetHighlightRangeInfo = targetHighlightRangeInfo?.isEmpty == false
|
||||
let shouldKeepPendingNavigation =
|
||||
normalizedLocation.fragment != nil ||
|
||||
normalizedLocation.rangeAnchor != nil ||
|
||||
hasTargetHighlightRangeInfo
|
||||
pendingNavigationLocation = shouldKeepPendingNavigation ? normalizedLocation : nil
|
||||
pendingNavigationPageNum = shouldKeepPendingNavigation ? pageIndex + 1 : nil
|
||||
pendingNavigationHighlightRangeInfo = hasTargetHighlightRangeInfo ? targetHighlightRangeInfo : nil
|
||||
transition(to: .jumping)
|
||||
return pageIndex + 1
|
||||
}
|
||||
@@ -363,4 +393,4 @@ public final class RDEPUBReadingSession {
|
||||
|
||||
return (pages, chapters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user