- 拆分 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>
52 lines
1.6 KiB
Swift
52 lines
1.6 KiB
Swift
import Foundation
|
|
|
|
public struct RDEPUBCFIResolverResult: Equatable {
|
|
|
|
public var href: String?
|
|
|
|
public var fileIndex: Int?
|
|
|
|
public var chapterOffset: Int?
|
|
|
|
public var fragmentID: String?
|
|
|
|
public init(href: String? = nil, fileIndex: Int? = nil, chapterOffset: Int? = nil, fragmentID: String? = nil) {
|
|
self.href = href
|
|
self.fileIndex = fileIndex
|
|
self.chapterOffset = chapterOffset
|
|
self.fragmentID = fragmentID
|
|
}
|
|
}
|
|
|
|
public enum RDEPUBCFIResolver {
|
|
|
|
public static func resolve(_ cfi: RDEPUBCFI) -> RDEPUBCFIResolverResult {
|
|
|
|
// EPUB CFI spec: package path structure is /6/2[spine]/2n[manifest-id]
|
|
// Manifest step is always the 3rd step (index 2) if present, or the last step with an id assertion.
|
|
let manifestStep: RDEPUBCFIStep?
|
|
if cfi.packagePath.steps.count >= 3 {
|
|
manifestStep = cfi.packagePath.steps[2]
|
|
} else {
|
|
manifestStep = cfi.packagePath.steps.last(where: { $0.idAssertion?.rd_nilIfEmpty != nil })
|
|
}
|
|
let href = manifestStep?.idAssertion
|
|
|
|
// Spine step is the 2nd step (index 1) in the package path
|
|
let fileIndex: Int?
|
|
if cfi.packagePath.steps.count >= 2 {
|
|
fileIndex = max((cfi.packagePath.steps[1].index / 2) - 1, 0)
|
|
} else {
|
|
fileIndex = nil
|
|
}
|
|
|
|
let fragmentID = cfi.contentPath.steps.last(where: { $0.idAssertion?.rd_nilIfEmpty != nil })?.idAssertion
|
|
return RDEPUBCFIResolverResult(
|
|
href: href,
|
|
fileIndex: fileIndex,
|
|
chapterOffset: cfi.characterOffset,
|
|
fragmentID: fragmentID
|
|
)
|
|
}
|
|
}
|