69 lines
2.4 KiB
TypeScript
69 lines
2.4 KiB
TypeScript
// Bridge to the native ShareTargetPlugin (see
|
|
// android/app/src/main/java/chat/vojo/app/ShareTargetPlugin.java).
|
|
//
|
|
// On Android the native plugin captures ACTION_SEND / ACTION_SEND_MULTIPLE
|
|
// intents into the app cache. JS picks them up on boot via pickPendingShare()
|
|
// and reacts to warm shares via the `shareReceived` event.
|
|
//
|
|
// Web has no system share-sheet handoff, so the fallback is a no-op that
|
|
// always reports an empty slot.
|
|
|
|
import { Capacitor, registerPlugin, type PluginListenerHandle } from '@capacitor/core';
|
|
import { isAndroidPlatform } from '../utils/capacitor';
|
|
|
|
// Mirror of the JSObject the native plugin assembles.
|
|
export interface SharedFile {
|
|
name: string;
|
|
mimeType: string;
|
|
size: number;
|
|
// Absolute filesystem path inside the app cache. Wrap with
|
|
// Capacitor.convertFileSrc() before fetch().
|
|
path: string;
|
|
}
|
|
|
|
export type PendingShare =
|
|
| { empty: true }
|
|
| {
|
|
empty: false;
|
|
text?: string;
|
|
subject?: string;
|
|
items: SharedFile[];
|
|
};
|
|
|
|
interface ShareTargetPluginIface {
|
|
pickPendingShare(options?: { consume?: boolean }): Promise<PendingShare>;
|
|
addListener(eventName: 'shareReceived', listener: () => void): Promise<PluginListenerHandle>;
|
|
}
|
|
|
|
const plugin = registerPlugin<ShareTargetPluginIface>('ShareTarget', {
|
|
web: {
|
|
pickPendingShare: async () => ({ empty: true } as PendingShare),
|
|
addListener: async () => ({
|
|
remove: async () => undefined,
|
|
}),
|
|
},
|
|
});
|
|
|
|
export const shareTarget = {
|
|
async pickPendingShare(consume = true): Promise<PendingShare> {
|
|
if (!isAndroidPlatform()) return { empty: true };
|
|
try {
|
|
return await plugin.pickPendingShare({ consume });
|
|
} catch {
|
|
// Old APK installed before the plugin shipped — be silent and treat
|
|
// as "no pending share" so the rest of the app boots normally.
|
|
return { empty: true };
|
|
}
|
|
},
|
|
addShareReceivedListener(cb: () => void): Promise<PluginListenerHandle> {
|
|
if (!isAndroidPlatform()) {
|
|
return Promise.resolve({ remove: async () => undefined });
|
|
}
|
|
return plugin.addListener('shareReceived', cb);
|
|
},
|
|
};
|
|
|
|
// Convert the cached absolute path into a URL fetchable inside the WebView
|
|
// (Capacitor wraps it as https://localhost/_capacitor_file_/…). Exposed here
|
|
// so the consumer doesn't have to import @capacitor/core directly.
|
|
export const sharedFilePathToUrl = (path: string): string => Capacitor.convertFileSrc(path);
|