Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
93c12d9
chore(web): upgrade @readium/* toolkit to 2.5.x
ddfreiling May 23, 2026
d05c475
feat(web): implement AudioNavigator, TTS engine, and Media Overlay
ddfreiling May 23, 2026
333d375
chore(web): collapse webpack bundle into single readiumReader.js
ddfreiling May 23, 2026
dad1435
fix(web): correct platform-interface bugs surfaced during web testing
ddfreiling May 23, 2026
06164cc
feat(example): add seek controls and extend web manifest list
ddfreiling May 23, 2026
aeb1961
chore(vscode): add web example launch configuration
ddfreiling May 23, 2026
5c8a2ea
chore(web): allow loading local files and update remote manifest URLs
ddfreiling May 23, 2026
c179cf7
fix: update FlutterReadiumWebPlugin to latest platform interface
ddfreiling May 23, 2026
baba672
chore: hide text settings not relevant on web
ddfreiling May 23, 2026
e467843
chore: update Epub preferences for web
ddfreiling May 23, 2026
43f7f66
chore(web): support syncEnabled in ttsNavigator
ddfreiling May 23, 2026
7166550
fix: debounce textLocator emission from epubNavigator
ddfreiling May 23, 2026
c415a36
fix(web): translation map parsing
ddfreiling May 23, 2026
e94d607
feat(web): add ToC enrich and skip to epubNavigator
ddfreiling May 23, 2026
10f722c
fix(web): parsing of sync-narr alternate items
ddfreiling May 23, 2026
42cfe10
chore(web): minor preferences update
ddfreiling May 23, 2026
2ed29a8
feat(web): enable audiobooks even when no visual container present
ddfreiling May 23, 2026
91e9944
fix(web): temp patch to bug in @readium/shared
ddfreiling May 23, 2026
88471a8
chore: some changelogs from Claude, not sure how relevant
ddfreiling May 23, 2026
98fb868
feat(web): implement goToProgression
ddfreiling May 23, 2026
9a99b59
chore: format
ddfreiling May 23, 2026
f836b1b
chore: implement valuable refactors from old PR 39 (draft)
ddfreiling May 23, 2026
eb86305
fix: MediaOverlayNavigator should use upstream serialize() methods
ddfreiling May 23, 2026
1144729
chore: AudioNavigator should auto-advance to next track
ddfreiling May 23, 2026
7e8e165
refactor: findLinkByHref helper
ddfreiling May 23, 2026
4d5c2ec
fix(web): audio navigator now advances and emits state correctly
ddfreiling May 23, 2026
2c37903
feat(web): improve logs and format
ddfreiling May 24, 2026
fe9c2c8
chore: apply log format to rest of plugin library code
ddfreiling May 24, 2026
c4f692f
ci: make web platform run integration tests with its own fixtures (re…
ddfreiling May 24, 2026
dc06298
chore(web): further logs at high-risk areas
ddfreiling May 24, 2026
a6e7550
fix(web): apply patch to upstream bug properly
ddfreiling May 24, 2026
b4ad074
fix(web): TTS now starts playing correctly
ddfreiling May 24, 2026
6b770ce
chore: note for web integration test
ddfreiling May 24, 2026
07f5d10
chore: claude hint on architecture
ddfreiling May 24, 2026
9c1ba2c
ci: fix setup-chromedriver version reference
ddfreiling May 26, 2026
11cdda2
chore: remove getString / getLinkContent
ddfreiling May 28, 2026
af76225
chore: add dart mcp-server to vscode mcp
ddfreiling May 28, 2026
468b38f
feat: four TTS/MediaOverlay decoration styles (highlight, underline, …
ddfreiling May 28, 2026
cb0ff34
chore: wire up applyDecorations on web
ddfreiling May 28, 2026
3be468e
fix: map decoration tint colors from Dart to CSS on web
ddfreiling May 28, 2026
102d057
fix: serialize page property as name in Properties toJson method
SifAa May 28, 2026
207a20e
feat(web): totalProgression for epub and audio navigators
ddfreiling May 29, 2026
4f0a0af
chore(web): decoration improvements
ddfreiling May 29, 2026
eabe0ab
Merge branch 'main' into feat/web-feature-parity
ddfreiling May 29, 2026
b7a783d
chore(example): adjust font weight handling for web platform
SifAa May 29, 2026
0417c67
Merge branch 'feat/web-feature-parity' of github.com:ddfreiling/flutt…
ddfreiling May 29, 2026
21e9368
feat(web): use serialize() and try to map mediaOverlay received text …
ddfreiling May 29, 2026
592486d
fix(web): audio playback follows visual reader; ToC tap seeks audio f…
ddfreiling May 29, 2026
ea15138
chore(web): info-level logs at audio / MediaOverlay decision boundaries
ddfreiling May 29, 2026
01c7e23
fix(web): make goTo work properly for all navigators
ddfreiling May 29, 2026
7965fd4
fix(web): highlight modes didnt work as expected
ddfreiling May 29, 2026
7142062
chore: improve AI agent instructions
ddfreiling May 29, 2026
de6469f
chore: add architecture drawio diagram
ddfreiling Jun 1, 2026
9ccdd73
chore: add an example app path to gitignore
ddfreiling Jun 1, 2026
0e72b28
docs: remove unimplemented EpubThemeType / theme preference
ddfreiling May 25, 2026
12130d3
feat(pdf): add offsetFirstPage, spread, visibleScrollbar preferences …
ddfreiling May 25, 2026
df8f486
feat: add isActive flag to ReaderDecorationStyle (iOS + Android)
ddfreiling May 25, 2026
7de08e9
feat(web): implement onErrorEvent stream
ddfreiling May 25, 2026
59a992b
feat(web): support guided-navigation
ddfreiling Jun 1, 2026
a01ab8d
refactor: extract spotlight/ruler/isActive decorations to separate PR
ddfreiling Jun 1, 2026
eae59c4
fix(web): tts navigator - only decorate utterance when equal to segment
ddfreiling Jun 1, 2026
f22d117
chore: guided-navigation example for web
ddfreiling Jun 2, 2026
7ccea6b
fix(web): make guided-navigation sync with visual reader
ddfreiling Jun 2, 2026
70fce64
chore: make bin scripts more folder/tty independent
ddfreiling Jun 2, 2026
56c4103
fix(web): compute media-overlay totalProgression from audio locator
ddfreiling Jun 2, 2026
837b9c2
fix(web): make sure to enrich with position on Locator where necessary
ddfreiling Jun 2, 2026
aaa4c60
feat: add unit tests for web
ddfreiling Jun 2, 2026
1431381
fix(web): work around upstream AudioNavigator issue
ddfreiling Jun 2, 2026
e16e8dd
feat(web): add support for nota comics
ddfreiling Jun 2, 2026
be17741
chore: run web unit tests in test CI workflow
ddfreiling Jun 2, 2026
16079b1
feat(web): add better tocHref tracking
ddfreiling Jun 2, 2026
9f7b76e
docs: add feature parity plans with status to /docs
ddfreiling Jun 3, 2026
8722441
chore: review follow-up
ddfreiling Jun 3, 2026
ec7ccec
Merge remote-tracking branch 'origin' into feat/web-feature-parity
ddfreiling Jun 3, 2026
ced3d21
chore: clean-up CHANGELOG
ddfreiling Jun 3, 2026
0bfbb99
chore: local builds and CI should be against in-repo versions of flut…
ddfreiling Jun 3, 2026
cb4a94d
fix(iOS): missing result(nil) calls on a few onMethodCall cases
ddfreiling Jun 3, 2026
92ee53b
feat: add web integration tests and fixtures
ddfreiling Jun 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# flutter_readium

A Flutter plugin wrapping the [Readium](https://readium.org) toolkits for EPUB / audiobook / WebPub reading. The Dart API is shared across iOS, Android, and Web; each platform delegates to the matching native Readium toolkit. macOS registers a no-op stub only — native macOS is unsupported by upstream swift-toolkit.

## Architecture

Federated Flutter plugin with two pub packages:

- `flutter_readium_platform_interface/` — shared Dart models, method-channel contract, abstract platform interface.
- `flutter_readium/` — app-facing package with native wrappers (iOS/Swift, Android/Kotlin, macOS stub) and a TypeScript→JS web implementation.
- `flutter_readium/example/` — canonical smoke-test app. Verify all UI/behavior changes here before declaring a task done.

Data flow:
```
FlutterReadium (singleton)
→ FlutterReadiumPlatform (abstract)
→ MethodChannelFlutterReadium
├── iOS: Swift / swift-toolkit
├── Android: Kotlin / kotlin-toolkit
└── Web: TypeScript / @readium/navigator (in webview via postMessage)
```

Channels defined in `MethodChannelFlutterReadium`:
- **Method channel** `flutter_readium` — request/response (open, navigate, preferences, …)
- **Event channels** (native→Dart): `flutter_readium/reader_status`, `flutter_readium/text_locator`, `flutter_readium/timebased_state`, `flutter_readium/error_event`

Upstream toolkits (source of truth for native behavior — read on GitHub, don't decompile artifacts):
- iOS: https://github.com/readium/swift-toolkit/ (pinned in `flutter_readium/ios/flutter_readium.podspec`)
- Android: https://github.com/readium/kotlin-toolkit/ (pinned via `ext.readium_version` in `flutter_readium/android/build.gradle`)
- Web: `@readium/*` npm packages (see `flutter_readium/package.json`)

## Commands

Run all scripts from the repo root unless noted.

| Command | Purpose |
|---------|---------|
| `bin/install` | Bootstrap: `pub get`, CocoaPods install, build web JS. Run after clone or dependency changes. |
| `bin/format` | Check Dart formatting across all three packages. Fails on any reformatting needed. |
| `bin/analyze` | `dart analyze --fatal-infos --fatal-warnings` across all packages. |
| `bin/update_web_example` | Build TS → JS and copy into `example/web/`. Run after editing TypeScript. |
| `bin/forAll <cmd>` | Run a command in both pub packages. |
| `bin/prepare-release <version>` | Bump versions, move Unreleased changelog entries, leave fresh Unreleased header. |

**Run before any PR:** `bin/format && bin/analyze`

### Tests

```bash
# Unit tests (platform interface)
cd flutter_readium_platform_interface && flutter test

# Unit tests (plugin)
cd flutter_readium && flutter test

# Single test file
cd flutter_readium && flutter test test/some_test.dart

# Integration tests (requires booted simulator/emulator)
cd flutter_readium/example
flutter test integration_test --device-id=<udid> # iOS
flutter test integration_test # Android
```

## Key Conventions

### Models & serialization

- Models use hand-written `toJson` / `fromJson` (via `JSONable` mixin). **Do not reintroduce `json_serializable` or `freezed` / build_runner codegen.**
- **Method channel serialization**: Readium-owned objects (`Locator`, `Decoration`, etc.) cross the bridge as **JSON strings** via `json.encode`. Plugin-owned flat structures use Maps/Dictionaries.

### Method channel contract

When adding a method-channel call, all three native sides (Swift, Kotlin, web) need a matching handler — or an explicit `UnimplementedError`. Undocumented silence looks like a bug.

### Singleton pattern

`FlutterReadium` is a singleton with one reader active at a time. Don't introduce per-instance state without reviewing the existing global publication lifecycle.

### PDF locators

PDF position lives in `Locator.locations.position` as a **1-based page number**. Don't invent plugin-side parallel models — use the upstream representation and round-trip via `goToLocator`.

### Changelog & commits

- Update `CHANGELOG.md` for every feature or bugfix. New entries go under `## Unreleased`.
- [Conventional Commits](https://www.conventionalcommits.org/) with scopes: `feat(android):`, `fix(ios):`, `chore(example):`, etc. Branch off `main`.

> Platform-specific conventions (Android log format, navigator null guard, TypeScript locator serialization) are in the scoped instruction files under `.github/instructions/`.

## MCP Servers

Two MCP servers are configured in `.mcp.json`:

**`dart`** — Dart tooling daemon. Prefer its tools over raw bash for Dart/Flutter work:
- `dart-run_tests` instead of `flutter test` in bash — structured pass/fail output, supports filtering by name
- `dart-analyze_files` instead of `dart analyze` — targeted per-file analysis
- `dart-dart_format` / `dart-dart_fix` — format or auto-fix specific files
- `dart-resolve_workspace_symbol` — find symbols by name (fuzzy) across all packages
- `dart-hover` — type info and docs at a cursor position
- `dart-pub` — `add`, `remove`, `get`, `upgrade` without leaving the tool interface

**`mnemosyne`** *(optional, user-wide)* — persistent memory layer backed by a local SQLite file. Both Copilot CLI (`store_memory`) and Claude Code (auto memory) have native memory, so mnemosyne's main value here is as a **shared cross-agent store** — facts either agent writes are visible to the other. Available user-wide in Claude Code via `claude mcp add --scope user`.

**`marionette`** — Flutter app remote control (requires a running example app). Use for all smoke testing:
- `marionette-connect` first (with the VM service URI from `flutter run` output, suffixed with `/ws`)
- `marionette-take_screenshots` — capture current visual state
- `marionette-get_interactive_elements` — discover tappable widgets and their keys
- `marionette-tap` / `marionette-enter_text` — interact with UI elements
- `marionette-get_logs` — read Flutter logs from the running app
- `marionette-hot_reload` / `marionette-hot_restart` — apply code changes without restarting

## Smoke Testing (marionette)

Run the example app in the background — `flutter run` never terminates:

```bash
# Start app (async, background)
flutter run # poll output for "A Dart VM Service ... is available at: <uri>"
# Connect marionette
marionette register <name> <uri>/ws
```

- Prefer `tap --key` / `tap --text` over coordinate taps (fragile).
- Add `ValueKey<String>` to interactive widgets in the example app for reliable marionette targeting.
- PDF content is invisible to marionette screenshots (native platform view). Use `xcrun simctl io booted screenshot /tmp/screen.png` for visual verification; check `marionette get-logs` for `onPageChanged` locator position.
28 changes: 28 additions & 0 deletions .github/instructions/context7.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
applyTo: '**'
---

# Context7 MCP — Readium & Flutter Documentation

Use the `context7` MCP server proactively when working with Readium toolkit APIs or Flutter/Dart framework APIs — **without waiting for the user to ask**. Your training data may be stale or miss recent API changes.

## Two-step workflow

1. `resolve-library-id` — map a library name to its Context7 ID.
2. `get-library-docs` — fetch relevant docs for that ID, scoped by a topic query.

## Library IDs (pre-resolved)

| Library | Context7 ID |
|---|---|
| Readium Swift Toolkit | `/readium/swift-toolkit` |
| Readium Kotlin Toolkit | `/readium/kotlin-toolkit` |
| Readium Web (TS) | `/readium/ts-toolkit` |
| Flutter | `/websites/flutter_dev` |
| Flutter API reference | `/websites/api_flutter_dev` |

Use `get-library-docs` with a focused `topic` query, e.g.:
- `"Locator navigation"` for locator / navigator APIs
- `"EPUB decorations"` for highlight/decoration APIs
- `"TTS ReadingProgression"` for TTS APIs
- `"Publication resource loading"` for resource/fetcher APIs
Loading