ReadViewSDK/Sources/RDReaderView/EPUBUI/RDEPUBReaderController+RuntimeBridge.swift
shenlei ed390da147 feat: unify reader chrome state management
- Add RDEPUBReaderUIState struct for centralized UI state model
- Refactor RDEPUBReaderChromeCoordinator with makeUIState() and applyUIState()
- Remove direct UI updates from RDEPUBReaderAnnotationCoordinator
- Consolidate updateBookmarkChrome() into updateReaderChrome()
- Update RDEPUBReaderContext, Runtime, and LocationCoordinator
- Add reader problem fix development checklist documentation

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 17:51:08 +08:00

281 lines
10 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// RDEPUBReaderController+RuntimeBridge.swift
// EPUB
// runtime
//
import UIKit
/// RDEPUBReaderController
///
/// runtime
///
extension RDEPUBReaderController {
/// //
func applyReaderViewConfiguration() {
let resolvedDirection = resolvedPageDirection()
let presentationDidChange = readerView.currentDisplayType != configuration.displayType
|| readerView.landscapeDualPageEnabled != configuration.landscapeDualPageEnabled
|| readerView.pageDirection != resolvedDirection
let preservedLocation = presentationDidChange
? (runtime.viewportMonitor.consumePendingPresentationRestoreLocation() ?? currentVisibleLocation() ?? persistenceLocation())
: nil
view.backgroundColor = configuration.theme.contentBackgroundColor
readerView.landscapeDualPageEnabled = configuration.landscapeDualPageEnabled
readerView.pageDirection = resolvedDirection
updateReaderChrome()
if presentationDidChange {
readerView.switchReaderDisplayType(configuration.displayType)
if let preservedLocation {
_ = restoreReadingLocation(preservedLocation)
}
}
}
///
func startInitialLoadIfNeeded() {
runtime.startInitialLoadIfNeeded()
}
/// EPUB
func loadPublication() {
runtime.loadPublication()
}
///
func applyParsedPublication(
parser: RDEPUBParser,
publication: RDEPUBPublication,
bookIdentifier: String,
restoreLocation: RDEPUBLocation?,
bookmarks: [RDEPUBBookmark],
highlights: [RDEPUBHighlight]
) {
runtime.applyParsedPublication(
parser: parser,
publication: publication,
bookIdentifier: bookIdentifier,
restoreLocation: restoreLocation,
bookmarks: bookmarks,
highlights: highlights
)
}
///
func paginatePublication(restoreLocation: RDEPUBLocation?) {
runtime.paginatePublication(restoreLocation: restoreLocation)
}
///
func applyTextBook(_ textBook: RDEPUBTextBook, restoreLocation: RDEPUBLocation?) {
runtime.applyTextBook(textBook, restoreLocation: restoreLocation)
}
///
func applyPaginationSnapshot(
_ snapshot: (pages: [EPUBPage], chapters: [EPUBChapterInfo]),
restoreLocation: RDEPUBLocation?
) {
runtime.applyPaginationSnapshot(snapshot, restoreLocation: restoreLocation)
}
///
func finishPagination(restoreLocation: RDEPUBLocation?) {
runtime.finishPagination(restoreLocation: restoreLocation)
}
///
func repaginatePreservingCurrentLocation() {
runtime.repaginatePreservingCurrentLocation()
}
///
@discardableResult
func restoreReadingLocation(_ location: RDEPUBLocation, animated: Bool = false) -> Bool {
runtime.restoreReadingLocation(location, animated: animated)
}
///
func currentVisibleLocation() -> RDEPUBLocation? {
runtime.currentVisibleLocation()
}
///
func persistenceLocation() -> RDEPUBLocation? {
readerContext.persistenceLocation()
}
///
func persist(location: RDEPUBLocation) {
readerContext.persist(location: location)
}
///
func updateCurrentSelection(_ selection: RDEPUBSelection?) {
runtime.annotationCoordinator.updateCurrentSelection(selection)
}
/// spine
func scopedSelection(
_ selection: RDEPUBSelection,
relativeToSpineIndex spineIndex: Int?
) -> RDEPUBSelection? {
runtime.annotationCoordinator.scopedSelection(selection, relativeToSpineIndex: spineIndex)
}
///
func refreshVisibleContentPreservingLocation() {
runtime.refreshVisibleContentPreservingLocation()
}
///
func rebuildExternalTextBook() {
runtime.rebuildExternalTextBook()
}
/// UI
func updateReaderChrome() {
runtime.updateReaderChrome()
}
///
func presentBookmarksManager() {
runtime.presentBookmarksManager()
}
///
func presentHighlightsManager() {
runtime.presentHighlightsManager()
}
///
func presentAnnotationCreation() {
runtime.presentAnnotationCreation()
}
///
func handleSelectionMenuAction(_ action: RDEPUBAnnotationMenuAction, selection: RDEPUBSelection?) {
runtime.handleSelectionMenuAction(action, selection: selection)
}
///
func presentSettings() {
runtime.presentSettings()
}
/// 使
func updateConfiguration(_ update: (inout RDEPUBReaderConfiguration) -> Void) {
var nextConfiguration = configuration
update(&nextConfiguration)
configuration = nextConfiguration
}
///
func setScreenBrightness(_ brightness: CGFloat) {
currentBrightness = max(0, min(1, brightness))
persistReaderSettingsIfNeeded()
}
///
func persistReaderSettingsIfNeeded() {
let settings = RDEPUBReaderSettings.capture(
configuration: configuration,
brightness: currentBrightness
)
persistence?.saveReaderSettings(settings)
}
///
func requiresRepagination(
from oldConfiguration: RDEPUBReaderConfiguration,
to newConfiguration: RDEPUBReaderConfiguration
) -> Bool {
oldConfiguration.fontSize != newConfiguration.fontSize ||
oldConfiguration.fontChoice != newConfiguration.fontChoice ||
oldConfiguration.lineHeightMultiple != newConfiguration.lineHeightMultiple ||
oldConfiguration.numberOfColumns != newConfiguration.numberOfColumns ||
oldConfiguration.columnGap != newConfiguration.columnGap ||
oldConfiguration.reflowableContentInsets != newConfiguration.reflowableContentInsets ||
oldConfiguration.fixedContentInset != newConfiguration.fixedContentInset ||
oldConfiguration.fixedLayoutFit != newConfiguration.fixedLayoutFit ||
oldConfiguration.fixedLayoutSpreadMode != newConfiguration.fixedLayoutSpreadMode ||
oldConfiguration.textRenderingEngine != newConfiguration.textRenderingEngine
}
///
func requiresVisibleRefresh(
from oldConfiguration: RDEPUBReaderConfiguration,
to newConfiguration: RDEPUBReaderConfiguration
) -> Bool {
oldConfiguration.theme != newConfiguration.theme ||
oldConfiguration.darkImageAdjustmentEnabled != newConfiguration.darkImageAdjustmentEnabled ||
oldConfiguration.darkImageBlendRatio != newConfiguration.darkImageBlendRatio
}
///
func presentTableOfContents() {
runtime.presentTableOfContents()
}
///
func handleBackAction() {
runtime.handleBackAction()
}
///
func handle(error: Error) {
isRepaginating = false
hideLoading()
readerContext.clearActiveSnapshot()
textBook = nil
readerContext.bookPageMap = nil
readerView.reloadData()
errorLabel.text = error.localizedDescription
errorLabel.isHidden = false
delegate?.epubReader(self, didFailWithError: error)
}
///
func showLoading() {
errorLabel.isHidden = true
loadingIndicator.startAnimating()
}
///
func hideLoading() {
loadingIndicator.stopAnimating()
}
///
func currentViewportSignature() -> RDEPUBViewportSignature? {
runtime.currentViewportSignature()
}
///
func handleViewportChangeIfNeeded(
reason: RDEPUBViewportChangeReason,
viewportSignature: RDEPUBViewportSignature? = nil
) {
runtime.handleViewportChangeIfNeeded(reason: reason, viewportSignature: viewportSignature)
}
///
func searchPresentation(for page: EPUBPage) -> RDEPUBSearchPresentation? {
runtime.searchPresentation(for: page)
}
///
private func resolvedPageDirection() -> RDReaderView.PageDirection {
publication?.readingProgression == .rtl ? .rightToLeft : .leftToRight
}
}
// MARK: -
extension RDEPUBReaderController: UIGestureRecognizerDelegate {
/// true
public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
true
}
}