diff --git a/src/components/sortedUserList.ts b/src/components/sortedUserList.ts index c8a46a60..de58a889 100644 --- a/src/components/sortedUserList.ts +++ b/src/components/sortedUserList.ts @@ -21,8 +21,8 @@ type SortedUser = { }; export default class SortedUserList { protected static SORT_INTERVAL = 30e3; - protected users: Map; - protected sorted: Array; + public users: Map; + public sorted: Array; public list: HTMLUListElement; protected lazyLoadQueue: LazyLoadQueueIntersector; @@ -78,8 +78,12 @@ export default class SortedUserList { return true; } + public has(peerId: number) { + return this.users.has(peerId); + } + public add(peerId: number) { - if(this.users.has(peerId)) { + if(this.has(peerId)) { return; } @@ -104,6 +108,17 @@ export default class SortedUserList { this.update(peerId); } + public delete(peerId: number) { + const user = this.users.get(peerId); + if(!user) { + return; + } + + user.dom.listEl.remove(); + this.users.delete(peerId); + this.sorted.findAndSplice(_user => _user === user); + } + public update(peerId: number, batch = false) { const sortedUser = this.users.get(peerId); sortedUser.status = appUsersManager.getUserStatusForSort(peerId); diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 42fa78a3..60c5df48 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -108,7 +108,9 @@ export class AppDialogsManager { private lastActiveElements: Set = new Set(); private offsets: {top: number, bottom: number} = {top: 0, bottom: 0}; - loadContacts: () => void; + + private loadContacts: () => void; + private processContact: (peerId: number) => void; constructor() { this.chatsPreloader = putPreloader(null, true); @@ -190,8 +192,7 @@ export class AppDialogsManager { this.setFiltersUnreadCount(); }); */ - rootScope.addEventListener('dialog_flush', (e) => { - const peerId: number = e.peerId; + rootScope.addEventListener('dialog_flush', ({peerId}) => { const dialog = appMessagesManager.getDialogOnly(peerId); if(dialog) { this.setLastMessage(dialog); @@ -200,29 +201,31 @@ export class AppDialogsManager { } }); - rootScope.addEventListener('dialogs_multiupdate', (e) => { - const dialogs = e; - + rootScope.addEventListener('dialogs_multiupdate', (dialogs) => { for(const id in dialogs) { const dialog = dialogs[id]; this.updateDialog(dialog); + + if(this.processContact) { + this.processContact(+id); + } } this.validateForFilter(); this.setFiltersUnreadCount(); }); - rootScope.addEventListener('dialog_drop', (e) => { - const {peerId} = e; - + rootScope.addEventListener('dialog_drop', ({peerId}) => { this.deleteDialog(peerId); this.setFiltersUnreadCount(); - }); - rootScope.addEventListener('dialog_unread', (e) => { - const info = e; + if(this.processContact) { + this.processContact(peerId); + } + }); - const dialog = appMessagesManager.getDialogOnly(info.peerId); + rootScope.addEventListener('dialog_unread', ({peerId}) => { + const dialog = appMessagesManager.getDialogOnly(peerId); if(dialog) { this.setUnreadMessages(dialog); this.validateForFilter(); @@ -234,16 +237,18 @@ export class AppDialogsManager { this.setUnreadMessages(dialog); // возможно это не нужно, но нужно менять is-muted }); - rootScope.addEventListener('dialog_draft', (e) => { - const dialog = appMessagesManager.getDialogOnly(e.peerId); + rootScope.addEventListener('dialog_draft', ({peerId}) => { + const dialog = appMessagesManager.getDialogOnly(peerId); if(dialog) { this.updateDialog(dialog); + + if(this.processContact) { + this.processContact(peerId); + } } }); - rootScope.addEventListener('peer_changed', (e) => { - const peerId = e; - + rootScope.addEventListener('peer_changed', (peerId) => { //const perf = performance.now(); for(const element of this.lastActiveElements) { if(+element.dataset.peerId !== peerId) { @@ -260,8 +265,7 @@ export class AppDialogsManager { //this.log('peer_changed total time:', performance.now() - perf); }); - rootScope.addEventListener('filter_update', (e) => { - const filter: DialogFilter = e; + rootScope.addEventListener('filter_update', (filter) => { if(!this.filtersRendered[filter.id]) { this.addFilter(filter); return; @@ -280,8 +284,7 @@ export class AppDialogsManager { elements.title.innerHTML = RichTextProcessor.wrapEmojiText(filter.title); }); - rootScope.addEventListener('filter_delete', (e) => { - const filter: DialogFilter = e; + rootScope.addEventListener('filter_delete', (filter) => { const elements = this.filtersRendered[filter.id]; if(!elements) return; @@ -301,9 +304,7 @@ export class AppDialogsManager { } }); - rootScope.addEventListener('filter_order', (e) => { - const order = e; - + rootScope.addEventListener('filter_order', (order) => { const containerToAppend = this.folders.menu as HTMLElement; order.forEach((filterId) => { const filter = appMessagesManager.filtersStorage.filters[filterId]; @@ -319,9 +320,7 @@ export class AppDialogsManager { } */ }); - rootScope.addEventListener('peer_typings', (e) => { - const {peerId, typings} = e; - + rootScope.addEventListener('peer_typings', ({peerId, typings}) => { const dialog = appMessagesManager.getDialogOnly(peerId); if(!dialog) return; @@ -888,16 +887,27 @@ export class AppDialogsManager { } private onListLengthChange = () => { - return; - this.checkIfPlaceholderNeeded(); if(this.filterId > 0) return; + + const count = this.chatList.childElementCount; + + const parts = this.chatList.parentElement.parentElement; const bottom = this.chatList.parentElement.nextElementSibling as HTMLElement; + const hasContacts = !!bottom.childElementCount; + if(count >= 10) { + if(hasContacts) { + parts.classList.remove('with-contacts'); + bottom.innerHTML = ''; + this.loadContacts = undefined; + this.processContact = undefined; + } - if(bottom.childElementCount) return; + return; + } else if(hasContacts) return; - bottom.parentElement.classList.add('with-contacts'); + parts.classList.add('with-contacts'); const section = new SettingSection({ name: 'Contacts', @@ -911,7 +921,7 @@ export class AppDialogsManager { const sortedUserList = new SortedUserList({avatarSize: 42, new: true}); this.loadContacts = () => { const pageCount = appPhotosManager.windowH / 60 | 0; - const arr = contacts.splice(0, pageCount); + const arr = contacts.splice(0, pageCount).filter(this.verifyUserIdForContacts); arr.forEach((peerId) => { sortedUserList.add(peerId); @@ -924,6 +934,17 @@ export class AppDialogsManager { this.loadContacts(); + this.processContact = (peerId) => { + if(peerId < 0) { + return; + } + + const good = this.verifyUserIdForContacts(peerId); + const added = sortedUserList.has(peerId); + if(!added && good) sortedUserList.add(peerId); + else if(added && !good) sortedUserList.delete(peerId); + }; + const list = sortedUserList.list; list.classList.add('chatlist-new'); this.setListClickListener(list); @@ -934,6 +955,11 @@ export class AppDialogsManager { bottom.append(section.container); }; + private verifyUserIdForContacts = (peerId: number) => { + const dialog = appMessagesManager.getDialogOnly(peerId); + return !dialog; + }; + public onChatsRegularScroll = () => { if(this.sliceTimeout) clearTimeout(this.sliceTimeout); this.sliceTimeout = window.setTimeout(() => { @@ -944,7 +970,7 @@ export class AppDialogsManager { return; } - if(!this.chatList.childElementCount) { + if(!this.chatList.childElementCount || this.processContact) { return; } diff --git a/src/lib/mtproto/authorizer.ts b/src/lib/mtproto/authorizer.ts index 66a45111..ac6d69b7 100644 --- a/src/lib/mtproto/authorizer.ts +++ b/src/lib/mtproto/authorizer.ts @@ -64,7 +64,9 @@ type AuthOptions = { serverSalt?: Uint8Array, localTime?: number, - serverTime?: any + serverTime?: any, + + localTry?: number }; type ResPQ = { @@ -122,8 +124,7 @@ export class Authorizer { const transport = dcConfigurator.chooseServer(dcId); const baseError = { code: 406, - type: 'NETWORK_BAD_RESPONSE', - transport + type: 'NETWORK_BAD_RESPONSE' }; if(DEBUG) { @@ -245,7 +246,7 @@ export class Authorizer { return this.sendReqDhParams(auth); } - private async sendReqDhParams(auth: AuthOptions) { + private async sendReqDhParams(auth: AuthOptions): Promise { auth.newNonce = new Uint8Array(32).randomize(); const p_q_inner_data_dc: P_Q_inner_data = { @@ -578,16 +579,26 @@ export class Authorizer { MTProto.secureRandom.nextBytes(nonce); */ if(!dcConfigurator.chooseServer(dcId)) { - return Promise.reject(new Error('[MT] No server found for dc ' + dcId)); + throw new Error('[MT] No server found for dc ' + dcId); } // await new Promise((resolve) => setTimeout(resolve, 2e3)); + const auth: AuthOptions = {dcId, nonce, localTry: 1}; + try { - const promise = this.sendReqPQ({dcId, nonce}); + const promise = this.sendReqPQ(auth); this.cached[dcId] = promise; return await promise; } catch(err) { + if(err.originalError === -404 && auth.localTry <= 3) { + return this.sendReqPQ({ + dcId: auth.dcId, + nonce: new Uint8Array(16).randomize(), + localTry: auth.localTry + 1 + }); + } + delete this.cached[dcId]; throw err; } diff --git a/src/scss/partials/_chatPinned.scss b/src/scss/partials/_chatPinned.scss index 2519e82d..3f7af823 100644 --- a/src/scss/partials/_chatPinned.scss +++ b/src/scss/partials/_chatPinned.scss @@ -249,12 +249,14 @@ &.is-floating { position: absolute !important; - top: 100%; - width: 100% !important; - background: var(--surface-color) !important; + top: 3.5rem; + right: 0; left: 0; - max-height: 100% !important; - height: 52px; + margin: 0; + width: auto; + height: 3.25rem; + max-height: 3.25rem; + background: var(--surface-color) !important; .pinned-container-close { position: absolute; diff --git a/src/scss/partials/pages/_pages.scss b/src/scss/partials/pages/_pages.scss index a6648214..4a4fc221 100644 --- a/src/scss/partials/pages/_pages.scss +++ b/src/scss/partials/pages/_pages.scss @@ -91,12 +91,13 @@ flex-direction: row; } */ - > div { + .container { height: 810px; padding: 0; flex: 1 1 auto; display: flex; flex-direction: column; + width: 100%; @media screen and (max-height: 810px) { height: 760px;