Skip to content

feat: EPUB image tap detection#159

Draft
ddfreiling wants to merge 8 commits into
Notalib:mainfrom
ddfreiling:feat/epub-image-tap
Draft

feat: EPUB image tap detection#159
ddfreiling wants to merge 8 commits into
Notalib:mainfrom
ddfreiling:feat/epub-image-tap

Conversation

@ddfreiling

Copy link
Copy Markdown
Member

Adds tap-to-open support for images inside EPUBs across all three platforms,
plus a resource-bytes API for lazy image loading.

Tapping an image now fires onImageTapped with an ImageTapEvent carrying the
publication-relative href, optional alt/caption, on-screen rect, natural
pixel dimensions, and (on Web) a direct srcUrl. The event fires for every
tapped image — deciding whether to act (e.g. may want to ignore taps inside a comic) is
the consumer's responsibility.

ddfreiling and others added 8 commits June 20, 2026 21:45
…ustrated fixture

Follow-ups to the EPUB image-tap feature:

- web: resolve the tapped element via the event's cssSelector instead of
  elementFromPoint(e.x, e.y). Upstream Peripherals multiplies tap coordinates
  by devicePixelRatio, so on HiDPI/Retina displays they overshot and no image
  was ever detected. elementFromPoint kept as a dpr-corrected fallback.
- android: implement getResourceBytes via publication.get(url).read(); only
  image-tap *detection* remains the documented Android gap.
- comics: image-tap is no longer gated plugin-side. onImageTapped fires for
  every tapped image; deciding whether to act on it (e.g. ignoring comic
  books) is the consumer's responsibility. Documented on ImageTapEvent.
- test: replace the moby_dick stand-in with peter_rabbit.epub (Project
  Gutenberg #14838, ~29 images) for the image-tap / getResourceBytes
  integration tests.
- rebuild web bundle (lib/helpers + example copy).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- FullScreenImageView: replace FutureBuilder with Image+imageProvider;
  ReadiumResourceImageProvider already handles caching and avoids
  re-fetching on every rebuild (drops no-op .then and Uint8List.fromList)
- ImageTapDetector: replace manual DOM walk with el.closest('img')
- FlutterEpubNavigator: extract shared handleImageTapEvent for tap/click
  (was identical copy-paste)
- FlutterReadiumPlugin: align getResourceBytes task priority to .high
  (was inconsistently .userInitiated vs .high everywhere else)
- example pubspec.lock: reflect v0.1.0 from main rebase

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…y escaping

- EPUBReaderView: use image.accessibilityLabel (HTML alt="") instead of
  image.caption (<figcaption>, always nil — TODO in swift-toolkit); caption
  and alt are semantically distinct fields
- ReadiumReaderChannel: Log.reader.warn (matches the logger API; .warning
  was a non-existent method)
- reader_image_interaction: ImageTapEvent.rect is now dart:ui Rect instead
  of Map<String, double>; callers use .left/.top/.width/.height
- ReadiumReaderWidget: fix viewTypeChannelName → VIEW_TYPE_CHANNEL_NAME
  (screaming snake case for const, and restore correct value
  dk.nota.flutter_readium/ReadiumReaderWidget — without-underscore typo
  introduced in the WIP commit broke Android platform view registration)
- ReadiumReaderWidget: wrap syncPolicy in JSONObject.quote() before JS
  injection to prevent breakage if the value contains quotes or backslashes
- FlutterReadiumPlugin: restore Task priority to .userInitiated (.high is
  an alias with identical raw value; .userInitiated is more descriptive for
  plugin work where the user is actively waiting)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement EPUB image-tap on Android via a @JavascriptInterface bridge
(EpubImageTapBridge) registered on each resource WebView and a capture-phase
click listener injected on page load. The bridge resolves the publication-
relative href by suffix-matching img.src against the manifest and emits
onImageTapped through ReadiumReaderChannel, matching the iOS/Web contract.

Add Jest coverage for the web hit-testing logic (tryBuildImageTapPayload):
frame resolution, cssSelector vs dpr-corrected elementFromPoint fallback,
the <img> ancestor walk, href derivation, and the null paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…upport

v0.1.0 is already tagged/published without these features, so the image-tap
and getResourceBytes entries belong under Unreleased, not the released 0.1.0
section. Also update the image-tap entry to reflect Android detection now
being implemented (was "iOS and Web, Android follow-up tracked").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add Unreleased entries for the ImageTapEvent model and getResourceBytes API.
Also correct the getResourceBytes doc comment, which wrongly claimed it was
unimplemented on Android — it is implemented on iOS, Android, and Web.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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