diff --git a/ts/components/App.tsx b/ts/components/App.tsx index 4e22441c6..b06797321 100644 --- a/ts/components/App.tsx +++ b/ts/components/App.tsx @@ -81,6 +81,7 @@ export const App = ({ requestVerification, selectedConversationId, selectedMessage, + selectedMessageSource, showConversation, showWhatsNewModal, theme, @@ -117,6 +118,7 @@ export const App = ({ renderLeftPane={renderLeftPane} selectedConversationId={selectedConversationId} selectedMessage={selectedMessage} + selectedMessageSource={selectedMessageSource} showConversation={showConversation} showWhatsNewModal={showWhatsNewModal} /> diff --git a/ts/components/Inbox.tsx b/ts/components/Inbox.tsx index cb268b62d..d45e53fad 100644 --- a/ts/components/Inbox.tsx +++ b/ts/components/Inbox.tsx @@ -15,6 +15,7 @@ import { ToastStickerPackInstallFailed } from './ToastStickerPackInstallFailed'; import { WhatsNewLink } from './WhatsNewLink'; import { showToast } from '../util/showToast'; import { strictAssert } from '../util/assert'; +import { SelectedMessageSource } from '../state/ducks/conversationsEnums'; export type PropsType = { hasInitialLoadCompleted: boolean; @@ -24,6 +25,7 @@ export type PropsType = { renderLeftPane: () => JSX.Element; selectedConversationId?: string; selectedMessage?: string; + selectedMessageSource?: SelectedMessageSource; showConversation: ShowConversationType; showWhatsNewModal: () => unknown; }; @@ -36,6 +38,7 @@ export const Inbox = ({ renderLeftPane, selectedConversationId, selectedMessage, + selectedMessageSource, showConversation, showWhatsNewModal, }: PropsType): JSX.Element => { @@ -86,13 +89,21 @@ export const Inbox = ({ setPrevConversation(conversation); conversation.trigger('opened', selectedMessage); - } else if (selectedMessage) { + } else if ( + selectedMessage && + selectedMessageSource !== SelectedMessageSource.Focus + ) { conversation.trigger('scroll-to-message', selectedMessage); } // Make sure poppers are positioned properly window.dispatchEvent(new Event('resize')); - }, [prevConversation, selectedConversationId, selectedMessage]); + }, [ + prevConversation, + selectedConversationId, + selectedMessage, + selectedMessageSource, + ]); // Whenever the selectedConversationId is cleared we should also ensure // that prevConversation is cleared too. diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index fcdf74cfb..f9c4eac21 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -72,6 +72,7 @@ import { ComposerStep, ConversationVerificationState, OneTimeModalState, + SelectedMessageSource, } from './conversationsEnums'; import { markViewed as messageUpdaterMarkViewed } from '../../services/MessageUpdater'; import { useBoundActions } from '../../hooks/useBoundActions'; @@ -341,8 +342,9 @@ export type ConversationsStateType = { conversationsByGroupId: ConversationLookupType; conversationsByUsername: ConversationLookupType; selectedConversationId?: string; - selectedMessage?: string; + selectedMessage: string | undefined; selectedMessageCounter: number; + selectedMessageSource: SelectedMessageSource | undefined; selectedConversationTitle?: string; selectedConversationPanelDepth: number; showArchived: boolean; @@ -2118,7 +2120,9 @@ export function getEmptyState(): ConversationsStateType { verificationDataByConversation: {}, messagesByConversation: {}, messagesLookup: {}, + selectedMessage: undefined, selectedMessageCounter: 0, + selectedMessageSource: undefined, showArchived: false, selectedConversationTitle: '', selectedConversationPanelDepth: 0, @@ -2605,6 +2609,7 @@ export function reducer( ...state, selectedMessage: messageId, selectedMessageCounter: state.selectedMessageCounter + 1, + selectedMessageSource: SelectedMessageSource.Focus, }; } if (action.type === CONVERSATION_STOPPED_BY_MISSING_VERIFICATION) { @@ -2750,6 +2755,7 @@ export function reducer( ? { selectedMessage: scrollToMessageId, selectedMessageCounter: state.selectedMessageCounter + 1, + selectedMessageSource: SelectedMessageSource.Reset, } : {}), messagesLookup: { @@ -2842,6 +2848,7 @@ export function reducer( ...state, selectedMessage: messageId, selectedMessageCounter: state.selectedMessageCounter + 1, + selectedMessageSource: SelectedMessageSource.NavigateToMessage, messagesByConversation: { ...messagesByConversation, [conversationId]: { @@ -3127,6 +3134,8 @@ export function reducer( return { ...state, selectedMessage: undefined, + selectedMessageCounter: 0, + selectedMessageSource: undefined, }; } if (action.type === 'CLEAR_UNREAD_METRICS') { @@ -3161,6 +3170,7 @@ export function reducer( ...omit(state, 'contactSpoofingReview'), selectedConversationId: id, selectedMessage: messageId, + selectedMessageSource: SelectedMessageSource.NavigateToMessage, }; if (switchToAssociatedView && id) { diff --git a/ts/state/ducks/conversationsEnums.ts b/ts/state/ducks/conversationsEnums.ts index 4cbc835b6..4c4aad3dc 100644 --- a/ts/state/ducks/conversationsEnums.ts +++ b/ts/state/ducks/conversationsEnums.ts @@ -23,3 +23,9 @@ export enum ConversationVerificationState { PendingVerification = 'PendingVerification', VerificationCancelled = 'VerificationCancelled', } + +export enum SelectedMessageSource { + Reset = 'Reset', + NavigateToMessage = 'NavigateToMessage', + Focus = 'Focus', +} diff --git a/ts/state/smart/App.tsx b/ts/state/smart/App.tsx index aef2c05f1..83b204b24 100644 --- a/ts/state/smart/App.tsx +++ b/ts/state/smart/App.tsx @@ -85,6 +85,7 @@ const mapStateToProps = (state: StateType) => { }, selectedConversationId: state.conversations.selectedConversationId, selectedMessage: state.conversations.selectedMessage, + selectedMessageSource: state.conversations.selectedMessageSource, theme: getTheme(state), executeMenuRole: (role: MenuItemConstructorOptions['role']): void => {