Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ All notable changes to this project will be documented in this file. Take a look
* Support for displaying Divina (image-based publications like CBZ) in the fixed-layout EPUB navigator.
* Bitmap images in the EPUB reading order are now supported as a fixed layout resource.
* Added `offsetFirstPage` preference for fixed-layout EPUBs to control whether the first page is displayed alone or alongside the second page when spreads are enabled.
* Added `func navigator(_ navigator: any VisualNavigator, didDragBy delta: CGFloat)` and `func navigator(_ navigator: any VisualNavigator, didEndDraggingWithVelocity velocity: CGFloat)` to `VisualNavigatorDelegate`.

#### Streamer

Expand Down
12 changes: 12 additions & 0 deletions Sources/Navigator/EPUB/EPUBNavigatorViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,18 @@ extension EPUBNavigatorViewController: EPUBSpreadViewDelegate {
}
}

func spreadView(_ spreadView: EPUBSpreadView, didDragBy delta: CGFloat) {
if paginationView?.currentView == spreadView {
delegate?.navigator(self, didDragBy: delta)
}
}

func spreadView(_ spreadView: EPUBSpreadView, didEndDraggingWithVelocity velocity: CGFloat) {
if paginationView?.currentView == spreadView {
delegate?.navigator(self, didEndDraggingWithVelocity: velocity)
}
}

func spreadView(_ spreadView: EPUBSpreadView, present viewController: UIViewController) {
present(viewController, animated: true)
}
Expand Down
42 changes: 42 additions & 0 deletions Sources/Navigator/EPUB/EPUBReflowableSpreadView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ final class EPUBReflowableSpreadView: EPUBSpreadView {
private var progression: ClosedRange<Double>?
/// To check if a progression change was cancelled or not.
private var previousProgression: ClosedRange<Double>?
/// Previous scroll offset while the user is dragging.
private var previousDragOffset: CGPoint?

/// Called by the javascript code to notify that scrolling ended.
private func progressionDidChange(_ body: Any) {
Expand Down Expand Up @@ -432,8 +434,48 @@ final class EPUBReflowableSpreadView: EPUBSpreadView {

// MARK: - UIScrollViewDelegate

override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
super.scrollViewWillBeginDragging(scrollView)
previousDragOffset = scrollView.contentOffset
}

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
super.scrollViewDidScroll(scrollView)
setNeedsNotifyPagesDidChange()

let currentOffset = scrollView.contentOffset
if scrollView.isDragging, let previousOffset = previousDragOffset {
let delta = progressionDelta(from: previousOffset, to: currentOffset)
if delta != 0 {
delegate?.spreadView(self, didDragBy: delta)
}
}
previousDragOffset = currentOffset
}

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
delegate?.spreadView(self, didEndDraggingWithVelocity: progressionVelocity(from: velocity))
previousDragOffset = nil
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
previousDragOffset = nil
}

private func progressionDelta(from previousOffset: CGPoint, to currentOffset: CGPoint) -> CGFloat {
if viewModel.scroll, !viewModel.verticalText {
return currentOffset.y - previousOffset.y
}

let delta = currentOffset.x - previousOffset.x
return viewModel.readingProgression == .rtl ? -delta : delta
}

private func progressionVelocity(from velocity: CGPoint) -> CGFloat {
if viewModel.scroll, !viewModel.verticalText {
return velocity.y
}

return viewModel.readingProgression == .rtl ? -velocity.x : velocity.x
}
}
6 changes: 6 additions & 0 deletions Sources/Navigator/EPUB/EPUBSpreadView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ protocol EPUBSpreadViewDelegate: AnyObject {
/// Called when the pages visible in the spread changed.
func spreadViewPagesDidChange(_ spreadView: EPUBSpreadView)

/// Called continuously while the user drags the content.
func spreadView(_ spreadView: EPUBSpreadView, didDragBy delta: CGFloat)

/// Called when the user lifts their finger after dragging.
func spreadView(_ spreadView: EPUBSpreadView, didEndDraggingWithVelocity velocity: CGFloat)

/// Called when the spread view needs to present a view controller.
func spreadView(_ spreadView: EPUBSpreadView, present viewController: UIViewController)

Expand Down
23 changes: 23 additions & 0 deletions Sources/Navigator/VisualNavigator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,21 @@ public struct VisualNavigatorPresentation {
/// Return `true` to navigate to the link, or `false` if you intend to
/// present the link yourself
func navigator(_ navigator: VisualNavigator, shouldNavigateToLink link: Link) -> Bool

/// Called continuously while the user drags the content.
///
/// `delta` is the distance in points along the scroll axis since the last
/// call. Positive values indicate forward progression through the content.
///
/// Not called during momentum deceleration after the user lifts their
/// finger.
func navigator(_ navigator: any VisualNavigator, didDragBy delta: CGFloat)

/// Called when the user lifts their finger after dragging.
///
/// `velocity` is in points per second along the scroll axis. Positive
/// values indicate forward momentum.
func navigator(_ navigator: any VisualNavigator, didEndDraggingWithVelocity velocity: CGFloat)
}

public extension VisualNavigatorDelegate {
Expand All @@ -143,4 +158,12 @@ public extension VisualNavigatorDelegate {
func navigator(_ navigator: VisualNavigator, shouldNavigateToLink link: Link) -> Bool {
true
}

func navigator(_ navigator: any VisualNavigator, didDragBy delta: CGFloat) {
// Optional
}

func navigator(_ navigator: any VisualNavigator, didEndDraggingWithVelocity velocity: CGFloat) {
// Optional
}
}