Sync: Fix missing chats in folders, refactor and simplify
This commit is contained in:
parent
57dd323b78
commit
0e7f5658c4
@ -28,7 +28,7 @@ export type OwnProps = {
|
|||||||
filterRef: RefObject<HTMLInputElement>;
|
filterRef: RefObject<HTMLInputElement>;
|
||||||
filterPlaceholder: string;
|
filterPlaceholder: string;
|
||||||
filter: string;
|
filter: string;
|
||||||
loadMore: NoneToVoidFunction;
|
loadMore?: NoneToVoidFunction;
|
||||||
onFilterChange: (filter: string) => void;
|
onFilterChange: (filter: string) => void;
|
||||||
onSelectChatOrUser: (chatOrUserId: string) => void;
|
onSelectChatOrUser: (chatOrUserId: string) => void;
|
||||||
onClose: NoneToVoidFunction;
|
onClose: NoneToVoidFunction;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, memo, useMemo, useCallback, useEffect,
|
FC, memo, useMemo, useEffect,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getDispatch } from '../../../lib/teact/teactn';
|
import { getDispatch } from '../../../lib/teact/teactn';
|
||||||
|
|
||||||
@ -7,7 +7,6 @@ import { SettingsScreens } from '../../../types';
|
|||||||
import { FolderEditDispatch } from '../../../hooks/reducers/useFoldersReducer';
|
import { FolderEditDispatch } from '../../../hooks/reducers/useFoldersReducer';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ALL_CHATS_PRELOAD_DISABLED,
|
|
||||||
ALL_FOLDER_ID,
|
ALL_FOLDER_ID,
|
||||||
ARCHIVED_FOLDER_ID,
|
ARCHIVED_FOLDER_ID,
|
||||||
CHAT_HEIGHT_PX,
|
CHAT_HEIGHT_PX,
|
||||||
@ -39,17 +38,10 @@ const ChatList: FC<OwnProps> = ({
|
|||||||
folderType,
|
folderType,
|
||||||
folderId,
|
folderId,
|
||||||
isActive,
|
isActive,
|
||||||
lastSyncTime,
|
|
||||||
foldersDispatch,
|
foldersDispatch,
|
||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const { openChat, openNextChat } = getDispatch();
|
||||||
loadMoreChats,
|
|
||||||
preloadTopChatMessages,
|
|
||||||
preloadArchivedChats,
|
|
||||||
openChat,
|
|
||||||
openNextChat,
|
|
||||||
} = getDispatch();
|
|
||||||
|
|
||||||
const resolvedFolderId = (
|
const resolvedFolderId = (
|
||||||
folderType === 'all' ? ALL_FOLDER_ID : folderType === 'archived' ? ARCHIVED_FOLDER_ID : folderId!
|
folderType === 'all' ? ALL_FOLDER_ID : folderType === 'archived' ? ARCHIVED_FOLDER_ID : folderId!
|
||||||
@ -80,24 +72,7 @@ const ChatList: FC<OwnProps> = ({
|
|||||||
});
|
});
|
||||||
}, [orderById, prevOrderById]);
|
}, [orderById, prevOrderById]);
|
||||||
|
|
||||||
const loadMoreOfType = useCallback(() => {
|
const [viewportIds, getMore] = useInfiniteScroll(undefined, orderedIds, undefined, CHAT_LIST_SLICE);
|
||||||
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]);
|
|
||||||
|
|
||||||
// Support <Cmd>+<Digit> and <Alt>+<Up/Down> to navigate between chats
|
// Support <Cmd>+<Digit> and <Alt>+<Up/Down> to navigate between chats
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, memo, useMemo, useCallback,
|
FC, memo, useMemo, useCallback,
|
||||||
} from '../../../../lib/teact/teact';
|
} from '../../../../lib/teact/teact';
|
||||||
import { getDispatch, getGlobal } from '../../../../lib/teact/teactn';
|
import { getGlobal } from '../../../../lib/teact/teactn';
|
||||||
|
|
||||||
import { SettingsScreens } from '../../../../types';
|
import { SettingsScreens } from '../../../../types';
|
||||||
|
|
||||||
@ -38,8 +38,6 @@ const SettingsFoldersChatFilters: FC<OwnProps> = ({
|
|||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
onReset,
|
onReset,
|
||||||
}) => {
|
}) => {
|
||||||
const { loadMoreChats } = getDispatch();
|
|
||||||
|
|
||||||
const { chatFilter } = state;
|
const { chatFilter } = state;
|
||||||
const { selectedChatIds, selectedChatTypes } = selectChatFilters(state, mode, true);
|
const { selectedChatIds, selectedChatTypes } = selectChatFilters(state, mode, true);
|
||||||
|
|
||||||
@ -124,7 +122,6 @@ const SettingsFoldersChatFilters: FC<OwnProps> = ({
|
|||||||
onSelectedIdsChange={handleSelectedIdsChange}
|
onSelectedIdsChange={handleSelectedIdsChange}
|
||||||
onSelectedChatTypesChange={handleSelectedChatTypesChange}
|
onSelectedChatTypesChange={handleSelectedChatTypesChange}
|
||||||
onFilterChange={handleFilterChange}
|
onFilterChange={handleFilterChange}
|
||||||
onLoadMore={loadMoreChats}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -32,7 +32,6 @@ type OwnProps = {
|
|||||||
onSelectedIdsChange: (ids: string[]) => void;
|
onSelectedIdsChange: (ids: string[]) => void;
|
||||||
onSelectedChatTypesChange: (types: string[]) => void;
|
onSelectedChatTypesChange: (types: string[]) => void;
|
||||||
onFilterChange: (value: string) => void;
|
onFilterChange: (value: string) => void;
|
||||||
onLoadMore: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Focus slows down animation, also it breaks transition layout in Chrome
|
// Focus slows down animation, also it breaks transition layout in Chrome
|
||||||
@ -51,7 +50,6 @@ const SettingsFoldersChatsPicker: FC<OwnProps> = ({
|
|||||||
onSelectedIdsChange,
|
onSelectedIdsChange,
|
||||||
onSelectedChatTypesChange,
|
onSelectedChatTypesChange,
|
||||||
onFilterChange,
|
onFilterChange,
|
||||||
onLoadMore,
|
|
||||||
}) => {
|
}) => {
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
@ -156,7 +154,7 @@ const SettingsFoldersChatsPicker: FC<OwnProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [viewportIds, getMore] = useInfiniteScroll(onLoadMore, chatIds, Boolean(filterValue));
|
const [viewportIds, getMore] = useInfiniteScroll(undefined, chatIds, Boolean(filterValue));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Picker SettingsFoldersChatsPicker">
|
<div className="Picker SettingsFoldersChatsPicker">
|
||||||
|
|||||||
@ -66,7 +66,6 @@ const SettingsFoldersEdit: FC<OwnProps & StateProps> = ({
|
|||||||
const {
|
const {
|
||||||
editChatFolder,
|
editChatFolder,
|
||||||
addChatFolder,
|
addChatFolder,
|
||||||
loadMoreChats,
|
|
||||||
} = getDispatch();
|
} = getDispatch();
|
||||||
|
|
||||||
const [animationData, setAnimationData] = useState<string>();
|
const [animationData, setAnimationData] = useState<string>();
|
||||||
@ -119,21 +118,6 @@ const SettingsFoldersEdit: FC<OwnProps & StateProps> = ({
|
|||||||
loadedActiveChatIds, loadedArchivedChatIds,
|
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();
|
const lang = useLang();
|
||||||
|
|
||||||
useHistoryBack(isActive, onBack, onScreenSelect, state.mode === 'edit'
|
useHistoryBack(isActive, onBack, onScreenSelect, state.mode === 'edit'
|
||||||
|
|||||||
@ -43,7 +43,6 @@ const ForwardPicker: FC<OwnProps & StateProps> = ({
|
|||||||
const {
|
const {
|
||||||
setForwardChatId,
|
setForwardChatId,
|
||||||
exitForwardMode,
|
exitForwardMode,
|
||||||
loadMoreChats,
|
|
||||||
} = getDispatch();
|
} = getDispatch();
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
@ -105,7 +104,6 @@ const ForwardPicker: FC<OwnProps & StateProps> = ({
|
|||||||
filterPlaceholder={lang('ForwardTo')}
|
filterPlaceholder={lang('ForwardTo')}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
onFilterChange={setFilter}
|
onFilterChange={setFilter}
|
||||||
loadMore={loadMoreChats}
|
|
||||||
onSelectChatOrUser={handleSelectUser}
|
onSelectChatOrUser={handleSelectUser}
|
||||||
onClose={exitForwardMode}
|
onClose={exitForwardMode}
|
||||||
onCloseAnimationEnd={unmarkIsShown}
|
onCloseAnimationEnd={unmarkIsShown}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import React, {
|
|||||||
import { getDispatch, withGlobal } from '../../lib/teact/teactn';
|
import { getDispatch, withGlobal } from '../../lib/teact/teactn';
|
||||||
|
|
||||||
import { LangCode } from '../../types';
|
import { LangCode } from '../../types';
|
||||||
import { ApiMessage } from '../../api/types';
|
import { ApiMessage, ApiUpdateAuthorizationStateType, ApiUpdateConnectionStateType } from '../../api/types';
|
||||||
|
|
||||||
import '../../modules/actions/all';
|
import '../../modules/actions/all';
|
||||||
import {
|
import {
|
||||||
@ -52,6 +52,8 @@ import CallFallbackConfirm from '../calls/CallFallbackConfirm.async';
|
|||||||
import './Main.scss';
|
import './Main.scss';
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
|
connectionState?: ApiUpdateConnectionStateType;
|
||||||
|
authState?: ApiUpdateAuthorizationStateType;
|
||||||
lastSyncTime?: number;
|
lastSyncTime?: number;
|
||||||
isLeftColumnShown: boolean;
|
isLeftColumnShown: boolean;
|
||||||
isRightColumnShown: boolean;
|
isRightColumnShown: boolean;
|
||||||
@ -81,6 +83,8 @@ let notificationInterval: number | undefined;
|
|||||||
let DEBUG_isLogged = false;
|
let DEBUG_isLogged = false;
|
||||||
|
|
||||||
const Main: FC<StateProps> = ({
|
const Main: FC<StateProps> = ({
|
||||||
|
connectionState,
|
||||||
|
authState,
|
||||||
lastSyncTime,
|
lastSyncTime,
|
||||||
isLeftColumnShown,
|
isLeftColumnShown,
|
||||||
isRightColumnShown,
|
isRightColumnShown,
|
||||||
@ -102,6 +106,7 @@ const Main: FC<StateProps> = ({
|
|||||||
addedSetIds,
|
addedSetIds,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
|
sync,
|
||||||
loadAnimatedEmojis,
|
loadAnimatedEmojis,
|
||||||
loadNotificationSettings,
|
loadNotificationSettings,
|
||||||
loadNotificationExceptions,
|
loadNotificationExceptions,
|
||||||
@ -125,6 +130,12 @@ const Main: FC<StateProps> = ({
|
|||||||
console.log('>>> RENDER MAIN');
|
console.log('>>> RENDER MAIN');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (connectionState === 'connectionStateReady' && authState === 'authorizationStateReady') {
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
}, [connectionState, authState, sync]);
|
||||||
|
|
||||||
// Initial API calls
|
// Initial API calls
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (lastSyncTime) {
|
if (lastSyncTime) {
|
||||||
@ -356,6 +367,8 @@ export default memo(withGlobal(
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
connectionState: global.connectionState,
|
||||||
|
authState: global.authState,
|
||||||
lastSyncTime: global.lastSyncTime,
|
lastSyncTime: global.lastSyncTime,
|
||||||
isLeftColumnShown: global.isLeftColumnShown,
|
isLeftColumnShown: global.isLeftColumnShown,
|
||||||
isRightColumnShown: selectIsRightColumnShown(global),
|
isRightColumnShown: selectIsRightColumnShown(global),
|
||||||
|
|||||||
@ -61,7 +61,6 @@ export const GROUP_CALL_PARTICIPANTS_LIMIT = 100;
|
|||||||
export const REACTION_LIST_LIMIT = 100;
|
export const REACTION_LIST_LIMIT = 100;
|
||||||
|
|
||||||
export const TOP_CHAT_MESSAGES_PRELOAD_LIMIT = 20;
|
export const TOP_CHAT_MESSAGES_PRELOAD_LIMIT = 20;
|
||||||
export const ALL_CHATS_PRELOAD_DISABLED = false;
|
|
||||||
|
|
||||||
export const SPONSORED_MESSAGE_CACHE_MS = 300000; // 5 min
|
export const SPONSORED_MESSAGE_CACHE_MS = 300000; // 5 min
|
||||||
|
|
||||||
|
|||||||
@ -503,7 +503,7 @@ export type GlobalState = {
|
|||||||
|
|
||||||
export type ActionTypes = (
|
export type ActionTypes = (
|
||||||
// system
|
// system
|
||||||
'init' | 'reset' | 'disconnect' | 'initApi' | 'apiUpdate' | 'sync' | 'saveSession' | 'afterSync' |
|
'init' | 'reset' | 'disconnect' | 'initApi' | 'apiUpdate' | 'sync' | 'saveSession' |
|
||||||
'showNotification' | 'dismissNotification' | 'showDialog' | 'dismissDialog' |
|
'showNotification' | 'dismissNotification' | 'showDialog' | 'dismissDialog' |
|
||||||
// ui
|
// ui
|
||||||
'toggleChatInfo' | 'setIsUiReady' | 'addRecentEmoji' | 'addRecentSticker' | 'toggleLeftColumn' |
|
'toggleChatInfo' | 'setIsUiReady' | 'addRecentEmoji' | 'addRecentSticker' | 'toggleLeftColumn' |
|
||||||
@ -515,8 +515,7 @@ export type ActionTypes = (
|
|||||||
'setAuthPhoneNumber' | 'setAuthCode' | 'setAuthPassword' | 'signUp' | 'returnToAuthPhoneNumber' | 'signOut' |
|
'setAuthPhoneNumber' | 'setAuthCode' | 'setAuthPassword' | 'signUp' | 'returnToAuthPhoneNumber' | 'signOut' |
|
||||||
'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'goToAuthQrCode' | 'clearCache' |
|
'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'goToAuthQrCode' | 'clearCache' |
|
||||||
// chats
|
// chats
|
||||||
'preloadTopChatMessages' | 'preloadArchivedChats' | 'loadChats' | 'loadMoreChats' | 'openChat' |
|
'preloadTopChatMessages' | 'loadAllChats' | 'openChat' | 'openChatWithInfo' | 'openLinkedChat' |
|
||||||
'openChatWithInfo' | 'openLinkedChat' |
|
|
||||||
'openSupportChat' | 'openTipsChat' | 'focusMessageInComments' |
|
'openSupportChat' | 'openTipsChat' | 'focusMessageInComments' |
|
||||||
'loadFullChat' | 'loadTopChats' | 'requestChatUpdate' | 'updateChatMutedState' |
|
'loadFullChat' | 'loadTopChats' | 'requestChatUpdate' | 'updateChatMutedState' |
|
||||||
'joinChannel' | 'leaveChannel' | 'deleteChannel' | 'toggleChatPinned' | 'toggleChatArchived' | 'toggleChatUnread' |
|
'joinChannel' | 'leaveChannel' | 'deleteChannel' | 'toggleChatPinned' | 'toggleChatArchived' | 'toggleChatUnread' |
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useRef } from '../lib/teact/teact';
|
import { useCallback, useRef } from '../lib/teact/teact';
|
||||||
import { LoadMoreDirection } from '../types';
|
import { LoadMoreDirection } from '../types';
|
||||||
|
|
||||||
import { areSortedArraysEqual } from '../util/iteratees';
|
import { areSortedArraysEqual } from '../util/iteratees';
|
||||||
@ -15,7 +15,6 @@ const useInfiniteScroll = <ListId extends string | number>(
|
|||||||
listIds?: ListId[],
|
listIds?: ListId[],
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
listSlice = DEFAULT_LIST_SLICE,
|
listSlice = DEFAULT_LIST_SLICE,
|
||||||
forceFullPreload = false,
|
|
||||||
): [ListId[]?, GetMore?] => {
|
): [ListId[]?, GetMore?] => {
|
||||||
const lastParamsRef = useRef<{
|
const lastParamsRef = useRef<{
|
||||||
direction?: LoadMoreDirection;
|
direction?: LoadMoreDirection;
|
||||||
@ -49,13 +48,6 @@ const useInfiniteScroll = <ListId extends string | number>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (listIds && !isDisabled && loadMoreBackwards && forceFullPreload) {
|
|
||||||
const viewportIds = viewportIdsRef.current!;
|
|
||||||
loadMoreBackwards({ offsetId: viewportIds[viewportIds.length - 1] });
|
|
||||||
}
|
|
||||||
}, [listIds, isDisabled, loadMoreBackwards, forceFullPreload]);
|
|
||||||
|
|
||||||
const getMore: GetMore = useCallback(({
|
const getMore: GetMore = useCallback(({
|
||||||
direction,
|
direction,
|
||||||
noScroll,
|
noScroll,
|
||||||
|
|||||||
@ -20,28 +20,16 @@ import {
|
|||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
import { callApi } from '../../../api/gramjs';
|
import { callApi } from '../../../api/gramjs';
|
||||||
import {
|
import {
|
||||||
addChats,
|
addChats, addUsers, addUserStatuses, replaceThreadParam,
|
||||||
addUsers,
|
updateChatListIds, updateChats, updateChat, updateChatListSecondaryInfo,
|
||||||
addUserStatuses,
|
updateManagementProgress, leaveChat, replaceUsers, replaceUserStatuses,
|
||||||
replaceThreadParam,
|
replaceChats, replaceChatListIds,
|
||||||
updateChatListIds,
|
|
||||||
updateChats,
|
|
||||||
updateChat,
|
|
||||||
updateChatListSecondaryInfo,
|
|
||||||
updateManagementProgress,
|
|
||||||
leaveChat,
|
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import {
|
import {
|
||||||
selectChat,
|
selectChat, selectUser, selectChatListType, selectIsChatPinned,
|
||||||
selectUser,
|
selectChatFolder, selectSupportChat, selectChatByUsername, selectThreadTopMessageId,
|
||||||
selectChatListType,
|
selectCurrentMessageList, selectThreadInfo, selectCurrentChat, selectLastServiceNotification,
|
||||||
selectIsChatPinned,
|
selectThreadParam, selectChatMessage,
|
||||||
selectChatFolder,
|
|
||||||
selectSupportChat,
|
|
||||||
selectChatByUsername,
|
|
||||||
selectThreadTopMessageId,
|
|
||||||
selectCurrentMessageList,
|
|
||||||
selectThreadInfo, selectCurrentChat, selectLastServiceNotification,
|
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
import { buildCollectionByKey, omit } from '../../../util/iteratees';
|
import { buildCollectionByKey, omit } from '../../../util/iteratees';
|
||||||
import { debounce, pause, throttle } from '../../../util/schedulers';
|
import { debounce, pause, throttle } from '../../../util/schedulers';
|
||||||
@ -54,9 +42,7 @@ import { selectGroupCall } from '../../selectors/calls';
|
|||||||
import { getOrderedIds } from '../../../util/folderManager';
|
import { getOrderedIds } from '../../../util/folderManager';
|
||||||
|
|
||||||
const TOP_CHAT_MESSAGES_PRELOAD_INTERVAL = 100;
|
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 runThrottledForLoadTopChats = throttle((cb) => cb(), 3000, true);
|
||||||
const runDebouncedForLoadFullChat = debounce((cb) => cb(), 500, false, true);
|
const runDebouncedForLoadFullChat = debounce((cb) => cb(), 500, false, true);
|
||||||
|
|
||||||
@ -179,43 +165,30 @@ addReducer('openTipsChat', (global, actions, payload) => {
|
|||||||
actions.openChatByUsername({ username: `${TIPS_USERNAME}${usernamePostfix}` });
|
actions.openChatByUsername({ username: `${TIPS_USERNAME}${usernamePostfix}` });
|
||||||
});
|
});
|
||||||
|
|
||||||
addReducer('loadMoreChats', (global, actions, payload) => {
|
addReducer('loadAllChats', (global, actions, payload) => {
|
||||||
const { listType = 'active' } = payload!;
|
const listType = payload.listType as 'active' | 'archived';
|
||||||
const listIds = global.chats.listIds[listType as ('active' | 'archived')];
|
let { shouldReplace, onReplace } = payload;
|
||||||
const isFullyLoaded = global.chats.isFullyLoaded[listType as ('active' | 'archived')];
|
|
||||||
|
|
||||||
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 () => {
|
(async () => {
|
||||||
while (!getGlobal().chats.isFullyLoaded.archived) {
|
while (shouldReplace || !global.chats.isFullyLoaded[listType]) {
|
||||||
const currentGlobal = getGlobal();
|
const listIds = !shouldReplace && global.chats.listIds[listType];
|
||||||
const listIds = currentGlobal.chats.listIds.archived;
|
|
||||||
const oldestChat = listIds
|
const oldestChat = listIds
|
||||||
? listIds
|
? listIds
|
||||||
.map((id) => currentGlobal.chats.byId[id])
|
/* eslint-disable @typescript-eslint/no-loop-func */
|
||||||
.filter((chat) => Boolean(chat?.lastMessage) && !selectIsChatPinned(currentGlobal, chat.id))
|
.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]
|
.sort((chat1, chat2) => (chat1.lastMessage!.date - chat2.lastMessage!.date))[0]
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
await loadChats('archived', oldestChat?.id, oldestChat?.lastMessage!.date);
|
await loadChats(listType, oldestChat?.id, oldestChat?.lastMessage!.date, shouldReplace);
|
||||||
await pause(CHATS_PRELOAD_INTERVAL);
|
|
||||||
|
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();
|
let global = getGlobal();
|
||||||
|
|
||||||
const result = await callApi('fetchChats', {
|
const result = await callApi('fetchChats', {
|
||||||
limit: CHAT_LIST_LOAD_SLICE,
|
limit: CHAT_LIST_LOAD_SLICE,
|
||||||
offsetDate,
|
offsetDate,
|
||||||
archived: listType === 'archived',
|
archived: listType === 'archived',
|
||||||
withPinned: global.chats.orderedPinnedIds[listType] === undefined,
|
withPinned: shouldReplace,
|
||||||
serverTimeOffset: global.serverTimeOffset,
|
serverTimeOffset: global.serverTimeOffset,
|
||||||
lastLocalServiceMessage: selectLastServiceNotification(global)?.message,
|
lastLocalServiceMessage: selectLastServiceNotification(global)?.message,
|
||||||
});
|
});
|
||||||
@ -1035,11 +1010,44 @@ async function loadChats(listType: 'active' | 'archived', offsetId?: string, off
|
|||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
|
|
||||||
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
|
if (shouldReplace && listType === 'active') {
|
||||||
global = addUserStatuses(global, result.userStatusesById);
|
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);
|
global = updateChatListSecondaryInfo(global, listType, result);
|
||||||
|
|
||||||
Object.keys(result.draftsById).forEach((chatId) => {
|
Object.keys(result.draftsById).forEach((chatId) => {
|
||||||
|
|||||||
@ -3,23 +3,17 @@ import {
|
|||||||
} from '../../../lib/teact/teactn';
|
} from '../../../lib/teact/teactn';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ApiChat, ApiFormattedText, ApiMessage, ApiUser, MAIN_THREAD_ID,
|
ApiChat, ApiFormattedText, ApiMessage, MAIN_THREAD_ID,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CHAT_LIST_LOAD_SLICE, DEBUG, MESSAGE_LIST_SLICE, SERVICE_NOTIFICATIONS_USER_ID,
|
DEBUG, MESSAGE_LIST_SLICE, SERVICE_NOTIFICATIONS_USER_ID,
|
||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
import { callApi } from '../../../api/gramjs';
|
import { callApi } from '../../../api/gramjs';
|
||||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||||
import {
|
import {
|
||||||
replaceChatListIds,
|
|
||||||
replaceChats,
|
|
||||||
replaceUsers,
|
|
||||||
replaceUserStatuses,
|
|
||||||
updateUsers,
|
updateUsers,
|
||||||
addUserStatuses,
|
|
||||||
updateChats,
|
updateChats,
|
||||||
updateChatListSecondaryInfo,
|
|
||||||
updateThreadInfos,
|
updateThreadInfos,
|
||||||
replaceThreadParam,
|
replaceThreadParam,
|
||||||
updateListedIds,
|
updateListedIds,
|
||||||
@ -27,29 +21,18 @@ import {
|
|||||||
addChatMessagesById,
|
addChatMessagesById,
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import {
|
import {
|
||||||
selectUser,
|
|
||||||
selectChat,
|
|
||||||
selectCurrentMessageList,
|
selectCurrentMessageList,
|
||||||
selectDraft,
|
selectDraft,
|
||||||
selectChatMessage,
|
selectChatMessage,
|
||||||
selectThreadInfo,
|
selectThreadInfo,
|
||||||
selectLastServiceNotification,
|
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
import { isUserId } from '../../helpers';
|
import { init as initFolderManager } from '../../../util/folderManager';
|
||||||
|
|
||||||
addReducer('sync', (global, actions) => {
|
|
||||||
void sync(actions.afterSync);
|
|
||||||
});
|
|
||||||
|
|
||||||
addReducer('afterSync', () => {
|
|
||||||
void afterSync();
|
|
||||||
});
|
|
||||||
|
|
||||||
const RELEASE_STATUS_TIMEOUT = 15000; // 10 sec;
|
const RELEASE_STATUS_TIMEOUT = 15000; // 10 sec;
|
||||||
|
|
||||||
let releaseStatusTimeout: number | undefined;
|
let releaseStatusTimeout: number | undefined;
|
||||||
|
|
||||||
async function sync(afterSyncCallback: () => void) {
|
addReducer('sync', () => {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log('>>> START SYNC');
|
console.log('>>> START SYNC');
|
||||||
@ -67,149 +50,35 @@ async function sync(afterSyncCallback: () => void) {
|
|||||||
releaseStatusTimeout = undefined;
|
releaseStatusTimeout = undefined;
|
||||||
}, RELEASE_STATUS_TIMEOUT);
|
}, 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`
|
loadAllChats({
|
||||||
const savedUsers = await loadAndReplaceChats();
|
listType: 'active',
|
||||||
await loadAndReplaceMessages(savedUsers);
|
shouldReplace: true,
|
||||||
|
onReplace: async () => {
|
||||||
|
await loadAndReplaceMessages();
|
||||||
|
|
||||||
setGlobal({
|
setGlobal({
|
||||||
...getGlobal(),
|
...getGlobal(),
|
||||||
lastSyncTime: Date.now(),
|
lastSyncTime: Date.now(),
|
||||||
isSyncing: false,
|
isSyncing: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log('>>> FINISH SYNC');
|
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<ApiUser>(Boolean as any);
|
|
||||||
|
|
||||||
const savedChats = savedPrivateChatIds
|
|
||||||
.map((id) => selectChat(global, id))
|
|
||||||
.filter<ApiChat>(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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
savedUsers.push(...result.users);
|
initFolderManager();
|
||||||
savedChats.push(...result.chats);
|
loadAllChats({ listType: 'archived', shouldReplace: true });
|
||||||
|
void callApi('fetchCurrentUser');
|
||||||
global = replaceUserStatuses(global, result.userStatusesById);
|
preloadTopChatMessages();
|
||||||
|
},
|
||||||
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]);
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Object.keys(result.replyingToById).forEach((chatId) => {
|
async function loadAndReplaceMessages() {
|
||||||
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[]) {
|
|
||||||
let areMessagesLoaded = false;
|
let areMessagesLoaded = false;
|
||||||
let users = savedUsers || [];
|
|
||||||
|
|
||||||
let global = getGlobal();
|
let global = getGlobal();
|
||||||
const { chatId: currentChatId, threadId: currentThreadId } = selectCurrentMessageList(global) || {};
|
const { chatId: currentChatId, threadId: currentThreadId } = selectCurrentMessageList(global) || {};
|
||||||
@ -294,10 +163,10 @@ async function loadAndReplaceMessages(savedUsers?: ApiUser[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
global = updateChats(global, buildCollectionByKey(result.chats, 'id'));
|
global = updateChats(global, buildCollectionByKey(result.chats, 'id'));
|
||||||
|
global = updateUsers(global, buildCollectionByKey(result.users, 'id'));
|
||||||
global = updateThreadInfos(global, currentChatId, result.threadInfos);
|
global = updateThreadInfos(global, currentChatId, result.threadInfos);
|
||||||
|
|
||||||
areMessagesLoaded = true;
|
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]);
|
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);
|
setGlobal(global);
|
||||||
|
|
||||||
const { chatId: audioChatId, messageId: audioMessageId } = global.audioPlayer;
|
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<ApiUser>(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) {
|
function loadTopMessages(chat: ApiChat) {
|
||||||
return callApi('fetchMessages', {
|
return callApi('fetchMessages', {
|
||||||
chat,
|
chat,
|
||||||
|
|||||||
@ -134,7 +134,6 @@ function onUpdateAuthorizationState(update: ApiUpdateAuthorizationState) {
|
|||||||
setGlobal({
|
setGlobal({
|
||||||
...global,
|
...global,
|
||||||
isLoggingOut: false,
|
isLoggingOut: false,
|
||||||
lastSyncTime: Date.now(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -162,9 +161,7 @@ function onUpdateConnectionState(update: ApiUpdateConnectionState) {
|
|||||||
connectionState,
|
connectionState,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (connectionState === 'connectionStateReady' && global.authState === 'authorizationStateReady') {
|
if (connectionState === 'connectionStateBroken') {
|
||||||
getDispatch().sync();
|
|
||||||
} else if (connectionState === 'connectionStateBroken') {
|
|
||||||
getDispatch().signOut();
|
getDispatch().signOut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,7 +93,9 @@ const updateFolderManagerThrottled = throttle(() => {
|
|||||||
|
|
||||||
let inited = false;
|
let inited = false;
|
||||||
|
|
||||||
function init() {
|
/* Getters */
|
||||||
|
|
||||||
|
export function init() {
|
||||||
inited = true;
|
inited = true;
|
||||||
|
|
||||||
addCallback(updateFolderManagerThrottled);
|
addCallback(updateFolderManagerThrottled);
|
||||||
@ -102,8 +104,6 @@ function init() {
|
|||||||
updateFolderManager(getGlobal());
|
updateFolderManager(getGlobal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Getters */
|
|
||||||
|
|
||||||
export function getOrderedIds(folderId: number) {
|
export function getOrderedIds(folderId: number) {
|
||||||
if (!inited) init();
|
if (!inited) init();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user