Skip to content

feat: 2026-08 upstream merge sync — 53 commits (Batches A–C, D PR#1, TTS issue #19) - #20

Merged
bizzkoot merged 54 commits into
masterfrom
dev
Aug 9, 2026
Merged

feat: 2026-08 upstream merge sync — 53 commits (Batches A–C, D PR#1, TTS issue #19)#20
bizzkoot merged 54 commits into
masterfrom
dev

Conversation

@bizzkoot

@bizzkoot bizzkoot commented Aug 6, 2026

Copy link
Copy Markdown
Owner

1. Summary

The 2026-08 upstream merge sync: a selective port of upstream lnreader/lnreader fixes and features (170 upstream commits analyzed, 76 worth porting, 94 skipped — see §2), delivered as 53 verified commits across four porting batches plus an independent audit fix batch:

Batch Content Status
A 29 upstream safety fixes (DB / downloads / native-file / reader / tracker) ✅ 29/29
B 7 high-value features (Kitsu, parallel updates, first-unread, jump-to-chapter, EPUB chapter numbers, skip-version updates, download cooldown) ✅ 7/7
C 7 UX/theme items (context ThemeProvider, Material You, MD3 Slider, top-tab indicators, standardized bottom sheets, modernized Menu) + 2 build patches ✅ 7/7 + 2
D PR#1 DB Migration 004 (recreate julianday triggers) + TTS visible-text & cleanup ruleset unification (issue #19)
Audit 9 findings from an independent 4-POV post-port verification — all resolved (e9198c4c3) ✅ 9/9

Every commit was verified against its claimed intent (not just its message): a 4-agent multi-POV audit cross-checked each port against the fork's actual architecture, found 3 initially-incomplete ports (fixed in follow-ups, see §4), found 1 real defect during the audit itself (fixed on the spot), and the 9-finding fix batch closed out the remaining MED/LOW items.


2. Context — why selective porting (not a full merge)

A full upstream merge remains infeasible — three architecture walls separate the repos:

  1. DB: upstream migrated to Drizzle ORM + op-sqlite (Db manager lnreader/lnreader#1735) vs fork's raw expo-sqlite SQL + custom MigrationRunner.
  2. TTS/Native: upstream uses Nitro modules + MediaSession + WorkManager (refactor: Migrate Background Tasks to Native Android Scheduling lnreader/lnreader#1889/feat: Replace Legacy Media Controls with Nitro-Powered Playback lnreader/lnreader#1896) vs fork's custom Kotlin (TTSHighlightModule, TTSForegroundService, DoH) + background-actions.
  3. Build: upstream is Expo 55 managed + rock CLI (Migration to Expo managed workflow lnreader/lnreader#1885/feat: migrate from rn community cli to rock lnreader/lnreader#1812) vs fork's Expo 54 bare + Gradle 9.2.0.

Strategy: selective cherry-pick / manual port, prioritizing (a) fixes where the fork carries byte-identical pre-fix code (i.e. the fork has the same live bugs), (b) high-user-value features that port cleanly, and (c) theme/UX modernization with zero TTS/DoH/per-novel-settings impact.


3. What this PR does

3.1 Batch A — 29 upstream safety fixes (key highlights)

  • Critical SQL fixes (the fork had the same live bugs upstream just fixed):
    • edfdbaea6deleteDownloads previously ran UPDATE with no WHERE, wiping isDownloaded for all chapters; now scoped WHERE id IN (…). Also fixed deleteReadChaptersFromDb passing novelId twice (deleted the wrong disk folder).
    • 95f79626d / 153038d70 — chapter pages compared as strings ('10' < '2'); now CAST(page AS INTEGER) everywhere.
    • cf5b5923elastUpdatedAt compared lexicographically in SQLite triggers; now julianday() (completed by Migration 004, §3.4).
    • 969f088cbfa5e10b76 — exclusive transactions: callbacks now run on the txn object (expo-sqlite opens a new connection), restoring true atomicity for library restore/migrations.
    • 91c10cf83 — default-category lookup replaced hardcoded sort = 1.
  • Crash hardening: f352ec1df native-file ops wrapped in try/catch + stream close (top native crash class); ac1cb9153/9a4110de9 tracker null guards; ac92f34e7 genre parser.
  • TTS/reader: 261b379a1 strips leading/trailing quotes from normalized TTS text (length-preserving); b0b32fe28 restores saved chapter progress from DB; a7eb69d09 table overflow scroll + chip contrast; 45bd7b0af drawer seam.
  • Service: ce69ec0e2 notification throttle no longer computes negative delays; EPUB filenames sanitized.
  • Tracker: d61228002 restores search requests on submit.

3.2 Batch B — 7 high-value features

  • f7c4b65e8Kitsu tracker (4th tracker; OAuth + GraphQL search/score, kitsu.ts byte-identical to upstream, 14 unit tests).
  • a1d23a0a2Parallel library updates (concurrency ≤ 3 sources, rate-limit safe, 2 tests).
  • 0c6a6dc96Start Reading jumps to first unread chapter (Read button + FAB).
  • 62091cb07Jump-to-chapter loads unloaded batches (novels with thousands of chapters) + drawer end-reach batch loading.
  • 032723bbcEPUB chapter numbers option (epubIncludeChapterNumber).
  • 7ecb98ab4Skip-version update notifications (preserved the fork's richer update dialog; also fixed the first-launch check bug).
  • 398ecb958Configurable chapter download cooldown (service actually consumes getChapterDownloadCooldownMs(); no hard-coded sleep).

3.3 Batch C — UX/theme train (7 items + 2 build patches)

  • b07e701bb — context-based ThemeProvider with legacy theme-ID migration (1–21 → 100–108), instant re-render; fork's uiScale density scaling preserved.
  • 0f0dd626adynamic Material You colors (@pchmn/expo-material3-theme), Android 12+ only, graceful fallback.
  • b1b08f7f2 + 2f27e8e65custom MD3 Slider replacing @react-native-community/slider (dep removed; all 7 consumers migrated, TTS min/max/step preserved; release-flicker fixed).
  • d7f25f94aM3 top-tab indicators (TopTabBar) across 6 tab views.
  • a8e6a24bastandardized bottom sheets (surfaceContainerLow/High tokens, 9 consumers).
  • 54d5d758amodernized Menu (outside-tap + back-button dismissal, M3 tokens, uiScale kept).
  • 494ad9707 + f716159ff — expo-material3-theme gradle namespace + abortOnError patches (required under Gradle 9.2.0 / AGP 8.12.0; verified applied in node_modules).

3.4 Batch D PR#1 — Migration 004 + TTS issue #19

  • b6b367df6DB Migration 004: recreates the 4 SQLite julianday triggers on ALL installs (they were inert on existing installs), narrows the Chapter update trigger to AFTER UPDATE OF isDownloaded, unread, readTime, updatedTime (no longer fires on per-paragraph TTS progress saves), includes add_category, with column guards + julianday backfill. 28 migration tests incl. full upgrade-path matrix (fresh/v1/v2/v3/empty/large).
  • 1f4833064TTS: unify visible text and TTS cleanup rulesets (issue Feature Request: Unify Visible Text and TTS Cleanup Logic #19) — one declarative ruleset can now also clean the visible reader DOM (applyTo: 'tts' | 'visible' | 'both', default 'tts' = zero behavior change). Count-preserving (U+200B padding keeps the RN↔WebView paragraph-index contract), pristine-snapshot TTS reads, envelope v2 export with version-validated import.

3.5 Audit fix batch (e9198c4c3) — 9 findings resolved

Independent 4-POV verification of all 52 commits (before this one) found 2 MED UX defects + 1 MED UX regression risk + 6 LOW items. All resolved:

# Finding Fix
1 Duplicate "Applies to" row in TTS cleanup modal Removed duplicate Pressable
2 Visible cleanup only applied on next WebView load Re-inject setVisibleCleanup on settings change; toggle-off restores pristine DOM from snapshots
3 Custom Slider swallowed vertical scroll (blocked scroll-through in TTS sheet/settings) Claim only horizontal-dominant gestures (shouldClaimPanResponder, 6px threshold); tap-to-jump preserved; flicker fix intact
4 No-op visible write-back flattened inline markup Skip write-back when nothing changed
5 Invalid persisted applyTo behaved as 'both' resolveTtsCleanupTarget() — garbage → 'tts' everywhere
6 Menu text not uiScale-scaled; nav-bar dead code; dbError ErrorFallback unthemed scaleDimension(16/20, uiScale); dead call removed + documented (upstream lnreader#1076 rationale); pure buildPaperTheme + ErrorFallbackPaperProvider (no DB-bound hook)
7 README "all deprecation warnings resolved" was false Corrected to factual API-35 + partial-cleanup claims
8 Chapter-number lookup heuristic; jump/drawer scroll target not filter-safe; fully-read novel hid Read button/FAB chapterNumber-first query w/ position fallback; findIndex scroll target; chapters[0] fallback
9 No tests for update-checker first-launch/ignoreVersion; theme-ID migration map unpinned +6 update-checker tests; transformThemeId exported + full 1–21→100–108 map pinned

4. Gaps found & resolved during porting

Three Batch-A ports were initially incomplete and are fully resolved within this PR (verified):

Initial port Gap Resolved by
f4f8defdf EPUB range ordering Range branch used per-page position window (wrong/duplicated chapters on multi-page novels) ebea3c75aLIMIT ? OFFSET ? over flat (page, position) order (+6 tests)
969f088cb exclusive transactions Callbacks called db.runAsync (outside the txn's new connection) → atomicity silently lost fa5e10b76 — all 6 sites rebound to tx.runAsync (grep-verified zero db.* in txn callbacks)
cf5b5923e julianday triggers CREATE TRIGGER IF NOT EXISTS never recreated triggers on existing installs b6b367df6 — Migration 004 drop/recreate + backfill (+28 tests)

5. Verification

5.1 Automated gates (all green at HEAD e9198c4c3)

Gate Result
pnpm run test 86 suites / 1,435 tests (baseline 84/1,349 → +2 suites, +86 tests, zero regressions)
pnpm run type-check ✅ 0 errors
pnpm run lint ✅ 0 errors (7 pre-existing warnings, unchanged)
pnpm run format:check ✅ clean
pnpm run test:tts-wake-cycle ✅ 7/7
pnpm run test:tts-refill

5.2 Verification methodology (independent, per-commit)

  • 4 parallel POV review agents (TTS / DB / theme-UI / features) cross-checked every commit against git show diffs + live code with file:line evidence; the 2 MED + regression-risk findings were re-verified by the main agent before fixing.
  • Prior fixes kept intact in the final state: TTS quote-strip, progress restore, per-novel overrides, DoH, uiScale scaling.
  • Fork integrity: zero TTS-pipeline / TTS-state-machine / TTS-native / DoH / per-novel-settings code touched by the theme train; dependencies net −@react-native-community/slider +@pchmn/expo-material3-theme only.

5.3 Manual test checklist

  • Reader TTS bottom sheet: speech rate / pitch sliders adjust, page scrolls when swiping on the slider, no flicker on release
  • TTS cleanup modal: single "Applies to" row; switching TTS-only ↔ Visible/Both cleans/restores the reader DOM without reload
  • Library update runs in parallel (up to 3 sources) without rate-limit failures
  • Trackers: Kitsu login + score; update dialog "Skip version" suppresses the prompt
  • Jump-to-chapter in a 1000+ chapter novel (unloaded range) + filtered drawer scroll
  • Fully-read novel: Read button / FAB still opens chapter 1
  • EPUB range export (multi-page novel) + "chapter numbers" toggle
  • Themes: legacy theme ID migration (existing installs), dynamic colors on Android 12+, fallback below
  • App update from v2.1.3 → this build: Migration 004 runs (library lastUpdatedAt sorting correct)

6. Files changed (high-level)

153 files, +7,079 / −1,195 across: database migrations/queries (+~1,900 lines incl. 28 migration tests), theme/UI components (new Slider.tsx, TopTabBar.tsx, layout.ts), tracker (new kitsu.ts + 14 tests), updates service (parallel runner + 2 tests), TTS cleanup engine (visible-text unification, +190 test lines), native (NativeFile.kt hardening, core.js visible-cleanup bridge), plus the audit fix batch. Full list in the commit log (git log 6550a7884..e9198c4c3).


7. Out of scope / deferred (tracked in .agents/upstream-merge-memory.md)

  • Batch D remaining: time tracking, in-chapter search, stats overhaul, reader perf sprint, scheduled updates.
  • Batch B stretch (15 items) and Batch C optional (2 items) — deferred.
  • 94 of 170 analyzed upstream commits skipped (CI/release/docs/infra/ALREADY-HAVE/Drizzle).
  • Known LOW residuals (non-blocking, documented): lastReadAt still lexicographic for non-padded imported data; Migration 004 backfill is O(novels×chapters) one-time cost on very large libraries; remaining in-app Kotlin deprecation warnings tracked in plan.md.

8. Commit list (53, oldest → newest)

6550a7884 docs(merge) independent review · f352ec1df native-file hardening · ce69ec0e2 throttle+epub filenames · a7eb69d09 table overflow/chip/nav · 261b379a1 TTS quote-strip · 45bd7b0af drawer seam · 341cf16c3 M3 bottom nav · 9a4110de9 tracker null-safe · 7d0d0a1bf gitignore · c2a10f08f repo back nav · 95f79626d numeric pages · f4f8defdf epub ordering · 153038d70 numeric cast · da8b1b337 category reorder · 969f088cb exclusive txn · edfdbaea6 download scoping · 91c10cf83 default category · cf5b5923e julianday · b0b32fe28 progress restore · ac1cb9153 tracker client ids · ac92f34e7 genres · ca9261308 statuses · d61228002 tracker search · f0fb47943 docs Batch A · a1d23a0a2 parallel updates · f7c4b65e8 Kitsu · 0c6a6dc96 first-unread · 62091cb07 jump-to-chapter · 032723bbc epub numbers · 7ecb98ab4 skip-version · 398ecb958 cooldown · 275c1069e docs Batch B · 7b47bb66b docs TTS note · b07e701bb ThemeProvider · 0f0dd626a Material You · b1b08f7f2 MD3 slider · 2f27e8e65 slider flicker · d7f25f94a top tabs · a8e6a24ba bottom sheets · 54d5d758a menu · 84a59e970 docs Batch C · 494ad9707 gradle patch · 2e5b119b6 docs registry · fa5e10b76 txn-object fix · 131179d6e docs audit · ebea3c75a quick-fix batch · 2eca9c1c9 docs quick-fix · b6b367df6 migration 004 · 4bdc18bb9 docs Batch D PR1 · f716159ff abortOnError patch · 1f4833064 TTS visible-cleanup unify (issue #19) · 9d0751ecf docs readme · e9198c4c3 audit fix batch (9 findings)


9. How to test this PR

git checkout dev
pnpm install
pnpm run type-check && pnpm run lint && pnpm run format:check
pnpm run test          # expect 86 suites / 1435 tests
pnpm run test:tts-wake-cycle
pnpm run test:tts-refill

Manual smoke: launch on Android 12+ (dynamic colors), open a chapter (TTS + visible cleanup), Library → Update (parallel), a novel page (first-unread, jump-to-chapter, EPUB export), Settings → Trackers (Kitsu).

bizzkoot added 30 commits August 4, 2026 18:39
…tions

4-subagent review verified the 2026-08 upstream merge analysis (170 commits):
- All 6 live fork bug claims CONFIRMED, 9/9 ALREADY-HAVE claims SOUND,
  trap commit 72bfcad correctly flagged, PRDs A-D rated SOUND

Corrections applied:
- 0cb9da9 reclassified SKIP->PORT-A2 (pre-Drizzle expo-sqlite tx-concurrency fix)
- 5 DIRECT labels -> MANUAL (31cb4b9, 93bc5e5, 2a919ec, f1fdafd, a062bee)
- 9783c4d reclassified SKIP->PORT-A1 (safe back-nav deletion)
- c3c891c relabeled SKIP-CI -> SKIP-INFRA
- PRD-A: 29 fixes (16 Tier-1 + 6 SQL + 7 extended), epub/import.ts hunk added,
  precondition + fork-side test notes
- PRD-C: require BOTH surfaceContainerLow+High theme keys
- Counts: PORT 74->76, SKIP 96->94

Report: specs/upstream-merge-analysis-2026-08/REVIEW-2026-08-04.md
- unlink: return instead of throwing when file already missing (34be7a1)
- wrap writeFile/readFile/copyFileContent in try/catch so IOException
  serializes across the TurboModule bridge instead of crashing the app
  process (45c4ea8)
- guard EPUB import copyFile with a user-friendly error (45c4ea8)
- close OkHttp response body and streams in downloadFile to prevent OOM
  during batch downloads (4088d59)
- ServiceManager.setMeta: invert throttle condition (< 1000) and compute
  delay as 1000 - (now - lastNotifUpdate) so the notification update is
  actually debounced by 1s instead of firing immediately (57b9d41)
- ExportNovelAsEpubButton: strip filesystem-unsafe chars from epub
  filename with a safe fallback (9e38ad1)
…om nav

- index.css: scroll tables not in the reader chapter element to avoid
  overflow; cleanup next-button styles (788f6ce)
- SelectableChip: drop selectedColor override restoring Midnight Dusk
  contrast (7610631)
- BottomNavigator: shift -> fade animation (65e8610)
normalizeText now removes surrounding quote characters (straight and
curly) so TTS no longer reads them aloud. Length-preserving - only
strips quote chars at string edges, paragraph index contract intact
(54fedc2)
Transparent drawer background so the reader drawer doesn't flash a
white seam over the chapter background (0ed7d87)
…l height

- BottomTabBar: add 16px bottom padding per M3 spec and trim pressable
  vertical padding (intent of 31cb4b9; fork uses scaled padding.xs)
- BrowseScreen: initialLayout for TabView prevents tab bar height jump;
  replace shadow with border to stop shadow flash (f1fdafd)
- SetCategoriesModal: cap category list at 40% window height so long
  lists don't overflow the modal (a062bee)
String(trackItem.progress ?? 0) instead of progress.toString() so a
null/undefined progress value no longer crashes the dialog
(93bc5e5; myAnimeList.ts hunk skipped - fork already null-handles)
Remove useBackHandler + unconditional popTo so back always respects the
navigation stack (9783c4d)
bizzkoot added 23 commits August 5, 2026 05:19
withExclusiveTransactionAsync opens a new connection (useNewConnection),
so db.runAsync inside the callback executes OUTSIDE the transaction,
silently losing atomicity for multi-statement operations
(restoreLibrary, _restoreNovelAndChapters, transactionAsync, migrateNovel).

Route statements through the txn parameter, matching the pre-existing
pattern in ChapterQueries/LibraryUpdateQueries and upstream 0cb9da9.
Test mock updated so tx proxies the shared runAsync mock (assertions on
db.runAsync remain valid).
… theming, mock fidelity

- fix(epub): getNovelDownloadedChapters range branch → LIMIT/OFFSET over
  flat (page, position) order. position is per-page (resets in
  insertChapters), so the old position-window query matched every page for
  multi-page novels → wrong/duplicated chapter set on chapter-range EPUB
  export. 6 new tests pin single-page parity, multi-page correct set,
  overrun clamping, and isDownloaded filter.
- fix(epub): carry LIVE toggle values through the onSubmit payload
  (EpubExportOptions) instead of reading stale useChapterReaderSettings()
  closure at export time. First export after toggling was one submit behind
  for all 4 toggles (appTheme/CSS/JS/chapterNumber). Persistence call kept.
  4 new tests on the pure payload builder.
- fix(ui): render ErrorFallback inside ThemeProvider on the dbError path
  and move ThemeProvider above AppErrorBoundary so boundary-caught errors
  also render themed (was unstyled white screen + console.error for
  dark/AMOLED users).
- test(mock): isDynamicThemeSupported is a plain boolean false in the
  material-you jest mock, matching the real module (a jest.fn was truthy,
  silently steering future dynamic-theme tests into the wrong branch).

Validated: type-check clean, eslint 0 errors, 80 suites / 1304 tests
passing (+10 vs baseline 1294). No PR created.
Triggers were only created in createInitialSchema (user_version === 0), so
existing v2/v3 installs kept stale pre-julianday trigger bodies forever
(CREATE TRIGGER IF NOT EXISTS is a no-op when the trigger exists).

- New migration004: column guard (SQLite doesn't validate trigger-body
  column refs at CREATE time — error only on first fire) → DROP ×4 →
  CREATE ×4 from the shared NovelTable/CategoryTable constants (single
  source of truth, fresh + migrated installs converge) → julianday
  lastUpdatedAt backfill (same subquery the triggers use).
- Perf fix in scope: update trigger now has 'AFTER UPDATE OF
  isDownloaded, unread, readTime, updatedTime' — previously fired on every
  Chapter UPDATE incl. per-paragraph TTS progress saves (pure waste);
  verified semantically safe (no computed column derives from progress).
- add_category trigger included (pre-migration-system installs never had it
  → NULL sort → wrong category ordering).
- Fresh installs keep user_version=2 (004 runs as idempotent no-op,
  matching the 003 precedent); db.ts untouched.
- Tests: real better-sqlite3 engine via ExpoLikeDb adapter + real
  MigrationRunner (better-sqlite3 chosen over node:sqlite — CI pins
  Node 20). 28 tests: trigger recreation/drift invariant, fire behavior,
  lexicographic-vs-chronological divergence, backfill, column-list
  non-firing, idempotency, column guards, upgrade paths v0/v1/v2/v3,
  large-novel set, LibraryQueries sort rewrite.

Validated: type-check clean, eslint 0 errors, 84 suites / 1332 tests
passing (+28 vs baseline). No PR created.
extend the fork-maintained pnpm patch to use 'abortOnError = false'
assignment syntax (was deprecated space-assignment 'abortOnError false').
This was the only fork-actionable warning in the release build; all other
warnings are third-party node_modules or AGP-internal multi-string
dependency declarations (Gradle 10 removals, non-blocking on Gradle 9.2.0).

patch hash updated in pnpm-lock.yaml (f0171c0e → 6f6350cd) via pnpm
patch-commit; verified applied in node_modules and release build warning
count for this module is now zero.
The declarative TTS Text Cleanup ruleset can now also clean the visible
reader DOM, so users maintain ONE ruleset instead of juggling a parallel
Custom JS TreeWalker script (issue #19, filed against v2.1.3).

- Settings: applyTo?: 'tts'|'visible'|'both' on TtsTextCleanupSettings
  (default 'tts' — zero behavior change for existing installs)
- Engine: cleanVisibleText() rules-only, count-preserving visible pass
  (phonetic dictionary + Unicode normalization stay TTS-only); centralized
  gating so cleanTtsText/applyTtsTextCleanup no-op when applyTo==='visible';
  emptied paragraphs padded with VISIBLE_PAD_CHAR (U+200B) to keep the
  RN <-> WebView paragraph-index contract intact
- core.js bridge: setVisibleCleanup/requestVisibleCleanup/applyVisibleCleanup
  with pristine dataset.originalText snapshot captured pre-mutation; all
  three TTS text-read sites (speak, locked dialog, tts-queue lookahead) prefer
  the pristine snapshot so the full ruleset applies exactly once; re-run hooks
  after bionic/spacing DOM rebuild and stitched chapter append
- WebViewReader: 'visible-cleanup' message allowlist + handler (RN cleans,
  injects write-back), setVisibleCleanup inject on load; effective settings
  read from ref (per-novel overrides honored)
- UI: 'Applies to' picker (TTS audio only / Visible text only / Both) in the
  cleanup modal with TTS-only disclaimer; contextual copy in Accessibility +
  Reader TTS tabs; Custom JS editor hint
- Envelope: exports lnreader-tts-cleanup v2 when applyTo non-default (v1
  otherwise); import now validates versions (accepts 1-2, rejects others);
  missing/invalid applyTo maps to 'tts'; bare-object imports keep working
- Tests: cleanVisibleText rules-only gating + count preservation, applyTo
  gating matrix, envelope version matrix, WebView bridge integration test;
  harden flaky 'uses MMKV saved position' test (macrotask flush after
  rerender + waitFor retry, same assertion)
- Docs: README feature table + TTS Text Cleanup section + mermaid diagram;
  PRD Phase 10 (visible text unification)
- add sections for parallel updates, material you design, and trackers
- document technical implementation of dynamic theme and concurrent updater
- update "what's new" with stability fixes, platform updates, and db hardening
- fix image link encoding for tts engine picker screenshot
- restructure table of contents for improved navigation
TTS text cleanup pipeline (issue #19 follow-ups):
- Remove duplicate 'Applies to' row in TTS cleanup modal (#1)
- Re-inject setVisibleCleanup on effective-settings change so visible
  cleanup applies without reload; toggle-off restores pristine DOM text
  from dataset snapshots (#2)
- Skip no-op visible write-back so inline markup is never flattened by a
  rule-less pass (#4)
- Strict resolveTtsCleanupTarget gating: garbage persisted applyTo values
  behave as 'tts' everywhere (#5)

UI/theme:
- Slider claims only horizontal-dominant gestures so vertical swipes scroll
  the parent; tap-to-jump preserved; flicker fix intact (#3)
- Menu item text uiScale-scaled (pre-change value restored); nav-bar dead
  code removed with rationale documented (#6)
- Theme ErrorFallback on the dbError path via pure buildPaperTheme +
  ErrorFallbackPaperProvider (no DB-bound auto-backup hook) (#6)

Docs & novel edge cases:
- Correct README deprecation-warning overstatements (API 35 true; cleanup
  partial, tracked in plan.md) (#7)
- getNovelChaptersByNumber prefers real chapterNumber match with position
  fallback; jump-to-chapter scroll target filter-safe (findIndex + clamp);
  fully-read novels keep Read button/FAB via chapters[0] fallback (#8)

Tests:
- useGithubUpdateChecker: first-launch check, 24h skip, ignoreVersion
- theme-ID migration map 1-21 -> 100-108 pinned for light/dark
- transformThemeId exported for testing

Gates: 86 suites / 1435 tests (baseline 84/1349), TTS wake-cycle 7/7,
type-check clean, lint 0 errors.
- add missing architecture links to table of contents
- fold screenshots, demos, and changelog into collapsible sections
- hide verbose architecture and tts configuration details by default
@bizzkoot
bizzkoot merged commit 9cca755 into master Aug 9, 2026
1 check 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