Remember message Read More state when scrolling in virtualized container
This commit is contained in:
parent
c5b5f2fe42
commit
edab7c7d83
12 changed files with 159 additions and 72 deletions
|
@ -144,6 +144,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
||||
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
||||
markViewed: action('markViewed'),
|
||||
messageExpanded: action('messageExpanded'),
|
||||
onHeightChange: action('onHeightChange'),
|
||||
openConversation: action('openConversation'),
|
||||
openLink: action('openLink'),
|
||||
|
|
|
@ -131,6 +131,7 @@ export type PropsData = {
|
|||
conversationColor: ConversationColorType;
|
||||
customColor?: CustomColorType;
|
||||
conversationId: string;
|
||||
displayLimit?: number;
|
||||
text?: string;
|
||||
textPending?: boolean;
|
||||
isSticker?: boolean;
|
||||
|
@ -216,6 +217,7 @@ export type PropsActions = {
|
|||
clearSelectedMessage: () => unknown;
|
||||
doubleCheckMissingQuoteReference: (messageId: string) => unknown;
|
||||
onHeightChange: () => unknown;
|
||||
messageExpanded: (id: string, displayLimit: number) => unknown;
|
||||
checkForAccount: (identifier: string) => unknown;
|
||||
|
||||
reactToMessage: (
|
||||
|
@ -1229,7 +1231,10 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
bodyRanges,
|
||||
deletedForEveryone,
|
||||
direction,
|
||||
displayLimit,
|
||||
i18n,
|
||||
id,
|
||||
messageExpanded,
|
||||
onHeightChange,
|
||||
openConversation,
|
||||
status,
|
||||
|
@ -1263,7 +1268,10 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
bodyRanges={bodyRanges}
|
||||
disableLinks={!this.areLinksEnabled()}
|
||||
direction={direction}
|
||||
displayLimit={displayLimit}
|
||||
i18n={i18n}
|
||||
id={id}
|
||||
messageExpanded={messageExpanded}
|
||||
openConversation={openConversation}
|
||||
onHeightChange={onHeightChange}
|
||||
text={contents || ''}
|
||||
|
|
|
@ -19,7 +19,10 @@ const story = storiesOf('Components/Conversation/MessageBodyReadMore', module);
|
|||
const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||
bodyRanges: overrideProps.bodyRanges,
|
||||
direction: 'incoming',
|
||||
displayLimit: overrideProps.displayLimit,
|
||||
i18n,
|
||||
id: 'some-id',
|
||||
messageExpanded: action('messageExpanded'),
|
||||
onHeightChange: action('onHeightChange'),
|
||||
text: text('text', overrideProps.text || ''),
|
||||
});
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// 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 { MessageBody } from './MessageBody';
|
||||
import { usePrevious } from '../../hooks/usePrevious';
|
||||
|
||||
export type Props = Pick<
|
||||
MessageBodyPropsType,
|
||||
|
@ -16,6 +17,9 @@ export type Props = Pick<
|
|||
| 'bodyRanges'
|
||||
| 'openConversation'
|
||||
> & {
|
||||
id: string;
|
||||
displayLimit?: number;
|
||||
messageExpanded: (id: string, displayLimit: number) => unknown;
|
||||
onHeightChange: () => unknown;
|
||||
};
|
||||
|
||||
|
@ -57,20 +61,29 @@ export function MessageBodyReadMore({
|
|||
bodyRanges,
|
||||
direction,
|
||||
disableLinks,
|
||||
displayLimit,
|
||||
i18n,
|
||||
id,
|
||||
messageExpanded,
|
||||
onHeightChange,
|
||||
openConversation,
|
||||
text,
|
||||
textPending,
|
||||
}: 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 onIncreaseTextLength = hasReadMore
|
||||
? () => {
|
||||
setMaxLength(oldMaxLength => oldMaxLength + INCREMENT_COUNT);
|
||||
onHeightChange();
|
||||
messageExpanded(id, maxLength + INCREMENT_COUNT);
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
|
|
@ -313,6 +313,7 @@ export class MessageDetail extends React.Component<Props> {
|
|||
}
|
||||
disableMenu
|
||||
disableScroll
|
||||
displayLimit={Number.MAX_SAFE_INTEGER}
|
||||
displayTapToViewMessage={displayTapToViewMessage}
|
||||
downloadAttachment={() =>
|
||||
log.warn('MessageDetail: deleteMessageForEveryone called!')
|
||||
|
@ -323,6 +324,7 @@ export class MessageDetail extends React.Component<Props> {
|
|||
kickOffAttachmentDownload={kickOffAttachmentDownload}
|
||||
markAttachmentAsCorrupted={markAttachmentAsCorrupted}
|
||||
markViewed={markViewed}
|
||||
messageExpanded={noop}
|
||||
onHeightChange={noop}
|
||||
openConversation={openConversation}
|
||||
openLink={openLink}
|
||||
|
|
|
@ -63,7 +63,8 @@ const defaultMessageProps: MessagesProps = {
|
|||
kickOffAttachmentDownload: action('default--kickOffAttachmentDownload'),
|
||||
markAttachmentAsCorrupted: action('default--markAttachmentAsCorrupted'),
|
||||
markViewed: action('default--markViewed'),
|
||||
onHeightChange: action('onHeightChange'),
|
||||
messageExpanded: action('dafult--message-expanded'),
|
||||
onHeightChange: action('default--onHeightChange'),
|
||||
openConversation: action('default--openConversation'),
|
||||
openLink: action('default--openLink'),
|
||||
previews: [],
|
||||
|
|
|
@ -327,6 +327,7 @@ const actions = () => ({
|
|||
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
||||
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
||||
markViewed: action('markViewed'),
|
||||
messageExpanded: action('messageExpanded'),
|
||||
showVisualAttachment: action('showVisualAttachment'),
|
||||
downloadAttachment: action('downloadAttachment'),
|
||||
displayTapToViewMessage: action('displayTapToViewMessage'),
|
||||
|
|
|
@ -269,6 +269,7 @@ const getActions = createSelector(
|
|||
'showContactModal',
|
||||
'kickOffAttachmentDownload',
|
||||
'markAttachmentAsCorrupted',
|
||||
'messageExpanded',
|
||||
'showVisualAttachment',
|
||||
'downloadAttachment',
|
||||
'displayTapToViewMessage',
|
||||
|
|
|
@ -66,6 +66,7 @@ const getDefaultProps = () => ({
|
|||
learnMoreAboutDeliveryIssue: action('learnMoreAboutDeliveryIssue'),
|
||||
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
||||
markViewed: action('markViewed'),
|
||||
messageExpanded: action('messageExpanded'),
|
||||
showMessageDetail: action('showMessageDetail'),
|
||||
openConversation: action('openConversation'),
|
||||
showContactDetail: action('showContactDetail'),
|
||||
|
|
|
@ -87,6 +87,9 @@ export type InteractionModeType = typeof InteractionModes[number];
|
|||
export type MessageType = MessageAttributesType & {
|
||||
interactionType?: InteractionModeType;
|
||||
};
|
||||
export type MessageWithUIFieldsType = MessageAttributesType & {
|
||||
displayLimit?: number;
|
||||
};
|
||||
|
||||
export const ConversationTypes = ['direct', 'group'] as const;
|
||||
export type ConversationTypeType = typeof ConversationTypes[number];
|
||||
|
@ -235,7 +238,7 @@ type MessageMetricsType = {
|
|||
};
|
||||
|
||||
export type MessageLookupType = {
|
||||
[key: string]: MessageAttributesType;
|
||||
[key: string]: MessageWithUIFieldsType;
|
||||
};
|
||||
export type ConversationMessageType = {
|
||||
heightChangeMessageIds: Array<string>;
|
||||
|
@ -523,6 +526,14 @@ export type MessageDeletedActionType = {
|
|||
conversationId: string;
|
||||
};
|
||||
};
|
||||
export type MessageExpandedActionType = {
|
||||
type: 'MESSAGE_EXPANDED';
|
||||
payload: {
|
||||
id: string;
|
||||
displayLimit: number;
|
||||
};
|
||||
};
|
||||
|
||||
type MessageSizeChangedActionType = {
|
||||
type: 'MESSAGE_SIZE_CHANGED';
|
||||
payload: {
|
||||
|
@ -738,6 +749,7 @@ export type ConversationActionType =
|
|||
| MessageStoppedByMissingVerificationActionType
|
||||
| MessageChangedActionType
|
||||
| MessageDeletedActionType
|
||||
| MessageExpandedActionType
|
||||
| MessageSelectedActionType
|
||||
| MessageSizeChangedActionType
|
||||
| MessagesAddedActionType
|
||||
|
@ -801,6 +813,7 @@ export const actions = {
|
|||
messageStoppedByMissingVerification,
|
||||
messageChanged,
|
||||
messageDeleted,
|
||||
messageExpanded,
|
||||
messageSizeChanged,
|
||||
messagesAdded,
|
||||
messagesReset,
|
||||
|
@ -1504,6 +1517,18 @@ function messageDeleted(
|
|||
},
|
||||
};
|
||||
}
|
||||
function messageExpanded(
|
||||
id: string,
|
||||
displayLimit: number
|
||||
): MessageExpandedActionType {
|
||||
return {
|
||||
type: 'MESSAGE_EXPANDED',
|
||||
payload: {
|
||||
id,
|
||||
displayLimit,
|
||||
},
|
||||
};
|
||||
}
|
||||
function messageSizeChanged(
|
||||
id: string,
|
||||
conversationId: string
|
||||
|
@ -2361,7 +2386,7 @@ export function reducer(
|
|||
return state;
|
||||
}
|
||||
// ...and we've already loaded that message once
|
||||
const existingMessage = state.messagesLookup[id];
|
||||
const existingMessage = getOwn(state.messagesLookup, id);
|
||||
if (!existingMessage) {
|
||||
return state;
|
||||
}
|
||||
|
@ -2379,7 +2404,10 @@ export function reducer(
|
|||
...state,
|
||||
messagesLookup: {
|
||||
...state.messagesLookup,
|
||||
[id]: data,
|
||||
[id]: {
|
||||
...data,
|
||||
displayLimit: existingMessage.displayLimit,
|
||||
},
|
||||
},
|
||||
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') {
|
||||
const { id, conversationId } = action.payload;
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ import filesize from 'filesize';
|
|||
|
||||
import type {
|
||||
LastMessageStatus,
|
||||
MessageAttributesType,
|
||||
MessageReactionType,
|
||||
ShallowChallengeError,
|
||||
} from '../../model-types.d';
|
||||
|
@ -58,7 +57,10 @@ import { isMoreRecentThan } from '../../util/timestamp';
|
|||
import * as iterables from '../../util/iterables';
|
||||
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 { CallSelectorType, CallStateType } from './calling';
|
||||
|
@ -114,25 +116,25 @@ export type GetPropsForBubbleOptions = Readonly<{
|
|||
}>;
|
||||
|
||||
export function isIncoming(
|
||||
message: Pick<MessageAttributesType, 'type'>
|
||||
message: Pick<MessageWithUIFieldsType, 'type'>
|
||||
): boolean {
|
||||
return message.type === 'incoming';
|
||||
}
|
||||
|
||||
export function isOutgoing(
|
||||
message: Pick<MessageAttributesType, 'type'>
|
||||
message: Pick<MessageWithUIFieldsType, 'type'>
|
||||
): boolean {
|
||||
return message.type === 'outgoing';
|
||||
}
|
||||
|
||||
export function hasErrors(
|
||||
message: Pick<MessageAttributesType, 'errors'>
|
||||
message: Pick<MessageWithUIFieldsType, 'errors'>
|
||||
): boolean {
|
||||
return message.errors ? message.errors.length > 0 : false;
|
||||
}
|
||||
|
||||
export function getSource(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
ourNumber: string | undefined
|
||||
): string | undefined {
|
||||
if (isIncoming(message)) {
|
||||
|
@ -146,7 +148,7 @@ export function getSource(
|
|||
}
|
||||
|
||||
export function getSourceDevice(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
ourDeviceId: number
|
||||
): string | number | undefined {
|
||||
const { sourceDevice } = message;
|
||||
|
@ -164,7 +166,7 @@ export function getSourceDevice(
|
|||
}
|
||||
|
||||
export function getSourceUuid(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
ourUuid: string | undefined
|
||||
): string | undefined {
|
||||
if (isIncoming(message)) {
|
||||
|
@ -185,7 +187,7 @@ export type GetContactOptions = Pick<
|
|||
>;
|
||||
|
||||
function getContactId(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{
|
||||
conversationSelector,
|
||||
ourConversationId,
|
||||
|
@ -206,7 +208,7 @@ function getContactId(
|
|||
|
||||
// TODO: DESKTOP-2145
|
||||
export function getContact(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{
|
||||
conversationSelector,
|
||||
ourConversationId,
|
||||
|
@ -225,7 +227,7 @@ export function getContact(
|
|||
}
|
||||
|
||||
export function getConversation(
|
||||
message: Pick<MessageAttributesType, 'conversationId'>,
|
||||
message: Pick<MessageWithUIFieldsType, 'conversationId'>,
|
||||
conversationSelector: GetConversationByIdType
|
||||
): ConversationType {
|
||||
return conversationSelector(message.conversationId);
|
||||
|
@ -237,12 +239,12 @@ export const getAttachmentsForMessage = createSelectorCreator(memoizeByRoot)(
|
|||
// `memoizeByRoot` requirement
|
||||
identity,
|
||||
|
||||
({ sticker }: MessageAttributesType) => sticker,
|
||||
({ attachments }: MessageAttributesType) => attachments,
|
||||
({ sticker }: MessageWithUIFieldsType) => sticker,
|
||||
({ attachments }: MessageWithUIFieldsType) => attachments,
|
||||
(
|
||||
_: MessageAttributesType,
|
||||
sticker: MessageAttributesType['sticker'],
|
||||
attachments: MessageAttributesType['attachments'] = []
|
||||
_: MessageWithUIFieldsType,
|
||||
sticker: MessageWithUIFieldsType['sticker'],
|
||||
attachments: MessageWithUIFieldsType['attachments'] = []
|
||||
): Array<AttachmentType> => {
|
||||
if (sticker && sticker.data) {
|
||||
const { data } = sticker;
|
||||
|
@ -276,7 +278,7 @@ export const processBodyRanges = createSelectorCreator(memoizeByRoot, isEqual)(
|
|||
identity,
|
||||
|
||||
(
|
||||
{ bodyRanges }: Pick<MessageAttributesType, 'bodyRanges'>,
|
||||
{ bodyRanges }: Pick<MessageWithUIFieldsType, 'bodyRanges'>,
|
||||
{ conversationSelector }: { conversationSelector: GetConversationByIdType }
|
||||
): BodyRangesType | undefined => {
|
||||
if (!bodyRanges) {
|
||||
|
@ -296,7 +298,7 @@ export const processBodyRanges = createSelectorCreator(memoizeByRoot, isEqual)(
|
|||
})
|
||||
.sort((a, b) => b.start - a.start);
|
||||
},
|
||||
(_: MessageAttributesType, ranges?: BodyRangesType) => ranges
|
||||
(_: MessageWithUIFieldsType, ranges?: BodyRangesType) => ranges
|
||||
);
|
||||
|
||||
const getAuthorForMessage = createSelectorCreator(memoizeByRoot)(
|
||||
|
@ -305,7 +307,10 @@ const getAuthorForMessage = createSelectorCreator(memoizeByRoot)(
|
|||
|
||||
getContact,
|
||||
|
||||
(_: MessageAttributesType, convo: ConversationType): PropsData['author'] => {
|
||||
(
|
||||
_: MessageWithUIFieldsType,
|
||||
convo: ConversationType
|
||||
): PropsData['author'] => {
|
||||
const {
|
||||
acceptedMessageRequest,
|
||||
avatarPath,
|
||||
|
@ -347,7 +352,7 @@ const getCachedAuthorForMessage = createSelectorCreator(memoizeByRoot, isEqual)(
|
|||
getAuthorForMessage,
|
||||
|
||||
(
|
||||
_: MessageAttributesType,
|
||||
_: MessageWithUIFieldsType,
|
||||
author: PropsData['author']
|
||||
): PropsData['author'] => author
|
||||
);
|
||||
|
@ -356,11 +361,11 @@ export const getPreviewsForMessage = createSelectorCreator(memoizeByRoot)(
|
|||
// `memoizeByRoot` requirement
|
||||
identity,
|
||||
|
||||
({ preview }: MessageAttributesType) => preview,
|
||||
({ preview }: MessageWithUIFieldsType) => preview,
|
||||
|
||||
(
|
||||
_: MessageAttributesType,
|
||||
previews: MessageAttributesType['preview'] = []
|
||||
_: MessageWithUIFieldsType,
|
||||
previews: MessageWithUIFieldsType['preview'] = []
|
||||
): Array<LinkPreviewType> => {
|
||||
return previews.map(preview => ({
|
||||
...preview,
|
||||
|
@ -379,7 +384,7 @@ export const getReactionsForMessage = createSelectorCreator(
|
|||
identity,
|
||||
|
||||
(
|
||||
{ reactions = [] }: MessageAttributesType,
|
||||
{ reactions = [] }: MessageWithUIFieldsType,
|
||||
{ conversationSelector }: { conversationSelector: GetConversationByIdType }
|
||||
) => {
|
||||
const reactionBySender = new Map<string, MessageReactionType>();
|
||||
|
@ -430,7 +435,7 @@ export const getReactionsForMessage = createSelectorCreator(
|
|||
return [...formattedReactions];
|
||||
},
|
||||
|
||||
(_: MessageAttributesType, reactions: PropsData['reactions']) => reactions
|
||||
(_: MessageWithUIFieldsType, reactions: PropsData['reactions']) => reactions
|
||||
);
|
||||
|
||||
export const getPropsForQuote = createSelectorCreator(memoizeByRoot, isEqual)(
|
||||
|
@ -438,7 +443,7 @@ export const getPropsForQuote = createSelectorCreator(memoizeByRoot, isEqual)(
|
|||
identity,
|
||||
|
||||
(
|
||||
message: Pick<MessageAttributesType, 'conversationId' | 'quote'>,
|
||||
message: Pick<MessageWithUIFieldsType, 'conversationId' | 'quote'>,
|
||||
{
|
||||
conversationSelector,
|
||||
ourConversationId,
|
||||
|
@ -528,6 +533,7 @@ type ShallowPropsType = Pick<
|
|||
| 'customColor'
|
||||
| 'deletedForEveryone'
|
||||
| 'direction'
|
||||
| 'displayLimit'
|
||||
| 'expirationLength'
|
||||
| 'expirationTimestamp'
|
||||
| 'id'
|
||||
|
@ -552,7 +558,7 @@ const getShallowPropsForMessage = createSelectorCreator(memoizeByRoot, isEqual)(
|
|||
identity,
|
||||
|
||||
(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{
|
||||
accountSelector,
|
||||
conversationSelector,
|
||||
|
@ -611,6 +617,7 @@ const getShallowPropsForMessage = createSelectorCreator(memoizeByRoot, isEqual)(
|
|||
defaultConversationColor.customColorData?.value,
|
||||
deletedForEveryone: message.deletedForEveryone || false,
|
||||
direction: isIncoming(message) ? 'incoming' : 'outgoing',
|
||||
displayLimit: message.displayLimit,
|
||||
expirationLength,
|
||||
expirationTimestamp,
|
||||
id: message.id,
|
||||
|
@ -681,7 +688,7 @@ export const getBubblePropsForMessage = createSelectorCreator(memoizeByRoot)(
|
|||
|
||||
// Top-level prop generation for the message bubble
|
||||
export function getPropsForBubble(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
options: GetPropsForBubbleOptions
|
||||
): TimelineItemType {
|
||||
if (isUnsupportedMessage(message)) {
|
||||
|
@ -780,7 +787,9 @@ export function getPropsForBubble(
|
|||
|
||||
// Unsupported Message
|
||||
|
||||
export function isUnsupportedMessage(message: MessageAttributesType): boolean {
|
||||
export function isUnsupportedMessage(
|
||||
message: MessageWithUIFieldsType
|
||||
): boolean {
|
||||
const versionAtReceive = message.supportedVersionAtReceive;
|
||||
const requiredVersion = message.requiredProtocolVersion;
|
||||
|
||||
|
@ -792,7 +801,7 @@ export function isUnsupportedMessage(message: MessageAttributesType): boolean {
|
|||
}
|
||||
|
||||
function getPropsForUnsupportedMessage(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
options: GetContactOptions
|
||||
): PropsForUnsupportedMessage {
|
||||
const CURRENT_PROTOCOL_VERSION = Proto.DataMessage.ProtocolVersion.CURRENT;
|
||||
|
@ -812,12 +821,12 @@ function getPropsForUnsupportedMessage(
|
|||
|
||||
// GroupV2 Change
|
||||
|
||||
export function isGroupV2Change(message: MessageAttributesType): boolean {
|
||||
export function isGroupV2Change(message: MessageWithUIFieldsType): boolean {
|
||||
return Boolean(message.groupV2Change);
|
||||
}
|
||||
|
||||
function getPropsForGroupV2Change(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{ conversationSelector, ourUuid }: GetPropsForBubbleOptions
|
||||
): GroupsV2Props {
|
||||
const change = message.groupV2Change;
|
||||
|
@ -837,12 +846,12 @@ function getPropsForGroupV2Change(
|
|||
|
||||
// GroupV1 Migration
|
||||
|
||||
export function isGroupV1Migration(message: MessageAttributesType): boolean {
|
||||
export function isGroupV1Migration(message: MessageWithUIFieldsType): boolean {
|
||||
return message.type === 'group-v1-migration';
|
||||
}
|
||||
|
||||
function getPropsForGroupV1Migration(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{ conversationSelector }: GetPropsForBubbleOptions
|
||||
): GroupV1MigrationPropsType {
|
||||
const migration = message.groupMigration;
|
||||
|
@ -887,7 +896,7 @@ function getPropsForGroupV1Migration(
|
|||
// Message History Unsynced
|
||||
|
||||
export function isMessageHistoryUnsynced(
|
||||
message: MessageAttributesType
|
||||
message: MessageWithUIFieldsType
|
||||
): boolean {
|
||||
return message.type === 'message-history-unsynced';
|
||||
}
|
||||
|
@ -897,7 +906,7 @@ export function isMessageHistoryUnsynced(
|
|||
// Expiration Timer Update
|
||||
|
||||
export function isExpirationTimerUpdate(
|
||||
message: Pick<MessageAttributesType, 'flags'>
|
||||
message: Pick<MessageWithUIFieldsType, 'flags'>
|
||||
): boolean {
|
||||
const flag = Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE;
|
||||
// eslint-disable-next-line no-bitwise
|
||||
|
@ -905,7 +914,7 @@ export function isExpirationTimerUpdate(
|
|||
}
|
||||
|
||||
function getPropsForTimerNotification(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{ ourConversationId, conversationSelector }: GetPropsForBubbleOptions
|
||||
): TimerNotificationProps {
|
||||
const timerUpdate = message.expirationTimerUpdate;
|
||||
|
@ -951,12 +960,12 @@ function getPropsForTimerNotification(
|
|||
|
||||
// Key Change
|
||||
|
||||
export function isKeyChange(message: MessageAttributesType): boolean {
|
||||
export function isKeyChange(message: MessageWithUIFieldsType): boolean {
|
||||
return message.type === 'keychange';
|
||||
}
|
||||
|
||||
function getPropsForSafetyNumberNotification(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{ conversationSelector }: GetPropsForBubbleOptions
|
||||
): SafetyNumberNotificationProps {
|
||||
const conversation = getConversation(message, conversationSelector);
|
||||
|
@ -972,12 +981,12 @@ function getPropsForSafetyNumberNotification(
|
|||
|
||||
// Verified Change
|
||||
|
||||
export function isVerifiedChange(message: MessageAttributesType): boolean {
|
||||
export function isVerifiedChange(message: MessageWithUIFieldsType): boolean {
|
||||
return message.type === 'verified-change';
|
||||
}
|
||||
|
||||
function getPropsForVerificationNotification(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{ conversationSelector }: GetPropsForBubbleOptions
|
||||
): VerificationNotificationProps {
|
||||
const type = message.verified ? 'markVerified' : 'markNotVerified';
|
||||
|
@ -994,13 +1003,13 @@ function getPropsForVerificationNotification(
|
|||
// Group Update (V1)
|
||||
|
||||
export function isGroupUpdate(
|
||||
message: Pick<MessageAttributesType, 'group_update'>
|
||||
message: Pick<MessageWithUIFieldsType, 'group_update'>
|
||||
): boolean {
|
||||
return Boolean(message.group_update);
|
||||
}
|
||||
|
||||
function getPropsForGroupNotification(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
options: GetContactOptions
|
||||
): GroupNotificationProps {
|
||||
const groupUpdate = message.group_update;
|
||||
|
@ -1075,7 +1084,7 @@ function getPropsForGroupNotification(
|
|||
// End Session
|
||||
|
||||
export function isEndSession(
|
||||
message: Pick<MessageAttributesType, 'flags'>
|
||||
message: Pick<MessageWithUIFieldsType, 'flags'>
|
||||
): boolean {
|
||||
const flag = Proto.DataMessage.Flags.END_SESSION;
|
||||
// eslint-disable-next-line no-bitwise
|
||||
|
@ -1084,7 +1093,7 @@ export function isEndSession(
|
|||
|
||||
// Call History
|
||||
|
||||
export function isCallHistory(message: MessageAttributesType): boolean {
|
||||
export function isCallHistory(message: MessageWithUIFieldsType): boolean {
|
||||
return message.type === 'call-history';
|
||||
}
|
||||
|
||||
|
@ -1094,7 +1103,7 @@ export type GetPropsForCallHistoryOptions = Pick<
|
|||
>;
|
||||
|
||||
export function getPropsForCallHistory(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{
|
||||
conversationSelector,
|
||||
callSelector,
|
||||
|
@ -1151,12 +1160,12 @@ export function getPropsForCallHistory(
|
|||
|
||||
// Profile Change
|
||||
|
||||
export function isProfileChange(message: MessageAttributesType): boolean {
|
||||
export function isProfileChange(message: MessageWithUIFieldsType): boolean {
|
||||
return message.type === 'profile-change';
|
||||
}
|
||||
|
||||
function getPropsForProfileChange(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{ conversationSelector }: GetPropsForBubbleOptions
|
||||
): ProfileChangeNotificationPropsType {
|
||||
const change = message.profileChange;
|
||||
|
@ -1178,7 +1187,7 @@ function getPropsForProfileChange(
|
|||
// Note: smart, so props not generated here
|
||||
|
||||
export function isUniversalTimerNotification(
|
||||
message: MessageAttributesType
|
||||
message: MessageWithUIFieldsType
|
||||
): boolean {
|
||||
return message.type === 'universal-timer-notification';
|
||||
}
|
||||
|
@ -1186,13 +1195,13 @@ export function isUniversalTimerNotification(
|
|||
// Change Number Notification
|
||||
|
||||
export function isChangeNumberNotification(
|
||||
message: MessageAttributesType
|
||||
message: MessageWithUIFieldsType
|
||||
): boolean {
|
||||
return message.type === 'change-number-notification';
|
||||
}
|
||||
|
||||
function getPropsForChangeNumberNotification(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{ conversationSelector }: GetPropsForBubbleOptions
|
||||
): ChangeNumberNotificationProps {
|
||||
return {
|
||||
|
@ -1204,7 +1213,7 @@ function getPropsForChangeNumberNotification(
|
|||
// Chat Session Refreshed
|
||||
|
||||
export function isChatSessionRefreshed(
|
||||
message: MessageAttributesType
|
||||
message: MessageWithUIFieldsType
|
||||
): boolean {
|
||||
return message.type === 'chat-session-refreshed';
|
||||
}
|
||||
|
@ -1213,12 +1222,12 @@ export function isChatSessionRefreshed(
|
|||
|
||||
// Delivery Issue
|
||||
|
||||
export function isDeliveryIssue(message: MessageAttributesType): boolean {
|
||||
export function isDeliveryIssue(message: MessageWithUIFieldsType): boolean {
|
||||
return message.type === 'delivery-issue';
|
||||
}
|
||||
|
||||
function getPropsForDeliveryIssue(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
{ conversationSelector }: GetPropsForBubbleOptions
|
||||
): DeliveryIssuePropsType {
|
||||
const sender = conversationSelector(message.sourceUuid);
|
||||
|
@ -1232,7 +1241,7 @@ function getPropsForDeliveryIssue(
|
|||
|
||||
// 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 (message.deletedForEveryone) {
|
||||
return false;
|
||||
|
@ -1259,7 +1268,7 @@ function createNonBreakingLastSeparator(text?: string): string {
|
|||
|
||||
export function getMessagePropStatus(
|
||||
message: Pick<
|
||||
MessageAttributesType,
|
||||
MessageWithUIFieldsType,
|
||||
'type' | 'errors' | 'sendStateByConversationId'
|
||||
>,
|
||||
ourConversationId: string
|
||||
|
@ -1318,7 +1327,7 @@ export function getMessagePropStatus(
|
|||
}
|
||||
|
||||
export function getPropsForEmbeddedContact(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
regionCode: string,
|
||||
accountSelector: (identifier?: string) => boolean
|
||||
): EmbeddedContactType | undefined {
|
||||
|
@ -1400,7 +1409,7 @@ function processQuoteAttachment(
|
|||
|
||||
function canReplyOrReact(
|
||||
message: Pick<
|
||||
MessageAttributesType,
|
||||
MessageWithUIFieldsType,
|
||||
'deletedForEveryone' | 'sendStateByConversationId' | 'type'
|
||||
>,
|
||||
ourConversationId: string,
|
||||
|
@ -1445,7 +1454,7 @@ function canReplyOrReact(
|
|||
|
||||
export function canReply(
|
||||
message: Pick<
|
||||
MessageAttributesType,
|
||||
MessageWithUIFieldsType,
|
||||
| 'conversationId'
|
||||
| 'deletedForEveryone'
|
||||
| 'sendStateByConversationId'
|
||||
|
@ -1466,7 +1475,7 @@ export function canReply(
|
|||
|
||||
export function canReact(
|
||||
message: Pick<
|
||||
MessageAttributesType,
|
||||
MessageWithUIFieldsType,
|
||||
| 'conversationId'
|
||||
| 'deletedForEveryone'
|
||||
| 'sendStateByConversationId'
|
||||
|
@ -1481,7 +1490,7 @@ export function canReact(
|
|||
|
||||
export function canDeleteForEveryone(
|
||||
message: Pick<
|
||||
MessageAttributesType,
|
||||
MessageWithUIFieldsType,
|
||||
'type' | 'deletedForEveryone' | 'sent_at' | 'sendStateByConversationId'
|
||||
>
|
||||
): boolean {
|
||||
|
@ -1501,7 +1510,7 @@ export function canDeleteForEveryone(
|
|||
}
|
||||
|
||||
export function canDownload(
|
||||
message: MessageAttributesType,
|
||||
message: MessageWithUIFieldsType,
|
||||
conversationSelector: GetConversationByIdType
|
||||
): boolean {
|
||||
if (isOutgoing(message)) {
|
||||
|
@ -1526,7 +1535,7 @@ export function canDownload(
|
|||
}
|
||||
|
||||
export function getLastChallengeError(
|
||||
message: Pick<MessageAttributesType, 'errors'>
|
||||
message: Pick<MessageWithUIFieldsType, 'errors'>
|
||||
): ShallowChallengeError | undefined {
|
||||
const { errors } = message;
|
||||
if (!errors) {
|
||||
|
|
|
@ -11994,4 +11994,4 @@
|
|||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-09-17T21:02:59.414Z"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue