fix(mobile): support file downloads and image previews

This commit is contained in:
Bohdan Triapitsyn
2026-08-13 23:44:36 +03:00
parent 0da89f3f88
commit 55fcd5092e
3 changed files with 48 additions and 53 deletions
+21 -1
View File
@@ -1,9 +1,13 @@
import { describe, expect, it, vi } from 'vitest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import type { RuntimeUrlQuery, RuntimeUrlResolver } from '@openchamber/ui/lib/runtime-url';
const runtimeFetchMock = vi.fn();
afterEach(() => {
vi.unstubAllGlobals();
});
vi.mock('@openchamber/ui/lib/runtime-fetch', () => ({
runtimeFetch: runtimeFetchMock,
}));
@@ -87,4 +91,20 @@ describe('createWebFilesAPI', () => {
headers: { 'x-opencode-directory': '/current-workspace' },
});
});
it('opens the native share sheet for downloads in the Capacitor app', async () => {
const { createWebFilesAPI } = await import('./files');
const api = createWebFilesAPI({ urls, getDirectory: () => '/workspace' });
const share = vi.fn().mockResolvedValue(undefined);
vi.stubGlobal('window', globalThis);
vi.stubGlobal('navigator', {});
Object.defineProperty(window, 'Capacitor', { configurable: true, value: { isNativePlatform: () => true } });
Object.defineProperty(navigator, 'canShare', { configurable: true, value: () => true });
Object.defineProperty(navigator, 'share', { configurable: true, value: share });
runtimeFetchMock.mockResolvedValueOnce(new Response('hello', { headers: { 'Content-Type': 'text/plain' } }));
await api.downloadFile?.('/workspace/hello.txt');
expect(share).toHaveBeenCalledWith({ files: [expect.objectContaining({ name: 'hello.txt', type: 'text/plain' })] });
});
});
+11 -1
View File
@@ -285,10 +285,20 @@ export const createWebFilesAPI = ({ getDirectory }: WebFilesAPIOptions): FilesAP
}
const blob = await response.blob();
const filename = target.split('/').pop() || 'file';
const capacitor = (window as typeof window & {
Capacitor?: { isNativePlatform?: () => boolean };
}).Capacitor;
const file = new File([blob], filename, { type: blob.type || 'application/octet-stream' });
if (capacitor?.isNativePlatform?.() === true && navigator.canShare?.({ files: [file] })) {
await navigator.share({ files: [file] });
return;
}
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = target.split('/').pop() || 'file';
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);