From da7b9e6d9fc2c3ddcbb7a11615b48511f5581124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mickae=CC=88l=20Menu?= Date: Fri, 27 Jan 2023 13:37:01 +0100 Subject: [PATCH 1/2] Emit `onJumpToLocator` when swiping across resources in scroll mode --- CHANGELOG.md | 9 ++- .../readium/r2/navigator/R2BasicWebView.kt | 74 ++++++++++++------- .../navigator/epub/EpubNavigatorFragment.kt | 36 +++++++-- 3 files changed, 85 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c45abc3207..987b622699 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,14 @@ All notable changes to this project will be documented in this file. Take a look **Warning:** Features marked as *experimental* may change or be removed in a future release without notice. Use with caution. - +## [Unreleased] + +### Added + +#### Navigator + +* Scroll mode: jumping between two EPUB resources with a horizontal swipe triggers the `Navigator.Listener.onJumpToLocator()` callback. + * This can be used to allow the user to go back to their previous location if they swiped across chapters by mistake. ## [2.3.0] diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/R2BasicWebView.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/R2BasicWebView.kt index d405c3cc99..e70dd9b7ff 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/R2BasicWebView.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/R2BasicWebView.kt @@ -65,8 +65,8 @@ open class R2BasicWebView(context: Context, attrs: AttributeSet) : WebView(conte fun onProgressionChanged() fun onHighlightActivated(id: String) fun onHighlightAnnotationMarkActivated(id: String) - fun goForward(animated: Boolean = false, completion: () -> Unit = {}): Boolean - fun goBackward(animated: Boolean = false, completion: () -> Unit = {}): Boolean + fun goForward(animated: Boolean = false, completion: () -> Unit = {}): Boolean = false + fun goBackward(animated: Boolean = false, completion: () -> Unit = {}): Boolean = false /** * Returns the custom [ActionMode.Callback] to be used with the text selection menu. @@ -75,15 +75,23 @@ open class R2BasicWebView(context: Context, attrs: AttributeSet) : WebView(conte @InternalReadiumApi fun javascriptInterfacesForResource(link: Link): Map = emptyMap() - @InternalReadiumApi fun shouldOverrideUrlLoading(webView: WebView, request: WebResourceRequest): Boolean = false - @InternalReadiumApi fun shouldInterceptRequest(webView: WebView, request: WebResourceRequest): WebResourceResponse? = null - @InternalReadiumApi fun resourceAtUrl(url: String): Resource? = null + + /** + * Requests to load the next resource in the reading order. + * + * @param jump Indicates whether it's a discontinuous jump from the current locator. Used + * for scroll mode. + */ + @InternalReadiumApi + fun goToNextResource(jump: Boolean, animated: Boolean): Boolean = false + @InternalReadiumApi + fun goToPreviousResource(jump: Boolean, animated: Boolean): Boolean = false } lateinit var listener: Listener @@ -182,22 +190,31 @@ open class R2BasicWebView(context: Context, attrs: AttributeSet) : WebView(conte uiScope.launch { listener.onScroll() - fun goRight() { + val isRtl = (listener.readingProgression == ReadingProgression.RTL) + + fun goRight(jump: Boolean) { if (listener.readingProgression == ReadingProgression.RTL) { - listener.goBackward(animated = animated) + listener.goBackward(animated = animated) // Legacy + listener.goToPreviousResource(jump = jump, animated = animated) } else { - listener.goForward(animated = animated) + listener.goForward(animated = animated) // Legacy + listener.goToNextResource(jump = jump, animated = animated) } } - if (scrollMode || !this@R2BasicWebView.canScrollHorizontally(1)) { - goRight() - } else { - runJavaScript("readium.scrollRight();") { success -> - if (!success.toBoolean()) { - goRight() + when { + scrollMode -> + goRight(jump = true) + + !this@R2BasicWebView.canScrollHorizontally(1) -> + goRight(jump = false) + + else -> + runJavaScript("readium.scrollRight();") { success -> + if (!success.toBoolean()) { + goRight(jump = false) + } } - } } } } @@ -207,22 +224,29 @@ open class R2BasicWebView(context: Context, attrs: AttributeSet) : WebView(conte uiScope.launch { listener.onScroll() - fun goLeft() { + fun goLeft(jump: Boolean) { if (listener.readingProgression == ReadingProgression.RTL) { - listener.goForward(animated = animated) + listener.goForward(animated = animated) // legacy + listener.goToNextResource(jump = jump, animated = animated) } else { - listener.goBackward(animated = animated) + listener.goBackward(animated = animated) // legacy + listener.goToPreviousResource(jump = jump, animated = animated) } } - if (scrollMode || !this@R2BasicWebView.canScrollHorizontally(-1)) { - goLeft() - } else { - runJavaScript("readium.scrollLeft();") { success -> - if (!success.toBoolean()) { - goLeft() + when { + scrollMode -> + goLeft(jump = true) + + !this@R2BasicWebView.canScrollHorizontally(1) -> + goLeft(jump = false) + + else -> + runJavaScript("readium.scrollLeft();") { success -> + if (!success.toBoolean()) { + goLeft(jump = false) + } } - } } } } diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt index 5ebca0739f..9de7e9e7ba 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt @@ -744,11 +744,13 @@ class EpubNavigatorFragment internal constructor( r2Activity?.highlightAnnotationMarkActivated(id) } - override fun goForward(animated: Boolean, completion: () -> Unit): Boolean = - goToNextResource(animated, completion) + override fun goToPreviousResource(jump: Boolean, animated: Boolean): Boolean { + return this@EpubNavigatorFragment.goToPreviousResource(jump = jump, animated = animated) + } - override fun goBackward(animated: Boolean, completion: () -> Unit): Boolean = - goToPreviousResource(animated, completion) + override fun goToNextResource(jump: Boolean, animated: Boolean): Boolean { + return this@EpubNavigatorFragment.goToNextResource(jump = jump, animated = animated) + } override val selectionActionModeCallback: ActionMode.Callback? get() = config.selectionActionModeCallback @@ -772,7 +774,7 @@ class EpubNavigatorFragment internal constructor( override fun goForward(animated: Boolean, completion: () -> Unit): Boolean { if (publication.metadata.presentation.layout == EpubLayout.FIXED) { - return goToNextResource(animated, completion) + return goToNextResource(jump = false, animated = animated, completion) } val webView = currentReflowablePageFragment?.webView ?: return false @@ -790,7 +792,7 @@ class EpubNavigatorFragment internal constructor( override fun goBackward(animated: Boolean, completion: () -> Unit): Boolean { if (publication.metadata.presentation.layout == EpubLayout.FIXED) { - return goToPreviousResource(animated, completion) + return goToPreviousResource(jump = false, animated = animated, completion) } val webView = currentReflowablePageFragment?.webView ?: return false @@ -806,12 +808,16 @@ class EpubNavigatorFragment internal constructor( return true } - private fun goToNextResource(animated: Boolean, completion: () -> Unit): Boolean { + private fun goToNextResource(jump: Boolean, animated: Boolean, completion: () -> Unit = {}): Boolean { val adapter = resourcePager.adapter ?: return false if (resourcePager.currentItem >= adapter.count - 1) { return false } + if (jump) { + locatorToNextResource()?.let { listener?.onJumpToLocator(it) } + } + resourcePager.setCurrentItem(resourcePager.currentItem + 1, animated) currentReflowablePageFragment?.webView?.let { webView -> @@ -826,11 +832,15 @@ class EpubNavigatorFragment internal constructor( return true } - private fun goToPreviousResource(animated: Boolean, completion: () -> Unit): Boolean { + private fun goToPreviousResource(jump: Boolean, animated: Boolean, completion: () -> Unit = {}): Boolean { if (resourcePager.currentItem <= 0) { return false } + if (jump) { + locatorToPreviousResource()?.let { listener?.onJumpToLocator(it) } + } + resourcePager.setCurrentItem(resourcePager.currentItem - 1, animated) currentReflowablePageFragment?.webView?.let { webView -> @@ -845,6 +855,16 @@ class EpubNavigatorFragment internal constructor( return true } + private fun locatorToPreviousResource(): Locator? = + locatorToResourceAtIndex(resourcePager.currentItem - 1) + + private fun locatorToNextResource(): Locator? = + locatorToResourceAtIndex(resourcePager.currentItem + 1) + + private fun locatorToResourceAtIndex(index: Int): Locator? = + publication.readingOrder.getOrNull(index) + ?.let { publication.locatorFromLink(it) } + private val r2PagerAdapter: R2PagerAdapter? get() = if (::resourcePager.isInitialized) resourcePager.adapter as? R2PagerAdapter else null From 52aa1c3111615c3af9fc9889b041ca82040e1261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mickae=CC=88l=20Menu?= Date: Thu, 9 Feb 2023 10:01:22 +0100 Subject: [PATCH 2/2] Fix offset --- .../src/main/java/org/readium/r2/navigator/R2BasicWebView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/R2BasicWebView.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/R2BasicWebView.kt index 4570275a78..d4e6363899 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/R2BasicWebView.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/R2BasicWebView.kt @@ -240,7 +240,7 @@ open class R2BasicWebView(context: Context, attrs: AttributeSet) : WebView(conte scrollMode -> goLeft(jump = true) - !this@R2BasicWebView.canScrollHorizontally(1) -> + !this@R2BasicWebView.canScrollHorizontally(-1) -> goLeft(jump = false) else ->