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:
@@ -7,9 +7,9 @@ import com.capacitorjs.plugins.statusbar.StatusBarPlugin;
|
|||||||
public class MainActivity extends BridgeActivity {
|
public class MainActivity extends BridgeActivity {
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
// Custom plugins must be registered before bridge initialization.
|
||||||
// Register custom and community plugins after initialization
|
|
||||||
registerPlugin(FileUploaderPlugin.class);
|
registerPlugin(FileUploaderPlugin.class);
|
||||||
registerPlugin(StatusBarPlugin.class);
|
registerPlugin(StatusBarPlugin.class);
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,6 +96,7 @@ describe('useFileUpload', () => {
|
|||||||
|
|
||||||
vi.mocked(Capacitor.getPlatform).mockReturnValue('web');
|
vi.mocked(Capacitor.getPlatform).mockReturnValue('web');
|
||||||
window.electronApi = undefined;
|
window.electronApi = undefined;
|
||||||
|
window.isElectron = false;
|
||||||
vi.spyOn(window, 'alert').mockImplementation(() => undefined);
|
vi.spyOn(window, 'alert').mockImplementation(() => undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -154,6 +155,31 @@ describe('useFileUpload', () => {
|
|||||||
expect(hook().isUploading).toBe(false);
|
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 () => {
|
it('shows web fallback alert and does not upload', async () => {
|
||||||
uploadModeRef.value = 'preferred';
|
uploadModeRef.value = 'preferred';
|
||||||
preferredProviderRef.value = 'catbox';
|
preferredProviderRef.value = 'catbox';
|
||||||
|
|||||||
@@ -9,9 +9,13 @@ import useMediaHostingStore from '../stores/use-media-hosting-store';
|
|||||||
|
|
||||||
const FILE_SELECTION_CANCELLED_ERROR = 'File selection cancelled';
|
const FILE_SELECTION_CANCELLED_ERROR = 'File selection cancelled';
|
||||||
|
|
||||||
|
function isElectronRuntime(): boolean {
|
||||||
|
return window.electronApi?.isElectron === true || window.isElectron === true;
|
||||||
|
}
|
||||||
|
|
||||||
function getRuntime(): 'web' | 'electron' | 'android' {
|
function getRuntime(): 'web' | 'electron' | 'android' {
|
||||||
if (Capacitor.getPlatform() === 'android') return 'android';
|
if (Capacitor.getPlatform() === 'android') return 'android';
|
||||||
if (window.electronApi?.isElectron) return 'electron';
|
if (isElectronRuntime()) return 'electron';
|
||||||
return 'web';
|
return 'web';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,36 +29,50 @@ function selectFileViaInput(): Promise<File | null> {
|
|||||||
input.type = 'file';
|
input.type = 'file';
|
||||||
input.accept = 'image/jpeg,image/png,video/mp4,video/webm';
|
input.accept = 'image/jpeg,image/png,video/mp4,video/webm';
|
||||||
input.style.display = 'none';
|
input.style.display = 'none';
|
||||||
|
let resolved = false;
|
||||||
|
let focusTimeoutId: number | null = null;
|
||||||
|
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
input.remove();
|
if (focusTimeoutId !== null) {
|
||||||
window.removeEventListener('focus', onFocus);
|
window.clearTimeout(focusTimeoutId);
|
||||||
};
|
focusTimeoutId = null;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
});
|
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);
|
document.body.appendChild(input);
|
||||||
input.click();
|
input.click();
|
||||||
});
|
});
|
||||||
@@ -87,7 +105,7 @@ export function useFileUpload(options: UseFileUploadOptions) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.electronApi?.isElectron) {
|
if (isElectronRuntime()) {
|
||||||
const file = await selectFileViaInput();
|
const file = await selectFileViaInput();
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw new Error(FILE_SELECTION_CANCELLED_ERROR);
|
throw new Error(FILE_SELECTION_CANCELLED_ERROR);
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import { Capacitor } from '@capacitor/core';
|
import { Capacitor } from '@capacitor/core';
|
||||||
import type { UploadMode } from './types';
|
import type { UploadMode } from './types';
|
||||||
|
|
||||||
|
function isElectronRuntime(): boolean {
|
||||||
|
return window.electronApi?.isElectron === true || window.isElectron === true;
|
||||||
|
}
|
||||||
|
|
||||||
/** Web runtime = web browser, not Electron */
|
/** Web runtime = web browser, not Electron */
|
||||||
export function isWebRuntime(): boolean {
|
export function isWebRuntime(): boolean {
|
||||||
return Capacitor.getPlatform() === 'web' && !window.electronApi?.isElectron;
|
return Capacitor.getPlatform() === 'web' && !isElectronRuntime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user