源码注释: - 为 ~60 个 Swift 文件补充缺失的 doc comment(file header、类型、属性、方法) - 修正 4 处错误注释:翻页模式数量、搜索行为描述、手势识别器描述、悬空文档块 文档维护: - 删除重复文档:WXRead/读书EPUB阅读器实现架构.md(与微信读书版完全一致) - 合并重叠文档:阅读器规划.md → 阅读器功能开发计划.md(单一真值) - 修正过时内容:所有文档中"四种翻页模式"→"三种",移除 horizontalCoverScroll - 更新架构图:补齐 EPUBUI/ReaderController、Paging/、Typesetter/ 等子目录 - 更新 index.md 索引:新增开发计划和架构对比文档引用
94 lines
3.9 KiB
Swift
94 lines
3.9 KiB
Swift
import Foundation
|
||
|
||
/// EPUB 阅读器加载协调器:负责 EPUB 文件的解析和出版物初始化。
|
||
///
|
||
/// 职责:
|
||
/// - 判断是否需要执行首次加载
|
||
/// - 后台解析 EPUB 文件并构建 Publication 模型
|
||
/// - 将解析结果应用到阅读器上下文并触发分页
|
||
final class RDEPUBReaderLoadCoordinator {
|
||
private unowned let context: RDEPUBReaderContext
|
||
|
||
init(context: RDEPUBReaderContext) {
|
||
self.context = context
|
||
}
|
||
|
||
/// 检查条件后启动首次加载,确保只执行一次且视图已布局。
|
||
func startInitialLoadIfNeeded() {
|
||
guard let controller = context.controller,
|
||
let readerView = context.readerView,
|
||
!controller.didStartInitialLoad,
|
||
readerView.bounds.width > 0,
|
||
readerView.bounds.height > 0 else {
|
||
return
|
||
}
|
||
controller.didStartInitialLoad = true
|
||
loadPublication()
|
||
}
|
||
|
||
/// 后台解析 EPUB 文件,加载书签、高亮和阅读位置,完成后回调主线程。
|
||
func loadPublication() {
|
||
guard let controller = context.controller else { return }
|
||
context.showLoading()
|
||
let loadToken = UUID()
|
||
context.paginationToken = loadToken
|
||
|
||
DispatchQueue.global(qos: .userInitiated).async { [weak controller] in
|
||
guard let controller else { return }
|
||
let parser = self.context.makeParser()
|
||
|
||
do {
|
||
try parser.parse(epubURL: controller.epubURL)
|
||
let publication = parser.makePublication()
|
||
let bookIdentifier = parser.metadata.identifier ?? controller.epubURL.lastPathComponent
|
||
let restoreLocation = controller.persistence?.loadLocation(for: bookIdentifier)
|
||
let bookmarks = controller.persistence?.loadBookmarks(for: bookIdentifier) ?? []
|
||
let highlights = controller.persistence?.loadHighlights(for: bookIdentifier) ?? []
|
||
|
||
DispatchQueue.main.async {
|
||
guard self.context.paginationToken == loadToken else { return }
|
||
self.context.runtime?.applyParsedPublication(
|
||
parser: parser,
|
||
publication: publication,
|
||
bookIdentifier: bookIdentifier,
|
||
restoreLocation: restoreLocation,
|
||
bookmarks: bookmarks,
|
||
highlights: highlights
|
||
)
|
||
}
|
||
} catch {
|
||
DispatchQueue.main.async {
|
||
guard self.context.paginationToken == loadToken else { return }
|
||
self.context.handle(error: error)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 将解析完成的出版物应用到上下文,设置书签/高亮/会话,并触发分页。
|
||
func applyParsedPublication(
|
||
parser: RDEPUBParser,
|
||
publication: RDEPUBPublication,
|
||
bookIdentifier: String,
|
||
restoreLocation: RDEPUBLocation?,
|
||
bookmarks: [RDEPUBBookmark],
|
||
highlights: [RDEPUBHighlight]
|
||
) {
|
||
guard let controller = context.controller else { return }
|
||
context.parser = parser
|
||
context.publication = publication
|
||
context.currentBookIdentifier = bookIdentifier
|
||
context.activeBookmarks = bookmarks
|
||
context.activeHighlights = highlights
|
||
context.readingSession = RDEPUBReadingSession(publication: publication)
|
||
context.readingSession?.transition(to: .loading)
|
||
controller.title = parser.metadata.title.isEmpty
|
||
? controller.epubURL.deletingPathExtension().lastPathComponent
|
||
: parser.metadata.title
|
||
controller.applyReaderViewConfiguration()
|
||
context.updateReaderChrome()
|
||
controller.delegate?.epubReader(controller, didOpen: publication)
|
||
context.runtime?.paginatePublication(restoreLocation: restoreLocation)
|
||
}
|
||
}
|