源码注释: - 为 ~60 个 Swift 文件补充缺失的 doc comment(file header、类型、属性、方法) - 修正 4 处错误注释:翻页模式数量、搜索行为描述、手势识别器描述、悬空文档块 文档维护: - 删除重复文档:WXRead/读书EPUB阅读器实现架构.md(与微信读书版完全一致) - 合并重叠文档:阅读器规划.md → 阅读器功能开发计划.md(单一真值) - 修正过时内容:所有文档中"四种翻页模式"→"三种",移除 horizontalCoverScroll - 更新架构图:补齐 EPUBUI/ReaderController、Paging/、Typesetter/ 等子目录 - 更新 index.md 索引:新增开发计划和架构对比文档引用
80 lines
3.9 KiB
Swift
80 lines
3.9 KiB
Swift
import UIKit
|
||
|
||
/// EPUB 阅读器界面组装协调器:负责阅读器初次启动时的 UI 搭建。
|
||
///
|
||
/// 职责:
|
||
/// - 组装阅读器视图层次结构(readerView、loadingIndicator、errorLabel)
|
||
/// - 注册内容视图类型
|
||
/// - 处理外部纯文本图书的启动收尾逻辑
|
||
final class RDEPUBReaderAssemblyCoordinator {
|
||
private unowned let context: RDEPUBReaderContext
|
||
|
||
init(context: RDEPUBReaderContext) {
|
||
self.context = context
|
||
}
|
||
|
||
/// 组装阅读器界面:添加 readerView、loadingIndicator、errorLabel 到控制器视图,并配置顶部工具栏。
|
||
func assembleInterface() {
|
||
guard let controller = context.controller,
|
||
let readerView = context.readerView else { return }
|
||
|
||
controller.view.backgroundColor = context.configuration.theme.contentBackgroundColor
|
||
setupReaderView(readerView, in: controller.view)
|
||
setupLoadingIndicator(controller.loadingIndicator, in: controller.view)
|
||
setupErrorLabel(controller.errorLabel, in: controller.view)
|
||
controller.delegate?.epubReader(controller, configureTopToolView: controller.topToolView)
|
||
}
|
||
|
||
/// 外部纯文本图书启动时,加载已保存的书签、高亮和阅读位置,完成分页收尾。
|
||
func finishExternalTextBookLaunchIfNeeded() {
|
||
guard let runtime = context.runtime,
|
||
context.isExternalTextBook else {
|
||
return
|
||
}
|
||
|
||
let restoreLocation = context.currentBookIdentifier.flatMap { context.persistence?.loadLocation(for: $0) }
|
||
if let id = context.currentBookIdentifier {
|
||
context.activeBookmarks = context.persistence?.loadBookmarks(for: id) ?? []
|
||
context.activeHighlights = context.persistence?.loadHighlights(for: id) ?? []
|
||
}
|
||
runtime.finishPagination(restoreLocation: restoreLocation)
|
||
}
|
||
|
||
private func setupReaderView(_ readerView: RDReaderView, in containerView: UIView) {
|
||
readerView.dataSource = context.controller as? RDReaderDataSource
|
||
readerView.delegate = context.controller as? RDReaderDelegate
|
||
readerView.translatesAutoresizingMaskIntoConstraints = false
|
||
containerView.addSubview(readerView)
|
||
NSLayoutConstraint.activate([
|
||
readerView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||
readerView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||
readerView.topAnchor.constraint(equalTo: containerView.topAnchor),
|
||
readerView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
|
||
])
|
||
|
||
readerView.register(contentView: RDEPUBTextContentView.self, contentViewWithReuseIdentifier: NSStringFromClass(RDEPUBTextContentView.self))
|
||
readerView.register(contentView: RDEPUBWebContentView.self, contentViewWithReuseIdentifier: NSStringFromClass(RDEPUBWebContentView.self))
|
||
context.controller?.applyReaderViewConfiguration()
|
||
}
|
||
|
||
private func setupLoadingIndicator(_ loadingIndicator: UIActivityIndicatorView, in containerView: UIView) {
|
||
loadingIndicator.hidesWhenStopped = true
|
||
loadingIndicator.translatesAutoresizingMaskIntoConstraints = false
|
||
containerView.addSubview(loadingIndicator)
|
||
NSLayoutConstraint.activate([
|
||
loadingIndicator.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
|
||
loadingIndicator.centerYAnchor.constraint(equalTo: containerView.centerYAnchor)
|
||
])
|
||
}
|
||
|
||
private func setupErrorLabel(_ errorLabel: UILabel, in containerView: UIView) {
|
||
errorLabel.translatesAutoresizingMaskIntoConstraints = false
|
||
containerView.addSubview(errorLabel)
|
||
NSLayoutConstraint.activate([
|
||
errorLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 24),
|
||
errorLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -24),
|
||
errorLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor)
|
||
])
|
||
}
|
||
}
|