Skip to content

feat: in-chapter search, RTL support, reading statistics & scheduled updates - #21

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

feat: in-chapter search, RTL support, reading statistics & scheduled updates#21
bizzkoot merged 54 commits into
masterfrom
dev

Conversation

@bizzkoot

Copy link
Copy Markdown
Owner

PR: Comprehensive Upstream Feature Integration, Analytics Overhaul & Architectural Hardening (110 Commits)

Repository: bizzkoot/lnreader
Source Branch: dev (6b7b213bb)
Target Branch: master (9984f90d9)
Commits Ahead: 110 commits · Files Changed: 346 files (+23,806 / −3,370 lines)
Verification Status:116 test suites / 1,674 tests passing (100%) · tsc --noEmit 0 errors · ESLint clean · TTS wake-cycle & refill verified


1. Executive Summary

This PR integrates all remaining high-value features, security updates, stability fixes, and UX modernizations from upstream lnreader/lnreader into our production-hardened fork, while strictly preserving our core architectural pillars:

  • 3-Layer Hybrid TTS Engine: React Native controller + WebView DOM parsing + Native Android Foreground Service with length-preserving phonetic text cleanup.
  • Dynamic UI & Font Scaling: Centralized scaleDimension() and useScaledDimensions() density scaling tokens.
  • Native DNS-over-HTTPS (DoH): Native OkHttp DoH engine with bootstrap IPs, runtime provider switching, and SharedPreferences persistence.
  • Raw-SQL SQLite Storage: High-performance indexed SQLite schema, exclusive transaction wrappers, and automated migration runner.

Across 110 commits, this release delivers 5 major upstream feature pillars, unified visible/TTS cleanup, Material You / MD3 theme overhaul, Kitsu tracker support, remote backup DoH routing & security hardening, in-app features documentation, and multi-pass adversarial audit remediations.


2. Architectural Context — Why Selective Porting

A direct git merge from upstream is structurally impossible due to four fundamental architectural divergences:

