// Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; import classNames from 'classnames'; import { useEscapeHandling } from '../../hooks/useEscapeHandling'; import { getSuggestedFilename } from '../../types/Attachment'; import { IMAGE_PNG, type MIMEType } from '../../types/MIME'; export type PropsType = { conversationId: string; hasOpenModal: boolean; hasOpenPanel: boolean; isSelectMode: boolean; onExitSelectMode: () => void; processAttachments: (options: { conversationId: string; files: ReadonlyArray; flags: number | null; }) => void; renderCompositionArea: (conversationId: string) => JSX.Element; renderConversationHeader: (conversationId: string) => JSX.Element; renderTimeline: (conversationId: string) => JSX.Element; renderPanel: (conversationId: string) => JSX.Element | undefined; shouldHideConversationView?: boolean; }; // https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/clipboard/data_object_item.cc;l=184;drc=1d545578bf3756af94e89f274544c6017267f885 const DEFAULT_CHROMIUM_IMAGE_FILENAME = 'image.png'; function getAsFile(item: DataTransferItem): File | null { const file = item.getAsFile(); if (!file) { return null; } if ( file.type === IMAGE_PNG && file.name === DEFAULT_CHROMIUM_IMAGE_FILENAME ) { return new File( [file.slice(0, file.size, file.type)], getSuggestedFilename({ attachment: { contentType: file.type as MIMEType, }, timestamp: Date.now(), scenario: 'sending', }), { type: file.type, lastModified: file.lastModified, } ); } return file; } export function ConversationView({ conversationId, hasOpenModal, hasOpenPanel, isSelectMode, onExitSelectMode, processAttachments, renderCompositionArea, renderConversationHeader, renderTimeline, renderPanel, shouldHideConversationView, }: PropsType): JSX.Element { const onDrop = React.useCallback( (event: React.DragEvent) => { event.stopPropagation(); event.preventDefault(); if (!event.dataTransfer) { return; } if (event.dataTransfer.types[0] !== 'Files') { return; } const { files } = event.dataTransfer; processAttachments({ conversationId, files: Array.from(files), flags: null, }); }, [conversationId, processAttachments] ); const onPaste = React.useCallback( (event: React.ClipboardEvent) => { if (hasOpenModal || hasOpenPanel) { return; } if (!event.clipboardData) { return; } const { items } = event.clipboardData; const fileItems = [...items].filter(item => item.kind === 'file'); if (fileItems.length === 0) { return; } const allVisual = fileItems.every(item => { const type = item.type.split('/')[0]; return type === 'image' || type === 'video'; }); if (allVisual) { const files: Array = []; for (let i = 0; i < items.length; i += 1) { const file = getAsFile(items[i]); if (file) { files.push(file); } } processAttachments({ conversationId, files, flags: null, }); event.stopPropagation(); event.preventDefault(); return; } const firstAttachment = fileItems[0] ? getAsFile(fileItems[0]) : null; if (firstAttachment) { processAttachments({ conversationId, files: [firstAttachment], flags: null, }); event.stopPropagation(); event.preventDefault(); } }, [conversationId, processAttachments, hasOpenModal, hasOpenPanel] ); useEscapeHandling( isSelectMode && !hasOpenModal ? onExitSelectMode : undefined ); return (
{renderConversationHeader(conversationId)}
{renderTimeline(conversationId)}
{renderCompositionArea(conversationId)}
{renderPanel(conversationId)}
); }