[Perf] Various optimizations for calculating chat lists
This commit is contained in:
parent
865ed08d82
commit
8015a7360e
@ -4,7 +4,7 @@ import React, {
|
||||
import { withGlobal } from '../../../lib/teact/teactn';
|
||||
|
||||
import { ApiChat, ApiChatFolder, ApiUser } from '../../../api/types';
|
||||
import { GlobalActions } from '../../../global/types';
|
||||
import { GlobalActions, GlobalState } from '../../../global/types';
|
||||
import { NotifyException, NotifySettings, SettingsScreens } from '../../../types';
|
||||
import { FolderEditDispatch } from '../../../hooks/reducers/useFoldersReducer';
|
||||
|
||||
@ -30,6 +30,7 @@ type OwnProps = {
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
allListIds: GlobalState['chats']['listIds'];
|
||||
chatsById: Record<string, ApiChat>;
|
||||
usersById: Record<string, ApiUser>;
|
||||
chatFoldersById: Record<number, ApiChatFolder>;
|
||||
@ -48,6 +49,7 @@ const INFO_THROTTLE = 3000;
|
||||
const SAVED_MESSAGES_HOTKEY = '0';
|
||||
|
||||
const ChatFolders: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
allListIds,
|
||||
chatsById,
|
||||
usersById,
|
||||
chatFoldersById,
|
||||
@ -86,11 +88,10 @@ const ChatFolders: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const chatIds = Object.keys(chatsById);
|
||||
const counters = displayedFolders.map((folder) => {
|
||||
const {
|
||||
unreadDialogsCount, hasActiveDialogs,
|
||||
} = getFolderUnreadDialogs(chatsById, usersById, folder, chatIds, notifySettings, notifyExceptions) || {};
|
||||
} = getFolderUnreadDialogs(allListIds, chatsById, usersById, folder, notifySettings, notifyExceptions) || {};
|
||||
|
||||
return {
|
||||
id: folder.id,
|
||||
@ -100,7 +101,7 @@ const ChatFolders: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
});
|
||||
|
||||
return buildCollectionByKey(counters, 'id');
|
||||
}, INFO_THROTTLE, [displayedFolders, chatsById, usersById, notifySettings, notifyExceptions]);
|
||||
}, INFO_THROTTLE, [displayedFolders, allListIds, chatsById, usersById, notifySettings, notifyExceptions]);
|
||||
|
||||
const folderTabs = useMemo(() => {
|
||||
if (!displayedFolders || !displayedFolders.length) {
|
||||
@ -240,7 +241,7 @@ const ChatFolders: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global): StateProps => {
|
||||
const {
|
||||
chats: { byId: chatsById },
|
||||
chats: { listIds: allListIds, byId: chatsById },
|
||||
users: { byId: usersById },
|
||||
chatFolders: {
|
||||
byId: chatFoldersById,
|
||||
@ -253,6 +254,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
} = global;
|
||||
|
||||
return {
|
||||
allListIds,
|
||||
chatsById,
|
||||
usersById,
|
||||
chatFoldersById,
|
||||
|
||||
@ -3,7 +3,7 @@ import React, {
|
||||
} from '../../../lib/teact/teact';
|
||||
import { withGlobal } from '../../../lib/teact/teactn';
|
||||
|
||||
import { GlobalActions } from '../../../global/types';
|
||||
import { GlobalActions, GlobalState } from '../../../global/types';
|
||||
import {
|
||||
ApiChat, ApiChatFolder, ApiUser,
|
||||
} from '../../../api/types';
|
||||
@ -37,11 +37,12 @@ type OwnProps = {
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
allListIds: GlobalState['chats']['listIds'];
|
||||
chatsById: Record<string, ApiChat>;
|
||||
usersById: Record<string, ApiUser>;
|
||||
chatFolder?: ApiChatFolder;
|
||||
listIds?: string[];
|
||||
orderedPinnedIds?: string[];
|
||||
chatFolder?: ApiChatFolder;
|
||||
lastSyncTime?: number;
|
||||
notifySettings: NotifySettings;
|
||||
notifyExceptions?: Record<number, NotifyException>;
|
||||
@ -60,15 +61,16 @@ const ChatList: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
folderType,
|
||||
folderId,
|
||||
isActive,
|
||||
chatFolder,
|
||||
allListIds,
|
||||
chatsById,
|
||||
usersById,
|
||||
listIds,
|
||||
orderedPinnedIds,
|
||||
chatFolder,
|
||||
lastSyncTime,
|
||||
foldersDispatch,
|
||||
notifySettings,
|
||||
notifyExceptions,
|
||||
foldersDispatch,
|
||||
onScreenSelect,
|
||||
loadMoreChats,
|
||||
preloadTopChatMessages,
|
||||
@ -78,9 +80,12 @@ const ChatList: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
}) => {
|
||||
const [currentListIds, currentPinnedIds] = useMemo(() => {
|
||||
return folderType === 'folder' && chatFolder
|
||||
? prepareFolderListIds(chatsById, usersById, chatFolder, notifySettings, notifyExceptions)
|
||||
? prepareFolderListIds(allListIds, chatsById, usersById, chatFolder, notifySettings, notifyExceptions)
|
||||
: [listIds, orderedPinnedIds];
|
||||
}, [folderType, chatFolder, chatsById, usersById, notifySettings, notifyExceptions, listIds, orderedPinnedIds]);
|
||||
}, [
|
||||
folderType, chatFolder, allListIds, chatsById, usersById,
|
||||
notifySettings, notifyExceptions, listIds, orderedPinnedIds,
|
||||
]);
|
||||
|
||||
const [orderById, orderedIds, chatArrays] = useMemo(() => {
|
||||
if (!currentListIds || (folderType === 'folder' && !chatFolder)) {
|
||||
@ -106,7 +111,7 @@ const ChatList: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
}
|
||||
|
||||
return mapValues(orderById, (order, id) => {
|
||||
return order - (prevOrderById[id] !== undefined ? prevOrderById[id] : Infinity);
|
||||
return prevOrderById[id] !== undefined ? order - prevOrderById[id] : -Infinity;
|
||||
});
|
||||
}, [orderById, prevOrderById]);
|
||||
|
||||
@ -137,6 +142,39 @@ const ChatList: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
}
|
||||
}, [lastSyncTime, folderType, preloadTopChatMessages, preloadArchivedChats]);
|
||||
|
||||
// Support <Cmd>+<Digit> and <Alt>+<Up/Down> to navigate between chats
|
||||
useEffect(() => {
|
||||
if (!isActive || !orderedIds) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function handleKeyDown(e: KeyboardEvent) {
|
||||
if (IS_PWA && ((IS_MAC_OS && e.metaKey) || (!IS_MAC_OS && e.ctrlKey)) && e.code.startsWith('Digit')) {
|
||||
const [, digit] = e.code.match(/Digit(\d)/) || [];
|
||||
if (!digit) return;
|
||||
|
||||
const position = Number(digit) - 1;
|
||||
if (position > orderedIds!.length - 1) return;
|
||||
|
||||
openChat({ id: orderedIds![position], shouldReplaceHistory: true });
|
||||
}
|
||||
|
||||
if (e.altKey) {
|
||||
const targetIndexDelta = e.key === 'ArrowDown' ? 1 : e.key === 'ArrowUp' ? -1 : undefined;
|
||||
if (!targetIndexDelta) return;
|
||||
|
||||
e.preventDefault();
|
||||
openNextChat({ targetIndexDelta, orderedIds });
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [isActive, openChat, openNextChat, orderedIds]);
|
||||
|
||||
const getAnimationType = useChatAnimationType(orderDiffById);
|
||||
|
||||
function renderChats() {
|
||||
@ -179,36 +217,6 @@ const ChatList: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (isActive && orderedIds) {
|
||||
if (IS_PWA && ((IS_MAC_OS && e.metaKey) || (!IS_MAC_OS && e.ctrlKey)) && e.code.startsWith('Digit')) {
|
||||
const [, digit] = e.code.match(/Digit(\d)/) || [];
|
||||
if (!digit) return;
|
||||
|
||||
const position = Number(digit) - 1;
|
||||
if (position > orderedIds.length - 1) return;
|
||||
|
||||
openChat({ id: orderedIds[position], shouldReplaceHistory: true });
|
||||
}
|
||||
|
||||
if (e.altKey) {
|
||||
const targetIndexDelta = e.key === 'ArrowDown' ? 1 : e.key === 'ArrowUp' ? -1 : undefined;
|
||||
if (!targetIndexDelta) return;
|
||||
|
||||
e.preventDefault();
|
||||
openNextChat({ targetIndexDelta, orderedIds });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', handleKeyDown, false);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown, false);
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<InfiniteScroll
|
||||
className="chat-list custom-scroll"
|
||||
@ -251,6 +259,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const chatFolder = folderId ? selectChatFolder(global, folderId) : undefined;
|
||||
|
||||
return {
|
||||
allListIds: listIds,
|
||||
chatsById,
|
||||
usersById,
|
||||
lastSyncTime,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCallback } from '../../../../lib/teact/teact';
|
||||
import { useMemo } from '../../../../lib/teact/teact';
|
||||
|
||||
export enum ChatAnimationTypes {
|
||||
Move,
|
||||
@ -7,29 +7,27 @@ export enum ChatAnimationTypes {
|
||||
}
|
||||
|
||||
export function useChatAnimationType(orderDiffById: Record<string, number>) {
|
||||
const movesUp = useCallback((id: string) => orderDiffById[id] < 0, [orderDiffById]);
|
||||
const movesDown = useCallback((id: string) => orderDiffById[id] > 0, [orderDiffById]);
|
||||
return useMemo(() => {
|
||||
const orderDiffs = Object.values(orderDiffById);
|
||||
const numberOfUp = orderDiffs.filter((diff) => diff < 0).length;
|
||||
const numberOfDown = orderDiffs.filter((diff) => diff > 0).length;
|
||||
|
||||
const orderDiffIds = Object.keys(orderDiffById);
|
||||
const numberOfUp = orderDiffIds.filter(movesUp).length;
|
||||
const numberOfDown = orderDiffIds.filter(movesDown).length;
|
||||
return (chatId: string): ChatAnimationTypes => {
|
||||
const orderDiff = orderDiffById[chatId];
|
||||
if (orderDiff === 0) {
|
||||
return ChatAnimationTypes.None;
|
||||
}
|
||||
|
||||
return useCallback((chatId: string): ChatAnimationTypes => {
|
||||
const orderDiff = orderDiffById[chatId];
|
||||
if (
|
||||
orderDiff === Infinity
|
||||
|| orderDiff === -Infinity
|
||||
|| (numberOfUp <= numberOfDown && orderDiff < 0)
|
||||
|| (numberOfDown < numberOfUp && orderDiff > 0)
|
||||
) {
|
||||
return ChatAnimationTypes.Opacity;
|
||||
}
|
||||
|
||||
if (orderDiff === 0) {
|
||||
return ChatAnimationTypes.None;
|
||||
}
|
||||
|
||||
if (
|
||||
orderDiff === Infinity
|
||||
|| orderDiff === -Infinity
|
||||
|| (numberOfUp <= numberOfDown && movesUp(chatId))
|
||||
|| (numberOfDown < numberOfUp && movesDown(chatId))
|
||||
) {
|
||||
return ChatAnimationTypes.Opacity;
|
||||
}
|
||||
|
||||
return ChatAnimationTypes.Move;
|
||||
}, [movesDown, movesUp, numberOfDown, numberOfUp, orderDiffById]);
|
||||
return ChatAnimationTypes.Move;
|
||||
};
|
||||
}, [orderDiffById]);
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import React, {
|
||||
} from '../../../../lib/teact/teact';
|
||||
import { withGlobal } from '../../../../lib/teact/teactn';
|
||||
|
||||
import { GlobalActions } from '../../../../global/types';
|
||||
import { GlobalActions, GlobalState } from '../../../../global/types';
|
||||
import { ApiChatFolder, ApiChat, ApiUser } from '../../../../api/types';
|
||||
import { NotifyException, NotifySettings, SettingsScreens } from '../../../../types';
|
||||
|
||||
@ -22,14 +22,15 @@ import Loading from '../../../ui/Loading';
|
||||
import AnimatedSticker from '../../../common/AnimatedSticker';
|
||||
|
||||
type OwnProps = {
|
||||
isActive?: boolean;
|
||||
onCreateFolder: () => void;
|
||||
onEditFolder: (folder: ApiChatFolder) => void;
|
||||
isActive?: boolean;
|
||||
onScreenSelect: (screen: SettingsScreens) => void;
|
||||
onReset: () => void;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
allListIds: GlobalState['chats']['listIds'];
|
||||
chatsById: Record<string, ApiChat>;
|
||||
usersById: Record<string, ApiUser>;
|
||||
orderedFolderIds?: number[];
|
||||
@ -46,11 +47,8 @@ const runThrottledForLoadRecommended = throttle((cb) => cb(), 60000, true);
|
||||
const MAX_ALLOWED_FOLDERS = 10;
|
||||
|
||||
const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
onCreateFolder,
|
||||
onEditFolder,
|
||||
isActive,
|
||||
onScreenSelect,
|
||||
onReset,
|
||||
allListIds,
|
||||
chatsById,
|
||||
usersById,
|
||||
orderedFolderIds,
|
||||
@ -58,6 +56,10 @@ const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
recommendedChatFolders,
|
||||
notifySettings,
|
||||
notifyExceptions,
|
||||
onCreateFolder,
|
||||
onEditFolder,
|
||||
onScreenSelect,
|
||||
onReset,
|
||||
loadRecommendedChatFolders,
|
||||
addChatFolder,
|
||||
showDialog,
|
||||
@ -104,8 +106,6 @@ const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const chatIds = Object.keys(chatsById);
|
||||
|
||||
return orderedFolderIds.map((id) => {
|
||||
const folder = foldersById[id];
|
||||
|
||||
@ -113,11 +113,11 @@ const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
id: folder.id,
|
||||
title: folder.title,
|
||||
subtitle: getFolderDescriptionText(
|
||||
lang, chatsById, usersById, folder, chatIds, notifySettings, notifyExceptions,
|
||||
lang, allListIds, chatsById, usersById, folder, notifySettings, notifyExceptions,
|
||||
),
|
||||
};
|
||||
});
|
||||
}, [orderedFolderIds, chatsById, foldersById, usersById, notifySettings, notifyExceptions, lang]);
|
||||
}, [lang, allListIds, foldersById, chatsById, usersById, orderedFolderIds, notifySettings, notifyExceptions]);
|
||||
|
||||
const handleCreateFolderFromRecommended = useCallback((folder: ApiChatFolder) => {
|
||||
if (Object.keys(foldersById).length >= MAX_ALLOWED_FOLDERS) {
|
||||
@ -229,7 +229,7 @@ const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global): StateProps => {
|
||||
const {
|
||||
chats: { byId: chatsById },
|
||||
chats: { listIds: allListIds, byId: chatsById },
|
||||
users: { byId: usersById },
|
||||
} = global;
|
||||
|
||||
@ -240,6 +240,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
} = global.chatFolders;
|
||||
|
||||
return {
|
||||
allListIds,
|
||||
chatsById,
|
||||
usersById,
|
||||
orderedFolderIds,
|
||||
|
||||
@ -76,7 +76,7 @@ addReducer('preloadTopChatMessages', (global, actions) => {
|
||||
}
|
||||
|
||||
const { chatId: currentChatId } = selectCurrentMessageList(global) || {};
|
||||
const { pinnedChats, otherChats } = prepareChatList(byId, listIds, orderedPinnedIds);
|
||||
const { pinnedChats, otherChats } = prepareChatList(byId, listIds, orderedPinnedIds, 'all', true);
|
||||
const topChats = [...pinnedChats, ...otherChats];
|
||||
const chatToPreload = topChats.find(({ id }) => id !== currentChatId && !preloadedChatIds.includes(id));
|
||||
if (!chatToPreload) {
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
MAIN_THREAD_ID,
|
||||
} from '../../api/types';
|
||||
|
||||
import { GlobalState } from '../../global/types';
|
||||
import { NotifyException, NotifySettings } from '../../types';
|
||||
import { LangFn } from '../../hooks/useLang';
|
||||
|
||||
@ -269,17 +270,17 @@ export function getCanDeleteChat(chat: ApiChat) {
|
||||
}
|
||||
|
||||
export function prepareFolderListIds(
|
||||
allListIds: GlobalState['chats']['listIds'],
|
||||
chatsById: Record<string, ApiChat>,
|
||||
usersById: Record<string, ApiUser>,
|
||||
folder: ApiChatFolder,
|
||||
notifySettings: NotifySettings,
|
||||
notifyExceptions?: Record<number, NotifyException>,
|
||||
chatIdsCache?: string[],
|
||||
) {
|
||||
const excludedChatIds = folder.excludedChatIds ? new Set(folder.excludedChatIds) : undefined;
|
||||
const includedChatIds = folder.excludedChatIds ? new Set(folder.includedChatIds) : undefined;
|
||||
const pinnedChatIds = folder.excludedChatIds ? new Set(folder.pinnedChatIds) : undefined;
|
||||
const listIds = (chatIdsCache || Object.keys(chatsById))
|
||||
const listIds = ([] as string[]).concat(allListIds.active || [], allListIds.archived || [])
|
||||
.filter((id) => {
|
||||
return filterChatFolder(
|
||||
chatsById[id],
|
||||
@ -296,6 +297,7 @@ export function prepareFolderListIds(
|
||||
return [listIds, folder.pinnedChatIds] as const;
|
||||
}
|
||||
|
||||
// This function is the most expensive in the project, so any possible optimizations are welcome
|
||||
function filterChatFolder(
|
||||
chat: ApiChat,
|
||||
folder: ApiChatFolder,
|
||||
@ -310,51 +312,55 @@ function filterChatFolder(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (excludedChatIds && excludedChatIds.has(chat.id)) {
|
||||
const { id: chatId, type, unreadMentionsCount } = chat;
|
||||
|
||||
if (excludedChatIds?.has(chatId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (includedChatIds && includedChatIds.has(chat.id)) {
|
||||
if (includedChatIds?.has(chatId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pinnedChatIds && pinnedChatIds.has(chat.id)) {
|
||||
if (pinnedChatIds?.has(chatId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isChatArchived(chat) && folder.excludeArchived) {
|
||||
if (folder.excludeArchived && chat.folderId === ARCHIVED_FOLDER_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (folder.excludeMuted && !chat.unreadMentionsCount && selectIsChatMuted(chat, notifySettings, notifyExceptions)) {
|
||||
if (folder.excludeRead && !chat.unreadCount && !unreadMentionsCount && !chat.hasUnreadMark) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!chat.unreadCount && !chat.unreadMentionsCount && !chat.hasUnreadMark && folder.excludeRead) {
|
||||
if (folder.excludeMuted && !unreadMentionsCount && selectIsChatMuted(chat, notifySettings, notifyExceptions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isUserId(chat.id)) {
|
||||
const privateChatUser = usersById[chat.id];
|
||||
if (type === 'chatTypePrivate') {
|
||||
const user = usersById[chatId];
|
||||
if (user) {
|
||||
const { type: userType, isContact } = user;
|
||||
|
||||
const isChatWithBot = privateChatUser && privateChatUser.type === 'userTypeBot';
|
||||
if (isChatWithBot) {
|
||||
if (folder.bots) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (folder.contacts && privateChatUser && privateChatUser.isContact) {
|
||||
return true;
|
||||
}
|
||||
if (userType === 'userTypeBot') {
|
||||
if (folder.bots) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (folder.contacts && isContact) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (folder.nonContacts && privateChatUser && !privateChatUser.isContact) {
|
||||
return true;
|
||||
if (folder.nonContacts && !isContact) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isChatGroup(chat)) {
|
||||
return !!folder.groups;
|
||||
} else if (isChatChannel(chat)) {
|
||||
} else if (type === 'chatTypeChannel') {
|
||||
return !!folder.channels;
|
||||
} else if (type === 'chatTypeBasicGroup' || type === 'chatTypeSuperGroup') {
|
||||
return !!folder.groups;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -365,6 +371,7 @@ export function prepareChatList(
|
||||
listIds: string[],
|
||||
orderedPinnedIds?: string[],
|
||||
folderType: 'all' | 'archived' | 'folder' = 'all',
|
||||
noOrder = false,
|
||||
) {
|
||||
const listIdsSet = new Set(listIds);
|
||||
const orderedPinnedIdsSet = orderedPinnedIds ? new Set(orderedPinnedIds) : undefined;
|
||||
@ -372,7 +379,7 @@ export function prepareChatList(
|
||||
const pinnedChats = orderedPinnedIds?.reduce((acc, id) => {
|
||||
const chat = chatsById[id];
|
||||
|
||||
if (chat && listIdsSet.has(chat.id) && chatFilter(chat, folderType)) {
|
||||
if (chat && listIdsSet.has(chat.id) && checkChat(chat, folderType)) {
|
||||
acc.push(chat);
|
||||
}
|
||||
|
||||
@ -382,39 +389,25 @@ export function prepareChatList(
|
||||
const otherChats = listIds.reduce((acc, id) => {
|
||||
const chat = chatsById[id];
|
||||
|
||||
if (chat && (!orderedPinnedIdsSet || !orderedPinnedIdsSet.has(chat.id)) && chatFilter(chat, folderType)) {
|
||||
if (chat && (!orderedPinnedIdsSet || !orderedPinnedIdsSet.has(chat.id)) && checkChat(chat, folderType)) {
|
||||
acc.push(chat);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, [] as ApiChat[]);
|
||||
const otherChatsOrdered = orderBy(otherChats, getChatOrder, 'desc');
|
||||
|
||||
return {
|
||||
pinnedChats,
|
||||
otherChats: otherChatsOrdered,
|
||||
otherChats: noOrder ? otherChats : orderBy(otherChats, getChatOrder, 'desc'),
|
||||
};
|
||||
}
|
||||
|
||||
function chatFilter(chat: ApiChat, folderType: 'all' | 'archived' | 'folder') {
|
||||
if (!chat.lastMessage || chat.migratedTo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (folderType) {
|
||||
case 'all':
|
||||
if (isChatArchived(chat)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'archived':
|
||||
if (!isChatArchived(chat)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return !chat.isRestricted && !chat.isNotJoined;
|
||||
function checkChat(chat: ApiChat, folderType: 'all' | 'archived' | 'folder') {
|
||||
return (
|
||||
chat.lastMessage && !chat.migratedTo && !chat.isRestricted && !chat.isNotJoined
|
||||
&& !(folderType === 'all' && chat.folderId === ARCHIVED_FOLDER_ID)
|
||||
&& !(folderType === 'archived' && chat.folderId !== ARCHIVED_FOLDER_ID)
|
||||
);
|
||||
}
|
||||
|
||||
export function reduceChatList(
|
||||
@ -430,26 +423,36 @@ export function reduceChatList(
|
||||
}
|
||||
|
||||
export function getFolderUnreadDialogs(
|
||||
allListIds: GlobalState['chats']['listIds'],
|
||||
chatsById: Record<string, ApiChat>,
|
||||
usersById: Record<string, ApiUser>,
|
||||
folder: ApiChatFolder,
|
||||
chatIdsCache: string[],
|
||||
notifySettings: NotifySettings,
|
||||
notifyExceptions?: Record<number, NotifyException>,
|
||||
) {
|
||||
const [listIds] = prepareFolderListIds(chatsById, usersById, folder, notifySettings, notifyExceptions, chatIdsCache);
|
||||
const [listIds] = prepareFolderListIds(allListIds, chatsById, usersById, folder, notifySettings, notifyExceptions);
|
||||
|
||||
const listedChats = listIds
|
||||
.map((id) => chatsById[id])
|
||||
.filter((chat) => (chat?.lastMessage && !chat.isRestricted && !chat.isNotJoined));
|
||||
let hasActiveDialogs = false;
|
||||
const unreadDialogsCount = listIds.reduce((acc, id) => {
|
||||
const chat = chatsById[id];
|
||||
if (!chat?.lastMessage || chat?.isRestricted || chat?.isNotJoined) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
const unreadDialogsCount = listedChats
|
||||
.reduce((total, chat) => (chat.unreadCount || chat.hasUnreadMark ? total + 1 : total), 0);
|
||||
const isUnread = chat.unreadCount || chat.hasUnreadMark;
|
||||
|
||||
const hasActiveDialogs = listedChats.some((chat) => (
|
||||
chat.unreadMentionsCount
|
||||
|| (!selectIsChatMuted(chat, notifySettings, notifyExceptions) && (chat.unreadCount || chat.hasUnreadMark))
|
||||
));
|
||||
if (isUnread) {
|
||||
acc++;
|
||||
}
|
||||
|
||||
if (!hasActiveDialogs && (
|
||||
chat.unreadMentionsCount || (isUnread && !selectIsChatMuted(chat, notifySettings, notifyExceptions))
|
||||
)) {
|
||||
hasActiveDialogs = true;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, 0);
|
||||
|
||||
return {
|
||||
unreadDialogsCount,
|
||||
@ -459,10 +462,10 @@ export function getFolderUnreadDialogs(
|
||||
|
||||
export function getFolderDescriptionText(
|
||||
lang: LangFn,
|
||||
allListIds: GlobalState['chats']['listIds'],
|
||||
chatsById: Record<string, ApiChat>,
|
||||
usersById: Record<string, ApiUser>,
|
||||
folder: ApiChatFolder,
|
||||
chatIdsCache: string[],
|
||||
notifySettings: NotifySettings,
|
||||
notifyExceptions?: Record<number, NotifyException>,
|
||||
) {
|
||||
@ -480,7 +483,7 @@ export function getFolderDescriptionText(
|
||||
|| (excludedChatIds?.length)
|
||||
|| (includedChatIds?.length)
|
||||
) {
|
||||
const length = getFolderChatsCount(chatsById, usersById, folder, chatIdsCache, notifySettings, notifyExceptions);
|
||||
const length = getFolderChatsCount(allListIds, chatsById, usersById, folder, notifySettings, notifyExceptions);
|
||||
return lang('Chats', length);
|
||||
}
|
||||
|
||||
@ -501,17 +504,17 @@ export function getFolderDescriptionText(
|
||||
}
|
||||
|
||||
function getFolderChatsCount(
|
||||
allListIds: GlobalState['chats']['listIds'],
|
||||
chatsById: Record<string, ApiChat>,
|
||||
usersById: Record<string, ApiUser>,
|
||||
folder: ApiChatFolder,
|
||||
chatIdsCache: string[],
|
||||
notifySettings: NotifySettings,
|
||||
notifyExceptions?: Record<string, NotifyException>,
|
||||
) {
|
||||
const [listIds, pinnedIds] = prepareFolderListIds(
|
||||
chatsById, usersById, folder, notifySettings, notifyExceptions, chatIdsCache,
|
||||
allListIds, chatsById, usersById, folder, notifySettings, notifyExceptions,
|
||||
);
|
||||
const { pinnedChats, otherChats } = prepareChatList(chatsById, listIds, pinnedIds, 'folder');
|
||||
const { pinnedChats, otherChats } = prepareChatList(chatsById, listIds, pinnedIds, 'folder', true);
|
||||
return pinnedChats.length + otherChats.length;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user