forked from akai/readest
114 lines
3.8 KiB
TypeScript
114 lines
3.8 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { useEnv } from '@/context/EnvContext';
|
|
import { impactFeedback } from '@tauri-apps/plugin-haptics';
|
|
import { eventDispatcher } from '@/utils/event';
|
|
import { SelectedFile } from '@/hooks/useFileSelector';
|
|
import { isTauriAppPlatform } from '@/services/environment';
|
|
import { getCurrentWebview } from '@tauri-apps/api/webview';
|
|
import { useTranslation } from '@/hooks/useTranslation';
|
|
import { BOOK_ACCEPT_FORMATS } from '@/services/constants';
|
|
import { useSearchParams } from 'next/navigation';
|
|
|
|
export const useDragDropImport = () => {
|
|
const _ = useTranslation();
|
|
const searchParams = useSearchParams();
|
|
const group = searchParams?.get('group') || '';
|
|
|
|
const { appService } = useEnv();
|
|
const [isDragging, setIsDragging] = useState(false);
|
|
|
|
const handleDroppedFiles = async (files: File[] | string[]) => {
|
|
if (files.length === 0) return;
|
|
const supportedFiles = files.filter((file) => {
|
|
let fileExt;
|
|
if (typeof file === 'string') {
|
|
fileExt = file.split('.').pop()?.toLowerCase();
|
|
} else {
|
|
fileExt = file.name.split('.').pop()?.toLowerCase();
|
|
}
|
|
return BOOK_ACCEPT_FORMATS.includes(`.${fileExt}`);
|
|
});
|
|
if (supportedFiles.length === 0) {
|
|
eventDispatcher.dispatch('toast', {
|
|
message: _('No supported files found. Supported formats: {{formats}}', {
|
|
formats: BOOK_ACCEPT_FORMATS,
|
|
}),
|
|
type: 'error',
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (appService?.hasHaptics) {
|
|
impactFeedback('medium');
|
|
}
|
|
|
|
const selectedFiles = supportedFiles.map(
|
|
(file) =>
|
|
({
|
|
file: typeof file === 'string' ? undefined : file,
|
|
path: typeof file === 'string' ? file : undefined,
|
|
}) as SelectedFile,
|
|
);
|
|
eventDispatcher.dispatch('import-book-files', { files: selectedFiles, groupId: group });
|
|
};
|
|
|
|
const handleDragOver = (event: React.DragEvent<HTMLDivElement> | DragEvent) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
setIsDragging(true);
|
|
};
|
|
|
|
const handleDragLeave = (event: React.DragEvent<HTMLDivElement> | DragEvent) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
setIsDragging(false);
|
|
};
|
|
|
|
const handleDrop = async (event: React.DragEvent<HTMLDivElement> | DragEvent) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
setIsDragging(false);
|
|
|
|
if (event.dataTransfer?.files && event.dataTransfer.files.length > 0) {
|
|
const files = Array.from(event.dataTransfer.files);
|
|
handleDroppedFiles(files);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
const libraryPage = document.querySelector('.library-page');
|
|
if (!appService?.isMobile) {
|
|
libraryPage?.addEventListener('dragover', handleDragOver as unknown as EventListener);
|
|
libraryPage?.addEventListener('dragleave', handleDragLeave as unknown as EventListener);
|
|
libraryPage?.addEventListener('drop', handleDrop as unknown as EventListener);
|
|
}
|
|
|
|
if (isTauriAppPlatform()) {
|
|
const unlisten = getCurrentWebview().onDragDropEvent((event) => {
|
|
if (event.payload.type === 'over') {
|
|
setIsDragging(true);
|
|
} else if (event.payload.type === 'drop') {
|
|
setIsDragging(false);
|
|
handleDroppedFiles(event.payload.paths);
|
|
} else {
|
|
setIsDragging(false);
|
|
}
|
|
});
|
|
return () => {
|
|
unlisten.then((fn) => fn());
|
|
};
|
|
}
|
|
|
|
return () => {
|
|
if (!appService?.isMobile) {
|
|
libraryPage?.removeEventListener('dragover', handleDragOver as unknown as EventListener);
|
|
libraryPage?.removeEventListener('dragleave', handleDragLeave as unknown as EventListener);
|
|
libraryPage?.removeEventListener('drop', handleDrop as unknown as EventListener);
|
|
}
|
|
};
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [group]);
|
|
|
|
return { isDragging };
|
|
};
|