源码注释: - 为 ~60 个 Swift 文件补充缺失的 doc comment(file header、类型、属性、方法) - 修正 4 处错误注释:翻页模式数量、搜索行为描述、手势识别器描述、悬空文档块 文档维护: - 删除重复文档:WXRead/读书EPUB阅读器实现架构.md(与微信读书版完全一致) - 合并重叠文档:阅读器规划.md → 阅读器功能开发计划.md(单一真值) - 修正过时内容:所有文档中"四种翻页模式"→"三种",移除 horizontalCoverScroll - 更新架构图:补齐 EPUBUI/ReaderController、Paging/、Typesetter/ 等子目录 - 更新 index.md 索引:新增开发计划和架构对比文档引用
90 lines
2.8 KiB
Swift
90 lines
2.8 KiB
Swift
// RDEPUBPublication.swift
|
||
// EPUB 出版物门面(Facade)
|
||
// 对 RDEPUBParser 的高层封装,提供 metadata、spine、TOC 等只读访问,
|
||
// 以及固定版式双页展开判断和 spread 生成等业务逻辑。
|
||
// 是 EPUBCore Publication 层对外暴露的主要接口。
|
||
|
||
import Foundation
|
||
|
||
/// EPUB 出版物门面对象,封装解析结果并提供高层访问接口
|
||
public final class RDEPUBPublication {
|
||
/// 底层解析器(持有解析数据)
|
||
public let parser: RDEPUBParser
|
||
/// 资源解析器(URL 转换和路径规范化)
|
||
public let resourceResolver: RDEPUBResourceResolver
|
||
|
||
/// 基于解析器创建出版物门面对象
|
||
/// - Parameter parser: 已完成解析的 EPUB 解析器
|
||
public init(parser: RDEPUBParser) {
|
||
self.parser = parser
|
||
self.resourceResolver = RDEPUBResourceResolver(parser: parser)
|
||
}
|
||
|
||
/// 元数据代理
|
||
public var metadata: RDEPUBMetadata {
|
||
parser.metadata
|
||
}
|
||
|
||
/// 资源清单代理
|
||
public var manifest: [String: RDEPUBManifestItem] {
|
||
parser.manifest
|
||
}
|
||
|
||
/// 阅读顺序代理
|
||
public var spine: [RDEPUBSpineItem] {
|
||
parser.spine
|
||
}
|
||
|
||
/// 目录代理
|
||
public var tableOfContents: [EPUBTableOfContentsItem] {
|
||
parser.tableOfContents
|
||
}
|
||
|
||
/// 布局模式(fixed/reflowable)
|
||
public var layout: RDEPUBLayout {
|
||
metadata.layout
|
||
}
|
||
|
||
/// 阅读配置文件(webFixedLayout/webInteractive/textReflowable)
|
||
public var readingProfile: RDEPUBReadingProfile {
|
||
parser.readingProfile()
|
||
}
|
||
|
||
/// 阅读方向(ltr/rtl/auto)
|
||
public var readingProgression: RDEPUBReadingProgression {
|
||
metadata.readingProgression
|
||
}
|
||
|
||
/// 书籍唯一标识符
|
||
public var bookIdentifier: String? {
|
||
metadata.identifier
|
||
}
|
||
|
||
/// 判断固定版式是否启用双页展开模式
|
||
/// 综合考虑 metadata.spread、偏好设置和视口方向
|
||
public func fixedLayoutSpreadEnabled(for preferences: RDEPUBPreferences, viewportSize: CGSize) -> Bool {
|
||
guard layout == .fixed else {
|
||
return false
|
||
}
|
||
guard metadata.spread?.lowercased() != "none" else {
|
||
return false
|
||
}
|
||
|
||
switch preferences.fixedLayoutSpreadMode {
|
||
case .never:
|
||
return false
|
||
case .always:
|
||
return spine.count > 1
|
||
case .automatic:
|
||
return viewportSize.width > viewportSize.height
|
||
}
|
||
}
|
||
|
||
/// 根据偏好和视口生成固定版式的 spread 数组
|
||
public func makeFixedSpreads(preferences: RDEPUBPreferences, viewportSize: CGSize) -> [EPUBFixedSpread] {
|
||
EPUBFixedSpread.makeSpreads(
|
||
spine: spine,
|
||
spreadEnabled: fixedLayoutSpreadEnabled(for: preferences, viewportSize: viewportSize)
|
||
)
|
||
}
|
||
} |