mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix: resolve android plugin registration and electron upload runtime detection regressions
This commit is contained in:
@@ -96,6 +96,7 @@ describe('useFileUpload', () => {
|
||||
|
||||
vi.mocked(Capacitor.getPlatform).mockReturnValue('web');
|
||||
window.electronApi = undefined;
|
||||
window.isElectron = false;
|
||||
vi.spyOn(window, 'alert').mockImplementation(() => undefined);
|
||||
});
|
||||
|
||||
@@ -154,6 +155,31 @@ describe('useFileUpload', () => {
|
||||
expect(hook().isUploading).toBe(false);
|
||||
});
|
||||
|
||||
it('treats runtime as Electron when window.isElectron is true even if electronApi is unavailable', async () => {
|
||||
uploadModeRef.value = 'preferred';
|
||||
preferredProviderRef.value = 'catbox';
|
||||
vi.mocked(Capacitor.getPlatform).mockReturnValue('web');
|
||||
window.electronApi = undefined;
|
||||
window.isElectron = true;
|
||||
vi.mocked(orchestrateElectronUpload).mockResolvedValue('https://files.catbox.moe/electron-fallback.png');
|
||||
|
||||
const selectedFile = new File(['abc'], 'electron-fallback.png', { type: 'image/png' });
|
||||
const { onUploadComplete, hook } = mountHook();
|
||||
|
||||
let uploadPromise: Promise<void> | undefined;
|
||||
await act(async () => {
|
||||
uploadPromise = hook().handleUpload();
|
||||
});
|
||||
await selectFileFromHiddenInput(selectedFile);
|
||||
await act(async () => {
|
||||
await uploadPromise;
|
||||
});
|
||||
|
||||
expect(orchestrateElectronUpload).toHaveBeenCalledWith(selectedFile, ['catbox']);
|
||||
expect(window.alert).not.toHaveBeenCalledWith('upload_not_supported_web');
|
||||
expect(onUploadComplete).toHaveBeenCalledWith('https://files.catbox.moe/electron-fallback.png', 'electron-fallback.png');
|
||||
});
|
||||
|
||||
it('shows web fallback alert and does not upload', async () => {
|
||||
uploadModeRef.value = 'preferred';
|
||||
preferredProviderRef.value = 'catbox';
|
||||
|
||||
@@ -9,9 +9,13 @@ import useMediaHostingStore from '../stores/use-media-hosting-store';
|
||||
|
||||
const FILE_SELECTION_CANCELLED_ERROR = 'File selection cancelled';
|
||||
|
||||
function isElectronRuntime(): boolean {
|
||||
return window.electronApi?.isElectron === true || window.isElectron === true;
|
||||
}
|
||||
|
||||
function getRuntime(): 'web' | 'electron' | 'android' {
|
||||
if (Capacitor.getPlatform() === 'android') return 'android';
|
||||
if (window.electronApi?.isElectron) return 'electron';
|
||||
if (isElectronRuntime()) return 'electron';
|
||||
return 'web';
|
||||
}
|
||||
|
||||
@@ -25,36 +29,50 @@ function selectFileViaInput(): Promise<File | null> {
|
||||
input.type = 'file';
|
||||
input.accept = 'image/jpeg,image/png,video/mp4,video/webm';
|
||||
input.style.display = 'none';
|
||||
let resolved = false;
|
||||
let focusTimeoutId: number | null = null;
|
||||
|
||||
const cleanup = () => {
|
||||
input.remove();
|
||||
window.removeEventListener('focus', onFocus);
|
||||
};
|
||||
|
||||
const onFocus = () => {
|
||||
window.removeEventListener('focus', onFocus);
|
||||
setTimeout(() => {
|
||||
if (input.files && input.files.length > 0) {
|
||||
return;
|
||||
}
|
||||
cleanup();
|
||||
resolve(null);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
input.addEventListener('change', () => {
|
||||
window.removeEventListener('focus', onFocus);
|
||||
if (input.files && input.files.length > 0) {
|
||||
const file = input.files[0];
|
||||
cleanup();
|
||||
resolve(file);
|
||||
} else {
|
||||
cleanup();
|
||||
resolve(null);
|
||||
if (focusTimeoutId !== null) {
|
||||
window.clearTimeout(focusTimeoutId);
|
||||
focusTimeoutId = null;
|
||||
}
|
||||
});
|
||||
input.remove();
|
||||
window.removeEventListener('focus', onFocusFallback);
|
||||
input.removeEventListener('change', onChange);
|
||||
input.removeEventListener('cancel', onCancel);
|
||||
};
|
||||
|
||||
window.addEventListener('focus', onFocus);
|
||||
const finalize = (file: File | null) => {
|
||||
if (resolved) return;
|
||||
resolved = true;
|
||||
cleanup();
|
||||
resolve(file);
|
||||
};
|
||||
|
||||
const onChange = () => {
|
||||
const file = input.files && input.files.length > 0 ? input.files[0] : null;
|
||||
finalize(file);
|
||||
};
|
||||
|
||||
const onCancel = () => finalize(null);
|
||||
|
||||
// Fallback: some environments don't reliably emit `cancel`.
|
||||
const onFocusFallback = () => {
|
||||
if (resolved) return;
|
||||
if (focusTimeoutId !== null) {
|
||||
window.clearTimeout(focusTimeoutId);
|
||||
}
|
||||
focusTimeoutId = window.setTimeout(() => {
|
||||
if (resolved) return;
|
||||
const file = input.files && input.files.length > 0 ? input.files[0] : null;
|
||||
finalize(file);
|
||||
}, 800);
|
||||
};
|
||||
|
||||
input.addEventListener('change', onChange);
|
||||
input.addEventListener('cancel', onCancel);
|
||||
window.addEventListener('focus', onFocusFallback);
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
});
|
||||
@@ -87,7 +105,7 @@ export function useFileUpload(options: UseFileUploadOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.electronApi?.isElectron) {
|
||||
if (isElectronRuntime()) {
|
||||
const file = await selectFileViaInput();
|
||||
if (!file) {
|
||||
throw new Error(FILE_SELECTION_CANCELLED_ERROR);
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
import type { UploadMode } from './types';
|
||||
|
||||
function isElectronRuntime(): boolean {
|
||||
return window.electronApi?.isElectron === true || window.isElectron === true;
|
||||
}
|
||||
|
||||
/** Web runtime = web browser, not Electron */
|
||||
export function isWebRuntime(): boolean {
|
||||
return Capacitor.getPlatform() === 'web' && !window.electronApi?.isElectron;
|
||||
return Capacitor.getPlatform() === 'web' && !isElectronRuntime();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user