feat(native): files open in the system viewer instead of the share sheet

A PDF, image or document opened in the app went straight to the share sheet.
It now opens in Quick Look on iOS, to page through and zoom with its own share
button, and in the app that views its type on Android. An app without the
viewer (feature filePreview), or a type nothing on the device shows, gets the
share sheet as before.
This commit is contained in:
Maurice
2026-11-10 00:21:28 +01:00
parent 28079197e7
commit 2f03554a60
7 changed files with 188 additions and 10 deletions
+38 -1
View File
@@ -1,10 +1,14 @@
import { Directory, Filesystem } from '@capacitor/filesystem';
import { Share } from '@capacitor/share';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { cacheFileName, fileNameFromUrl, shareFile } from './nativeFiles';
import { hasNativeFeature } from './capabilities';
import { cacheFileName, fileNameFromUrl, openNativeFile, shareFile } from './nativeFiles';
import { TrekShell } from './trekShell';
vi.mock('@capacitor/filesystem', () => ({ Directory: { Cache: 'CACHE' }, Filesystem: { writeFile: vi.fn() } }));
vi.mock('@capacitor/share', () => ({ Share: { share: vi.fn() } }));
vi.mock('./capabilities', () => ({ hasNativeFeature: vi.fn() }));
vi.mock('./trekShell', () => ({ TrekShell: { previewFile: vi.fn() } }));
beforeEach(() => {
vi.mocked(Filesystem.writeFile).mockReset().mockResolvedValue({ uri: 'file:///cache/trip.pdf' });
@@ -51,3 +55,36 @@ describe('shareFile', () => {
await expect(shareFile(new Blob(['x']), 'x.txt')).rejects.toThrow('No activity found');
});
});
describe('openNativeFile', () => {
const pdf = () => new Blob(['%PDF'], { type: 'application/pdf' });
it('FE-NATIVE-FILES-OPEN-001: shows the file in the system viewer where the app has one, not in the share sheet', async () => {
vi.mocked(hasNativeFeature).mockReturnValue(true);
vi.mocked(TrekShell.previewFile).mockResolvedValue({ result: 'shown' });
await openNativeFile(pdf(), 'trip.pdf');
expect(TrekShell.previewFile).toHaveBeenCalledWith({
path: 'file:///cache/trip.pdf',
mimeType: 'application/pdf',
title: 'trip.pdf',
});
expect(Share.share).not.toHaveBeenCalled();
});
it('FE-NATIVE-FILES-OPEN-002: falls back to the share sheet for an older app, a type nothing shows, or a viewer that fails', async () => {
vi.mocked(hasNativeFeature).mockReturnValue(false);
await openNativeFile(pdf(), 'trip.pdf');
expect(TrekShell.previewFile).not.toHaveBeenCalled();
vi.mocked(hasNativeFeature).mockReturnValue(true);
vi.mocked(TrekShell.previewFile).mockResolvedValueOnce({ result: 'unsupported' });
await openNativeFile(pdf(), 'trip.pdf');
vi.mocked(TrekShell.previewFile).mockRejectedValueOnce(new Error('no window'));
await openNativeFile(pdf(), 'trip.pdf');
expect(Share.share).toHaveBeenCalledTimes(3);
expect(Share.share).toHaveBeenCalledWith({ files: ['file:///cache/trip.pdf'] });
});
});