refactor: split reader architecture and chrome handling
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import UIKit
|
||||
|
||||
final class RDEPUBReaderChromeCoordinator {
|
||||
private unowned let context: RDEPUBReaderContext
|
||||
|
||||
init(context: RDEPUBReaderContext) {
|
||||
self.context = context
|
||||
}
|
||||
|
||||
private var controller: RDEPUBReaderController? {
|
||||
context.controller
|
||||
}
|
||||
|
||||
func makeTopToolView() -> RDEPUBReaderTopToolView {
|
||||
let toolView = RDEPUBReaderTopToolView()
|
||||
toolView.onBack = { [weak self] in
|
||||
print("[Debug] onBack fired, controller: \(String(describing: self?.controller))")
|
||||
self?.handleBackAction()
|
||||
}
|
||||
toolView.onToggleBookmark = { [weak self] in
|
||||
_ = self?.context.runtime?.toggleBookmark()
|
||||
}
|
||||
return toolView
|
||||
}
|
||||
|
||||
func makeBottomToolView() -> RDEPUBReaderBottomToolView {
|
||||
let toolView = RDEPUBReaderBottomToolView()
|
||||
toolView.onShowTableOfContents = { [weak self] in
|
||||
self?.presentTableOfContents()
|
||||
}
|
||||
toolView.onShowBookmarks = { [weak self] in
|
||||
self?.context.runtime?.presentBookmarksManager()
|
||||
}
|
||||
toolView.onShowHighlights = { [weak self] in
|
||||
self?.context.runtime?.presentHighlightsManager()
|
||||
}
|
||||
toolView.onAddHighlight = { [weak self] in
|
||||
self?.context.runtime?.presentAnnotationCreation()
|
||||
}
|
||||
toolView.onShowSettings = { [weak self] in
|
||||
self?.presentSettings()
|
||||
}
|
||||
return toolView
|
||||
}
|
||||
|
||||
func updateReaderChrome() {
|
||||
guard let controller else { return }
|
||||
controller.topToolView.apply(theme: controller.configuration.theme)
|
||||
controller.topToolView.setTitle(
|
||||
controller.title
|
||||
?? controller.parser?.metadata.title
|
||||
?? controller.epubURL.deletingPathExtension().lastPathComponent
|
||||
)
|
||||
controller.topToolView.setBookmarkEnabled(controller.currentBookIdentifier != nil)
|
||||
controller.bottomToolView.apply(theme: controller.configuration.theme)
|
||||
controller.bottomToolView.updateVisibility(
|
||||
showsTableOfContents: controller.configuration.showsTableOfContents,
|
||||
allowsHighlights: controller.configuration.allowsHighlights,
|
||||
showsSettingsPanel: controller.configuration.showsSettingsPanel
|
||||
)
|
||||
controller.bottomToolView.setBookmarksEnabled(!controller.activeBookmarks.isEmpty)
|
||||
controller.bottomToolView.setAddHighlightEnabled(
|
||||
controller.configuration.allowsHighlights && controller.currentSelection != nil
|
||||
)
|
||||
controller.bottomToolView.setHighlightsEnabled(
|
||||
controller.configuration.allowsHighlights && !controller.activeHighlights.isEmpty
|
||||
)
|
||||
controller.updateBookmarkChrome()
|
||||
}
|
||||
|
||||
func presentSettings() {
|
||||
guard let controller else { return }
|
||||
guard controller.configuration.showsSettingsPanel else { return }
|
||||
let settingsController = RDEPUBReaderSettingsViewController(
|
||||
configuration: controller.configuration,
|
||||
brightness: controller.currentBrightness
|
||||
)
|
||||
settingsController.onBrightnessChange = { [weak controller] brightness in
|
||||
controller?.setScreenBrightness(brightness)
|
||||
}
|
||||
settingsController.onFontSizeChange = { [weak controller] fontSize in
|
||||
controller?.updateConfiguration { $0.fontSize = fontSize }
|
||||
}
|
||||
settingsController.onLineHeightChange = { [weak controller] lineHeightMultiple in
|
||||
controller?.updateConfiguration { $0.lineHeightMultiple = lineHeightMultiple }
|
||||
}
|
||||
settingsController.onColumnCountChange = { [weak controller] numberOfColumns in
|
||||
controller?.updateConfiguration { $0.numberOfColumns = numberOfColumns }
|
||||
}
|
||||
settingsController.onDisplayTypeChange = { [weak controller] displayType in
|
||||
controller?.updateConfiguration { $0.displayType = displayType }
|
||||
}
|
||||
settingsController.onThemeChange = { [weak controller] theme in
|
||||
controller?.updateConfiguration { $0.theme = theme }
|
||||
}
|
||||
|
||||
let navigationController = UINavigationController(rootViewController: settingsController)
|
||||
navigationController.modalPresentationStyle = .pageSheet
|
||||
controller.present(navigationController, animated: true)
|
||||
}
|
||||
|
||||
func presentTableOfContents() {
|
||||
guard let controller else { return }
|
||||
guard controller.configuration.showsTableOfContents else { return }
|
||||
let items = controller.flattenedTableOfContents
|
||||
guard !items.isEmpty else { return }
|
||||
|
||||
let chapterController = RDEPUBReaderChapterListController(
|
||||
items: items,
|
||||
currentItem: controller.currentTableOfContentsItem,
|
||||
theme: controller.configuration.theme
|
||||
)
|
||||
chapterController.onSelectItem = { [weak controller] item in
|
||||
guard let controller else { return }
|
||||
chapterController.dismiss(animated: true) {
|
||||
_ = controller.go(toTableOfContentsItem: item, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
let navigationController = UINavigationController(rootViewController: chapterController)
|
||||
navigationController.modalPresentationStyle = .pageSheet
|
||||
controller.present(navigationController, animated: true)
|
||||
}
|
||||
|
||||
func handleBackAction() {
|
||||
guard let controller else { return }
|
||||
close(controller)
|
||||
}
|
||||
|
||||
private func close(_ controller: UIViewController) {
|
||||
let target = closestDismissTarget(from: controller)
|
||||
if let navigationController = target.navigationController,
|
||||
navigationController.viewControllers.first !== target {
|
||||
navigationController.popViewController(animated: true)
|
||||
return
|
||||
}
|
||||
|
||||
if let navigationController = target.navigationController,
|
||||
navigationController.presentingViewController != nil {
|
||||
navigationController.dismiss(animated: true)
|
||||
return
|
||||
}
|
||||
|
||||
if target.presentingViewController != nil {
|
||||
target.dismiss(animated: true)
|
||||
return
|
||||
}
|
||||
|
||||
controller.dismiss(animated: true)
|
||||
}
|
||||
|
||||
private func closestDismissTarget(from controller: UIViewController) -> UIViewController {
|
||||
var candidate: UIViewController = controller
|
||||
var current = controller.parent
|
||||
while let parent = current {
|
||||
if let navigationController = parent.navigationController,
|
||||
navigationController.viewControllers.contains(parent) {
|
||||
return parent
|
||||
}
|
||||
if parent.presentingViewController != nil || parent.navigationController?.presentingViewController != nil {
|
||||
return parent
|
||||
}
|
||||
candidate = parent
|
||||
current = parent.parent
|
||||
}
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user