diff --git a/src/components/middle/MessageList.tsx b/src/components/middle/MessageList.tsx index aeac2fef6..a66ce0e4a 100644 --- a/src/components/middle/MessageList.tsx +++ b/src/components/middle/MessageList.tsx @@ -36,7 +36,6 @@ import { selectIsChatBotNotStarted, selectScrollOffset, selectThreadTopMessageId, - selectFirstMessageId, selectChatScheduledMessages, selectCurrentMessageIds, selectIsCurrentUserPremium, @@ -127,7 +126,6 @@ type StateProps = { isLoadingBotInfo?: boolean; botInfo?: ApiBotInfo; threadTopMessageId?: number; - threadFirstMessageId?: number; hasLinkedChat?: boolean; lastSyncTime?: number; topic?: ApiTopic; @@ -170,7 +168,6 @@ const MessageList: FC = ({ firstUnreadId, isComments, isViewportNewest, - threadFirstMessageId, isRestricted, restrictionReason, focusingId, @@ -259,23 +256,11 @@ const MessageList: FC = ({ useNativeCopySelectedMessages(copyMessagesByIds); const messageGroups = useMemo(() => { - if (!messageIds || !messagesById) { + if (!messageIds?.length || !messagesById) { return undefined; } - const viewportIds = ( - threadTopMessageId - && threadFirstMessageId !== threadTopMessageId - && (!messageIds[0] || threadFirstMessageId === messageIds[0]) - ) - ? [threadTopMessageId, ...messageIds] - : messageIds; - - if (!viewportIds.length) { - return undefined; - } - - const listedMessages = viewportIds.map((id) => messagesById[id]).filter(Boolean); + const listedMessages = messageIds.map((id) => messagesById[id]).filter(Boolean); // Service notifications have local IDs which may be not in sync with real message history const orderRule: (keyof ApiMessage)[] = type === 'scheduled' || isServiceNotificationsChat @@ -285,7 +270,7 @@ const MessageList: FC = ({ return listedMessages.length ? groupMessages(orderBy(listedMessages, orderRule), memoUnreadDividerBeforeIdRef.current) : undefined; - }, [messageIds, messagesById, threadFirstMessageId, threadTopMessageId, type, isServiceNotificationsChat]); + }, [messageIds, messagesById, type, isServiceNotificationsChat]); useInterval(() => { if (!messageIds || !messagesById || type === 'scheduled') { @@ -746,7 +731,6 @@ export default memo(withGlobal( isComments: Boolean(threadInfo?.originChannelId), firstUnreadId: selectFirstUnreadId(global, chatId, threadId), isViewportNewest: type !== 'thread' || selectIsViewportNewest(global, chatId, threadId), - threadFirstMessageId: selectFirstMessageId(global, chatId, threadId), focusingId, isSelectModeActive: selectIsInSelectMode(global), isLoadingBotInfo, diff --git a/src/components/middle/MiddleColumn.tsx b/src/components/middle/MiddleColumn.tsx index 0a976a1e1..f323dba4a 100644 --- a/src/components/middle/MiddleColumn.tsx +++ b/src/components/middle/MiddleColumn.tsx @@ -45,7 +45,7 @@ import { selectReplyingToId, selectTabState, selectTheme, - selectThreadInfo, + selectThreadInfo, selectThreadTopMessageId, } from '../../global/selectors'; import { getCanPostInChat, @@ -140,6 +140,7 @@ type StateProps = { shouldSendJoinRequest?: boolean; lastSyncTime?: number; pinnedIds?: number[]; + topMessageId?: number; }; function isImage(item: DataTransferItem) { @@ -193,6 +194,7 @@ function MiddleColumn({ shouldLoadFullChat, lastSyncTime, pinnedIds, + topMessageId, }: OwnProps & StateProps) { const { openChat, @@ -226,7 +228,7 @@ function MiddleColumn({ getCurrentPinnedIndexes, getLoadingPinnedId, getForceNextPinnedInHeader, - } = usePinnedMessage(chatId, threadId, pinnedIds); + } = usePinnedMessage(chatId, threadId, pinnedIds, topMessageId); const isMobileSearchActive = isMobile && hasCurrentTextSearch; const closeAnimationDuration = isMobile ? LAYER_ANIMATION_DURATION_MS : undefined; @@ -720,6 +722,9 @@ export default memo(withGlobal( ? selectChatMessage(global, audioChatId, audioMessageId) : undefined; + const isCommentThread = threadId !== MAIN_THREAD_ID && !chat?.isForum; + const topMessageId = isCommentThread ? selectThreadTopMessageId(global, chatId, threadId) : undefined; + return { ...state, chatId, @@ -737,10 +742,7 @@ export default memo(withGlobal( isPinnedMessageList, currentUserBannedRights: chat?.currentUserBannedRights, defaultBannedRights: chat?.defaultBannedRights, - hasPinned: ( - (threadId !== MAIN_THREAD_ID && !chat?.isForum) - || Boolean(!isPinnedMessageList && pinnedIds?.length) - ), + hasPinned: isCommentThread || Boolean(!isPinnedMessageList && pinnedIds?.length), hasAudioPlayer: Boolean(audioMessage), hasButtonInHeader: canStartBot || canRestartBot || canSubscribe || shouldSendJoinRequest, pinnedMessagesCount: pinnedIds ? pinnedIds.length : 0, @@ -753,6 +755,7 @@ export default memo(withGlobal( shouldSendJoinRequest, shouldLoadFullChat, pinnedIds, + topMessageId, }; }, )(MiddleColumn)); diff --git a/src/components/middle/hooks/usePinnedMessage.ts b/src/components/middle/hooks/usePinnedMessage.ts index 1c2402581..226bd28eb 100644 --- a/src/components/middle/hooks/usePinnedMessage.ts +++ b/src/components/middle/hooks/usePinnedMessage.ts @@ -23,7 +23,9 @@ type PinnedIntersectionChangedParams = { export type PinnedIntersectionChangedCallback = (params: PinnedIntersectionChangedParams) => void; -export default function usePinnedMessage(chatId?: string, threadId?: number, pinnedIds?: number[]) { +export default function usePinnedMessage( + chatId?: string, threadId?: number, pinnedIds?: number[], topMessageId?: number, +) { const [getCurrentPinnedIndexes, setCurrentPinnedIndexes] = useSignal>({}); const [getForceNextPinnedInHeader, setForceNextPinnedInHeader] = useSignal(); const viewportPinnedIdsRef = useRef(); @@ -133,7 +135,10 @@ export default function usePinnedMessage(chatId?: string, threadId?: number, pin if (!chatId || !threadId || !key || getLoadingPinnedId()) return false; const global = getGlobal(); - if (!pinnedIds?.length) return false; + if (!pinnedIds?.length) { + // Focusing on a post in comments + return topMessageId === messageId; + } const index = pinnedIds.indexOf(messageId); const newPinnedIndex = cycleRestrict(pinnedIds.length, index + 1); diff --git a/src/global/actions/api/messages.ts b/src/global/actions/api/messages.ts index a7c449fcb..ccbd8db1b 100644 --- a/src/global/actions/api/messages.ts +++ b/src/global/actions/api/messages.ts @@ -68,7 +68,7 @@ import { selectDraft, selectEditingId, selectEditingMessage, - selectEditingScheduledId, + selectEditingScheduledId, selectFirstMessageId, selectFirstUnreadId, selectFocusedMessageId, selectForwardsCanBeSentToChat, @@ -1020,6 +1020,12 @@ async function loadViewportMessages( const allMessages = ([] as ApiMessage[]).concat(messages, localMessages); const byId = buildCollectionByKey(allMessages, 'id'); const ids = Object.keys(byId).map(Number); + const threadFirstMessageId = selectFirstMessageId(global, chatId, threadId) || {}; + if (threadId + && threadFirstMessageId !== threadId + && (!ids[0] || threadFirstMessageId === ids[0])) { + ids.unshift(threadId); + } global = addChatMessagesById(global, chatId, byId); global = isOutlying