diff --git a/src/components/sidebarLeft/tabs/archivedTab.ts b/src/components/sidebarLeft/tabs/archivedTab.ts index 777bae02..620fe82e 100644 --- a/src/components/sidebarLeft/tabs/archivedTab.ts +++ b/src/components/sidebarLeft/tabs/archivedTab.ts @@ -5,12 +5,11 @@ */ import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; -import type { LOCAL_FOLDER_ID } from "../../../lib/storages/dialogs"; -import type { MyDialogFilter } from "../../../lib/storages/filters"; import { SliderSuperTab } from "../../slider"; +import { FOLDER_ID_ARCHIVE, REAL_FOLDER_ID } from "../../../lib/mtproto/mtproto_config"; export default class AppArchivedTab extends SliderSuperTab { - private static filterId: LOCAL_FOLDER_ID = 1; + private static filterId: REAL_FOLDER_ID = FOLDER_ID_ARCHIVE; private wasFilterId: number; protected init() { @@ -21,7 +20,12 @@ export default class AppArchivedTab extends SliderSuperTab { if(!appDialogsManager.sortedLists[AppArchivedTab.filterId]) { const chatList = appDialogsManager.createChatList(); - appDialogsManager.generateScrollable(chatList, {id: AppArchivedTab.filterId, orderIndex: 1} as any as MyDialogFilter).container.append(chatList); + const scrollable = appDialogsManager.generateScrollable(chatList, { + title: undefined, + id: AppArchivedTab.filterId, + localId: FOLDER_ID_ARCHIVE + }); + scrollable.container.append(chatList); appDialogsManager.setListClickListener(chatList, null, true); //appDialogsManager.setListClickListener(archivedChatList, null, true); // * to test peer changing } diff --git a/src/components/sidebarLeft/tabs/chatFolders.ts b/src/components/sidebarLeft/tabs/chatFolders.ts index b17141ca..b7677186 100644 --- a/src/components/sidebarLeft/tabs/chatFolders.ts +++ b/src/components/sidebarLeft/tabs/chatFolders.ts @@ -109,9 +109,9 @@ export default class AppChatFoldersTab extends SliderSuperTab { div = row.container; - if((filter as MyDialogFilter).hasOwnProperty('orderIndex')) { + if((filter as MyDialogFilter).localId !== undefined) { // ! header will be at 0 index - positionElementByIndex(div, div.parentElement || container, (filter as MyDialogFilter).orderIndex); + positionElementByIndex(div, div.parentElement || container, (filter as MyDialogFilter).localId); } else if(container) container.append(div); return div; diff --git a/src/config/state.ts b/src/config/state.ts index c7f1053e..fff7d7fb 100644 --- a/src/config/state.ts +++ b/src/config/state.ts @@ -50,7 +50,8 @@ export type State = { pts: number, date: number }>, - filters: FiltersStorage['filters'], + // filters?: FiltersStorage['filters'], // ! DEPRECATED + filtersArr?: FiltersStorage['filtersArr'], maxSeenMsgId: number, stateCreatedTime: number, recentEmoji: string[], @@ -151,7 +152,7 @@ export const STATE_INIT: State = { // contactsList: [], contactsListCachedTime: 0, updates: {}, - filters: {}, + filtersArr: [], maxSeenMsgId: 0, stateCreatedTime: Date.now(), recentEmoji: [], diff --git a/src/layer.d.ts b/src/layer.d.ts index ab7ddbd4..82cd9313 100644 --- a/src/layer.d.ts +++ b/src/layer.d.ts @@ -8399,6 +8399,7 @@ export namespace DialogFilter { exclude_muted?: true, exclude_read?: true, exclude_archived?: true, + exclude_unarchived?: true, }>, id: number, title: string, @@ -8406,13 +8407,15 @@ export namespace DialogFilter { pinned_peers: Array, include_peers: Array, exclude_peers: Array, - orderIndex?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21, - peerId?: PeerId, - folder_id?: number + localId?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21, + pinnedPeerIds?: PeerId[], + includePeerIds?: PeerId[], + excludePeerIds?: PeerId[] }; export type dialogFilterDefault = { - _: 'dialogFilterDefault' + _: 'dialogFilterDefault', + localId?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 }; } diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 070b8bdc..18dc87ad 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -45,7 +45,7 @@ import isInDOM from "../../helpers/dom/isInDOM"; import { setSendingStatus } from "../../components/sendingStatus"; import SortedList, { SortedElementBase } from "../../helpers/sortedList"; import debounce from "../../helpers/schedulers/debounce"; -import { NULL_PEER_ID } from "../mtproto/mtproto_config"; +import { FOLDER_ID_ALL, FOLDER_ID_ARCHIVE, NULL_PEER_ID, REAL_FOLDERS, REAL_FOLDER_ID } from "../mtproto/mtproto_config"; import groupCallActiveIcon from "../../components/groupCallActiveIcon"; import { Chat, Message, NotifyPeer } from "../../layer"; import IS_GROUP_CALL_SUPPORTED from "../../environment/groupCallSupport"; @@ -81,6 +81,7 @@ import DialogsPlaceholder from "../../helpers/dialogsPlaceholder"; import pause from "../../helpers/schedulers/pause"; import apiManagerProxy from "../mtproto/mtprotoworker"; import filterAsync from "../../helpers/array/filterAsync"; +import forEachReverse from "../../helpers/array/forEachReverse"; export const DIALOG_LIST_ELEMENT_TAG = 'A'; @@ -315,11 +316,11 @@ export class AppDialogsManager { })//, 5000); }); - this.setFilterId(0, 0); + this.setFilterId(FOLDER_ID_ALL, FOLDER_ID_ALL); this.addFilter({ - id: this.filterId, + id: FOLDER_ID_ALL, title: '', - orderIndex: 0 + localId: FOLDER_ID_ALL }); const foldersScrollable = new ScrollableX(this.folders.menuScrollContainer); @@ -329,7 +330,7 @@ export class AppDialogsManager { id += 1; } */ - id = +tabContent.dataset.filterId || 0; + id = +tabContent.dataset.filterId || FOLDER_ID_ALL; if(!IS_MOBILE_SAFARI) { if(id) { @@ -420,15 +421,15 @@ export class AppDialogsManager { this.scroll = this.scrollables[this.filterId]; //selectTab(0); - (this.folders.menu.firstElementChild as HTMLElement).click(); + // (this.folders.menu.firstElementChild as HTMLElement).click(); } public get chatList() { return this.sortedList.list; } - public setFilterId(filterId: number, orderIndex: MyDialogFilter['orderIndex']) { - this.indexKey = getDialogIndexKey(orderIndex); + public setFilterId(filterId: number, localId: MyDialogFilter['localId']) { + this.indexKey = getDialogIndexKey(localId); this.filterId = filterId; } @@ -552,6 +553,10 @@ export class AppDialogsManager { }); rootScope.addEventListener('filter_update', async(filter) => { + if(REAL_FOLDERS.has(filter.id)) { + return; + } + if(!this.filtersRendered[filter.id]) { this.addFilter(filter); return; @@ -602,8 +607,8 @@ export class AppDialogsManager { const sortedList = this.sortedLists[filterId]; sortedList.indexKey = indexKey; - positionElementByIndex(renderedFilter.menu, containerToAppend, filter.orderIndex); - positionElementByIndex(renderedFilter.container, this.folders.container, filter.orderIndex); + positionElementByIndex(renderedFilter.menu, containerToAppend, filter.localId); + positionElementByIndex(renderedFilter.container, this.folders.container, filter.localId); }); this.indexKey = await this.managers.dialogsStorage.getDialogIndexKeyByFilterId(this.filterId); @@ -642,6 +647,27 @@ export class AppDialogsManager { } private async onStateLoaded(state: State) { + const filtersArr = state.filtersArr; + const haveFilters = filtersArr.length > REAL_FOLDERS.size; + const filter = filtersArr.find((filter) => filter.id !== FOLDER_ID_ARCHIVE); + + const addFilters = (filters: MyDialogFilter[]) => { + // forEachReverse(filters, (filter) => { + // this.addFilter(filter); + // }); + for(const filter of filters) { + this.addFilter(filter); + } + }; + + if(haveFilters) { + addFilters(filtersArr); + } else { + this.managers.filtersStorage.getDialogFilters().then(addFilters); + } + + (this.folders.menu.firstElementChild as HTMLElement).click(); + const loadDialogsPromise = this.onChatsScroll(); if(!this.initedListeners) { @@ -649,19 +675,8 @@ export class AppDialogsManager { this.initedListeners = true; } - const haveFilters = !!(state.filters && Object.keys(state.filters).length); - const getDialogsFiltersPromise = haveFilters ? Promise.resolve(Object.values(state.filters).sort((a, b) => a.orderIndex - b.orderIndex)) : this.managers.filtersStorage.getDialogFilters(); - const renderFiltersPromise = getDialogsFiltersPromise.then((filters) => { - for(const filter of filters) { - this.addFilter(filter); - } - }); - - if(haveFilters) { - await renderFiltersPromise; - if(this.showFiltersPromise) { - await this.showFiltersPromise; - } + if(haveFilters && this.showFiltersPromise) { + await this.showFiltersPromise; } this.managers.appNotificationsManager.getNotifyPeerTypeSettings(); @@ -738,7 +753,7 @@ export class AppDialogsManager { }; private async setFilterUnreadCount(filterId: number) { - if(filterId === 0) { + if(filterId === FOLDER_ID_ALL) { return; } @@ -786,7 +801,7 @@ export class AppDialogsManager { public testDialogForFilter(dialog: Dialog) { if( !dialog || - (this.filterId > 1 ? getDialogIndex(dialog, this.indexKey) === undefined : this.filterId !== dialog.folder_id) + (!REAL_FOLDERS.has(this.filterId) ? getDialogIndex(dialog, this.indexKey) === undefined : this.filterId !== dialog.folder_id) // (filter && !(await this.managers.filtersStorage.testDialogForFilter(dialog, filter))) ) { return false; @@ -807,7 +822,7 @@ export class AppDialogsManager { const sortedDialogList = new SortedDialogList( this.managers, list, - getDialogIndexKey(filter.orderIndex), + getDialogIndexKey(filter.localId), this.onListLengthChange ); @@ -820,16 +835,16 @@ export class AppDialogsManager { return scrollable; } - private addFilter(filter: Pick) { - if(filter.id === 1) { + private addFilter(filter: Pick) { + if(filter.id === FOLDER_ID_ARCHIVE) { return; } const containerToAppend = this.folders.menu as HTMLElement; const renderedFilter = this.filtersRendered[filter.id]; if(renderedFilter) { - positionElementByIndex(renderedFilter.menu, containerToAppend, filter.orderIndex); - positionElementByIndex(renderedFilter.container, this.folders.container, filter.orderIndex); + positionElementByIndex(renderedFilter.menu, containerToAppend, filter.localId); + positionElementByIndex(renderedFilter.container, this.folders.container, filter.localId); return; } @@ -838,7 +853,7 @@ export class AppDialogsManager { const span = document.createElement('span'); const titleSpan = document.createElement('span'); titleSpan.classList.add('text-super'); - if(filter.id === 0) titleSpan.append(this.allChatsIntlElement.element); + if(filter.id === FOLDER_ID_ALL) titleSpan.append(this.allChatsIntlElement.element); else setInnerHTML(titleSpan, wrapEmojiText(filter.title)); const unreadSpan = document.createElement('div'); unreadSpan.classList.add('badge', 'badge-20', 'badge-primary'); @@ -847,7 +862,9 @@ export class AppDialogsManager { ripple(menuTab); menuTab.append(span); - positionElementByIndex(menuTab, containerToAppend, filter.orderIndex); + menuTab.dataset.filterId = '' + filter.id; + + positionElementByIndex(menuTab, containerToAppend, filter.localId); //containerToAppend.append(li); const ul = this.createChatList(); @@ -871,7 +888,7 @@ export class AppDialogsManager { const div = scrollable.container; //this.folders.container.append(div); - positionElementByIndex(scrollable.container, this.folders.container, filter.orderIndex); + positionElementByIndex(scrollable.container, this.folders.container, filter.localId); this.setListClickListener(ul, null, true); @@ -969,7 +986,7 @@ export class AppDialogsManager { ) ) { placeholder = this.placeholders[filterId] = new DialogsPlaceholder(); - const getRectFrom = filterId === 1 ? this.chatsContainer : this.folders.container; + const getRectFrom = filterId === FOLDER_ID_ARCHIVE ? this.chatsContainer : this.folders.container; placeholder.attach({ container: chatList.parentElement, getRectFrom, @@ -1104,7 +1121,7 @@ export class AppDialogsManager { } private checkIfPlaceholderNeeded() { - if(this.filterId === 1) { + if(this.filterId === FOLDER_ID_ARCHIVE) { return; } @@ -1239,7 +1256,7 @@ export class AppDialogsManager { this.checkIfPlaceholderNeeded(); - if(this.filterId > 0) return; + if(this.filterId !== FOLDER_ID_ALL) return; const chatList = this.chatList; const count = chatList.childElementCount; diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 12acb485..1636fcaf 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -18,14 +18,14 @@ import { ArgumentTypes, InvokeApiOptions } from "../../types"; import { logger, LogTypes } from "../logger"; import type { ApiFileManager } from '../mtproto/apiFileManager'; import { ReferenceContext } from "../mtproto/referenceDatabase"; -import { GLOBAL_FOLDER_ID, LOCAL_FOLDER_ID } from "../storages/dialogs"; +import { GLOBAL_FOLDER_ID } from "../storages/dialogs"; import { ChatRights } from "./appChatsManager"; import { MyDocument } from "./appDocsManager"; import { MyPhoto } from "./appPhotosManager"; import { getFileNameByLocation } from "../../helpers/fileName"; import DEBUG from "../../config/debug"; import SlicedArray, { Slice, SliceEnd } from "../../helpers/slicedArray"; -import { MUTE_UNTIL, NULL_PEER_ID, REPLIES_HIDDEN_CHANNEL_ID, REPLIES_PEER_ID, SERVICE_PEER_ID } from "../mtproto/mtproto_config"; +import { FOLDER_ID_ALL, MUTE_UNTIL, NULL_PEER_ID, REAL_FOLDER_ID, REPLIES_HIDDEN_CHANNEL_ID, REPLIES_PEER_ID, SERVICE_PEER_ID } from "../mtproto/mtproto_config"; import telegramMeWebManager from "../mtproto/telegramMeWebManager"; import { getMiddleware } from "../../helpers/middleware"; import assumeType from "../../helpers/assumeType"; @@ -1852,7 +1852,7 @@ export class AppMessagesManager extends AppManager { } // public lolSet = new Set(); - public getTopMessages(limit: number, folderId: LOCAL_FOLDER_ID, offsetDate?: number) { + public getTopMessages(limit: number, folderId: REAL_FOLDER_ID, offsetDate?: number) { //const dialogs = this.dialogsStorage.getFolder(folderId); let offsetId = 0; let offsetPeerId: PeerId; @@ -1913,7 +1913,7 @@ export class AppMessagesManager extends AppManager { let maxSeenIdIncremented = offsetDate ? true : false; let hasPrepend = false; const noIdsDialogs: {[peerId: PeerId]: Dialog} = {}; - const setFolderId: LOCAL_FOLDER_ID = folderId === GLOBAL_FOLDER_ID ? 0 : folderId; + const setFolderId: REAL_FOLDER_ID = folderId === GLOBAL_FOLDER_ID ? FOLDER_ID_ALL : folderId; const saveGlobalOffset = folderId === GLOBAL_FOLDER_ID; forEachReverse((dialogsResult.dialogs as Dialog[]), (dialog) => { //const d = Object.assign({}, dialog); diff --git a/src/lib/appManagers/utils/dialogs/getDialogIndex.ts b/src/lib/appManagers/utils/dialogs/getDialogIndex.ts index f0c78d9d..d9670220 100644 --- a/src/lib/appManagers/utils/dialogs/getDialogIndex.ts +++ b/src/lib/appManagers/utils/dialogs/getDialogIndex.ts @@ -11,5 +11,5 @@ export default function getDialogIndex( dialog: Dialog.dialog, indexKey: ReturnType = getDialogIndexKey(dialog.folder_id) ) { - return dialog && dialog[indexKey]; + return dialog?.[indexKey]; } diff --git a/src/lib/appManagers/utils/dialogs/getDialogIndexKey.ts b/src/lib/appManagers/utils/dialogs/getDialogIndexKey.ts index 7557c1bf..d74c5b14 100644 --- a/src/lib/appManagers/utils/dialogs/getDialogIndexKey.ts +++ b/src/lib/appManagers/utils/dialogs/getDialogIndexKey.ts @@ -6,8 +6,8 @@ import type { DialogFilter } from "../../../../layer"; -export default function getDialogIndexKey(orderIndex?: DialogFilter.dialogFilter['orderIndex']) { - return `index_${orderIndex}` as const; +export default function getDialogIndexKey(localId?: DialogFilter.dialogFilter['localId']) { + return `index_${localId}` as const; // return filterId !== undefined && filterId > 1 ? `filter_${filterId}` as const : 'main' as const; // const indexStr = filterId > 1 ? // `index_${filterId}` as const : diff --git a/src/lib/appManagers/utils/state/loadState.ts b/src/lib/appManagers/utils/state/loadState.ts index 4a8192e3..c3e12473 100644 --- a/src/lib/appManagers/utils/state/loadState.ts +++ b/src/lib/appManagers/utils/state/loadState.ts @@ -32,7 +32,7 @@ const REFRESH_KEYS: Array = [ 'contactsListCachedTime', 'stateCreatedTime', 'maxSeenMsgId', - 'filters' + 'filtersArr' ]; //const REFRESH_KEYS_WEEK = ['dialogs', 'allDialogsLoaded', 'updates', 'pinnedOrders'] as any as Array; @@ -300,7 +300,7 @@ async function loadStateInner() { // reset filters and dialogs if version is older if(compareVersion(state.version, '0.8.7') === -1 || state.build < 179) { state.allDialogsLoaded = copy(STATE_INIT.allDialogsLoaded); - state.filters = copy(STATE_INIT.filters); + // state.filters = copy(STATE_INIT.filters); resetStorages.add('dialogs'); } diff --git a/src/lib/mtproto/mtproto_config.ts b/src/lib/mtproto/mtproto_config.ts index 5c3ced16..5cb055b5 100644 --- a/src/lib/mtproto/mtproto_config.ts +++ b/src/lib/mtproto/mtproto_config.ts @@ -4,11 +4,11 @@ * https://github.com/morethanwords/tweb/blob/master/LICENSE */ - /** * Legacy Webogram's format, don't change dcID to camelCase. date is timestamp */ export type UserAuth = {dcID: number | string, date: number, id: PeerId}; +export type REAL_FOLDER_ID = 0 | 1; export const NULL_PEER_ID: PeerId = 0; export const REPLIES_PEER_ID: PeerId = 1271266957; @@ -16,3 +16,7 @@ export const REPLIES_HIDDEN_CHANNEL_ID: ChatId = 777; export const SERVICE_PEER_ID: PeerId = 777000; export const MUTE_UNTIL = 0x7FFFFFFF; export const BOT_START_PARAM = ''; + +export const FOLDER_ID_ALL: REAL_FOLDER_ID = 0; +export const FOLDER_ID_ARCHIVE: REAL_FOLDER_ID = 1; +export const REAL_FOLDERS: Set = new Set([FOLDER_ID_ALL, FOLDER_ID_ARCHIVE]); diff --git a/src/lib/storages/dialogs.ts b/src/lib/storages/dialogs.ts index 8e392916..2b4d9a87 100644 --- a/src/lib/storages/dialogs.ts +++ b/src/lib/storages/dialogs.ts @@ -15,7 +15,7 @@ import tsNow from "../../helpers/tsNow"; import SearchIndex from "../searchIndex"; import { SliceEnd } from "../../helpers/slicedArray"; import { MyDialogFilter } from "./filters"; -import { NULL_PEER_ID } from "../mtproto/mtproto_config"; +import { FOLDER_ID_ALL, FOLDER_ID_ARCHIVE, NULL_PEER_ID, REAL_FOLDERS, REAL_FOLDER_ID } from "../mtproto/mtproto_config"; import { NoneToVoidFunction } from "../../types"; import ctx from "../../environment/ctx"; import AppStorage from "../storage"; @@ -50,8 +50,7 @@ export type Folder = { dispatchUnreadTimeout?: number }; -export const GLOBAL_FOLDER_ID: LOCAL_FOLDER_ID = undefined; -export type LOCAL_FOLDER_ID = 0 | 1; +export const GLOBAL_FOLDER_ID: REAL_FOLDER_ID = undefined; // let spentTime = 0; export default class DialogsStorage extends AppManager { @@ -159,9 +158,15 @@ export default class DialogsStorage extends AppManager { this.storage = storage; this.dialogs = this.storage.getCache(); - this.pinnedOrders = state.pinnedOrders || {}; - if(!this.pinnedOrders[0]) this.pinnedOrders[0] = []; - if(!this.pinnedOrders[1]) this.pinnedOrders[1] = []; + for(const folderId of REAL_FOLDERS) { + const order = state.pinnedOrders[folderId]; + if(!order) { + continue; + } + + const _order = this.pinnedOrders[folderId]; + _order.splice(0, _order.length, ...order); + } if(dialogs.length) { AppStorage.freezeSaving(this.setDialogsFromState.bind(this, dialogs), ['chats', 'dialogs', 'messages', 'users']); @@ -212,13 +217,13 @@ export default class DialogsStorage extends AppManager { public setDialogsLoaded(folderId: number, loaded: boolean) { if(folderId === GLOBAL_FOLDER_ID && loaded) { - this.allDialogsLoaded[0] = loaded; - this.allDialogsLoaded[1] = loaded; + this.allDialogsLoaded[FOLDER_ID_ALL] = loaded; + this.allDialogsLoaded[FOLDER_ID_ARCHIVE] = loaded; } else { this.allDialogsLoaded[folderId] = loaded; } - if(this.allDialogsLoaded[0] && this.allDialogsLoaded[1]) { + if(Array.from(REAL_FOLDERS).every((folderId) => this.allDialogsLoaded[folderId])) { this.allDialogsLoaded[GLOBAL_FOLDER_ID] = true; } @@ -226,20 +231,23 @@ export default class DialogsStorage extends AppManager { } public clear = (init = false) => { - this.pinnedOrders = { - 0: [], - 1: [] - }; - if(!init) { this.storage.clear(); - this.setDialogsLoaded(0, false); - this.setDialogsLoaded(1, false); + this.setDialogsLoaded(FOLDER_ID_ALL, false); + this.setDialogsLoaded(FOLDER_ID_ARCHIVE, false); this.setDialogsLoaded(GLOBAL_FOLDER_ID, false); + + for(const folderId of REAL_FOLDERS) { + this.resetPinnedOrder(folderId); + } this.savePinnedOrders(); } else { this.allDialogsLoaded = {}; + this.pinnedOrders = {}; + for(const folderId of REAL_FOLDERS) { + this.pinnedOrders[folderId] = []; + } } this.folders = {}; @@ -270,7 +278,7 @@ export default class DialogsStorage extends AppManager { } public resetPinnedOrder(folderId: number) { - this.pinnedOrders[folderId] = []; + this.pinnedOrders[folderId].length = 0; } public getPinnedOrders(folderId: number) { @@ -280,29 +288,30 @@ export default class DialogsStorage extends AppManager { public getOffsetDate(folderId: number): number { const offsetDate = this.dialogsOffsetDate[folderId] || 0; if(folderId === GLOBAL_FOLDER_ID && !offsetDate) { // make request not from beginning if we have loaded some dialogs - return Math.min(this.getOffsetDate(0), this.getOffsetDate(1)); + return Math.min(...Array.from(REAL_FOLDERS).sort((a, b) => a - b)); } return offsetDate; } - public getFolder(id: number) { - let folder = this.folders[id]; - if(!folder) { - folder = this.folders[id] = { - dialogs: [], - id, - unreadMessagesCount: 0, - unreadPeerIds: new Set(), - unreadUnmutedPeerIds: new Set() - }; + private generateFolder(id: number) { + const folder: Folder = { + dialogs: [], + id, + unreadMessagesCount: 0, + unreadPeerIds: new Set(), + unreadUnmutedPeerIds: new Set() + }; - defineNotNumerableProperties(folder, ['dispatchUnreadTimeout']); - } + defineNotNumerableProperties(folder, ['dispatchUnreadTimeout']); return folder; } + public getFolder(id: number) { + return this.folders[id] ??= this.generateFolder(id); + } + public getFolderDialogs(id: number, skipMigrated = true): Dialog[] { if(id === GLOBAL_FOLDER_ID) { // * it won't be sorted return this.getCachedDialogs(skipMigrated); @@ -331,9 +340,9 @@ export default class DialogsStorage extends AppManager { } public getDialogIndexKeyByFilterId(filterId: number) { - if(filterId <= 1) return getDialogIndexKey(filterId as LOCAL_FOLDER_ID); + if(REAL_FOLDERS.has(filterId)) return getDialogIndexKey(filterId as REAL_FOLDER_ID); const filter = this.filtersStorage.getFilter(filterId); - return getDialogIndexKey(filter.orderIndex); + return getDialogIndexKey(filter.localId); } public isPeerUnmuted(peerId: PeerId) { @@ -346,18 +355,19 @@ export default class DialogsStorage extends AppManager { } public getCachedDialogs(skipMigrated?: boolean) { - return this.getFolderDialogs(0, skipMigrated).concat(this.getFolderDialogs(1, skipMigrated)); + const arrays = Array.from(REAL_FOLDERS).map((folderId) => this.getFolderDialogs(folderId, skipMigrated)); + return [].concat(...arrays) as typeof arrays[0]; } private setDialogIndexInFilter(dialog: Dialog, indexKey: ReturnType, filter: MyDialogFilter) { let index: number; - /* if(filter.id <= 1) { - index = getDialogIndex(dialog, getDialogIndexKey(filter.id)); - } else */if(this.filtersStorage.testDialogForFilter(dialog, filter)) { + if(REAL_FOLDERS.has(filter.id)) { + index = getDialogIndex(dialog, indexKey); + } else if(this.filtersStorage.testDialogForFilter(dialog, filter)) { const pinnedIndex = filter.pinnedPeerIds.indexOf(dialog.peerId); if(pinnedIndex !== -1) { - index = this.generateDialogIndex(this.generateDialogPinnedDateByIndex(filter.pinned_peers.length - 1 - pinnedIndex), true); + index = this.generateDialogIndex(this.generateDialogPinnedDateByIndex(filter.pinnedPeerIds.length - 1 - pinnedIndex), true); } else if(dialog.pFlags?.pinned) { index = this.generateIndexForDialog(dialog, true); } else { @@ -376,7 +386,7 @@ export default class DialogsStorage extends AppManager { const folders: Dialog[][] = []; if(folderId === undefined) { - folders.push(this.getFolder(0).dialogs, this.getFolder(1).dialogs); + folders.push(...Array.from(REAL_FOLDERS).map((folderId) => this.getFolder(folderId).dialogs)); } else { folders.push(this.getFolderDialogs(folderId, false)); } @@ -533,6 +543,10 @@ export default class DialogsStorage extends AppManager { } public generateIndexForDialog(dialog: Dialog, justReturn = false, message?: MyMessage) { + // if(!justReturn) { + // return; + // } + let topDate = 0, isPinned: boolean; if(dialog.pFlags.pinned && !justReturn) { topDate = this.generateDialogPinnedDate(dialog); @@ -577,14 +591,14 @@ export default class DialogsStorage extends AppManager { public generateDialogPinnedDate(dialog: Dialog) { const order = this.pinnedOrders[dialog.folder_id]; - const foundIndex = order.indexOf(dialog.peerId); - let pinnedIndex = foundIndex; - if(foundIndex === -1) { - pinnedIndex = order.push(dialog.peerId) - 1; + let pinnedIndex = order.indexOf(dialog.peerId); + if(pinnedIndex === -1) { + order.unshift(dialog.peerId); + pinnedIndex = 0; this.savePinnedOrders(); } - return this.generateDialogPinnedDateByIndex(pinnedIndex); + return this.generateDialogPinnedDateByIndex(order.length - 1 - pinnedIndex); } /* public generateDialog(peerId: PeerId) { @@ -658,11 +672,11 @@ export default class DialogsStorage extends AppManager { public pushDialog(dialog: Dialog, offsetDate?: number, ignoreOffsetDate?: boolean, saveGlobalOffset?: boolean) { const {folder_id, peerId} = dialog; - const dialogs = this.getFolderDialogs(folder_id, false); - const pos = dialogs.findIndex((d) => d.peerId === peerId); - if(pos !== -1) { - dialogs.splice(pos, 1); - } + // const dialogs = this.getFolderDialogs(folder_id, false); + // const pos = dialogs.findIndex((d) => d.peerId === peerId); + // if(pos !== -1) { + // dialogs.splice(pos, 1); + // } //if(!this.dialogs[peerId]) { this.dialogs[peerId] = dialog; @@ -696,12 +710,12 @@ export default class DialogsStorage extends AppManager { } } - if(pos === -1) { - this.prepareFolderUnreadCountModifyingByDialog(folder_id, dialog, true); - } + // if(pos === -1) { + // this.prepareFolderUnreadCountModifyingByDialog(folder_id, dialog, true); + // } - const indexKey = getDialogIndexKey(folder_id); - /* const newPos = */insertInDescendSortedArray(dialogs, dialog, (dialog) => getDialogIndex(dialog, indexKey), -1); + // const indexKey = getDialogIndexKey(folder_id); + // /* const newPos = */insertInDescendSortedArray(dialogs, dialog, (dialog) => getDialogIndex(dialog, indexKey), -1); /* if(pos !== -1 && pos !== newPos) { rootScope.dispatchEvent('dialog_order', {dialog, pos: newPos}); } */ @@ -823,7 +837,7 @@ export default class DialogsStorage extends AppManager { /** * Won't save migrated from peer, forbidden peers, left and kicked */ - public saveDialog(dialog: Dialog, folderId = dialog.folder_id ?? 0, ignoreOffsetDate?: boolean, saveGlobalOffset?: boolean) { + public saveDialog(dialog: Dialog, folderId = dialog.folder_id ?? FOLDER_ID_ALL, ignoreOffsetDate?: boolean, saveGlobalOffset?: boolean) { const peerId = getPeerId(dialog.peer); if(!peerId) { console.error('saveConversation no peerId???', dialog, folderId); @@ -914,6 +928,10 @@ export default class DialogsStorage extends AppManager { dialog.peerId = peerId; // dialog.indexes ??= {} as any; + // if(dialog.peerId === -) { + // debugger; + // } + // Because we saved message without dialog present if(message && message.pFlags.is_outgoing) { const isOut = message.pFlags.out; @@ -983,7 +1001,7 @@ export default class DialogsStorage extends AppManager { isTopEnd: boolean, isEnd: boolean }> { - if(folderId > 1) { + if(!REAL_FOLDERS.has(folderId)) { const promises: Promise[] = []; const fillContactsResult = this.appUsersManager.fillContacts(); @@ -1004,7 +1022,7 @@ export default class DialogsStorage extends AppManager { } // let's load only first pages by certain folderId. next pages will load without folder filtering - const realFolderId: LOCAL_FOLDER_ID = folderId > 1 || this.getOffsetDate(folderId) ? GLOBAL_FOLDER_ID : folderId as LOCAL_FOLDER_ID; + const realFolderId: REAL_FOLDER_ID = !REAL_FOLDERS.has(folderId) || this.getOffsetDate(folderId) ? GLOBAL_FOLDER_ID : folderId as REAL_FOLDER_ID; let curDialogStorage = this.getFolderDialogs(folderId, skipMigrated); const indexKey = this.getDialogIndexKeyByFilterId(folderId); @@ -1098,7 +1116,7 @@ export default class DialogsStorage extends AppManager { this.handleDialogUnpinning(dialog, folder_id); } - dialog.folder_id = folder_id as LOCAL_FOLDER_ID; + dialog.folder_id = folder_id as REAL_FOLDER_ID; this.generateIndexForDialog(dialog); this.pushDialog(dialog); // need for simultaneously updatePinnedDialogs } @@ -1108,7 +1126,7 @@ export default class DialogsStorage extends AppManager { }; private onUpdateDialogPinned = (update: Update.updateDialogPinned) => { - const folderId = update.folder_id ?? 0; + const folderId = update.folder_id ?? FOLDER_ID_ALL; //this.log('updateDialogPinned', update); const peerId = getPeerId((update.peer as DialogPeer.dialogPeer).peer); const dialog = this.getDialogOnly(peerId); @@ -1137,10 +1155,10 @@ export default class DialogsStorage extends AppManager { }; private onUpdatePinnedDialogs = (update: Update.updatePinnedDialogs) => { - const folderId = update.folder_id ?? 0; - + const folderId = update.folder_id ?? FOLDER_ID_ALL; + const handleOrder = (order: PeerId[]) => { - this.pinnedOrders[folderId].length = 0; + this.resetPinnedOrder(folderId); order.reverse(); // index must be higher order.forEach((peerId) => { newPinned[peerId] = true; diff --git a/src/lib/storages/filters.ts b/src/lib/storages/filters.ts index a9ae57f2..fb62e168 100644 --- a/src/lib/storages/filters.ts +++ b/src/lib/storages/filters.ts @@ -5,23 +5,16 @@ */ import type { DialogFilter, Update } from "../../layer"; -import { Modify } from "../../types"; import type { Dialog } from '../appManagers/appMessagesManager'; import forEachReverse from "../../helpers/array/forEachReverse"; import copy from "../../helpers/object/copy"; -import safeReplaceObject from "../../helpers/object/safeReplaceObject"; import getPeerId from "../appManagers/utils/peers/getPeerId"; import { AppManager } from "../appManagers/manager"; +import findAndSplice from "../../helpers/array/findAndSplice"; import assumeType from "../../helpers/assumeType"; +import { FOLDER_ID_ALL, FOLDER_ID_ARCHIVE, REAL_FOLDERS, REAL_FOLDER_ID } from "../mtproto/mtproto_config"; -export type MyDialogFilter = Modify; +export type MyDialogFilter = DialogFilter.dialogFilter; const convertment = [ ['pinned_peers', 'pinnedPeerIds'], @@ -29,29 +22,32 @@ const convertment = [ ['include_peers', 'includePeerIds'] ] as ['pinned_peers' | 'exclude_peers' | 'include_peers', 'pinnedPeerIds' | 'excludePeerIds' | 'includePeerIds'][]; -const START_ORDER_INDEX = 2; - -// const LOCAL_FILTER: MyDialogFilter = { -// _: 'dialogFilter', -// id: 0, -// title: '', -// exclude_peers: [], -// include_peers: [], -// pinned_peers: [], -// excludePeerIds: [], -// includePeerIds: [], -// pinnedPeerIds: [], -// pFlags: {} -// }; +const START_LOCAL_ID = Math.max(...Array.from(REAL_FOLDERS)) + 1 as MyDialogFilter['localId']; +const PREPENDED_FILTERS = REAL_FOLDERS.size; + +const LOCAL_FILTER: MyDialogFilter = { + _: 'dialogFilter', + pFlags: {}, + flags: 0, + id: 0, + title: '', + exclude_peers: [], + include_peers: [], + pinned_peers: [], + excludePeerIds: [], + includePeerIds: [], + pinnedPeerIds: [], +}; export default class FiltersStorage extends AppManager { private filters: {[filterId: string]: MyDialogFilter}; - private orderIndex: number; + private filtersArr: Array; + private localFilters: {[filterId: string]: MyDialogFilter}; + private localId: number; private reloadedPeerIds: Set; protected after() { this.clear(true); - this.filters = {}; this.apiUpdatesManager.addMultipleEventsListeners({ updateDialogFilter: this.onUpdateDialogFilter, @@ -97,28 +93,50 @@ export default class FiltersStorage extends AppManager { }); */ return this.appStateManager.getState().then((state) => { - safeReplaceObject(this.filters, state.filters); + const filtersArr = this.prependFilters(state.filtersArr); + filtersArr.map((filter) => { + delete filter.localId; + this.saveDialogFilter(filter, false, true); + }); + }); + } - for(const filterId in this.filters) { - const filter = this.filters[filterId]; - if(filter.hasOwnProperty('orderIndex') && filter.orderIndex >= this.orderIndex) { - this.orderIndex = filter.orderIndex + 1; - } + /** + * ! use it only with saving + */ + private prependFilters(filters: DialogFilter[]) { + filters = filters.slice(); - /* this.appMessagesManager.dialogsStorage.folders[+filterId] = { - dialogs: [] - }; */ - } + const allChatsFilter = this.localFilters[FOLDER_ID_ALL]; + const archiveFilter = this.localFilters[FOLDER_ID_ARCHIVE]; - // delete this.filters[0]; - // delete this.filters[1]; - // this.getLocalFilter(0); - // this.getLocalFilter(1); - }); + const allChatsFilterIndex = filters.findIndex((filter) => filter._ === 'dialogFilterDefault' || filter.id === FOLDER_ID_ALL); + if(allChatsFilterIndex !== -1) filters[allChatsFilterIndex] = allChatsFilter; + else filters.unshift(allChatsFilter); + + findAndSplice(filters, (filter) => (filter as MyDialogFilter).id === FOLDER_ID_ARCHIVE); + filters.splice(/* 1 */filters[0] === allChatsFilter ? 1 : 0, 0, archiveFilter); + + return filters; + } + + private generateLocalFilter(id: REAL_FOLDER_ID) { + const filter: MyDialogFilter = {...copy(LOCAL_FILTER), id}; + if(id === FOLDER_ID_ALL) { + filter.pFlags.exclude_archived = true; + } else if(id === FOLDER_ID_ARCHIVE) { + filter.pFlags.exclude_unarchived = true; + } + + if(REAL_FOLDERS.has(id)) { + filter.pinnedPeerIds = this.dialogsStorage.getPinnedOrders(id); + } + + return filter; } // private getLocalFilter(id: number) { - // return this.filters[id] ??= {...copy(LOCAL_FILTER), id}; + // return this.filters[id] ??= this.generateLocalFilter(id); // } public clear = (init?: boolean) => { @@ -128,10 +146,16 @@ export default class FiltersStorage extends AppManager { this.clearFilters(); } else { this.filters = {}; + this.filtersArr = []; this.reloadedPeerIds = new Set(); + + this.localFilters = {}; + for(const filterId of REAL_FOLDERS) { + this.localFilters[filterId] = this.generateLocalFilter(filterId as REAL_FOLDER_ID); + } } - this.orderIndex = START_ORDER_INDEX; + this.localId = START_LOCAL_ID; }; private onUpdateDialogFilter = (update: Update.updateDialogFilter) => { @@ -141,28 +165,33 @@ export default class FiltersStorage extends AppManager { //this.getDialogFilters(true); this.rootScope.dispatchEvent('filter_delete', this.filters[update.id]); delete this.filters[update.id]; + findAndSplice(this.filtersArr, (filter) => (filter as DialogFilter.dialogFilter).id === update.id); } - this.appStateManager.pushToState('filters', this.filters); + this.pushToState(); }; private onUpdateDialogFilterOrder = (update: Update.updateDialogFilterOrder) => { //console.log('updateDialogFilterOrder', update); - this.orderIndex = START_ORDER_INDEX; + this.localId = START_LOCAL_ID; update.order.forEach((filterId, idx) => { const filter = this.filters[filterId]; - delete filter.orderIndex; - this.setOrderIndex(filter); + delete filter.localId; + this.setLocalId(filter); }); this.rootScope.dispatchEvent('filter_order', update.order); - this.appStateManager.pushToState('filters', this.filters); + this.pushToState(); }; + private pushToState() { + this.appStateManager.pushToState('filtersArr', this.filtersArr); + } + public testDialogForFilter(dialog: Dialog, filter: MyDialogFilter) { - if(filter.id <= 1) { + if(REAL_FOLDERS.has(filter.id)) { return dialog.folder_id === filter.id; } @@ -186,7 +215,7 @@ export default class FiltersStorage extends AppManager { const pFlags = filter.pFlags; // exclude_archived - if(pFlags.exclude_archived && dialog.folder_id === 1) { + if(pFlags.exclude_archived && dialog.folder_id === FOLDER_ID_ARCHIVE) { return false; } @@ -247,6 +276,10 @@ export default class FiltersStorage extends AppManager { public clearFilters() { const filters = this.getFilters(); for(const filterId in filters) { // delete filters + if(REAL_FOLDERS.has(+filterId)) { + continue; + } + this.onUpdateDialogFilter({ _: 'updateDialogFilter', id: +filterId, @@ -311,13 +344,13 @@ export default class FiltersStorage extends AppManager { const f: MyDialogFilter[] = []; for(const filterId in this.filters) { const filter = this.filters[filterId]; - ++filter.orderIndex; + ++filter.localId; f.push(filter); } - filter.orderIndex = START_ORDER_INDEX; + filter.localId = START_LOCAL_ID; - const order = f.sort((a, b) => a.orderIndex - b.orderIndex).map((filter) => filter.id); + const order = f.sort((a, b) => a.localId - b.localId).map((filter) => filter.id); this.onUpdateDialogFilterOrder({ _: 'updateDialogFilterOrder', order @@ -427,37 +460,37 @@ export default class FiltersStorage extends AppManager { public async getDialogFilters(overwrite = false): Promise { const keys = Object.keys(this.filters); - if(keys.length && !overwrite) { - return keys.map((filterId) => this.filters[filterId]).sort((a, b) => a.orderIndex - b.orderIndex); + if(keys.length > PREPENDED_FILTERS && !overwrite) { + return keys.map((filterId) => this.filters[filterId]).sort((a, b) => a.localId - b.localId); } const filters = await this.apiManager.invokeApiSingle('messages.getDialogFilters'); - return filters.map((filter) => this.saveDialogFilter(filter, overwrite)).filter(Boolean); + return this.prependFilters(filters).map((filter) => this.saveDialogFilter(filter, overwrite)).filter(Boolean); } public getSuggestedDialogsFilters() { return this.apiManager.invokeApi('messages.getSuggestedDialogFilters'); } - public saveDialogFilter(filter: DialogFilter, update = true) { + public saveDialogFilter(filter: DialogFilter, update = true, silent?: boolean) { // defineNotNumerableProperties(filter, ['includePeerIds', 'excludePeerIds', 'pinnedPeerIds']); - // if(filter._ === 'dialogFilterDefault') { - // return; - // // filter = this.getLocalFilter(0); - // // delete filter.orderIndex; - // } + if(filter._ === 'dialogFilterDefault') { + filter = this.localFilters[FOLDER_ID_ALL]; + } assumeType(filter); - convertment.forEach(([from, to]) => { - assumeType(filter); - filter[to] = filter[from].map((peer) => getPeerId(peer)); - }); + if(!REAL_FOLDERS.has(filter.id)) { + convertment.forEach(([from, to]) => { + assumeType(filter); + filter[to] = filter[from].map((peer) => getPeerId(peer)); + }); - this.filterIncludedPinnedPeers(filter); + this.filterIncludedPinnedPeers(filter); - filter.include_peers = filter.pinned_peers.concat(filter.include_peers); - filter.includePeerIds = filter.pinnedPeerIds.concat(filter.includePeerIds); + filter.include_peers = filter.pinned_peers.concat(filter.include_peers); + filter.includePeerIds = filter.pinnedPeerIds.concat(filter.includePeerIds); + } const oldFilter = this.filters[filter.id]; if(oldFilter) { @@ -466,26 +499,29 @@ export default class FiltersStorage extends AppManager { this.filters[filter.id] = filter; } - this.setOrderIndex(filter); + this.setLocalId(filter); - if(update) { - this.rootScope.dispatchEvent('filter_update', filter); - } else if(!oldFilter) { - this.rootScope.dispatchEvent('filter_new', filter); + if(!silent) { + if(update) { + this.rootScope.dispatchEvent('filter_update', filter); + } else if(!oldFilter) { + this.rootScope.dispatchEvent('filter_new', filter); + } } return filter; } - public setOrderIndex(filter: MyDialogFilter) { - if(filter.hasOwnProperty('orderIndex')) { - if(filter.orderIndex >= this.orderIndex) { - this.orderIndex = filter.orderIndex + 1; + private setLocalId(filter: MyDialogFilter) { + if(filter.localId !== undefined) { + if(filter.localId >= this.localId) { + this.localId = filter.localId + 1; } } else { - filter.orderIndex = this.orderIndex++ as MyDialogFilter['orderIndex']; + filter.localId = this.localId++ as MyDialogFilter['localId']; + findAndSplice(this.filtersArr, (_filter) => _filter.id === filter.id); + this.filtersArr.push(filter); + this.pushToState(); } - - this.appStateManager.pushToState('filters', this.filters); } } diff --git a/src/scripts/in/schema_additional_params.json b/src/scripts/in/schema_additional_params.json index 3606b279..772495f6 100644 --- a/src/scripts/in/schema_additional_params.json +++ b/src/scripts/in/schema_additional_params.json @@ -61,9 +61,16 @@ }, { "predicate": "dialogFilter", "params": [ - {"name": "orderIndex", "type": "0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21"}, - {"name": "peerId", "type": "PeerId"}, - {"name": "folder_id", "type": "number"} + {"name": "localId", "type": "0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21"}, + {"name": "pinnedPeerIds", "type": "PeerId[]"}, + {"name": "includePeerIds", "type": "PeerId[]"}, + {"name": "excludePeerIds", "type": "PeerId[]"}, + {"name": "exclude_unarchived", "type": "true"} + ] +}, { + "predicate": "dialogFilterDefault", + "params": [ + {"name": "localId", "type": "0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21"} ] }, { "predicate": "message",