Optimize render part 2
This commit is contained in:
parent
3f1adec614
commit
d41e61a96b
3 changed files with 307 additions and 182 deletions
55
ts/components/Profiler.tsx
Normal file
55
ts/components/Profiler.tsx
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import React, { ReactNode } from 'react';
|
||||||
|
|
||||||
|
type InternalPropsType = Readonly<{
|
||||||
|
id: string;
|
||||||
|
children: ReactNode;
|
||||||
|
|
||||||
|
onRender(
|
||||||
|
id: string,
|
||||||
|
phase: 'mount' | 'update',
|
||||||
|
actualDuration: number,
|
||||||
|
baseDuration: number,
|
||||||
|
startTime: number,
|
||||||
|
commitTime: number,
|
||||||
|
interactions: Set<unknown>
|
||||||
|
): void;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const Fallback: React.FC<InternalPropsType> = ({ children }) => {
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const BaseProfiler: React.FC<InternalPropsType> =
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
(React as any).unstable_Profiler || Fallback;
|
||||||
|
|
||||||
|
export type PropsType = Readonly<{
|
||||||
|
id: string;
|
||||||
|
children: ReactNode;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const onRender: InternalPropsType['onRender'] = (
|
||||||
|
id,
|
||||||
|
phase,
|
||||||
|
actual,
|
||||||
|
base,
|
||||||
|
start,
|
||||||
|
commit
|
||||||
|
) => {
|
||||||
|
window.log.info(
|
||||||
|
`Profiler.tsx(${id}): actual=${actual.toFixed(1)}ms phase=${phase} ` +
|
||||||
|
`base=${base.toFixed(1)}ms start=${start.toFixed(1)}ms ` +
|
||||||
|
`commit=${commit.toFixed(1)}ms`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Profiler: React.FC<PropsType> = ({ id, children }) => {
|
||||||
|
return (
|
||||||
|
<BaseProfiler id={id} onRender={onRender}>
|
||||||
|
{children}
|
||||||
|
</BaseProfiler>
|
||||||
|
);
|
||||||
|
};
|
|
@ -11,7 +11,7 @@ import {
|
||||||
pick,
|
pick,
|
||||||
reduce,
|
reduce,
|
||||||
} from 'lodash';
|
} from 'lodash';
|
||||||
import { createSelector, createSelectorCreator } from 'reselect';
|
import { createSelectorCreator } from 'reselect';
|
||||||
import filesize from 'filesize';
|
import filesize from 'filesize';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -102,108 +102,6 @@ export type GetPropsForBubbleOptions = Readonly<{
|
||||||
accountSelector: (identifier?: string) => boolean;
|
accountSelector: (identifier?: string) => boolean;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// Top-level prop generation for the message bubble
|
|
||||||
export function getPropsForBubble(
|
|
||||||
message: MessageAttributesType,
|
|
||||||
options: GetPropsForBubbleOptions
|
|
||||||
): TimelineItemType {
|
|
||||||
if (isUnsupportedMessage(message)) {
|
|
||||||
return {
|
|
||||||
type: 'unsupportedMessage',
|
|
||||||
data: getPropsForUnsupportedMessage(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isGroupV2Change(message)) {
|
|
||||||
return {
|
|
||||||
type: 'groupV2Change',
|
|
||||||
data: getPropsForGroupV2Change(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isGroupV1Migration(message)) {
|
|
||||||
return {
|
|
||||||
type: 'groupV1Migration',
|
|
||||||
data: getPropsForGroupV1Migration(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isMessageHistoryUnsynced(message)) {
|
|
||||||
return {
|
|
||||||
type: 'linkNotification',
|
|
||||||
data: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isExpirationTimerUpdate(message)) {
|
|
||||||
return {
|
|
||||||
type: 'timerNotification',
|
|
||||||
data: getPropsForTimerNotification(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isKeyChange(message)) {
|
|
||||||
return {
|
|
||||||
type: 'safetyNumberNotification',
|
|
||||||
data: getPropsForSafetyNumberNotification(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isVerifiedChange(message)) {
|
|
||||||
return {
|
|
||||||
type: 'verificationNotification',
|
|
||||||
data: getPropsForVerificationNotification(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isGroupUpdate(message)) {
|
|
||||||
return {
|
|
||||||
type: 'groupNotification',
|
|
||||||
data: getPropsForGroupNotification(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isEndSession(message)) {
|
|
||||||
return {
|
|
||||||
type: 'resetSessionNotification',
|
|
||||||
data: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isCallHistory(message)) {
|
|
||||||
return {
|
|
||||||
type: 'callHistory',
|
|
||||||
data: getPropsForCallHistory(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isProfileChange(message)) {
|
|
||||||
return {
|
|
||||||
type: 'profileChange',
|
|
||||||
data: getPropsForProfileChange(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isUniversalTimerNotification(message)) {
|
|
||||||
return {
|
|
||||||
type: 'universalTimerNotification',
|
|
||||||
data: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isChangeNumberNotification(message)) {
|
|
||||||
return {
|
|
||||||
type: 'changeNumberNotification',
|
|
||||||
data: getPropsForChangeNumberNotification(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isChatSessionRefreshed(message)) {
|
|
||||||
return {
|
|
||||||
type: 'chatSessionRefreshed',
|
|
||||||
data: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isDeliveryIssue(message)) {
|
|
||||||
return {
|
|
||||||
type: 'deliveryIssue',
|
|
||||||
data: getPropsForDeliveryIssue(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: 'message',
|
|
||||||
data: getPropsForMessage(message, options),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isIncoming(
|
export function isIncoming(
|
||||||
message: Pick<MessageAttributesType, 'type'>
|
message: Pick<MessageAttributesType, 'type'>
|
||||||
): boolean {
|
): boolean {
|
||||||
|
@ -483,6 +381,70 @@ export const getReactionsForMessage = createSelectorCreator(
|
||||||
(_: MessageAttributesType, reactions: PropsData['reactions']) => reactions
|
(_: MessageAttributesType, reactions: PropsData['reactions']) => reactions
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getPropsForQuote = createSelectorCreator(memoizeByRoot, isEqual)(
|
||||||
|
// `memoizeByRoot` requirement
|
||||||
|
identity,
|
||||||
|
|
||||||
|
(
|
||||||
|
message: Pick<MessageAttributesType, 'conversationId' | 'quote'>,
|
||||||
|
{
|
||||||
|
conversationSelector,
|
||||||
|
ourConversationId,
|
||||||
|
}: {
|
||||||
|
conversationSelector: GetConversationByIdType;
|
||||||
|
ourConversationId?: string;
|
||||||
|
}
|
||||||
|
): PropsData['quote'] => {
|
||||||
|
const { quote } = message;
|
||||||
|
if (!quote) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
author,
|
||||||
|
authorUuid,
|
||||||
|
id: sentAt,
|
||||||
|
isViewOnce,
|
||||||
|
referencedMessageNotFound,
|
||||||
|
text,
|
||||||
|
} = quote;
|
||||||
|
|
||||||
|
const contact = conversationSelector(authorUuid || author);
|
||||||
|
|
||||||
|
const authorId = contact.id;
|
||||||
|
const authorName = contact.name;
|
||||||
|
const authorPhoneNumber = contact.phoneNumber;
|
||||||
|
const authorProfileName = contact.profileName;
|
||||||
|
const authorTitle = contact.title;
|
||||||
|
const isFromMe = authorId === ourConversationId;
|
||||||
|
|
||||||
|
const firstAttachment = quote.attachments && quote.attachments[0];
|
||||||
|
const conversation = getConversation(message, conversationSelector);
|
||||||
|
|
||||||
|
return {
|
||||||
|
authorId,
|
||||||
|
authorName,
|
||||||
|
authorPhoneNumber,
|
||||||
|
authorProfileName,
|
||||||
|
authorTitle,
|
||||||
|
bodyRanges: processBodyRanges(quote, { conversationSelector }),
|
||||||
|
conversationColor:
|
||||||
|
conversation.conversationColor ?? ConversationColors[0],
|
||||||
|
customColor: conversation.customColor,
|
||||||
|
isFromMe,
|
||||||
|
rawAttachment: firstAttachment
|
||||||
|
? processQuoteAttachment(firstAttachment)
|
||||||
|
: undefined,
|
||||||
|
isViewOnce,
|
||||||
|
referencedMessageNotFound,
|
||||||
|
sentAt: Number(sentAt),
|
||||||
|
text: createNonBreakingLastSeparator(text),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
(_: unknown, quote: PropsData['quote']) => quote
|
||||||
|
);
|
||||||
|
|
||||||
export type GetPropsForMessageOptions = Pick<
|
export type GetPropsForMessageOptions = Pick<
|
||||||
GetPropsForBubbleOptions,
|
GetPropsForBubbleOptions,
|
||||||
| 'conversationSelector'
|
| 'conversationSelector'
|
||||||
|
@ -493,30 +455,51 @@ export type GetPropsForMessageOptions = Pick<
|
||||||
| 'accountSelector'
|
| 'accountSelector'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const getPropsForMessage = createSelector(
|
type ShallowPropsType = Pick<
|
||||||
(message: MessageAttributesType) => message,
|
PropsForMessage,
|
||||||
getAttachmentsForMessage,
|
| 'canDeleteForEveryone'
|
||||||
processBodyRanges,
|
| 'canDownload'
|
||||||
getAuthorForMessage,
|
| 'canReply'
|
||||||
getPreviewsForMessage,
|
| 'contact'
|
||||||
getReactionsForMessage,
|
| 'conversationColor'
|
||||||
(_: unknown, options: GetPropsForMessageOptions) => options,
|
| 'conversationId'
|
||||||
|
| 'conversationType'
|
||||||
|
| 'customColor'
|
||||||
|
| 'deletedForEveryone'
|
||||||
|
| 'direction'
|
||||||
|
| 'expirationLength'
|
||||||
|
| 'expirationTimestamp'
|
||||||
|
| 'id'
|
||||||
|
| 'isBlocked'
|
||||||
|
| 'isMessageRequestAccepted'
|
||||||
|
| 'isSelected'
|
||||||
|
| 'isSelectedCounter'
|
||||||
|
| 'isSticker'
|
||||||
|
| 'isTapToView'
|
||||||
|
| 'isTapToViewError'
|
||||||
|
| 'isTapToViewExpired'
|
||||||
|
| 'selectedReaction'
|
||||||
|
| 'status'
|
||||||
|
| 'text'
|
||||||
|
| 'textPending'
|
||||||
|
| 'timestamp'
|
||||||
|
>;
|
||||||
|
|
||||||
|
const getShallowPropsForMessage = createSelectorCreator(memoizeByRoot, isEqual)(
|
||||||
|
// `memoizeByRoot` requirement
|
||||||
|
identity,
|
||||||
|
|
||||||
(
|
(
|
||||||
message: MessageAttributesType,
|
message: MessageAttributesType,
|
||||||
attachments: Array<AttachmentType>,
|
|
||||||
bodyRanges: BodyRangesType | undefined,
|
|
||||||
author: PropsData['author'],
|
|
||||||
previews: Array<LinkPreviewType>,
|
|
||||||
reactions: PropsData['reactions'],
|
|
||||||
{
|
{
|
||||||
|
accountSelector,
|
||||||
conversationSelector,
|
conversationSelector,
|
||||||
ourConversationId,
|
ourConversationId,
|
||||||
|
regionCode,
|
||||||
selectedMessageId,
|
selectedMessageId,
|
||||||
selectedMessageCounter,
|
selectedMessageCounter,
|
||||||
regionCode,
|
|
||||||
accountSelector,
|
|
||||||
}: GetPropsForMessageOptions
|
}: GetPropsForMessageOptions
|
||||||
): Omit<PropsForMessage, 'renderingContext'> => {
|
): ShallowPropsType => {
|
||||||
const { expireTimer, expirationStartTimestamp } = message;
|
const { expireTimer, expirationStartTimestamp } = message;
|
||||||
const expirationLength = expireTimer ? expireTimer * 1000 : undefined;
|
const expirationLength = expireTimer ? expireTimer * 1000 : undefined;
|
||||||
const expirationTimestamp =
|
const expirationTimestamp =
|
||||||
|
@ -530,17 +513,14 @@ export const getPropsForMessage = createSelector(
|
||||||
|
|
||||||
const isMessageTapToView = isTapToView(message);
|
const isMessageTapToView = isTapToView(message);
|
||||||
|
|
||||||
|
const isSelected = message.id === selectedMessageId;
|
||||||
|
|
||||||
const selectedReaction = (
|
const selectedReaction = (
|
||||||
(message.reactions || []).find(re => re.fromId === ourConversationId) ||
|
(message.reactions || []).find(re => re.fromId === ourConversationId) ||
|
||||||
{}
|
{}
|
||||||
).emoji;
|
).emoji;
|
||||||
|
|
||||||
const isSelected = message.id === selectedMessageId;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
attachments,
|
|
||||||
author,
|
|
||||||
bodyRanges,
|
|
||||||
canDeleteForEveryone: canDeleteForEveryone(message),
|
canDeleteForEveryone: canDeleteForEveryone(message),
|
||||||
canDownload: canDownload(message, conversationSelector),
|
canDownload: canDownload(message, conversationSelector),
|
||||||
canReply: canReply(message, ourConversationId, conversationSelector),
|
canReply: canReply(message, ourConversationId, conversationSelector),
|
||||||
|
@ -564,18 +544,160 @@ export const getPropsForMessage = createSelector(
|
||||||
isTapToViewError:
|
isTapToViewError:
|
||||||
isMessageTapToView && isIncoming(message) && message.isTapToViewInvalid,
|
isMessageTapToView && isIncoming(message) && message.isTapToViewInvalid,
|
||||||
isTapToViewExpired: isMessageTapToView && message.isErased,
|
isTapToViewExpired: isMessageTapToView && message.isErased,
|
||||||
previews,
|
|
||||||
quote: getPropsForQuote(message, conversationSelector, ourConversationId),
|
|
||||||
reactions,
|
|
||||||
selectedReaction,
|
selectedReaction,
|
||||||
status: getMessagePropStatus(message, ourConversationId),
|
status: getMessagePropStatus(message, ourConversationId),
|
||||||
text: createNonBreakingLastSeparator(message.body),
|
text: createNonBreakingLastSeparator(message.body),
|
||||||
textPending: message.bodyPending,
|
textPending: message.bodyPending,
|
||||||
timestamp: message.sent_at,
|
timestamp: message.sent_at,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
(_: unknown, props: ShallowPropsType) => props
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getPropsForMessage = createSelectorCreator(memoizeByRoot)(
|
||||||
|
// `memoizeByRoot` requirement
|
||||||
|
identity,
|
||||||
|
|
||||||
|
getAttachmentsForMessage,
|
||||||
|
processBodyRanges,
|
||||||
|
getAuthorForMessage,
|
||||||
|
getPreviewsForMessage,
|
||||||
|
getReactionsForMessage,
|
||||||
|
getPropsForQuote,
|
||||||
|
getShallowPropsForMessage,
|
||||||
|
(
|
||||||
|
_: unknown,
|
||||||
|
attachments: Array<AttachmentType>,
|
||||||
|
bodyRanges: BodyRangesType | undefined,
|
||||||
|
author: PropsData['author'],
|
||||||
|
previews: Array<LinkPreviewType>,
|
||||||
|
reactions: PropsData['reactions'],
|
||||||
|
quote: PropsData['quote'],
|
||||||
|
shallowProps: ShallowPropsType
|
||||||
|
): Omit<PropsForMessage, 'renderingContext'> => {
|
||||||
|
return {
|
||||||
|
attachments,
|
||||||
|
author,
|
||||||
|
bodyRanges,
|
||||||
|
previews,
|
||||||
|
quote,
|
||||||
|
reactions,
|
||||||
|
...shallowProps,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getBubblePropsForMessage = createSelectorCreator(memoizeByRoot)(
|
||||||
|
// `memoizeByRoot` requirement
|
||||||
|
identity,
|
||||||
|
|
||||||
|
getPropsForMessage,
|
||||||
|
(_: unknown, data: ReturnType<typeof getPropsForMessage>) => ({
|
||||||
|
type: 'message' as const,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Top-level prop generation for the message bubble
|
||||||
|
export function getPropsForBubble(
|
||||||
|
message: MessageAttributesType,
|
||||||
|
options: GetPropsForBubbleOptions
|
||||||
|
): TimelineItemType {
|
||||||
|
if (isUnsupportedMessage(message)) {
|
||||||
|
return {
|
||||||
|
type: 'unsupportedMessage',
|
||||||
|
data: getPropsForUnsupportedMessage(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isGroupV2Change(message)) {
|
||||||
|
return {
|
||||||
|
type: 'groupV2Change',
|
||||||
|
data: getPropsForGroupV2Change(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isGroupV1Migration(message)) {
|
||||||
|
return {
|
||||||
|
type: 'groupV1Migration',
|
||||||
|
data: getPropsForGroupV1Migration(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isMessageHistoryUnsynced(message)) {
|
||||||
|
return {
|
||||||
|
type: 'linkNotification',
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isExpirationTimerUpdate(message)) {
|
||||||
|
return {
|
||||||
|
type: 'timerNotification',
|
||||||
|
data: getPropsForTimerNotification(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isKeyChange(message)) {
|
||||||
|
return {
|
||||||
|
type: 'safetyNumberNotification',
|
||||||
|
data: getPropsForSafetyNumberNotification(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isVerifiedChange(message)) {
|
||||||
|
return {
|
||||||
|
type: 'verificationNotification',
|
||||||
|
data: getPropsForVerificationNotification(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isGroupUpdate(message)) {
|
||||||
|
return {
|
||||||
|
type: 'groupNotification',
|
||||||
|
data: getPropsForGroupNotification(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isEndSession(message)) {
|
||||||
|
return {
|
||||||
|
type: 'resetSessionNotification',
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isCallHistory(message)) {
|
||||||
|
return {
|
||||||
|
type: 'callHistory',
|
||||||
|
data: getPropsForCallHistory(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isProfileChange(message)) {
|
||||||
|
return {
|
||||||
|
type: 'profileChange',
|
||||||
|
data: getPropsForProfileChange(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isUniversalTimerNotification(message)) {
|
||||||
|
return {
|
||||||
|
type: 'universalTimerNotification',
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isChangeNumberNotification(message)) {
|
||||||
|
return {
|
||||||
|
type: 'changeNumberNotification',
|
||||||
|
data: getPropsForChangeNumberNotification(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isChatSessionRefreshed(message)) {
|
||||||
|
return {
|
||||||
|
type: 'chatSessionRefreshed',
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isDeliveryIssue(message)) {
|
||||||
|
return {
|
||||||
|
type: 'deliveryIssue',
|
||||||
|
data: getPropsForDeliveryIssue(message, options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return getBubblePropsForMessage(message, options);
|
||||||
|
}
|
||||||
|
|
||||||
// Unsupported Message
|
// Unsupported Message
|
||||||
|
|
||||||
export function isUnsupportedMessage(message: MessageAttributesType): boolean {
|
export function isUnsupportedMessage(message: MessageAttributesType): boolean {
|
||||||
|
@ -1168,57 +1290,6 @@ export function getPropsForAttachment(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPropsForQuote(
|
|
||||||
message: Pick<MessageAttributesType, 'conversationId' | 'quote'>,
|
|
||||||
conversationSelector: GetConversationByIdType,
|
|
||||||
ourConversationId: string | undefined
|
|
||||||
): PropsData['quote'] {
|
|
||||||
const { quote } = message;
|
|
||||||
if (!quote) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
author,
|
|
||||||
authorUuid,
|
|
||||||
id: sentAt,
|
|
||||||
isViewOnce,
|
|
||||||
referencedMessageNotFound,
|
|
||||||
text,
|
|
||||||
} = quote;
|
|
||||||
|
|
||||||
const contact = conversationSelector(authorUuid || author);
|
|
||||||
|
|
||||||
const authorId = contact.id;
|
|
||||||
const authorName = contact.name;
|
|
||||||
const authorPhoneNumber = contact.phoneNumber;
|
|
||||||
const authorProfileName = contact.profileName;
|
|
||||||
const authorTitle = contact.title;
|
|
||||||
const isFromMe = authorId === ourConversationId;
|
|
||||||
|
|
||||||
const firstAttachment = quote.attachments && quote.attachments[0];
|
|
||||||
const conversation = getConversation(message, conversationSelector);
|
|
||||||
|
|
||||||
return {
|
|
||||||
authorId,
|
|
||||||
authorName,
|
|
||||||
authorPhoneNumber,
|
|
||||||
authorProfileName,
|
|
||||||
authorTitle,
|
|
||||||
bodyRanges: processBodyRanges(quote, { conversationSelector }),
|
|
||||||
conversationColor: conversation.conversationColor ?? ConversationColors[0],
|
|
||||||
customColor: conversation.customColor,
|
|
||||||
isFromMe,
|
|
||||||
rawAttachment: firstAttachment
|
|
||||||
? processQuoteAttachment(firstAttachment)
|
|
||||||
: undefined,
|
|
||||||
isViewOnce,
|
|
||||||
referencedMessageNotFound,
|
|
||||||
sentAt: Number(sentAt),
|
|
||||||
text: createNonBreakingLastSeparator(text),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function processQuoteAttachment(
|
function processQuoteAttachment(
|
||||||
attachment: AttachmentType
|
attachment: AttachmentType
|
||||||
): QuotedAttachmentType {
|
): QuotedAttachmentType {
|
||||||
|
|
|
@ -87,11 +87,10 @@ const mapStateToProps = (state: StateType, props: ExternalProps) => {
|
||||||
linkPreviewResult,
|
linkPreviewResult,
|
||||||
// Quote
|
// Quote
|
||||||
quotedMessageProps: quotedMessage
|
quotedMessageProps: quotedMessage
|
||||||
? getPropsForQuote(
|
? getPropsForQuote(quotedMessage, {
|
||||||
quotedMessage,
|
|
||||||
conversationSelector,
|
conversationSelector,
|
||||||
getUserConversationId(state)
|
ourConversationId: getUserConversationId(state),
|
||||||
)
|
})
|
||||||
: undefined,
|
: undefined,
|
||||||
onClickQuotedMessage: () =>
|
onClickQuotedMessage: () =>
|
||||||
onClickQuotedMessage(quotedMessage?.quote?.messageId),
|
onClickQuotedMessage(quotedMessage?.quote?.messageId),
|
||||||
|
|
Loading…
Reference in a new issue