You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
4.7 KiB
168 lines
4.7 KiB
/**
|
|
* 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<string, unknown>,
|
|
): 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<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* 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<string, unknown>,
|
|
);
|
|
}
|
|
|
|
// ─── 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<boolean> {
|
|
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<string, unknown>);
|
|
}
|
|
|
|
// ─── 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<string, string>;
|
|
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<string, unknown>,
|
|
);
|
|
}
|
|
|
|
// ─── 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");
|
|
}
|