162 lines
4.8 KiB
TypeScript
162 lines
4.8 KiB
TypeScript
|
import useTransferDialog from "components/system/Dialogs/Transfer/useTransferDialog";
|
||
|
import {
|
||
|
getEventData,
|
||
|
handleFileInputEvent,
|
||
|
} from "components/system/Files/FileManager/functions";
|
||
|
import type { DragPosition } from "components/system/Files/FileManager/useDraggableEntries";
|
||
|
import type { CompleteAction } from "components/system/Files/FileManager/useFolder";
|
||
|
import { COMPLETE_ACTION } from "components/system/Files/FileManager/useFolder";
|
||
|
import { useFileSystem } from "contexts/fileSystem";
|
||
|
import { useProcesses } from "contexts/process";
|
||
|
import { useSession } from "contexts/session";
|
||
|
import { basename, extname, join, relative } from "path";
|
||
|
import { useCallback } from "react";
|
||
|
import { DESKTOP_PATH } from "utils/constants";
|
||
|
import { haltEvent, updateIconPositions } from "utils/functions";
|
||
|
|
||
|
export type FileDrop = {
|
||
|
onDragLeave?: (event: DragEvent | React.DragEvent<HTMLElement>) => void;
|
||
|
onDragOver: (event: DragEvent | React.DragEvent<HTMLElement>) => void;
|
||
|
onDrop: (event: DragEvent | React.DragEvent<HTMLElement>) => void;
|
||
|
};
|
||
|
|
||
|
type FileDropProps = {
|
||
|
callback?: (
|
||
|
path: string,
|
||
|
buffer?: Buffer,
|
||
|
completeAction?: CompleteAction
|
||
|
) => Promise<void>;
|
||
|
directory?: string;
|
||
|
id?: string;
|
||
|
onDragLeave?: (event: DragEvent | React.DragEvent<HTMLElement>) => void;
|
||
|
onDragOver?: (event: DragEvent | React.DragEvent<HTMLElement>) => void;
|
||
|
updatePositions?: boolean;
|
||
|
};
|
||
|
|
||
|
const useFileDrop = ({
|
||
|
callback,
|
||
|
directory = DESKTOP_PATH,
|
||
|
id,
|
||
|
onDragLeave,
|
||
|
onDragOver,
|
||
|
updatePositions,
|
||
|
}: FileDropProps): FileDrop => {
|
||
|
const { url } = useProcesses();
|
||
|
const { iconPositions, sortOrders, setIconPositions } = useSession();
|
||
|
const { mkdirRecursive, updateFolder, writeFile } = useFileSystem();
|
||
|
const updateProcessUrl = useCallback(
|
||
|
async (
|
||
|
filePath: string,
|
||
|
fileData?: Buffer,
|
||
|
completeAction?: CompleteAction
|
||
|
): Promise<void> => {
|
||
|
if (id) {
|
||
|
if (fileData) {
|
||
|
const tempPath = join(DESKTOP_PATH, filePath);
|
||
|
|
||
|
await mkdirRecursive(DESKTOP_PATH);
|
||
|
|
||
|
if (await writeFile(tempPath, fileData, true)) {
|
||
|
if (completeAction === COMPLETE_ACTION.UPDATE_URL) {
|
||
|
url(id, tempPath);
|
||
|
}
|
||
|
updateFolder(DESKTOP_PATH, filePath);
|
||
|
}
|
||
|
} else if (completeAction === COMPLETE_ACTION.UPDATE_URL) {
|
||
|
url(id, filePath);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
[id, mkdirRecursive, updateFolder, url, writeFile]
|
||
|
);
|
||
|
const { openTransferDialog } = useTransferDialog();
|
||
|
|
||
|
return {
|
||
|
onDragLeave,
|
||
|
onDragOver: (event) => {
|
||
|
onDragOver?.(event);
|
||
|
haltEvent(event);
|
||
|
},
|
||
|
onDrop: (event) => {
|
||
|
if (updatePositions && event.target instanceof HTMLElement) {
|
||
|
const { files, text } = getEventData(event as React.DragEvent);
|
||
|
|
||
|
if (files.length === 0 && text === "") return;
|
||
|
|
||
|
const dragPosition = {
|
||
|
x: event.clientX,
|
||
|
y: event.clientY,
|
||
|
} as DragPosition;
|
||
|
|
||
|
let fileEntries: string[] = [];
|
||
|
|
||
|
if (text) {
|
||
|
try {
|
||
|
fileEntries = JSON.parse(text) as string[];
|
||
|
} catch {
|
||
|
// Ignore failed JSON parsing
|
||
|
}
|
||
|
|
||
|
if (!Array.isArray(fileEntries)) return;
|
||
|
|
||
|
const [firstEntry] = fileEntries;
|
||
|
|
||
|
if (!firstEntry) return;
|
||
|
|
||
|
if (
|
||
|
firstEntry.startsWith(directory) &&
|
||
|
basename(firstEntry) === relative(directory, firstEntry)
|
||
|
) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
fileEntries = fileEntries.map((entry) => basename(entry));
|
||
|
} else if (files instanceof FileList) {
|
||
|
fileEntries = [...files].map((file) => file.name);
|
||
|
} else {
|
||
|
fileEntries = [...files]
|
||
|
.map((file) => file.getAsFile()?.name || "")
|
||
|
.filter(Boolean);
|
||
|
}
|
||
|
|
||
|
fileEntries = fileEntries.map((fileEntry) => {
|
||
|
if (!iconPositions[`${directory}/${fileEntry}`]) return fileEntry;
|
||
|
|
||
|
let iteration = 0;
|
||
|
let entryIteration = "";
|
||
|
|
||
|
do {
|
||
|
iteration += 1;
|
||
|
entryIteration = `${directory}/${basename(
|
||
|
fileEntry,
|
||
|
extname(fileEntry)
|
||
|
)} (${iteration})${extname(fileEntry)}`;
|
||
|
} while (iconPositions[entryIteration]);
|
||
|
|
||
|
return basename(entryIteration);
|
||
|
});
|
||
|
|
||
|
updateIconPositions(
|
||
|
directory,
|
||
|
event.target,
|
||
|
iconPositions,
|
||
|
sortOrders,
|
||
|
dragPosition,
|
||
|
fileEntries,
|
||
|
setIconPositions
|
||
|
);
|
||
|
}
|
||
|
|
||
|
handleFileInputEvent(
|
||
|
event as React.DragEvent,
|
||
|
callback || updateProcessUrl,
|
||
|
directory,
|
||
|
openTransferDialog,
|
||
|
Boolean(id)
|
||
|
);
|
||
|
},
|
||
|
};
|
||
|
};
|
||
|
|
||
|
export default useFileDrop;
|