mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-23 15:36:33 +00:00
94674e7572
Sharing a tour fetched the GPX file first and only then called navigator.share, so the tap that asked had often run out by then. The retry path kept that file for one more tap only, and a tap while a sheet was still open made the browser throw InvalidStateError, which read as a failed share. The share button now fetches the file ahead where sharing is offered (not while the planner has unsaved changes), and every tap hands a fresh File built from the kept bytes to the sheet before anything is awaited. A file a tap had to fetch is kept for the next tap. A tap while a sheet is open is let be, and InvalidStateError and a closed sheet stay quiet; only a real failure still says the download is left.
41 lines
1.8 KiB
TypeScript
41 lines
1.8 KiB
TypeScript
/**
|
|
* Handing a file to the system's share sheet (the Web Share API), where the
|
|
* platform takes files of that kind. Chrome takes only an allow-list of file
|
|
* types, Safari and the phones most, so whether a share is offered is asked
|
|
* per file name and type, never assumed from `navigator.share` alone.
|
|
*/
|
|
|
|
/** Whether this browser would hand a file of this name and type to the share sheet. */
|
|
export function canShareFile(name: string, type: string): boolean {
|
|
if (typeof navigator === 'undefined' || typeof navigator.share !== 'function') return false;
|
|
if (typeof navigator.canShare !== 'function') return false;
|
|
try {
|
|
return navigator.canShare({ files: [new File([''], name, { type })] });
|
|
} catch {
|
|
// A browser that cannot even build the question cannot share the file either.
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* How a share ended: `cancelled` when the sheet was closed without a target,
|
|
* `needs-gesture` when the browser refused because the tap that asked lies too
|
|
* far back (Safari, after the file had to be fetched first), `busy` when an
|
|
* earlier sheet is still open (the browser's InvalidStateError), `failed`
|
|
* otherwise.
|
|
*/
|
|
export type FileShareOutcome = 'shared' | 'cancelled' | 'needs-gesture' | 'busy' | 'failed';
|
|
|
|
/** Opens the share sheet with the file; call it straight from the tap that asks for it. */
|
|
export async function shareFile(file: File, title: string): Promise<FileShareOutcome> {
|
|
try {
|
|
await navigator.share({ files: [file], title });
|
|
return 'shared';
|
|
} catch (error: unknown) {
|
|
if (error instanceof DOMException && error.name === 'AbortError') return 'cancelled';
|
|
if (error instanceof DOMException && error.name === 'NotAllowedError') return 'needs-gesture';
|
|
if (error instanceof DOMException && error.name === 'InvalidStateError') return 'busy';
|
|
return 'failed';
|
|
}
|
|
}
|