Better draft attachment management logic

This commit is contained in:
Fedor Indutny 2025-09-25 14:36:47 -07:00 committed by GitHub
commit 32f65e86a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 29 additions and 21 deletions

View file

@ -180,7 +180,10 @@ export type OwnProps = Readonly<{
quotedMessageAuthorAci: AciString | null; quotedMessageAuthorAci: AciString | null;
quotedMessageSentAt: number | null; quotedMessageSentAt: number | null;
removeAttachment: (conversationId: string, filePath: string) => unknown; removeAttachment: (
conversationId: string,
attachment: AttachmentDraftType
) => unknown;
scrollToMessage: (conversationId: string, messageId: string) => unknown; scrollToMessage: (conversationId: string, messageId: string) => unknown;
setComposerFocus: (conversationId: string) => unknown; setComposerFocus: (conversationId: string) => unknown;
setMessageToEdit(conversationId: string, messageId: string): unknown; setMessageToEdit(conversationId: string, messageId: string): unknown;
@ -1172,9 +1175,7 @@ export const CompositionArea = memo(function CompositionArea({
onClickAttachment={maybeEditAttachment} onClickAttachment={maybeEditAttachment}
onClose={() => onClearAttachments(conversationId)} onClose={() => onClearAttachments(conversationId)}
onCloseAttachment={attachment => { onCloseAttachment={attachment => {
if (attachment.path) { removeAttachment(conversationId, attachment);
removeAttachment(conversationId, attachment.path);
}
}} }}
/> />
</div> </div>

View file

@ -5,7 +5,6 @@ import path from 'node:path';
import lodash from 'lodash'; import lodash from 'lodash';
import type { ThunkAction, ThunkDispatch } from 'redux-thunk'; import type { ThunkAction, ThunkDispatch } from 'redux-thunk';
import { v4 as generateUuid } from 'uuid'; import { v4 as generateUuid } from 'uuid';
import { webUtils } from 'electron';
import type { ReadonlyDeep } from 'type-fest'; import type { ReadonlyDeep } from 'type-fest';
import type { import type {
@ -1036,7 +1035,10 @@ function processAttachments({
const nextDraftAttachments = ( const nextDraftAttachments = (
conversation.get('draftAttachments') || [] conversation.get('draftAttachments') || []
).slice(); ).slice();
const filesToProcess: Array<File> = []; const filesToProcess: Array<{
file: File;
pendingAttachment: AttachmentDraftType;
}> = [];
for (let i = 0; i < files.length; i += 1) { for (let i = 0; i < files.length; i += 1) {
const file = files[i]; const file = files[i];
const processingResult = preProcessAttachment(file, nextDraftAttachments); const processingResult = preProcessAttachment(file, nextDraftAttachments);
@ -1050,7 +1052,7 @@ function processAttachments({
getState, getState,
undefined undefined
); );
filesToProcess.push(file); filesToProcess.push({ file, pendingAttachment });
// we keep a running count of the draft attachments so we can show a // we keep a running count of the draft attachments so we can show a
// toast in case we add too many attachments at once // toast in case we add too many attachments at once
nextDraftAttachments.push(pendingAttachment); nextDraftAttachments.push(pendingAttachment);
@ -1062,14 +1064,14 @@ function processAttachments({
try { try {
await Promise.all( await Promise.all(
filesToProcess.map(async file => { filesToProcess.map(async ({ file, pendingAttachment }) => {
try { try {
const attachment = await processAttachment(file, { const attachment = await processAttachment(file, {
generateScreenshot: true, generateScreenshot: true,
flags, flags,
}); });
if (!attachment) { if (!attachment) {
removeAttachment(conversationId, webUtils.getPathForFile(file))( removeAttachment(conversationId, pendingAttachment)(
dispatch, dispatch,
getState, getState,
undefined undefined
@ -1086,7 +1088,7 @@ function processAttachments({
'handleAttachmentsProcessing: failed to process attachment:', 'handleAttachmentsProcessing: failed to process attachment:',
err.stack err.stack
); );
removeAttachment(conversationId, webUtils.getPathForFile(file))( removeAttachment(conversationId, pendingAttachment)(
dispatch, dispatch,
getState, getState,
undefined undefined
@ -1183,7 +1185,7 @@ function getPendingAttachment(file: File): AttachmentDraftType | undefined {
function removeAttachment( function removeAttachment(
conversationId: string, conversationId: string,
filePath: string draft: AttachmentDraftType
): ThunkAction<void, RootStateType, unknown, ReplaceAttachmentsActionType> { ): ThunkAction<void, RootStateType, unknown, ReplaceAttachmentsActionType> {
return async (dispatch, getState) => { return async (dispatch, getState) => {
const state = getState(); const state = getState();
@ -1193,16 +1195,21 @@ function removeAttachment(
conversationId conversationId
); );
const [targetAttachment] = attachments.filter( const targetAttachmentIndex = attachments.findIndex(attachment => {
attachment => attachment.path === filePath return (
); (attachment.clientUuid != null &&
if (!targetAttachment) { attachment.clientUuid === draft.clientUuid) ||
(attachment.path != null && attachment.path === draft.path)
);
});
if (targetAttachmentIndex === -1) {
return; return;
} }
const nextAttachments = attachments.filter( const targetAttachment = attachments[targetAttachmentIndex];
attachment => attachment.path !== filePath const nextAttachments = attachments
); .slice(0, targetAttachmentIndex)
.concat(attachments.slice(targetAttachmentIndex + 1));
const conversation = window.ConversationController.get(conversationId); const conversation = window.ConversationController.get(conversationId);
if (conversation) { if (conversation) {

View file

@ -99,14 +99,14 @@ export const SmartCompositionRecordingDraft = memo(
const handleCancel = useCallback(() => { const handleCancel = useCallback(() => {
unloadMessageAudio(); unloadMessageAudio();
if (selectedConversationId && voiceNoteAttachment.path) { if (selectedConversationId) {
removeAttachment(selectedConversationId, voiceNoteAttachment.path); removeAttachment(selectedConversationId, voiceNoteAttachment);
} }
}, [ }, [
removeAttachment, removeAttachment,
selectedConversationId, selectedConversationId,
unloadMessageAudio, unloadMessageAudio,
voiceNoteAttachment.path, voiceNoteAttachment,
]); ]);
const handleScrub = useCallback( const handleScrub = useCallback(