From 48b6a263cf68ccc9ed2ab33f04b7cad0837e1229 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Fri, 20 Aug 2021 23:46:48 +0300 Subject: [PATCH] Threads: Fix some threads are loading forever (#1401) --- src/api/gramjs/apiBuilders/messages.ts | 1 + src/api/types/messages.ts | 1 + .../middle/message/CommentButton.tsx | 18 ++------- src/modules/actions/api/chats.ts | 8 ++++ src/modules/actions/api/messages.ts | 26 +++++++++++-- src/modules/actions/apiUpdaters/messages.ts | 37 +++++++++++++++++-- src/modules/reducers/messages.ts | 21 +++++++++++ 7 files changed, 90 insertions(+), 22 deletions(-) diff --git a/src/api/gramjs/apiBuilders/messages.ts b/src/api/gramjs/apiBuilders/messages.ts index 2116946b9..fa9763334 100644 --- a/src/api/gramjs/apiBuilders/messages.ts +++ b/src/api/gramjs/apiBuilders/messages.ts @@ -242,6 +242,7 @@ function buildApiMessageForwardInfo(fwdFrom: GramJs.MessageFwdHeader, isChatWith return { isChannelPost: Boolean(fwdFrom.channelPost), + channelPostId: fwdFrom.channelPost, isLinkedChannelPost: Boolean(fwdFrom.channelPost && savedFromPeerId && !isChatWithSelf), fromChatId: savedFromPeerId || fromId, fromMessageId: fwdFrom.channelPost || fwdFrom.savedFromMsgId, diff --git a/src/api/types/messages.ts b/src/api/types/messages.ts index 69937a5ab..45edb0c14 100644 --- a/src/api/types/messages.ts +++ b/src/api/types/messages.ts @@ -173,6 +173,7 @@ export interface ApiWebPage { export interface ApiMessageForwardInfo { isChannelPost: boolean; + channelPostId?: number; isLinkedChannelPost?: boolean; fromChatId?: number; senderUserId?: number; diff --git a/src/components/middle/message/CommentButton.tsx b/src/components/middle/message/CommentButton.tsx index a34908ba3..79283c29c 100644 --- a/src/components/middle/message/CommentButton.tsx +++ b/src/components/middle/message/CommentButton.tsx @@ -1,5 +1,5 @@ import React, { - FC, memo, useCallback, useEffect, + FC, memo, useCallback, } from '../../../lib/teact/teact'; import { withGlobal } from '../../../lib/teact/teactn'; @@ -12,7 +12,7 @@ import { pick } from '../../../util/iteratees'; import { isChatPrivate } from '../../../modules/helpers'; import { formatIntegerCompact } from '../../../util/textFormat'; import buildClassName from '../../../util/buildClassName'; -import { selectThreadInfo, selectThreadOriginChat } from '../../../modules/selectors'; +import { selectThreadInfo } from '../../../modules/selectors'; import useLang from '../../../hooks/useLang'; import Avatar from '../../common/Avatar'; @@ -28,19 +28,16 @@ type StateProps = { threadInfo: ApiThreadInfo; usersById?: Record; chatsById?: Record; - shouldRequestThreadUpdate: boolean; }; -type DispatchProps = Pick; +type DispatchProps = Pick; const CommentButton: FC = ({ disabled, threadInfo, usersById, chatsById, - shouldRequestThreadUpdate, openChat, - requestThreadInfoUpdate, }) => { const lang = useLang(); const { @@ -51,12 +48,6 @@ const CommentButton: FC = ({ openChat({ id: chatId, threadId }); }, [openChat, chatId, threadId]); - useEffect(() => { - if (shouldRequestThreadUpdate) { - requestThreadInfoUpdate({ chatId, threadId }); - } - }, [chatId, requestThreadInfoUpdate, shouldRequestThreadUpdate, threadId]); - if (messagesCount === undefined) { return undefined; } @@ -107,7 +98,6 @@ export default memo(withGlobal( const { threadId, chatId } = message.threadInfo!; const threadInfo = selectThreadInfo(global, chatId, threadId) || message.threadInfo!; - const chat = selectThreadOriginChat(global, chatId, threadId); const { byId: usersById } = global.users; const { byId: chatsById } = global.chats; @@ -115,11 +105,9 @@ export default memo(withGlobal( threadInfo, usersById, chatsById, - shouldRequestThreadUpdate: !!chat && !threadInfo.topMessageId, }; }, (setGlobal, actions): DispatchProps => pick(actions, [ 'openChat', - 'requestThreadInfoUpdate', ]), )(CommentButton)); diff --git a/src/modules/actions/api/chats.ts b/src/modules/actions/api/chats.ts index 85e584e9e..474bc7572 100644 --- a/src/modules/actions/api/chats.ts +++ b/src/modules/actions/api/chats.ts @@ -94,6 +94,14 @@ addReducer('openChat', (global, actions, payload) => { actions.toggleChatUnread({ id }); } + // Please telegram send us some updates about linked chat 🙏 + if (chat && chat.lastMessage && chat.lastMessage.threadInfo) { + actions.requestThreadInfoUpdate({ + chatId: chat.lastMessage.threadInfo.chatId, + threadId: chat.lastMessage.threadInfo.threadId, + }); + } + if (!chat) { if (id === currentUserId) { void callApi('fetchChat', { type: 'self' }); diff --git a/src/modules/actions/api/messages.ts b/src/modules/actions/api/messages.ts index a5820051b..f3b9070da 100644 --- a/src/modules/actions/api/messages.ts +++ b/src/modules/actions/api/messages.ts @@ -30,6 +30,7 @@ import { replaceScheduledMessages, updateThreadInfos, updateChat, + updateThreadUnreadFromForwardedMessage, } from '../../reducers'; import { selectChat, @@ -145,14 +146,29 @@ async function loadWithBudget( } addReducer('loadMessage', (global, actions, payload) => { - const { chatId, messageId, replyOriginForId } = payload!; + const { + chatId, messageId, replyOriginForId, threadUpdate, + } = payload!; const chat = selectChat(global, chatId); if (!chat) { return; } - void loadMessage(chat, messageId, replyOriginForId); + (async () => { + const message = await loadMessage(chat, messageId, replyOriginForId); + if (message && threadUpdate) { + const { lastMessageId, isDeleting } = threadUpdate; + + setGlobal(updateThreadUnreadFromForwardedMessage( + getGlobal(), + message, + chatId, + lastMessageId, + isDeleting, + )); + } + })(); }); addReducer('sendMessage', (global, actions, payload) => { @@ -683,7 +699,7 @@ async function loadViewportMessages( async function loadMessage(chat: ApiChat, messageId: number, replyOriginForId: number) { const result = await callApi('fetchMessage', { chat, messageId }); if (!result) { - return; + return undefined; } if (result === MESSAGE_DELETED) { @@ -697,13 +713,15 @@ async function loadMessage(chat: ApiChat, messageId: number, replyOriginForId: n setGlobal(global); } - return; + return undefined; } let global = getGlobal(); global = updateChatMessage(global, chat.id, messageId, result.message); global = addUsers(global, buildCollectionByKey(result.users, 'id')); setGlobal(global); + + return result.message; } function findClosestIndex(sourceIds: number[], offsetId: number) { diff --git a/src/modules/actions/apiUpdaters/messages.ts b/src/modules/actions/apiUpdaters/messages.ts index 6b076f486..691a6e6a0 100644 --- a/src/modules/actions/apiUpdaters/messages.ts +++ b/src/modules/actions/apiUpdaters/messages.ts @@ -15,6 +15,7 @@ import { replaceThreadParam, updateScheduledMessage, deleteChatScheduledMessages, + updateThreadUnreadFromForwardedMessage, } from '../../reducers'; import { GlobalActions, GlobalState } from '../../../global/types'; import { @@ -46,7 +47,7 @@ addReducer('apiUpdate', (global, actions, update: ApiUpdate) => { case 'newMessage': { const { chatId, id, message } = update; global = updateWithLocalMedia(global, chatId, id, message); - global = updateListedAndViewportIds(global, message as ApiMessage); + global = updateListedAndViewportIds(global, actions, message as ApiMessage); if (message.threadInfo) { global = updateThreadInfo( @@ -157,7 +158,7 @@ addReducer('apiUpdate', (global, actions, update: ApiUpdate) => { case 'updateMessageSendSucceeded': { const { chatId, localId, message } = update; - global = updateListedAndViewportIds(global, message as ApiMessage); + global = updateListedAndViewportIds(global, actions, message as ApiMessage); const currentMessage = selectChatMessage(global, chatId, localId); @@ -443,7 +444,31 @@ function updateWithLocalMedia( : updateChatMessage(global, chatId, id, message); } -function updateListedAndViewportIds(global: GlobalState, message: ApiMessage) { +function updateThreadUnread(global: GlobalState, actions: GlobalActions, message: ApiMessage, isDeleting?: boolean) { + const { chatId } = message; + + const { threadInfo } = selectThreadByMessage(global, chatId, message) || {}; + + if (!threadInfo && message.replyToMessageId) { + const originMessage = selectChatMessage(global, chatId, message.replyToMessageId); + if (originMessage) { + global = updateThreadUnreadFromForwardedMessage(global, originMessage, chatId, message.id, isDeleting); + } else { + actions.loadMessage({ + chatId, + messageId: message.replyToMessageId, + threadUpdate: { + isDeleting, + lastMessageId: message.id, + }, + }); + } + } + + return global; +} + +function updateListedAndViewportIds(global: GlobalState, actions: GlobalActions, message: ApiMessage) { const { id, chatId } = message; const { threadInfo, firstMessageId } = selectThreadByMessage(global, chatId, message) || {}; @@ -451,6 +476,8 @@ function updateListedAndViewportIds(global: GlobalState, message: ApiMessage) { const chat = selectChat(global, chatId); const isUnreadChatNotLoaded = chat && chat.unreadCount && !selectListedIds(global, chatId, MAIN_THREAD_ID); + global = updateThreadUnread(global, actions, message); + if (threadInfo) { if (firstMessageId || !isMessageLocal(message)) { global = updateListedIds(global, chatId, threadInfo.threadId, [id]); @@ -559,12 +586,16 @@ function deleteMessages(chatId: number | undefined, ids: number[], actions: Glob return; } + global = updateThreadUnread(global, actions, message, true); + const { threadInfo } = selectThreadByMessage(global, chatId, message) || {}; if (threadInfo) { threadIdsToUpdate.push(threadInfo.threadId); } }); + setGlobal(global); + setTimeout(() => { setGlobal(deleteChatMessages(getGlobal(), chatId, ids)); diff --git a/src/modules/reducers/messages.ts b/src/modules/reducers/messages.ts index 109ce1249..082b6f2d8 100644 --- a/src/modules/reducers/messages.ts +++ b/src/modules/reducers/messages.ts @@ -528,3 +528,24 @@ export function exitMessageSelectMode(global: GlobalState): GlobalState { selectedMessages: undefined, }; } + +export function updateThreadUnreadFromForwardedMessage( + global: GlobalState, + originMessage: ApiMessage, + chatId: number, + lastMessageId: number, + isDeleting?: boolean, +) { + const { channelPostId, fromChatId } = originMessage.forwardInfo || {}; + if (channelPostId && fromChatId) { + const threadInfoOld = selectThreadInfo(global, chatId, channelPostId); + if (threadInfoOld) { + global = replaceThreadParam(global, chatId, channelPostId, 'threadInfo', { + ...threadInfoOld, + lastMessageId, + messagesCount: threadInfoOld.messagesCount + (isDeleting ? -1 : 1), + }); + } + } + return global; +}