Skip to content

fix(mobile-reader): Prev returns to your place, ‹ works in uploads, PDF no longer creeps forward on reopen - #739

Merged
mrviduus merged 7 commits into
mainfrom
fix/mobile-prev-and-pdf-drift
Oct 6, 2026
Merged

mrviduus merged 7 commits into
mainfrom
fix/mobile-prev-and-pdf-drift

Conversation

@mrviduus

@mrviduus mrviduus commented Oct 6, 2026

Copy link
Copy Markdown
Owner

Found by the emulator QA run. None are regressions from 2026-10-05/06.

  1. ‹ disabled in every upload chapter — backend UserChapterDto sends Previous, shared UserBookChapterDto read prev. Mapped once in shared getUserBookChapter (toUserBookChapter); stored chapters without a link repaired from the book's chapter list (chapterLinks.ts).
  2. Next → read → Prev opened at the top — the device keeps one progress record per book, so chapter I had no position after any save in II. useReaderPersistence now remembers each chapter's last gated save in memory per book (cleared on sign-out); hand-off and the server newer-check still win. ponytail: memory only — a killed app forgets.
  3. PDF crept forward ~2 pages per reopen — shared dimsReadyUpTo clamped to a short dims array, so the mobile viewer settled the jump on estimated heights; real heights then moved the page under the top and it was saved. Short array = not ready; no page reports while a jump travels; a reader touch/wheel/key cancels the jump; 8 s hard deadline so a jump never waits forever.

Code review: 2 findings (no escape from a travelling jump; stored chapters kept ‹ disabled) fixed with tests.

Tests: mobile 690, shared 602, web 1040; tsc clean; bundle regenerated, check:mobile-pdf green. JS-only (OTA). Emulator recheck after merge.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TBqXDqcbLYbPwGKnTsWYLz

mrviduus and others added 7 commits October 6, 2026 12:49
…obile Prev was disabled in every upload

Backend UserChapterDto sends Previous; shared UserBookChapterDto read prev,
always undefined. Mapped once in shared getUserBookChapter (toUserBookChapter).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBqXDqcbLYbPwGKnTsWYLz
The device record is one row per book and names the last chapter saved, so
after Next and any reading, the previous chapter had no position on the phone
and reopened at the top. Not a regression of #728/#731/#736: true since #683
(one chapter per document). useReaderPersistence now remembers each chapter's
last saved place for this app run and uses it when the device record names
another chapter; cleared on sign-out.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBqXDqcbLYbPwGKnTsWYLz
…per open

dimsReadyUpTo clamped the target to dims.length. Web preallocates numPages
entries; the mobile viewer fills its array as sizes arrive, so with only page 1
measured every jump read as ready, settled and was acked on cover-sized
estimates. The real heights then streamed in under a fixed scrollY and the
viewer reported (and RN saved) the page that drifted under the top: 55 -> 61 in
the repro. Since #424, not #716/#728.

- shared dimsReadyUpTo: an array shorter than the target is not ready.
- viewer: no page reports while a jump is still travelling (RN's +-1 / 4s gate
  accepted them); a jump settles at once when sizes are known (it was never
  acked after the prefetch finished); a page whose size failed keeps its
  estimate so a jump past it can still land.
- entry.test.ts: the real bundle in jsdom over a modelled page column, its
  reports through the real pdfPersistGate. Fails 3/3 on main.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBqXDqcbLYbPwGKnTsWYLz
…s gesture cancels it, 8 s deadline lands it

Review of the drift fix: with reports held while a jump travels, a slow stream
(or a size fetch that never returns) left the reader unsaved, and a late landing
snapped them back. touchmove/wheel/keydown now cancel the jump where they are
(acked, reporting resumes), and JUMP_DEADLINE_MS lands it on the column's
target. Input events, not scroll: streaming sizes and scroll anchoring move
scrollY with no reader.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBqXDqcbLYbPwGKnTsWYLz
…` fix still gets its ‹

Stored rows carry prev null, the reader shows the stored copy first and the
refresh does not re-render, so ‹ stayed disabled until a second online open.
fillChapterLinks takes a missing link from the book's chapter list (already
loaded for the TOC) when the upload source hands the chapter to the shell;
never overrides a link the chapter has.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBqXDqcbLYbPwGKnTsWYLz
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBqXDqcbLYbPwGKnTsWYLz
…r too

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBqXDqcbLYbPwGKnTsWYLz
@mrviduus
mrviduus force-pushed the fix/mobile-prev-and-pdf-drift branch from 17332e5 to 659f639 Compare October 6, 2026 16:50
@mrviduus
mrviduus merged commit 4ab96bb into main Oct 6, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant