Skip to content

Dev#1

Merged
Retsomm merged 3 commits into
mainfrom
dev
Jul 4, 2026
Merged

Dev#1
Retsomm merged 3 commits into
mainfrom
dev

Conversation

@Retsomm

@Retsomm Retsomm commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added a mobile app with a bookshelf tab, reader view, and settings tab.
    • Books can now be added, opened, and removed from the library on mobile.
    • Introduced EPUB reading support with saved progress and reading position restore.
  • Bug Fixes

    • Improved app stability on macOS by avoiding a crash when Dock integration is unavailable.
    • Added better handling for keyboard and reader display behavior on iOS/Android.
  • Documentation

    • Added a setup guide and mobile development notes for building and troubleshooting the app.

Retsomm and others added 2 commits July 4, 2026 18:01
非 macOS 平台或啟動階段 app.dock 可能不存在,加上 optional chaining 避免崩潰。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
新增 Expo/RN app 骨架與 epub.js WebView reader,翻頁方式從滑動改為點擊畫面左右 1/3
區塊(蓋在 #viewer 上層的最外層文件 tap zone),避開先前滑動手勢與未來劃詞註記手勢
的衝突,也修正舊版點擊翻頁因 iframe 內部座標系失準導致的失效問題。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
travel-in-time Ready Ready Preview, Comment Jul 4, 2026 10:27am

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Retsomm, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7145ddd9-3349-481d-af60-5aff599c657f

📥 Commits

Reviewing files that changed from the base of the PR and between 0a76248 and 4f10b32.

⛔ Files ignored due to path filters (1)
  • mobile/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (9)
  • RN_SETUP_GUIDE.md
  • mobile/app/(tabs)/index.tsx
  • mobile/app/reader/[id].tsx
  • mobile/lib/library.ts
  • mobile/lib/readerHtml.generated.ts
  • mobile/lib/readerMessages.ts
  • mobile/package.json
  • mobile/reader-web/index.ts
  • mobile/scripts/build-reader-html.js
📝 Walkthrough

Walkthrough

This PR bootstraps a new Expo/React Native mobile app (TravelInTime) with tab navigation, an AsyncStorage-backed EPUB library, a WebView-based epub.js reader with a build script generating READER_HTML, project config files (app.json, eas.json, tsconfig, gitignore, license), documentation, and a minor Electron Dock icon safety fix.

Changes

Mobile App Bootstrap

Layer / File(s) Summary
Project scaffolding, config and license
mobile/package.json, mobile/tsconfig.json, mobile/.gitignore, mobile/LICENSE, mobile/app.json, mobile/eas.json, mobile/AGENTS.md, mobile/CLAUDE.md
Establishes Expo workspace metadata, strict TypeScript config, ignore rules, MIT license, app/build config for iOS/Android, and agent documentation.
Expo Router navigation
mobile/app/_layout.tsx, mobile/app/(tabs)/_layout.tsx, mobile/app/(tabs)/settings.tsx
Defines root Stack layout and tab navigator wiring library/settings screens and the reader route.
Library persistence
mobile/lib/library.ts
Implements AsyncStorage-based CRUD, progress, CFI, settings, and bookmark helpers for EPUB books with file copy management.
Library screen UI
mobile/app/(tabs)/index.tsx
Implements LibraryScreen listing books, adding/removing books, and navigating to the reader.
Reader web bundle & build script
mobile/reader-web/index.ts, mobile/scripts/build-reader-html.js
Implements epub.js-based reader with message protocol, navigation locking, tap zones, resize handling, and esbuild script generating READER_HTML.
Reader screen UI
mobile/app/reader/[id].tsx
Implements ReaderScreen wiring WebView messages to library persistence and rendering loading/error overlays.
Setup guide documentation
RN_SETUP_GUIDE.md
Documents Expo/RN setup, build environment fixes, keyboard/header workarounds, and TravelInTime progress notes.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Electron Dock Icon Fix

Layer / File(s) Summary
Safe dock icon call
electron/main.ts
Changes app.dock.setIcon to app.dock?.setIcon to avoid a runtime error when app.dock is unavailable.

Sequence Diagram(s)

sequenceDiagram
  participant ReaderScreen
  participant WebView as WebView (READER_HTML)
  participant Library as library.ts

  ReaderScreen->>WebView: post "ready" listener setup
  WebView-->>ReaderScreen: { type: "ready" }
  ReaderScreen->>Library: getBookBase64, loadReadingCfi
  ReaderScreen->>WebView: post { type: "load", base64, cfi }
  WebView->>WebView: loadBook(base64, cfi) via epub.js
  WebView-->>ReaderScreen: { type: "relocated", cfi, page }
  ReaderScreen->>Library: saveReadingCfi, updateProgress
Loading

Related issues: None found.

Related PRs: None found.

Suggested labels: mobile, enhancement, documentation

Suggested reviewers: None found.

🐰

A rabbit hops through code so new,
Building shelves for books to sit and stew,
WebView pages turn with epub's grace,
Dock icons safely guard their place,
Hop, hop—TravelInTime springs into view.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is too vague to describe the PR’s main change. Use a concise descriptive title that mentions the primary change, such as the new mobile Expo app setup or EPUB reader implementation.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (3)
mobile/lib/library.ts (1)

39-48: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Unsynchronized read-modify-write on the shared meta array.

loadMeta()/saveMeta() is used by addBook, removeBook, touchBook, and updateProgress as a read-then-overwrite pattern with no locking. If two of these fire close together (e.g., touchBook on focus while updateProgress/saveReadingCfi fire from reader relocated events, per mobile/app/reader/[id].tsx), the second write can silently clobber the first based on a stale read, losing a progress or lastOpenedAt update.

Consider serializing writes through an in-memory mutex/queue (or a single "apply(fn)" helper that always re-reads inside a critical section) to make these mutations atomic.

Also applies to: 85-104

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mobile/lib/library.ts` around lines 39 - 48, The shared meta updates in
loadMeta/saveMeta are vulnerable to lost writes because addBook, removeBook,
touchBook, and updateProgress do read-modify-write without serialization. Add a
single atomic update path in library.ts, such as an in-memory mutex/queue or an
apply(fn) helper that re-reads inside a critical section, and route those
mutators through it so concurrent calls cannot overwrite each other with stale
BookRecord data.
mobile/app/reader/[id].tsx (1)

18-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate message-contract type.

OutboundMessage here is a copy of the type defined in mobile/reader-web/index.ts (lines 9-13). Keeping the WebView message contract in two independently-maintained files risks silent drift (e.g., one side adds/renames a field and the other isn't updated, with no compiler error since matching is structural).

Consider extracting InboundMessage/OutboundMessage into a shared module (e.g. mobile/lib/readerMessages.ts) imported by both reader-web/index.ts and this screen.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mobile/app/reader/`[id].tsx around lines 18 - 22, The OutboundMessage
contract is duplicated between this screen and reader-web/index.ts, which can
drift silently. Move InboundMessage/OutboundMessage into a shared module such as
a readerMessages file and import the types from there in both the WebView screen
and the web entrypoint. Keep the message-shape definitions centralized so any
future field changes are made once and reused consistently.
mobile/scripts/build-reader-html.js (1)

20-48: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Unescaped </script> in bundled JS can break the generated HTML.

bundleJs is interpolated raw into <script>${bundleJs}</script>. If the minified bundle (or any transitive dependency like epub.js) ever contains the literal substring </script>, it will prematurely close the tag and corrupt the generated HTML, silently breaking the reader.

🛡️ Proposed fix: escape closing script tags
-<script>${bundleJs}</script>
+<script>${bundleJs.replace(/<\/script/gi, '<\\/script')}</script>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mobile/scripts/build-reader-html.js` around lines 20 - 48, The inline bundle
injection in build-reader-html.js can be broken by a literal closing script tag
inside bundleJs. Update the HTML assembly around the
<script>${bundleJs}</script> block to safely escape any </script> sequences
before interpolation so the generated document cannot be prematurely terminated.
Keep the fix localized to the html template construction in build-reader-html.js
and ensure the resulting bundle still loads normally in the reader.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mobile/app/`(tabs)/index.tsx:
- Around line 22-39: Add error handling around the async library calls in
handleAddBook and handleDeleteBook in index.tsx, since addBook() and
removeBook() can reject and currently fail silently. Wrap the await calls in
try/catch (including the Alert.alert onPress callback), and on failure show a
user-facing alert or message while keeping refresh() only on success.

In `@mobile/app/reader/`[id].tsx:
- Around line 99-101: The icon-only back control in the reader screen lacks
accessibility metadata, so update the Pressable used with handleBack to expose
an accessibility role and a descriptive label. Add the appropriate accessibility
props directly on the Pressable in the [id] reader component so screen readers
announce it as a back button instead of an unlabeled glyph.
- Around line 107-117: The Reader WebView currently allows top-level navigation
from EPUB content, so add an onShouldStartLoadWithRequest guard to the WebView
in [id].tsx that permits the local READER_HTML and iframe/local resource loads
but blocks any non-local top-frame request. Update the reader message/link
handling around handleMessage so external URLs are intercepted and opened with
Linking.openURL instead of allowing the WebView to navigate there.

In `@mobile/lib/library.ts`:
- Around line 52-78: In addBook, the EPUB file copy is started without waiting
for it to finish, so metadata can be saved before the file actually exists.
Update the addBook flow to await picked.copy(destination) before building the
BookRecord and calling saveMeta, and make sure any copy failure prevents
persisting the new record.

In `@mobile/package.json`:
- Around line 5-20: The mobile package is missing the web runtime dependencies
needed by the existing web entrypoint and web script. Update the dependencies
block in mobile/package.json to include react-dom and react-native-web alongside
the Expo/React Native packages, using versions compatible with the current Expo
57 stack, so the web target can resolve expo-router/entry correctly.

In `@mobile/reader-web/index.ts`:
- Around line 41-71: The navigation lock in turnPage/lockNav can remain active
at book boundaries because rendition.prev()/rendition.next() may resolve without
firing relocated, leaving navBusy true until the 1500ms fallback. Update
turnPage to unlock on promise settlement as well as on relocated, using the
existing unlockNav and unlockNavSoon helpers so boundary taps do not get
swallowed; keep the current navBusy guard and ensure any successful or no-op
navigation clears the lock promptly.

In `@RN_SETUP_GUIDE.md`:
- Around line 63-68: The bootstrap install step in RN_SETUP_GUIDE.md is missing
dependencies that later setup assumes are already present. Update the expo
install command in the initial mobile setup to include expo-constants and
expo-linking alongside expo-router, expo-dev-client,
react-native-safe-area-context, and react-native-screens, or separate them into
a clearly labeled install step so the guide stays consistent.
- Around line 34-50: Section 2 is out of sync with the current mobile baseline
and should be updated or explicitly marked as historical context. In
RN_SETUP_GUIDE.md, revise the version block and the Expo docs reference to match
the active mobile/ baseline used elsewhere (Expo SDK 57 / RN 0.86), or clearly
label the current table as legacy SelfMap versions. Keep the guidance aligned
with the surrounding setup instructions and the relevant version symbols (expo,
expo-router, react-native, typescript) so readers do not follow stale baselines.

---

Nitpick comments:
In `@mobile/app/reader/`[id].tsx:
- Around line 18-22: The OutboundMessage contract is duplicated between this
screen and reader-web/index.ts, which can drift silently. Move
InboundMessage/OutboundMessage into a shared module such as a readerMessages
file and import the types from there in both the WebView screen and the web
entrypoint. Keep the message-shape definitions centralized so any future field
changes are made once and reused consistently.

In `@mobile/lib/library.ts`:
- Around line 39-48: The shared meta updates in loadMeta/saveMeta are vulnerable
to lost writes because addBook, removeBook, touchBook, and updateProgress do
read-modify-write without serialization. Add a single atomic update path in
library.ts, such as an in-memory mutex/queue or an apply(fn) helper that
re-reads inside a critical section, and route those mutators through it so
concurrent calls cannot overwrite each other with stale BookRecord data.

In `@mobile/scripts/build-reader-html.js`:
- Around line 20-48: The inline bundle injection in build-reader-html.js can be
broken by a literal closing script tag inside bundleJs. Update the HTML assembly
around the <script>${bundleJs}</script> block to safely escape any </script>
sequences before interpolation so the generated document cannot be prematurely
terminated. Keep the fix localized to the html template construction in
build-reader-html.js and ensure the resulting bundle still loads normally in the
reader.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a965a16f-49ba-4acb-8873-9f63df3f4831

📥 Commits

Reviewing files that changed from the base of the PR and between 60f4e36 and 0a76248.

⛔ Files ignored due to path filters (7)
  • mobile/assets/android-icon-background.png is excluded by !**/*.png
  • mobile/assets/android-icon-foreground.png is excluded by !**/*.png
  • mobile/assets/android-icon-monochrome.png is excluded by !**/*.png
  • mobile/assets/favicon.png is excluded by !**/*.png
  • mobile/assets/icon.png is excluded by !**/*.png
  • mobile/assets/splash-icon.png is excluded by !**/*.png
  • mobile/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (19)
  • RN_SETUP_GUIDE.md
  • electron/main.ts
  • mobile/.gitignore
  • mobile/AGENTS.md
  • mobile/CLAUDE.md
  • mobile/LICENSE
  • mobile/app.json
  • mobile/app/(tabs)/_layout.tsx
  • mobile/app/(tabs)/index.tsx
  • mobile/app/(tabs)/settings.tsx
  • mobile/app/_layout.tsx
  • mobile/app/reader/[id].tsx
  • mobile/eas.json
  • mobile/lib/library.ts
  • mobile/lib/readerHtml.generated.ts
  • mobile/package.json
  • mobile/reader-web/index.ts
  • mobile/scripts/build-reader-html.js
  • mobile/tsconfig.json

Comment thread mobile/app/(tabs)/index.tsx
Comment thread mobile/app/reader/[id].tsx Outdated
Comment thread mobile/app/reader/[id].tsx
Comment thread mobile/lib/library.ts
Comment thread mobile/package.json
Comment thread mobile/reader-web/index.ts
Comment thread RN_SETUP_GUIDE.md Outdated
Comment thread RN_SETUP_GUIDE.md
- 書櫃頁 addBook/removeBook 加上錯誤處理與提示
- 閱讀頁返回鍵補上無障礙標籤,WebView 加上導航守衛避免被導離
- library.ts 的 addBook 等待檔案複製完成,並將 meta 讀寫改為排隊序列化避免併發覆蓋
- reader-web 翻頁鎖在 promise resolve 時也會解鎖,避免邊界翻頁卡住
- 抽出共用的 readerMessages 型別、跳脫 bundle 內的 </script>
- 補上 web 版所需的 react-dom/react-native-web 依賴
- RN_SETUP_GUIDE.md 補齊安裝指令並標註版本章節為舊版參考

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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