Repository navigation
feat(reading): V2 Android reader bars, tap zones, back, keep-awake, save on close (#1264) - #1288
Merged
Merged
Conversation
…ave on leave V2 Android host (#1263 Android half, #1264): - top/bottom bars over the WebView (legacy ReaderTopBar/ReaderFooter/useReaderBars), auto-hide, centre tap toggles, scrolling hides in scrolled flow; reduced motion skips the animation - tap zones in paginated flow (chrome.mjs, pure, for web too): word/link/selection-dismissing tap never turns the page; the page's tap has no place, so the host pairs it with the touch - hardware back: offer, then the book (to the list), then the route; keep-awake while a book is on screen; status bar follows the bars; stable top inset - __fol.flush() injected on background, unmount and close (page does not have it yet) - reader.chrome.* strings, golden fixtures Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ared tapZone Merges origin/v2/1263-page-chrome-protocol. Drops the touch pairing and long-press guess: zones from tap.x (readTap) + WebView width, rtl from opened.dir, tapZone.mjs taken verbatim from v2/1263-web-bars. Host decisions (hidesBarsOnRelocate, backAction) added to the page branch's chrome.mjs. flush() now exists in the page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bars, Escape shows bars Tap zones use the same latest direction as keys (opened.dir, then relocate.dir). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… relocate, bars re-arm - closing a book: list at once, CLOSE_BOOK_JS (flush, then book-closed), then the book ends as the open one; a ready reopens only a book on screen; per-book state reset; hidden page out of the accessibility tree, its tap/key/word/selection dropped - readRelocate (bounded numbers, capped toc, dir) for everything the chrome shows - one effective flow for tap zones and scroll-hide; host goTo/bar moves never hide the bars - bars auto-hide re-armed on every open (count trigger) - dismissible notices over a book; unmount flush documented as best effort Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to v2/1263-1264-android-chrome
…taps act as taps until #1269 - readRelocate gains strict moved; hidesBarsOnRelocate is one rule for both flows (moved, not under a bar button); the host's CFI-difference guess and the re-layout known item are gone - createHostMoves kept for bar buttons and the chosen goTo only (sync goTo is moved: false) - readWordTap: a word acts as a tap at its rect's centre until the word popup (#1269) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 12, 2026
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.
Summary
The V2 Android reader gets its reading frame: top and bottom bars that hide while reading, tap zones, hardware back, keep-awake, safe areas, and a save when a book is closed or the app goes to the background. The route is still dev-only (
__DEV__).Stack: 3 of 4. Base is #1287 (page protocol), which sits on #1285. Merge order: #1285 → #1287 → this → web bars. Full CI runs here only after GitHub retargets this PR to
main.Slice
Wave 14, B4 (Android half) + B5. Fixes #1264. Refs #1263 (closed by the web bars PR).
Changes
V2ReaderScreen.tsxrelocatethe reader caused (relocate.moved, either flow). A centre tap toggles them. A bar button, the taken offer, a re-layout or a sync jump does not hide them. Reduced motion: no slide or fade.tapZone.mjstapAction: the outer 25 % of each side turns the page in paginated flow and always for a fixed-layout book; the centre toggles; direction from the page's latestdir. A tap that dismisses a selection never arrives as a tap.readWordTap), so text, which is most of the screen, is not a dead zone. Slice V2 reader: word popup, translation and explain through the host #1269 (word popup) replaces this.keyAction; one press, one turn.book-closed; the host clears the open book and its per-book state. A laterready(renderer reclaimed in the background, Retry) reopens nothing. While no book is open the WebView is hidden from accessibility and itstap/key/word/selectionmessages are dropped.__fol.flush()when the app goes to the background and before a book is closed.chrome.mjs(shared, no React Native types):readRelocate(everything the chrome displays fromrelocateis validated: the page renders untrusted content),readWordTap,hidesBarsOnRelocate,createHostMoves,backAction,reopensOnReady,takenWithoutBook,CLOSE_BOOK_JS.tapZone.mjs(+.d.mts, test): byte-identical to the web bars branch's copy, so the two PRs merge cleanly.Reused from the legacy reader:
ReaderTopBar(highlights / TOC / settings buttons now optional, back button takes an accessible name),ReaderFooter(prev / next names can be passed in),useReaderBars(reduced motion, and a count as its re-arm trigger; the legacy reader gets reduced motion too),useKeepReaderAwake,useFlushOnBackground. New:useFlushOnLeave.No native change:
expo-keep-awake,expo-status-bar,react-native-safe-area-contextare already in the app. The Expo fingerprint does not move.Strings:
reader.chrome.back,.prevPage,.nextPage,.dismissinpackages/shared/src/i18n/en.json(+ both golden fixtures).Tests
chrome.test.ts,tapZone.test.ts,useFlushOnLeave.test.ts,useReaderBars.test.ts: readers incl. hostile payloads, bars rule, back order, close script order (storebeforebook-closed), a closed book not reopened onready, messages dropped without a book, timer re-armed on a replayed open.tsc0, vitest 1488; shared vitest 755; web locale tests 28;check:v2-readerup to date (no page source edits).endBookonbook-closed, the effective flow passed to the zones, the crash count gated on a book being on screen, the accessibility props, the Dismiss button.Rollback plan
Revert the PR. No server, schema or stored-data change; the route is dev-only.
Docs: updated (
apps/mobile/src/lib/v2reader/README.md"Reader chrome")Notes
What the review changed (/code-review high, 10 findings; 8 fixed, 1 documented, 1 skipped)
relocatefields went unvalidated into React children and styles (a non-stringtocwould crash the screen).relocate.moved, feat(reading): V2 reader page protocol for bars: tap position, direction, keys, flush (#1263) #1287).ReaderTopBar(deleted at R8).Known and left
storereturns to a handler that is gone. Back and the top bar close the book first, which saves.Device checks owed by the owner
tap.xand the WebView width are in the same units).🤖 Generated with Claude Code