From 0d5043b029d26ca131d536ab7ea31e57e76c7907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Menu?= Date: Fri, 3 May 2024 12:35:36 +0200 Subject: [PATCH 1/3] Fix applying preferences while recreating EPUB fragments --- CHANGELOG.md | 1 + .../navigator/epub/EpubNavigatorFragment.kt | 13 +++--- .../r2/navigator/pager/R2EpubPageFragment.kt | 40 ++++++++++++++++++- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2456b7c77..ed7df82fc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file. Take a look #### Navigator * [#325](https://github.com/readium/kotlin-toolkit/issues/325) Top EPUB selections no longer break when dragging the selection handles. +* Fixed applying preferences while the EPUB navigator fragment is being recreated. ## [3.0.0-alpha.2] 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 b9f8541819..4c6f60d0a1 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 @@ -294,8 +294,7 @@ public class EpubNavigatorFragment internal constructor( public suspend fun evaluateJavascript(script: String): String? { val page = currentReflowablePageFragment ?: return null page.awaitLoaded() - val webView = page.webView ?: return null - return webView.runJavaScriptSuspend(script) + return page.runJavaScriptSuspend(script) } private val viewModel: EpubNavigatorViewModel by viewModels { @@ -665,17 +664,17 @@ public class EpubNavigatorFragment internal constructor( private fun run(command: RunScriptCommand) { when (command.scope) { RunScriptCommand.Scope.CurrentResource -> { - currentReflowablePageFragment?.webView + currentReflowablePageFragment ?.runJavaScript(command.script) } RunScriptCommand.Scope.LoadedResources -> { r2PagerAdapter?.mFragments?.forEach { _, fragment -> - (fragment as? R2EpubPageFragment)?.webView + (fragment as? R2EpubPageFragment) ?.runJavaScript(command.script) } } is RunScriptCommand.Scope.Resource -> { - loadedFragmentForHref(command.scope.href)?.webView + loadedFragmentForHref(command.scope.href) ?.runJavaScript(command.script) } is RunScriptCommand.Scope.WebView -> { @@ -713,9 +712,9 @@ public class EpubNavigatorFragment internal constructor( // SelectableNavigator override suspend fun currentSelection(): Selection? { - val webView = currentReflowablePageFragment?.webView ?: return null + val fragment = currentReflowablePageFragment ?: return null val json = - webView.runJavaScriptSuspend("readium.getCurrentSelection();") + fragment.runJavaScriptSuspend("readium.getCurrentSelection();") .takeIf { it != "null" } ?.let { tryOrLog { JSONObject(it) } } ?: return null diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/pager/R2EpubPageFragment.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/pager/R2EpubPageFragment.kt index 7f0d474c2e..f218726764 100755 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/pager/R2EpubPageFragment.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/pager/R2EpubPageFragment.kt @@ -11,7 +11,6 @@ package org.readium.r2.navigator.pager import android.annotation.SuppressLint import android.graphics.PointF -import android.os.Build import android.os.Bundle import android.util.DisplayMetrics import android.view.* @@ -30,6 +29,8 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.webkit.WebViewClientCompat import androidx.webkit.WebViewCompat import androidx.webkit.WebViewFeature +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine import kotlin.math.roundToInt import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch @@ -56,6 +57,7 @@ internal class R2EpubPageFragment : Fragment() { internal val link: Link? get() = BundleCompat.getParcelable(requireArguments(), "link", Link::class.java) + private var isPageFinished = false private var pendingLocator: Locator? = null private val positionCount: Long @@ -213,6 +215,11 @@ internal class R2EpubPageFragment : Fragment() { override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) + if (!isPageFinished) { + isPageFinished = true + runPendingJavaScripts() + } + link?.let { webView.listener?.onResourceLoaded(webView, it) } @@ -448,6 +455,37 @@ internal class R2EpubPageFragment : Fragment() { } } + private data class PendingJavaScript( + val script: String, + val callback: ((String) -> Unit)? + ) + + private var pendingJavaScripts: MutableList = mutableListOf() + + fun runJavaScript(script: String, callback: ((String) -> Unit)? = null) { + if (!isPageFinished) { + pendingJavaScripts.add(PendingJavaScript(script, callback)) + return + } + + requireNotNull(webView).runJavaScript(script, callback) + } + + suspend fun runJavaScriptSuspend(javascript: String): String = suspendCoroutine { cont -> + runJavaScript(javascript) { result -> + cont.resume(result) + } + } + + private fun runPendingJavaScripts() { + require(isPageFinished) + val webView = requireNotNull(webView) + pendingJavaScripts.forEach { (script, callback) -> + webView.runJavaScript(script, callback) + } + pendingJavaScripts.clear() + } + companion object { private const val textZoomBundleKey = "org.readium.textZoom" From b8d7f41c0a926069159b4d6aded280d7efe22d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Menu?= Date: Fri, 3 May 2024 12:52:58 +0200 Subject: [PATCH 2/3] Refactor --- .../r2/navigator/pager/R2EpubPageFragment.kt | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/pager/R2EpubPageFragment.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/pager/R2EpubPageFragment.kt index f218726764..5a613ddce9 100755 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/pager/R2EpubPageFragment.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/pager/R2EpubPageFragment.kt @@ -57,7 +57,6 @@ internal class R2EpubPageFragment : Fragment() { internal val link: Link? get() = BundleCompat.getParcelable(requireArguments(), "link", Link::class.java) - private var isPageFinished = false private var pendingLocator: Locator? = null private val positionCount: Long @@ -215,10 +214,7 @@ internal class R2EpubPageFragment : Fragment() { override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) - if (!isPageFinished) { - isPageFinished = true - runPendingJavaScripts() - } + onPageFinished() link?.let { webView.listener?.onResourceLoaded(webView, it) @@ -256,6 +252,26 @@ internal class R2EpubPageFragment : Fragment() { return containerView } + private var isPageFinished = false + private val pendingPageFinished = mutableListOf<() -> Unit>() + + /** + * Will run the given [action] when the content of the [WebView] is loaded. + */ + fun whenPageFinished(action: () -> Unit) { + if (isPageFinished) { + action() + } else { + pendingPageFinished.add(action) + } + } + + private fun onPageFinished() { + isPageFinished = true + pendingPageFinished.forEach { it() } + pendingPageFinished.clear() + } + /** * Will run the given [action] when the content of the [WebView] is fully laid out. */ @@ -455,20 +471,10 @@ internal class R2EpubPageFragment : Fragment() { } } - private data class PendingJavaScript( - val script: String, - val callback: ((String) -> Unit)? - ) - - private var pendingJavaScripts: MutableList = mutableListOf() - fun runJavaScript(script: String, callback: ((String) -> Unit)? = null) { - if (!isPageFinished) { - pendingJavaScripts.add(PendingJavaScript(script, callback)) - return + whenPageFinished { + requireNotNull(webView).runJavaScript(script, callback) } - - requireNotNull(webView).runJavaScript(script, callback) } suspend fun runJavaScriptSuspend(javascript: String): String = suspendCoroutine { cont -> @@ -477,15 +483,6 @@ internal class R2EpubPageFragment : Fragment() { } } - private fun runPendingJavaScripts() { - require(isPageFinished) - val webView = requireNotNull(webView) - pendingJavaScripts.forEach { (script, callback) -> - webView.runJavaScript(script, callback) - } - pendingJavaScripts.clear() - } - companion object { private const val textZoomBundleKey = "org.readium.textZoom" From 2a3c528271fd4e8d9d26e6bd4a9510f4018275ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Menu?= Date: Fri, 3 May 2024 13:03:58 +0200 Subject: [PATCH 3/3] Minor fix --- readium/opds/src/main/java/org/readium/r2/opds/OPDS1Parser.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readium/opds/src/main/java/org/readium/r2/opds/OPDS1Parser.kt b/readium/opds/src/main/java/org/readium/r2/opds/OPDS1Parser.kt index e8991f53e8..15cffc5e6f 100644 --- a/readium/opds/src/main/java/org/readium/r2/opds/OPDS1Parser.kt +++ b/readium/opds/src/main/java/org/readium/r2/opds/OPDS1Parser.kt @@ -81,7 +81,7 @@ public class OPDS1Parser { ReplaceWith("parse(jsonData, url.toUrl()!!)"), DeprecationLevel.ERROR ) - public fun parse(jsonData: ByteArray, url: URL): ParseData = + public fun parse(xmlData: ByteArray, url: URL): ParseData = throw NotImplementedError() private fun parseFeed(root: ElementNode, url: Url): Feed {