05da6bdf43
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.
109 lines
3.2 KiB
Rust
109 lines
3.2 KiB
Rust
use std::sync::{Arc, Mutex};
|
|
use tauri::{
|
|
plugin::{Builder, TauriPlugin},
|
|
Manager, Runtime,
|
|
};
|
|
|
|
pub use models::*;
|
|
|
|
#[cfg(desktop)]
|
|
mod desktop;
|
|
#[cfg(mobile)]
|
|
mod mobile;
|
|
|
|
mod commands;
|
|
mod error;
|
|
mod models;
|
|
mod platform;
|
|
|
|
pub use error::{Error, Result};
|
|
|
|
use std::path::PathBuf;
|
|
use tauri::AppHandle;
|
|
|
|
#[cfg(desktop)]
|
|
use desktop::NativeBridge;
|
|
#[cfg(mobile)]
|
|
use mobile::NativeBridge;
|
|
|
|
/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the native-bridge APIs.
|
|
pub trait NativeBridgeExt<R: Runtime> {
|
|
fn native_bridge(&self) -> &NativeBridge<R>;
|
|
}
|
|
|
|
impl<R: Runtime, T: Manager<R>> crate::NativeBridgeExt<R> for T {
|
|
fn native_bridge(&self) -> &NativeBridge<R> {
|
|
self.state::<NativeBridge<R>>().inner()
|
|
}
|
|
}
|
|
|
|
type DirectoryCallback<R> = Box<dyn Fn(&AppHandle<R>, &PathBuf) + Send + Sync>;
|
|
|
|
pub struct DirectoryCallbackState<R: Runtime> {
|
|
pub callback: Arc<Mutex<Option<DirectoryCallback<R>>>>,
|
|
}
|
|
|
|
impl<R: Runtime> Default for DirectoryCallbackState<R> {
|
|
fn default() -> Self {
|
|
Self {
|
|
callback: Arc::new(Mutex::new(None)),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Initializes the plugin.
|
|
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|
Builder::new("native-bridge")
|
|
.invoke_handler(tauri::generate_handler![
|
|
commands::auth_with_safari,
|
|
commands::auth_with_custom_tab,
|
|
commands::copy_uri_to_path,
|
|
commands::use_background_audio,
|
|
commands::install_package,
|
|
commands::set_system_ui_visibility,
|
|
commands::get_status_bar_height,
|
|
commands::get_sys_fonts_list,
|
|
commands::intercept_keys,
|
|
commands::lock_screen_orientation,
|
|
commands::iap_is_available,
|
|
commands::iap_initialize,
|
|
commands::iap_fetch_products,
|
|
commands::iap_purchase_product,
|
|
commands::iap_restore_purchases,
|
|
commands::get_system_color_scheme,
|
|
commands::get_safe_area_insets,
|
|
commands::get_screen_brightness,
|
|
commands::set_screen_brightness,
|
|
commands::get_external_sdcard_path,
|
|
commands::open_external_url,
|
|
commands::show_lookup_popover,
|
|
commands::select_directory,
|
|
commands::get_storefront_region_code,
|
|
commands::request_manage_storage_permission,
|
|
commands::set_sync_passphrase,
|
|
commands::get_sync_passphrase,
|
|
commands::clear_sync_passphrase,
|
|
commands::is_sync_keychain_available,
|
|
])
|
|
.setup(|app, api| {
|
|
#[cfg(mobile)]
|
|
let native_bridge = mobile::init(app, api)?;
|
|
#[cfg(desktop)]
|
|
let native_bridge = desktop::init(app, api)?;
|
|
app.manage(native_bridge);
|
|
app.manage(DirectoryCallbackState::<R>::default());
|
|
Ok(())
|
|
})
|
|
.build()
|
|
}
|
|
|
|
pub fn register_select_directory_callback<R: Runtime>(
|
|
app: &AppHandle<R>,
|
|
callback: impl Fn(&AppHandle<R>, &PathBuf) + Send + Sync + 'static,
|
|
) {
|
|
if let Some(state) = app.try_state::<DirectoryCallbackState<R>>() {
|
|
let mut cb = state.callback.lock().unwrap();
|
|
*cb = Some(Box::new(callback));
|
|
}
|
|
}
|