feat: improve epub reader controls and annotations
This commit is contained in:
@@ -527,10 +527,13 @@ public class RDEpubReaderView: UIView {
|
||||
let pageView = preloadController.pageViewForDisplay(
|
||||
pageNum: pageNum,
|
||||
environment: preloadEnvironment,
|
||||
contentViewProvider: pageContentViewForDisplay(pageNum:reusableView:)
|
||||
contentViewProvider: contentViewForPage(_:reusableView:)
|
||||
)
|
||||
// A data-source request is only a candidate. UIPageViewController may
|
||||
// ask for duplicate instances of the current page; activation happens
|
||||
// after the winning controller is actually installed.
|
||||
(pageView as? RDEpubReaderPageVisibilityHandling)?
|
||||
.readerPageVisibilityDidChange(isVisible: isReaderPageVisible(pageNum))
|
||||
.readerPageVisibilityDidChange(isVisible: false)
|
||||
return pageView
|
||||
}
|
||||
|
||||
@@ -551,10 +554,6 @@ public class RDEpubReaderView: UIView {
|
||||
return contentViewForPage(pageNum, reusableView: reusableView)
|
||||
}
|
||||
|
||||
private func pageContentViewForDisplay(pageNum: Int, reusableView: UIView?) -> UIView? {
|
||||
return contentViewForPage(pageNum, reusableView: reusableView)
|
||||
}
|
||||
|
||||
func isReaderPageVisible(_ pageNum: Int) -> Bool {
|
||||
guard currentPage >= 0 else { return pageNum == 0 }
|
||||
if landscapeDualPageEnabled && isLandscape {
|
||||
@@ -564,7 +563,7 @@ public class RDEpubReaderView: UIView {
|
||||
return pageNum == currentPage
|
||||
}
|
||||
|
||||
private func updatePageContentVisibility() {
|
||||
func updatePageContentVisibility() {
|
||||
var visiblePageNumbers = Set<Int>()
|
||||
if currentPage >= 0 {
|
||||
visiblePageNumbers.insert(currentPage)
|
||||
@@ -574,20 +573,57 @@ public class RDEpubReaderView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
preloadController.updatePageVisibility(visiblePageNumbers: visiblePageNumbers)
|
||||
|
||||
for viewController in pageViewController.viewControllers ?? [] {
|
||||
guard let pageController = viewController as? RDEpubReaderPageChildViewController,
|
||||
let contentView = pageController.contentView else { continue }
|
||||
(contentView as? RDEpubReaderPageVisibilityHandling)?
|
||||
.readerPageVisibilityDidChange(isVisible: visiblePageNumbers.contains(pageController.pageNum))
|
||||
let pageControllers: [RDEpubReaderPageChildViewController]
|
||||
let visibleCellContents: [(pageNumber: Int, contentView: UIView)]
|
||||
if currentDisplayType == .pageCurl {
|
||||
pageControllers = (pageViewController.viewControllers ?? []).compactMap {
|
||||
$0 as? RDEpubReaderPageChildViewController
|
||||
}
|
||||
visibleCellContents = []
|
||||
} else {
|
||||
pageControllers = []
|
||||
visibleCellContents = collectionView.indexPathsForVisibleItems.compactMap { indexPath in
|
||||
guard let cell = collectionView.cellForItem(at: indexPath) as? RDEpubReaderContentCell,
|
||||
let contentView = cell.containerView else { return nil }
|
||||
return (indexPath.item, contentView)
|
||||
}
|
||||
}
|
||||
|
||||
for indexPath in collectionView.indexPathsForVisibleItems {
|
||||
guard let cell = collectionView.cellForItem(at: indexPath) as? RDEpubReaderContentCell,
|
||||
let contentView = cell.containerView else { continue }
|
||||
for pageController in pageControllers where !visiblePageNumbers.contains(pageController.pageNum) {
|
||||
guard let contentView = pageController.contentView else { continue }
|
||||
(contentView as? RDEpubReaderPageVisibilityHandling)?
|
||||
.readerPageVisibilityDidChange(isVisible: visiblePageNumbers.contains(indexPath.item))
|
||||
.readerPageVisibilityDidChange(isVisible: false)
|
||||
}
|
||||
|
||||
for entry in visibleCellContents where !visiblePageNumbers.contains(entry.pageNumber) {
|
||||
(entry.contentView as? RDEpubReaderPageVisibilityHandling)?
|
||||
.readerPageVisibilityDidChange(isVisible: false)
|
||||
}
|
||||
|
||||
// Suspend every cached non-winner before the attached winner below is
|
||||
// activated. Object identity matters because a page number can have
|
||||
// multiple UIPageViewController candidates.
|
||||
let visibleViewIdentifiers = Set(
|
||||
pageControllers.compactMap { pageController -> ObjectIdentifier? in
|
||||
guard visiblePageNumbers.contains(pageController.pageNum),
|
||||
let contentView = pageController.contentView else { return nil }
|
||||
return ObjectIdentifier(contentView)
|
||||
} + visibleCellContents.compactMap { entry -> ObjectIdentifier? in
|
||||
guard visiblePageNumbers.contains(entry.pageNumber) else { return nil }
|
||||
return ObjectIdentifier(entry.contentView)
|
||||
}
|
||||
)
|
||||
preloadController.updatePageVisibility(visibleViewIdentifiers: visibleViewIdentifiers)
|
||||
|
||||
for pageController in pageControllers where visiblePageNumbers.contains(pageController.pageNum) {
|
||||
guard let contentView = pageController.contentView else { continue }
|
||||
(contentView as? RDEpubReaderPageVisibilityHandling)?
|
||||
.readerPageVisibilityDidChange(isVisible: true)
|
||||
}
|
||||
|
||||
for entry in visibleCellContents where visiblePageNumbers.contains(entry.pageNumber) {
|
||||
(entry.contentView as? RDEpubReaderPageVisibilityHandling)?
|
||||
.readerPageVisibilityDidChange(isVisible: true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,6 +665,11 @@ public class RDEpubReaderView: UIView {
|
||||
}
|
||||
|
||||
private func detachPageViewControllerIfNeeded() {
|
||||
for case let childController as RDEpubReaderPageChildViewController in pageViewController.viewControllers ?? [] {
|
||||
guard let contentView = childController.contentView else { continue }
|
||||
(contentView as? RDEpubReaderPageVisibilityHandling)?
|
||||
.readerPageVisibilityDidChange(isVisible: false)
|
||||
}
|
||||
if pageViewController.parent != nil {
|
||||
pageViewController.willMove(toParent: nil)
|
||||
}
|
||||
@@ -882,6 +923,17 @@ public class RDEpubReaderView: UIView {
|
||||
}
|
||||
predictedPageDirection = currentPage >= 0 ? safePageNum >= currentPage : nil
|
||||
attachPageViewControllerIfNeeded()
|
||||
|
||||
// Programmatic setViewControllers transitions do not call the
|
||||
// UIPageViewControllerDelegate didFinishAnimating callback. Stop
|
||||
// the outgoing controllers explicitly before replacing them, even
|
||||
// when a duplicate page instance has fallen out of our cache map.
|
||||
for case let childController as RDEpubReaderPageChildViewController in pageViewController.viewControllers ?? [] {
|
||||
guard let contentView = childController.contentView else { continue }
|
||||
(contentView as? RDEpubReaderPageVisibilityHandling)?
|
||||
.readerPageVisibilityDidChange(isVisible: false)
|
||||
}
|
||||
|
||||
if isDualPage {
|
||||
let pair = dualPagePair(for: safePageNum)
|
||||
let leftContent = pageViewForDisplay(pageNum: pair.left)
|
||||
@@ -903,7 +955,11 @@ public class RDEpubReaderView: UIView {
|
||||
self.finishPageCurlTransition()
|
||||
}
|
||||
}
|
||||
let pageChanged = currentPage != pair.left
|
||||
currentPage = pair.left
|
||||
if !pageChanged {
|
||||
updatePageContentVisibility()
|
||||
}
|
||||
primePageCache(around: pair.left, preferredForward: predictedPageDirection)
|
||||
} else {
|
||||
let contentView = pageViewForDisplay(pageNum: safePageNum)
|
||||
@@ -913,7 +969,11 @@ public class RDEpubReaderView: UIView {
|
||||
guard let self else { return }
|
||||
self.finishPageCurlTransition()
|
||||
}
|
||||
let pageChanged = currentPage != safePageNum
|
||||
currentPage = safePageNum
|
||||
if !pageChanged {
|
||||
updatePageContentVisibility()
|
||||
}
|
||||
primePageCache(around: safePageNum, preferredForward: predictedPageDirection)
|
||||
}
|
||||
default:
|
||||
@@ -921,7 +981,11 @@ public class RDEpubReaderView: UIView {
|
||||
collectionView.layoutIfNeeded()
|
||||
predictedPageDirection = currentPage >= 0 ? safePageNum >= currentPage : nil
|
||||
collectionView.setContentOffset(layout.currentContentOffset(count: safePageNum), animated: animated)
|
||||
let pageChanged = currentPage != safePageNum
|
||||
currentPage = safePageNum
|
||||
if !pageChanged {
|
||||
updatePageContentVisibility()
|
||||
}
|
||||
primePageCache(around: safePageNum, preferredForward: predictedPageDirection)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user