Skip to content

Commit 30727af

Browse files
authored
Fix various EPUB positioning issues (readium#499)
1 parent bccfabc commit 30727af

File tree

8 files changed

+58
-33
lines changed

8 files changed

+58
-33
lines changed

readium/navigator/src/main/assets/_scripts/src/decorator.js

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -304,19 +304,21 @@ window.addEventListener(
304304
const body = document.body;
305305
var lastSize = { width: 0, height: 0 };
306306
const observer = new ResizeObserver(() => {
307-
if (
308-
lastSize.width === body.clientWidth &&
309-
lastSize.height === body.clientHeight
310-
) {
311-
return;
312-
}
313-
lastSize = {
314-
width: body.clientWidth,
315-
height: body.clientHeight,
316-
};
317-
318-
groups.forEach(function (group) {
319-
group.requestLayout();
307+
requestAnimationFrame(() => {
308+
if (
309+
lastSize.width === body.clientWidth &&
310+
lastSize.height === body.clientHeight
311+
) {
312+
return;
313+
}
314+
lastSize = {
315+
width: body.clientWidth,
316+
height: body.clientHeight,
317+
};
318+
319+
groups.forEach(function (group) {
320+
group.requestLayout();
321+
});
320322
});
321323
});
322324
observer.observe(body);

readium/navigator/src/main/assets/_scripts/src/utils.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ window.addEventListener(
1919
"load",
2020
function () {
2121
const observer = new ResizeObserver(() => {
22-
onViewportWidthChanged();
23-
snapCurrentOffset();
22+
requestAnimationFrame(() => {
23+
onViewportWidthChanged();
24+
snapCurrentOffset();
25+
});
2426
});
2527
observer.observe(document.body);
2628
},

readium/navigator/src/main/assets/readium/scripts/readium-fixed.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

readium/navigator/src/main/assets/readium/scripts/readium-reflowable.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -267,13 +267,13 @@ public class EpubNavigatorFragment internal constructor(
267267

268268
private sealed class State {
269269
/** The navigator just started and didn't load any resource yet. */
270-
object Initializing : State()
270+
data object Initializing : State()
271271

272-
/** The navigator is jumping to the resource at `locator`. */
273-
data class Loading(val locator: Locator) : State()
272+
/** The navigator is loading the first resource at `initialResourceHref`. */
273+
data class Loading(val initialResourceHref: Url) : State()
274274

275-
/** The navigator is idle and ready for interactions. */
276-
object Ready : State()
275+
/** The navigator is fully initialized and ready for action. */
276+
data object Ready : State()
277277
}
278278

279279
private var state: State = State.Initializing
@@ -608,7 +608,9 @@ public class EpubNavigatorFragment internal constructor(
608608
@Suppress("NAME_SHADOWING")
609609
val locator = publication.normalizeLocator(locator)
610610

611-
state = State.Loading(locator)
611+
if (state == State.Initializing) {
612+
state = State.Loading(locator.href)
613+
}
612614

613615
listener?.onJumpToLocator(locator)
614616

@@ -781,7 +783,8 @@ public class EpubNavigatorFragment internal constructor(
781783
override fun onPageLoaded(webView: R2BasicWebView, link: Link) {
782784
paginationListener?.onPageLoaded()
783785

784-
if (state is State.Initializing || (state as? State.Loading)?.locator?.href == link.url()) {
786+
val href = link.url()
787+
if (state is State.Initializing || (state as? State.Loading)?.initialResourceHref == href) {
785788
state = State.Ready
786789
}
787790

readium/navigator/src/main/java/org/readium/r2/navigator/pager/R2EpubPageFragment.kt

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package org.readium.r2.navigator.pager
1111

1212
import android.annotation.SuppressLint
1313
import android.graphics.PointF
14+
import android.os.Build
1415
import android.os.Bundle
1516
import android.util.DisplayMetrics
1617
import android.view.*
@@ -19,13 +20,16 @@ import android.webkit.WebResourceResponse
1920
import android.webkit.WebView
2021
import androidx.core.os.BundleCompat
2122
import androidx.core.view.ViewCompat
23+
import androidx.core.view.postDelayed
2224
import androidx.fragment.app.Fragment
2325
import androidx.fragment.app.viewModels
2426
import androidx.lifecycle.Lifecycle
2527
import androidx.lifecycle.flowWithLifecycle
2628
import androidx.lifecycle.lifecycleScope
2729
import androidx.lifecycle.repeatOnLifecycle
2830
import androidx.webkit.WebViewClientCompat
31+
import androidx.webkit.WebViewCompat
32+
import androidx.webkit.WebViewFeature
2933
import kotlin.math.roundToInt
3034
import kotlinx.coroutines.flow.*
3135
import kotlinx.coroutines.launch
@@ -213,9 +217,7 @@ internal class R2EpubPageFragment : Fragment() {
213217
webView.listener?.onResourceLoaded(webView, it)
214218
}
215219

216-
// To make sure the page is properly laid out before jumping to the target locator,
217-
// we execute a dummy JavaScript and wait for the callback result.
218-
webView.evaluateJavascript("true") {
220+
webView.onContentReady {
219221
onLoadPage()
220222
}
221223
}
@@ -247,6 +249,24 @@ internal class R2EpubPageFragment : Fragment() {
247249
return containerView
248250
}
249251

252+
/**
253+
* Will run the given [action] when the content of the [WebView] is fully laid out.
254+
*/
255+
private fun WebView.onContentReady(action: () -> Unit) {
256+
if (WebViewFeature.isFeatureSupported(WebViewFeature.VISUAL_STATE_CALLBACK)) {
257+
WebViewCompat.postVisualStateCallback(this, 0) {
258+
action()
259+
}
260+
} else {
261+
// On older devices, there's no reliable way to guarantee the page is fully laid out.
262+
// As a workaround, we run a dummy JavaScript, then wait for a short delay before
263+
// assuming it's ready.
264+
evaluateJavascript("true") {
265+
postDelayed(500, action)
266+
}
267+
}
268+
}
269+
250270
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
251271
super.onViewCreated(view, savedInstanceState)
252272

test-app/src/main/java/org/readium/r2/testapp/reader/ReaderActivity.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,6 @@ open class ReaderActivity : AppCompatActivity() {
138138
)
139139
}
140140

141-
override fun finish() {
142-
model.close()
143-
super.finish()
144-
}
145-
146141
private fun handleReaderFragmentEvent(command: ReaderViewModel.ActivityCommand) {
147142
when (command) {
148143
is ReaderViewModel.ActivityCommand.OpenOutlineRequested ->

test-app/src/main/java/org/readium/r2/testapp/reader/ReaderViewModel.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,10 @@ class ReaderViewModel(
102102
readerInitData = readerInitData
103103
)
104104

105-
fun close() {
105+
override fun onCleared() {
106+
// When the ReaderViewModel is disposed of, we want to close the publication to avoid
107+
// using outdated information (such as the initial location) if the `ReaderActivity` is
108+
// opened again with the same book.
106109
readerRepository.close(bookId)
107110
}
108111

0 commit comments

Comments
 (0)