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,26 +1,20 @@
import Foundation
import UIKit
// MARK: - NSAttributedString WXRead com.weread.highlight / com.weread.underline
/// NSAttributedString CoreText
/// WXRead kWRHighlightAttributeName = "com.weread.highlight"
public let kRDEPUBHighlightAttributeName = NSAttributedString.Key("com.rdreader.highlight")
/// 线
/// WXRead kWRUnderlineAttributeName = "com.weread.underline"
public let kRDEPUBUnderlineAttributeName = NSAttributedString.Key("com.rdreader.underline")
public struct RDEPUBSelection: Codable, Equatable {
///
public var bookIdentifier: String?
///
public var location: RDEPUBLocation
///
public var text: String
/// DOM Range JSON
public var rangeInfo: String?
///
public var createdAt: Date
public init(
@@ -37,51 +31,38 @@ public struct RDEPUBSelection: Codable, Equatable {
self.createdAt = createdAt
}
///
public var isEmpty: Bool {
text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
}
///
/// - highlight:
/// - underline: 线
public enum RDEPUBHighlightStyle: String, Codable {
case highlight
case underline
}
/// WXRead WRBookmark
public enum RDEPUBAnnotationKind: String, Codable, Equatable {
case bookmark
case highlight
case underline
}
///
public enum RDEPUBAnnotationMenuAction: Equatable {
case copy
case highlight
case annotate
}
/// EPUB
/// 使 DOM Range DTCoreText
public struct RDEPUBTextOffsetRangeInfo: Codable, Equatable {
/// "text-offset"
public var kind: String
///
public var href: String
///
public var start: Int
///
public var end: Int
///
/// - Parameters:
/// - href:
/// - start:
/// - end:
public init(href: String, start: Int, end: Int) {
self.kind = "text-offset"
self.href = href
@@ -89,19 +70,16 @@ public struct RDEPUBTextOffsetRangeInfo: Codable, Equatable {
self.end = end
}
/// NSRange NSAttributedString
public var nsRange: NSRange? {
guard end > start else { return nil }
return NSRange(location: start, length: end - start)
}
/// JSON
public func jsonString() -> String? {
guard let data = try? JSONEncoder().encode(self) else { return nil }
return String(data: data, encoding: .utf8)
}
/// JSON kind
public static func decode(from string: String?) -> RDEPUBTextOffsetRangeInfo? {
guard let string,
let data = string.data(using: .utf8),
@@ -114,25 +92,24 @@ public struct RDEPUBTextOffsetRangeInfo: Codable, Equatable {
}
}
///
public struct RDEPUBHighlight: Codable, Equatable {
///
public var id: String
///
public var bookIdentifier: String?
///
public var location: RDEPUBLocation
///
public var text: String
/// Web EPUB DOM Range JSON EPUB JSON
public var rangeInfo: String?
/// 线
public var style: RDEPUBHighlightStyle
/// CSS "#F8E16C"
public var color: String
///
public var note: String?
///
public var createdAt: Date
public init(
@@ -157,18 +134,15 @@ public struct RDEPUBHighlight: Codable, Equatable {
self.createdAt = createdAt
}
///
public var hasNote: Bool {
note?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false
}
/// CSS hex UIColor WXRead UIColorForHighlightColor35% alpha
public var uiColor: UIColor {
UIColor(rdHexString: color, alpha: 0.35)
?? UIColor(red: 248 / 255, green: 225 / 255, blue: 108 / 255, alpha: 0.35)
}
/// Codable /
private enum CodingKeys: String, CodingKey {
case id
case bookIdentifier
@@ -181,7 +155,6 @@ public struct RDEPUBHighlight: Codable, Equatable {
case createdAt
}
/// 使
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
@@ -200,7 +173,6 @@ public struct RDEPUBHighlight: Codable, Equatable {
createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt) ?? Date()
}
///
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
@@ -219,19 +191,18 @@ public struct RDEPUBHighlight: Codable, Equatable {
}
}
///
public struct RDEPUBBookmark: Codable, Equatable {
///
public var id: String
///
public var bookIdentifier: String?
///
public var location: RDEPUBLocation
///
public var chapterTitle: String?
///
public var note: String?
///
public var createdAt: Date
public init(
@@ -250,7 +221,6 @@ public struct RDEPUBBookmark: Codable, Equatable {
self.createdAt = createdAt
}
///
public var hasNote: Bool {
note?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false
}
@@ -260,7 +230,6 @@ public struct RDEPUBBookmark: Codable, Equatable {
}
}
/// WXRead WRBookmark
public struct RDEPUBAnnotation: Codable, Equatable {
public var id: String
public var bookIdentifier: String?
@@ -358,7 +327,6 @@ public struct RDEPUBAnnotation: Codable, Equatable {
}
}
private extension String {
var nilIfEmpty: String? {
let trimmed = trimmingCharacters(in: .whitespacesAndNewlines)