Comments: Fix focus on top message (#3356)

This commit is contained in:
Alexander Zinchuk 2023-06-18 12:04:00 +02:00
parent 86f8ad9e2f
commit 915dbe5736
4 changed files with 26 additions and 28 deletions

View File

@ -36,7 +36,6 @@ import {
selectIsChatBotNotStarted, selectIsChatBotNotStarted,
selectScrollOffset, selectScrollOffset,
selectThreadTopMessageId, selectThreadTopMessageId,
selectFirstMessageId,
selectChatScheduledMessages, selectChatScheduledMessages,
selectCurrentMessageIds, selectCurrentMessageIds,
selectIsCurrentUserPremium, selectIsCurrentUserPremium,
@ -127,7 +126,6 @@ type StateProps = {
isLoadingBotInfo?: boolean; isLoadingBotInfo?: boolean;
botInfo?: ApiBotInfo; botInfo?: ApiBotInfo;
threadTopMessageId?: number; threadTopMessageId?: number;
threadFirstMessageId?: number;
hasLinkedChat?: boolean; hasLinkedChat?: boolean;
lastSyncTime?: number; lastSyncTime?: number;
topic?: ApiTopic; topic?: ApiTopic;
@ -170,7 +168,6 @@ const MessageList: FC<OwnProps & StateProps> = ({
firstUnreadId, firstUnreadId,
isComments, isComments,
isViewportNewest, isViewportNewest,
threadFirstMessageId,
isRestricted, isRestricted,
restrictionReason, restrictionReason,
focusingId, focusingId,
@ -259,23 +256,11 @@ const MessageList: FC<OwnProps & StateProps> = ({
useNativeCopySelectedMessages(copyMessagesByIds); useNativeCopySelectedMessages(copyMessagesByIds);
const messageGroups = useMemo(() => { const messageGroups = useMemo(() => {
if (!messageIds || !messagesById) { if (!messageIds?.length || !messagesById) {
return undefined; return undefined;
} }
const viewportIds = ( const listedMessages = messageIds.map((id) => messagesById[id]).filter(Boolean);
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);
// Service notifications have local IDs which may be not in sync with real message history // Service notifications have local IDs which may be not in sync with real message history
const orderRule: (keyof ApiMessage)[] = type === 'scheduled' || isServiceNotificationsChat const orderRule: (keyof ApiMessage)[] = type === 'scheduled' || isServiceNotificationsChat
@ -285,7 +270,7 @@ const MessageList: FC<OwnProps & StateProps> = ({
return listedMessages.length return listedMessages.length
? groupMessages(orderBy(listedMessages, orderRule), memoUnreadDividerBeforeIdRef.current) ? groupMessages(orderBy(listedMessages, orderRule), memoUnreadDividerBeforeIdRef.current)
: undefined; : undefined;
}, [messageIds, messagesById, threadFirstMessageId, threadTopMessageId, type, isServiceNotificationsChat]); }, [messageIds, messagesById, type, isServiceNotificationsChat]);
useInterval(() => { useInterval(() => {
if (!messageIds || !messagesById || type === 'scheduled') { if (!messageIds || !messagesById || type === 'scheduled') {
@ -746,7 +731,6 @@ export default memo(withGlobal<OwnProps>(
isComments: Boolean(threadInfo?.originChannelId), isComments: Boolean(threadInfo?.originChannelId),
firstUnreadId: selectFirstUnreadId(global, chatId, threadId), firstUnreadId: selectFirstUnreadId(global, chatId, threadId),
isViewportNewest: type !== 'thread' || selectIsViewportNewest(global, chatId, threadId), isViewportNewest: type !== 'thread' || selectIsViewportNewest(global, chatId, threadId),
threadFirstMessageId: selectFirstMessageId(global, chatId, threadId),
focusingId, focusingId,
isSelectModeActive: selectIsInSelectMode(global), isSelectModeActive: selectIsInSelectMode(global),
isLoadingBotInfo, isLoadingBotInfo,

View File

@ -45,7 +45,7 @@ import {
selectReplyingToId, selectReplyingToId,
selectTabState, selectTabState,
selectTheme, selectTheme,
selectThreadInfo, selectThreadInfo, selectThreadTopMessageId,
} from '../../global/selectors'; } from '../../global/selectors';
import { import {
getCanPostInChat, getCanPostInChat,
@ -140,6 +140,7 @@ type StateProps = {
shouldSendJoinRequest?: boolean; shouldSendJoinRequest?: boolean;
lastSyncTime?: number; lastSyncTime?: number;
pinnedIds?: number[]; pinnedIds?: number[];
topMessageId?: number;
}; };
function isImage(item: DataTransferItem) { function isImage(item: DataTransferItem) {
@ -193,6 +194,7 @@ function MiddleColumn({
shouldLoadFullChat, shouldLoadFullChat,
lastSyncTime, lastSyncTime,
pinnedIds, pinnedIds,
topMessageId,
}: OwnProps & StateProps) { }: OwnProps & StateProps) {
const { const {
openChat, openChat,
@ -226,7 +228,7 @@ function MiddleColumn({
getCurrentPinnedIndexes, getCurrentPinnedIndexes,
getLoadingPinnedId, getLoadingPinnedId,
getForceNextPinnedInHeader, getForceNextPinnedInHeader,
} = usePinnedMessage(chatId, threadId, pinnedIds); } = usePinnedMessage(chatId, threadId, pinnedIds, topMessageId);
const isMobileSearchActive = isMobile && hasCurrentTextSearch; const isMobileSearchActive = isMobile && hasCurrentTextSearch;
const closeAnimationDuration = isMobile ? LAYER_ANIMATION_DURATION_MS : undefined; const closeAnimationDuration = isMobile ? LAYER_ANIMATION_DURATION_MS : undefined;
@ -720,6 +722,9 @@ export default memo(withGlobal<OwnProps>(
? selectChatMessage(global, audioChatId, audioMessageId) ? selectChatMessage(global, audioChatId, audioMessageId)
: undefined; : undefined;
const isCommentThread = threadId !== MAIN_THREAD_ID && !chat?.isForum;
const topMessageId = isCommentThread ? selectThreadTopMessageId(global, chatId, threadId) : undefined;
return { return {
...state, ...state,
chatId, chatId,
@ -737,10 +742,7 @@ export default memo(withGlobal<OwnProps>(
isPinnedMessageList, isPinnedMessageList,
currentUserBannedRights: chat?.currentUserBannedRights, currentUserBannedRights: chat?.currentUserBannedRights,
defaultBannedRights: chat?.defaultBannedRights, defaultBannedRights: chat?.defaultBannedRights,
hasPinned: ( hasPinned: isCommentThread || Boolean(!isPinnedMessageList && pinnedIds?.length),
(threadId !== MAIN_THREAD_ID && !chat?.isForum)
|| Boolean(!isPinnedMessageList && pinnedIds?.length)
),
hasAudioPlayer: Boolean(audioMessage), hasAudioPlayer: Boolean(audioMessage),
hasButtonInHeader: canStartBot || canRestartBot || canSubscribe || shouldSendJoinRequest, hasButtonInHeader: canStartBot || canRestartBot || canSubscribe || shouldSendJoinRequest,
pinnedMessagesCount: pinnedIds ? pinnedIds.length : 0, pinnedMessagesCount: pinnedIds ? pinnedIds.length : 0,
@ -753,6 +755,7 @@ export default memo(withGlobal<OwnProps>(
shouldSendJoinRequest, shouldSendJoinRequest,
shouldLoadFullChat, shouldLoadFullChat,
pinnedIds, pinnedIds,
topMessageId,
}; };
}, },
)(MiddleColumn)); )(MiddleColumn));

View File

@ -23,7 +23,9 @@ type PinnedIntersectionChangedParams = {
export type PinnedIntersectionChangedCallback = (params: PinnedIntersectionChangedParams) => void; 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<Record<string, number>>({}); const [getCurrentPinnedIndexes, setCurrentPinnedIndexes] = useSignal<Record<string, number>>({});
const [getForceNextPinnedInHeader, setForceNextPinnedInHeader] = useSignal<boolean | undefined>(); const [getForceNextPinnedInHeader, setForceNextPinnedInHeader] = useSignal<boolean | undefined>();
const viewportPinnedIdsRef = useRef<number[] | undefined>(); const viewportPinnedIdsRef = useRef<number[] | undefined>();
@ -133,7 +135,10 @@ export default function usePinnedMessage(chatId?: string, threadId?: number, pin
if (!chatId || !threadId || !key || getLoadingPinnedId()) return false; if (!chatId || !threadId || !key || getLoadingPinnedId()) return false;
const global = getGlobal(); 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 index = pinnedIds.indexOf(messageId);
const newPinnedIndex = cycleRestrict(pinnedIds.length, index + 1); const newPinnedIndex = cycleRestrict(pinnedIds.length, index + 1);

View File

@ -68,7 +68,7 @@ import {
selectDraft, selectDraft,
selectEditingId, selectEditingId,
selectEditingMessage, selectEditingMessage,
selectEditingScheduledId, selectEditingScheduledId, selectFirstMessageId,
selectFirstUnreadId, selectFirstUnreadId,
selectFocusedMessageId, selectFocusedMessageId,
selectForwardsCanBeSentToChat, selectForwardsCanBeSentToChat,
@ -1020,6 +1020,12 @@ async function loadViewportMessages<T extends GlobalState>(
const allMessages = ([] as ApiMessage[]).concat(messages, localMessages); const allMessages = ([] as ApiMessage[]).concat(messages, localMessages);
const byId = buildCollectionByKey(allMessages, 'id'); const byId = buildCollectionByKey(allMessages, 'id');
const ids = Object.keys(byId).map(Number); 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 = addChatMessagesById(global, chatId, byId);
global = isOutlying global = isOutlying