Commit Graph

24 Commits

Author SHA1 Message Date
Huang Xin 17749f7cc7 feat(send): mobile URL clipping via native-bridge plugin (#4252)
iOS and Android now run the same Web-URL clip flow as desktop. Paste
an article URL, the native side opens a full-screen WKWebView /
WebView with the same Chrome UA + fingerprint mask + "Saving to
Readest" overlay as the desktop hidden window, waits for load +
settle, captures `document.documentElement.outerHTML` via the
platform's `evaluateJavaScript`, and returns it through the existing
`convertToEpub` pipeline.

JS surface stays `invoke('clip_url', { url, options })` — no changes
in `library/page.tsx` or `send/page.tsx`. The platform branch lives
entirely in `clip_url.rs`.

Why not Tauri's `Window::add_child`

`add_child` is gated `#[cfg(any(test, all(desktop, feature =
"unstable")))]` in tauri 2.10. No public API for attaching a second
webview to the main window on mobile, so the clip flow can't be a
`#[cfg(mobile)]` branch of the existing `WebviewWindowBuilder` shape
— it needs native code. Extend `tauri-plugin-native-bridge` rather
than create a separate plugin: the Swift / Kotlin scaffolding +
Tauri IPC are already there.

Layout

- `src-tauri/src/clip_url.rs` — desktop branch unchanged; new
  `#[cfg(mobile)]` `clip_url` command routes through
  `app.native_bridge().clip_url(request)`. Shared `ClipOptions`
  struct exposes its fields `pub` so the mobile branch can map into
  the plugin's `ClipUrlRequest`.
- `plugins/tauri-plugin-native-bridge/src/models.rs` — `ClipUrlRequest`
  + `ClipUrlResponse` mirroring `ClipOptions` field-for-field so the
  payload travels untouched from JS through to Swift/Kotlin.
- `plugins/tauri-plugin-native-bridge/src/{desktop,mobile}.rs` — desktop
  returns an error (desktop has its own path); mobile dispatches via
  `run_mobile_plugin("clip_url", payload)`.
- `ios/Sources/ClipUrlController.swift` — `UIViewController` hosting
  `WKWebView` with the loading overlay drawn as native UIKit views
  (not an injected user script, so the page's own hydration can't
  wipe the spinner). 30 s hard timeout + 3 s settle window after
  `didFinish`, same as desktop. Fingerprint mask injected as
  `WKUserScript` at `.atDocumentStart`.
- `android/src/main/java/ClipUrlController.kt` — full-screen Dialog
  hosting a `WebView`, mirrors the iOS controller's behaviour. JSON-
  decodes the `evaluateJavascript` callback (raw return value is a
  JSON-encoded string).
- `NativeBridgePlugin.{swift,kt}` — new `clip_url` method that parses
  args via `invoke.parseArgs`, presents the controller, resolves the
  invoke with `{ html }` on success or `invoke.reject` on failure.
  Same rejection vocabulary as desktop (`"Invalid URL"`, `"Page took
  too long to load"`, etc.) so the calling JS doesn't need a
  platform branch.
- `build.rs` — adds `clip_url` to the plugin's `COMMANDS` array.

Notes

- The Swift overlay reserves the iOS safe-area-edge-to-edge so notch /
  Dynamic Island devices don't see the underlying app peek through
  during the brief capture window.
- The Android overlay's spinner tint follows the foreground theme
  colour at 85 % alpha — same idea as the iOS controller.
- `WKWebView`'s JS keeps running while the controller is presented;
  no off-screen / `isHidden` trick that would let iOS throttle the
  page mid-capture.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 16:00:53 +02:00
loveheaven 05da6bdf43 feat(dictionary): add system dictionary provider for macOS, iOS, and Android (#4219)
Hand selected words off to the platform's native dictionary surface
when the user opts into the new "System Dictionary" entry under
Settings → Languages → Dictionaries. The setting is exclusive: enabling
it disables all other providers (and vice versa) so the in-app lookup
button either always opens the popup or always invokes the OS — no
mixed states.

Per platform:
- macOS: AppKit's -[NSView showDefinitionForAttributedString:atPoint:]
  via a top-level Tauri command in src-tauri/src/macos/system_dictionary.rs.
  Anchored at the selection's bottom-center (CSS pixels mapped into
  NSView coords), so the inline Lookup HUD appears just below the
  highlighted text without raising Dictionary.app to the foreground.
- iOS: UIReferenceLibraryViewController presented as a half-detent
  pageSheet on iPhone (medium → large drag-to-expand) and as a
  formSheet on iPad. Implemented in the native-bridge plugin.
- Android: ACTION_PROCESS_TEXT intent with EXTRA_PROCESS_TEXT_READONLY,
  dispatched without createChooser so users get the standard system
  disambiguation dialog with "Just once / Always" buttons. Reports
  unavailable=true when no app handles the intent so the TS layer can
  silently skip rather than open an empty chooser.

Web/Linux/Windows hide the row entirely. The provider is a sentinel —
the registry filters it out of the popup tab list (it has no in-popup
UI) and the annotator's handleDictionary checks isSystemDictionaryEnabled
to dispatch directly to the native bridge before opening the in-app
DictionaryPopup.
2026-05-19 07:03:52 +02:00
Huang Xin 48920a87bf chore(opds): disable popular online opds catalogs in certain regions on App Store (#3031) 2026-01-22 11:42:16 +01:00
Huang Xin 5141be1c3f fix(iap): don't initialize billing on Android without google play service, closes #2630 (#2677) 2025-12-10 15:34:23 +01:00
Huang Xin 4e6f146b8f feat(android): support opening shared files from other apps, closes #2484 (#2628) 2025-12-05 18:13:06 +01:00
Huang Xin 8f22a5c570 feat: select directory to save last book cover image (#2521) 2025-11-23 17:00:49 +01:00
Huang Xin 6d5b16ea8b fix(iap): open external app for payment (#2465) 2025-11-18 12:07:43 +01:00
Huang Xin 78e61060d2 fix(tts): fixed listener of tts events (#2349) 2025-10-28 18:36:57 +01:00
Huang Xin 50d7f9a9dd feat(android): support custom data location on external sdcard (#2292) 2025-10-22 10:14:41 +02:00
Huang Xin ada427b134 feat(settings): add settings to adjust screen brightness when reading, closes #1532 (#2197) 2025-10-10 19:02:35 +02:00
Huang Xin 1d4541e353 feat: request manage external storage permission when changing data directory to sdcard root on Android (#2142) 2025-09-30 08:59:16 +02:00
Huang Xin 5ee860f1e8 refactor: use safe insets from native for Android, closes #1793 and closes #1886 (#1897) 2025-08-25 09:38:49 +02:00
Huang Xin f46be89036 fix: apply system color scheme for iOS in auto theme mode, closes #1762 (#1767) 2025-08-08 13:45:04 +02:00
Huang Xin f3e9983742 feat: add IAP in native bridge plugin for iOS (#1673) 2025-07-24 14:54:17 +02:00
Huang Xin 5e04f6ae03 feat: support locking screen orientation, closes #860 (#1034) 2025-05-05 10:55:50 +02:00
Huang Xin 4275508ccd feat: add volume keys for page turning, closes #471 (#982) 2025-04-28 12:36:24 +02:00
Huang Xin a424ae8b15 feat: retrieve system fonts on iOS and Android and show font weight variants, closes #949 and closes #557 (#976) 2025-04-26 17:37:04 +02:00
Huang Xin 172ab382bc fix: query status bar height on Android, closes #943 (#947) 2025-04-23 14:01:37 +02:00
Huang Xin cf66665096 feat: immersive UI in reader page on iOS and Android, closes #886 and closes #864 (#911) 2025-04-19 16:43:39 +02:00
Huang Xin 8efad90932 feat: in-app updater for Android (#885) 2025-04-14 14:21:58 +02:00
Huang Xin 4f0ef01a17 fix: tts now works in background in iOS, closes #547 (#822)
To enable background playback in Android, go to Settings > Apps & Notifications > Readest > Battery > Battery Optimization, and disable battery optimization for Readest.
2025-04-06 18:42:58 +02:00
Huang Xin 6131180a31 fix: initiate OAuth using Custom Tabs on Android, closes #361 (#788) 2025-04-01 17:04:17 +02:00
Huang Xin 7ccf3d0632 refactor: read local file with fs plugin for Tauri App, closes #553 and closes #489 (#785) 2025-04-01 14:26:26 +02:00
Huang Xin a72c8f2391 refactor: rename plugin safari-auth to native-bridge (#749)
* fix: layout tweaks for mobile

* refactor: rename plugin safari-auth to native-bridge
2025-03-29 07:27:18 +01:00