Composer: Support uploading folders (#1682)
This commit is contained in:
parent
80fb334d3d
commit
d2d70a1952
@ -254,7 +254,7 @@ const MiddleColumn: FC<StateProps> = ({
|
||||
}
|
||||
|
||||
const { items } = e.dataTransfer || {};
|
||||
const shouldDrawQuick = items && Array.from(items)
|
||||
const shouldDrawQuick = items && items.length > 0 && Array.from(items)
|
||||
// Filter unnecessary element for drag and drop images in Firefox (https://github.com/Ajaxy/telegram-tt/issues/49)
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#image
|
||||
.filter((item) => item.type !== 'text/uri-list')
|
||||
|
||||
@ -4,6 +4,7 @@ import React, {
|
||||
|
||||
import useShowTransition from '../../../hooks/useShowTransition';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import getFilesFromDataTransferItems from './helpers/getFilesFromDataTransferItems';
|
||||
|
||||
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
||||
import usePrevious from '../../../hooks/usePrevious';
|
||||
@ -38,13 +39,23 @@ const DropArea: FC<OwnProps> = ({
|
||||
|
||||
useEffect(() => (isOpen ? captureEscKeyListener(onHide) : undefined), [isOpen, onHide]);
|
||||
|
||||
const handleFilesDrop = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
const handleFilesDrop = useCallback(async (e: React.DragEvent<HTMLDivElement>) => {
|
||||
const { dataTransfer: dt } = e;
|
||||
let files: File[] = [];
|
||||
|
||||
if (dt.items && dt.items.length > 0) {
|
||||
const folderFiles = await getFilesFromDataTransferItems(dt.items);
|
||||
if (folderFiles.length) {
|
||||
files = files.concat(folderFiles);
|
||||
}
|
||||
}
|
||||
|
||||
if (dt.files && dt.files.length > 0) {
|
||||
onHide();
|
||||
onFileSelect(Array.from(dt.files), false);
|
||||
files = files.concat(Array.from(dt.files));
|
||||
}
|
||||
|
||||
onHide();
|
||||
onFileSelect(files, false);
|
||||
}, [onFileSelect, onHide]);
|
||||
|
||||
const handleQuickFilesDrop = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
export default async function getFilesFromDataTransferItems(dataTransferItems: DataTransferItemList) {
|
||||
const files: File[] = [];
|
||||
|
||||
function traverseFileTreePromise(entry: FileSystemEntry | File) {
|
||||
return new Promise(resolve => {
|
||||
if (entry instanceof File) {
|
||||
files.push(entry);
|
||||
resolve(entry);
|
||||
} else if (entry.isFile) {
|
||||
(entry as FileSystemFileEntry).file((file) => {
|
||||
files.push(file);
|
||||
resolve(file);
|
||||
});
|
||||
} else if (entry.isDirectory) {
|
||||
let dirReader = (entry as FileSystemDirectoryEntry).createReader();
|
||||
dirReader.readEntries((entries) => {
|
||||
let entriesPromises = [];
|
||||
for (let entr of entries) {
|
||||
entriesPromises.push(traverseFileTreePromise(entr));
|
||||
}
|
||||
resolve(Promise.all(entriesPromises));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let entriesPromises = [];
|
||||
for (let item of dataTransferItems) {
|
||||
if (item.kind === 'file') {
|
||||
const entry = item.webkitGetAsEntry() || item.getAsFile();
|
||||
if (entry) {
|
||||
entriesPromises.push(traverseFileTreePromise(entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(entriesPromises);
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import { ApiAttachment, ApiMessage } from '../../../../api/types';
|
||||
|
||||
import buildAttachment from '../helpers/buildAttachment';
|
||||
import { EDITABLE_INPUT_ID, EDITABLE_INPUT_MODAL_ID } from '../../../../config';
|
||||
import getFilesFromDataTransferItems from '../helpers/getFilesFromDataTransferItems';
|
||||
|
||||
const CLIPBOARD_ACCEPTED_TYPES = ['image/png', 'image/jpeg', 'image/gif'];
|
||||
const MAX_MESSAGE_LENGTH = 4096;
|
||||
@ -23,24 +24,25 @@ const useClipboardPaste = (
|
||||
return;
|
||||
}
|
||||
|
||||
const { items } = e.clipboardData;
|
||||
const media = Array.from(items)
|
||||
.find((item) => CLIPBOARD_ACCEPTED_TYPES.includes(item.type) && item.kind === 'file');
|
||||
const file = media && media.getAsFile();
|
||||
const pastedText = e.clipboardData.getData('text').substring(0, MAX_MESSAGE_LENGTH);
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
if (!file && !pastedText) {
|
||||
const { items } = e.clipboardData;
|
||||
let files: File[] = [];
|
||||
|
||||
if (items.length > 0) {
|
||||
files = await getFilesFromDataTransferItems(items);
|
||||
}
|
||||
const pastedText = e.clipboardData.getData('text').substring(0, MAX_MESSAGE_LENGTH);
|
||||
|
||||
if (files.length === 0 && !pastedText) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file && !editedMessage) {
|
||||
const attachment = await buildAttachment(file.name, file, true);
|
||||
setAttachments((attachments) => [
|
||||
...attachments,
|
||||
attachment,
|
||||
]);
|
||||
if (files.length > 0 && !editedMessage) {
|
||||
const newAttachments = await Promise.all(files.map((file) => {
|
||||
return buildAttachment(file.name, file, files.length === 1 && CLIPBOARD_ACCEPTED_TYPES.includes(file.type));
|
||||
}));
|
||||
setAttachments((attachments) => attachments.concat(newAttachments));
|
||||
}
|
||||
|
||||
if (pastedText) {
|
||||
|
||||
@ -482,7 +482,7 @@
|
||||
&.is-reply .media-inner,
|
||||
&.force-sender-name .Album,
|
||||
&.is-reply .Album,
|
||||
.message-title ~ .media-inner:not(.RoundVideo) {
|
||||
.message-title ~ .media-inner {
|
||||
margin-top: 0.375rem;
|
||||
margin-bottom: -0.375rem;
|
||||
|
||||
@ -491,6 +491,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.text) .RoundVideo {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
// Moved below .is-reply to overwrite its styles
|
||||
&.text .media-inner,
|
||||
&.text .Album {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user