Settings / Folders: Fix layout in Settings Folders Chats Picker component (#4668)

This commit is contained in:
Alexander Zinchuk 2024-07-15 15:50:50 +02:00
parent 0f2c670e0f
commit 8faa652eb6
9 changed files with 181 additions and 370 deletions

View File

@ -37,6 +37,7 @@ type OwnProps = {
lockedUnselectedSubtitle?: string; lockedUnselectedSubtitle?: string;
filterValue?: string; filterValue?: string;
filterPlaceholder?: string; filterPlaceholder?: string;
categoryPlaceholderKey?: string;
notFoundText?: string; notFoundText?: string;
searchInputId?: string; searchInputId?: string;
isLoading?: boolean; isLoading?: boolean;
@ -65,6 +66,7 @@ const Picker: FC<OwnProps> = ({
categories, categories,
itemIds, itemIds,
selectedCategories, selectedCategories,
categoryPlaceholderKey,
selectedIds, selectedIds,
filterValue, filterValue,
filterPlaceholder, filterPlaceholder,
@ -171,7 +173,9 @@ const Picker: FC<OwnProps> = ({
onFilterChange?.(value); onFilterChange?.(value);
}); });
const [viewportIds, getMore] = useInfiniteScroll(onLoadMore, sortedItemIds, Boolean(filterValue)); const [viewportIds, getMore] = useInfiniteScroll(
onLoadMore, sortedItemIds, Boolean(filterValue),
);
const lang = useOldLang(); const lang = useOldLang();
@ -247,13 +251,15 @@ const Picker: FC<OwnProps> = ({
return ( return (
<div key="categories"> <div key="categories">
{Boolean(categories?.length) && ( {Boolean(categories?.length) && (
<div className="picker-category-title">{lang('PrivacyUserTypes')}</div> <>
{categoryPlaceholderKey && <div className="picker-category-title">{lang(categoryPlaceholderKey)}</div>}
{categories?.map((category) => renderItem(category.type, true))}
<div className="picker-category-title">{lang('FilterChats')}</div>
</>
)} )}
{categories?.map((category) => renderItem(category.type, true))}
<div className="picker-category-title">{lang('FilterChats')}</div>
</div> </div>
); );
}, [categories, lang, renderItem]); }, [categories, categoryPlaceholderKey, lang, renderItem]);
return ( return (
<div className={buildClassName('Picker', className)}> <div className={buildClassName('Picker', className)}>

View File

@ -146,6 +146,7 @@ const SettingsPrivacyVisibilityExceptionList: FC<OwnProps & StateProps> = ({
selectedCategories={newSelectedCategoryTypes} selectedCategories={newSelectedCategoryTypes}
filterValue={searchQuery} filterValue={searchQuery}
filterPlaceholder={isAllowList ? lang('AlwaysAllowPlaceholder') : lang('NeverAllowPlaceholder')} filterPlaceholder={isAllowList ? lang('AlwaysAllowPlaceholder') : lang('NeverAllowPlaceholder')}
categoryPlaceholderKey="PrivacyUserTypes"
searchInputId="new-group-picker-search" searchInputId="new-group-picker-search"
isSearchable isSearchable
onSelectedIdsChange={handleSelectedContactIdsChange} onSelectedIdsChange={handleSelectedContactIdsChange}

View File

@ -94,3 +94,16 @@
.settings-sortable-item .multiline-item { .settings-sortable-item .multiline-item {
padding-inline-end: 3rem; padding-inline-end: 3rem;
} }
.settings-folders-chat-list {
padding: 0.5rem;
}
.picker-category-title {
padding-top: 0.75rem;
}
.down {
font-size: 1.5rem;
margin-right: 0.5rem;
}

View File

@ -1,25 +1,31 @@
import type { FC } from '../../../../lib/teact/teact'; import type { FC } from '../../../../lib/teact/teact';
import React, { memo, useCallback, useMemo } from '../../../../lib/teact/teact'; import React, {
import { getGlobal } from '../../../../global'; memo, useEffect, useMemo, useState,
} from '../../../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../../../global';
import type { import type { FolderEditDispatch, FoldersState } from '../../../../hooks/reducers/useFoldersReducer';
FolderEditDispatch,
FoldersState,
} from '../../../../hooks/reducers/useFoldersReducer';
import { ALL_FOLDER_ID, ARCHIVED_FOLDER_ID } from '../../../../config'; import { ALL_FOLDER_ID, ARCHIVED_FOLDER_ID } from '../../../../config';
import { filterChatsByName } from '../../../../global/helpers'; import { filterChatsByName } from '../../../../global/helpers';
import { selectCurrentLimit } from '../../../../global/selectors/limits';
import { unique } from '../../../../util/iteratees'; import { unique } from '../../../../util/iteratees';
import { CUSTOM_PEER_EXCLUDED_CHAT_TYPES, CUSTOM_PEER_INCLUDED_CHAT_TYPES } from '../../../../util/objects/customPeer';
import { import { selectChatFilters } from '../../../../hooks/reducers/useFoldersReducer';
selectChatFilters,
} from '../../../../hooks/reducers/useFoldersReducer';
import { useFolderManagerForOrderedIds } from '../../../../hooks/useFolderManager'; import { useFolderManagerForOrderedIds } from '../../../../hooks/useFolderManager';
import useHistoryBack from '../../../../hooks/useHistoryBack'; import useHistoryBack from '../../../../hooks/useHistoryBack';
import useLastCallback from '../../../../hooks/useLastCallback';
import useOldLang from '../../../../hooks/useOldLang'; import useOldLang from '../../../../hooks/useOldLang';
import Icon from '../../../common/icons/Icon';
import Picker from '../../../common/Picker';
import FloatingActionButton from '../../../ui/FloatingActionButton';
import Loading from '../../../ui/Loading'; import Loading from '../../../ui/Loading';
import SettingsFoldersChatsPicker from './SettingsFoldersChatsPicker';
type StateProps = {
maxChats: number;
};
type OwnProps = { type OwnProps = {
mode: 'included' | 'excluded'; mode: 'included' | 'excluded';
@ -30,44 +36,62 @@ type OwnProps = {
onSaveFilter: VoidFunction; onSaveFilter: VoidFunction;
}; };
const SettingsFoldersChatFilters: FC<OwnProps> = ({ const SettingsFoldersChatFilters: FC<OwnProps & StateProps> = ({
mode, mode,
state, state,
dispatch, dispatch,
isActive, isActive,
onReset, onReset,
onSaveFilter, onSaveFilter,
maxChats,
}) => { }) => {
const lang = useOldLang();
const { openLimitReachedModal } = getActions();
const { chatFilter } = state; const { chatFilter } = state;
const { selectedChatIds, selectedChatTypes } = selectChatFilters(state, mode, true); const { selectedChatIds, selectedChatTypes } = selectChatFilters(state, mode, true);
const chatTypes = mode === 'included' ? CUSTOM_PEER_INCLUDED_CHAT_TYPES : CUSTOM_PEER_EXCLUDED_CHAT_TYPES;
const lang = useOldLang(); const [isTouched, setIsTouched] = useState(false);
const folderAllOrderedIds = useFolderManagerForOrderedIds(ALL_FOLDER_ID); const folderAllOrderedIds = useFolderManagerForOrderedIds(ALL_FOLDER_ID);
const folderArchivedOrderedIds = useFolderManagerForOrderedIds(ARCHIVED_FOLDER_ID); const folderArchivedOrderedIds = useFolderManagerForOrderedIds(ARCHIVED_FOLDER_ID);
const shouldHideChatTypes = state.folder.isChatList; const shouldHideChatTypes = state.folder.isChatList;
useEffect(() => {
if (!isActive) {
setIsTouched(false);
}
}, [isActive]);
const displayedIds = useMemo(() => { const displayedIds = useMemo(() => {
// No need for expensive global updates on chats, so we avoid them // No need for expensive global updates on chats, so we avoid them
const chatsById = getGlobal().chats.byId; const chatsById = getGlobal().chats.byId;
const chatIds = [...folderAllOrderedIds || [], ...folderArchivedOrderedIds || []]; const chatIds = [...folderAllOrderedIds || [], ...folderArchivedOrderedIds || []];
return unique([ return unique([
...selectedChatIds,
...filterChatsByName(lang, chatIds, chatsById, chatFilter), ...filterChatsByName(lang, chatIds, chatsById, chatFilter),
]); ]);
}, [folderAllOrderedIds, folderArchivedOrderedIds, selectedChatIds, lang, chatFilter]); }, [folderAllOrderedIds, folderArchivedOrderedIds, lang, chatFilter]);
const handleFilterChange = useCallback((newFilter: string) => { const handleFilterChange = useLastCallback((newFilter: string) => {
dispatch({ dispatch({
type: 'setChatFilter', type: 'setChatFilter',
payload: newFilter, payload: newFilter,
}); });
}, [dispatch]); setIsTouched(true);
});
const handleSelectedIdsChange = useCallback((ids: string[]) => { const handleSelectedIdsChange = useLastCallback((ids: string[]) => {
if (mode === 'included') { if (mode === 'included') {
if (ids.length >= maxChats) {
openLimitReachedModal({
limit: 'dialogFiltersChats',
});
return;
}
dispatch({ dispatch({
type: 'setIncludeFilters', type: 'setIncludeFilters',
payload: { ...state.includeFilters, includedChatIds: ids }, payload: { ...state.includeFilters, includedChatIds: ids },
@ -78,9 +102,10 @@ const SettingsFoldersChatFilters: FC<OwnProps> = ({
payload: { ...state.excludeFilters, excludedChatIds: ids }, payload: { ...state.excludeFilters, excludedChatIds: ids },
}); });
} }
}, [mode, state, dispatch]); setIsTouched(true);
});
const handleSelectedChatTypesChange = useCallback((keys: string[]) => { const handleSelectedChatTypesChange = useLastCallback((keys: string[]) => {
const newFilters: Record<string, boolean> = {}; const newFilters: Record<string, boolean> = {};
keys.forEach((key) => { keys.forEach((key) => {
newFilters[key] = true; newFilters[key] = true;
@ -103,7 +128,7 @@ const SettingsFoldersChatFilters: FC<OwnProps> = ({
}, },
}); });
} }
}, [mode, selectedChatIds, dispatch]); });
useHistoryBack({ useHistoryBack({
isActive, isActive,
@ -115,20 +140,38 @@ const SettingsFoldersChatFilters: FC<OwnProps> = ({
} }
return ( return (
<SettingsFoldersChatsPicker <div className="Picker settings-folders-chat-list">
mode={mode} <Picker
chatIds={displayedIds} categories={shouldHideChatTypes ? undefined : chatTypes}
selectedIds={selectedChatIds} itemIds={displayedIds}
selectedChatTypes={selectedChatTypes} selectedIds={selectedChatIds}
filterValue={chatFilter} selectedCategories={selectedChatTypes}
shouldHideChatTypes={shouldHideChatTypes} filterValue={chatFilter}
onSelectedIdsChange={handleSelectedIdsChange} filterPlaceholder={lang('Search')}
onSelectedChatTypesChange={handleSelectedChatTypesChange} categoryPlaceholderKey="FilterChatTypes"
onFilterChange={handleFilterChange} searchInputId="new-group-picker-search"
onSaveFilter={onSaveFilter} isSearchable
isActive={isActive} isRoundCheckbox
/> onSelectedIdsChange={handleSelectedIdsChange}
onSelectedCategoriesChange={handleSelectedChatTypesChange}
onFilterChange={handleFilterChange}
/>
<FloatingActionButton
isShown={isTouched}
onClick={onSaveFilter}
ariaLabel={lang('Save')}
>
<Icon name="check" />
</FloatingActionButton>
</div>
); );
}; };
export default memo(SettingsFoldersChatFilters); export default memo(withGlobal<OwnProps>(
(global): StateProps => {
return {
maxChats: selectCurrentLimit(global, 'dialogFiltersChats'),
};
},
)(SettingsFoldersChatFilters));

View File

@ -1,63 +0,0 @@
.SettingsFoldersChatsPicker {
height: calc(100% - var(--header-height));
.picker-header {
box-shadow: 0 0 2px var(--color-default-shadow);
.max-items-reached {
margin-bottom: 0.5rem;
margin-left: 0.5rem;
flex-grow: 1;
color: var(--color-text-secondary);
}
}
.picker-list {
padding: 0 0.5rem 0.5rem;
.no-results {
height: 10rem;
}
}
.ListItem.picker-list-item {
&.chat-type-item .ListItem-button {
padding: 0.875rem 0.75rem;
}
&.chat-item .ListItem-button {
padding: 0.5rem 0.75rem;
}
.Checkbox {
margin-left: auto;
padding-left: 3.25rem;
}
.chat-type {
font-size: 1rem;
font-weight: 400;
margin: 0;
}
&[dir="rtl"] {
.Checkbox {
margin-left: 0;
margin-right: auto;
padding-left: 0;
padding-right: 3.25rem;
}
}
}
.settings-item-header {
margin-left: 0.75rem;
margin-top: 1rem;
margin-bottom: 0.5rem;
}
.picker-list-divider {
margin: 0.5rem -0.5rem 0;
border-bottom: 1px solid var(--color-borders);
}
}

View File

@ -1,262 +0,0 @@
import type { FC } from '../../../../lib/teact/teact';
import React, {
memo, useCallback, useEffect, useRef, useState,
} from '../../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../../global';
import type { FolderChatType } from '../../../../hooks/reducers/useFoldersReducer';
import { requestMutation } from '../../../../lib/fasterdom/fasterdom';
import { isUserId } from '../../../../global/helpers';
import { selectCurrentLimit } from '../../../../global/selectors/limits';
import buildClassName from '../../../../util/buildClassName';
import {
EXCLUDED_CHAT_TYPES,
INCLUDED_CHAT_TYPES,
} from '../../../../hooks/reducers/useFoldersReducer';
import useInfiniteScroll from '../../../../hooks/useInfiniteScroll';
import useOldLang from '../../../../hooks/useOldLang';
import GroupChatInfo from '../../../common/GroupChatInfo';
import PickerSelectedItem from '../../../common/PickerSelectedItem';
import PrivateChatInfo from '../../../common/PrivateChatInfo';
import Checkbox from '../../../ui/Checkbox';
import FloatingActionButton from '../../../ui/FloatingActionButton';
import InfiniteScroll from '../../../ui/InfiniteScroll';
import InputText from '../../../ui/InputText';
import ListItem from '../../../ui/ListItem';
import Loading from '../../../ui/Loading';
import '../../../common/Picker.scss';
import './SettingsFoldersChatsPicker.scss';
type OwnProps = {
mode: 'included' | 'excluded';
chatIds: string[];
selectedIds: string[];
selectedChatTypes: string[];
filterValue?: string;
shouldHideChatTypes?: boolean;
onSelectedIdsChange: (ids: string[]) => void;
onSelectedChatTypesChange: (types: string[]) => void;
onFilterChange: (value: string) => void;
onSaveFilter: VoidFunction;
isActive?: boolean;
};
// Focus slows down animation, also it breaks transition layout in Chrome
const FOCUS_DELAY_MS = 500;
const MAX_FULL_ITEMS = 10;
const ALWAYS_FULL_ITEMS_COUNT = 5;
type StateProps = {
maxChats: number;
};
const SettingsFoldersChatsPicker: FC<OwnProps & StateProps> = ({
mode,
chatIds,
selectedIds,
selectedChatTypes,
filterValue,
shouldHideChatTypes,
onSelectedIdsChange,
onSelectedChatTypesChange,
onFilterChange,
maxChats,
onSaveFilter,
isActive,
}) => {
const { openLimitReachedModal } = getActions();
// eslint-disable-next-line no-null/no-null
const inputRef = useRef<HTMLInputElement>(null);
const chatTypes = mode === 'included' ? INCLUDED_CHAT_TYPES : EXCLUDED_CHAT_TYPES;
const shouldMinimize = selectedIds.length + selectedChatTypes.length > MAX_FULL_ITEMS;
const [isTouched, setIsTouched] = useState(false);
useEffect(() => {
if (!isActive) {
setIsTouched(false);
}
}, [isActive]);
useEffect(() => {
setTimeout(() => {
requestMutation(() => {
inputRef.current!.focus();
});
}, FOCUS_DELAY_MS);
}, []);
const handleItemClick = useCallback((id: string) => {
const newSelectedIds = [...selectedIds];
if (newSelectedIds.includes(id)) {
newSelectedIds.splice(newSelectedIds.indexOf(id), 1);
} else {
if (selectedIds.length >= maxChats && mode === 'included') {
openLimitReachedModal({
limit: 'dialogFiltersChats',
});
return;
}
newSelectedIds.push(id);
}
setIsTouched(true);
onSelectedIdsChange(newSelectedIds);
}, [selectedIds, onSelectedIdsChange, maxChats, mode, openLimitReachedModal]);
const handleChatTypeClick = useCallback((key: FolderChatType['key']) => {
const newSelectedChatTypes = [...selectedChatTypes];
if (newSelectedChatTypes.includes(key)) {
newSelectedChatTypes.splice(newSelectedChatTypes.indexOf(key), 1);
} else {
newSelectedChatTypes.push(key);
}
setIsTouched(true);
onSelectedChatTypesChange(newSelectedChatTypes);
}, [selectedChatTypes, onSelectedChatTypesChange]);
const handleFilterChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const { value } = e.currentTarget;
onFilterChange(value);
}, [onFilterChange]);
const lang = useOldLang();
function renderSelectedChatType(key: string) {
const selectedType = chatTypes.find(({ key: typeKey }) => key === typeKey);
if (!selectedType) {
return undefined;
}
return (
<PickerSelectedItem
icon={selectedType.icon}
title={lang(selectedType.title)}
isMinimized={shouldMinimize}
canClose
onClick={handleChatTypeClick}
clickArg={selectedType.key}
/>
);
}
function renderChatType(type: FolderChatType) {
return (
<ListItem
key={type.key}
className="chat-item-clickable picker-list-item chat-type-item"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => handleChatTypeClick(type.key)}
ripple
>
<i className={buildClassName('icon', `icon-${type.icon}`)} />
<h3 className="chat-type" dir="auto">{lang(type.title)}</h3>
<Checkbox
label=""
checked={selectedChatTypes.includes(type.key)}
round
/>
</ListItem>
);
}
function renderItem(id: string) {
const isSelected = selectedIds.includes(id);
return (
<ListItem
key={id}
className="chat-item-clickable picker-list-item chat-item"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => handleItemClick(id)}
ripple
>
{isUserId(id) ? (
<PrivateChatInfo userId={id} />
) : (
<GroupChatInfo chatId={id} withChatType />
)}
<Checkbox
label=""
checked={isSelected}
round
/>
</ListItem>
);
}
const [viewportIds, getMore] = useInfiniteScroll(undefined, chatIds, Boolean(filterValue));
return (
<div className="Picker SettingsFoldersChatsPicker">
<div className="picker-header custom-scroll">
{selectedChatTypes.map(renderSelectedChatType)}
{selectedIds.map((id, i) => (
<PickerSelectedItem
peerId={id}
isMinimized={shouldMinimize && i < selectedIds.length - ALWAYS_FULL_ITEMS_COUNT}
canClose
onClick={handleItemClick}
clickArg={id}
/>
))}
<InputText
ref={inputRef}
value={filterValue}
onChange={handleFilterChange}
placeholder={lang('Search')}
/>
</div>
<InfiniteScroll
className="picker-list custom-scroll fab-padding-bottom"
itemSelector=".chat-item"
items={viewportIds}
onLoadMore={getMore}
>
{(!viewportIds || !viewportIds.length || viewportIds.includes(chatIds[0])) && (
<div key="header">
{!shouldHideChatTypes && (
<>
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
{lang('FilterChatTypes')}
</h4>
{chatTypes.map(renderChatType)}
<div className="picker-list-divider" />
</>
)}
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
{lang('FilterChats')}
</h4>
</div>
)}
{viewportIds?.length ? (
viewportIds.map(renderItem)
) : viewportIds && !viewportIds.length ? (
<p className="no-results" key="no-results">Sorry, nothing found.</p>
) : (
<Loading key="loading" />
)}
</InfiniteScroll>
<FloatingActionButton
isShown={isTouched}
onClick={onSaveFilter}
ariaLabel={lang('Save')}
>
<i className="icon icon-check" />
</FloatingActionButton>
</div>
);
};
export default memo(withGlobal<OwnProps>(
(global): StateProps => {
return {
maxChats: selectCurrentLimit(global, 'dialogFiltersChats'),
};
},
)(SettingsFoldersChatsPicker));

View File

@ -28,11 +28,11 @@ import useOldLang from '../../../../hooks/useOldLang';
import AnimatedIcon from '../../../common/AnimatedIcon'; import AnimatedIcon from '../../../common/AnimatedIcon';
import GroupChatInfo from '../../../common/GroupChatInfo'; import GroupChatInfo from '../../../common/GroupChatInfo';
import Icon from '../../../common/icons/Icon';
import PrivateChatInfo from '../../../common/PrivateChatInfo'; import PrivateChatInfo from '../../../common/PrivateChatInfo';
import FloatingActionButton from '../../../ui/FloatingActionButton'; import FloatingActionButton from '../../../ui/FloatingActionButton';
import InputText from '../../../ui/InputText'; import InputText from '../../../ui/InputText';
import ListItem from '../../../ui/ListItem'; import ListItem from '../../../ui/ListItem';
import ShowMoreButton from '../../../ui/ShowMoreButton';
import Spinner from '../../../ui/Spinner'; import Spinner from '../../../ui/Spinner';
type OwnProps = { type OwnProps = {
@ -265,12 +265,14 @@ const SettingsFoldersEdit: FC<OwnProps & StateProps> = ({
</ListItem> </ListItem>
))} ))}
{(!isExpanded && leftChatsCount > 0) && ( {(!isExpanded && leftChatsCount > 0) && (
<ShowMoreButton <ListItem
count={leftChatsCount} key="load-more"
itemName="chat"
// eslint-disable-next-line react/jsx-no-bind // eslint-disable-next-line react/jsx-no-bind
onClick={clickHandler} onClick={clickHandler}
/> >
<Icon name="down" className="down" />
{lang('FilterShowMoreChats', leftChatsCount, 'i')}
</ListItem>
)} )}
</> </>
); );

View File

@ -483,7 +483,8 @@ export type InlineBotSettings = {
cacheTime: number; cacheTime: number;
}; };
export type CustomPeerType = 'premium' | 'toBeDistributed'; export type CustomPeerType = 'premium' | 'toBeDistributed' | 'contacts' | 'nonContacts'
| 'groups' | 'channels' | 'bots' | 'excludeMuted' | 'excludeArchived' | 'excludeRead';
export interface CustomPeer { export interface CustomPeer {
isCustomPeer: true; isCustomPeer: true;

View File

@ -17,3 +17,73 @@ export const CUSTOM_PEER_TO_BE_DISTRIBUTED: UniqueCustomPeer = {
avatarIcon: 'user', avatarIcon: 'user',
withPremiumGradient: true, withPremiumGradient: true,
}; };
export const CUSTOM_PEER_INCLUDED_CHAT_TYPES: UniqueCustomPeer[] = [
{
isCustomPeer: true,
type: 'contacts',
titleKey: 'FilterContacts',
avatarIcon: 'user',
isAvatarSquare: true,
peerColorId: 5,
},
{
isCustomPeer: true,
type: 'nonContacts',
titleKey: 'FilterNonContacts',
avatarIcon: 'non-contacts',
isAvatarSquare: true,
peerColorId: 4,
},
{
isCustomPeer: true,
type: 'groups',
titleKey: 'FilterGroups',
avatarIcon: 'group',
isAvatarSquare: true,
peerColorId: 3,
},
{
isCustomPeer: true,
type: 'channels',
titleKey: 'FilterChannels',
avatarIcon: 'channel',
isAvatarSquare: true,
peerColorId: 1,
},
{
isCustomPeer: true,
type: 'bots',
titleKey: 'FilterBots',
avatarIcon: 'bots',
isAvatarSquare: true,
peerColorId: 6,
},
];
export const CUSTOM_PEER_EXCLUDED_CHAT_TYPES: UniqueCustomPeer[] = [
{
isCustomPeer: true,
type: 'excludeMuted',
titleKey: 'FilterMuted',
avatarIcon: 'mute',
isAvatarSquare: true,
peerColorId: 6,
},
{
isCustomPeer: true,
type: 'excludeRead',
titleKey: 'FilterRead',
avatarIcon: 'readchats',
isAvatarSquare: true,
peerColorId: 4,
},
{
isCustomPeer: true,
type: 'excludeArchived',
titleKey: 'FilterArchived',
avatarIcon: 'archive',
isAvatarSquare: true,
peerColorId: 5,
},
];