From 0e7f5658c473019a5e21bbba33bf85f3673a044f Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Fri, 11 Feb 2022 15:13:02 +0100 Subject: [PATCH] Sync: Fix missing chats in folders, refactor and simplify --- src/components/common/ChatOrUserPicker.tsx | 2 +- src/components/left/main/ChatList.tsx | 31 +-- .../folders/SettingsFoldersChatFilters.tsx | 5 +- .../folders/SettingsFoldersChatsPicker.tsx | 4 +- .../settings/folders/SettingsFoldersEdit.tsx | 16 -- src/components/main/ForwardPicker.tsx | 2 - src/components/main/Main.tsx | 15 +- src/config.ts | 1 - src/global/types.ts | 5 +- src/hooks/useInfiniteScroll.ts | 10 +- src/modules/actions/api/chats.ts | 124 +++++----- src/modules/actions/api/sync.ts | 219 +++--------------- src/modules/actions/apiUpdaters/initial.ts | 5 +- src/util/folderManager.ts | 6 +- 14 files changed, 119 insertions(+), 326 deletions(-) diff --git a/src/components/common/ChatOrUserPicker.tsx b/src/components/common/ChatOrUserPicker.tsx index 329b0066c..fbc3c2c27 100644 --- a/src/components/common/ChatOrUserPicker.tsx +++ b/src/components/common/ChatOrUserPicker.tsx @@ -28,7 +28,7 @@ export type OwnProps = { filterRef: RefObject; filterPlaceholder: string; filter: string; - loadMore: NoneToVoidFunction; + loadMore?: NoneToVoidFunction; onFilterChange: (filter: string) => void; onSelectChatOrUser: (chatOrUserId: string) => void; onClose: NoneToVoidFunction; diff --git a/src/components/left/main/ChatList.tsx b/src/components/left/main/ChatList.tsx index 2540ea033..71f56e341 100644 --- a/src/components/left/main/ChatList.tsx +++ b/src/components/left/main/ChatList.tsx @@ -1,5 +1,5 @@ import React, { - FC, memo, useMemo, useCallback, useEffect, + FC, memo, useMemo, useEffect, } from '../../../lib/teact/teact'; import { getDispatch } from '../../../lib/teact/teactn'; @@ -7,7 +7,6 @@ import { SettingsScreens } from '../../../types'; import { FolderEditDispatch } from '../../../hooks/reducers/useFoldersReducer'; import { - ALL_CHATS_PRELOAD_DISABLED, ALL_FOLDER_ID, ARCHIVED_FOLDER_ID, CHAT_HEIGHT_PX, @@ -39,17 +38,10 @@ const ChatList: FC = ({ folderType, folderId, isActive, - lastSyncTime, foldersDispatch, onScreenSelect, }) => { - const { - loadMoreChats, - preloadTopChatMessages, - preloadArchivedChats, - openChat, - openNextChat, - } = getDispatch(); + const { openChat, openNextChat } = getDispatch(); const resolvedFolderId = ( folderType === 'all' ? ALL_FOLDER_ID : folderType === 'archived' ? ARCHIVED_FOLDER_ID : folderId! @@ -80,24 +72,7 @@ const ChatList: FC = ({ }); }, [orderById, prevOrderById]); - const loadMoreOfType = useCallback(() => { - loadMoreChats({ listType: folderType === 'archived' ? 'archived' : 'active' }); - }, [loadMoreChats, folderType]); - - const [viewportIds, getMore] = useInfiniteScroll( - lastSyncTime ? loadMoreOfType : undefined, - orderedIds, - undefined, - CHAT_LIST_SLICE, - folderType === 'all' && !ALL_CHATS_PRELOAD_DISABLED, - ); - - useEffect(() => { - if (lastSyncTime && folderType === 'all') { - preloadTopChatMessages(); - preloadArchivedChats(); - } - }, [lastSyncTime, folderType, preloadTopChatMessages, preloadArchivedChats]); + const [viewportIds, getMore] = useInfiniteScroll(undefined, orderedIds, undefined, CHAT_LIST_SLICE); // Support + and + to navigate between chats useEffect(() => { diff --git a/src/components/left/settings/folders/SettingsFoldersChatFilters.tsx b/src/components/left/settings/folders/SettingsFoldersChatFilters.tsx index 8212ae971..7f8788676 100644 --- a/src/components/left/settings/folders/SettingsFoldersChatFilters.tsx +++ b/src/components/left/settings/folders/SettingsFoldersChatFilters.tsx @@ -1,7 +1,7 @@ import React, { FC, memo, useMemo, useCallback, } from '../../../../lib/teact/teact'; -import { getDispatch, getGlobal } from '../../../../lib/teact/teactn'; +import { getGlobal } from '../../../../lib/teact/teactn'; import { SettingsScreens } from '../../../../types'; @@ -38,8 +38,6 @@ const SettingsFoldersChatFilters: FC = ({ onScreenSelect, onReset, }) => { - const { loadMoreChats } = getDispatch(); - const { chatFilter } = state; const { selectedChatIds, selectedChatTypes } = selectChatFilters(state, mode, true); @@ -124,7 +122,6 @@ const SettingsFoldersChatFilters: FC = ({ onSelectedIdsChange={handleSelectedIdsChange} onSelectedChatTypesChange={handleSelectedChatTypesChange} onFilterChange={handleFilterChange} - onLoadMore={loadMoreChats} /> ); }; diff --git a/src/components/left/settings/folders/SettingsFoldersChatsPicker.tsx b/src/components/left/settings/folders/SettingsFoldersChatsPicker.tsx index 0803df9cd..4f11ed177 100644 --- a/src/components/left/settings/folders/SettingsFoldersChatsPicker.tsx +++ b/src/components/left/settings/folders/SettingsFoldersChatsPicker.tsx @@ -32,7 +32,6 @@ type OwnProps = { onSelectedIdsChange: (ids: string[]) => void; onSelectedChatTypesChange: (types: string[]) => void; onFilterChange: (value: string) => void; - onLoadMore: () => void; }; // Focus slows down animation, also it breaks transition layout in Chrome @@ -51,7 +50,6 @@ const SettingsFoldersChatsPicker: FC = ({ onSelectedIdsChange, onSelectedChatTypesChange, onFilterChange, - onLoadMore, }) => { // eslint-disable-next-line no-null/no-null const inputRef = useRef(null); @@ -156,7 +154,7 @@ const SettingsFoldersChatsPicker: FC = ({ ); } - const [viewportIds, getMore] = useInfiniteScroll(onLoadMore, chatIds, Boolean(filterValue)); + const [viewportIds, getMore] = useInfiniteScroll(undefined, chatIds, Boolean(filterValue)); return (
diff --git a/src/components/left/settings/folders/SettingsFoldersEdit.tsx b/src/components/left/settings/folders/SettingsFoldersEdit.tsx index 405459304..edffc2316 100644 --- a/src/components/left/settings/folders/SettingsFoldersEdit.tsx +++ b/src/components/left/settings/folders/SettingsFoldersEdit.tsx @@ -66,7 +66,6 @@ const SettingsFoldersEdit: FC = ({ const { editChatFolder, addChatFolder, - loadMoreChats, } = getDispatch(); const [animationData, setAnimationData] = useState(); @@ -119,21 +118,6 @@ const SettingsFoldersEdit: FC = ({ loadedActiveChatIds, loadedArchivedChatIds, ]); - useEffect(() => { - if ( - visibleIncludedChatIds.length < includedChatIds.length - || visibleExcludedChatIds.length < excludedChatIds.length - ) { - loadMoreChats({ listType: 'active' }); - } - }, [ - loadMoreChats, - excludedChatIds.length, - includedChatIds.length, - visibleExcludedChatIds.length, - visibleIncludedChatIds.length, - ]); - const lang = useLang(); useHistoryBack(isActive, onBack, onScreenSelect, state.mode === 'edit' diff --git a/src/components/main/ForwardPicker.tsx b/src/components/main/ForwardPicker.tsx index 74581470c..e8beff592 100644 --- a/src/components/main/ForwardPicker.tsx +++ b/src/components/main/ForwardPicker.tsx @@ -43,7 +43,6 @@ const ForwardPicker: FC = ({ const { setForwardChatId, exitForwardMode, - loadMoreChats, } = getDispatch(); const lang = useLang(); @@ -105,7 +104,6 @@ const ForwardPicker: FC = ({ filterPlaceholder={lang('ForwardTo')} filter={filter} onFilterChange={setFilter} - loadMore={loadMoreChats} onSelectChatOrUser={handleSelectUser} onClose={exitForwardMode} onCloseAnimationEnd={unmarkIsShown} diff --git a/src/components/main/Main.tsx b/src/components/main/Main.tsx index 0d98419ca..ea5b61b3c 100644 --- a/src/components/main/Main.tsx +++ b/src/components/main/Main.tsx @@ -4,7 +4,7 @@ import React, { import { getDispatch, withGlobal } from '../../lib/teact/teactn'; import { LangCode } from '../../types'; -import { ApiMessage } from '../../api/types'; +import { ApiMessage, ApiUpdateAuthorizationStateType, ApiUpdateConnectionStateType } from '../../api/types'; import '../../modules/actions/all'; import { @@ -52,6 +52,8 @@ import CallFallbackConfirm from '../calls/CallFallbackConfirm.async'; import './Main.scss'; type StateProps = { + connectionState?: ApiUpdateConnectionStateType; + authState?: ApiUpdateAuthorizationStateType; lastSyncTime?: number; isLeftColumnShown: boolean; isRightColumnShown: boolean; @@ -81,6 +83,8 @@ let notificationInterval: number | undefined; let DEBUG_isLogged = false; const Main: FC = ({ + connectionState, + authState, lastSyncTime, isLeftColumnShown, isRightColumnShown, @@ -102,6 +106,7 @@ const Main: FC = ({ addedSetIds, }) => { const { + sync, loadAnimatedEmojis, loadNotificationSettings, loadNotificationExceptions, @@ -125,6 +130,12 @@ const Main: FC = ({ console.log('>>> RENDER MAIN'); } + useEffect(() => { + if (connectionState === 'connectionStateReady' && authState === 'authorizationStateReady') { + sync(); + } + }, [connectionState, authState, sync]); + // Initial API calls useEffect(() => { if (lastSyncTime) { @@ -356,6 +367,8 @@ export default memo(withGlobal( : undefined; return { + connectionState: global.connectionState, + authState: global.authState, lastSyncTime: global.lastSyncTime, isLeftColumnShown: global.isLeftColumnShown, isRightColumnShown: selectIsRightColumnShown(global), diff --git a/src/config.ts b/src/config.ts index 0908ecb0a..e6bf8047c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -61,7 +61,6 @@ export const GROUP_CALL_PARTICIPANTS_LIMIT = 100; export const REACTION_LIST_LIMIT = 100; export const TOP_CHAT_MESSAGES_PRELOAD_LIMIT = 20; -export const ALL_CHATS_PRELOAD_DISABLED = false; export const SPONSORED_MESSAGE_CACHE_MS = 300000; // 5 min diff --git a/src/global/types.ts b/src/global/types.ts index f4aab931c..dbc3715d7 100644 --- a/src/global/types.ts +++ b/src/global/types.ts @@ -503,7 +503,7 @@ export type GlobalState = { export type ActionTypes = ( // system - 'init' | 'reset' | 'disconnect' | 'initApi' | 'apiUpdate' | 'sync' | 'saveSession' | 'afterSync' | + 'init' | 'reset' | 'disconnect' | 'initApi' | 'apiUpdate' | 'sync' | 'saveSession' | 'showNotification' | 'dismissNotification' | 'showDialog' | 'dismissDialog' | // ui 'toggleChatInfo' | 'setIsUiReady' | 'addRecentEmoji' | 'addRecentSticker' | 'toggleLeftColumn' | @@ -515,8 +515,7 @@ export type ActionTypes = ( 'setAuthPhoneNumber' | 'setAuthCode' | 'setAuthPassword' | 'signUp' | 'returnToAuthPhoneNumber' | 'signOut' | 'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'goToAuthQrCode' | 'clearCache' | // chats - 'preloadTopChatMessages' | 'preloadArchivedChats' | 'loadChats' | 'loadMoreChats' | 'openChat' | - 'openChatWithInfo' | 'openLinkedChat' | + 'preloadTopChatMessages' | 'loadAllChats' | 'openChat' | 'openChatWithInfo' | 'openLinkedChat' | 'openSupportChat' | 'openTipsChat' | 'focusMessageInComments' | 'loadFullChat' | 'loadTopChats' | 'requestChatUpdate' | 'updateChatMutedState' | 'joinChannel' | 'leaveChannel' | 'deleteChannel' | 'toggleChatPinned' | 'toggleChatArchived' | 'toggleChatUnread' | diff --git a/src/hooks/useInfiniteScroll.ts b/src/hooks/useInfiniteScroll.ts index b37c1c74e..1a0c5be66 100644 --- a/src/hooks/useInfiniteScroll.ts +++ b/src/hooks/useInfiniteScroll.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef } from '../lib/teact/teact'; +import { useCallback, useRef } from '../lib/teact/teact'; import { LoadMoreDirection } from '../types'; import { areSortedArraysEqual } from '../util/iteratees'; @@ -15,7 +15,6 @@ const useInfiniteScroll = ( listIds?: ListId[], isDisabled = false, listSlice = DEFAULT_LIST_SLICE, - forceFullPreload = false, ): [ListId[]?, GetMore?] => { const lastParamsRef = useRef<{ direction?: LoadMoreDirection; @@ -49,13 +48,6 @@ const useInfiniteScroll = ( } } - useEffect(() => { - if (listIds && !isDisabled && loadMoreBackwards && forceFullPreload) { - const viewportIds = viewportIdsRef.current!; - loadMoreBackwards({ offsetId: viewportIds[viewportIds.length - 1] }); - } - }, [listIds, isDisabled, loadMoreBackwards, forceFullPreload]); - const getMore: GetMore = useCallback(({ direction, noScroll, diff --git a/src/modules/actions/api/chats.ts b/src/modules/actions/api/chats.ts index c063de69a..48ee2dad4 100644 --- a/src/modules/actions/api/chats.ts +++ b/src/modules/actions/api/chats.ts @@ -20,28 +20,16 @@ import { } from '../../../config'; import { callApi } from '../../../api/gramjs'; import { - addChats, - addUsers, - addUserStatuses, - replaceThreadParam, - updateChatListIds, - updateChats, - updateChat, - updateChatListSecondaryInfo, - updateManagementProgress, - leaveChat, + addChats, addUsers, addUserStatuses, replaceThreadParam, + updateChatListIds, updateChats, updateChat, updateChatListSecondaryInfo, + updateManagementProgress, leaveChat, replaceUsers, replaceUserStatuses, + replaceChats, replaceChatListIds, } from '../../reducers'; import { - selectChat, - selectUser, - selectChatListType, - selectIsChatPinned, - selectChatFolder, - selectSupportChat, - selectChatByUsername, - selectThreadTopMessageId, - selectCurrentMessageList, - selectThreadInfo, selectCurrentChat, selectLastServiceNotification, + selectChat, selectUser, selectChatListType, selectIsChatPinned, + selectChatFolder, selectSupportChat, selectChatByUsername, selectThreadTopMessageId, + selectCurrentMessageList, selectThreadInfo, selectCurrentChat, selectLastServiceNotification, + selectThreadParam, selectChatMessage, } from '../../selectors'; import { buildCollectionByKey, omit } from '../../../util/iteratees'; import { debounce, pause, throttle } from '../../../util/schedulers'; @@ -54,9 +42,7 @@ import { selectGroupCall } from '../../selectors/calls'; import { getOrderedIds } from '../../../util/folderManager'; const TOP_CHAT_MESSAGES_PRELOAD_INTERVAL = 100; -const CHATS_PRELOAD_INTERVAL = 300; -const runThrottledForLoadChats = throttle((cb) => cb(), CHATS_PRELOAD_INTERVAL, true); const runThrottledForLoadTopChats = throttle((cb) => cb(), 3000, true); const runDebouncedForLoadFullChat = debounce((cb) => cb(), 500, false, true); @@ -179,43 +165,30 @@ addReducer('openTipsChat', (global, actions, payload) => { actions.openChatByUsername({ username: `${TIPS_USERNAME}${usernamePostfix}` }); }); -addReducer('loadMoreChats', (global, actions, payload) => { - const { listType = 'active' } = payload!; - const listIds = global.chats.listIds[listType as ('active' | 'archived')]; - const isFullyLoaded = global.chats.isFullyLoaded[listType as ('active' | 'archived')]; +addReducer('loadAllChats', (global, actions, payload) => { + const listType = payload.listType as 'active' | 'archived'; + let { shouldReplace, onReplace } = payload; - if (isFullyLoaded) { - return; - } - - const oldestChat = listIds - ? listIds - .map((id) => global.chats.byId[id]) - .filter((chat) => Boolean(chat?.lastMessage) && !selectIsChatPinned(global, chat.id)) - .sort((chat1, chat2) => (chat1.lastMessage!.date - chat2.lastMessage!.date))[0] - : undefined; - - if (oldestChat) { - runThrottledForLoadChats(() => loadChats(listType, oldestChat.id, oldestChat.lastMessage!.date)); - } else { - runThrottledForLoadChats(() => loadChats(listType)); - } -}); - -addReducer('preloadArchivedChats', () => { (async () => { - while (!getGlobal().chats.isFullyLoaded.archived) { - const currentGlobal = getGlobal(); - const listIds = currentGlobal.chats.listIds.archived; + while (shouldReplace || !global.chats.isFullyLoaded[listType]) { + const listIds = !shouldReplace && global.chats.listIds[listType]; const oldestChat = listIds ? listIds - .map((id) => currentGlobal.chats.byId[id]) - .filter((chat) => Boolean(chat?.lastMessage) && !selectIsChatPinned(currentGlobal, chat.id)) + /* eslint-disable @typescript-eslint/no-loop-func */ + .map((id) => global.chats.byId[id]) + .filter((chat) => Boolean(chat?.lastMessage) && !selectIsChatPinned(global, chat.id)) + /* eslint-enable @typescript-eslint/no-loop-func */ .sort((chat1, chat2) => (chat1.lastMessage!.date - chat2.lastMessage!.date))[0] : undefined; - await loadChats('archived', oldestChat?.id, oldestChat?.lastMessage!.date); - await pause(CHATS_PRELOAD_INTERVAL); + await loadChats(listType, oldestChat?.id, oldestChat?.lastMessage!.date, shouldReplace); + + if (shouldReplace) { + onReplace?.(); + } + + global = getGlobal(); + shouldReplace = false; } })(); }); @@ -1011,14 +984,16 @@ addReducer('setChatEnabledReactions', (global, actions, payload) => { })(); }); -async function loadChats(listType: 'active' | 'archived', offsetId?: string, offsetDate?: number) { +async function loadChats( + listType: 'active' | 'archived', offsetId?: string, offsetDate?: number, shouldReplace = false, +) { let global = getGlobal(); const result = await callApi('fetchChats', { limit: CHAT_LIST_LOAD_SLICE, offsetDate, archived: listType === 'archived', - withPinned: global.chats.orderedPinnedIds[listType] === undefined, + withPinned: shouldReplace, serverTimeOffset: global.serverTimeOffset, lastLocalServiceMessage: selectLastServiceNotification(global)?.message, }); @@ -1035,11 +1010,44 @@ async function loadChats(listType: 'active' | 'archived', offsetId?: string, off global = getGlobal(); - global = addUsers(global, buildCollectionByKey(result.users, 'id')); - global = addUserStatuses(global, result.userStatusesById); + if (shouldReplace && listType === 'active') { + const visibleChats = []; + const visibleUsers = []; + + const currentChat = selectCurrentChat(global); + if (currentChat) { + const { threadId } = selectCurrentMessageList(global)!; + visibleChats.push(currentChat); + const messageIds = selectThreadParam(global, currentChat.id, threadId, 'viewportIds'); + const messageSenders = messageIds ? messageIds + .map((messageId) => { + const { senderId } = selectChatMessage(global, currentChat.id, messageId) || {}; + return senderId ? selectUser(global, senderId) : undefined; + }) + .filter(Boolean) : []; + visibleUsers.push(...messageSenders); + } + + if (global.currentUserId && global.users.byId[global.currentUserId]) { + visibleUsers.push(global.users.byId[global.currentUserId]); + } + + global = replaceUsers(global, buildCollectionByKey(visibleUsers.concat(result.users), 'id')); + global = replaceUserStatuses(global, result.userStatusesById); + global = replaceChats(global, buildCollectionByKey(visibleChats.concat(result.chats), 'id')); + global = replaceChatListIds(global, listType, chatIds); + } else if (shouldReplace && listType === 'archived') { + global = addUsers(global, buildCollectionByKey(result.users, 'id')); + global = addUserStatuses(global, result.userStatusesById); + global = updateChats(global, buildCollectionByKey(result.chats, 'id')); + global = replaceChatListIds(global, listType, chatIds); + } else { + global = addUsers(global, buildCollectionByKey(result.users, 'id')); + global = addUserStatuses(global, result.userStatusesById); + global = updateChats(global, buildCollectionByKey(result.chats, 'id')); + global = updateChatListIds(global, listType, chatIds); + } - global = updateChats(global, buildCollectionByKey(result.chats, 'id')); - global = updateChatListIds(global, listType, chatIds); global = updateChatListSecondaryInfo(global, listType, result); Object.keys(result.draftsById).forEach((chatId) => { diff --git a/src/modules/actions/api/sync.ts b/src/modules/actions/api/sync.ts index 3f6562cae..2ef81e5e0 100644 --- a/src/modules/actions/api/sync.ts +++ b/src/modules/actions/api/sync.ts @@ -3,23 +3,17 @@ import { } from '../../../lib/teact/teactn'; import { - ApiChat, ApiFormattedText, ApiMessage, ApiUser, MAIN_THREAD_ID, + ApiChat, ApiFormattedText, ApiMessage, MAIN_THREAD_ID, } from '../../../api/types'; import { - CHAT_LIST_LOAD_SLICE, DEBUG, MESSAGE_LIST_SLICE, SERVICE_NOTIFICATIONS_USER_ID, + DEBUG, MESSAGE_LIST_SLICE, SERVICE_NOTIFICATIONS_USER_ID, } from '../../../config'; import { callApi } from '../../../api/gramjs'; import { buildCollectionByKey } from '../../../util/iteratees'; import { - replaceChatListIds, - replaceChats, - replaceUsers, - replaceUserStatuses, updateUsers, - addUserStatuses, updateChats, - updateChatListSecondaryInfo, updateThreadInfos, replaceThreadParam, updateListedIds, @@ -27,29 +21,18 @@ import { addChatMessagesById, } from '../../reducers'; import { - selectUser, - selectChat, selectCurrentMessageList, selectDraft, selectChatMessage, selectThreadInfo, - selectLastServiceNotification, } from '../../selectors'; -import { isUserId } from '../../helpers'; - -addReducer('sync', (global, actions) => { - void sync(actions.afterSync); -}); - -addReducer('afterSync', () => { - void afterSync(); -}); +import { init as initFolderManager } from '../../../util/folderManager'; const RELEASE_STATUS_TIMEOUT = 15000; // 10 sec; let releaseStatusTimeout: number | undefined; -async function sync(afterSyncCallback: () => void) { +addReducer('sync', () => { if (DEBUG) { // eslint-disable-next-line no-console console.log('>>> START SYNC'); @@ -67,149 +50,35 @@ async function sync(afterSyncCallback: () => void) { releaseStatusTimeout = undefined; }, RELEASE_STATUS_TIMEOUT); - await callApi('fetchCurrentUser'); + const { loadAllChats, preloadTopChatMessages } = getDispatch(); - // This fetches only active chats and clears archived chats, which will be fetched in `afterSync` - const savedUsers = await loadAndReplaceChats(); - await loadAndReplaceMessages(savedUsers); + loadAllChats({ + listType: 'active', + shouldReplace: true, + onReplace: async () => { + await loadAndReplaceMessages(); - setGlobal({ - ...getGlobal(), - lastSyncTime: Date.now(), - isSyncing: false, - }); + setGlobal({ + ...getGlobal(), + lastSyncTime: Date.now(), + isSyncing: false, + }); - if (DEBUG) { - // eslint-disable-next-line no-console - console.log('>>> FINISH SYNC'); - } - - afterSyncCallback(); -} - -async function afterSync() { - if (DEBUG) { - // eslint-disable-next-line no-console - console.log('>>> START AFTER-SYNC'); - } - - await Promise.all([ - loadAndUpdateUsers(), - loadAndReplaceArchivedChats(), - ]); - - await callApi('fetchCurrentUser'); - - if (DEBUG) { - // eslint-disable-next-line no-console - console.log('>>> FINISH AFTER-SYNC'); - } -} - -async function loadAndReplaceChats() { - let global = getGlobal(); - - const result = await callApi('fetchChats', { - limit: CHAT_LIST_LOAD_SLICE, - withPinned: true, - serverTimeOffset: global.serverTimeOffset, - lastLocalServiceMessage: selectLastServiceNotification(global)?.message, - }); - - if (!result) { - return undefined; - } - - global = getGlobal(); - - const { recentlyFoundChatIds } = global.globalSearch; - const { userIds: contactIds } = global.contactList || {}; - const { currentUserId } = global; - - const savedPrivateChatIds = [ - ...(recentlyFoundChatIds || []), - ...(contactIds || []), - ...(currentUserId ? [currentUserId] : []), - ]; - - const savedUsers = savedPrivateChatIds - .map((id) => selectUser(global, id)) - .filter(Boolean as any); - - const savedChats = savedPrivateChatIds - .map((id) => selectChat(global, id)) - .filter(Boolean as any); - - const { chatId: currentChatId } = selectCurrentMessageList(global) || {}; - if (currentChatId) { - const selectedChat = selectChat(global, currentChatId); - if (selectedChat && !savedPrivateChatIds.includes(currentChatId)) { - savedChats.push(selectedChat); - } - - if (isUserId(currentChatId)) { - const selectedChatUser = selectUser(global, currentChatId); - if (selectedChatUser && !savedPrivateChatIds.includes(currentChatId)) { - savedUsers.push(selectedChatUser); + if (DEBUG) { + // eslint-disable-next-line no-console + console.log('>>> FINISH SYNC'); } - } - } - savedUsers.push(...result.users); - savedChats.push(...result.chats); - - global = replaceUserStatuses(global, result.userStatusesById); - - global = replaceChats(global, buildCollectionByKey(savedChats, 'id')); - global = replaceChatListIds(global, 'active', result.chatIds); - global = updateChatListSecondaryInfo(global, 'active', result); - - Object.keys(result.draftsById).forEach((chatId) => { - global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'draft', result.draftsById[chatId]); + initFolderManager(); + loadAllChats({ listType: 'archived', shouldReplace: true }); + void callApi('fetchCurrentUser'); + preloadTopChatMessages(); + }, }); +}); - Object.keys(result.replyingToById).forEach((chatId) => { - global = replaceThreadParam( - global, chatId, MAIN_THREAD_ID, 'replyingToId', result.replyingToById[chatId], - ); - }); - - setGlobal(global); - - if (currentChatId && !global.chats.byId[currentChatId]) { - getDispatch().openChat({ id: undefined }); - } - - return savedUsers; -} - -async function loadAndReplaceArchivedChats() { - const result = await callApi('fetchChats', { - limit: CHAT_LIST_LOAD_SLICE, - archived: true, - withPinned: true, - serverTimeOffset: getGlobal().serverTimeOffset, - }); - - if (!result) { - return; - } - - let global = getGlobal(); - - global = updateUsers(global, buildCollectionByKey(result.users, 'id')); - global = addUserStatuses(global, result.userStatusesById); - - global = updateChats(global, buildCollectionByKey(result.chats, 'id')); - global = replaceChatListIds(global, 'archived', result.chatIds); - global = updateChatListSecondaryInfo(global, 'archived', result); - - setGlobal(global); -} - -async function loadAndReplaceMessages(savedUsers?: ApiUser[]) { +async function loadAndReplaceMessages() { let areMessagesLoaded = false; - let users = savedUsers || []; let global = getGlobal(); const { chatId: currentChatId, threadId: currentThreadId } = selectCurrentMessageList(global) || {}; @@ -294,10 +163,10 @@ async function loadAndReplaceMessages(savedUsers?: ApiUser[]) { } global = updateChats(global, buildCollectionByKey(result.chats, 'id')); + global = updateUsers(global, buildCollectionByKey(result.users, 'id')); global = updateThreadInfos(global, currentChatId, result.threadInfos); areMessagesLoaded = true; - users = Array.prototype.concat(users, result.users); } } @@ -316,13 +185,6 @@ async function loadAndReplaceMessages(savedUsers?: ApiUser[]) { global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'draft', draftsByChatId[chatId]); }); - if (savedUsers) { - global = replaceUsers(global, buildCollectionByKey(users, 'id')); - } else if (users) { - // If `fetchChats` has failed for some reason, we don't have saved chats, thus we can not replace - global = updateUsers(global, buildCollectionByKey(users, 'id')); - } - setGlobal(global); const { chatId: audioChatId, messageId: audioMessageId } = global.audioPlayer; @@ -331,35 +193,6 @@ async function loadAndReplaceMessages(savedUsers?: ApiUser[]) { } } -async function loadAndUpdateUsers() { - let global = getGlobal(); - const { recentlyFoundChatIds } = global.globalSearch; - const { userIds: contactIds } = global.contactList || {}; - if ( - (!contactIds || !contactIds.length) - && (!recentlyFoundChatIds || !recentlyFoundChatIds.length) - ) { - return; - } - - const users = [ - ...(recentlyFoundChatIds || []), - ...(contactIds || []), - ].map((id) => selectUser(global, id)).filter(Boolean as any); - - const result = await callApi('fetchUsers', { users }); - if (!result) { - return; - } - - const { users: updatedUsers, userStatusesById } = result; - - global = getGlobal(); - global = updateUsers(global, buildCollectionByKey(updatedUsers, 'id')); - global = addUserStatuses(global, userStatusesById); - setGlobal(global); -} - function loadTopMessages(chat: ApiChat) { return callApi('fetchMessages', { chat, diff --git a/src/modules/actions/apiUpdaters/initial.ts b/src/modules/actions/apiUpdaters/initial.ts index 13fe7a1c6..49c2301af 100644 --- a/src/modules/actions/apiUpdaters/initial.ts +++ b/src/modules/actions/apiUpdaters/initial.ts @@ -134,7 +134,6 @@ function onUpdateAuthorizationState(update: ApiUpdateAuthorizationState) { setGlobal({ ...global, isLoggingOut: false, - lastSyncTime: Date.now(), }); break; @@ -162,9 +161,7 @@ function onUpdateConnectionState(update: ApiUpdateConnectionState) { connectionState, }); - if (connectionState === 'connectionStateReady' && global.authState === 'authorizationStateReady') { - getDispatch().sync(); - } else if (connectionState === 'connectionStateBroken') { + if (connectionState === 'connectionStateBroken') { getDispatch().signOut(); } } diff --git a/src/util/folderManager.ts b/src/util/folderManager.ts index 5526779b4..d519c2eaa 100644 --- a/src/util/folderManager.ts +++ b/src/util/folderManager.ts @@ -93,7 +93,9 @@ const updateFolderManagerThrottled = throttle(() => { let inited = false; -function init() { +/* Getters */ + +export function init() { inited = true; addCallback(updateFolderManagerThrottled); @@ -102,8 +104,6 @@ function init() { updateFolderManager(getGlobal()); } -/* Getters */ - export function getOrderedIds(folderId: number) { if (!inited) init();