Skip to content
Merged
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ All notable changes to this project will be documented in this file. Take a look

* The PDF navigator now honors the publication reading progression with support for right-to-left and horizontal scrolling.
* The default (auto) reading progression for PDF is top-to-bottom, which is vertical scrolling.
* A new convenience utility `EdgeTapNavigation` to trigger page turns while tapping the screen edges.
* It takes into account the navigator reading progression to move into the right direction.
* Call it from the `VisualNavigator.Listener.onTap()` callback as demonstrated below:
```kotlin
override fun onTap(point: PointF): Boolean {
val navigated = edgeTapNavigation.onTap(point, requireView())
if (!navigated) {
// Fallback action, for example toggling the app bar.
}
return true
}
```

### Fixed

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package org.readium.r2.navigator.util

import android.graphics.PointF
import android.view.View
import org.readium.r2.navigator.VisualNavigator
import org.readium.r2.shared.publication.ReadingProgression

/**
* Convenience utility to handle page turns when tapping the edge of the screen.
*
* Call [EdgeTapNavigation.onTap] from the [VisualNavigator.Listener.onTap] callback to turn pages
* automatically.
*
* @param navigator Navigator used to turn pages.
* @param minimumEdgeSize The minimum edge dimension triggering page turns, in pixels.
* @param edgeThresholdPercent The percentage of the viewport dimension used to compute the edge
* dimension. When null, minimumEdgeSize will be used instead.
* @param animatedTransition Indicates whether the page turns should be animated.
*/
class EdgeTapNavigation(
private val navigator: VisualNavigator,
private val minimumEdgeSize: Double = 200.0,
private val edgeThresholdPercent: Double? = 0.3,
private val animatedTransition: Boolean = false,
) {
private enum class Transition {
FORWARD, BACKWARD, NONE;

fun reverse() = when (this) {
FORWARD -> BACKWARD
BACKWARD -> FORWARD
NONE -> NONE
}
}

/**
* Handles a tap in the navigator viewport and returns whether it was successful.
*
* To be called from [VisualNavigator.Listener.onTap].
*
* @param view Navigator view from which the point is relative.
*/
fun onTap(point: PointF, view: View): Boolean {
val horizontalEdgeSize by lazy {
if (edgeThresholdPercent != null)
(edgeThresholdPercent * view.width).coerceAtLeast(minimumEdgeSize)
else minimumEdgeSize
}
val leftRange by lazy { 0.0..horizontalEdgeSize }
val rightRange by lazy { (view.width - horizontalEdgeSize)..view.width.toDouble() }

val verticalEdgeSize by lazy {
if (edgeThresholdPercent != null)
(edgeThresholdPercent * view.height).coerceAtLeast(minimumEdgeSize)
else minimumEdgeSize
}
val topRange by lazy { 0.0..verticalEdgeSize }
val bottomRange by lazy { (view.height - verticalEdgeSize)..view.height.toDouble() }

val isHorizontal = navigator.readingProgression.isHorizontal ?: true
val isReverse = when (navigator.readingProgression) {
ReadingProgression.LTR, ReadingProgression.TTB, ReadingProgression.AUTO -> false
ReadingProgression.RTL, ReadingProgression.BTT -> true
}

var transition: Transition =
if (isHorizontal) {
when {
rightRange.contains(point.x) -> Transition.FORWARD
leftRange.contains(point.x) -> Transition.BACKWARD
else -> Transition.NONE
}
} else {
when {
bottomRange.contains(point.y) -> Transition.FORWARD
topRange.contains(point.y) -> Transition.BACKWARD
else -> Transition.NONE
}
}

if (isReverse) {
transition = transition.reverse()
}

return when (transition) {
Transition.FORWARD -> navigator.goForward(animated = animatedTransition)
Transition.BACKWARD -> navigator.goBackward(animated = animatedTransition)
Transition.NONE -> false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,6 @@ class EpubReaderFragment : VisualReaderFragment(), EpubNavigatorFragment.Listene
}
}

override fun onTap(point: PointF): Boolean {
requireActivity().toggleSystemUi()
return true
}

private fun showSearchFragment() {
childFragmentManager.commit {
childFragmentManager.findFragmentByTag(SEARCH_FRAGMENT_TAG)?.let { remove(it) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

package org.readium.r2.testapp.reader

import android.graphics.PointF
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
Expand All @@ -17,7 +16,6 @@ import org.readium.r2.navigator.Navigator
import org.readium.r2.navigator.image.ImageNavigatorFragment
import org.readium.r2.shared.publication.Publication
import org.readium.r2.testapp.R
import org.readium.r2.testapp.utils.toggleSystemUi

class ImageReaderFragment : VisualReaderFragment(), ImageNavigatorFragment.Listener {

Expand Down Expand Up @@ -48,19 +46,6 @@ class ImageReaderFragment : VisualReaderFragment(), ImageNavigatorFragment.Liste
return view
}

override fun onTap(point: PointF): Boolean {
val viewWidth = requireView().width
val leftRange = 0.0..(0.2 * viewWidth)

when {
leftRange.contains(point.x) -> navigator.goBackward(animated = true)
leftRange.contains(viewWidth - point.x) -> navigator.goForward(animated = true)
else -> requireActivity().toggleSystemUi()
}

return true
}

companion object {

const val NAVIGATOR_FRAGMENT_TAG = "navigator"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,6 @@ class PdfReaderFragment : VisualReaderFragment(), PdfNavigatorFragment.Listener
requireActivity().finish()
}

override fun onTap(point: PointF): Boolean {
val viewWidth = requireView().width
val leftRange = 0.0..(0.2 * viewWidth)

when {
leftRange.contains(point.x) -> navigator.goBackward()
leftRange.contains(viewWidth - point.x) -> navigator.goForward()
else -> requireActivity().toggleSystemUi()
}

return true
}

companion object {

const val NAVIGATOR_FRAGMENT_TAG = "navigator"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package org.readium.r2.testapp.reader

import android.graphics.PointF
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
Expand All @@ -15,17 +16,16 @@ import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import org.readium.r2.navigator.DecorableNavigator
import org.readium.r2.navigator.ExperimentalDecorator
import org.readium.r2.navigator.VisualNavigator
import org.readium.r2.navigator.util.EdgeTapNavigation
import org.readium.r2.testapp.R
import org.readium.r2.testapp.databinding.FragmentReaderBinding
import org.readium.r2.testapp.utils.clearPadding
import org.readium.r2.testapp.utils.hideSystemUi
import org.readium.r2.testapp.utils.padSystemUi
import org.readium.r2.testapp.utils.showSystemUi
import org.readium.r2.testapp.utils.*

/*
* Adds fullscreen support to the BaseReaderFragment
*/
abstract class VisualReaderFragment : BaseReaderFragment() {
abstract class VisualReaderFragment : BaseReaderFragment(), VisualNavigator.Listener {

private lateinit var navigatorFragment: Fragment

Expand Down Expand Up @@ -75,4 +75,20 @@ abstract class VisualReaderFragment : BaseReaderFragment() {
container.clearPadding()
}
}

// VisualNavigator.Listener

override fun onTap(point: PointF): Boolean {
val navigated = edgeTapNavigation.onTap(point, requireView())
if (!navigated) {
requireActivity().toggleSystemUi()
}
return true
}

private val edgeTapNavigation by lazy {
EdgeTapNavigation(
navigator = navigator as VisualNavigator
)
}
}