feat: 交互协调器拆分、附件提示、暗色图片适配、选区放大镜及文档清理
- 拆分 ContentDelegates/TextContentView 为独立协调器(InteractionCoordinator、LocationResolution、ExternalLinks、AttachmentTooltip) - 新增 RDEPUBAttachmentTooltipView/OverlayView 附件气泡提示 - 新增 RDEPUBDarkImageAdjuster 暗色模式图片亮度适配 - 新增 RDEPUBSelectionLoupeView 选区放大镜 - 新增 MetadataParseWorker/CancellationController 元数据解析取消机制 - 重构 PresentationRuntime/PaginationCoordinator 精简职责 - 优化 ChapterLoader/WarmupOrchestrator 异步章节加载 - CFI 模块微调与 NoteModels 更新 - 清理冗余文档,更新架构/UML/业务逻辑文档 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -75,7 +75,7 @@ public enum RDEPUBCFIDOMPathBuilder {
|
||||
match.numberOfRanges > 2 else {
|
||||
return nil
|
||||
}
|
||||
return nsAttributes.substring(with: match.range(at: 2)).rd_cfiNilIfEmpty
|
||||
return nsAttributes.substring(with: match.range(at: 2)).rd_nilIfEmpty
|
||||
}
|
||||
|
||||
static func isIgnorableTag(_ tagName: String) -> Bool {
|
||||
@@ -138,8 +138,8 @@ enum RDEPUBCFITextNodeMapBuilder {
|
||||
markers: markers,
|
||||
pathRanges: pathRanges,
|
||||
recoveryMetadata: RDEPUBCFIRecoveryMetadata(
|
||||
domFingerprint: rawHTML.sha256Hex,
|
||||
normalizedTextChecksum: normalizedChapter.normalizedText.sha256Hex,
|
||||
domFingerprint: rawHTML.rd_sha256Hex,
|
||||
normalizedTextChecksum: normalizedChapter.normalizedText.rd_sha256Hex,
|
||||
tokenIndex: makeTokenAnchors(
|
||||
normalizedChapter: normalizedChapter,
|
||||
markers: markers,
|
||||
@@ -516,14 +516,6 @@ private struct RDEPUBNormalizedTextIndex {
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
var rd_cfiNilIfEmpty: String? {
|
||||
let trimmed = trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return trimmed.isEmpty ? nil : trimmed
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension String {
|
||||
var fnv1a64: UInt64 {
|
||||
let offsetBasis: UInt64 = 14695981039346656037
|
||||
|
||||
@@ -114,7 +114,7 @@ public enum RDEPUBCFIParser {
|
||||
if let open = rawStep.firstIndex(of: "["),
|
||||
let close = rawStep.lastIndex(of: "]"),
|
||||
open < close {
|
||||
idAssertion = String(rawStep[rawStep.index(after: open)..<close]).rd_cfiNilIfEmpty
|
||||
idAssertion = String(rawStep[rawStep.index(after: open)..<close]).rd_nilIfEmpty
|
||||
} else {
|
||||
idAssertion = nil
|
||||
}
|
||||
|
||||
@@ -34,6 +34,6 @@ public struct RDEPUBCFIStep: Codable, Equatable, Hashable {
|
||||
|
||||
public init(index: Int, idAssertion: String? = nil) {
|
||||
self.index = index
|
||||
self.idAssertion = idAssertion?.rd_cfiNilIfEmpty
|
||||
self.idAssertion = idAssertion?.rd_nilIfEmpty
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public enum RDEPUBCFIResolver {
|
||||
if cfi.packagePath.steps.count >= 3 {
|
||||
manifestStep = cfi.packagePath.steps[2]
|
||||
} else {
|
||||
manifestStep = cfi.packagePath.steps.last(where: { $0.idAssertion?.rd_cfiNilIfEmpty != nil })
|
||||
manifestStep = cfi.packagePath.steps.last(where: { $0.idAssertion?.rd_nilIfEmpty != nil })
|
||||
}
|
||||
let href = manifestStep?.idAssertion
|
||||
|
||||
@@ -40,7 +40,7 @@ public enum RDEPUBCFIResolver {
|
||||
fileIndex = nil
|
||||
}
|
||||
|
||||
let fragmentID = cfi.contentPath.steps.last(where: { $0.idAssertion?.rd_cfiNilIfEmpty != nil })?.idAssertion
|
||||
let fragmentID = cfi.contentPath.steps.last(where: { $0.idAssertion?.rd_nilIfEmpty != nil })?.idAssertion
|
||||
return RDEPUBCFIResolverResult(
|
||||
href: href,
|
||||
fileIndex: fileIndex,
|
||||
|
||||
Reference in New Issue
Block a user