signal-desktop/ts/state/smart/TimelineItem.tsx

247 lines
8.7 KiB
TypeScript
Raw Normal View History

2023-01-03 19:55:46 +00:00
// Copyright 2019 Signal Messenger, LLC
2020-10-30 20:34:04 +00:00
// SPDX-License-Identifier: AGPL-3.0-only
import type { RefObject } from 'react';
import React, { useCallback, memo } from 'react';
import { useSelector } from 'react-redux';
import { TimelineItem } from '../../components/conversation/TimelineItem';
import type { WidthBreakpoint } from '../../components/_util';
import { useConversationsActions } from '../ducks/conversations';
import { useComposerActions } from '../ducks/composer';
import { useGlobalModalActions } from '../ducks/globalModals';
import { useAccountsActions } from '../ducks/accounts';
import { useLightboxActions } from '../ducks/lightbox';
import { useStoriesActions } from '../ducks/stories';
import { useCallingActions } from '../ducks/calling';
2021-11-17 21:11:46 +00:00
import { getPreferredBadgeSelector } from '../selectors/badges';
2023-04-03 20:16:27 +00:00
import {
getIntl,
getInteractionMode,
getTheme,
getPlatform,
} from '../selectors/user';
2024-04-30 13:24:21 +00:00
import {
getTargetedMessage,
getCheckServiceIdEquivalence,
} from '../selectors/conversations';
2024-02-27 16:01:25 +00:00
import { useTimelineItem } from '../selectors/timeline';
import {
areMessagesInSameGroup,
shouldCurrentMessageHideMetadata,
UnreadIndicatorPlacement,
} from '../../util/timelineUtil';
2020-09-09 02:25:05 +00:00
import { SmartContactName } from './ContactName';
2021-06-01 20:45:43 +00:00
import { SmartUniversalTimerNotification } from './UniversalTimerNotification';
import { isSameDay } from '../../util/timestamp';
import { renderAudioAttachment } from './renderAudioAttachment';
import { renderEmojiPicker } from './renderEmojiPicker';
import { renderReactionPicker } from './renderReactionPicker';
2024-03-12 16:29:31 +00:00
import type { MessageRequestState } from '../../components/conversation/MessageRequestActionsConfirmation';
2020-09-09 02:25:05 +00:00
2024-02-27 16:01:25 +00:00
export type SmartTimelineItemProps = {
containerElementRef: RefObject<HTMLElement>;
containerWidthBreakpoint: WidthBreakpoint;
conversationId: string;
2024-03-12 16:29:31 +00:00
isBlocked: boolean;
2024-04-12 17:07:57 +00:00
isGroup: boolean;
2022-01-26 23:05:26 +00:00
isOldestTimelineItem: boolean;
messageId: string;
nextMessageId: undefined | string;
previousMessageId: undefined | string;
unreadIndicatorPlacement: undefined | UnreadIndicatorPlacement;
};
function renderContact(contactId: string): JSX.Element {
return <SmartContactName contactId={contactId} />;
2020-09-09 02:25:05 +00:00
}
2021-06-01 20:45:43 +00:00
function renderUniversalTimerNotification(): JSX.Element {
return <SmartUniversalTimerNotification />;
}
export const SmartTimelineItem = memo(function SmartTimelineItem(
props: SmartTimelineItemProps
): JSX.Element {
const {
containerElementRef,
containerWidthBreakpoint,
conversationId,
2024-03-12 16:29:31 +00:00
isBlocked,
2024-04-12 17:07:57 +00:00
isGroup,
2022-01-26 23:05:26 +00:00
isOldestTimelineItem,
messageId,
nextMessageId,
previousMessageId,
unreadIndicatorPlacement,
} = props;
const i18n = useSelector(getIntl);
const getPreferredBadge = useSelector(getPreferredBadgeSelector);
const interactionMode = useSelector(getInteractionMode);
const theme = useSelector(getTheme);
2023-04-03 20:16:27 +00:00
const platform = useSelector(getPlatform);
2024-02-27 16:01:25 +00:00
const item = useTimelineItem(messageId, conversationId);
const previousItem = useTimelineItem(previousMessageId, conversationId);
const nextItem = useTimelineItem(nextMessageId, conversationId);
2023-03-20 22:23:53 +00:00
const targetedMessage = useSelector(getTargetedMessage);
const isTargeted = Boolean(
targetedMessage && messageId === targetedMessage.id
);
2024-04-30 13:24:21 +00:00
const checkServiceIdEquivalence = useSelector(getCheckServiceIdEquivalence);
2019-11-07 21:36:16 +00:00
const isNextItemCallingNotification = nextItem?.type === 'callHistory';
const shouldCollapseAbove = areMessagesInSameGroup(
previousItem,
unreadIndicatorPlacement === UnreadIndicatorPlacement.JustAbove,
item
);
const shouldCollapseBelow = areMessagesInSameGroup(
item,
unreadIndicatorPlacement === UnreadIndicatorPlacement.JustBelow,
nextItem
);
const shouldHideMetadata = shouldCurrentMessageHideMetadata(
shouldCollapseBelow,
item,
nextItem
);
const shouldRenderDateHeader =
isOldestTimelineItem ||
Boolean(
item &&
previousItem &&
// This comparison avoids strange header behavior for out-of-order messages.
item.timestamp > previousItem.timestamp &&
!isSameDay(previousItem.timestamp, item.timestamp)
);
const {
blockGroupLinkRequests,
2023-03-20 22:23:53 +00:00
clearTargetedMessage: clearSelectedMessage,
doubleCheckMissingQuoteReference,
kickOffAttachmentDownload,
markAttachmentAsCorrupted,
messageExpanded,
openGiftBadge,
pushPanelForConversation,
copyMessageText,
retryDeleteForEveryone,
retryMessageSend,
saveAttachment,
2023-03-20 22:23:53 +00:00
targetMessage,
toggleSelectMessage,
setMessageToEdit,
showConversation,
showExpiredIncomingTapToViewToast,
showExpiredOutgoingTapToViewToast,
showSpoiler,
startConversation,
} = useConversationsActions();
const { reactToMessage, scrollToQuotedMessage, setQuoteByMessageId } =
useComposerActions();
const {
showContactModal,
2023-03-27 23:48:57 +00:00
showEditHistoryModal,
2024-03-12 16:29:31 +00:00
toggleMessageRequestActionsConfirmation,
toggleDeleteMessagesModal,
2024-03-26 19:48:33 +00:00
toggleEditNicknameAndNoteModal,
2023-03-20 22:23:53 +00:00
toggleForwardMessagesModal,
toggleSafetyNumberModal,
} = useGlobalModalActions();
const { checkForAccount } = useAccountsActions();
const { showLightbox, showLightboxForViewOnceMedia } = useLightboxActions();
const { viewStory } = useStoriesActions();
const {
onOutgoingAudioCallInConversation,
onOutgoingVideoCallInConversation,
returnToActiveCall,
} = useCallingActions();
const onOpenEditNicknameAndNoteModal = useCallback(
(contactId: string) => {
toggleEditNicknameAndNoteModal({ conversationId: contactId });
},
[toggleEditNicknameAndNoteModal]
);
2024-03-26 19:48:33 +00:00
2024-03-12 16:29:31 +00:00
const onOpenMessageRequestActionsConfirmation = useCallback(
(state: MessageRequestState) => {
toggleMessageRequestActionsConfirmation({ conversationId, state });
},
[conversationId, toggleMessageRequestActionsConfirmation]
);
return (
<TimelineItem
item={item}
id={messageId}
2024-04-30 13:24:21 +00:00
checkServiceIdEquivalence={checkServiceIdEquivalence}
containerElementRef={containerElementRef}
containerWidthBreakpoint={containerWidthBreakpoint}
conversationId={conversationId}
getPreferredBadge={getPreferredBadge}
isNextItemCallingNotification={isNextItemCallingNotification}
2023-03-20 22:23:53 +00:00
isTargeted={isTargeted}
renderAudioAttachment={renderAudioAttachment}
renderContact={renderContact}
renderEmojiPicker={renderEmojiPicker}
renderReactionPicker={renderReactionPicker}
renderUniversalTimerNotification={renderUniversalTimerNotification}
shouldCollapseAbove={shouldCollapseAbove}
shouldCollapseBelow={shouldCollapseBelow}
shouldHideMetadata={shouldHideMetadata}
shouldRenderDateHeader={shouldRenderDateHeader}
2023-03-27 23:48:57 +00:00
showEditHistoryModal={showEditHistoryModal}
i18n={i18n}
interactionMode={interactionMode}
2024-03-12 16:29:31 +00:00
isBlocked={isBlocked}
2024-04-12 17:07:57 +00:00
isGroup={isGroup}
theme={theme}
2023-04-03 20:16:27 +00:00
platform={platform}
blockGroupLinkRequests={blockGroupLinkRequests}
checkForAccount={checkForAccount}
2023-03-20 22:23:53 +00:00
clearTargetedMessage={clearSelectedMessage}
doubleCheckMissingQuoteReference={doubleCheckMissingQuoteReference}
kickOffAttachmentDownload={kickOffAttachmentDownload}
markAttachmentAsCorrupted={markAttachmentAsCorrupted}
messageExpanded={messageExpanded}
openGiftBadge={openGiftBadge}
pushPanelForConversation={pushPanelForConversation}
reactToMessage={reactToMessage}
copyMessageText={copyMessageText}
2024-03-26 19:48:33 +00:00
onOpenEditNicknameAndNoteModal={onOpenEditNicknameAndNoteModal}
2024-03-12 16:29:31 +00:00
onOpenMessageRequestActionsConfirmation={
onOpenMessageRequestActionsConfirmation
}
onOutgoingAudioCallInConversation={onOutgoingAudioCallInConversation}
onOutgoingVideoCallInConversation={onOutgoingVideoCallInConversation}
retryDeleteForEveryone={retryDeleteForEveryone}
retryMessageSend={retryMessageSend}
returnToActiveCall={returnToActiveCall}
saveAttachment={saveAttachment}
scrollToQuotedMessage={scrollToQuotedMessage}
2023-03-20 22:23:53 +00:00
targetMessage={targetMessage}
setQuoteByMessageId={setQuoteByMessageId}
setMessageToEdit={setMessageToEdit}
showContactModal={showContactModal}
showConversation={showConversation}
showExpiredIncomingTapToViewToast={showExpiredIncomingTapToViewToast}
showExpiredOutgoingTapToViewToast={showExpiredOutgoingTapToViewToast}
showLightbox={showLightbox}
showLightboxForViewOnceMedia={showLightboxForViewOnceMedia}
showSpoiler={showSpoiler}
startConversation={startConversation}
toggleDeleteMessagesModal={toggleDeleteMessagesModal}
2023-03-20 22:23:53 +00:00
toggleForwardMessagesModal={toggleForwardMessagesModal}
toggleSafetyNumberModal={toggleSafetyNumberModal}
viewStory={viewStory}
2023-03-20 22:23:53 +00:00
toggleSelectMessage={toggleSelectMessage}
/>
);
});