/** * WebView Utility Actions * * Helper module for sending utility actions to Flutter via HabibApp channel. * Actions: download_file, copy_to_clipboard, open_external_url, upload_file, buy_coin * * Docs: WEBVIEW_ACTION_DOWNLOAD.md */ // ─── Helpers ───────────────────────────────────────────── /** Check if running inside Flutter WebView (HabibApp channel available). */ export function isInFlutterWebView(): boolean { return typeof window !== "undefined" && !!window.HabibApp?.postMessage; } /** * Low-level: send a JSON message to Flutter via HabibApp.postMessage. * Returns `true` if the message was dispatched, `false` if channel unavailable. */ export function postActionToFlutter( action: string, data?: Record, ): boolean { if (!isInFlutterWebView()) return false; const message = data !== undefined ? { action, data } : { action }; window.HabibApp!.postMessage(JSON.stringify(message)); return true; } // ─── download_file ─────────────────────────────────────── export interface DownloadFileOptions { url: string; fileName?: string; title?: string; mimeType?: string; fileType?: "image" | "video" | "audio" | "document" | "archive" | "other"; size?: number; metadata?: Record; } /** * Ask Flutter to download a file natively. * * ```ts * downloadFile({ url: 'https://…/doc.pdf', fileName: 'doc.pdf', mimeType: 'application/pdf', fileType: 'document' }); * ``` */ export function downloadFile(options: DownloadFileOptions): boolean { return postActionToFlutter( "download_file", options as unknown as Record, ); } // ─── copy_to_clipboard ────────────────────────────────── export interface CopyToClipboardOptions { text: string; label?: string; showToast?: boolean; } /** * Copy text to the device clipboard via Flutter. * Falls back to `navigator.clipboard.writeText` if not in WebView. */ export async function copyToClipboard( text: string, label?: string, ): Promise { if (isInFlutterWebView()) { return postActionToFlutter("copy_to_clipboard", { text, label, showToast: true, }); } // Fallback for normal browser try { await navigator.clipboard.writeText(text); return true; } catch { return false; } } // ─── open_external_url ────────────────────────────────── export interface OpenExternalUrlOptions { url: string; mode?: "externalApplication" | "platformDefault"; title?: string; showErrorToast?: boolean; } /** * Ask Flutter to open a URL in the external browser / app. * * ```ts * openExternalUrl({ url: 'https://habibapp.com' }); * ``` */ export function openExternalUrl(options: OpenExternalUrlOptions): boolean { return postActionToFlutter("open_external_url", { mode: "externalApplication", showErrorToast: true, ...options, } as Record); } // ─── upload_file ───────────────────────────────────────── export interface UploadFileOptions { mediaType: "image" | "video" | "image+video" | "audio" | "file"; source?: "gallery" | "camera" | "any"; multiple?: boolean; returnAs?: "upload" | "base64"; uploadUrl?: string; fieldName?: string; uploadMethod?: string; headers?: Record; maxBytes?: number; allowedExtensions?: string[]; maxWidth?: number; maxHeight?: number; imageQuality?: number; title?: string; } /** * Ask Flutter to pick (and optionally upload) a file from the device. * * ```ts * uploadFile({ * mediaType: 'image', * source: 'gallery', * returnAs: 'upload', * uploadUrl: '/hussainya/dashboard/upload-media/', * maxBytes: 5_242_880, * }); * ``` */ export function uploadFile(options: UploadFileOptions): boolean { return postActionToFlutter( "upload_file", options as unknown as Record, ); } // ─── buy_coin ──────────────────────────────────────────── /** * Ask Flutter to open the Habib Coin packages list page (Add Coin). * * Used when a payment fails with "Not enough coins": the user tops up * natively, returns to the WebView and retries the payment. * * ```ts * buyHabibCoinPackages(); * ``` */ export function buyHabibCoinPackages(): boolean { return postActionToFlutter("buy_coin"); }