From 2d221672d204f0b672f1f0d8cacbffed11a37084 Mon Sep 17 00:00:00 2001 From: Daniel Freiling Date: Wed, 16 Sep 2026 23:18:15 +0200 Subject: [PATCH 1/2] fix(ios): seed MO-active when a reader view registers `audioEnable` turns on media-overlay column-break prevention through `currentReaderView?.setMOActive(true)`. The call is optional-chained, so when no reader view is mounted yet the flag is simply dropped. A view that registers afterwards starts with `isMOActive == false` and its per-resource `injectColumnBreakCSS()` check never fires, so highlighted text can be split across CSS columns for the rest of the session. Seed the flag from the live navigator in `registerAsCurrentReaderView`. Android has no equivalent gap: there the flag lives on the singleton `ReadiumReader`, not on the widget, so a widget mounting later already sees it. Co-Authored-By: Claude Opus 5 --- flutter_readium/CHANGELOG.md | 6 ++++++ .../Sources/flutter_readium/FlutterReadiumPlugin.swift | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/flutter_readium/CHANGELOG.md b/flutter_readium/CHANGELOG.md index ad3b37e61..1752028b4 100644 --- a/flutter_readium/CHANGELOG.md +++ b/flutter_readium/CHANGELOG.md @@ -7,6 +7,12 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Fixed +- **iOS reader views mounted after `audioEnable` never applied the media-overlay + column-break CSS.** The MO-active flag lives on the reader view, so a view created + after audio was enabled started with it off and word highlighting could be split + across CSS columns for the rest of the session. The flag is now seeded from the live + navigator when a reader view registers, matching Android, where it lives on the + shared reader. - **Guided-navigation playback reported later reading-order positions on iOS and web.** Those platforms converted the matched reading-order index twice, so the second item was emitted as position 3. Locators now apply Readium's 1-based position convention exactly once. diff --git a/flutter_readium/ios/flutter_readium/Sources/flutter_readium/FlutterReadiumPlugin.swift b/flutter_readium/ios/flutter_readium/Sources/flutter_readium/FlutterReadiumPlugin.swift index 6ca8b1671..51e7a3c37 100644 --- a/flutter_readium/ios/flutter_readium/Sources/flutter_readium/FlutterReadiumPlugin.swift +++ b/flutter_readium/ios/flutter_readium/Sources/flutter_readium/FlutterReadiumPlugin.swift @@ -119,6 +119,12 @@ public class FlutterReadiumPlugin: NSObject, FlutterPlugin, ReadiumShared.Warnin internal func registerAsCurrentReaderView(_ readerView: any ReadiumReaderView) { let old = currentReaderView currentReaderView = readerView + // Seed MO-active from the live navigator: `audioEnable` sets it via the + // optional-chained `currentReaderView?`, so a view that mounts afterwards + // would never learn MO is running and would skip its column-break CSS for + // the rest of the session. Android has no such gap - the flag lives on the + // singleton `ReadiumReader`, not on the widget. + readerView.setMOActive(timebasedNavigator is FlutterMediaOverlayNavigator) _ = old // released here, safely outside the write } From a1d3b68da80343c9acb9929245b0e63355861b4a Mon Sep 17 00:00:00 2001 From: Daniel Freiling Date: Wed, 16 Sep 2026 23:31:35 +0200 Subject: [PATCH 2/2] style(ios): tighten the MO-active seeding comment Co-Authored-By: Claude Opus 5 --- .../Sources/flutter_readium/FlutterReadiumPlugin.swift | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/flutter_readium/ios/flutter_readium/Sources/flutter_readium/FlutterReadiumPlugin.swift b/flutter_readium/ios/flutter_readium/Sources/flutter_readium/FlutterReadiumPlugin.swift index 51e7a3c37..aed41d06e 100644 --- a/flutter_readium/ios/flutter_readium/Sources/flutter_readium/FlutterReadiumPlugin.swift +++ b/flutter_readium/ios/flutter_readium/Sources/flutter_readium/FlutterReadiumPlugin.swift @@ -119,11 +119,8 @@ public class FlutterReadiumPlugin: NSObject, FlutterPlugin, ReadiumShared.Warnin internal func registerAsCurrentReaderView(_ readerView: any ReadiumReaderView) { let old = currentReaderView currentReaderView = readerView - // Seed MO-active from the live navigator: `audioEnable` sets it via the - // optional-chained `currentReaderView?`, so a view that mounts afterwards - // would never learn MO is running and would skip its column-break CSS for - // the rest of the session. Android has no such gap - the flag lives on the - // singleton `ReadiumReader`, not on the widget. + // `audioEnable` sets MO-active through an optional-chained `currentReaderView?`, + // so a view registering later must pick the flag up from the navigator itself. readerView.setMOActive(timebasedNavigator is FlutterMediaOverlayNavigator) _ = old // released here, safely outside the write }