Fix forwarding attachments that haven't been downloaded

This commit is contained in:
Jamie Kyle 2023-06-16 11:41:52 -07:00 committed by GitHub
parent ac76271772
commit 0db5a3b888
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 155 additions and 85 deletions

View file

@ -36,9 +36,11 @@ import {
MESSAGE_CHANGED,
MESSAGE_DELETED,
MESSAGE_EXPIRED,
actions as conversationsActions,
} from './conversations';
import { SHOW_TOAST } from './toast';
import type { ShowToastActionType } from './toast';
import { isDownloaded } from '../../types/Attachment';
// State
@ -564,6 +566,14 @@ function toggleForwardMessagesModal(
);
}
const attachments = message.get('attachments') ?? [];
if (!attachments.every(isDownloaded)) {
dispatch(
conversationsActions.kickOffAttachmentDownload({ messageId })
);
}
const messagePropsSelector = getMessagePropsSelector(getState());
const messageProps = messagePropsSelector(message.attributes);
@ -832,6 +842,21 @@ export function confirmAuthorizeArtCreator(): ThunkAction<
};
}
function copyOverMessageAttributesIntoForwardMessages(
messagesProps: ReadonlyArray<ForwardMessagePropsType>,
attributes: ReadonlyDeep<MessageAttributesType>
): ReadonlyArray<ForwardMessagePropsType> {
return messagesProps.map(messageProps => {
if (messageProps.id !== attributes.id) {
return messageProps;
}
return {
...messageProps,
attachments: attributes.attachments,
};
});
}
// Reducer
export function getEmptyState(): GlobalModalsStateType {
@ -1099,57 +1124,77 @@ export function reducer(
};
}
if (
action.type === MESSAGE_CHANGED ||
action.type === MESSAGE_DELETED ||
action.type === MESSAGE_EXPIRED
) {
if (!state.editHistoryMessages) {
return state;
}
if (action.type === MESSAGE_DELETED || action.type === MESSAGE_EXPIRED) {
const hasMessageId = state.editHistoryMessages.some(
edit => edit.id === action.payload.id
);
if (!hasMessageId) {
return state;
}
return {
...state,
editHistoryMessages: undefined,
};
}
if (state.forwardMessagesProps != null) {
if (action.type === MESSAGE_CHANGED) {
if (!action.payload.data.editHistory) {
return state;
}
const hasMessageId = state.editHistoryMessages.some(
edit => edit.id === action.payload.id
);
if (!hasMessageId) {
return state;
}
const nextEditHistoryMessages = copyOverMessageAttributesIntoEditHistory(
action.payload.data
);
if (!nextEditHistoryMessages) {
if (
!state.forwardMessagesProps.messages.some(message => {
return message.id === action.payload.id;
})
) {
return state;
}
return {
...state,
editHistoryMessages: nextEditHistoryMessages,
forwardMessagesProps: {
...state.forwardMessagesProps,
messages: copyOverMessageAttributesIntoForwardMessages(
state.forwardMessagesProps.messages,
action.payload.data
),
},
};
}
}
if (state.editHistoryMessages != null) {
if (
action.type === MESSAGE_CHANGED ||
action.type === MESSAGE_DELETED ||
action.type === MESSAGE_EXPIRED
) {
if (action.type === MESSAGE_DELETED || action.type === MESSAGE_EXPIRED) {
const hasMessageId = state.editHistoryMessages.some(
edit => edit.id === action.payload.id
);
if (!hasMessageId) {
return state;
}
return {
...state,
editHistoryMessages: undefined,
};
}
if (action.type === MESSAGE_CHANGED) {
if (!action.payload.data.editHistory) {
return state;
}
const hasMessageId = state.editHistoryMessages.some(
edit => edit.id === action.payload.id
);
if (!hasMessageId) {
return state;
}
const nextEditHistoryMessages =
copyOverMessageAttributesIntoEditHistory(action.payload.data);
if (!nextEditHistoryMessages) {
return state;
}
return {
...state,
editHistoryMessages: nextEditHistoryMessages,
};
}
}
}
return state;
}

View file

@ -3,12 +3,16 @@
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import type { ForwardMessagesPropsType } from '../ducks/globalModals';
import type {
ForwardMessagePropsType,
ForwardMessagesPropsType,
} from '../ducks/globalModals';
import type { StateType } from '../reducer';
import * as log from '../../logging/log';
import { ForwardMessagesModal } from '../../components/ForwardMessagesModal';
import { LinkPreviewSourceType } from '../../types/LinkPreview';
import * as Errors from '../../types/errors';
import type { GetConversationByIdType } from '../selectors/conversations';
import {
getAllComposableConversations,
getConversationSelector,
@ -31,12 +35,53 @@ import { useLinkPreviewActions } from '../ducks/linkPreviews';
import { SmartCompositionTextArea } from './CompositionTextArea';
import { useToastActions } from '../ducks/toast';
import { hydrateRanges } from '../../types/BodyRange';
import { isDownloaded } from '../../types/Attachment';
function toMessageForwardDraft(
props: ForwardMessagePropsType,
getConversation: GetConversationByIdType
): MessageForwardDraft {
return {
attachments: props.attachments ?? [],
bodyRanges: hydrateRanges(props.bodyRanges, getConversation),
hasContact: Boolean(props.contact),
isSticker: Boolean(props.isSticker),
messageBody: props.text,
originalMessageId: props.id,
previews: props.previews ?? [],
};
}
export function SmartForwardMessagesModal(): JSX.Element | null {
const forwardMessagesProps = useSelector<
StateType,
ForwardMessagesPropsType | undefined
>(state => state.globalModals.forwardMessagesProps);
if (forwardMessagesProps == null) {
return null;
}
if (
!forwardMessagesProps.messages.every(message => {
return message.attachments?.every(isDownloaded) ?? true;
})
) {
return null;
}
return (
<SmartForwardMessagesModalInner
forwardMessagesProps={forwardMessagesProps}
/>
);
}
function SmartForwardMessagesModalInner({
forwardMessagesProps,
}: {
forwardMessagesProps: ForwardMessagesPropsType;
}): JSX.Element | null {
const candidateConversations = useSelector(getAllComposableConversations);
const getPreferredBadge = useSelector(getPreferredBadgeSelector);
const getConversation = useSelector(getConversationSelector);
@ -51,19 +96,9 @@ export function SmartForwardMessagesModal(): JSX.Element | null {
const [drafts, setDrafts] = useState<ReadonlyArray<MessageForwardDraft>>(
() => {
return (
forwardMessagesProps?.messages.map((props): MessageForwardDraft => {
return {
attachments: props.attachments ?? [],
bodyRanges: hydrateRanges(props.bodyRanges, getConversation),
hasContact: Boolean(props.contact),
isSticker: Boolean(props.isSticker),
messageBody: props.text,
originalMessageId: props.id,
previews: props.previews ?? [],
};
}) ?? []
);
return forwardMessagesProps.messages.map((props): MessageForwardDraft => {
return toMessageForwardDraft(props, getConversation);
});
}
);

View file

@ -3,7 +3,7 @@
import { orderBy } from 'lodash';
import type { AttachmentType } from '../types/Attachment';
import { isVoiceMessage } from '../types/Attachment';
import { isVoiceMessage, isDownloaded } from '../types/Attachment';
import type {
LinkPreviewType,
LinkPreviewWithHydratedData,
@ -57,41 +57,31 @@ export function isDraftEditable(draft: MessageForwardDraft): boolean {
return true;
}
export function isDraftForwardable(draft: MessageForwardDraft): boolean {
const messageLength = draft.messageBody?.length ?? 0;
if (messageLength > 0) {
return true;
function isDraftEmpty(draft: MessageForwardDraft) {
const { messageBody, attachments, isSticker, hasContact } = draft;
if (isSticker || hasContact) {
return false;
}
if (draft.isSticker) {
return true;
if (attachments != null && attachments.length > 0) {
return false;
}
if (draft.hasContact) {
return true;
if (messageBody != null && messageBody.length > 0) {
return false;
}
const attachmentsLength = draft.attachments?.length ?? 0;
if (attachmentsLength > 0) {
return true;
}
return false;
return true;
}
export function isMessageForwardable(message: MessageAttributesType): boolean {
const { body, attachments, sticker, contact } = message;
const messageLength = body?.length ?? 0;
if (messageLength > 0) {
return true;
export function isDraftForwardable(draft: MessageForwardDraft): boolean {
const { attachments } = draft;
if (isDraftEmpty(draft)) {
return false;
}
if (sticker) {
return true;
if (attachments != null && attachments.length > 0) {
if (!attachments.every(isDownloaded)) {
return false;
}
}
if (contact?.length) {
return true;
}
const attachmentsLength = attachments?.length ?? 0;
if (attachmentsLength > 0) {
return true;
}
return false;
return true;
}
export function sortByMessageOrder<T>(