Skip to content

Commit

Permalink
Remember message Read More state when scrolling in virtualized container
Browse files Browse the repository at this point in the history
Co-authored-by: Scott Nonnenberg <scott@signal.org>
  • Loading branch information
automated-signal and scottnonnenberg-signal committed Nov 12, 2021
1 parent 2ee5526 commit 5c14b7f
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 72 deletions.
1 change: 1 addition & 0 deletions ts/components/conversation/Message.stories.tsx
Expand Up @@ -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'),
Expand Down
8 changes: 8 additions & 0 deletions ts/components/conversation/Message.tsx
Expand Up @@ -131,6 +131,7 @@ export type PropsData = {
conversationColor: ConversationColorType;
customColor?: CustomColorType;
conversationId: string;
displayLimit?: number;
text?: string;
textPending?: boolean;
isSticker?: boolean;
Expand Down Expand Up @@ -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: (
Expand Down Expand Up @@ -1227,7 +1229,10 @@ export class Message extends React.PureComponent<Props, State> {
bodyRanges,
deletedForEveryone,
direction,
displayLimit,
i18n,
id,
messageExpanded,
onHeightChange,
openConversation,
status,
Expand Down Expand Up @@ -1261,7 +1266,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 || ''}
Expand Down
3 changes: 3 additions & 0 deletions ts/components/conversation/MessageBodyReadMore.stories.tsx
Expand Up @@ -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 || ''),
});
Expand Down
21 changes: 17 additions & 4 deletions ts/components/conversation/MessageBodyReadMore.tsx
@@ -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,
Expand All @@ -16,6 +17,9 @@ export type Props = Pick<
| 'bodyRanges'
| 'openConversation'
> & {
id: string;
displayLimit?: number;
messageExpanded: (id: string, displayLimit: number) => unknown;
onHeightChange: () => unknown;
};

Expand Down Expand Up @@ -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;

Expand Down
2 changes: 2 additions & 0 deletions ts/components/conversation/MessageDetail.tsx
Expand Up @@ -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!')
Expand All @@ -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}
Expand Down
3 changes: 2 additions & 1 deletion ts/components/conversation/Quote.stories.tsx
Expand Up @@ -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: [],
Expand Down
1 change: 1 addition & 0 deletions ts/components/conversation/Timeline.stories.tsx
Expand Up @@ -329,6 +329,7 @@ const actions = () => ({
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
markViewed: action('markViewed'),
messageExpanded: action('messageExpanded'),
showVisualAttachment: action('showVisualAttachment'),
downloadAttachment: action('downloadAttachment'),
displayTapToViewMessage: action('displayTapToViewMessage'),
Expand Down
1 change: 1 addition & 0 deletions ts/components/conversation/Timeline.tsx
Expand Up @@ -269,6 +269,7 @@ const getActions = createSelector(
'showContactModal',
'kickOffAttachmentDownload',
'markAttachmentAsCorrupted',
'messageExpanded',
'showVisualAttachment',
'downloadAttachment',
'displayTapToViewMessage',
Expand Down
1 change: 1 addition & 0 deletions ts/components/conversation/TimelineItem.stories.tsx
Expand Up @@ -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'),
Expand Down
53 changes: 50 additions & 3 deletions ts/state/ducks/conversations.ts
Expand Up @@ -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];
Expand Down Expand Up @@ -235,7 +238,7 @@ type MessageMetricsType = {
};

export type MessageLookupType = {
[key: string]: MessageAttributesType;
[key: string]: MessageWithUIFieldsType;
};
export type ConversationMessageType = {
heightChangeMessageIds: Array<string>;
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -738,6 +749,7 @@ export type ConversationActionType =
| MessageStoppedByMissingVerificationActionType
| MessageChangedActionType
| MessageDeletedActionType
| MessageExpandedActionType
| MessageSelectedActionType
| MessageSizeChangedActionType
| MessagesAddedActionType
Expand Down Expand Up @@ -801,6 +813,7 @@ export const actions = {
messageStoppedByMissingVerification,
messageChanged,
messageDeleted,
messageExpanded,
messageSizeChanged,
messagesAdded,
messagesReset,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2360,7 +2385,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;
}
Expand All @@ -2378,7 +2403,10 @@ export function reducer(
...state,
messagesLookup: {
...state.messagesLookup,
[id]: data,
[id]: {
...data,
displayLimit: existingMessage.displayLimit,
},
},
messagesByConversation: {
...state.messagesByConversation,
Expand All @@ -2389,6 +2417,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;

Expand Down

0 comments on commit 5c14b7f

Please sign in to comment.