Skip to content

Commit

Permalink
Group disparate status together, but show metadata if different
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 Mar 28, 2022
1 parent 23889ac commit a613ce0
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 126 deletions.
6 changes: 3 additions & 3 deletions ts/components/conversation/CallingNotification.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const story = storiesOf('Components/Conversation/CallingNotification', module);
const getCommonProps = () => ({
conversationId: 'fake-conversation-id',
i18n,
isNextItemCallingNotification: false,
messageId: 'fake-message-id',
nextItem: undefined,
now: Date.now(),
returnToActiveCall: action('returnToActiveCall'),
startCallingLobby: action('startCallingLobby'),
Expand Down Expand Up @@ -70,7 +70,7 @@ story.add('Two incoming direct calls back-to-back', () => {
<CallingNotification
{...getCommonProps()}
{...call1}
nextItem={{ type: 'callHistory', data: call2, timestamp: Date.now() }}
isNextItemCallingNotification
/>
<CallingNotification {...getCommonProps()} {...call2} />
</>
Expand Down Expand Up @@ -99,7 +99,7 @@ story.add('Two outgoing direct calls back-to-back', () => {
<CallingNotification
{...getCommonProps()}
{...call1}
nextItem={{ type: 'callHistory', data: call2, timestamp: Date.now() }}
isNextItemCallingNotification
/>
<CallingNotification {...getCommonProps()} {...call2} />
</>
Expand Down
7 changes: 3 additions & 4 deletions ts/components/conversation/CallingNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
} from '../../util/callingNotification';
import { missingCaseError } from '../../util/missingCaseError';
import { Tooltip, TooltipPlacement } from '../Tooltip';
import type { TimelineItemType } from './TimelineItem';
import * as log from '../../logging/log';

export type PropsActionsType = {
Expand All @@ -31,7 +30,7 @@ export type PropsActionsType = {
type PropsHousekeeping = {
i18n: LocalizerType;
conversationId: string;
nextItem: undefined | TimelineItemType;
isNextItemCallingNotification: boolean;
};

type PropsType = CallingNotificationType & PropsActionsType & PropsHousekeeping;
Expand Down Expand Up @@ -86,12 +85,12 @@ function renderCallingNotificationButton(
activeCallConversationId,
conversationId,
i18n,
nextItem,
isNextItemCallingNotification,
returnToActiveCall,
startCallingLobby,
} = props;

if (nextItem?.type === 'callHistory') {
if (isNextItemCallingNotification) {
return null;
}

Expand Down
13 changes: 11 additions & 2 deletions ts/components/conversation/Message.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,15 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
retryDeleteForEveryone: action('retryDeleteForEveryone'),
scrollToQuotedMessage: action('scrollToQuotedMessage'),
selectMessage: action('selectMessage'),
shouldCollapseAbove: isBoolean(overrideProps.shouldCollapseAbove)
? overrideProps.shouldCollapseAbove
: false,
shouldCollapseBelow: isBoolean(overrideProps.shouldCollapseBelow)
? overrideProps.shouldCollapseBelow
: false,
shouldHideMetadata: isBoolean(overrideProps.shouldHideMetadata)
? overrideProps.shouldHideMetadata
: false,
showContactDetail: action('showContactDetail'),
showContactModal: action('showContactModal'),
showExpiredIncomingTapToViewToast: action(
Expand Down Expand Up @@ -202,9 +211,9 @@ const renderMany = (propsArray: ReadonlyArray<Props>) =>
<Message
key={message.text}
{...message}
previousItem={createTimelineItem(propsArray[index - 1])}
shouldCollapseAbove={Boolean(propsArray[index - 1])}
item={createTimelineItem(message)}
nextItem={createTimelineItem(propsArray[index + 1])}
shouldCollapseBelow={Boolean(propsArray[index + 1])}
/>
));

Expand Down
74 changes: 32 additions & 42 deletions ts/components/conversation/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,6 @@ import { getCustomColorStyle } from '../../util/getCustomColorStyle';
import { offsetDistanceModifier } from '../../util/popperUtil';
import * as KeyboardLayout from '../../services/keyboardLayout';
import { StopPropagation } from '../StopPropagation';
import {
areMessagesInSameGroup,
UnreadIndicatorPlacement,
} from '../../util/timelineUtil';

type Trigger = {
handleContextClick: (event: React.MouseEvent<HTMLDivElement>) => void;
Expand Down Expand Up @@ -269,14 +265,14 @@ export type PropsHousekeeping = {
i18n: LocalizerType;
interactionMode: InteractionModeType;
item?: TimelineItemType;
nextItem?: TimelineItemType;
previousItem?: TimelineItemType;
renderAudioAttachment: (props: AudioAttachmentProps) => JSX.Element;
renderReactionPicker: (
props: React.ComponentProps<typeof SmartReactionPicker>
) => JSX.Element;
shouldCollapseAbove: boolean;
shouldCollapseBelow: boolean;
shouldHideMetadata: boolean;
theme: ThemeType;
unreadIndicatorPlacement?: undefined | UnreadIndicatorPlacement;
};

export type PropsActions = {
Expand Down Expand Up @@ -554,6 +550,7 @@ export class Message extends React.PureComponent<Props, State> {
attachments,
expirationLength,
expirationTimestamp,
shouldHideMetadata,
status,
text,
textDirection,
Expand All @@ -565,7 +562,7 @@ export class Message extends React.PureComponent<Props, State> {
!expirationLength &&
!expirationTimestamp &&
(!status || SENT_STATUSES.has(status)) &&
this.isCollapsedBelow()
shouldHideMetadata
) {
return MetadataPlacement.NotRendered;
}
Expand Down Expand Up @@ -688,34 +685,14 @@ export class Message extends React.PureComponent<Props, State> {
return isMessageRequestAccepted && !isBlocked;
}

private isCollapsedAbove(
{ item, previousItem, unreadIndicatorPlacement }: Readonly<Props> = this
.props
): boolean {
return areMessagesInSameGroup(
previousItem,
unreadIndicatorPlacement === UnreadIndicatorPlacement.JustAbove,
item
);
}

private isCollapsedBelow(
{ item, nextItem, unreadIndicatorPlacement }: Readonly<Props> = this.props
): boolean {
return areMessagesInSameGroup(
item,
unreadIndicatorPlacement === UnreadIndicatorPlacement.JustBelow,
nextItem
);
}

private shouldRenderAuthor(): boolean {
const { author, conversationType, direction } = this.props;
const { author, conversationType, direction, shouldCollapseAbove } =
this.props;
return Boolean(
direction === 'incoming' &&
conversationType === 'group' &&
author.title &&
!this.isCollapsedAbove()
!shouldCollapseAbove
);
}

Expand Down Expand Up @@ -850,6 +827,8 @@ export class Message extends React.PureComponent<Props, State> {
renderingContext,
showMessageDetail,
showVisualAttachment,
shouldCollapseAbove,
shouldCollapseBelow,
status,
text,
textPending,
Expand Down Expand Up @@ -925,10 +904,10 @@ export class Message extends React.PureComponent<Props, State> {
<ImageGrid
attachments={attachments}
withContentAbove={
isSticker || withContentAbove || this.isCollapsedAbove()
isSticker || withContentAbove || shouldCollapseAbove
}
withContentBelow={
isSticker || withContentBelow || this.isCollapsedBelow()
isSticker || withContentBelow || shouldCollapseBelow
}
isSticker={isSticker}
stickerSize={STICKER_SIZE}
Expand Down Expand Up @@ -1223,6 +1202,7 @@ export class Message extends React.PureComponent<Props, State> {
id,
quote,
scrollToQuotedMessage,
shouldCollapseAbove,
} = this.props;

if (!quote) {
Expand All @@ -1248,11 +1228,11 @@ export class Message extends React.PureComponent<Props, State> {
curveTopLeft = false;
curveTopRight = false;
} else if (isIncoming) {
curveTopLeft = !this.isCollapsedAbove();
curveTopLeft = !shouldCollapseAbove;
curveTopRight = true;
} else {
curveTopLeft = true;
curveTopRight = !this.isCollapsedAbove();
curveTopRight = !shouldCollapseAbove;
}

return (
Expand Down Expand Up @@ -1285,6 +1265,7 @@ export class Message extends React.PureComponent<Props, State> {
direction,
i18n,
storyReplyContext,
shouldCollapseAbove,
} = this.props;

if (!storyReplyContext) {
Expand All @@ -1299,11 +1280,11 @@ export class Message extends React.PureComponent<Props, State> {
curveTopLeft = false;
curveTopRight = false;
} else if (isIncoming) {
curveTopLeft = !this.isCollapsedAbove();
curveTopLeft = !shouldCollapseAbove;
curveTopRight = true;
} else {
curveTopLeft = true;
curveTopRight = !this.isCollapsedAbove();
curveTopRight = !shouldCollapseAbove;
}

return (
Expand Down Expand Up @@ -1400,6 +1381,7 @@ export class Message extends React.PureComponent<Props, State> {
direction,
getPreferredBadge,
i18n,
shouldCollapseBelow,
showContactModal,
theme,
} = this.props;
Expand All @@ -1415,7 +1397,7 @@ export class Message extends React.PureComponent<Props, State> {
this.hasReactions(),
})}
>
{this.isCollapsedBelow() ? (
{shouldCollapseBelow ? (
<AvatarSpacer size={GROUP_AVATAR_SIZE} />
) : (
<Avatar
Expand Down Expand Up @@ -2660,8 +2642,16 @@ export class Message extends React.PureComponent<Props, State> {
}

public override render(): JSX.Element | null {
const { author, attachments, direction, id, isSticker, timestamp } =
this.props;
const {
author,
attachments,
direction,
id,
isSticker,
shouldCollapseAbove,
shouldCollapseBelow,
timestamp,
} = this.props;
const { expired, expiring, imageBroken, isSelected } = this.state;

// This id is what connects our triple-dot click with our associated pop-up menu.
Expand All @@ -2681,8 +2671,8 @@ export class Message extends React.PureComponent<Props, State> {
className={classNames(
'module-message',
`module-message--${direction}`,
this.isCollapsedAbove() && 'module-message--collapsed-above',
this.isCollapsedBelow() && 'module-message--collapsed-below',
shouldCollapseAbove && 'module-message--collapsed-above',
shouldCollapseBelow && 'module-message--collapsed-below',
isSelected ? 'module-message--selected' : null,
expiring ? 'module-message--expired' : null
)}
Expand Down
3 changes: 3 additions & 0 deletions ts/components/conversation/MessageDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ export class MessageDetail extends React.Component<Props> {
replyToMessage={replyToMessage}
retryDeleteForEveryone={retryDeleteForEveryone}
retrySend={retrySend}
shouldCollapseAbove={false}
shouldCollapseBelow={false}
shouldHideMetadata={false}
showForwardMessageModal={showForwardMessageModal}
scrollToQuotedMessage={() => {
log.warn('MessageDetail: scrollToQuotedMessage called!');
Expand Down
3 changes: 3 additions & 0 deletions ts/components/conversation/Quote.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ const defaultMessageProps: MessagesProps = {
retryDeleteForEveryone: action('default--retryDeleteForEveryone'),
scrollToQuotedMessage: action('default--scrollToQuotedMessage'),
selectMessage: action('default--selectMessage'),
shouldCollapseAbove: false,
shouldCollapseBelow: false,
shouldHideMetadata: false,
showContactDetail: action('default--showContactDetail'),
showContactModal: action('default--showContactModal'),
showExpiredIncomingTapToViewToast: action(
Expand Down
10 changes: 5 additions & 5 deletions ts/components/conversation/Timeline.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -421,25 +421,21 @@ const renderItem = ({
messageId,
containerElementRef,
containerWidthBreakpoint,
isOldestTimelineItem,
}: {
messageId: string;
containerElementRef: React.RefObject<HTMLElement>;
containerWidthBreakpoint: WidthBreakpoint;
isOldestTimelineItem: boolean;
}) => (
<TimelineItem
getPreferredBadge={() => undefined}
id=""
isOldestTimelineItem={isOldestTimelineItem}
isSelected={false}
renderEmojiPicker={() => <div />}
renderReactionPicker={() => <div />}
item={items[messageId]}
previousItem={undefined}
nextItem={undefined}
i18n={i18n}
interactionMode="keyboard"
isNextItemCallingNotification={false}
theme={ThemeType.light}
containerElementRef={containerElementRef}
containerWidthBreakpoint={containerWidthBreakpoint}
Expand All @@ -449,6 +445,10 @@ const renderItem = ({
<div>*UniversalTimerNotification*</div>
)}
renderAudioAttachment={() => <div>*AudioAttachment*</div>}
shouldCollapseAbove={false}
shouldCollapseBelow={false}
shouldHideMetadata={false}
shouldRenderDateHeader={false}
{...actions()}
/>
);
Expand Down
9 changes: 6 additions & 3 deletions ts/components/conversation/TimelineItem.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const getDefaultProps = () => ({
conversationId: 'conversation-id',
getPreferredBadge: () => undefined,
id: 'asdf',
isOldestTimelineItem: false,
isNextItemCallingNotification: false,
isSelected: false,
interactionMode: 'keyboard' as const,
theme: ThemeType.light,
Expand Down Expand Up @@ -94,8 +94,11 @@ const getDefaultProps = () => ({
showIdentity: action('showIdentity'),
startCallingLobby: action('startCallingLobby'),
returnToActiveCall: action('returnToActiveCall'),
previousItem: undefined,
nextItem: undefined,
shouldCollapseAbove: false,
shouldCollapseBelow: false,
shouldHideMetadata: false,
shouldRenderDateHeader: false,

now: Date.now(),

renderContact,
Expand Down

0 comments on commit a613ce0

Please sign in to comment.