┌─────────────────────────┬───────────────────────────────────┬──────────────────────────────────────────┐
│ Architectural Subsystem │ Upstream (lnreader/lnreader)      │ This Fork (bizzkoot/lnreader)            │
├─────────────────────────┼───────────────────────────────────┼──────────────────────────────────────────┤
│ Database Layer          │ Drizzle ORM + op-sqlite (#1735)   │ Raw-SQL expo-sqlite + MigrationRunner    │
│ TTS Subsystem           │ Nitro C++ Modules (#1889/#1896)   │ 3-Layer Hybrid Kotlin Service + Bridge   │
│ Background Scheduling   │ Android WorkManager Module        │ ServiceManager + Opportunistic Pipeline  │
│ UI & Density Scaling    │ Fixed pixel layouts               │ Dynamic UI Scaling (scaleDimension)      │
│ Network Security        │ Standard OkHttpClient / System    │ Native DNS-over-HTTPS (DoH Engine)       │
└─────────────────────────┴───────────────────────────────────┴──────────────────────────────────────────┘

All upstream features and fixes were selectively re-engineered to fit our robust architecture, followed by multi-agent adversarial audits to eliminate regressions.


3. Major Features & Capabilities Added

3.1. In-Chapter Text Search (Upstream lnreader#1877)

  • Non-Destructive WebView Search: window.readerSearch engine with batched DOM scanning (80 chunks/tick) and live <mark> highlighting.
  • Zero TTS Interference: Injected <mark> tags are strictly contained inside paragraph text nodes, guaranteeing that paragraph indexing and window.tts.getTextNodes() remain 100% stable.
  • Scaled Modern UI: Material 3 styled ReaderSearchbar.tsx with occurrence counters, next/previous match steppers, hardware back button dismissal, and auto-scroll to match.

3.2. RTL Language & Layout Support (Upstream lnreader#1717)

  • Bidirectional Native Layout: Native RTL layout direction support for Arabic (ar), Hebrew (he), Persian (fa), and Urdu (ur) locales.
  • CSS Logical Flow: Converted reader document styling to CSS logical properties (padding-inline-start, padding-inline-end, margin-inline-start).
  • Dynamic Text Alignment: Dynamic 'start' text alignment resolution that mirrors seamlessly without breaking custom user alignments.
  • Indicator Geometry: Fixed layout ambiguities in TopTabBar.tsx ensuring indicator animations respect RTL constraints without jumping.

3.3. Reading Time Tracking & Inactivity Detection (Upstream lnreader#1899)

  • Database Migration 006: Introduced ReadingSession table with cascading foreign keys and compound indexes ((novelId, startTime)).
  • Lifecycle Engine (useTimeTracking.ts): Accurately tracks active manual reading time with foreground/background app state listeners.
  • Inactivity Auto-Pause: Automatically pauses reading session tracking after 2 minutes of inactivity to prevent skewed metrics.
  • TTS Synergy & Dual-Mode: Automatically pauses manual tracking when TTS is active, and records TTS reading time independently.
  • Hardened Progress Flush: Guaranteed progress and session flushing on app backgrounding and app unmount.

3.4. Analytics & Statistics Overhaul (Upstream lnreader#1919)

  • Multi-Tab Analytics Screen: 3 comprehensive analytics tabs: Overview, Time, and Plugins.
  • Raw-SQL Aggregations: Optimized aggregate queries in StatsQueries.ts calculating total read time, daily averages, completion rates, and reading velocity.
  • SVG Distribution Donut Charts: Interactive SVG donut distribution charts rendered via react-native-svg with zero-division math protections (NaN guard on empty libraries).
  • Genre Taxonomy & Deep-Dive: Interactive genre breakdown exploring reading habits and novel distribution across categories.

3.5. Scheduled Background Library Updates

  • Configurable Schedule: User-selectable automatic update intervals (12h, 24h, 48h, 72h, 168h / weekly) persisted in MMKV.
  • Opportunistic & Background Dispatching: Dispatches updates during application launch and background lifecycle windows via ServiceManager.
  • Clock-Skew Self-Healing: Resilient delta calculation that automatically recovers if device clock jumps backwards or syncs across timezones.

3.6. Unified Visible-Text & TTS Cleanup Ruleset (Issue #19)

  • Single Declarative Ruleset: Unified text replacement and regex stripping that can apply to TTS audio, visible reader text, or both (applyTo: 'tts' | 'visible' | 'both').
  • Contract & DOM Preservation: Count-preserving replacement using zero-width spaces (U+200B) to protect paragraph indexing. Toggle-off restores pristine DOM state from cached snapshots without requiring page reloads.

3.7. Material 3 Theme & Modern UI Suite

  • Dynamic Material You: Dynamic color palette extraction from wallpaper on Android 12+ (@pchmn/expo-material3-theme) with graceful fallbacks.
  • Context-Based ThemeProvider: Instant theme switching across the app with legacy theme ID migration (1–21 → 100–108).
  • Custom MD3 Slider: Replaced legacy @react-native-community/slider with modern MD3 Slider; hardened horizontal gesture claiming (shouldClaimPanResponder) to prevent swallowing vertical sheet scrolls and eliminated release flicker.
  • Standardized UI Tokens: Modernized TopTabBar indicators, bottom sheets (surfaceContainerLow/High), and outside-tap dismissible Menu.
  • Tab Swipe Gestures: Reader tab swipe navigation with slider drag protection.

3.8. Trackers & Download Enhancements

  • Kitsu Tracker Support: Full OAuth authentication and GraphQL search/progress sync for Kitsu.
  • Parallel Source Updates: Concurrency-controlled multi-source updates (up to 3 sources simultaneously) with rate-limiting safety.
  • Smart Reading Entrypoint: "Start Reading" button and FAB intelligently jump to the first unread chapter.
  • Unloaded Batch Jumping: Chapter jump modal and drawer seamlessly fetch and load unloaded chapter batches for novels with 1,000+ chapters.
  • Configurable Download Cooldown: User-tunable cooldown between chapter downloads to prevent IP bans.
  • EPUB Chapter Numbering: Optional chapter numbers in generated EPUB export titles.

4. Stability, Security & Hardening Fixes

4.1. Database Integrity & Migrations

  • Migration 004: Drops and recreates julianday triggers on all installs; narrows chapter update triggers to ignore high-frequency per-paragraph TTS progress saves.
  • Migration 005: Adds repository enable/disable status flags (isEnabled).
  • Migration 006: Creates ReadingSession table with cascading cleanup.
  • Exclusive Transactions: Rebound all transaction callbacks to run strictly on the active txn object, restoring full atomicity for migrations and backup restores.
  • Scoping Fixes: Scoped deleteDownloads with WHERE id IN (...) (preventing mass deletion) and fixed parameter passing in deleteReadChaptersFromDb.
  • Numeric Sorting: Enforced CAST(page AS INTEGER) across chapter queries and pagination.

4.2. Security & Network Hardening

  • Path Traversal & Zip-Slip Protection: Hardened backup archive extraction and restore routines against directory traversal attacks.
  • Remote Backup via DoH: Ensured Google Drive and WebDAV remote backup network calls route through the configured Native DoH resolver.
  • File Operations Hardening: Wrapped native file streams in safe try/catch blocks with guaranteed closure in NativeFile.kt.

4.3. Upstream Compatibility Waves


5. Verification & Test Coverage

5.1. Automated Verification Gates

Gate Target / Requirement Status
Jest Test Suites All unit and integration suites pass 116 passed / 116 total
Total Test Cases Zero test regressions 1,674 passed / 1,674 total
TypeScript Compilation tsc --noEmit with zero errors 0 errors
ESLint & Code Style Zero lint errors 0 errors
Prettier Formatting Code formatted per repository standards Clean
TTS Refill & Queue TTSAudioManager.refill.test.ts 7/7 passed
TTS Wake-Cycle Wake lifecycle synchronization tests Verified

5.2. Manual QA Smoke Checklist

  • In-Chapter Search: Open a chapter → tap Search icon → search for text → verify stepper navigates, counts match, and TTS playback is unaffected.
  • RTL Locales: Switch device language to Arabic or Hebrew → verify reader layout, top tabs, and chapter drawers mirror correctly.
  • Reading Statistics: Read several chapters manually and with TTS → navigate to More → Statistics → verify Time and Overview tabs display accurate sessions and donut charts.
  • Scheduled Updates: Configure 12h update interval in Settings → verify scheduled update check triggers on next cold start.
  • Visible & TTS Text Cleanup: Open TTS Text Cleanup modal → create replacement rule with applyTo: 'both' → verify live reader text and spoken audio both reflect the rule.
  • Material 3 Theme: Toggle Dynamic Colors on Android 12+ device → verify theme updates instantly across bottom sheets, tab bars, and modals.
  • Kitsu Tracker: Authenticate with Kitsu in Settings → Trackers → bind a novel → verify reading progress updates on chapter completion.
  • Backup & Restore: Export full backup → restore backup → verify all novels, categories, reading sessions, and settings restore without SQL lock errors.

6. Chronological Commit Log (110 Commits)

6550a7884 docs(merge): independent review of upstream analysis + applied corrections
f352ec1df fix(native-file): harden file operations against crashes
ce69ec0e2 fix(service): correct notification throttle and sanitize epub filenames
a7eb69d09 fix(reader): prevent table overflow, restore chip contrast, fade bottom nav
261b379a1 fix(tts): strip leading and trailing quotes from normalized text
45bd7b0af fix(reader): prevent white drawer seam on chapter screen
341cf16c3 fix(ui): align bottom nav with M3, stabilize browse tab bar, cap modal height
9a4110de9 fix(tracker): null-safe chapter progress in set-track dialog
7d0d0a1bf chore: gitignore tsconfig build cache
c2a10f08f fix(settings): normalize repository screen back navigation
95f79626d fix(db): order chapter pages numerically
f4f8defdf fix(db): order epub chapters across paginated pages
153038d70 fix(categories): stable key for drag reordering
da8b1b337 fix(db): preserve default category after reordering
969f088cb fix(db): use exclusive transactions and await runAsync
edfdbaea6 fix(db): scope download deletion and fix read-chapter folder
91c10cf83 fix(novel): prevent genre rendering crashes
cf5b5923e fix(db): date-correct library updates and sorting
b0b32fe28 fix(reader): restore saved chapter progress from db
ac1cb9153 fix(tracker): handle missing client IDs
ac92f34e7 feat(novel): add more statuses and icons
ca9261308 test(db): type-safe fixtures for download deletion tests
d61228002 fix(tracker): restore search requests on submit using event text
f0fb47943 docs(merge): record Batch A completion (29/29 fixes ported)
a1d23a0a2 feat(updates): run library updates in parallel across sources
f7c4b65e8 feat(tracker): add Kitsu tracker support
0c6a6dc96 feat(novel): jump to first unread chapter in read button and fab
62091cb07 fix(novel): load unloaded chapters in jump modal and drawer
032723bbc feat(epub): add chapter numbers to epub chapter titles
7ecb98ab4 feat(updates): add skip-version to update notifications
398ecb958 feat(downloads): make chapter download cooldown configurable
275c1069e docs(merge): record Batch B completion (7/7 core features ported)
7b47bb66b docs(merge): correct stale dev TTS note (already merged via PR #18)
b07e701bb refactor(theme): context-based theme provider with id migration
0f0dd626a feat(theme): dynamic material you colors
b1b08f7f2 feat(ui): replace community slider with md3 slider
2f27e8e65 fix(ui): prevent slider flicker after release
d7f25f94a feat(ui): material 3 top tab indicators
a8e6a24ba refactor(ui): standardize bottom sheet ux and styling
54d5d758a fix(ui): modernize menu styling and outside-tap dismissal
84a59e970 docs(merge): record Batch C completion (7/7 core items ported)
494ad9707 build: patch expo-material3-theme to use gradle namespace (fixes AGP deprecation)
2e5b119b6 docs(merge): fix fork metadata and update modification registry
fa5e10b76 fix(db): run exclusive-transaction statements on txn object
131179d6e docs(merge): record post-port audit of batches A/B/C + exclusive-transaction fix
ebea3c75a fix(epub,ui): quick-fix batch — range export, toggle staleness, error theming, mock fidelity
2eca9c1c9 docs(merge): record quick-fix batch implementation (items 1,3,4,5)
b6b367df6 fix(db): migration 004 — recreate julianday triggers on all installs
4bdc18bb9 docs(merge): record Batch D PR #1 (item #2) implementation
f716159ff build: fix abortOnError deprecation in expo-material3-theme patch
1f4833064 feat(tts): unify visible text and TTS cleanup rulesets (issue #19)
9d0751ecf docs(readme): update feature list and changelog
e9198c4c3 fix: resolve 9 audit findings from 52-commit merge verification
cee9d4a25 docs: collapse large readme sections
9cca7554c Merge pull request #20 from bizzkoot/dev
d4fe64c48 chore(release): v2.1.4
4c5b45229 fix(novel): select all chapters across lazy-loaded batches (upstream #1960)
4221a7f9e fix(db): prevent update-clear freeze on large libraries (upstream #1955)
487d58faf fix(library): prevent stuck loading state when fetch errors (upstream 1eb8c587c)
895f714f6 fix(novel): pass plugin image headers to novel detail cover (upstream #1977)
119a9b257 fix(db): add novel to library when setting categories (upstream #1945)
944b2b3ea fix(epub): support all image formats and cover documents on import (upstream #1622/#1946/#1948)
6fb30f26c fix(reader): soften and neutralize skeleton loading colors (upstream #1964)
a8da9255d fix(novel): pass library status through history and update navigation (upstream 57eca11a9)
8c49e6c05 fix(novel): stabilize update-card navigation callback deps (lint)
03683bd31 feat(plugins): add repository enable and disable controls (upstream #1628)
ba2e07c63 i18n: restore and correct translations across locales (upstream 3bf025108/3ad6e372f/f69e5d6a7)
4757b3aee style(novel): format update-card dependency array
ad242c988 docs(merge): record upstream sync waves 1-3 implementation (2026-08-14)
7a944566c docs(merge): add upstream sync 2026-08-14 analysis and POV review artifacts
06852a6a8 refactor(plugins): extract plugin selectors and clear stale update badges (upstream #1628)
f0e3b4767 docs(merge): record pluginSelectors study + follow-up implementation (2026-08-14)
bc68fbbb8 fix(reader,db,epub): resolve audit findings from upstream sync batch
54b36d5da test(plugins,library,dialog): add audit-requested coverage
02f0127de docs(merge): record audit findings + fix pass (2026-08-15)
ae7f8d60f fix(upstream-sync): harden fork integration
d2195bf75 fix(navigators): catch refreshPlugins rejection on cold start
a54ddae1c test(plugins,db,epub): close harden-commit coverage gaps
daa0b204d docs(merge): record follow-up audit, correct counts, add EPUB smoke fixtures
fa69f3e7d docs(merge): track deferred audit follow-up items
2e4dfdf73 fix(upstream-sync): harden fork integration
1dea15cad fix(security): harden archive and restore inputs
ffddaa1b5 fix(android): wire doh and harden restores
64be3eef5 fix(network): route remote backups through doh
57f4898cd test(updates): derive newer release version
d4c5525bc fix(network): finish streamed backup archives
d80bae9d3 fix(android): activate media session tests
fe7e28219 fix(tts): preserve paused paragraph
932638119 feat(reader): add in-chapter search
6ddfe3d2e feat(reader): add rtl support and fix lint
cde0aa1ff feat(reader): track manual reading time
caa1645cd feat(stats): overhaul analytics and charts
8fecb06a9 feat(updates): schedule library update checks
afb64818c docs(roadmap): update project context for upstream sync
296e6492c fix(ui): resolve tab indicator and appbar insets
384cdef45 fix(hardening): remediate rtl, scheduler and inset issues
91011becd test(reader): add in-chapter search and rtl minimal coverage
29d20cd4e fix(plugins): make fifo queues deterministic with reset gate
82ab55b7f refactor(db,docs): consolidate csv parsing and relax summary limit
4dd63579b fix(settings): fix ui scale slider range, live dragging, and sync
653a9e9f9 fix(reader): tighten progress save on app background
5baef20a6 fix(reader): harden background progress flush
d090bef38 test(reader): add regression for background progress flush
710249981 fix(audit): harden validation, ui gestures and persistence from audits #4-5
25a5186bd fix(audit): address deferred nits H5/M12/M13/LOW-7/9/10
da8110cec docs(db): clarify M15 predicate split and align with upstream (Option B)
e00cd22d9 feat(stats): add dual-mode time tracking and polish analytics UI
3466bfecc test(stats): add regression tests for reading velocity and navigation
4e6feb8cc feat(reader): enable tab swipe gestures and protect slider dragging
6b7b213bb docs(features): document analytics, in-chapter search, rtl, and updates

7. How to Test & Review This PR

# Checkout and setup
git checkout dev
pnpm install

# Run static quality checks
pnpm run type-check
pnpm run lint
pnpm run format:check

# Run full test suite (expect 116 suites / 1,674 tests passing)
pnpm run test

# Run specialized TTS invariant test suites
pnpm run test -- --testPathPatterns="TTSAudioManager.wakeCycle|TTSAudioManager.refill"

- i18n: bind reportUrl in emptyChapterMessage (fixes broken link in non-en locales)
- dialog: catch async onSubmit rejections (no unhandled rejection / stuck dialog)
- skeleton: consolidate on @utils/useLoadingColors, drop stale duplicate
- db: guard empty novelIds in updateNovelCategories; wrap chunked bulk ops in one transaction
- novel: try/catch + toast on select-all; fix range-select guard after select-all
- plugins: catch floating refreshPlugins in upsertRepository; document getLastUsedPluginId
- epub: skip bare-# fragment references in findImageReference
- migrations: dedupe registry comment; rename stale describe title
- usePlugins.refreshPlugins wiring: conditional INSTALLED_PLUGINS write,
  lastUsedPlugin re-stamp, clearUnavailableUpdates semantics
- useLibrary: refetch-after-success keeps loading hidden; stale request-id
  result is discarded
- ConfirmationDialog: dismiss deferred until onSubmit resolves; rejection
  keeps dialog open and interactive
- update db mocks to route transaction statements to shared execAsync/runAsync
Resolve audit findings from the upstream synchronization batch while preserving fork-specific behavior.

- Harden repository lifecycle handling, backup restoration, HTTPS validation, localization, and plugin update reconciliation.

- Serialize plugin filesystem and MMKV mutations to prevent concurrent install, update, and refresh races.

- Make chapter queries, migrations, history, library, and update flows resilient to stale async state, invalid ranges, nullable values, and failed writes.

- Add namespace-tolerant EPUB parsing, collision-safe image/CSS asset mapping, and awaited metadata downloads.

- Preserve falsy legacy backup settings and normalize repository enabled values across database and backup boundaries.

- Expand regression coverage for migrations, selections, ranges, plugin refreshes, and backup schemas.

Validation: type-check, lint, format, targeted Jest suites, native debug compilation, and diff checks passed.
All other refreshPlugins call sites attach a .catch (AvailableTab,
SettingsRepositoryScreen); Main fired it unguarded during the app-boot
effect, so a synchronous DB failure or corrupt MMKV JSON at cold start
produced an unhandled rejection. Repository refresh is non-fatal — it
re-runs on the next visit.
- Extract withPluginMutationLock into a dependency-free mutationQueue
  module (pluginManager pulls cheerio/htmlparser2/native deps, so the
  queue was untestable in isolation) and add serialization tests:
  FIFO exclusivity, release-on-reject, mid-chain rejection, sync ops.
- Add insertChapters upsert tests for the changes===0 UPDATE branch
  (null-safe IS NOT comparisons + null bindings) and the changes>0
  insert-only path; the branch was previously untested (mocks always
  returned changes:1).
- Export the import.ts asset helpers (decodePath/normalizePath/basename/
  createAssetNameMap/rewriteAssetReferences) and cover collision
  suffixing, percent-decoding, data:/absolute/fragment preservation,
  query/fragment suffix retention, and unquoted url() rewriting.
…ixtures

- Correct stale suite counts in the 2026-08-15 audit record: 1496 -> 1501
  tests, refreshPlugins wiring 5 -> 6, backup suites 27 -> 35.
- Persist the 4-POV follow-up audit reports (concurrency / db-integrity /
  epub-native / tests-validation) under audit-followup/.
- Add 4 EPUB device smoke-test fixtures (namespace-prefixed,
  css-relative-images, percent-encoded, duplicate-basenames) + generator
  script + procedure checklist at audit/epub-device-smoke-test.md —
  pending a device run, which cannot be done in-repo.
Living tracking list for the 2026-08-15 follow-up audit. Items 1-11 are
deliberately NOT fixed in the sync branch: all are pre-existing, low-
impact, or high-blast-radius (migration 004 needs its own PR per Batch D
convention). EPUB device smoke test (item 11) is blocked on a device run.
Resolve audit findings from the upstream synchronization batch while preserving fork-specific behavior.

- Harden update synchronization, plugin mutation serialization, installation timeouts, and library-state propagation.
- Correct Indonesian localization and remove formatting defects from synchronization audit documentation.
- Expand regression coverage for stale requests, write queues, plugin installation, and chapter queries.
- Document the required Conventional Commits format and validation expectations in AGENTS.md.

Validation: type-check, lint, format, targeted Jest suites, and diff checks passed.
- Prevent ZIP path traversal and bounded extraction bypasses.
- Sanitize stitched chapters and validate restore/plugin URLs.
- Remove forced process termination from DoH restart handling.
- Validate with type-check, lint, focused Jest tests, and format.
- Apply persisted DoH to React Native OkHttp clients before startup networking.
- Stage ZIP extraction atomically with bounded cleanup and rollback.
- Correct stale update tests and restore Android unit-test dependencies.
- Defer documented RED Android placeholder tests with explicit ignores.
- Validate with full Jest, Gradle unit tests, type-check, lint, and format.
- Replace remote backup HttpURLConnection calls with the configured OkHttp client.
- Preserve streaming ZIP extraction, limits, headers, timeouts, and atomic staging.
- Leave Chromium WebView DNS outside the OkHttp-controlled scope.
- Validate with TypeScript, Jest, Kotlin compilation, and Android unit tests.
- Build update fixtures from the current package patch version.
- Keep update tests reactive to package version bumps.
- Write the ZIP central directory before completing remote backup uploads.
- Preserve OkHttp sink ownership while producing valid archives.
- Validate with Android Kotlin compilation.
- Exercise MediaSession lifecycle, playback state, AudioFocus, and media actions.
- Throttle notification updates while preserving priority state changes.
- Validate self-host backup folder names at backup and restore boundaries.
- Validate with Android unit tests, focused Jest, type-check, lint, and format.
- Keep the reading flag active while refreshing the paused notification
- Preserve the currently spoken paragraph display without changing resume state
- Validate focused TTS utility and media control tests (42 passed)
- Add non-destructive WebView search highlighting and navigation
- Preserve TTS paragraph traversal and wire React Native search controls
- Update the root roadmap with implementation progress
- Validate with type-check and focused WebView tests
- Apply locale-driven RTL layout to native and WebView readers.
- Fix lint:fix so ESLint receives --fix as an option.
- Validate with formatting, type-checking, linting, and diff checks.
- Add ReadingSession migration and aggregate statistics queries.
- Track foreground manual reading with inactivity and TTS pause handling.
- Record WebView touch and scroll activity without changing TTS indexing.
- Add migration and query coverage and document commit newline handling.
- Validate with type-checking, linting, formatting, tests, and diff checks.
- Add Overview, Time, and Plugins statistics tabs.
- Add raw-SQL reading-time metrics, velocity, and top novels.
- Add genre taxonomy exploration and SVG donut charts.
- Add chart, query, and utility test coverage.
- Validate with type-checking, linting, formatting, tests, and TTS checks.
- Persist supported automatic update intervals with safe normalization.
- Dispatch due updates through ServiceManager on app foreground.
- Add settings UI, focused tests, and scheduler documentation.
- Validate with type-check, formatting, and focused tests.
- Record completion of 5 upstream roadmap features across phases 1-3.
- Update test suite baseline count to 1628 passing tests.
- Archive TTS Text Cleanup Pipeline into previous completed tasks.
- Validate with type-check, lint, formatting, and test suite.
- Fix TabBarIndicator double translation offset and width scaling in TopTabBar.

- Prevent duplicate status bar insets by excluding top padding on SafeAreaView.

- Default Appbar to small mode for compact single-row header across all screens.

- Validate with type-checking, linting, formatting, tests, and release build.
- map textAlign left to start for rtl auto-alignment and use logical css properties

- self-heal scheduler on clock skew by treating future timestamps as due

- remove yoga conflict in toptabbar and adopt safe area insets for appbar

- harden donut chart sweep against zero division with finite guard

- update tests and verify type-check, lint, unit tests and release build
- add ReaderSearchbar rendering, counter and min-length warning tests

- add search.js non-destructive wrap/reset and tts paragraph preservation tests

- add rtl locale dir detection and html attrs tests for 6ddfe3d
- add __resetQueueForTests to mutationQueue and writeQueue for isolation

- replace timing-dependent tick(20) with deferred promise gate and beforeEach reset

- verify 5/5 runs green, no interleaving, rejects still release queue
- extract splitCsvField helper to deduplicate genre/status parsing in 3 sites

- filter empty entries consistently via filter(Boolean) in db queries and ui

- update AGENTS.md summary limit from 50 to 72 chars (ideal 50, hard 90)
- export UI_SCALE_MIN/MAX/STEP from scaling.ts for single source of truth

- clamp button steps to safe range and correct boundary markers to 80%/130%

- sync localUiScale to persisted uiScale via useEffect on change

- refactor Slider to single root View with direct PanResponder touch ownership

- support real-time dragging progression and lock parent scrollview interference

- add comprehensive unit test suite covering drag, tap, and disabled scenarios
- WebView (core.js): add flushPendingProgressSave() that clears 150ms debounce and calls saveProgress() synchronously

- Wire visibilitychange (hidden) and pagehide to flush pending scroll save immediately, guarded by TTS reading check

- WebViewReader.tsx: add AppState background/inactive listener that injects flushPendingProgressSave (fallback to saveProgress) for non-TTS reading

- Prevents progress revert to 0% when user scrolls then backgrounds before debounce fires; MMKV sync write now guaranteed before suspension

- Validation: type-check pass, 1657 tests pass (112 suites), format pass
- core.js: guard flush during initial suppressSaveOnScroll to avoid saving stale 0% before layout stabilizes

- WebViewReader: stabilize AppState listener deps via isTTSReadingRef to prevent per-render resubscribe thrash

- Audit hardening for 653a9e9; validation: type-check pass, 1657 tests pass
- cover AppState background/inactive injection of flushPendingProgressSave

- verify injected JS is TTS-guarded and listener cleanup on unmount

- verify core.js flush guards: debounce clear, tts.reading skip, suppressSaveOnScroll skip

- validation: type-check pass, 1663 tests pass (113 suites)
…#4-5

- isValidPluginId: reject '.' and leading/trailing dots, require alphanum endpoints (C4)

- NovelQueries: gate insertNovelAndChapters and _restoreNovelAndChapters with isValidPluginId (H1)

- pluginManager: check response.ok before evaluating plugin code (H8)

- DoHManagerModule: whitelist provider IDs before persisting (M5)

- backup/utils + SettingsRepositoryScreen: replace greedy regex with URL parsing + pathname check (M6)

- HistoryCard: use novelName instead of chapter name for novel navigation (M9)

- Slider: wire shouldClaimPanResponder, onStart never claims, add Number.isFinite guard (H7)

- ChapterQueries: chunk and wrap deleteDownloads/deleteReadChaptersFromDb in withExclusiveTransactionAsync (H9)

- useUpdates: remove unconditional setIsLoading false in focus effect, add timer cleanup (M10)

- UpdateNovelCard: add mountedRef + sequence guard to avoid stale setState (M11)

- Main: log cold-start plugin refresh failures via rateLimitedLogger (M14)

- ReaderSearchbar: 150ms debounce to avoid bridge flood (LOW-1)

- DistributionBar: aggregate <0.5% slices into Other bucket (LOW-6)

- AutomaticLibraryUpdateModal: deduplicate useAppSettings call (LOW-8)

- WebViewReader + translations: expand RTL allowlist and map right->end (M1)

- Appbar: prefer insets.top only to avoid layout jump (M4)

- serialLock: consolidate writeQueue/mutationQueue duplicate FIFO primitives (M8)

Validation: pnpm run type-check, pnpm run test (113 suites, 1663 tests)
- H5: useTimeTracking: == null PK guards, clear chapter-change timer, store+clear 0-delay timeout (fix falsy-0, leaked timer)

- M12: move fetchPlugins inside withWriteLock to avoid duplicate fetch

- M13: migrate legacy string LAST_USED_PLUGIN to deletion

- LOW-7: StatsScreen: mounted guard for Promise.all abort-on-unmount

- LOW-9: TTSForegroundService: @VisibleForTesting for test hooks

- LOW-10: NativeZipArchive: requireNotNull parentFile for NPE at root /

- LOW-4/LOW-5: intentional skip - RTL float override external CSS, numeric ids safe (ponytail: no new abstraction)

Validation: pnpm run type-check, pnpm run test (113 suites, 1663 tests)
- Upstream master (getDetailedUpdatesQuery) uses same split: isDownloaded=1 vs updatedTime IS NOT NULL

- Downstream fork intentionally matches upstream: overview counts only updates, detail download-only lists all offline chapters (incl. NULL updatedTime)

- Add doc comment in ChapterQueries.ts pointing to upstream reference + one-line patch hint for Option A

- Add regression test ChapterQueries.updates.test.ts asserting intentional divergence

Validation: pnpm run type-check, pnpm run test (114 suites, 1666 tests)
- Enable reading time tracking by default and add dual-mode tracking for manual reading and active TTS playback
- Add Settings controls for reading time tracking toggle and inactivity auto-pause interval picker modal
- Fix incorrect header string in Overview tab and localize all missing labels across Overview, Time, and Plugins tabs
- Enhance Time tab with novel cover thumbnails, tap-to-navigate interaction, and velocity duration safeguards
- Make novel rows in Plugins tab interactive with ReaderStack navigation
- Validated with type-check, linter, full 1671 unit/integration tests, and wake cycle simulation
- Add TimeTab regression test suite for velocity thresholds and navigation payload
- Extract StatsCard into standalone component to optimize test imports
- Validated with type-check, linter, Prettier, and full 1674 tests passing
- Enable swipeEnabled across Reader settings TabViews for left/right navigation

- Claim Slider responder on touch start to prevent native ViewPager2 cancellation

- Wrap SettingsReaderScreen TabView in BottomSheetView for gesture hierarchy

- Update Slider unit test suite for touch-start claim verification

- Validated with jest (116 suites, 1674 tests passed) and tsc (zero errors)
- add in-chapter search, rtl support, and reading analytics to features screen

- update readme with reading analytics, search, rtl, and background updates
@bizzkoot
bizzkoot merged commit 4338307 into master Aug 22, 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