diff --git a/src/components/middle/ScrollDownButton.tsx b/src/components/middle/ScrollDownButton.tsx index 250a0fa78..141382c0e 100644 --- a/src/components/middle/ScrollDownButton.tsx +++ b/src/components/middle/ScrollDownButton.tsx @@ -27,7 +27,7 @@ type StateProps = { unreadCount?: number; }; -type DispatchProps = Pick; +type DispatchProps = Pick; const FOCUS_MARGIN = 20; @@ -36,7 +36,7 @@ const ScrollDownButton: FC = ({ canPost, messageListType, unreadCount, - focusLastMessage, + focusNextReply, }) => { const lang = useLang(); // eslint-disable-next-line no-null/no-null @@ -48,7 +48,7 @@ const ScrollDownButton: FC = ({ } if (messageListType === 'thread') { - focusLastMessage(); + focusNextReply(); } else { const messagesContainer = elementRef.current!.parentElement!.querySelector('.MessageList')!; const messageElements = messagesContainer.querySelectorAll('.message-list-item'); @@ -59,7 +59,7 @@ const ScrollDownButton: FC = ({ fastSmoothScroll(messagesContainer, lastMessageElement, 'end', FOCUS_MARGIN); } - }, [isShown, messageListType, focusLastMessage]); + }, [isShown, messageListType, focusNextReply]); const fabClassName = buildClassName( 'ScrollDownButton', @@ -101,5 +101,5 @@ export default memo(withGlobal( unreadCount: chat && threadId === MAIN_THREAD_ID && messageListType === 'thread' ? chat.unreadCount : undefined, }; }, - (setGlobal, actions): DispatchProps => pick(actions, ['focusLastMessage']), + (setGlobal, actions): DispatchProps => pick(actions, ['focusNextReply']), )(ScrollDownButton)); diff --git a/src/components/middle/message/Message.tsx b/src/components/middle/message/Message.tsx index 853d0fe0a..f87d812e0 100644 --- a/src/components/middle/message/Message.tsx +++ b/src/components/middle/message/Message.tsx @@ -416,8 +416,10 @@ const Message: FC = ({ }, [botSender, openUserInfo]); const handleReplyClick = useCallback((): void => { - focusMessage({ chatId, threadId, messageId: message.replyToMessageId }); - }, [focusMessage, chatId, threadId, message.replyToMessageId]); + focusMessage({ + chatId, threadId, messageId: message.replyToMessageId, replyMessageId: messageId, + }); + }, [focusMessage, chatId, threadId, message.replyToMessageId, messageId]); const handleMediaClick = useCallback((): void => { openMediaViewer({ diff --git a/src/global/types.ts b/src/global/types.ts index b10a624e4..19e8260df 100644 --- a/src/global/types.ts +++ b/src/global/types.ts @@ -58,6 +58,7 @@ export interface Thread { noWebPage?: boolean; threadInfo?: ApiThreadInfo; firstMessageId?: number; + replyStack?: number[]; } export type GlobalState = { @@ -424,7 +425,7 @@ export type ActionTypes = ( 'openTelegramLink' | 'openChatByUsername' | 'requestThreadInfoUpdate' | 'setScrollOffset' | 'unpinAllMessages' | 'setReplyingToId' | 'setEditingId' | 'editLastMessage' | 'saveDraft' | 'clearDraft' | 'loadPinnedMessages' | 'loadMessageLink' | 'toggleMessageWebPage' | 'replyToNextMessage' | 'deleteChatUser' | 'deleteChat' | - 'reportMessages' | + 'reportMessages' | 'focusNextReply' | // scheduled messages 'loadScheduledHistory' | 'sendScheduledMessages' | 'rescheduleMessage' | 'deleteScheduledMessages' | // poll result diff --git a/src/modules/actions/ui/chats.ts b/src/modules/actions/ui/chats.ts index 93768ad56..004a4f797 100644 --- a/src/modules/actions/ui/chats.ts +++ b/src/modules/actions/ui/chats.ts @@ -1,7 +1,6 @@ import { addReducer, setGlobal } from '../../../lib/teact/teactn'; import { - exitMessageSelectMode, - updateCurrentMessageList, + exitMessageSelectMode, replaceThreadParam, updateCurrentMessageList, } from '../../reducers'; import { selectCurrentMessageList } from '../../selectors'; import { closeLocalTextSearch } from './localSearch'; @@ -19,6 +18,7 @@ addReducer('openChat', (global, actions, payload) => { || currentMessageList.threadId !== threadId || currentMessageList.type !== type )) { + global = replaceThreadParam(global, id, threadId, 'replyStack', []); global = exitMessageSelectMode(global); global = closeLocalTextSearch(global); diff --git a/src/modules/actions/ui/messages.ts b/src/modules/actions/ui/messages.ts index 7231c7266..0f9460162 100644 --- a/src/modules/actions/ui/messages.ts +++ b/src/modules/actions/ui/messages.ts @@ -21,7 +21,7 @@ import { selectChatMessages, selectAllowedMessageActions, selectMessageIdsByGroupId, - selectForwardedMessageIdsByGroupId, selectIsViewportNewest, selectReplyingToId, + selectForwardedMessageIdsByGroupId, selectIsViewportNewest, selectReplyingToId, selectReplyStack, } from '../../selectors'; import { findLast } from '../../../util/iteratees'; import { IS_TOUCH_ENV } from '../../../util/environment'; @@ -240,9 +240,39 @@ addReducer('focusLastMessage', (global, actions) => { }); }); +addReducer('focusNextReply', (global, actions) => { + const currentMessageList = selectCurrentMessageList(global); + if (!currentMessageList) { + return undefined; + } + + const { chatId, threadId } = currentMessageList; + + const replyStack = selectReplyStack(global, chatId, threadId); + + if (!replyStack || replyStack.length === 0) { + actions.focusLastMessage(); + } else { + const messageId = replyStack.pop(); + + global = replaceThreadParam(global, chatId, threadId, 'replyStack', [...replyStack]); + + setGlobal(global); + + actions.focusMessage({ + chatId, + threadId, + messageId, + }); + } + + return undefined; +}); + addReducer('focusMessage', (global, actions, payload) => { const { chatId, threadId = MAIN_THREAD_ID, messageListType = 'thread', noHighlight, groupedId, groupedChatId, + replyMessageId, } = payload!; let { messageId } = payload!; @@ -275,6 +305,11 @@ addReducer('focusMessage', (global, actions, payload) => { global = updateFocusedMessage(global, chatId, messageId, noHighlight); global = updateFocusDirection(global, undefined); + if (replyMessageId) { + const replyStack = selectReplyStack(global, chatId, threadId) || []; + global = replaceThreadParam(global, chatId, threadId, 'replyStack', [...replyStack, replyMessageId]); + } + if (shouldSwitchChat) { global = updateFocusDirection(global, FocusDirection.Static); } diff --git a/src/modules/selectors/messages.ts b/src/modules/selectors/messages.ts index 241428319..85e2ee268 100644 --- a/src/modules/selectors/messages.ts +++ b/src/modules/selectors/messages.ts @@ -150,6 +150,10 @@ export function selectFirstMessageId(global: GlobalState, chatId: number, thread return selectThreadParam(global, chatId, threadId, 'firstMessageId'); } +export function selectReplyStack(global: GlobalState, chatId: number, threadId: number) { + return selectThreadParam(global, chatId, threadId, 'replyStack'); +} + export function selectThreadOriginChat(global: GlobalState, chatId: number, threadId: number) { if (threadId === MAIN_THREAD_ID) { return selectChat(global, chatId);