flutter_readium 0.1.0
flutter_readium: ^0.1.0 copied to clipboard
Flutter plugin for reading EPUB, audiobook, and WebPub publications. Wraps the Readium toolkits on iOS, Android, and Web.
Changelog #
All notable changes to flutter_readium are documented here.
Format follows Keep a Changelog.
Unreleased #
0.1.0 - 2026-06-20 #
Brings the Web platform up to feature parity with iOS / Android (audio, Media Overlay, TTS, Guided Navigation, decorations), plus a handful of supporting cross-platform additions.
Added #
- Web: Audio Navigator — audiobook publications now play on web.
audioEnable,play,pause,resume,stop,next,previous,audioSetPreferencesare all wired up via the upstreamAudioNavigator(ts-toolkit 2.4.0+). Playback state (offset, duration, locator) streams throughonTimebasedPlayerStateChanged, matching the iOS / Android contract. - Web: Media Overlay (Sync Narration) — EPUBs with embedded Sync Narration JSON
alternates (
application/vnd.readium.narration+json) can now play their synchronized narration.audioEnable()parses the narration, builds a synthetic audio reading order, and drivesAudioNavigator; audio time is mapped back to text locators soonTextLocatorChangedemits text-href locators as narration advances (matching iOS / AndroidreachedLocator). Enabling audio resumes from the visual reader's current position,goToLocatorand ToC / bookmark taps seek the audio to the matching narration item, andaudioSeekByis wired up viaAudioNavigator.jump(). - Web: TTS (text-to-speech) —
ttsEnable,ttsGetAvailableVoices,ttsSetVoice,ttsSetPreferencesare implemented on web using the browser'sSpeechSynthesisAPI and@readium/shared'sPublicationContentIterator+HTMLResourceContentIteratorfor paragraph-level text extraction. Playback state streams throughonTimebasedPlayerStateChangedand position bookmarks throughonTextLocatorChanged. Voice gender / quality is enriched via the bundledvoices.jsonfrom https://readium.org/speech/.play,pause,resume,stop,next,previousdispatch to the TTS engine when active, falling back toAudioNavigatorotherwise. - Web: Guided Navigation support — the web platform now detects EPUBs carrying
application/guided-navigation+json(publication-level link or reading-order alternate) and plays them through the Media Overlay pipeline, mirroring iOS / Android. When both Guided Navigation and Sync Narration are present, Guided Navigation takes precedence — matching native behaviour. Playback keeps the visual reader scrolled in sync. - Web: comic / FXL publication support — fixed-layout (Nota comic) publications now render on web.
- Web:
goToProgression— navigates to an absolute progression (0.0–1.0) on web. Supports EPUB (position-list lookup), audiobook (seek toprogression × duration), and Media Overlay content types. - Web:
audioSeekBy—audioSeekBy(Duration offset)is implemented for audiobook and Media Overlay playback viaAudioNavigator.jump(). - Web:
onErrorEventstream implemented — subscribing toFlutterReadium().onErrorEventon web no longer returns an empty stream. A broadcastStreamController<ReadiumError>now backs the stream;openPublicationfailures in the JS bundle are forwarded to Dart via anonErrorCallbackwindow setter. Pure audiobook paths register the same callback via_AudiobookCallbacks. - Web: ToC enrichment for media-overlay items — Sync Narration and Guided
Navigation items are enriched with
tocTitle/tocHrefderived from the publication's table of contents, matchingenrichOverlaysWithTocon iOS / Android. - Web:
onTextLocatorChangedlocators now carrytocHref— the EPUB navigator enriches each emitted locator with the current chapter's ToC href, matching the iOS / Android contract and unblocking chapter-skip features on the consumer side. - Web: TTS locators now carry
tocHref—Locator.locations.tocHrefis now populated on every locator emitted during TTS playback (utterance-start and word-boundary events), so chapter-aware features work during TTS on web — matching the existing behaviour for visual navigation and audiobook / media-overlay playback. - Web: reading-order item duration propagated to media-overlay items — the parent
reading-order link's declared
duration(when present) is carried on each item and used as the authoritative fallback for the synthetic audio Link's duration, replacing the cue-sum-only computation that underestimated total length when cues left gaps. - Web:
scrollPaddingLeft/scrollPaddingRightEPUB preferences — new fields in ts-toolkit 2.5.x are now passed through to the navigator. - Web: structured console logging — all web TS modules now log through a tagged
logger (
[Readium/<Module>] LEVEL: message) with runtime level control.setLogLevelnow propagates to the JS bundle so web logging verbosity is controlled from Dart alongside the native platforms. - Dart: tagged logging (
TaggedReadiumLog) — newReadiumLog.tag('Name')factory creates child loggers namedflutter_readium.<Name>, surfacing the source / area in log records (e.g.[INFO] flutter_readium.WebPlugin: ...). - PDF preferences: three new iOS-only fields —
offsetFirstPage: bool?,spread: PDFSpread?(new enum:auto/never/always), andvisibleScrollbar: bool?. These map to the matching properties on the iOSPDFNavigatorViewController.Preferences. AndroidPdfiumPreferencesdoes not expose these fields; they are silently ignored on Android and web. totalProgressionfor EPUB and audio navigators (web) — computed and surfaced for the progress slider on web.DecorationStyle.spotlight— new decoration style that dims everything outside the decorated range and (optionally) renders the tint inside it. Implemented across Dart API, iOS (box-shadow+ body dim), Android (box-shadow+ body dim), and web (body.flutter-readium-spotlightgates a body-wide dim; a per-group::highlight()restore rule keeps the spotlit range readable, and the caller-supplied tint colours the range's fill). Pass a non-transparent tint for "dim outside + tinted fill"; pass a transparent tint for "pure dim outside".DecorationStyle.ruler— new decoration style that renders a typoscope / reading mask: two full-viewport-width dim bands sit above and below the decorated range, leaving the range itself clear. Best suited to scrolled layouts. Implemented on the Dart API and on web (geometry-driven from the resolved range element, so it works in both the CSS Custom Highlight API path and the DOM-fallback path).ReaderDecorationStyle.isActive— newboolfield (defaultfalse) that renders the decoration in a visually distinct "active" state to mark the currently-focused annotation. Maps to the upstreamDecoration.Style.HighlightConfig.isActiveon iOS andDecoration.Style.Highlight/Underline.isActiveon Android; surfaces on web for the highlight / underline / spotlight paths.
Changed #
- Web: ts-toolkit version bump —
@readium/navigator^2.2.4→^2.5.5,@readium/navigator-html-injectables^2.2.1→^2.4.2,@readium/shared^2.1.1→^2.2.0. Picks up FXLpositionChangedreliability fix (navigator #218), vertical / RTL writing-mode support, Readium CSS v2.0.0, and content-protection infrastructure. - Web Decorator API —
applyDecorationsandsetDecorationStyleare now functional on web.applyDecorationsreplaces a group's decorations by sending a"clear"then an"add"per decoration via the upstream@readium/navigator-html-injectablesFrameComms"decorate"command. Thehighlight(filled box) andunderline(border-bottom) styles are both supported. - Web underline-style decorations —
DecorationStyle.underlinerenders as a border-bottom in the tint colour rather than a filled box, routed to a separate upstream group (<group>__underline) with an injected stylesheet +MutationObserverper iframe. The same distinction works in the CSS Custom Highlight API path (modern Chrome) via a paired sibling<style>whose::highlight()rule wins by cascade order. - Web: EPUB preferences mapping cleanup —
epubPreferences.tsnow mirrors the DartEPUBPreferencesshape (one preference per Dart field), with documented conversions:columnCountenum (auto/one/two) →number | null,imageFilterenum (darken/invert) →darkenFilter/invertFilter, andfontSizedivided by 100 to match the iOS plugin (Dart120→ web1.2). Dart fields the web navigator can't honor (publisherStyles,readingProgression,spread,typeScale,verticalText,language,blackAndWhiteComicMode,firstElementTopMargin) are dropped with inline rationale. - Web: content-protection, peripheral, and context-menu listener stubs — new required listener fields from ts-toolkit 2.3.0 are now present on both EPUB and WebPub navigator configurations.
- Docs: removed
EpubThemeType/themepreference — thethemefield referenced indocs/api-reference/preferences.mdanddocs/guides/preferences.mdwas never implemented; the docs now show how to achieve light / dark / sepia by settingbackgroundColorandtextColordirectly.
Fixed #
These are fixes to behaviour that shipped in 0.0.1 — chiefly iOS playback / locator
positioning, the existing web EPUB visual reader, and cross-platform serialization. (Bugs
introduced and resolved while building the new web audio / TTS / Media Overlay features are
not listed separately; their net effect is the Added entries above.)
- iOS: media-overlay books now resume at the saved in-chapter position — reopening a
sync-narration book restored the top of the chapter instead of where you left off (it only
snapped to the right place once playback started). swift-toolkit's reflowable navigator positions
via
fragments.firstand ignorescssSelector, where the media-overlay locator's DOM anchor was stored; the locator's DOM anchor is now promoted intofragments.firstfor the iOS visual navigator. Seedocs/parity/locator-field-priority.md. - iOS: TTS no longer snaps back to the previous page mid-sentence — when a spoken sentence
crossed a paginated page boundary, the reader correctly advanced to page N+1 for the word being
spoken but then flickered back to page N on each subsequent word. The cause was a double-assignment
to the
@Published playingUtteranceproperty (raw locator, then position mutation), which defeatedremoveDuplicates()and fired the page-sync on every word update instead of only on utterance changes. - iOS: early reader events are no longer dropped — the
text-locatorandreader-statusevent channels now buffer the most-recent event on the native side when Dart has not yet attached a listener. The buffer is flushed immediately whenonListenfires. - Web: improved error-handling —
ttsEnable,audioEnable, andttsGetAvailableVoicesfailures are now caught and.stackis now included inPlatformException.message. - Web:
setEPUBPreferencesno longer wipes existing preferences — the converter now emits only fields the Dart caller explicitly set, leaving prior preferences untouched on merge. Previously every unset field was sent asnull, which the navigator'smerging()does not skip (onlyundefined), so a partial update reset everything. - Web:
onTextLocatorChangedno longer floods consumers during scroll — text-locator events are trailing-edge debounced at 250 ms, matching the per-page cadence of the iOS / Android plugins (the ts-toolkit emits ~60 events/sec in scroll mode). - Web: EPUB navigation (
goTo,goForward,goBackward, ToC links) now works —ReadiumReader.goTosearchesreadingOrderbeforeresources(ToC chapter links point into reading order, so the previous resources-only lookup always failed), and the JS bridge now implements the progression-aware navigation methodsgoForward/goBackwardcall (previously errored withis not a function). - Web: nested ToC entries are no longer dropped —
flattenToctreated@readium/shared'sLinksas a plain array, silently discarding nested children; it now uses theLinksAPI. LocalizedStringtranslation-map parsing andProperties.toJsonpagekey serialization corrected (affects all platforms).- iOS:
applyDecorationsandsetEPUBPreferencesno longer hang when awaited — the EPUB reader view's native handlers now return a method-channel result on success (matching the PDF reader view); previously they never completed, so awaiting these methods could hang forever. - Web:
WebPubNavigatornow debouncesonTextLocatorChangedduring scroll — matches the existing EPUB debounce. The WebPub navigator was emitting position-changed events at rAF rate (~60 Hz), flooding the Dart-side text-locator stream with redundant updates. - Web: spotlight decoration now honours its tint and dims reliably on EPUB-profile
publications — the spotlight CSS no longer strips the caller-supplied tint (it
used to force
background-color: transparent !important, silently dropping any fill colour), and the body-wide dim selector is now specific enough to beat the ReadiumCSScustomColors_pref.cssuser-text-colour rule that previously won the cascade on EPUB-profile publications.
0.0.1 - 2026-06-01 #
Added #
- Core reader API —
FlutterReadiumsingleton providingopenPublication,closePublication,loadPublication,goToLocator,goToProgression,goForward,goBackward. - EPUB reader widget —
ReadiumReaderWidgetrenders EPUB and WebPub content via a native platform view (iOS/macOS/Android) or a WebView (web). - EPUB preferences —
EPUBPreferenceswith font family, font size, scroll mode, line height, word spacing, letter spacing, paragraph spacing, text alignment, column count, publisher styles, vertical writing, custom CSS properties and first-element margin. - TTS (text-to-speech) —
ttsEnable,ttsSetPreferences,ttsSetVoice,ttsGetAvailableVoiceswith voice metadata loaded from the Readium speech voice-data registry. TTS decoration styles are configurable viasetDecorationStyle. - Audio / MediaOverlay playback —
audioEnable,audioSetPreferences,audioSeekBy,play,pause,resume,stop,next,previousfor pre-recorded audio publications and MediaOverlay synchronized narration. - Decorations —
applyDecorationslets callers add highlights, underlines, and custom decoration styles to the visual reader. - Decoration styles —
DecorationStylehas two modes:highlight(filled rectangle behind text — default) andunderline(border-bottom in tint colour). Both are supported on iOS and Android. - Text selection callback —
ReadiumReaderWidget.onTextSelectedfires aTextSelectionEvent(locator + selected text) when the user selects text in the reader. - Selection actions —
ReadiumReaderWidget.selectionActionsconfigures native context menu items (up to 5 on iOS) shown on text selection. Tapping an action firesReadiumReaderWidget.onSelectionActionwith aSelectionActionEvent. - Decoration interaction —
ReadiumReaderWidget.onDecorationInteractionfires aDecorationInteractionEventwhen the user taps an existing decoration/highlight. Supported on iOS and Android. - Allowed default actions —
ReadiumReaderWidget.allowedDefaultActionscontrols which system-provided selection menu items (Copy, Share, Look Up, Translate, Select All) are shown. Passnullfor all defaults, or a specificSet<DefaultSelectionAction>to filter. iOS supportscopy,share,lookup,translate; Android supportscopy,share,selectAll. Unsupported values for a platform are silently ignored. - PDF reading —
ReadiumReaderWidgetopens PDF publications on iOS (PDFKit viaPDFNavigatorViewControllerfrom swift-toolkit) and Android (PDFium viaPdfiumNavigatorFragmentfrom kotlin-toolkit). PDF is not supported on Web. - PDF preferences —
FlutterReadium.setPDFPreferences(PDFPreferences)applies runtime display settings (layout,readingProgression,pageSpacing,fit) to the active PDF navigator.PDFLayoutunifies iOS'sscroll+scrollAxisand Android'sscrollAxisinto one cross-platform setting (paginated,scrollVertical,scrollHorizontal);PDFFitcontrols page fitting (auto,page,width). - PDF TOC enrichment —
onTextLocatorChangedevents for PDF publications includetitle(chapter name) andlocations.otherLocations["tocHref"]derived from#page=NTOC fragments, matching the existing EPUB enrichment behaviour. - Search —
searchInPublicationreturns a list ofTextSearchResultmatching a query string. - Navigation helpers —
skipToNextTOC/skipToPreviousTOCwalk the publication's table of contents;toPhysicalPageIndexandgoByLinknavigate by page-list entry or link. - Event streams —
onReaderStatusChanged,onTextLocatorChanged,onTimebasedPlayerStateChanged,onErrorEventexpose real-time reader state as Dart streams. - Platform support — iOS (swift-toolkit 3.7.0), macOS (same), Android (kotlin-toolkit 3.1.2), Web (TypeScript webpack bundle using @readium/navigator).
- Custom HTTP headers —
setCustomHeadersforwards headers to the native HTTP layer. - Log level control —
setLogLevelconfigures the plugin's internal logging verbosity. - Page information —
Locations.pageandLocations.totalPagesextension getters expose the current page and total page count (parsed from locator fragments) for publications that include a page list. - Progress slider support in the example app via a slider bound to
totalProgression.