Conversation
字體大小變更(pwa/pwa-next)與設定面板觸發的 resize(pwa/pwa-next/renderer)都漏了 重新呼叫 marks-pane 的 pane.render(),導致已存在的劃線標記停留在舊排版位置、跟改版後 的文字對不上;RN 版原本完全沒有這個重繪機制,一併補上。 同時補上「我的筆記」頁點擊個別註記可直接跳轉到書中對應位置(initialCfi),以及 annotations.add/underline 失敗時的除錯 log,方便後續排查標記不顯示的問題。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 38 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThe PR documents the multi-project architecture and sync validation status. It adds note links that open books at EPUB CFI locations, suppresses specific destroyed-resource rejections, refreshes annotation panes after layout changes, improves mobile annotation handling, and seeds a default mobile book. ChangesReader navigation and mobile initialization
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Notes
participant App
participant Reader
participant useReaderEngine
Notes->>App: Navigate to book with encoded CFI
App->>Reader: Set initialCfi
Reader->>useReaderEngine: Initialize reader with initialCfi
useReaderEngine->>useReaderEngine: Display CFI or saved progress
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
CLOUD_SYNC_PROGRESS.md (1)
13-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win明確區分離線同步測試與 PWA 冷啟動測試。
Line 14 states that service-worker app-shell caching is untested. Line 353 marks offline reading and synchronization as passed. State whether the passed test used an already loaded application. Keep PWA installation and offline cold-start validation pending if it was not covered.
Also applies to: 350-353
🤖 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 `@CLOUD_SYNC_PROGRESS.md` around lines 13 - 16, Update the Phase 4 status in CLOUD_SYNC_PROGRESS.md to clarify whether the passed offline reading and synchronization tests used an already loaded application; if they did not validate a fresh PWA launch, keep service-worker installation and offline cold-start/app-shell caching validation explicitly pending for Phase 5.
🤖 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 `@pwa-next/src/hooks/reader/useReaderEngine.ts`:
- Around line 632-643: Update the target CFI selection in the display flow
around initialCfi and savedCfi so an empty initialCfi is treated as absent and
savedCfi is selected instead. Preserve the existing one-time initial-CFI
behavior for non-empty values and the fallback handling for display failures.
In `@README.md`:
- Around line 19-20: Update the README privacy statement around “本機優先” so it no
longer claims that no data is uploaded generally. Limit the local-storage claim
to EPUB files and local settings, and explicitly state that pwa-next
synchronizes only lightweight library metadata such as the book list, progress,
bookmarks, and notes, excluding EPUB contents.
---
Nitpick comments:
In `@CLOUD_SYNC_PROGRESS.md`:
- Around line 13-16: Update the Phase 4 status in CLOUD_SYNC_PROGRESS.md to
clarify whether the passed offline reading and synchronization tests used an
already loaded application; if they did not validate a fresh PWA launch, keep
service-worker installation and offline cold-start/app-shell caching validation
explicitly pending for Phase 5.
🪄 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: 58412d55-d409-442a-a31e-795a2df06419
⛔ Files ignored due to path filters (1)
mobile/lib/readerHtml.generated.tsis excluded by!**/*.generated.*
📒 Files selected for processing (10)
CLOUD_SYNC_PROGRESS.mdREADME.mdmobile/reader-web/index.tspwa-next/src/App.tsxpwa-next/src/components/Reader/epubPatches.tspwa-next/src/hooks/reader/useReaderEngine.tspwa-next/src/page/Notes.tsxpwa-next/src/page/Reader.tsxpwa/src/hooks/reader/useReaderEngine.tsrenderer/src/hooks/reader/useReaderEngine.ts
讓測試者不用自己找 epub 匯入,就能直接體驗閱讀、朗讀、劃線等完整功能。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
長按拖曳選字延伸到 .epub-container 邊界時,WebKit/Chromium 會為了讓選取範圍可見強制 捲動該容器(即使是 overflow:hidden),連帶觸發 epub.js 的 scroll → relocated 回報; 既有的「連續卡在同一個 CFI 就強制跳下一章」偵測邏輯誤把這個非預期位移當成翻頁卡死, 而 lastNavDirection 是進入劃線模式前最後一次真實翻頁殘留的全域值,兩者一湊就會誤觸發 gotoTarget() 強制跳章。改為劃線模式中整段跳過這個偵測,並補上 scrollLeft 鎖定機制, 把偵測到的非預期位移即時修正回原位。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
mobile/assets/books/sample-book.epub (1)
1-4359: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winConsider Git LFS for this binary asset.
This EPUB file is committed directly as a binary blob in the main git history. Binary blobs committed this way stay in the repository history permanently, even if the file is later removed or replaced, and they increase clone and CI checkout time for all contributors.
Track this file with Git LFS instead of a plain binary commit. Do this before merge, because migrating already-committed binaries later requires a history rewrite.
🤖 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/assets/books/sample-book.epub` around lines 1 - 4359, Track the sample-book.epub asset with Git LFS instead of storing it as a regular Git blob. Add the asset’s pattern to .gitattributes, migrate the existing file into LFS storage, and ensure the commit contains the LFS pointer rather than the binary content before merging.
🤖 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 97-100: Update the extraction flow around seedDefaultBook and
handleAddBook so default-book and user-book metadata requests are serialized
rather than overwriting pendingExtractionRef. Queue each extraction and process
requests in order, ensuring every response refreshes metadata for its own book;
alternatively, prevent import while an extraction is active.
- Around line 97-101: Add rejection handling to the detached seedDefaultBook
promise in the tab screen initialization flow, logging the caught error through
the existing app logging mechanism. Preserve the current successful path that
refreshes and extracts metadata, and ensure failures from seedDefaultBook are
handled without unhandled rejections.
In `@mobile/lib/library.ts`:
- Around line 143-169: Update the default-book seeding flow around
DEFAULT_BOOK_SEEDED_KEY and seedDefaultBookPromise so the marker is written only
after the EPUB copy and updateMeta succeed. On failure, clear
seedDefaultBookPromise to allow a later retry, and make retries detect the
persisted sample book record before creating a duplicate when the final marker
write fails.
In `@mobile/reader-web/index.ts`:
- Around line 311-323: Reset annotation state at the start of loadBook alongside
the existing book-specific module-level resets: set annotationModeEnabled to
false and lockedScrollLeft to null, or invoke setAnnotationMode(false) if it
performs both updates. Ensure each newly loaded book starts with normal tap-zone
interaction and no stale scroll lock.
- Around line 658-669: Update the content touchstart and touchmove handlers
around the existing debugLog calls to return immediately when
annotationModeEnabled is false, before reading touch coordinates or logging.
Preserve the current coordinate logging behavior when annotation mode is
enabled, including the passive touchmove listener.
---
Nitpick comments:
In `@mobile/assets/books/sample-book.epub`:
- Around line 1-4359: Track the sample-book.epub asset with Git LFS instead of
storing it as a regular Git blob. Add the asset’s pattern to .gitattributes,
migrate the existing file into LFS storage, and ensure the commit contains the
LFS pointer rather than the binary content before merging.
🪄 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: 799a9cb4-b6a5-45d9-a6a1-0096f17eec45
⛔ Files ignored due to path filters (2)
mobile/lib/readerHtml.generated.tsis excluded by!**/*.generated.*mobile/yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (6)
mobile/app/(tabs)/index.tsxmobile/assets/books/sample-book.epubmobile/lib/library.tsmobile/metro.config.jsmobile/package.jsonmobile/reader-web/index.ts
| seedDefaultBook().then((record) => { | ||
| if (!record) return; | ||
| refresh(); | ||
| extractMetaFor(record).then(refresh); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Serialize metadata extraction requests.
pendingExtractionRef stores only one request. If the user adds a book before the default-book extraction completes, handleAddBook replaces this pending request. A response can then update metadata for the wrong book.
Put default-book and user-book extraction in one queue, or disable book import until the current extraction completes.
🤖 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/`(tabs)/index.tsx around lines 97 - 100, Update the extraction
flow around seedDefaultBook and handleAddBook so default-book and user-book
metadata requests are serialized rather than overwriting pendingExtractionRef.
Queue each extraction and process requests in order, ensuring every response
refreshes metadata for its own book; alternatively, prevent import while an
extraction is active.
| seedDefaultBook().then((record) => { | ||
| if (!record) return; | ||
| refresh(); | ||
| extractMetaFor(record).then(refresh); | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Handle seed failures.
seedDefaultBook() can reject during asset download, file copy, or metadata persistence. This detached promise has no rejection handler. Catch the rejection and log it so React Native does not report an unhandled rejection.
Proposed fix
- seedDefaultBook().then((record) => {
+ void seedDefaultBook()
+ .then(async (record) => {
if (!record) return;
- refresh();
- extractMetaFor(record).then(refresh);
- });
+ await refresh();
+ await extractMetaFor(record);
+ await refresh();
+ })
+ .catch((err) => console.warn('[library] seedDefaultBook failed', err));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| seedDefaultBook().then((record) => { | |
| if (!record) return; | |
| refresh(); | |
| extractMetaFor(record).then(refresh); | |
| }); | |
| void seedDefaultBook() | |
| .then(async (record) => { | |
| if (!record) return; | |
| await refresh(); | |
| await extractMetaFor(record); | |
| await refresh(); | |
| }) | |
| .catch((err) => console.warn('[library] seedDefaultBook failed', err)); |
🤖 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/`(tabs)/index.tsx around lines 97 - 101, Add rejection handling to
the detached seedDefaultBook promise in the tab screen initialization flow,
logging the caught error through the existing app logging mechanism. Preserve
the current successful path that refreshes and extracts metadata, and ensure
failures from seedDefaultBook are handled without unhandled rejections.
| const alreadySeeded = await AsyncStorage.getItem(DEFAULT_BOOK_SEEDED_KEY); | ||
| if (alreadySeeded) return null; | ||
| await AsyncStorage.setItem(DEFAULT_BOOK_SEEDED_KEY, '1'); | ||
|
|
||
| const asset = Asset.fromModule(require('../assets/books/sample-book.epub')); | ||
| await asset.downloadAsync(); | ||
| if (!asset.localUri) return null; | ||
|
|
||
| const dir = booksDir(); | ||
| if (!dir.exists) dir.create({ intermediates: true }); | ||
|
|
||
| const id = generateId(); | ||
| const filename = `${id}.epub`; | ||
| const destination = new File(dir, filename); | ||
| await new File(asset.localUri).copy(destination); | ||
|
|
||
| const record: BookRecord = { | ||
| id, | ||
| title: '台灣的有機農業', | ||
| author: '吳東傑', | ||
| filename, | ||
| addedAt: Date.now(), | ||
| lastOpenedAt: Date.now(), | ||
| }; | ||
|
|
||
| return updateMeta((records) => [[record, ...records], record]); | ||
| })(); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Persist the seed marker only after seeding succeeds.
Line 145 writes DEFAULT_BOOK_SEEDED_KEY before downloadAsync, copy, and updateMeta. If any later operation fails, later launches return null at line 144 and never install the sample book.
Write the marker after both the EPUB and metadata persist successfully. Reset seedDefaultBookPromise when seeding fails so a later focus event can retry. Make the retry idempotent against the persisted book record if the final marker write fails.
🤖 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 143 - 169, Update the default-book
seeding flow around DEFAULT_BOOK_SEEDED_KEY and seedDefaultBookPromise so the
marker is written only after the EPUB copy and updateMeta succeed. On failure,
clear seedDefaultBookPromise to allow a later retry, and make retries detect the
persisted sample book record before creating a duplicate when the final marker
write fails.
| let annotationModeEnabled = false; | ||
| // epub.js 的 DefaultViewManager 在 paginated flow 下把 .epub-container 設成 | ||
| // overflow:hidden,翻頁完全靠 JS 直接改 container.scrollLeft 實現(見 node_modules/epubjs/ | ||
| // src/managers/default/index.js 的 next()/prev()),不是靠使用者手勢捲動。但 WebKit/ | ||
| // Chromium 對「文字選取範圍延伸到 overflow:hidden 容器邊界」有個已知行為:即使該容器不接受 | ||
| // 一般觸控捲動手勢,瀏覽器仍可能為了讓選取範圍保持可見,強制把它 scrollIntoView,直接改動 | ||
| // container.scrollLeft。這個位移不是經由 turnPage() 發動,但 rendition 的 scroll→relocate | ||
| // 回報邏輯(見 DefaultViewManager.onScroll/EVENTS.MANAGERS.SCROLLED)不分青紅皂白,只要 | ||
| // scrollLeft 變了就當成翻頁回報,畫面看起來就像「框選文字時被強制翻頁」——這跟 tap-zone | ||
| // 點擊翻頁是完全不同的路徑,只擋點擊沒辦法擋到這個。 | ||
| // 劃線模式開啟時鎖住當下的 scrollLeft,之後偵測到「沒有經過 turnPage() 就跑掉」的 scrollLeft | ||
| // 位移,立刻鎖回原值,取消掉這個非預期的強制捲動。 | ||
| let lockedScrollLeft: number | null = null; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== loadBook reset block ==="
rg -n "const loadBook" -A 20 mobile/reader-web/index.ts
echo "=== any existing reset of annotationModeEnabled/lockedScrollLeft ==="
rg -n "annotationModeEnabled|lockedScrollLeft" mobile/reader-web/index.ts
echo "=== RN side: does it always turn off annotation mode before switching books? ==="
rg -n "setAnnotationMode" mobile/app/readerRepository: Retsomm/TravelInTime
Length of output: 2575
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== mobile/reader-web/index.ts outline around relevant symbols ==="
ast-grep outline mobile/reader-web/index.ts --match setAnnotationMode --view expanded || true
ast-grep outline mobile/reader-web/index.ts --match loadBook --view expanded || true
echo "=== loadBook full function ==="
sed -n '560,790p' mobile/reader-web/index.ts | cat -n
echo "=== annotation mode implementation and event handling ==="
sed -n '308,410p' mobile/reader-web/index.ts | cat -n
sed -n '640,745p' mobile/reader-web/index.ts | cat -n
echo "=== RN send and call sites for engine.postToWebView / setAnnotationMode ==="
rg -n "engine\.postToWebView|postToWebView|setAnnotationMode|loadBook|switching|navigate|onChange|id\]" mobile/app/reader mobile/reader-web -S
echo "=== focused text search for annotationModeEnabled/lockedScrollLeft in mobile/reader-web ==="
rg -n "annotationModeEnabled|lockedScrollLeft|setAnnotationMode|loadBook" mobile/reader-web/index.tsRepository: Retsomm/TravelInTime
Length of output: 26940
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== mobile/app/reader/[id].tsx relevant state and navigation/load paths ==="
sed -n '1,140p' mobile/app/reader/[id].tsx | cat -n
echo "=== mobile/app/reader/[id].tsx load/navigation callbacks and annotation mode UI ==="
rg -n "onBookChanged|navigate|load|loadBook|setAnnotationMode|annotationMode|toggle|checkbox|annotation" mobile/app/reader/[id].tsx -C 3
echo "=== Web message receiver and loadBook entry point ==="
sed -n '820,900p' mobile/reader-web/index.ts | cat -n
echo "=== focused structural check for loadBook resets ==="
python3 - <<'PY'
from pathlib import Path
p = Path('mobile/reader-web/index.ts')
text = p.read_text()
lines = text.splitlines()
for start, end in [(311, 350), (568, 582)]:
print(f"--- {start}-{end} ---")
for i in range(start, min(end, len(lines))+1):
print(f"{i}\t{lines[i-1]}")
print("loadBook contains 'chapterPageCounts = new Map()'?", "chapterPageCounts = new Map();" in "\n".join(lines[567:581]))
print("loadBook contains 'setAnnotationMode' call?", "setAnnotationMode" in "\n".join(lines[567:581]))
print("any loadBook contains 'lockedScrollLeft' assignment/comment?", any(x in "\n".join(lines[567:581]) for x in ['lockedScrollLeft', 'annotationModeEnabled']))
PYRepository: Retsomm/TravelInTime
Length of output: 18707
Reset annotation mode state when loadBook starts.
loadBook increments loadGeneration and clears book-specific state, but it leaves annotationModeEnabled and lockedScrollLeft from the previous book. If a book is closed while annotation mode is on, the next book opens with annotationModeEnabled === true; tap zones stay pointer-events: none, and any non-tap-zone scroll is locked back to the old scrollLeft. Reset this state in loadBook at the same time as the other module-level resets, or call setAnnotationMode(false).
🤖 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/reader-web/index.ts` around lines 311 - 323, Reset annotation state at
the start of loadBook alongside the existing book-specific module-level resets:
set annotationModeEnabled to false and lockedScrollLeft to null, or invoke
setAnnotationMode(false) if it performs both updates. Ensure each newly loaded
book starts with normal tap-zone interaction and no stale scroll lock.
| debugLog( | ||
| '[content touchstart]', 'annotationModeEnabled=', annotationModeEnabled, | ||
| 'x=', Math.round(t?.clientX ?? -1), 'y=', Math.round(t?.clientY ?? -1) | ||
| ); | ||
| }); | ||
| doc.addEventListener('touchmove', (e: TouchEvent) => { | ||
| const t = e.touches[0]; | ||
| debugLog( | ||
| '[content touchmove]', 'annotationModeEnabled=', annotationModeEnabled, | ||
| 'x=', Math.round(t?.clientX ?? -1), 'y=', Math.round(t?.clientY ?? -1) | ||
| ); | ||
| }, { passive: true }); |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "const debugLog|function debugLog" -A 20 mobile/reader-web/index.tsRepository: Retsomm/TravelInTime
Length of output: 1015
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file stats =="
wc -l mobile/reader-web/index.ts
echo "== surrounding scroll/touch handler regions =="
sed -n '330,390p' mobile/reader-web/index.ts
sed -n '630,690p' mobile/reader-web/index.ts
echo "== all annotationModeEnabled references around event setup =="
rg -n "annotationModeEnabled|debugLog|addEventListener\\(" mobile/reader-web/index.ts -C 2
echo "== static behavioral check for early returns in adjacent handlers =="
python3 - <<'PY'
from pathlib import Path
p = Path('mobile/reader-web/index.ts')
text = p.read_text()
for needle in ['addEventListener(\'scroll\'', 'addEventListener(\'touchstart\'', 'addEventListener(\'touchmove\'']:
idx = text.find(needle)
print(f'--- {needle}: line {text.count(chr(10),0,idx)+1}')
start=max(0,idx-400); end=min(len(text), idx+1200)
block=text[start:end]
for i,line in enumerate((block+'\n').splitlines(), text.count(chr(10),0,start)+1):
if i<=50: print(f'{i}: {line}')
PYRepository: Retsomm/TravelInTime
Length of output: 14193
Gate the content touch handlers on annotationModeEnabled.
debugLog only skips when DEBUG_BRIDGE is false; as long as it is enabled, both handlers build arguments and call post() on every touch. touchmove is high-frequency, and unlike the nearby scroll listener, these handlers no-return when annotation mode is disabled.
⚡ Proposed fix
doc.addEventListener('touchstart', (e: TouchEvent) => {
const t = e.touches[0];
+ if (!annotationModeEnabled) return;
debugLog(
'[content touchstart]', 'annotationModeEnabled=', annotationModeEnabled,
'x=', Math.round(t?.clientX ?? -1), 'y=', Math.round(t?.clientY ?? -1)
);
});
doc.addEventListener('touchmove', (e: TouchEvent) => {
const t = e.touches[0];
+ if (!annotationModeEnabled) return;
debugLog(
'[content touchmove]', 'annotationModeEnabled=', annotationModeEnabled,
'x=', Math.round(t?.clientX ?? -1), 'y=', Math.round(t?.clientY ?? -1)
);
}, { passive: true });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| debugLog( | |
| '[content touchstart]', 'annotationModeEnabled=', annotationModeEnabled, | |
| 'x=', Math.round(t?.clientX ?? -1), 'y=', Math.round(t?.clientY ?? -1) | |
| ); | |
| }); | |
| doc.addEventListener('touchmove', (e: TouchEvent) => { | |
| const t = e.touches[0]; | |
| debugLog( | |
| '[content touchmove]', 'annotationModeEnabled=', annotationModeEnabled, | |
| 'x=', Math.round(t?.clientX ?? -1), 'y=', Math.round(t?.clientY ?? -1) | |
| ); | |
| }, { passive: true }); | |
| doc.addEventListener('touchstart', (e: TouchEvent) => { | |
| const t = e.touches[0]; | |
| if (!annotationModeEnabled) return; | |
| debugLog( | |
| '[content touchstart]', 'annotationModeEnabled=', annotationModeEnabled, | |
| 'x=', Math.round(t?.clientX ?? -1), 'y=', Math.round(t?.clientY ?? -1) | |
| ); | |
| }); | |
| doc.addEventListener('touchmove', (e: TouchEvent) => { | |
| const t = e.touches[0]; | |
| if (!annotationModeEnabled) return; | |
| debugLog( | |
| '[content touchmove]', 'annotationModeEnabled=', annotationModeEnabled, | |
| 'x=', Math.round(t?.clientX ?? -1), 'y=', Math.round(t?.clientY ?? -1) | |
| ); | |
| }, { passive: true }); |
🤖 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/reader-web/index.ts` around lines 658 - 669, Update the content
touchstart and touchmove handlers around the existing debugLog calls to return
immediately when annotationModeEnabled is false, before reading touch
coordinates or logging. Preserve the current coordinate logging behavior when
annotation mode is enabled, including the passive touchmove listener.
…effect 錯誤 將 TTS 輔助函式(noteUserInteraction、clearAllTTSHighlights、clearOtherTTSHighlights、 refreshTTSPageEndOffset、unlockTTSAutoFollow、requestTTSAutoNextPage、cancelScheduledTTSHighlight) 與 rerenderAnnotationPane 移到使用處之前宣告。 睡眠計時器倒數歸零的收尾邏輯(清 interval、清 TTS 高亮、停止朗讀)改為直接在 setInterval 的 tick callback 中處理,取代原本監看 sleepRemaining === 0 的 useEffect,避免在 effect body 內同步呼叫 setState 觸發連鎖 render。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
toggleListPanel 原本預設分頁是 bookmarks,改為 chapters;README 補充說明本機儲存僅限 EPUB 檔案與本機設定。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
字體大小變更(pwa/pwa-next)與設定面板觸發的 resize(pwa/pwa-next/renderer)都漏了 重新呼叫 marks-pane 的 pane.render(),導致已存在的劃線標記停留在舊排版位置、跟改版後 的文字對不上;RN 版原本完全沒有這個重繪機制,一併補上。
同時補上「我的筆記」頁點擊個別註記可直接跳轉到書中對應位置(initialCfi),以及
annotations.add/underline 失敗時的除錯 log,方便後續排查標記不顯示的問題。
Summary by CodeRabbit
New Features
Bug Fixes
Documentation