feat: EPUB阅读器搜索、注释、CFI模块及大书远距跳转优化

- 实现EPUB阅读器搜索功能及选中注释功能
- 优化CFI模块,修复代码审查发现的11个问题
- 实现大书远距目录跳转与后台补全优化方案
- 优化设置面板与章节运行时联动
- 重构及大量改进优化
This commit is contained in:
shenlei
2026-06-22 20:26:34 +08:00
parent f50495ad91
commit c65c190b71
178 changed files with 11380 additions and 6728 deletions
@@ -1,29 +1,6 @@
//
// RDURLReaderController.swift
// RDReaderDemo
//
// URL
// ReadViewSDK 使
// - .epub RDEPUBReaderController
// - RDPlainTextBookBuilder RDEPUBReaderController
// - 退 UITextView
//
// RDReaderView UI
//
import UIKit
/// URL
/// URL
/// - EPUB 使 RDEPUBReaderController
/// - RDPlainTextBookBuilder 使 RDEPUBReaderController
/// - 退 UITextView
///
/// 使
/// ```swift
/// let controller = RDURLReaderController(bookURL: fileURL)
/// navigationController?.pushViewController(controller, animated: true)
/// ```
public final class RDURLReaderController: UIViewController {
private struct PendingDemoPageRequest {
let pageNumber: Int
@@ -31,11 +8,10 @@ public final class RDURLReaderController: UIViewController {
var attemptCount: Int
}
/// URL
private let bookURL: URL
/// EPUB
private let epubConfiguration: RDEPUBReaderConfiguration
///
private var embeddedController: UIViewController?
private let demoStateLabel: UILabel = {
let label = UILabel()
@@ -58,10 +34,6 @@ public final class RDURLReaderController: UIViewController {
private var lastActivatedExternalURL: URL?
private var lastReaderErrorDescription = "none"
///
/// - Parameters:
/// - bookURL: URL
/// - epubConfiguration: EPUB 使
public init(
bookURL: URL,
epubConfiguration: RDEPUBReaderConfiguration = RDEPUBReaderConfiguration()
@@ -76,7 +48,6 @@ public final class RDURLReaderController: UIViewController {
fatalError("init(coder:) has not been implemented")
}
///
public override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
@@ -101,18 +72,11 @@ public final class RDURLReaderController: UIViewController {
stopDemoStateTimer()
}
/// Demo
/// - Parameter displayType:
public func applyDemoDisplayType(_ displayType: RDReaderView.DisplayType) {
readerController?.configuration.displayType = displayType
emitDemoState(prefix: "display=\(displayType.demoArgumentValue)")
}
/// Demo
/// - Parameters:
/// - pageNumber:
/// - animated:
/// - Returns:
@discardableResult
public func goToDemoPage(_ pageNumber: Int, animated: Bool = false) -> Bool {
let moved = performDemoPageNavigation(pageNumber, animated: animated)
@@ -125,12 +89,6 @@ public final class RDURLReaderController: UIViewController {
return moved
}
/// Demo
///
/// - Parameters:
/// - displayTypes:
/// - initialPageNumber:
/// - stepDelay:
public func runDemoDisplaySequence(
_ displayTypes: [RDReaderView.DisplayType],
initialPageNumber: Int? = nil,
@@ -151,9 +109,6 @@ public final class RDURLReaderController: UIViewController {
}
}
/// Demo
/// `didUpdateLocation`
/// - Parameter keyword:
public func performDemoSearch(keyword: String) {
guard let readerController else { return }
readerController.showSearchBar()
@@ -187,8 +142,6 @@ public final class RDURLReaderController: UIViewController {
submitSearchAfterDelay(keyword: keyword, retries: 5)
}
///
/// Child View Controller
private func embedReaderController() {
let controller: UIViewController
if bookURL.pathExtension.lowercased() == "epub" {
@@ -224,7 +177,7 @@ public final class RDURLReaderController: UIViewController {
configuration: epubConfiguration
)
} else {
// 退
let fallback = UIViewController()
let textView = UITextView()
textView.isEditable = false
@@ -248,7 +201,6 @@ public final class RDURLReaderController: UIViewController {
emitDemoState()
}
/// EPUB
private var readerController: RDEPUBReaderController? {
embeddedController as? RDEPUBReaderController
}
@@ -322,7 +274,6 @@ public final class RDURLReaderController: UIViewController {
}
}
/// Demo
private func logDemoState(prefix: String) {
guard let readerController else { return }
let location = readerController.currentLocation
@@ -372,6 +323,9 @@ public final class RDURLReaderController: UIViewController {
let location = readerController?.currentLocation
let href = encodedDemoLocationHref(location?.href)
let progression = location.map { String(format: "%.4f", $0.navigationProgression) } ?? "nil"
let cfi = encodedDemoField(location?.cfi)
let lastCFI = encodedDemoField(location?.lastCFI)
let rangeCFI = encodedDemoField(location?.rangeCFI)
let mapSnapshot = demoPaginationSnapshot()
let layoutConfig = readerController?.readerContext.currentTextLayoutConfig(pageSize: currentTextPageSize())
let resourceMetrics = RDEPUBResourceURLSchemeHandler.debugMetricsSnapshot()
@@ -388,6 +342,9 @@ public final class RDURLReaderController: UIViewController {
"selection=\(selection)",
"href=\(href)",
"progression=\(progression)",
"cfi=\(cfi)",
"lastCFI=\(lastCFI)",
"rangeCFI=\(rangeCFI)",
"mode=\(mapSnapshot.mode)",
"pagination=\(mapSnapshot.phase)",
"knownPages=\(mapSnapshot.knownPages)",
@@ -464,14 +421,10 @@ public final class RDURLReaderController: UIViewController {
return ("snapshot", snapshotPages > 0 ? "full" : "none", snapshotPages, snapshotChapters, snapshotChapters)
}
///
/// 使 viewport layoutConfig.edgeInsets
///
private func currentTextPageSize() -> CGSize {
UIScreen.main.bounds.size
}
///
private func currentTextRenderStyle() -> RDEPUBTextRenderStyle {
let font = epubConfiguration.fontChoice.font(ofSize: epubConfiguration.fontSize)
let lineSpacing = max(font.lineHeight * (epubConfiguration.lineHeightMultiple - 1), 4)
@@ -483,8 +436,6 @@ public final class RDURLReaderController: UIViewController {
)
}
///
/// UTF-8 GBK GB2312
private func rd_decodeTextFile(url: URL) -> String {
if let content = try? NSString(contentsOf: url, encoding: String.Encoding.utf8.rawValue) as String {
return content
@@ -536,9 +487,8 @@ extension RDURLReaderController: RDEPUBReaderDelegate {
}
}
/// Demo
private extension RDReaderView.DisplayType {
/// Demo
var demoArgumentValue: String {
switch self {
case .pageCurl: