Remember message Read More state when scrolling in virtualized container

This commit is contained in:
Scott Nonnenberg 2021-11-11 15:45:47 -08:00 committed by GitHub
parent c5b5f2fe42
commit edab7c7d83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 159 additions and 72 deletions

View File

@ -144,6 +144,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
kickOffAttachmentDownload: action('kickOffAttachmentDownload'), kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'), markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
markViewed: action('markViewed'), markViewed: action('markViewed'),
messageExpanded: action('messageExpanded'),
onHeightChange: action('onHeightChange'), onHeightChange: action('onHeightChange'),
openConversation: action('openConversation'), openConversation: action('openConversation'),
openLink: action('openLink'), openLink: action('openLink'),

View File

@ -131,6 +131,7 @@ export type PropsData = {
conversationColor: ConversationColorType; conversationColor: ConversationColorType;
customColor?: CustomColorType; customColor?: CustomColorType;
conversationId: string; conversationId: string;
displayLimit?: number;
text?: string; text?: string;
textPending?: boolean; textPending?: boolean;
isSticker?: boolean; isSticker?: boolean;
@ -216,6 +217,7 @@ export type PropsActions = {
clearSelectedMessage: () => unknown; clearSelectedMessage: () => unknown;
doubleCheckMissingQuoteReference: (messageId: string) => unknown; doubleCheckMissingQuoteReference: (messageId: string) => unknown;
onHeightChange: () => unknown; onHeightChange: () => unknown;
messageExpanded: (id: string, displayLimit: number) => unknown;
checkForAccount: (identifier: string) => unknown; checkForAccount: (identifier: string) => unknown;
reactToMessage: ( reactToMessage: (
@ -1229,7 +1231,10 @@ export class Message extends React.PureComponent<Props, State> {
bodyRanges, bodyRanges,
deletedForEveryone, deletedForEveryone,
direction, direction,
displayLimit,
i18n, i18n,
id,
messageExpanded,
onHeightChange, onHeightChange,
openConversation, openConversation,
status, status,
@ -1263,7 +1268,10 @@ export class Message extends React.PureComponent<Props, State> {
bodyRanges={bodyRanges} bodyRanges={bodyRanges}
disableLinks={!this.areLinksEnabled()} disableLinks={!this.areLinksEnabled()}
direction={direction} direction={direction}
displayLimit={displayLimit}
i18n={i18n} i18n={i18n}
id={id}
messageExpanded={messageExpanded}
openConversation={openConversation} openConversation={openConversation}
onHeightChange={onHeightChange} onHeightChange={onHeightChange}
text={contents || ''} text={contents || ''}

View File

@ -19,7 +19,10 @@ const story = storiesOf('Components/Conversation/MessageBodyReadMore', module);
const createProps = (overrideProps: Partial<Props> = {}): Props => ({ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
bodyRanges: overrideProps.bodyRanges, bodyRanges: overrideProps.bodyRanges,
direction: 'incoming', direction: 'incoming',
displayLimit: overrideProps.displayLimit,
i18n, i18n,
id: 'some-id',
messageExpanded: action('messageExpanded'),
onHeightChange: action('onHeightChange'), onHeightChange: action('onHeightChange'),
text: text('text', overrideProps.text || ''), text: text('text', overrideProps.text || ''),
}); });

View File

@ -1,10 +1,11 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import React, { useState } from 'react'; import React, { useEffect } from 'react';
import type { Props as MessageBodyPropsType } from './MessageBody'; import type { Props as MessageBodyPropsType } from './MessageBody';
import { MessageBody } from './MessageBody'; import { MessageBody } from './MessageBody';
import { usePrevious } from '../../hooks/usePrevious';
export type Props = Pick< export type Props = Pick<
MessageBodyPropsType, MessageBodyPropsType,
@ -16,6 +17,9 @@ export type Props = Pick<
| 'bodyRanges' | 'bodyRanges'
| 'openConversation' | 'openConversation'
> & { > & {
id: string;
displayLimit?: number;
messageExpanded: (id: string, displayLimit: number) => unknown;
onHeightChange: () => unknown; onHeightChange: () => unknown;
}; };
@ -57,20 +61,29 @@ export function MessageBodyReadMore({
bodyRanges, bodyRanges,
direction, direction,
disableLinks, disableLinks,
displayLimit,
i18n, i18n,
id,
messageExpanded,
onHeightChange, onHeightChange,
openConversation, openConversation,
text, text,
textPending, textPending,
}: Props): JSX.Element { }: Props): JSX.Element {
const [maxLength, setMaxLength] = useState(INITIAL_LENGTH); const maxLength = displayLimit || INITIAL_LENGTH;
const previousMaxLength = usePrevious(maxLength, maxLength);
useEffect(() => {
if (previousMaxLength !== maxLength) {
onHeightChange();
}
}, [maxLength, previousMaxLength, onHeightChange]);
const { hasReadMore, text: slicedText } = graphemeAwareSlice(text, maxLength); const { hasReadMore, text: slicedText } = graphemeAwareSlice(text, maxLength);
const onIncreaseTextLength = hasReadMore const onIncreaseTextLength = hasReadMore
? () => { ? () => {
setMaxLength(oldMaxLength => oldMaxLength + INCREMENT_COUNT); messageExpanded(id, maxLength + INCREMENT_COUNT);
onHeightChange();
} }
: undefined; : undefined;

View File

@ -313,6 +313,7 @@ export class MessageDetail extends React.Component<Props> {
} }
disableMenu disableMenu
disableScroll disableScroll
displayLimit={Number.MAX_SAFE_INTEGER}
displayTapToViewMessage={displayTapToViewMessage} displayTapToViewMessage={displayTapToViewMessage}
downloadAttachment={() => downloadAttachment={() =>
log.warn('MessageDetail: deleteMessageForEveryone called!') log.warn('MessageDetail: deleteMessageForEveryone called!')
@ -323,6 +324,7 @@ export class MessageDetail extends React.Component<Props> {
kickOffAttachmentDownload={kickOffAttachmentDownload} kickOffAttachmentDownload={kickOffAttachmentDownload}
markAttachmentAsCorrupted={markAttachmentAsCorrupted} markAttachmentAsCorrupted={markAttachmentAsCorrupted}
markViewed={markViewed} markViewed={markViewed}
messageExpanded={noop}
onHeightChange={noop} onHeightChange={noop}
openConversation={openConversation} openConversation={openConversation}
openLink={openLink} openLink={openLink}

View File

@ -63,7 +63,8 @@ const defaultMessageProps: MessagesProps = {
kickOffAttachmentDownload: action('default--kickOffAttachmentDownload'), kickOffAttachmentDownload: action('default--kickOffAttachmentDownload'),
markAttachmentAsCorrupted: action('default--markAttachmentAsCorrupted'), markAttachmentAsCorrupted: action('default--markAttachmentAsCorrupted'),
markViewed: action('default--markViewed'), markViewed: action('default--markViewed'),
onHeightChange: action('onHeightChange'), messageExpanded: action('dafult--message-expanded'),
onHeightChange: action('default--onHeightChange'),
openConversation: action('default--openConversation'), openConversation: action('default--openConversation'),
openLink: action('default--openLink'), openLink: action('default--openLink'),
previews: [], previews: [],

View File

@ -327,6 +327,7 @@ const actions = () => ({
kickOffAttachmentDownload: action('kickOffAttachmentDownload'), kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'), markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
markViewed: action('markViewed'), markViewed: action('markViewed'),
messageExpanded: action('messageExpanded'),
showVisualAttachment: action('showVisualAttachment'), showVisualAttachment: action('showVisualAttachment'),
downloadAttachment: action('downloadAttachment'), downloadAttachment: action('downloadAttachment'),
displayTapToViewMessage: action('displayTapToViewMessage'), displayTapToViewMessage: action('displayTapToViewMessage'),

View File

@ -269,6 +269,7 @@ const getActions = createSelector(
'showContactModal', 'showContactModal',
'kickOffAttachmentDownload', 'kickOffAttachmentDownload',
'markAttachmentAsCorrupted', 'markAttachmentAsCorrupted',
'messageExpanded',
'showVisualAttachment', 'showVisualAttachment',
'downloadAttachment', 'downloadAttachment',
'displayTapToViewMessage', 'displayTapToViewMessage',

View File

@ -66,6 +66,7 @@ const getDefaultProps = () => ({
learnMoreAboutDeliveryIssue: action('learnMoreAboutDeliveryIssue'), learnMoreAboutDeliveryIssue: action('learnMoreAboutDeliveryIssue'),
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'), markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
markViewed: action('markViewed'), markViewed: action('markViewed'),
messageExpanded: action('messageExpanded'),
showMessageDetail: action('showMessageDetail'), showMessageDetail: action('showMessageDetail'),
openConversation: action('openConversation'), openConversation: action('openConversation'),
showContactDetail: action('showContactDetail'), showContactDetail: action('showContactDetail'),

View File

@ -87,6 +87,9 @@ export type InteractionModeType = typeof InteractionModes[number];
export type MessageType = MessageAttributesType & { export type MessageType = MessageAttributesType & {
interactionType?: InteractionModeType; interactionType?: InteractionModeType;
}; };
export type MessageWithUIFieldsType = MessageAttributesType & {
displayLimit?: number;
};
export const ConversationTypes = ['direct', 'group'] as const; export const ConversationTypes = ['direct', 'group'] as const;
export type ConversationTypeType = typeof ConversationTypes[number]; export type ConversationTypeType = typeof ConversationTypes[number];
@ -235,7 +238,7 @@ type MessageMetricsType = {
}; };
export type MessageLookupType = { export type MessageLookupType = {
[key: string]: MessageAttributesType; [key: string]: MessageWithUIFieldsType;
}; };
export type ConversationMessageType = { export type ConversationMessageType = {
heightChangeMessageIds: Array<string>; heightChangeMessageIds: Array<string>;
@ -523,6 +526,14 @@ export type MessageDeletedActionType = {
conversationId: string; conversationId: string;
}; };
}; };
export type MessageExpandedActionType = {
type: 'MESSAGE_EXPANDED';
payload: {
id: string;
displayLimit: number;
};
};
type MessageSizeChangedActionType = { type MessageSizeChangedActionType = {
type: 'MESSAGE_SIZE_CHANGED'; type: 'MESSAGE_SIZE_CHANGED';
payload: { payload: {
@ -738,6 +749,7 @@ export type ConversationActionType =
| MessageStoppedByMissingVerificationActionType | MessageStoppedByMissingVerificationActionType
| MessageChangedActionType | MessageChangedActionType
| MessageDeletedActionType | MessageDeletedActionType
| MessageExpandedActionType
| MessageSelectedActionType | MessageSelectedActionType
| MessageSizeChangedActionType | MessageSizeChangedActionType
| MessagesAddedActionType | MessagesAddedActionType
@ -801,6 +813,7 @@ export const actions = {
messageStoppedByMissingVerification, messageStoppedByMissingVerification,
messageChanged, messageChanged,
messageDeleted, messageDeleted,
messageExpanded,
messageSizeChanged, messageSizeChanged,
messagesAdded, messagesAdded,
messagesReset, messagesReset,
@ -1504,6 +1517,18 @@ function messageDeleted(
}, },
}; };
} }
function messageExpanded(
id: string,
displayLimit: number
): MessageExpandedActionType {
return {
type: 'MESSAGE_EXPANDED',
payload: {
id,
displayLimit,
},
};
}
function messageSizeChanged( function messageSizeChanged(
id: string, id: string,
conversationId: string conversationId: string
@ -2361,7 +2386,7 @@ export function reducer(
return state; return state;
} }
// ...and we've already loaded that message once // ...and we've already loaded that message once
const existingMessage = state.messagesLookup[id]; const existingMessage = getOwn(state.messagesLookup, id);
if (!existingMessage) { if (!existingMessage) {
return state; return state;
} }
@ -2379,7 +2404,10 @@ export function reducer(
...state, ...state,
messagesLookup: { messagesLookup: {
...state.messagesLookup, ...state.messagesLookup,
[id]: data, [id]: {
...data,
displayLimit: existingMessage.displayLimit,
},
}, },
messagesByConversation: { messagesByConversation: {
...state.messagesByConversation, ...state.messagesByConversation,
@ -2390,6 +2418,25 @@ export function reducer(
}, },
}; };
} }
if (action.type === 'MESSAGE_EXPANDED') {
const { id, displayLimit } = action.payload;
const existingMessage = state.messagesLookup[id];
if (!existingMessage) {
return state;
}
return {
...state,
messagesLookup: {
...state.messagesLookup,
[id]: {
...existingMessage,
displayLimit,
},
},
};
}
if (action.type === 'MESSAGE_SIZE_CHANGED') { if (action.type === 'MESSAGE_SIZE_CHANGED') {
const { id, conversationId } = action.payload; const { id, conversationId } = action.payload;

View File

@ -16,7 +16,6 @@ import filesize from 'filesize';
import type { import type {
LastMessageStatus, LastMessageStatus,
MessageAttributesType,
MessageReactionType, MessageReactionType,
ShallowChallengeError, ShallowChallengeError,
} from '../../model-types.d'; } from '../../model-types.d';
@ -58,7 +57,10 @@ import { isMoreRecentThan } from '../../util/timestamp';
import * as iterables from '../../util/iterables'; import * as iterables from '../../util/iterables';
import { strictAssert } from '../../util/assert'; import { strictAssert } from '../../util/assert';
import type { ConversationType } from '../ducks/conversations'; import type {
ConversationType,
MessageWithUIFieldsType,
} from '../ducks/conversations';
import type { AccountSelectorType } from './accounts'; import type { AccountSelectorType } from './accounts';
import type { CallSelectorType, CallStateType } from './calling'; import type { CallSelectorType, CallStateType } from './calling';
@ -114,25 +116,25 @@ export type GetPropsForBubbleOptions = Readonly<{
}>; }>;
export function isIncoming( export function isIncoming(
message: Pick<MessageAttributesType, 'type'> message: Pick<MessageWithUIFieldsType, 'type'>
): boolean { ): boolean {
return message.type === 'incoming'; return message.type === 'incoming';
} }
export function isOutgoing( export function isOutgoing(
message: Pick<MessageAttributesType, 'type'> message: Pick<MessageWithUIFieldsType, 'type'>
): boolean { ): boolean {
return message.type === 'outgoing'; return message.type === 'outgoing';
} }
export function hasErrors( export function hasErrors(
message: Pick<MessageAttributesType, 'errors'> message: Pick<MessageWithUIFieldsType, 'errors'>
): boolean { ): boolean {
return message.errors ? message.errors.length > 0 : false; return message.errors ? message.errors.length > 0 : false;
} }
export function getSource( export function getSource(
message: MessageAttributesType, message: MessageWithUIFieldsType,
ourNumber: string | undefined ourNumber: string | undefined
): string | undefined { ): string | undefined {
if (isIncoming(message)) { if (isIncoming(message)) {
@ -146,7 +148,7 @@ export function getSource(
} }
export function getSourceDevice( export function getSourceDevice(
message: MessageAttributesType, message: MessageWithUIFieldsType,
ourDeviceId: number ourDeviceId: number
): string | number | undefined { ): string | number | undefined {
const { sourceDevice } = message; const { sourceDevice } = message;
@ -164,7 +166,7 @@ export function getSourceDevice(
} }
export function getSourceUuid( export function getSourceUuid(
message: MessageAttributesType, message: MessageWithUIFieldsType,
ourUuid: string | undefined ourUuid: string | undefined
): string | undefined { ): string | undefined {
if (isIncoming(message)) { if (isIncoming(message)) {
@ -185,7 +187,7 @@ export type GetContactOptions = Pick<
>; >;
function getContactId( function getContactId(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ {
conversationSelector, conversationSelector,
ourConversationId, ourConversationId,
@ -206,7 +208,7 @@ function getContactId(
// TODO: DESKTOP-2145 // TODO: DESKTOP-2145
export function getContact( export function getContact(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ {
conversationSelector, conversationSelector,
ourConversationId, ourConversationId,
@ -225,7 +227,7 @@ export function getContact(
} }
export function getConversation( export function getConversation(
message: Pick<MessageAttributesType, 'conversationId'>, message: Pick<MessageWithUIFieldsType, 'conversationId'>,
conversationSelector: GetConversationByIdType conversationSelector: GetConversationByIdType
): ConversationType { ): ConversationType {
return conversationSelector(message.conversationId); return conversationSelector(message.conversationId);
@ -237,12 +239,12 @@ export const getAttachmentsForMessage = createSelectorCreator(memoizeByRoot)(
// `memoizeByRoot` requirement // `memoizeByRoot` requirement
identity, identity,
({ sticker }: MessageAttributesType) => sticker, ({ sticker }: MessageWithUIFieldsType) => sticker,
({ attachments }: MessageAttributesType) => attachments, ({ attachments }: MessageWithUIFieldsType) => attachments,
( (
_: MessageAttributesType, _: MessageWithUIFieldsType,
sticker: MessageAttributesType['sticker'], sticker: MessageWithUIFieldsType['sticker'],
attachments: MessageAttributesType['attachments'] = [] attachments: MessageWithUIFieldsType['attachments'] = []
): Array<AttachmentType> => { ): Array<AttachmentType> => {
if (sticker && sticker.data) { if (sticker && sticker.data) {
const { data } = sticker; const { data } = sticker;
@ -276,7 +278,7 @@ export const processBodyRanges = createSelectorCreator(memoizeByRoot, isEqual)(
identity, identity,
( (
{ bodyRanges }: Pick<MessageAttributesType, 'bodyRanges'>, { bodyRanges }: Pick<MessageWithUIFieldsType, 'bodyRanges'>,
{ conversationSelector }: { conversationSelector: GetConversationByIdType } { conversationSelector }: { conversationSelector: GetConversationByIdType }
): BodyRangesType | undefined => { ): BodyRangesType | undefined => {
if (!bodyRanges) { if (!bodyRanges) {
@ -296,7 +298,7 @@ export const processBodyRanges = createSelectorCreator(memoizeByRoot, isEqual)(
}) })
.sort((a, b) => b.start - a.start); .sort((a, b) => b.start - a.start);
}, },
(_: MessageAttributesType, ranges?: BodyRangesType) => ranges (_: MessageWithUIFieldsType, ranges?: BodyRangesType) => ranges
); );
const getAuthorForMessage = createSelectorCreator(memoizeByRoot)( const getAuthorForMessage = createSelectorCreator(memoizeByRoot)(
@ -305,7 +307,10 @@ const getAuthorForMessage = createSelectorCreator(memoizeByRoot)(
getContact, getContact,
(_: MessageAttributesType, convo: ConversationType): PropsData['author'] => { (
_: MessageWithUIFieldsType,
convo: ConversationType
): PropsData['author'] => {
const { const {
acceptedMessageRequest, acceptedMessageRequest,
avatarPath, avatarPath,
@ -347,7 +352,7 @@ const getCachedAuthorForMessage = createSelectorCreator(memoizeByRoot, isEqual)(
getAuthorForMessage, getAuthorForMessage,
( (
_: MessageAttributesType, _: MessageWithUIFieldsType,
author: PropsData['author'] author: PropsData['author']
): PropsData['author'] => author ): PropsData['author'] => author
); );
@ -356,11 +361,11 @@ export const getPreviewsForMessage = createSelectorCreator(memoizeByRoot)(
// `memoizeByRoot` requirement // `memoizeByRoot` requirement
identity, identity,
({ preview }: MessageAttributesType) => preview, ({ preview }: MessageWithUIFieldsType) => preview,
( (
_: MessageAttributesType, _: MessageWithUIFieldsType,
previews: MessageAttributesType['preview'] = [] previews: MessageWithUIFieldsType['preview'] = []
): Array<LinkPreviewType> => { ): Array<LinkPreviewType> => {
return previews.map(preview => ({ return previews.map(preview => ({
...preview, ...preview,
@ -379,7 +384,7 @@ export const getReactionsForMessage = createSelectorCreator(
identity, identity,
( (
{ reactions = [] }: MessageAttributesType, { reactions = [] }: MessageWithUIFieldsType,
{ conversationSelector }: { conversationSelector: GetConversationByIdType } { conversationSelector }: { conversationSelector: GetConversationByIdType }
) => { ) => {
const reactionBySender = new Map<string, MessageReactionType>(); const reactionBySender = new Map<string, MessageReactionType>();
@ -430,7 +435,7 @@ export const getReactionsForMessage = createSelectorCreator(
return [...formattedReactions]; return [...formattedReactions];
}, },
(_: MessageAttributesType, reactions: PropsData['reactions']) => reactions (_: MessageWithUIFieldsType, reactions: PropsData['reactions']) => reactions
); );
export const getPropsForQuote = createSelectorCreator(memoizeByRoot, isEqual)( export const getPropsForQuote = createSelectorCreator(memoizeByRoot, isEqual)(
@ -438,7 +443,7 @@ export const getPropsForQuote = createSelectorCreator(memoizeByRoot, isEqual)(
identity, identity,
( (
message: Pick<MessageAttributesType, 'conversationId' | 'quote'>, message: Pick<MessageWithUIFieldsType, 'conversationId' | 'quote'>,
{ {
conversationSelector, conversationSelector,
ourConversationId, ourConversationId,
@ -528,6 +533,7 @@ type ShallowPropsType = Pick<
| 'customColor' | 'customColor'
| 'deletedForEveryone' | 'deletedForEveryone'
| 'direction' | 'direction'
| 'displayLimit'
| 'expirationLength' | 'expirationLength'
| 'expirationTimestamp' | 'expirationTimestamp'
| 'id' | 'id'
@ -552,7 +558,7 @@ const getShallowPropsForMessage = createSelectorCreator(memoizeByRoot, isEqual)(
identity, identity,
( (
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ {
accountSelector, accountSelector,
conversationSelector, conversationSelector,
@ -611,6 +617,7 @@ const getShallowPropsForMessage = createSelectorCreator(memoizeByRoot, isEqual)(
defaultConversationColor.customColorData?.value, defaultConversationColor.customColorData?.value,
deletedForEveryone: message.deletedForEveryone || false, deletedForEveryone: message.deletedForEveryone || false,
direction: isIncoming(message) ? 'incoming' : 'outgoing', direction: isIncoming(message) ? 'incoming' : 'outgoing',
displayLimit: message.displayLimit,
expirationLength, expirationLength,
expirationTimestamp, expirationTimestamp,
id: message.id, id: message.id,
@ -681,7 +688,7 @@ export const getBubblePropsForMessage = createSelectorCreator(memoizeByRoot)(
// Top-level prop generation for the message bubble // Top-level prop generation for the message bubble
export function getPropsForBubble( export function getPropsForBubble(
message: MessageAttributesType, message: MessageWithUIFieldsType,
options: GetPropsForBubbleOptions options: GetPropsForBubbleOptions
): TimelineItemType { ): TimelineItemType {
if (isUnsupportedMessage(message)) { if (isUnsupportedMessage(message)) {
@ -780,7 +787,9 @@ export function getPropsForBubble(
// Unsupported Message // Unsupported Message
export function isUnsupportedMessage(message: MessageAttributesType): boolean { export function isUnsupportedMessage(
message: MessageWithUIFieldsType
): boolean {
const versionAtReceive = message.supportedVersionAtReceive; const versionAtReceive = message.supportedVersionAtReceive;
const requiredVersion = message.requiredProtocolVersion; const requiredVersion = message.requiredProtocolVersion;
@ -792,7 +801,7 @@ export function isUnsupportedMessage(message: MessageAttributesType): boolean {
} }
function getPropsForUnsupportedMessage( function getPropsForUnsupportedMessage(
message: MessageAttributesType, message: MessageWithUIFieldsType,
options: GetContactOptions options: GetContactOptions
): PropsForUnsupportedMessage { ): PropsForUnsupportedMessage {
const CURRENT_PROTOCOL_VERSION = Proto.DataMessage.ProtocolVersion.CURRENT; const CURRENT_PROTOCOL_VERSION = Proto.DataMessage.ProtocolVersion.CURRENT;
@ -812,12 +821,12 @@ function getPropsForUnsupportedMessage(
// GroupV2 Change // GroupV2 Change
export function isGroupV2Change(message: MessageAttributesType): boolean { export function isGroupV2Change(message: MessageWithUIFieldsType): boolean {
return Boolean(message.groupV2Change); return Boolean(message.groupV2Change);
} }
function getPropsForGroupV2Change( function getPropsForGroupV2Change(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ conversationSelector, ourUuid }: GetPropsForBubbleOptions { conversationSelector, ourUuid }: GetPropsForBubbleOptions
): GroupsV2Props { ): GroupsV2Props {
const change = message.groupV2Change; const change = message.groupV2Change;
@ -837,12 +846,12 @@ function getPropsForGroupV2Change(
// GroupV1 Migration // GroupV1 Migration
export function isGroupV1Migration(message: MessageAttributesType): boolean { export function isGroupV1Migration(message: MessageWithUIFieldsType): boolean {
return message.type === 'group-v1-migration'; return message.type === 'group-v1-migration';
} }
function getPropsForGroupV1Migration( function getPropsForGroupV1Migration(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ conversationSelector }: GetPropsForBubbleOptions { conversationSelector }: GetPropsForBubbleOptions
): GroupV1MigrationPropsType { ): GroupV1MigrationPropsType {
const migration = message.groupMigration; const migration = message.groupMigration;
@ -887,7 +896,7 @@ function getPropsForGroupV1Migration(
// Message History Unsynced // Message History Unsynced
export function isMessageHistoryUnsynced( export function isMessageHistoryUnsynced(
message: MessageAttributesType message: MessageWithUIFieldsType
): boolean { ): boolean {
return message.type === 'message-history-unsynced'; return message.type === 'message-history-unsynced';
} }
@ -897,7 +906,7 @@ export function isMessageHistoryUnsynced(
// Expiration Timer Update // Expiration Timer Update
export function isExpirationTimerUpdate( export function isExpirationTimerUpdate(
message: Pick<MessageAttributesType, 'flags'> message: Pick<MessageWithUIFieldsType, 'flags'>
): boolean { ): boolean {
const flag = Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE; const flag = Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE;
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
@ -905,7 +914,7 @@ export function isExpirationTimerUpdate(
} }
function getPropsForTimerNotification( function getPropsForTimerNotification(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ ourConversationId, conversationSelector }: GetPropsForBubbleOptions { ourConversationId, conversationSelector }: GetPropsForBubbleOptions
): TimerNotificationProps { ): TimerNotificationProps {
const timerUpdate = message.expirationTimerUpdate; const timerUpdate = message.expirationTimerUpdate;
@ -951,12 +960,12 @@ function getPropsForTimerNotification(
// Key Change // Key Change
export function isKeyChange(message: MessageAttributesType): boolean { export function isKeyChange(message: MessageWithUIFieldsType): boolean {
return message.type === 'keychange'; return message.type === 'keychange';
} }
function getPropsForSafetyNumberNotification( function getPropsForSafetyNumberNotification(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ conversationSelector }: GetPropsForBubbleOptions { conversationSelector }: GetPropsForBubbleOptions
): SafetyNumberNotificationProps { ): SafetyNumberNotificationProps {
const conversation = getConversation(message, conversationSelector); const conversation = getConversation(message, conversationSelector);
@ -972,12 +981,12 @@ function getPropsForSafetyNumberNotification(
// Verified Change // Verified Change
export function isVerifiedChange(message: MessageAttributesType): boolean { export function isVerifiedChange(message: MessageWithUIFieldsType): boolean {
return message.type === 'verified-change'; return message.type === 'verified-change';
} }
function getPropsForVerificationNotification( function getPropsForVerificationNotification(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ conversationSelector }: GetPropsForBubbleOptions { conversationSelector }: GetPropsForBubbleOptions
): VerificationNotificationProps { ): VerificationNotificationProps {
const type = message.verified ? 'markVerified' : 'markNotVerified'; const type = message.verified ? 'markVerified' : 'markNotVerified';
@ -994,13 +1003,13 @@ function getPropsForVerificationNotification(
// Group Update (V1) // Group Update (V1)
export function isGroupUpdate( export function isGroupUpdate(
message: Pick<MessageAttributesType, 'group_update'> message: Pick<MessageWithUIFieldsType, 'group_update'>
): boolean { ): boolean {
return Boolean(message.group_update); return Boolean(message.group_update);
} }
function getPropsForGroupNotification( function getPropsForGroupNotification(
message: MessageAttributesType, message: MessageWithUIFieldsType,
options: GetContactOptions options: GetContactOptions
): GroupNotificationProps { ): GroupNotificationProps {
const groupUpdate = message.group_update; const groupUpdate = message.group_update;
@ -1075,7 +1084,7 @@ function getPropsForGroupNotification(
// End Session // End Session
export function isEndSession( export function isEndSession(
message: Pick<MessageAttributesType, 'flags'> message: Pick<MessageWithUIFieldsType, 'flags'>
): boolean { ): boolean {
const flag = Proto.DataMessage.Flags.END_SESSION; const flag = Proto.DataMessage.Flags.END_SESSION;
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
@ -1084,7 +1093,7 @@ export function isEndSession(
// Call History // Call History
export function isCallHistory(message: MessageAttributesType): boolean { export function isCallHistory(message: MessageWithUIFieldsType): boolean {
return message.type === 'call-history'; return message.type === 'call-history';
} }
@ -1094,7 +1103,7 @@ export type GetPropsForCallHistoryOptions = Pick<
>; >;
export function getPropsForCallHistory( export function getPropsForCallHistory(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ {
conversationSelector, conversationSelector,
callSelector, callSelector,
@ -1151,12 +1160,12 @@ export function getPropsForCallHistory(
// Profile Change // Profile Change
export function isProfileChange(message: MessageAttributesType): boolean { export function isProfileChange(message: MessageWithUIFieldsType): boolean {
return message.type === 'profile-change'; return message.type === 'profile-change';
} }
function getPropsForProfileChange( function getPropsForProfileChange(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ conversationSelector }: GetPropsForBubbleOptions { conversationSelector }: GetPropsForBubbleOptions
): ProfileChangeNotificationPropsType { ): ProfileChangeNotificationPropsType {
const change = message.profileChange; const change = message.profileChange;
@ -1178,7 +1187,7 @@ function getPropsForProfileChange(
// Note: smart, so props not generated here // Note: smart, so props not generated here
export function isUniversalTimerNotification( export function isUniversalTimerNotification(
message: MessageAttributesType message: MessageWithUIFieldsType
): boolean { ): boolean {
return message.type === 'universal-timer-notification'; return message.type === 'universal-timer-notification';
} }
@ -1186,13 +1195,13 @@ export function isUniversalTimerNotification(
// Change Number Notification // Change Number Notification
export function isChangeNumberNotification( export function isChangeNumberNotification(
message: MessageAttributesType message: MessageWithUIFieldsType
): boolean { ): boolean {
return message.type === 'change-number-notification'; return message.type === 'change-number-notification';
} }
function getPropsForChangeNumberNotification( function getPropsForChangeNumberNotification(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ conversationSelector }: GetPropsForBubbleOptions { conversationSelector }: GetPropsForBubbleOptions
): ChangeNumberNotificationProps { ): ChangeNumberNotificationProps {
return { return {
@ -1204,7 +1213,7 @@ function getPropsForChangeNumberNotification(
// Chat Session Refreshed // Chat Session Refreshed
export function isChatSessionRefreshed( export function isChatSessionRefreshed(
message: MessageAttributesType message: MessageWithUIFieldsType
): boolean { ): boolean {
return message.type === 'chat-session-refreshed'; return message.type === 'chat-session-refreshed';
} }
@ -1213,12 +1222,12 @@ export function isChatSessionRefreshed(
// Delivery Issue // Delivery Issue
export function isDeliveryIssue(message: MessageAttributesType): boolean { export function isDeliveryIssue(message: MessageWithUIFieldsType): boolean {
return message.type === 'delivery-issue'; return message.type === 'delivery-issue';
} }
function getPropsForDeliveryIssue( function getPropsForDeliveryIssue(
message: MessageAttributesType, message: MessageWithUIFieldsType,
{ conversationSelector }: GetPropsForBubbleOptions { conversationSelector }: GetPropsForBubbleOptions
): DeliveryIssuePropsType { ): DeliveryIssuePropsType {
const sender = conversationSelector(message.sourceUuid); const sender = conversationSelector(message.sourceUuid);
@ -1232,7 +1241,7 @@ function getPropsForDeliveryIssue(
// Other utility functions // Other utility functions
export function isTapToView(message: MessageAttributesType): boolean { export function isTapToView(message: MessageWithUIFieldsType): boolean {
// If a message is deleted for everyone, that overrides all other styling // If a message is deleted for everyone, that overrides all other styling
if (message.deletedForEveryone) { if (message.deletedForEveryone) {
return false; return false;
@ -1259,7 +1268,7 @@ function createNonBreakingLastSeparator(text?: string): string {
export function getMessagePropStatus( export function getMessagePropStatus(
message: Pick< message: Pick<
MessageAttributesType, MessageWithUIFieldsType,
'type' | 'errors' | 'sendStateByConversationId' 'type' | 'errors' | 'sendStateByConversationId'
>, >,
ourConversationId: string ourConversationId: string
@ -1318,7 +1327,7 @@ export function getMessagePropStatus(
} }
export function getPropsForEmbeddedContact( export function getPropsForEmbeddedContact(
message: MessageAttributesType, message: MessageWithUIFieldsType,
regionCode: string, regionCode: string,
accountSelector: (identifier?: string) => boolean accountSelector: (identifier?: string) => boolean
): EmbeddedContactType | undefined { ): EmbeddedContactType | undefined {
@ -1400,7 +1409,7 @@ function processQuoteAttachment(
function canReplyOrReact( function canReplyOrReact(
message: Pick< message: Pick<
MessageAttributesType, MessageWithUIFieldsType,
'deletedForEveryone' | 'sendStateByConversationId' | 'type' 'deletedForEveryone' | 'sendStateByConversationId' | 'type'
>, >,
ourConversationId: string, ourConversationId: string,
@ -1445,7 +1454,7 @@ function canReplyOrReact(
export function canReply( export function canReply(
message: Pick< message: Pick<
MessageAttributesType, MessageWithUIFieldsType,
| 'conversationId' | 'conversationId'
| 'deletedForEveryone' | 'deletedForEveryone'
| 'sendStateByConversationId' | 'sendStateByConversationId'
@ -1466,7 +1475,7 @@ export function canReply(
export function canReact( export function canReact(
message: Pick< message: Pick<
MessageAttributesType, MessageWithUIFieldsType,
| 'conversationId' | 'conversationId'
| 'deletedForEveryone' | 'deletedForEveryone'
| 'sendStateByConversationId' | 'sendStateByConversationId'
@ -1481,7 +1490,7 @@ export function canReact(
export function canDeleteForEveryone( export function canDeleteForEveryone(
message: Pick< message: Pick<
MessageAttributesType, MessageWithUIFieldsType,
'type' | 'deletedForEveryone' | 'sent_at' | 'sendStateByConversationId' 'type' | 'deletedForEveryone' | 'sent_at' | 'sendStateByConversationId'
> >
): boolean { ): boolean {
@ -1501,7 +1510,7 @@ export function canDeleteForEveryone(
} }
export function canDownload( export function canDownload(
message: MessageAttributesType, message: MessageWithUIFieldsType,
conversationSelector: GetConversationByIdType conversationSelector: GetConversationByIdType
): boolean { ): boolean {
if (isOutgoing(message)) { if (isOutgoing(message)) {
@ -1526,7 +1535,7 @@ export function canDownload(
} }
export function getLastChallengeError( export function getLastChallengeError(
message: Pick<MessageAttributesType, 'errors'> message: Pick<MessageWithUIFieldsType, 'errors'>
): ShallowChallengeError | undefined { ): ShallowChallengeError | undefined {
const { errors } = message; const { errors } = message;
if (!errors) { if (!errors) {

View File

@ -11994,4 +11994,4 @@
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2021-09-17T21:02:59.414Z" "updated": "2021-09-17T21:02:59.414Z"
} }
] ]