import { invoke, Channel } from '@tauri-apps/api/core'; export interface CopyURIRequest { uri: string; dst: string; } export interface CopyURIResponse { success: boolean; error?: string; } export interface SaveImageToGalleryRequest { srcPath: string; fileName: string; mimeType: string; albumName?: string; } export interface SaveImageToGalleryResponse { success: boolean; uri?: string; error?: string; } export interface UseBackgroundAudioRequest { enabled: boolean; } export interface InstallPackageRequest { path: string; } export interface InstallPackageResponse { success: boolean; error?: string; } export interface SetSystemUIVisibilityRequest { visible: boolean; darkMode: boolean; } export interface SetSystemUIVisibilityResponse { success: boolean; error?: string; } export interface GetStatusBarHeightResponse { height: number; error?: string; } export interface GetSystemFontsListResponse { fonts: Record; // { fontName: fontFamily } error?: string; } export interface InterceptKeysRequest { volumeKeys?: boolean; backKey?: boolean; /** Intercept media keys (next/previous/play-pause) for the hardware page turner. */ pageTurnerKeys?: boolean; /** Forward every key press to JS so the settings UI can capture a binding. */ learnMode?: boolean; } export interface LockScreenRequest { orientation: 'portrait' | 'landscape' | 'auto'; } export interface GetSystemColorSchemeResponse { colorScheme: 'light' | 'dark'; error?: string; } export interface GetSafeAreaInsetsResponse { top: number; right: number; bottom: number; left: number; error?: string; } interface GetScreenBrightnessResponse { brightness: number; // 0.0 to 1.0 error?: string; } interface SetScreenBrightnessRequest { brightness: number; // 0.0 to 1.0 } interface SetScreenBrightnessResponse { success: boolean; error?: string; } interface GetExternalSDCardPathResponse { path: string | null; error?: string; } interface SelectDirectoryResponse { cancelled?: boolean; uri?: string; path?: string; error?: string; } export interface GetStorefrontRegionCodeResponse { regionCode?: string; error?: string; } export interface RefreshEinkScreenResponse { success: boolean; error?: string; } export async function copyURIToPath(request: CopyURIRequest): Promise { const result = await invoke('plugin:native-bridge|copy_uri_to_path', { payload: request, }); return result; } export async function saveImageToGallery( request: SaveImageToGalleryRequest, ): Promise { return await invoke('plugin:native-bridge|save_image_to_gallery', { payload: request, }); } export async function invokeUseBackgroundAudio(request: UseBackgroundAudioRequest): Promise { await invoke('plugin:native-bridge|use_background_audio', { payload: request, }); } export async function installPackage( request: InstallPackageRequest, ): Promise { const result = await invoke('plugin:native-bridge|install_package', { payload: request, }); return result; } export async function setSystemUIVisibility( request: SetSystemUIVisibilityRequest, ): Promise { const result = await invoke( 'plugin:native-bridge|set_system_ui_visibility', { payload: request, }, ); return result; } export async function getStatusBarHeight(): Promise { const result = await invoke( 'plugin:native-bridge|get_status_bar_height', ); return result; } let cachedSysFontsResult: GetSystemFontsListResponse | null = null; export async function getSysFontsList(): Promise { if (cachedSysFontsResult) { return cachedSysFontsResult; } const result = await invoke( 'plugin:native-bridge|get_sys_fonts_list', ); cachedSysFontsResult = result; return result; } export async function interceptKeys(request: InterceptKeysRequest): Promise { await invoke('plugin:native-bridge|intercept_keys', { payload: request, }); } export async function lockScreenOrientation(request: LockScreenRequest): Promise { await invoke('plugin:native-bridge|lock_screen_orientation', { payload: request, }); } export async function getSystemColorScheme(): Promise { const result = await invoke( 'plugin:native-bridge|get_system_color_scheme', ); return result; } export async function getSafeAreaInsets(): Promise { const result = await invoke( 'plugin:native-bridge|get_safe_area_insets', ); return result; } export async function getScreenBrightness(): Promise { const result = await invoke( 'plugin:native-bridge|get_screen_brightness', ); return result; } export async function setScreenBrightness( request: SetScreenBrightnessRequest, ): Promise { const result = await invoke( 'plugin:native-bridge|set_screen_brightness', { payload: request, }, ); return result; } export async function getExternalSDCardPath(): Promise { const result = await invoke( 'plugin:native-bridge|get_external_sdcard_path', ); return result; } export async function selectDirectory(): Promise { const result = await invoke('plugin:native-bridge|select_directory'); return result; } export async function getStorefrontRegionCode(): Promise { const result = await invoke( 'plugin:native-bridge|get_storefront_region_code', ); return result; } /** * Trigger a deep e-ink full screen refresh (GC / GC16 waveform) to clear * ghosting. Android-only; the native side probes several vendor mechanisms * via reflection and returns `success: false` on devices with no e-ink * controller. Other platforms reject with an unsupported-platform error. */ export async function refreshEinkScreen(): Promise { return await invoke('plugin:native-bridge|refresh_eink_screen'); } /** Webview region to snapshot, in CSS pixels of the viewport (origin top-left). */ export interface CaptureWebviewRegionRequest { x: number; y: number; width: number; height: number; } /** * Capture a region of the running webview as compressed image bytes for * the mesh page-curl texture (#555): PNG on macOS, JPEG on iOS/Android * (phone-CPU PNG encoding took ~1.5s per turn). The snapshot is taken at * screen scale, capped at 2x CSS pixels on mobile. Rejects on platforms * without a native capture implementation (web, Windows/Linux so far) — * callers fall back to the CSS curl. */ export async function captureWebviewRegion( request: CaptureWebviewRegionRequest, ): Promise { return await invoke('plugin:native-bridge|capture_webview_region', { payload: request, }); } // ── Sync passphrase keychain ──────────────────────────────────────────── // Tauri-only. Wired into the TauriPassphraseStore (src/libs/crypto/ // passphrase.ts) so the user's sync passphrase persists across app // launches via the OS keychain (macOS Keychain, Windows Credential // Manager, Linux libsecret, iOS Keychain, Android EncryptedSharedPrefs). export interface SetSyncPassphraseRequest { passphrase: string; } export interface SyncPassphraseResponse { success: boolean; error?: string; } export interface GetSyncPassphraseResponse { passphrase?: string; error?: string; } export interface SyncKeychainAvailableResponse { available: boolean; error?: string; } export async function setSyncPassphrase( request: SetSyncPassphraseRequest, ): Promise { return invoke('plugin:native-bridge|set_sync_passphrase', { payload: request, }); } export async function getSyncPassphrase(): Promise { return invoke('plugin:native-bridge|get_sync_passphrase'); } export async function clearSyncPassphrase(): Promise { return invoke('plugin:native-bridge|clear_sync_passphrase'); } export async function isSyncKeychainAvailable(): Promise { return invoke('plugin:native-bridge|is_sync_keychain_available'); } // ── Keyed secure key-value store ───────────────────────────────────────── // Tauri-only. A generic, keyed secret store over the same OS keychain backends // as the sync passphrase above, so secrets that aren't the single sync // passphrase (the Google Drive OAuth token set, and any future cloud // provider's refresh token) get the same XSS-free cross-launch persistence // without each needing its own native command. Availability is the same probe // as `is_sync_keychain_available`. export interface SetSecureItemRequest { key: string; value: string; } export interface GetSecureItemRequest { key: string; } export interface SecureItemResponse { success: boolean; error?: string; } export interface GetSecureItemResponse { value?: string; error?: string; } export async function setSecureItem(request: SetSecureItemRequest): Promise { return invoke('plugin:native-bridge|set_secure_item', { payload: request }); } export async function getSecureItem(request: GetSecureItemRequest): Promise { return invoke('plugin:native-bridge|get_secure_item', { payload: request, }); } export async function clearSecureItem(request: GetSecureItemRequest): Promise { return invoke('plugin:native-bridge|clear_secure_item', { payload: request }); } // ── Reading widget ──────────────────────────────────────────────────────── export interface ReadingWidgetBookPayload { hash: string; title: string; author: string; percent: number; coverPath: string; } export interface ReadingWidgetTts { active: boolean; playing: boolean; } export interface UpdateReadingWidgetRequest { books: ReadingWidgetBookPayload[]; sectionTitle: string; emptyTitle: string; tts?: ReadingWidgetTts; } export async function updateReadingWidget(request: UpdateReadingWidgetRequest): Promise { await invoke('plugin:native-bridge|update_reading_widget', { payload: request }); } // ── Nightly updater (main-app commands, no native-bridge prefix) ───────── // `verify_update_signature` gates the custom install flows (portable / // AppImage / Android); `install_nightly_update` drives the Tauri updater for // the platform keys it natively installs (macOS / Windows-NSIS). export async function verifyUpdateSignature( path: string, signature: string, pubKey: string, ): Promise { return invoke('verify_update_signature', { path, signature, pubKey }); } export interface NightlyProgress { event: 'progress' | 'finished'; downloaded: number; contentLength: number; } export async function installNightlyUpdate( endpoint: string, onProgress?: (p: NightlyProgress) => void, ): Promise { const channel = new Channel(); if (onProgress) channel.onmessage = onProgress; await invoke('install_nightly_update', { endpoint, channel }); }