diff --git a/src/components/middle/MiddleHeader.tsx b/src/components/middle/MiddleHeader.tsx index 3a97c2def..784f4b65b 100644 --- a/src/components/middle/MiddleHeader.tsx +++ b/src/components/middle/MiddleHeader.tsx @@ -92,6 +92,7 @@ type StateProps = { isChatWithSelf?: boolean; lastSyncTime?: number; hasButtonInHeader?: boolean; + hasReachedFocusedMessage?: boolean; shouldSkipHistoryAnimations?: boolean; currentTransitionKey: number; connectionState?: GlobalState['connectionState']; @@ -121,6 +122,7 @@ const MiddleHeader: FC = ({ shouldSkipHistoryAnimations, currentTransitionKey, connectionState, + hasReachedFocusedMessage, isSyncing, }) => { const { @@ -129,6 +131,7 @@ const MiddleHeader: FC = ({ focusMessage, openChat, openPreviousChat, + setReachedFocusedMessage, loadPinnedMessages, toggleLeftColumn, exitMessageSelectMode, @@ -136,6 +139,7 @@ const MiddleHeader: FC = ({ const lang = useLang(); const isBackButtonActive = useRef(true); + const [isWaitingForPinnedMessageFocus, setWaitingForPinnedMessageFocus] = useState(false); const { isTablet } = useAppLayout(); const [pinnedMessageIndex, setPinnedMessageIndex] = useState(0); @@ -157,8 +161,22 @@ const MiddleHeader: FC = ({ // Reset pinned index when switching chats and pinning/unpinning useEffect(() => { setPinnedMessageIndex(0); + setWaitingForPinnedMessageFocus(false); }, [pinnedMessageIds]); + useEffect(() => { + if (hasReachedFocusedMessage && isWaitingForPinnedMessageFocus) { + setReachedFocusedMessage({ hasReached: false }); + setWaitingForPinnedMessageFocus(false); + + const newIndex = cycleRestrict(pinnedMessagesCount || 1, pinnedMessageIndex + 1); + setPinnedMessageIndex(newIndex); + } + }, [ + hasReachedFocusedMessage, isWaitingForPinnedMessageFocus, pinnedMessageIndex, pinnedMessagesCount, + setReachedFocusedMessage, + ]); + useEnsureMessage(chatId, pinnedMessageId, pinnedMessage); const { width: windowWidth } = useWindowSize(); @@ -184,10 +202,9 @@ const MiddleHeader: FC = ({ chatId: pinnedMessage.chatId, threadId, messageId: pinnedMessage.id, noForumTopicPanel: true, }); - const newIndex = cycleRestrict(pinnedMessagesCount || 1, pinnedMessageIndex + 1); - setPinnedMessageIndex(newIndex); + setWaitingForPinnedMessageFocus(true); } - }, [pinnedMessage, focusMessage, threadId, pinnedMessagesCount, pinnedMessageIndex]); + }, [pinnedMessage, focusMessage, threadId]); const handleAllPinnedClick = useCallback(() => { openChat({ id: chatId, threadId, type: 'pinned' }); @@ -492,6 +509,7 @@ export default memo(withGlobal( ); const shouldSendJoinRequest = Boolean(chat?.isNotJoined && chat.isJoinRequest); const typingStatus = selectThreadParam(global, chatId, threadId, 'typingStatus'); + const focusedMessage = selectTabState(global).focusedMessage; const state: StateProps = { typingStatus, @@ -508,6 +526,7 @@ export default memo(withGlobal( connectionState: global.connectionState, isSyncing: global.isSyncing, hasButtonInHeader: canStartBot || canRestartBot || canSubscribe || shouldSendJoinRequest, + hasReachedFocusedMessage: !focusedMessage || focusedMessage.hasReachedMessage, }; const messagesById = selectChatMessages(global, chatId); diff --git a/src/components/middle/message/hooks/useFocusMessage.ts b/src/components/middle/message/hooks/useFocusMessage.ts index b7cf7adf7..1c2d54a01 100644 --- a/src/components/middle/message/hooks/useFocusMessage.ts +++ b/src/components/middle/message/hooks/useFocusMessage.ts @@ -1,3 +1,5 @@ +import { getActions } from '../../../../global'; + import type { FocusDirection } from '../../../../types'; import { useLayoutEffect } from '../../../../lib/teact/teact'; @@ -15,10 +17,16 @@ export default function useFocusMessage( noFocusHighlight?: boolean, isResizingContainer?: boolean, ) { + const { setReachedFocusedMessage } = getActions(); + useLayoutEffect(() => { if (isFocused && elementRef.current) { const messagesContainer = elementRef.current.closest('.MessageList')!; + setReachedFocusedMessage({ + hasReached: true, + }); + fastSmoothScroll( messagesContainer, elementRef.current, @@ -31,5 +39,7 @@ export default function useFocusMessage( isResizingContainer, ); } - }, [elementRef, chatId, isFocused, focusDirection, noFocusHighlight, isResizingContainer]); + }, [ + elementRef, chatId, isFocused, focusDirection, noFocusHighlight, isResizingContainer, setReachedFocusedMessage, + ]); } diff --git a/src/global/actions/ui/messages.ts b/src/global/actions/ui/messages.ts index e5bdb3ac8..53b3cc7dd 100644 --- a/src/global/actions/ui/messages.ts +++ b/src/global/actions/ui/messages.ts @@ -22,7 +22,7 @@ import { replaceThreadParam, replaceTabThreadParam, updateFocusDirection, - updateFocusedMessage, + updateFocusedMessage, updateFocusedMessageReached, } from '../../reducers'; import { selectCurrentChat, @@ -368,6 +368,12 @@ addActionHandler('focusNextReply', (global, actions, payload): ActionReturnType return undefined; }); +addActionHandler('setReachedFocusedMessage', (global, actions, payload): ActionReturnType => { + const { hasReached = false, tabId = getCurrentTabId() } = payload; + + return updateFocusedMessageReached(global, hasReached, tabId); +}); + addActionHandler('focusMessage', (global, actions, payload): ActionReturnType => { const { chatId, threadId = MAIN_THREAD_ID, messageListType = 'thread', noHighlight, groupedId, groupedChatId, diff --git a/src/global/reducers/messages.ts b/src/global/reducers/messages.ts index 7d417a419..ff39697ff 100644 --- a/src/global/reducers/messages.ts +++ b/src/global/reducers/messages.ts @@ -512,6 +512,22 @@ export function updateFocusedMessage( }, tabId); } +export function updateFocusedMessageReached( + global: T, hasReachedMessage: boolean, + ...[tabId = getCurrentTabId()]: TabArgs +): T { + const focusedMessage = selectTabState(global, tabId).focusedMessage; + + if (!focusedMessage) return global; + + return updateTabState(global, { + focusedMessage: { + ...focusedMessage, + hasReachedMessage, + }, + }, tabId); +} + export function updateSponsoredMessage( global: T, chatId: string, message: ApiSponsoredMessage, ): T { diff --git a/src/global/types.ts b/src/global/types.ts index 780cbb991..a1eda39cc 100644 --- a/src/global/types.ts +++ b/src/global/types.ts @@ -214,6 +214,7 @@ export type TabState = { direction?: FocusDirection; noHighlight?: boolean; isResizingContainer?: boolean; + hasReachedMessage?: boolean; }; selectedMessages?: { @@ -1445,6 +1446,9 @@ export interface ActionPayloads { showDialog: { data: TabState['dialogs'][number]; } & WithTabId; + setReachedFocusedMessage: { + hasReached?: boolean; + } & WithTabId; focusMessage: { chatId: string; threadId?: number;