fix(web): replay an audioEnable that arrives before the publication is open - #231
Merged
Merged
Conversation
…s open On web a text publication is only opened once `ReadiumWebView` mounts and supplies the `#container` element — `FlutterReadiumWeb.openPublication` calls the JS side only for pure audiobooks. An `audioEnable` issued straight after `openPublication` therefore found no publication, logged "no audiobook or Media Overlay content detected" and returned, and nothing ever retried it: 21:31:40.475 audioEnable 21:31:40.476 WARN audioEnable: no audiobook or Media Overlay content detected 21:31:41.101 Guided Navigation detected Remember such a call and replay it at the end of `openPublication`. It still resolves immediately rather than waiting for the publication. That is required, not merely convenient: the host app awaits `audioEnable` before it routes to the page hosting the reader view, so blocking would leave the open waiting on a reader that is waiting on the open. The replay is awaited inside `openPublication`, so a failure travels the existing open-failure path instead of being lost — the deferred caller can no longer be thrown to. The entry is consumed before replaying (a reader remount or hot restart cannot run it twice) and cleared by `closePublication`. The guard requires both no publication and no audio navigator, so it cannot intercept the pure-audiobook path, where the navigator exists on its own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Member
Author
|
Necessary fix to get out, I take full responsibility and merge this. Deeper root-cause refactor of how web opens publications will be initiated later. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On web, a text publication is only opened once
ReadiumWebViewmounts and supplies the#containerelement —FlutterReadiumWeb.openPublicationcalls the JS side only for pure audiobooks, which need no DOM container.So an
audioEnableissued straight afteropenPublicationarrives before there is anything to enable. It fell through every branch, logged a warning, and returned. Nothing retried it, so the book stayed atTimebasedState.noneforever.From a LYT4 Web E2E run:
626 ms too early.
Fix
Remember that call and replay it at the end of
openPublication.Why it still resolves immediately
This is required, not a convenience. The host app awaits
audioEnableinside its open flow, and only routes to the page hostingReadiumWebViewonce that flow succeeds. Blocking here would leave the open waiting on a reader that is waiting on the open — a deadlock.Consequences handled
openPublication, so failures travel the existing open-failure pathclosePublicationNo
play()is recorded alongside it, becauseaudioEnableresumes playback itself via_seekAudioAndResume(..., true).Follow-up (not in this PR)
This is a symptom of a deeper asymmetry: on iOS and Android the plugin owns the publication lifecycle, while on web the widget does. That is why the web platform API cannot honour its own contract, and why
play/pause/stopare fire-and-forget voids there. Worth tracking separately.Verification
bin/typecheckcleanbin/formatcleanbin/unit_tests: 18 suites, 283 tests pass (plus iOS unit tests), including 3 new ones covering defer, replay, and clear-on-closebin/build_jssucceedsNot verified: a web end-to-end run against this branch. That happens when LYT4 picks the release up.
🤖 Generated with Claude Code