From 5358d85c0ba89bc440a5b9469b9932fcc69e318c Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Mon, 29 Jun 2026 02:50:30 +0800 Subject: [PATCH] release: version 0.11.16 (#4847) --- apps/readest-app/.claude/memory/MEMORY.md | 157 +++++++++--------- .../.claude/memory/mobile-reading-widgets.md | 20 +++ apps/readest-app/package.json | 2 +- apps/readest-app/release-notes.json | 14 ++ data/metainfo/appdata.xml | 30 ++-- data/metainfo/appdata.xml.sha256 | 2 +- 6 files changed, 130 insertions(+), 95 deletions(-) create mode 100644 apps/readest-app/.claude/memory/mobile-reading-widgets.md diff --git a/apps/readest-app/.claude/memory/MEMORY.md b/apps/readest-app/.claude/memory/MEMORY.md index f0b2c313..5842581d 100644 --- a/apps/readest-app/.claude/memory/MEMORY.md +++ b/apps/readest-app/.claude/memory/MEMORY.md @@ -1,135 +1,136 @@ # Readest Project Memory ## Key Reference Documents (aggregators) -- [Bug Patterns](bug-patterns.md) · [CSS & Style](css-style-fixes.md) — EPUB CSS + style.ts · [TTS](tts-fixes.md) — architecture + bugs -- [Layout & UI](layout-ui-fixes.md) — insets/z-index · [Platform Compat](platform-compat-fixes.md) — Android/iOS/Linux/macOS · [Annotator & Reader](annotator-reader-fixes.md) — highlight/selection/a11y +- [Bug Patterns](bug-patterns.md) · [CSS & Style](css-style-fixes.md) — EPUB CSS + style.ts · [TTS](tts-fixes.md) +- [Layout & UI](layout-ui-fixes.md) — insets/z-index · [Platform Compat](platform-compat-fixes.md) — Android/iOS/Linux/macOS · [Annotator & Reader](annotator-reader-fixes.md) ## Safety & Security -- [In-place delete wiped originals](in-place-delete-wiped-originals.md) — never `fs.removeFile` `external` source; managed copy + sidecars only -- [Backup zip Windows paths (#4703)](backup-windows-zip-paths-4703.md) — `\` entry names broke restore; normalize separators -- [download_file scope Android (#4639)](download-file-scope-android-regression.md) — strict `is_allowed` broke downloads; `app.path()` base-dir membership -- [Security advisories 2026-06](security-advisories-web-2026-06.md) — 4 GHSA #4638 (OPDS SSRF, storage key, Stripe userId) + #4639 transfer_file.rs +- [In-place delete wiped originals](in-place-delete-wiped-originals.md) — never `fs.removeFile` `external` source; +- [Backup zip Windows paths (#4703)](backup-windows-zip-paths-4703.md) — `\` entry names broke restore; normalize +- [download_file scope Android (#4639)](download-file-scope-android-regression.md) — strict `is_allowed` broke +- [Security advisories 2026-06](security-advisories-web-2026-06.md) — 4 GHSA #4638 (OPDS SSRF, storage key, Stripe ## Paginator & Scroll - [Reading ruler line-aware](reading-ruler-line-aware.md) — snaps to real lines; iframe frame-offset map - [TOC expand + auto-scroll](toc-expand-and-autoscroll.md) — #4059 collapse-default breaks scroll-to-current -- [BooknoteView auto-scroll (#4352)](booknote-view-autoscroll-4352.md) — reload via `initialized` ref; `initialTopMostItemIndex` +- [BooknoteView auto-scroll (#4352)](booknote-view-autoscroll-4352.md) — reload via `initialized` ref; - [TOC current-position row](toc-current-position-row.md) — synthetic row; insert AFTER to keep flatItems index - [Swipe page-turn bg flash](paginator-swipe-bg-flash.md) — static `#background`; `computeBackgroundSegments` per-rAF -- [Paginated texture occlusion (#4399)](paginated-texture-occlusion-4399.md) — opaque bg occludes texture; `hasTexture ? '' : fallbackBg` -- [Background overflows column (#4394)](paginator-gutter-bleed-asymmetry-4394.md) — bg bled into gutter; clamp to container bounds +- [Paginated texture occlusion (#4399)](paginated-texture-occlusion-4399.md) — opaque bg occludes texture; `hasTexture +- [Background overflows column (#4394)](paginator-gutter-bleed-asymmetry-4394.md) — bg bled into gutter; clamp to - [Inline-block column overflow](inline-block-column-overflow.md) — body can't fragment; `#demoteUnfragmentableBoxes` -- [FXL fit-width scroll reset (#4683)](fixed-layout-paginated-scroll-reset-4683.md) — scrollTop not reset; `computePaginatedScroll` + `pageTurn` +- [FXL fit-width scroll reset (#4683)](fixed-layout-paginated-scroll-reset-4683.md) — scrollTop not reset; - [PDF spread 1px seam (#4587)](pdf-spread-canvas-seam-4587.md) — fractional dpr truncates; pin `canvas.style=viewport` -- [PDF scrolled wheel double (#4727)](pdf-scroll-mode-wheel-double-4727.md) — drop manual `scrollBy` over native chaining +- [PDF scrolled wheel double (#4727)](pdf-scroll-mode-wheel-double-4727.md) — drop manual `scrollBy` over native - [Scrolled header title center (#4436)](scrolled-header-title-center-4436.md) — view covering `renderedStart + size/2` - [Duokan fullscreen cover scroll](duokan-fullscreen-cover-scroll.md) — #4379 cover collapses; gate on `this.#column` -- [TOC table heading clip (#4439)](toc-table-heading-clip-4439.md) — #4400 scroll-wrapper `overflow:auto` clips decorative table's `margin:-1em` bleed; `hoistNegativeMargins` onto wrapper -- [Page-turn bg-replace reflow (#4785)](pageturn-bg-replace-reflow-4785.md) — `#replaceBackground` rebuilt context per frame (getComputedStyle + per-view getBCR), worst at boundaries; snapshot `#bgAnimContext` once per gesture (drag+snap); defer mid-drag preload via `!#touchScrolled` +- [TOC table heading clip (#4439)](toc-table-heading-clip-4439.md) — #4400 scroll-wrapper `overflow:auto` clips +- [Page-turn bg-replace reflow (#4785)](pageturn-bg-replace-reflow-4785.md) — `#replaceBackground` rebuilt context per ## Critical Files (Most Bug-Prone) - `src/utils/style.ts` EPUB CSS hub · `packages/foliate-js/paginator.js` layout/image/bg · `src/services/tts/TTSController.ts` TTS state machine - `src/hooks/useSafeAreaInsets.ts` insets · `src/app/reader/components/FoliateViewer.tsx` view orchestration · `.../annotator/Annotator.tsx` annotation lifecycle ## Sync Notes - [Grimmory native sync](grimmory-native-sync.md) — Booklore-fork REVERTED; id by ISBN/ASIN + koreader-hash -- KOSync: [CFI spine resolution](kosync-cfi-spine-resolution.md) convert via CFI's own spine; [connect() false-positive #4692](kosync-connect-false-positive-4692.md) validate koreader JSON not any 2xx +- KOSync: [CFI spine resolution](kosync-cfi-spine-resolution.md) convert via CFI's own spine; [connect() false-positive #4692](kosync-connect-false-positive-4692.md) - [Empty-start CFI sync](empty-start-cfi-sync.md) — `isMalformedLocationCfi` → discard synced value -- [Custom fonts vanish on sync (#4410)](custom-fonts-reincarnation-4410.md) — CRDT remove-wins; re-import `reincarnation` token -- koplugin: [note deletion](koplugin-note-deletion-sync.md) `recordDeletion` tombstone; [stats #4666](koplugin-stats-sync.md) statistics.sqlite3 delta LuaSettings; [bulk download #4751](koplugin-bulk-download-4751.md) `downloadAll()`/`coroutine.status` +- [Custom fonts vanish on sync (#4410)](custom-fonts-reincarnation-4410.md) — CRDT remove-wins; re-import +- koplugin: [note deletion](koplugin-note-deletion-sync.md) `recordDeletion` tombstone; [stats #4666](koplugin-stats-sync.md) statistics.sqlite3 delta LuaSettings; [bulk download #4751](koplugin-bulk-download-4751.md) - [Statusless books re-pin top (#4677)](sync-statusless-book-rebump-4677.md) — `(a??null)!==(b??null)` - [Pull cursor via synced_at (#4678)](sync-synced-at-cursor-4678.md) — books `synced_at` + BEFORE trigger -- [WebDAV metadata sync (#4756)](webdav-metadata-sync-4756.md) — PR #4776; LWW on `book.updatedAt` + `updateBookMetadata` -- [File-sync refactor (#4784)](webdav-filesync-refactor-plan.md) — `FileSyncEngine`/`FileSyncProvider`/`merge.ts`; incremental + Full Sync -- [Third-party library auto-sync (#4835)](third-party-library-autosync-4835.md) — `useLibraryFileSync` parity w/ `useBooksSync`; `library.json` on import/delete/close; delete propagation NEEDS full library (incl. deletedAt) passed to `syncLibrary` -- [WebDAV connect nullified (#4780)](webdav-connect-nullified-4780.md) — catch+finally saved STALE closure; `getState().settings` -- [WebDAV credential sync (#4810)](webdav-credential-sync-4810.md) — `webdav.*` missing from `SETTINGS_WHITELIST`/`ENCRYPTED_FIELDS`; new nested whitelist group NEEDS matching `mergeSettings` deep-merge or shallow merge clobbers per-device siblings -- [Multi-window settings clobber (#4580)](multiwindow-settings-clobber-4580.md) — stale window overwrites shared settings.json; cross-window broadcast `settingsSync.ts` -- Google Drive: [research](gdrive-sync-provider-research.md) Drive as `FileSyncProvider` token-persist+resumable; [multi-PR status](gdrive-provider-multipr-status.md) PR1+2+3 DONE on `feat/gdrive-sync-core` (5 commits thru `5efbe6b2f`, UNPUSHED, suite 6411 green); native KV+desktop OAuth+connect+ingress shipped; REMAINING (UI generalization, tauri.conf scheme, live verify) blocked on official Google client id (ops) -- [Hardcover progress edition_id (#4792)](hardcover-progress-edition-id-4792.md) — `edition_id` fell back to `book_id`; resolve real edition; old bug via #4614 +- [WebDAV metadata sync (#4756)](webdav-metadata-sync-4756.md) — PR #4776; LWW on `book.updatedAt` + +- [File-sync refactor (#4784)](webdav-filesync-refactor-plan.md) — `FileSyncEngine`/`FileSyncProvider`/`merge.ts`; +- [Third-party library auto-sync (#4835)](third-party-library-autosync-4835.md) — `useLibraryFileSync` parity w/ +- [WebDAV connect nullified (#4780)](webdav-connect-nullified-4780.md) — catch+finally saved STALE closure; +- [WebDAV credential sync (#4810)](webdav-credential-sync-4810.md) — `webdav.*` missing from +- [Multi-window settings clobber (#4580)](multiwindow-settings-clobber-4580.md) — stale window overwrites shared +- Google Drive: [research](gdrive-sync-provider-research.md) Drive as `FileSyncProvider` token-persist+resumable; [multi-PR status](gdrive-provider-multipr-status.md) +- [Hardcover progress edition_id (#4792)](hardcover-progress-edition-id-4792.md) — `edition_id` fell back to ## Build, Testing & CI - [format:check separate gate](verify-format-check-gate.md) — `pnpm format:check` own gate before push -- [Worktree rebase submodule drift](worktree-rebase-submodule-drift.md) — rebase leaves foliate-js submodule old; `git fetch ` +- [Worktree rebase submodule drift](worktree-rebase-submodule-drift.md) — rebase leaves foliate-js submodule old; `git - [Android CDP e2e lane](android-cdp-e2e-lane.md) — `pnpm test:android` adb+CDP; CI KVM emulator - [CDP Android WebView profiling](cdp-android-webview-profiling.md) — adb+CDP JS probes; locked-device freezes fetch - [Tauri Rust↔JS parser parity](tauri-parser-parity-tests.md) — #4369 cross-check; `dcterms:modified`→`published` - [TTS browser e2e harness](tts-browser-e2e-harness.md) — seed `settings.globalViewSettings` or getMergedRules crashes -- [TTS paragraph+RSVP sync (#3235)](tts-sync-paragraph-rsvp-3235.md) — TTS-is-clock; overlay CLONE via CSS Custom Highlight API +- [TTS paragraph+RSVP sync (#3235)](tts-sync-paragraph-rsvp-3235.md) — TTS-is-clock; overlay CLONE via CSS Custom - [fastlane App Store](fastlane-apple-appstore-submission.md) — keep `APPLE_API_KEY_PATH` out of macOS build env -- [Turbopack cache OOM (#4619)](turbopack-build-cache-oom-docker-standalone.md) — partial cache freeze; gate on `BUILD_STANDALONE` -- [Deps override workflow](deps-security-overrides-workflow.md) — overrides in `pnpm-workspace.yaml`; tauri-plugins age gate +- [Turbopack cache OOM (#4619)](turbopack-build-cache-oom-docker-standalone.md) — partial cache freeze; gate on +- [Deps override workflow](deps-security-overrides-workflow.md) — overrides in `pnpm-workspace.yaml`; tauri-plugins - [pdfjs vendor wasm](pdfjs-vendor-wasm-decoders.md) — pdfjs 5.7 moved JBIG2 to `jbig2.wasm`; copy `wasm/*` - [CI/PR delivery + push keepalive](ci-pr-delivery-and-push.md) — temp-index plumbing; SSH `ServerAliveInterval` ## Platform Compat -- [Android hyphen selection (#1553)](android-hyphen-selection-bounds-1553.md) — Blink start handle on last hyphen; repair anchor + custom handles -- [NativeFile vs RemoteFile I/O](android-nativefile-remotefile-io.md) — NativeFile slow; asset Range broken; handle-reuse 2.3× -- [Window-state sanitizer (#4398)](window-state-sanitize-4398.md) — invalid json crashes WebView2; sanitize before window-state -- [Android Open-with intent (#4521)](android-open-with-intent-flow.md) — VIEW gated by `autoImportBooksOnOpen` (#4747); Telegram cold-start -- [Dict lookup browser hijack (#4559)](dict-lookup-browser-hijack-4559.md) — missing `` sdk36; filter in `decideLookupDispatch` +- [Android hyphen selection (#1553)](android-hyphen-selection-bounds-1553.md) — Blink start handle on last hyphen; +- [NativeFile vs RemoteFile I/O](android-nativefile-remotefile-io.md) — NativeFile slow; asset Range broken; +- [Window-state sanitizer (#4398)](window-state-sanitize-4398.md) — invalid json crashes WebView2; sanitize before +- [Android Open-with intent (#4521)](android-open-with-intent-flow.md) — VIEW gated by `autoImportBooksOnOpen` +- [Dict lookup browser hijack (#4559)](dict-lookup-browser-hijack-4559.md) — missing `` sdk36; filter in - [Large-PDF OOM range flood (#3470)](pdf-oom-range-flood-3470.md) — un-awaited ranges OOM; MAX_CONCURRENT_RANGES=6 - [Android themed icon (#4733)](android-themed-icon-4733.md) — no monochrome → force-commit; tint=SRC_IN ## Reader Features & UI -- [PDF scrolled-mode lag (#4795/#4031)](pdf-scroll-lag-preload-4795.md) — 415ms/page render vs 50% margin; widen to 200% + `planScrollModePages` nearest-first bounded scheduler; CDP-verified Xiaomi -- [Scrolled-PDF pinch-zoom (#4817)](scrolled-pdf-pinch-zoom-4817.md) — live pinch + no-shift (gap×`--scroll-zoom` + rect-match anchor); cross-page pinch vs native selection MUTUALLY EXCLUSIVE (Android serializes cross-iframe touches), chose native selection (iframes interactive when idle); zoom store/attr desync gotcha -- [Search modes #4560 + spoiler-bound bug](search-modes-4560-and-spoiler-bound-bug.md) — regex + nearby-words; lookupPassage spoiler bound (page vs chunk) +- [Mobile reading widgets (#1602/PR#4842)](mobile-reading-widgets.md) — home-screen widget iOS+Android; gotchas: iOS +- [PDF scrolled-mode lag (#4795/#4031)](pdf-scroll-lag-preload-4795.md) — 415ms/page render vs 50% margin; widen to +- [Scrolled-PDF pinch-zoom (#4817)](scrolled-pdf-pinch-zoom-4817.md) — live pinch + no-shift (gap×`--scroll-zoom` + +- [Search modes #4560 + spoiler-bound bug](search-modes-4560-and-spoiler-bound-bug.md) — regex + nearby-words; - [OPDS groups carousel (#4750)](opds-groups-carousel-4750.md) — >=2 groups → virtuoso carousel; `scrollToIndex` -- [WebDAV browser sort + search (#4724)](webdav-browse-sort-search-4724.md) — PR #4786; `sortWebDAVEntries`/`filterWebDAVEntries` -- [Image zoom trackpad flicker (#4742)](image-zoom-trackpad-flicker-4742.md) — macOS pinch=`ctrl+wheel`; `isWheelZooming` debounce -- [Instant Highlight ate tap/swipe](instant-highlight-tap-paginate.md) — preventDefault killed tap-paginate; `INSTANT_HOLD_MS=300` -- [Keyboard selection adjust (#4728)](keyboard-selection-adjust-4728.md) — Shift+←/→ char, Ctrl/Alt+Shift word; `onAdjustTextSelection` -- [Double-click word select](iframe-double-click-word-select.md) — orphaned `iframe-double-click` → `handleDoubleClick` selects word via `getWordRangeFromPoint`/`Intl.Segmenter`, routes through `makeSelection`; `pointerDownTimeRef=0` bypasses hold gate; `isValidSelection` guard avoids desktop double-fire -- [Cross-page selection auto-turn (#4741)](cross-page-selection-autoturn-4741.md) — `useAutoPageTurn` dwell; `onAfterTurn` re-emit -- [Annotator onLoad listener leak (#4735)](annotator-onload-listener-leak-paragraph-mode.md) — `useRendererInputListeners` once-per-view -- [Paragraph mode toggle/resume (#4717)](paragraph-mode-toggle-resume-4717.md) — snapshot live Set; resume from fresh `lastLocation.cfi` -- [Paragraph-mode accidental exit (#4474)](paragraph-mode-accidental-exit-4474.md) — `paragraph-show-controls`; bar `absolute`→`fixed` +- [WebDAV browser sort + search (#4724)](webdav-browse-sort-search-4724.md) — PR #4786; +- [Image zoom trackpad flicker (#4742)](image-zoom-trackpad-flicker-4742.md) — macOS pinch=`ctrl+wheel`; +- [Instant Highlight ate tap/swipe](instant-highlight-tap-paginate.md) — preventDefault killed tap-paginate; +- [Keyboard selection adjust (#4728)](keyboard-selection-adjust-4728.md) — Shift+←/→ char, Ctrl/Alt+Shift word; +- [Double-click word select](iframe-double-click-word-select.md) — orphaned `iframe-double-click` → +- [Cross-page selection auto-turn (#4741)](cross-page-selection-autoturn-4741.md) — `useAutoPageTurn` dwell; +- [Annotator onLoad listener leak (#4735)](annotator-onload-listener-leak-paragraph-mode.md) — `useRendererInputListener +- [Paragraph mode toggle/resume (#4717)](paragraph-mode-toggle-resume-4717.md) — snapshot live Set; resume from fresh +- [Paragraph-mode accidental exit (#4474)](paragraph-mode-accidental-exit-4474.md) — `paragraph-show-controls`; bar - [#4584 tap-death](issue-4584-tap-death-investigation.md) — UNFIXED; `isPopuped` RED HERRING; likely WebView-148 - [Dblclick-drag turns page (#4524)](dblclick-drag-pageturn-4524.md) — `isMouseDown` gates `postSingleClick` - [Tap to open image/table (#4600)](tap-to-open-image-table-4600.md) — `iframe-open-media` + `detectMediaTarget` -- [PDF/CBZ Contrast view-menu](pdf-cbz-contrast-view-menu.md) — per-book `contrast`; ONE `filter:` (invert+contrast); `skipGlobal=true` +- [PDF/CBZ Contrast view-menu](pdf-cbz-contrast-view-menu.md) — per-book `contrast`; ONE `filter:` (invert+contrast); - [iOS instant-dict double popup](ios-instant-dict-double-popup.md) — once-per-gesture latch; `isLongPressHold` 300ms -- Dict: [popup font size #4443](dict-popup-font-size-4443.md) `--dict-font-scale` MDict `::part(dict-content)`; [lemmatization #4574](dict-lemmatization-4574.md) inflected→lemma `-ses→-sis` before `-es` -- Word Lens: [inline gloss](wordlens-feature.md) CFI-safe `` TTS/search isolation; [en-en](wordlens-en-en.md) WordNet synonym manifest-driven +- Dict: [popup font size #4443](dict-popup-font-size-4443.md) `--dict-font-scale` MDict `::part(dict-content)`; [lemmatization #4574](dict-lemmatization-4574.md) +- Word Lens: [inline gloss](wordlens-feature.md) CFI-safe `` TTS/search isolation; [en-en](wordlens-en-en.md) - [Stripe highest-active plan (#4694)](stripe-plan-highest-active-4694.md) — `plans.plan` = MAX over active subs -- [Save image to gallery (#4680)](save-image-to-gallery-android.md) — MediaStore; sharekit 0-byte self-copy (Temp==cacheDir) +- [Save image to gallery (#4680)](save-image-to-gallery-android.md) — MediaStore; sharekit 0-byte self-copy - [Webtoon Mode (#3647)](webtoon-mode-3647.md) — no-gap scrolled images; FXL fit-width; `--scroll-page-gap` - [Biometric app-lock (#4645)](biometric-app-lock-4645.md) — flag from `appLockStore`; plugin `cfg(mobile)` - [Reference Pages (#4542)](reference-pages-672-4542.md) — 'reference' progressStyle; `referencePageCount` -- [E-ink screen refresh page-turner (#4687)](eink-screen-refresh-pageturner-4687.md) — bindable 'refresh' action; generic `EinkRefreshController.kt` reflection (BOOX/Tolino/Rockchip), NO Onyx SDK bundle; gate Android+`viewSettings.isEink` -- [Share intent + toolbar (#4014)](annotation-share-toolbar-4014.md) — Share gated mobile+macOS; `annotationToolbarItems` -- [Instant highlight delete orphan (#4773)](instant-highlight-delete-orphan-4773.md) — stale memoized index + in-place `deletedAt`; re-check at READ -- [Empty highlight leak on annotate cancel (#4791)](empty-highlight-leak-on-annotate-cancel-4791.md) — Annotate eagerly creates placeholder; track `notebookNewHighlightId`, presentation-driven cleanup effect -- [Customize Toolbar global (#4760)](customize-toolbar-global-serializeconfig.md) — `serializeConfig` ref-compare → stale override; value compare -- [Customize Toolbar e-ink black bar (#4839)](customize-toolbar-eink-black-bar-4839.md) — preview Zone copied `bg-gray-600` w/o `.popup-container`; add `eink-bordered` (+ `eink:text-base-content` hint) -- Native TTS: [iOS #4676](native-ios-tts-4676.md) AVSpeechSynthesizer pause==stop rate `pow^(1/2.5)`; [offline halt #4613](native-tts-offline-autoadvance-4613.md) advance only on `end`, SKIP-on-error via `forward()` -- Edge TTS: [word highlight #4017](edge-tts-word-highlighting-4017.md) `audio.metadata` WordBoundary by rAF gate on UA; [drift](tts-word-highlight-singletextnode-drift.md) TEXT_NODE fast path ignored offsets, slice `[start,end]` -- [TTS highlight granularity setting](tts-highlight-granularity-setting.md) — Word/Sentence; gate `prepareSpeakWords` on granularity (NOT supportsWordBoundaries); suppress = wordBoundaries && word +- [E-ink screen refresh page-turner (#4687)](eink-screen-refresh-pageturner-4687.md) — bindable 'refresh' action; +- [Share intent + toolbar (#4014)](annotation-share-toolbar-4014.md) — Share gated mobile+macOS; +- [Instant highlight delete orphan (#4773)](instant-highlight-delete-orphan-4773.md) — stale memoized index + in-place +- [Empty highlight leak on annotate cancel (#4791)](empty-highlight-leak-on-annotate-cancel-4791.md) — Annotate +- [Customize Toolbar global (#4760)](customize-toolbar-global-serializeconfig.md) — `serializeConfig` ref-compare → +- [Customize Toolbar e-ink black bar (#4839)](customize-toolbar-eink-black-bar-4839.md) — preview Zone copied +- Native TTS: [iOS #4676](native-ios-tts-4676.md) AVSpeechSynthesizer pause==stop rate `pow^(1/2.5)`; [offline halt #4613](native-tts-offline-autoadvance-4613.md) +- Edge TTS: [word highlight #4017](edge-tts-word-highlighting-4017.md) `audio.metadata` WordBoundary by rAF gate on UA; [drift](tts-word-highlight-singletextnode-drift.md) +- [TTS highlight granularity setting](tts-highlight-granularity-setting.md) — Word/Sentence; gate `prepareSpeakWords` - [TTS start-from-selection](tts-start-from-selection.md) — use last mark at/before sel; cloneRange+deselect -- [Reuse TTS session on mode entry](tts-reuse-session-mode-entry.md) — `redispatchPosition()` + `tts-sync-request` replay -- RSVP: [control-bar overlap REVERT](rsvp-control-bar-overlap-revert.md) #4585 fixed/#4589 stale-reverted; [font face/family #4519](rsvp-font-settings-4519.md) `getBaseFontFamily` overlay top doc; [RTL word #4630](rsvp-rtl-word-display-4630.md) ORP breaks Arabic→whole `dir=rtl` -- [Overlay z-index scale](zindex-overlay-scale.md) — RSVP 100 / Settings 110 / ModalPortal 120 / toast 130 / app-lock 200 -- [Global annotation page-turn lag (#4575)](global-annotation-pageturn-perf-4575.md) — `global` re-fanned every turn; `WeakMap` memo -- [Overlayer splitRange text nodes](overlayer-splitrange-textnodes.md) — `'p,h1-h4'` dropped `li`; walk text nodes + img/svg +- [Reuse TTS session on mode entry](tts-reuse-session-mode-entry.md) — `redispatchPosition()` + `tts-sync-request` +- RSVP: [control-bar overlap REVERT](rsvp-control-bar-overlap-revert.md) #4585 fixed/#4589 stale-reverted; [font face/family #4519](rsvp-font-settings-4519.md) `getBaseFontFamily` overlay top doc; [RTL word #4630](rsvp-rtl-word-display-4630.md) +- [Overlay z-index scale](zindex-overlay-scale.md) — RSVP 100 / Settings 110 / ModalPortal 120 / toast 130 / app-lock +- [Global annotation page-turn lag (#4575)](global-annotation-pageturn-perf-4575.md) — `global` re-fanned every turn; +- [Overlayer splitRange text nodes](overlayer-splitrange-textnodes.md) — `'p,h1-h4'` dropped `li`; walk text nodes + - [Android image callout freeze](android-image-callout-freeze.md) — `.no-context-menu` on ANCESTOR - [Table dark-mode tint (#4419)](table-dark-mode-tint-4419.md) — `blockquote, table *` tint gated on `overrideColor` -- [Footnote aside border line (#4438)](footnote-aside-namespace-order-4438.md) — @font-face before @namespace; hoist @namespace -- Proofread: [enhancements #4700](proofread-enhancements-4700.md) regex UI/Ctrl+P reuse/`wholeWord` no-op; [per-book CRDT #4781](proofread-per-book-crdt-sync.md) `mergeProofreadRules` by id, `ensureRuleId` backfill -- [Russian hanging-preposition NBSP (#4769)](russian-hanging-prepositions-nbsp-4769.md) — generic `nbsp` + `NBSP_LANGUAGES` (`ru`); after `whitespace`/`simplecc` -- OPDS: [Firefox strict-XML #4479](opds-firefox-strict-xml-4479.md) junk after `` slice to last close; [JSON search #4502](opds2-json-search-4502.md) expand `{?query}` BEFORE resolveURL; [HTML desc #4503](opds-html-description-4503.md) decode-once+sanitize; [self-link meta #4749](opds-self-link-metadata-4749.md) `rel:self` deref; [popular dedup #4782](opds-popular-catalog-dedup-4782.md) normalized-URL +- [Footnote aside border line (#4438)](footnote-aside-namespace-order-4438.md) — @font-face before @namespace; hoist +- Proofread: [enhancements #4700](proofread-enhancements-4700.md) regex UI/Ctrl+P reuse/`wholeWord` no-op; [per-book CRDT #4781](proofread-per-book-crdt-sync.md) +- [Russian hanging-preposition NBSP (#4769)](russian-hanging-prepositions-nbsp-4769.md) — generic `nbsp` + +- OPDS: [Firefox strict-XML #4479](opds-firefox-strict-xml-4479.md) junk after `` slice to last close; [JSON search #4502](opds2-json-search-4502.md) expand `{?query}` BEFORE resolveURL; [HTML desc #4503](opds-html-description-4503.md) decode-once+sanitize; [self-link meta #4749](opds-self-link-metadata-4749.md) `rel:self` deref; [popular dedup #4782](opds-popular-catalog-dedup-4782.md) - [D-pad Navigation](dpad-navigation.md) — Android TV remote / arrow-key nav - [koplugin cover upload (#4374)](koplugin-cover-upload.md) — `extractLocalCover` via `getCoverImage` ## Library Fixes -- [Book action platform surfaces](book-actions-platform-surfaces.md) — context menu Tauri-desktop-only; cross-platform in `BookDetailView` +- [Book action platform surfaces](book-actions-platform-surfaces.md) — context menu Tauri-desktop-only; cross-platform - [Tauri menu append race (#4389)](tauri-menu-append-race-4389.md) — single `await Menu.new({ items })` -- TXT: [author recognition #4390](txt-author-recognition-4390.md) `parseLabeledAuthor`+`isPlausibleAuthorName`; [chapter measure-word FP #4658](txt-chapter-measure-word-4658.md) strong `[章节回讲篇话]` vs weak `[卷本册部封]` +- TXT: [author recognition #4390](txt-author-recognition-4390.md) `parseLabeledAuthor`+`isPlausibleAuthorName`; [chapter measure-word FP #4658](txt-chapter-measure-word-4658.md) - [Cover stale (in-place mutation)](cover-stale-inplace-mutation-memo.md) — pure `getBookWithUpdatedMetadata` -- [Series/author back no-op (#4437)](series-folder-back-noop-4437.md) — Next 16.2 empty-search no-op; `handleBack` `group=''` -- [Library/reader separate texture (#4743)](library-reader-separate-texture-4743.md) — `libraryBackground*` device-local; `none` unmounts -- [List view series overflow (#4796)](list-view-series-overflow-4796.md) — fixed `h-28` clipped series+description (Android font scale); `min-h-28` -- [Recently-read shelf (#3797)](recent-read-shelf-3797.md) — PR #4829; reuse `BookItem` + shared `useOpenBook`; flex strip needs grid's gap-aware `flexBasis` calc + `min-w-0` to align with bookshelf columns +- [Series/author back no-op (#4437)](series-folder-back-noop-4437.md) — Next 16.2 empty-search no-op; `handleBack` +- [Library/reader separate texture (#4743)](library-reader-separate-texture-4743.md) — `libraryBackground*` +- [List view series overflow (#4796)](list-view-series-overflow-4796.md) — fixed `h-28` clipped series+description +- [Recently-read shelf (#3797)](recent-read-shelf-3797.md) — PR #4829; reuse `BookItem` + shared `useOpenBook`; flex ## Architecture & Patterns - foliate-js submodule at `packages/foliate-js/`; multiview paginator preloads adjacent sections -- [Markdown .md support (#774)](markdown-md-support-774.md) — in-memory foliate book (no EPUB) in `src/utils/md.ts`; split-at-H1; `isMd()` before `isTxt()`; nav contract: `section.id`↔`splitTOCHref` SAME type (string), `loadText` needed for fragment CFIs, `XMLSerializer` for void-tag XHTML +- [Markdown .md support (#774)](markdown-md-support-774.md) — in-memory foliate book (no EPUB) in `src/utils/md.ts`; - Style: `getLayoutStyles()` always, `getColorStyles()` when overriding color; `transformStylesheet()` rewrites EPUB CSS at load - TTS independent section tracking (`#ttsSectionIndex`); safe insets: native plugin → useSafeAreaInsets → styles; Dropdowns `DropdownContext` -- Stale settings closure: store-hook `settings` stale across `await`; persist `useSettingsStore.getState().settings` ([#4780](webdav-connect-nullified-4780.md)) -- [Foliate touch-listener capture phase](foliate-touch-listener-capture-phase.md) — suppress gestures via `{capture:true}` -- [iframe cross-realm instanceof](iframe-cross-realm-instanceof.md) — `instanceof Element` false; duck-type `'closest' in target` +- Stale settings closure: store-hook `settings` stale across `await`; persist `useSettingsStore.getState().settings` ([#4780](webdav-connect-nullified-4780.md) +- [Foliate touch-listener capture phase](foliate-touch-listener-capture-phase.md) — suppress gestures via +- [iframe cross-realm instanceof](iframe-cross-realm-instanceof.md) — `instanceof Element` false; duck-type `'closest' - [Virtuoso + OverlayScrollbars](virtuoso_overlayscrollbars.md) — useOverlayScrollbars for mobile webviews - [Design system → DESIGN.md](feedback_design_system_doc.md) — never `pl/pr/ml/mr/text-left/right` (RTL) ## Workflow & Feedback @@ -142,6 +143,6 @@ - [No test seams in prod](feedback_no_test_seams_in_prod.md) — prod never imports `__reset*ForTests` - [No lookbehind regex](feedback_no_lookbehind_regex.md) — never `(?<=)`/`(?` (and ``) is NOT allowed → launcher inflate fails → "Can't load widget". Use an empty `FrameLayout` for spacers. Covers: badge + progress bar are **baked into the bitmap** (Canvas in `writeThumbnail`) because RemoteViews can't clip/overlay reliably; shown via `fitCenter`. Responsive sizing by grid cells: `n = (minWidthDp + 30) / 70` (Android cell formula); one book per column, cap 3. +- **Background TTS progress freeze.** `book.progress` (libraryStore) AND `readerProgressStore` are both written by the same `setProgress`, inside `commitRelocate` → **`requestAnimationFrame`**, which Android pauses for a backgrounded WebView → both freeze during background TTS. No store-only fix (page-based progress needs rendering). Fix: in `FoliateViewer.progressRelocateHandler`, commit synchronously when `document.visibilityState === 'hidden'` (relocate still fires; only the rAF commit was deferred). Confirmed working on device. +- **iOS TTS controls deferred** — interactive widget buttons need iOS 17 App Intents; widget min target is iOS 15 (15/16 widgets can only deep-link, no buttons). Android uses `MediaButtonReceiver.buildMediaButtonPendingIntent` (any version). Follow-up only. +- **`.superpowers/` is NOT gitignored** in this repo → a subagent's `git add` can sweep SDD scratch (`*-report.md`) into a commit; check `git ls-files '.superpowers/*'` before squashing/pushing. + +Related: [[android-nativefile-remotefile-io]] · [[tts-fixes]] · build/worktree [[feedback_use_worktree]] diff --git a/apps/readest-app/package.json b/apps/readest-app/package.json index e4972c07..603cdb83 100644 --- a/apps/readest-app/package.json +++ b/apps/readest-app/package.json @@ -1,6 +1,6 @@ { "name": "@readest/readest-app", - "version": "0.11.12", + "version": "0.11.16", "private": true, "type": "module", "scripts": { diff --git a/apps/readest-app/release-notes.json b/apps/readest-app/release-notes.json index c8ecf011..d0ff107e 100644 --- a/apps/readest-app/release-notes.json +++ b/apps/readest-app/release-notes.json @@ -1,5 +1,19 @@ { "releases": { + "0.11.16": { + "date": "2026-06-29", + "notes": [ + "Sync: Added WebDAV and Google Drive sync for your books and reading data", + "Widgets: Added home-screen reading widgets on mobile so you can jump straight back into your book", + "Reading: You can now open and read Markdown(.md) files", + "Reading: You can select a word by double-clicking it, and search gained regex and nearby-words modes", + "Reading: Added a sticky progress bar with chapter markers, and keyboard shortcuts to fine-tune text selection", + "Library: Added a Recently Read shelf to quickly pick up where you left off, plus a separate background texture for your library", + "Text-to-Speech: Added offline voices on iOS, a setting to highlight by word or by sentence", + "PDF: Smoother pinch-zoom and panning, faster scrolling on mobile, and a new contrast option in the view menu", + "More: Customize the highlight toolbar across all books, filter exported annotations by color and style" + ] + }, "0.11.12": { "date": "2026-06-20", "notes": [ diff --git a/data/metainfo/appdata.xml b/data/metainfo/appdata.xml index 9242f551..0bf6ac2b 100644 --- a/data/metainfo/appdata.xml +++ b/data/metainfo/appdata.xml @@ -70,6 +70,21 @@ + + +
    +
  • Sync: Added WebDAV and Google Drive sync for your books and reading data
  • +
  • Widgets: Added home-screen reading widgets on mobile so you can jump straight back into your book
  • +
  • Reading: You can now open and read Markdown(.md) files
  • +
  • Reading: You can select a word by double-clicking it, and search gained regex and nearby-words modes
  • +
  • Reading: Added a sticky progress bar with chapter markers, and keyboard shortcuts to fine-tune text selection
  • +
  • Library: Added a Recently Read shelf to quickly pick up where you left off, plus a separate background texture for your library
  • +
  • Text-to-Speech: Added offline voices on iOS, a setting to highlight by word or by sentence
  • +
  • PDF: Smoother pinch-zoom and panning, faster scrolling on mobile, and a new contrast option in the view menu
  • +
  • More: Customize the highlight toolbar across all books, filter exported annotations by color and style
  • +
+
+
    @@ -208,21 +223,6 @@
- - -
    -
  • Text-to-Speech: Fixed an issue where TTS could not continue to the next chapter
  • -
  • Reading: Fixed an issue importing very large TXT files on iOS
  • -
  • Reading: Fixed the layout of the reading ruler in scrolled mode
  • -
  • Reading: Smoother page-turn animations for a more fluid experience
  • -
  • Reading: Added a gallery mode to zoom and browse images within books
  • -
  • Annotations: Page numbers are now displayed and exported with highlights and notes
  • -
  • Annotations: Added support for exporting highlights to Readwise
  • -
  • OPDS: Fixed missing book descriptions in OPDS feeds
  • -
  • Android: Improved compatibility with older WebView versions on Android
  • -
-
-
FSFAP diff --git a/data/metainfo/appdata.xml.sha256 b/data/metainfo/appdata.xml.sha256 index 26d17700..2594323e 100644 --- a/data/metainfo/appdata.xml.sha256 +++ b/data/metainfo/appdata.xml.sha256 @@ -1 +1 @@ -1e0de8d004148c86f38822baed75abe6a1104df872c71f1b5541eaa10b28329c ../../data/metainfo/appdata.xml +509767206c4727e8f7a60d2b94879129f0edfa0bbbbcea34a748391b1113a073 ../../data/metainfo/appdata.xml