feat: EPUB阅读器搜索、注释、CFI模块及大书远距跳转优化
- 实现EPUB阅读器搜索功能及选中注释功能 - 优化CFI模块,修复代码审查发现的11个问题 - 实现大书远距目录跳转与后台补全优化方案 - 优化设置面板与章节运行时联动 - 重构及大量改进优化
This commit is contained in:
@@ -1,39 +1,30 @@
|
||||
// RDEPUBWebView.swift
|
||||
// EPUB WebView 主类
|
||||
// 封装 WKWebView 的 EPUB 渲染能力,是 Resource View 层的核心组件。
|
||||
// 统一管理固定版式和重排模式的加载流程,持有当前渲染状态(spineIndex、pageIndex、
|
||||
// 主题色、高亮等),并通过委托模式通知上层页面渲染和交互事件。
|
||||
// 具体逻辑分散在 +Configuration、+FixedLayout、+Reflowable、+JavaScriptBridge、+Search 扩展中。
|
||||
|
||||
import UIKit
|
||||
import WebKit
|
||||
|
||||
/// RDEPUBWebView 委托协议,定义 WebView 向上层通知的事件
|
||||
public protocol RDEPUBWebViewDelegate: AnyObject {
|
||||
/// 阅读位置更新事件
|
||||
|
||||
func epubWebView(_ webView: RDEPUBWebView, didUpdateLocation location: RDEPUBLocation, spineIndex: Int)
|
||||
/// 文本选择变化事件
|
||||
|
||||
func epubWebView(_ webView: RDEPUBWebView, didChangeSelection selection: RDEPUBSelection?, spineIndex: Int)
|
||||
/// 选择菜单动作请求事件
|
||||
|
||||
func epubWebView(_ webView: RDEPUBWebView, didRequestSelectionAction action: RDEPUBAnnotationMenuAction)
|
||||
/// 内部链接点击事件
|
||||
|
||||
func epubWebView(_ webView: RDEPUBWebView, didActivateInternalLink location: RDEPUBLocation, fromSpineIndex: Int)
|
||||
/// 外部链接点击事件
|
||||
|
||||
func epubWebView(_ webView: RDEPUBWebView, didActivateExternalLink url: URL)
|
||||
/// JavaScript 错误事件
|
||||
|
||||
func epubWebView(_ webView: RDEPUBWebView, didLogJavaScriptError message: String)
|
||||
/// 页面渲染完成事件
|
||||
|
||||
func epubWebViewDidFinishRendering(_ webView: RDEPUBWebView)
|
||||
}
|
||||
|
||||
/// 委托协议的默认实现(选择菜单动作为可选)
|
||||
public extension RDEPUBWebViewDelegate {
|
||||
func epubWebView(_ webView: RDEPUBWebView, didRequestSelectionAction action: RDEPUBAnnotationMenuAction) {}
|
||||
}
|
||||
|
||||
/// 自定义 WKWebView 子类,支持拷贝/高亮/批注选择菜单
|
||||
final class RDEPUBAnnotationWebView: WKWebView {
|
||||
/// 选择菜单动作回调
|
||||
|
||||
var onSelectionAction: ((RDEPUBAnnotationMenuAction) -> Void)?
|
||||
|
||||
override var canBecomeFirstResponder: Bool {
|
||||
@@ -64,63 +55,60 @@ final class RDEPUBAnnotationWebView: WKWebView {
|
||||
}
|
||||
}
|
||||
|
||||
/// EPUB WebView 主类,封装 WKWebView 的 EPUB 渲染能力
|
||||
/// Resource View 层核心组件,统一管理固定版式和重排模式的渲染
|
||||
public final class RDEPUBWebView: UIView {
|
||||
/// 委托对象,接收渲染和交互事件
|
||||
|
||||
public weak var delegate: RDEPUBWebViewDelegate?
|
||||
/// 渲染完成回调(与 delegate 并行使用)
|
||||
|
||||
public var onRendered: (() -> Void)?
|
||||
/// 内部原生装饰解析回调
|
||||
|
||||
var onDecorationsResolved: (([RDEPUBTextOverlayDecoration]) -> Void)?
|
||||
|
||||
/// 当前关联的出版物
|
||||
var publication: RDEPUBPublication?
|
||||
/// 当前渲染请求
|
||||
|
||||
var currentRenderRequest: RDEPUBRenderRequest?
|
||||
/// 内部 WKWebView 实例
|
||||
|
||||
var webView: WKWebView?
|
||||
/// URL Scheme 处理器
|
||||
|
||||
var schemeHandler: RDEPUBResourceURLSchemeHandler?
|
||||
/// 已配置的出版物标识(用于判断是否需要重建 WebView)
|
||||
|
||||
var configuredPublicationKey: String?
|
||||
/// 当前加载签名(用于去重相同请求)
|
||||
|
||||
var currentLoadSignature: String?
|
||||
/// 当前 spine 索引
|
||||
|
||||
var currentSpineIndex = 0
|
||||
/// 当前资源 href
|
||||
|
||||
var currentHref = ""
|
||||
/// 当前页码(从 0 开始)
|
||||
|
||||
var currentPageIndex = 0
|
||||
/// 当前章节总页数
|
||||
|
||||
var currentTotalPagesInChapter = 1
|
||||
/// 当前视口尺寸
|
||||
|
||||
var viewportSize: CGSize = .zero
|
||||
/// 当前内容内边距
|
||||
|
||||
var currentPadding: UIEdgeInsets = .zero
|
||||
/// 当前字号
|
||||
|
||||
var currentFontSize: CGFloat = 16
|
||||
/// 当前行高倍数
|
||||
|
||||
var currentLineHeightMultiple: CGFloat = 1.5
|
||||
/// 当前主题背景色
|
||||
|
||||
var currentThemeBackgroundColor: String?
|
||||
/// 当前主题文字色
|
||||
|
||||
var currentThemeTextColor: String?
|
||||
/// 目标跳转位置
|
||||
|
||||
var targetLocation: RDEPUBLocation?
|
||||
/// 待应用的高亮列表
|
||||
|
||||
var pendingHighlights: [RDEPUBHighlight] = []
|
||||
/// 当前固定版式 spread(固定版式时非空)
|
||||
|
||||
var fixedSpread: EPUBFixedSpread?
|
||||
/// 是否为固定版式模式
|
||||
|
||||
var isFixedLayout = false
|
||||
/// 是否有待处理的进度汇报请求
|
||||
|
||||
var pendingProgressionRequest = false
|
||||
/// 固定版式就绪回退定时器
|
||||
|
||||
var fixedLayoutReadyWorkItem: DispatchWorkItem?
|
||||
/// 当前请求是否已完成渲染
|
||||
|
||||
var didRenderCurrentRequest = false
|
||||
/// 调试日志作用域
|
||||
|
||||
let debugScope = "ReaderWebView"
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
@@ -141,7 +129,6 @@ public final class RDEPUBWebView: UIView {
|
||||
webView?.frame = bounds
|
||||
}
|
||||
|
||||
/// 重置所有状态并销毁 WebView
|
||||
public func reset() {
|
||||
delegate = nil
|
||||
onRendered = nil
|
||||
@@ -167,7 +154,6 @@ public final class RDEPUBWebView: UIView {
|
||||
teardownWebView()
|
||||
}
|
||||
|
||||
/// 加载渲染请求:配置 WebView、生成签名、分发到固定版式或重排处理
|
||||
public func load(publication: RDEPUBPublication, request: RDEPUBRenderRequest) {
|
||||
configureWebViewIfNeeded(publication: publication)
|
||||
guard let webView else { return }
|
||||
@@ -194,7 +180,6 @@ public final class RDEPUBWebView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
/// 生成页面加载签名
|
||||
func pageLoadSignature(
|
||||
publicationKey: String,
|
||||
request: RDEPUBRenderRequest
|
||||
@@ -207,7 +192,6 @@ public final class RDEPUBWebView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
/// 标记渲染完成:通知委托和回调,延迟 100ms 确保布局稳定
|
||||
func rendered() {
|
||||
guard !didRenderCurrentRequest else { return }
|
||||
didRenderCurrentRequest = true
|
||||
|
||||
Reference in New Issue
Block a user