diff --git a/ts/components/conversation/ConversationView.tsx b/ts/components/conversation/ConversationView.tsx index 945fcddd19..06a2d18f1b 100644 --- a/ts/components/conversation/ConversationView.tsx +++ b/ts/components/conversation/ConversationView.tsx @@ -4,6 +4,8 @@ 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; @@ -23,6 +25,37 @@ export type PropsType = { 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, @@ -82,7 +115,7 @@ export function ConversationView({ if (allVisual) { const files: Array = []; for (let i = 0; i < items.length; i += 1) { - const file = items[i].getAsFile(); + const file = getAsFile(items[i]); if (file) { files.push(file); } @@ -100,7 +133,7 @@ export function ConversationView({ return; } - const firstAttachment = fileItems[0]?.getAsFile(); + const firstAttachment = fileItems[0] ? getAsFile(fileItems[0]) : null; if (firstAttachment) { processAttachments({ conversationId, diff --git a/ts/types/Attachment.ts b/ts/types/Attachment.ts index 3bec07d84e..fcf675a58e 100644 --- a/ts/types/Attachment.ts +++ b/ts/types/Attachment.ts @@ -37,6 +37,7 @@ import { getMessageQueueTime } from '../util/getMessageQueueTime'; import { getLocalAttachmentUrl } from '../util/getLocalAttachmentUrl'; import type { ReencryptionInfo } from '../AttachmentCrypto'; import { redactGenericText } from '../util/privacy'; +import { missingCaseError } from '../util/missingCaseError'; const MAX_WIDTH = 300; const MAX_HEIGHT = MAX_WIDTH * 1.5; @@ -1100,17 +1101,31 @@ export const getSuggestedFilename = ({ attachment, timestamp, index, + scenario = 'saving-locally', }: { - attachment: AttachmentType; + attachment: Pick; timestamp?: number | Date; index?: number; + scenario?: 'sending' | 'saving-locally'; }): string => { const { fileName } = attachment; if (fileName) { return fileName; } - const prefix = 'signal'; + let prefix: string; + switch (scenario) { + case 'sending': + // when sending, we prefer a generic 'signal-less' name + prefix = 'image'; + break; + case 'saving-locally': + prefix = 'signal'; + break; + default: + throw missingCaseError(scenario); + } + const suffix = timestamp ? moment(timestamp).format('-YYYY-MM-DD-HHmmss') : ''; @@ -1125,7 +1140,7 @@ export const getSuggestedFilename = ({ }; export const getFileExtension = ( - attachment: AttachmentType + attachment: Pick ): string | undefined => { if (!attachment.contentType) { return undefined;