From 837fcbf13cad0f2a0e613971fa4c91421dbe87f6 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Mon, 31 Aug 2020 19:48:46 +0300 Subject: [PATCH] Select peers search by non-contact --- src/components/appForward.ts | 2 +- src/components/appSelectPeers.ts | 79 ++++++++++++++------- src/components/sidebarLeft/addMembers.ts | 14 +--- src/components/sidebarLeft/editFolder.ts | 7 ++ src/components/sidebarLeft/includedChats.ts | 2 +- src/lib/appManagers/appDialogsManager.ts | 55 +++++++------- src/lib/appManagers/appDocsManager.ts | 13 ++-- src/lib/appManagers/appMediaViewer.ts | 2 +- src/lib/appManagers/appMessagesManager.ts | 40 ++++++++++- src/lib/appManagers/appPhotosManager.ts | 2 +- src/lib/appManagers/appStateManager.ts | 12 +++- src/lib/appManagers/appUsersManager.ts | 25 +++++-- src/lib/config.ts | 2 + src/lib/mtproto/mtprotoworker.ts | 3 + src/lib/utils.ts | 22 ++++++ src/scss/partials/_chatBubble.scss | 7 ++ src/scss/partials/_leftSidebar.scss | 4 ++ src/scss/partials/_rightSidebar.scss | 9 +++ src/scss/style.scss | 24 ++++--- webpack.common.js | 2 +- 20 files changed, 229 insertions(+), 97 deletions(-) diff --git a/src/components/appForward.ts b/src/components/appForward.ts index a90b8476..04c66ea7 100644 --- a/src/components/appForward.ts +++ b/src/components/appForward.ts @@ -73,7 +73,7 @@ class AppForward { } else { this.sendBtn.classList.remove('is-visible'); } - }, 'both', () => { + }, ['dialogs', 'contacts'], () => { //console.log('forward rendered:', this.container.querySelector('.selector ul').childElementCount); this.sidebarWasActive = appSidebarRight.sidebarEl.classList.contains('active'); appSidebarRight.toggleSidebar(true); diff --git a/src/components/appSelectPeers.ts b/src/components/appSelectPeers.ts index 4049d32e..30352e68 100644 --- a/src/components/appSelectPeers.ts +++ b/src/components/appSelectPeers.ts @@ -1,12 +1,17 @@ import Scrollable from "./scrollable_new"; import appMessagesManager, { Dialog } from "../lib/appManagers/appMessagesManager"; -import { $rootScope, cancelEvent, findUpClassName, findUpTag, findUpAttribute } from "../lib/utils"; +import { $rootScope, cancelEvent, findUpClassName, findUpAttribute } from "../lib/utils"; import appDialogsManager from "../lib/appManagers/appDialogsManager"; import appChatsManager from "../lib/appManagers/appChatsManager"; import appUsersManager from "../lib/appManagers/appUsersManager"; import appPeersManager from "../lib/appManagers/appPeersManager"; import appPhotosManager from "../lib/appManagers/appPhotosManager"; +type PeerType = 'contacts' | 'dialogs'; + +// TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени + +let loadedAllDialogs = false; export class AppSelectPeers { public container = document.createElement('div'); public list = document.createElement('ul'); @@ -22,8 +27,6 @@ export class AppSelectPeers { public freezed = false; - private myID = $rootScope.myID; - private folderID = 0; private offsetIndex = 0; private promise: Promise; @@ -33,7 +36,7 @@ export class AppSelectPeers { private loadedWhat: Partial<{[k in 'dialogs' | 'archived' | 'contacts']: true}> = {}; - constructor(private appendTo: HTMLElement, private onChange?: (length: number) => void, private peerType: 'contacts' | 'dialogs' | 'both' = 'dialogs', onFirstRender?: () => void, private renderResultsFunc?: (peerIDs: number[]) => void) { + constructor(private appendTo: HTMLElement, private onChange?: (length: number) => void, private peerType: PeerType[] = ['dialogs'], onFirstRender?: () => void, private renderResultsFunc?: (peerIDs: number[]) => void) { this.container.classList.add('selector'); if(!this.renderResultsFunc) { @@ -44,7 +47,7 @@ export class AppSelectPeers { topContainer.classList.add('selector-search-container'); this.selectedContainer.classList.add('selector-search'); - this.input.placeholder = peerType == 'contacts' ? 'Add People...' : 'Select chat'; + this.input.placeholder = !peerType.includes('dialogs') ? 'Add People...' : 'Select chat'; this.input.type = 'text'; this.selectedContainer.append(this.input); topContainer.append(this.selectedContainer); @@ -94,27 +97,23 @@ export class AppSelectPeers { }); this.input.addEventListener('input', () => { - let value = this.input.value; + const value = this.input.value; if(this.query != value) { - if(this.peerType == 'contacts' || this.peerType == 'both') { + if(this.peerType.includes('contacts')) { delete this.loadedWhat.contacts; this.cachedContacts = null; } - if(this.peerType == 'dialogs' || this.peerType == 'both') { + //if(this.peerType.includes('dialogs')) { delete this.loadedWhat.dialogs; delete this.loadedWhat.archived; this.folderID = 0; this.offsetIndex = 0; - } + //} this.promise = null; this.list.innerHTML = ''; this.query = value; - - if(this.query && 'saved messages'.includes(this.query.toLowerCase())) { - this.renderResultsFunc([$rootScope.myID]); - } //console.log('selectPeers input:', this.query); this.getMoreResults(); @@ -151,15 +150,20 @@ export class AppSelectPeers { this.promise = appMessagesManager.getConversations(this.query, this.offsetIndex, pageCount, this.folderID); const value = await this.promise; + this.promise = null; let dialogs = value.dialogs as Dialog[]; if(dialogs.length) { const newOffsetIndex = dialogs[dialogs.length - 1].index || 0; - dialogs = dialogs.filter(d => d.peerID != this.myID); - if(!this.offsetIndex && this.folderID == 0 && !this.query) { + dialogs = dialogs.slice(); + dialogs.findAndSplice(d => d.peerID == $rootScope.myID); // no my account + + if(!this.offsetIndex && this.folderID == 0 && + (!this.query || 'saved messages'.includes(this.query.toLowerCase())) && + this.peerType.includes('dialogs')) { dialogs.unshift({ - peerID: this.myID, + peerID: $rootScope.myID, pFlags: {} } as any); } @@ -173,19 +177,15 @@ export class AppSelectPeers { this.offsetIndex = 0; this.folderID = 1; - this.promise = null; return this.getMoreDialogs(); } else { this.loadedWhat.archived = true; - if(!this.loadedWhat.contacts && this.peerType == 'both') { - this.promise = null; + if(!this.loadedWhat.contacts && this.peerType.includes('contacts')) { return this.getMoreContacts(); } } } - - this.promise = null; } private async getMoreContacts() { @@ -196,9 +196,16 @@ export class AppSelectPeers { } if(!this.cachedContacts) { + /* const promises: Promise[] = [appUsersManager.getContacts(this.query)]; + if(!this.peerType.includes('dialogs')) { + promises.push(appMessagesManager.getConversationsAll()); + } + + this.promise = Promise.all(promises); + this.cachedContacts = (await this.promise)[0].slice(); */ this.promise = appUsersManager.getContacts(this.query); this.cachedContacts = (await this.promise).slice(); - this.cachedContacts.findAndSplice(userID => userID == this.myID); // no my account + this.cachedContacts.findAndSplice(userID => userID == $rootScope.myID); // no my account this.promise = null; } @@ -206,14 +213,26 @@ export class AppSelectPeers { const pageCount = appPhotosManager.windowH / 72 * 1.25 | 0; const arr = this.cachedContacts.splice(0, pageCount); this.renderResultsFunc(arr); - } else { + } + + if(!this.cachedContacts.length) { this.loadedWhat.contacts = true; + + // need to load non-contacts + if(!this.peerType.includes('dialogs')) { + return this.getMoreDialogs(); + } } } private getMoreResults() { const promises: Promise[] = []; - if(this.peerType == 'dialogs' || this.peerType == 'both') { + + if(!loadedAllDialogs) { + promises.push(appMessagesManager.getConversationsAll()); + } + + if((this.peerType.includes('dialogs') || this.loadedWhat.contacts) && !this.loadedWhat.archived) { // to load non-contacts promises.push(this.getMoreDialogs()); if(!this.loadedWhat.archived) { @@ -221,7 +240,7 @@ export class AppSelectPeers { } } - if(this.peerType == 'contacts' || this.peerType == 'both') { + if(this.peerType.includes('contacts') && !this.loadedWhat.contacts) { promises.push(this.getMoreContacts()); } @@ -230,6 +249,14 @@ export class AppSelectPeers { private renderResults(peerIDs: number[]) { //console.log('will renderResults:', peerIDs); + + // оставим только неконтакты с диалогов + if(!this.peerType.includes('dialogs') && this.loadedWhat.contacts) { + peerIDs = peerIDs.filter(peerID => { + return appUsersManager.isNonContactUser(peerID); + }); + } + peerIDs.forEach(peerID => { const {dom} = appDialogsManager.addDialog(peerID, this.scrollable, false, false); @@ -240,7 +267,7 @@ export class AppSelectPeers { let subtitle = ''; if(peerID < 0) { subtitle = appChatsManager.getChatMembersString(-peerID); - } else if(peerID == this.myID) { + } else if(peerID == $rootScope.myID) { subtitle = 'chat with yourself'; } else { subtitle = appUsersManager.getUserStatusString(peerID); diff --git a/src/components/sidebarLeft/addMembers.ts b/src/components/sidebarLeft/addMembers.ts index 41d0b926..38428971 100644 --- a/src/components/sidebarLeft/addMembers.ts +++ b/src/components/sidebarLeft/addMembers.ts @@ -56,21 +56,13 @@ export default class AppAddMembersTab implements SliderTab { this.onCloseAfterTimeout(); this.selector = new AppSelectPeers(this.contentDiv, skippable ? null : (length) => { - if(length) { - this.nextBtn.classList.add('is-visible'); - } else { - this.nextBtn.classList.remove('is-visible'); - } - }, 'contacts'); + this.nextBtn.classList.toggle('is-visible', !!length); + }, ['contacts']); this.nextBtn.innerHTML = ''; this.nextBtn.disabled = false; this.nextBtn.classList.add('tgico-next'); - if(skippable) { - this.nextBtn.classList.add('is-visible'); - } else { - this.nextBtn.classList.remove('is-visible'); - } + this.nextBtn.classList.toggle('is-visible', skippable); appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.addMembers); } diff --git a/src/components/sidebarLeft/editFolder.ts b/src/components/sidebarLeft/editFolder.ts index fcb4abbc..6cacd02f 100644 --- a/src/components/sidebarLeft/editFolder.ts +++ b/src/components/sidebarLeft/editFolder.ts @@ -8,6 +8,8 @@ import { copy, deepEqual } from "../../lib/utils"; import { toast } from "../toast"; import { ripple } from "../ripple"; +const MAX_FOLDER_NAME_LENGTH = 12; + export default class AppEditFolderTab implements SliderTab { public container: HTMLElement; private closeBtn: HTMLElement; @@ -120,6 +122,11 @@ export default class AppEditFolderTab implements SliderTab { }); this.nameInput.addEventListener('input', () => { + if(this.nameInput.value.length > MAX_FOLDER_NAME_LENGTH) { + this.nameInput.value = this.nameInput.value.slice(0, MAX_FOLDER_NAME_LENGTH); + return; + } + this.filter.title = this.nameInput.value; this.nameInput.classList.remove('error'); diff --git a/src/components/sidebarLeft/includedChats.ts b/src/components/sidebarLeft/includedChats.ts index d309e2c8..5ad0d3c0 100644 --- a/src/components/sidebarLeft/includedChats.ts +++ b/src/components/sidebarLeft/includedChats.ts @@ -155,7 +155,7 @@ export default class AppIncludedChatsTab implements SliderTab { const selectedPeers = (this.type == 'included' ? filter.include_peers : filter.exclude_peers).slice(); - this.selector = new AppSelectPeers(this.container, this.onSelectChange, 'dialogs', null, this.renderResults); + this.selector = new AppSelectPeers(this.container, this.onSelectChange, ['dialogs'], null, this.renderResults); this.selector.selected = new Set(selectedPeers); this.selector.input.placeholder = 'Search'; diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index b66298e2..5b370654 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -1,4 +1,4 @@ -import { findUpClassName, $rootScope, escapeRegExp, whichChild, findUpTag, cancelEvent } from "../utils"; +import { findUpClassName, $rootScope, escapeRegExp, whichChild, findUpTag, cancelEvent, positionElementByIndex } from "../utils"; import appImManager, { AppImManager } from "./appImManager"; import appPeersManager from './appPeersManager'; import appMessagesManager, { AppMessagesManager, Dialog, DialogFilter } from "./appMessagesManager"; @@ -357,7 +357,8 @@ export class AppDialogsManager { [filterID: string]: { menu: HTMLElement, container: HTMLElement, - unread: HTMLElement + unread: HTMLElement, + title: HTMLElement } } = {}; private showFiltersTimeout: number; @@ -407,7 +408,7 @@ export class AppDialogsManager { this.setListClickListener(this.chatList, null, true); - if(testScroll) { + /* if(testScroll) { let i = 0; let add = () => { let li = document.createElement('li'); @@ -421,7 +422,7 @@ export class AppDialogsManager { add(); } (window as any).addElement = add; - } + } */ $rootScope.$on('user_update', (e: CustomEvent) => { let userID = e.detail; @@ -543,6 +544,7 @@ export class AppDialogsManager { const filter: DialogFilter = e.detail; if(!this.filtersRendered[filter.id]) { this.addFilter(filter); + return; } else if(filter.id == this.filterID) { // это нет тут смысла вызывать, так как будет dialogs_multiupdate //this.validateForFilter(); const folder = appMessagesManager.dialogsStorage.getFolder(filter.id); @@ -553,6 +555,9 @@ export class AppDialogsManager { } this.setFiltersUnreadCount(); } + + const elements = this.filtersRendered[filter.id]; + elements.title.innerHTML = RichTextProcessor.wrapEmojiText(filter.title); }); $rootScope.$on('filter_delete', (e: CustomEvent) => { @@ -704,21 +709,25 @@ export class AppDialogsManager { const li = document.createElement('li'); const span = document.createElement('span'); - span.innerHTML = RichTextProcessor.wrapEmojiText(filter.title); + const titleSpan = document.createElement('span'); + titleSpan.innerHTML = RichTextProcessor.wrapEmojiText(filter.title); const unreadSpan = document.createElement('span'); unreadSpan.classList.add('unread-count'); const i = document.createElement('i'); - span.append(unreadSpan, i); + span.append(titleSpan, unreadSpan, i); li.append(span); ripple(li); - - this.folders.menu.firstElementChild.append(li); + + const containerToAppend = this.folders.menu.firstElementChild as HTMLUListElement; + positionElementByIndex(li, containerToAppend, filter.orderIndex + 1); // because 0 is All + //containerToAppend.append(li); const ul = document.createElement('ul'); const div = document.createElement('div'); div.append(ul); div.dataset.filterID = '' + filter.id; - this.folders.container.append(div); + //this.folders.container.append(div); + positionElementByIndex(div, this.folders.container, filter.orderIndex + 1); // because 0 is All this.chatLists[filter.id] = ul; this.setListClickListener(ul, null, true); @@ -734,7 +743,8 @@ export class AppDialogsManager { this.filtersRendered[filter.id] = { menu: li, container: div, - unread: unreadSpan + unread: unreadSpan, + title: titleSpan }; } @@ -750,6 +760,8 @@ export class AppDialogsManager { container.append(this.chatsPreloader); } + //return; + const storage = appMessagesManager.dialogsStorage.getFolder(folderID); let offsetIndex = 0; @@ -862,28 +874,11 @@ export class AppDialogsManager { pos = appMessagesManager.dialogsStorage.getDialog(dialog.peerID, this.filterID)[1]; } - let prevPos = whichChild(dom.listEl); - - /* let wrongFolder = (dialog.folder_id == 1 && this.chatList == dom.listEl.parentElement) || (dialog.folder_id == 0 && this.chatListArchived == dom.listEl.parentElement); - let wrongFolder = false; - if(wrongFolder) prevPos = 0xFFFF; */ + if(positionElementByIndex(dom.listEl, this.chatList, pos)) { + this.scroll.reorder(); - if(prevPos == pos) { - return; - } else if(prevPos < pos) { // was higher - pos += 1; - } - - const chatList = this.chatList; - if(chatList.childElementCount > pos) { - chatList.insertBefore(dom.listEl, chatList.children[pos]); - } else { - chatList.append(dom.listEl); + this.log.debug('setDialogPosition:', dialog, dom, pos); } - - this.scroll.reorder(); - - this.log.debug('setDialogPosition:', dialog, dom, pos); } /* public setPinnedDelimiter() { diff --git a/src/lib/appManagers/appDocsManager.ts b/src/lib/appManagers/appDocsManager.ts index a97ac0fd..4131063c 100644 --- a/src/lib/appManagers/appDocsManager.ts +++ b/src/lib/appManagers/appDocsManager.ts @@ -5,6 +5,7 @@ import { MTDocument, inputDocumentFileLocation, MTPhotoSize } from '../../types' import { getFileNameByLocation } from '../bin_utils'; import appDownloadManager, { DownloadBlob } from './appDownloadManager'; import appPhotosManager from './appPhotosManager'; +import { isServiceWorkerSupported } from '../config'; class AppDocsManager { private docs: {[docID: string]: MTDocument} = {}; @@ -122,11 +123,13 @@ class AppDocsManager { } } - if((doc.type == 'gif' && doc.size > 8e6) || doc.type == 'audio' || doc.type == 'video') { - doc.supportsStreaming = true; - - if(!doc.url) { - doc.url = this.getFileURL(doc); + if(isServiceWorkerSupported) { + if((doc.type == 'gif' && doc.size > 8e6) || doc.type == 'audio' || doc.type == 'video') { + doc.supportsStreaming = true; + + if(!doc.url) { + doc.url = this.getFileURL(doc); + } } } diff --git a/src/lib/appManagers/appMediaViewer.ts b/src/lib/appManagers/appMediaViewer.ts index f2fbb709..442edd76 100644 --- a/src/lib/appManagers/appMediaViewer.ts +++ b/src/lib/appManagers/appMediaViewer.ts @@ -818,7 +818,7 @@ export class AppMediaViewer { this.log('openMedia doc:', message); const media = message.media.photo || message.media.document || message.media.webpage.document || message.media.webpage.photo; - const isVideo = media.mime_type == 'video/mp4'; + const isVideo = (media as MTDocument).type == 'video'; const isFirstOpen = !this.peerID; if(isFirstOpen) { diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 20e64c26..33fea619 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -255,10 +255,13 @@ export type DialogFilter = { emoticon?: string, pinned_peers: number[], include_peers: number[], - exclude_peers: number[] + exclude_peers: number[], + + orderIndex?: number }; export class FiltersStorage { public filters: {[filterID: string]: DialogFilter} = {}; + public orderIndex = 0; constructor() { $rootScope.$on('apiUpdate', (e: CustomEvent) => { @@ -269,7 +272,7 @@ export class FiltersStorage { public handleUpdate(update: any) { switch(update._) { case 'updateDialogFilter': { - console.log('updateDialogFilter', update); + //console.log('updateDialogFilter', update); if(update.filter) { this.saveDialogFilter(update.filter); } else if(this.filters[update.id]) { // Папка удалена @@ -433,7 +436,7 @@ export class FiltersStorage { id: filter.id, filter: remove ? undefined : this.getOutputDialogFilter(filter) }).then((bool: boolean) => { // возможно нужна проверка и откат, если результат не ТРУ - console.log('updateDialogFilter bool:', bool); + //console.log('updateDialogFilter bool:', bool); if(bool) { /* if(!this.filters[filter.id]) { @@ -543,10 +546,22 @@ export class FiltersStorage { this.filters[filter.id] = filter; } + this.setOrderIndex(filter); + if(update) { $rootScope.$broadcast('filter_update', filter); } } + + public setOrderIndex(filter: DialogFilter) { + if(filter.hasOwnProperty('orderIndex')) { + if(filter.orderIndex > this.orderIndex) { + this.orderIndex = filter.orderIndex; + } + } else { + filter.orderIndex = this.orderIndex++; + } + } } export class AppMessagesManager { @@ -1848,6 +1863,25 @@ export class AppMessagesManager { return false; } + public async getConversationsAll(query = '') { + const limit = 100, outDialogs: Dialog[] = []; + for(let folderID = 0; folderID < 2; ++folderID) { + let offsetIndex = 0; + for(;;) { + const {dialogs} = await appMessagesManager.getConversations(query, offsetIndex, limit, folderID); + + if(dialogs.length) { + outDialogs.push(...dialogs); + offsetIndex = dialogs[dialogs.length - 1].index || 0; + } else { + break; + } + } + } + + return outDialogs; + } + public getConversations(query = '', offsetIndex?: number, limit = 20, folderID = 0) { const realFolderID = folderID > 1 ? 0 : folderID; let curDialogStorage = this.dialogsStorage.getFolder(folderID); diff --git a/src/lib/appManagers/appPhotosManager.ts b/src/lib/appManagers/appPhotosManager.ts index 0b7e31b0..76618020 100644 --- a/src/lib/appManagers/appPhotosManager.ts +++ b/src/lib/appManagers/appPhotosManager.ts @@ -176,7 +176,7 @@ export class AppPhotosManager { //console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div); let sizes = (photo as MTPhoto).sizes || (photo as MTDocument).thumbs; - if((!photo.downloaded || (photo as MTDocument).type == 'video' || (photo as MTDocument).type == 'gif') && !isSticker && sizes && sizes[0].bytes && !dontRenderPreview) { + if((!photo.downloaded || (photo as MTDocument).type == 'video' || (photo as MTDocument).type == 'gif') && !isSticker && sizes?.length && sizes[0].bytes && !dontRenderPreview) { this.setAttachmentPreview(sizes[0].bytes, element, isSticker); } diff --git a/src/lib/appManagers/appStateManager.ts b/src/lib/appManagers/appStateManager.ts index 1acf9deb..4edd9d80 100644 --- a/src/lib/appManagers/appStateManager.ts +++ b/src/lib/appManagers/appStateManager.ts @@ -23,7 +23,7 @@ type State = Partial<{ recentEmoji: string[], topPeers: number[], recentSearch: number[] -}> +}>; export class AppStateManager { public loaded: Promise; @@ -42,7 +42,11 @@ export class AppStateManager { const time = Date.now(); if((state?.stateCreatedTime ?? 0) + REFRESH_EVERY < time) { this.log('will refresh state', state.stateCreatedTime, time); - state = {}; + (['dialogs', 'allDialogsLoaded', 'messages', 'contactsList', 'stateCreatedTime', + 'updates', 'maxSeenMsgID', 'filters', 'topPeers'] as any as Array).forEach(key => { + delete state[key]; + }); + //state = {}; } const {dialogs, allDialogsLoaded, peers, messages, contactsList, maxSeenMsgID, updates, filters} = state; @@ -212,4 +216,8 @@ export class AppStateManager { } const appStateManager = new AppStateManager(); +// @ts-ignore +if(process.env.NODE_ENV != 'production') { + (window as any).appStateManager = appStateManager; +} export default appStateManager; \ No newline at end of file diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts index 83b9acf3..b7bd4799 100644 --- a/src/lib/appManagers/appUsersManager.ts +++ b/src/lib/appManagers/appUsersManager.ts @@ -108,9 +108,9 @@ export class AppUsersManager { } else console.warn('No user by id:', userID); break - case 'updateContactLink': + /* case 'updateContactLink': this.onContactUpdated(update.user_id, update.my_link._ == 'contactLinkContact'); - break; + break; */ } }); } @@ -382,6 +382,19 @@ export class AppUsersManager { return this.users[id] && this.users[id].pFlags.bot; } + public isContact(id: number) { + return this.contactsList.has(id); + } + + public isRegularUser(id: number) { + const user = this.users[id]; + return user && !this.isBot(id) && !user.pFlags.deleted && !user.pFlags.support; + } + + public isNonContactUser(id: number) { + return this.isRegularUser(id) && !this.isContact(id) && id != $rootScope.myID; + } + public hasUser(id: number, allowMin?: boolean) { var user = this.users[id]; return isObject(user) && (allowMin || !user.pFlags.min); @@ -512,7 +525,7 @@ export class AppUsersManager { }) } */ - public deleteContacts(userIDs: number[]) { + /* public deleteContacts(userIDs: number[]) { var ids: any[] = []; userIDs.forEach((userID) => { ids.push(this.getUserInput(userID)); @@ -525,7 +538,7 @@ export class AppUsersManager { this.onContactUpdated(userID, false); }); }); - } + } */ public getTopPeers(): Promise { if(this.getPeersPromise) return this.getPeersPromise; @@ -576,7 +589,7 @@ export class AppUsersManager { }); } - public onContactUpdated(userID: number, isContact: boolean) { + /* public onContactUpdated(userID: number, isContact: boolean) { userID = parseInt('' + userID); if(Array.isArray(this.contactsList)) { @@ -594,7 +607,7 @@ export class AppUsersManager { $rootScope.$broadcast('contacts_update', userID); } } - } + } */ public setUserStatus(userID: number, offline: boolean) { if(this.isBot(userID)) { diff --git a/src/lib/config.ts b/src/lib/config.ts index e8e21dd2..90bb2195 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -96,6 +96,8 @@ export const mediaSizes = new MediaSizes(); // @ts-ignore export const touchSupport = ('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch); +export const isServiceWorkerSupported = 'serviceWorker' in navigator; + const Config = { Emoji, LatinizeMap, diff --git a/src/lib/mtproto/mtprotoworker.ts b/src/lib/mtproto/mtprotoworker.ts index 67a777d7..4497f99a 100644 --- a/src/lib/mtproto/mtprotoworker.ts +++ b/src/lib/mtproto/mtprotoworker.ts @@ -6,6 +6,7 @@ import webpWorkerController from '../webp/webpWorkerController'; import MTProtoWorker from 'worker-loader!./mtproto.worker'; import type { DownloadOptions } from './apiFileManager'; import type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.service'; +import { isServiceWorkerSupported } from '../config'; type Task = { taskID: number, @@ -42,6 +43,8 @@ class ApiManagerProxy extends CryptoWorkerMethods { } private registerServiceWorker() { + if(!isServiceWorkerSupported) return; + navigator.serviceWorker.register('./sw.js', {scope: './'}).then(registration => { }, (err) => { diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 1d39ce42..89f3a9a6 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -375,6 +375,10 @@ export function getObjectKeysAndSort(object: any, sort: 'asc' | 'desc' = 'asc') } export function whichChild(elem: Node) { + if(!elem.parentNode) { + return -1; + } + let i = 0; // @ts-ignore while((elem = elem.previousElementSibling) != null) ++i; @@ -533,3 +537,21 @@ export function getFileURL(type: FileURLType, options: DownloadOptions) { return '/' + type + '/' + encoded; } + +export function positionElementByIndex(element: HTMLElement, container: HTMLElement, pos: number) { + const prevPos = whichChild(element); + + if(prevPos == pos) { + return false; + } else if(prevPos != -1 && prevPos < pos) { // was higher + pos += 1; + } + + if(container.childElementCount > pos) { + container.insertBefore(element, container.children[pos]); + } else { + container.append(element); + } + + return true; +} diff --git a/src/scss/partials/_chatBubble.scss b/src/scss/partials/_chatBubble.scss index 39377cfd..53892d9c 100644 --- a/src/scss/partials/_chatBubble.scss +++ b/src/scss/partials/_chatBubble.scss @@ -813,6 +813,13 @@ $bubble-margin: .25rem; .time { width: unset; } + + /* @include respond-to(handhelds) { + .preloader-container .you-spin-me-round { + margin-top: 1px; + margin-left: 2px; + } + } */ } .message.contact-message { diff --git a/src/scss/partials/_leftSidebar.scss b/src/scss/partials/_leftSidebar.scss index 59afb5d7..b3551698 100644 --- a/src/scss/partials/_leftSidebar.scss +++ b/src/scss/partials/_leftSidebar.scss @@ -70,6 +70,10 @@ position: relative; } + #folders-container { + min-height: 100%; + } + .sidebar-slider { height: 100%; } diff --git a/src/scss/partials/_rightSidebar.scss b/src/scss/partials/_rightSidebar.scss index f3dedec5..fdbfbd4d 100644 --- a/src/scss/partials/_rightSidebar.scss +++ b/src/scss/partials/_rightSidebar.scss @@ -411,6 +411,15 @@ min-height: 60px; } + @include respond-to(handhelds) { + .preloader-container { + width: 40px; + height: 40px; + top: 9px; + left: 2px; + } + } + .audio { padding-bottom: 26px; padding-left: 61px; diff --git a/src/scss/style.scss b/src/scss/style.scss index 6c0be7f1..ffe9c326 100644 --- a/src/scss/style.scss +++ b/src/scss/style.scss @@ -767,6 +767,21 @@ avatar-element { max-width: 100%; text-overflow: ellipsis; } + + + @include respond-to(handhelds) { + &-download { + /* background: transparent; */ + margin-left: 2px; + margin-top: 1px; + } + + &.is-voice { + .audio-download { + margin: 0; + } + } + } } .avatar-edit { @@ -1445,15 +1460,6 @@ img.emoji { // } // } -.profile-content #content-audio .preloader-container { - @include respond-to(handhelds) { - width: 40px; - height: 40px; - top: 10px; - left: 3px; - } -} - .btn-disabled { pointer-events: none !important; cursor: default !important; diff --git a/webpack.common.js b/webpack.common.js index 86ebc3dd..07168357 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -6,7 +6,7 @@ const postcssPresetEnv = require('postcss-preset-env'); const ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin'); const fs = require('fs'); -const allowedIPs = ['195.66.140.39', '192.168.31.144', '127.0.0.1', '192.168.31.1', '192.168.31.192', '176.100.18.181', '46.219.250.22', '193.42.119.184', '46.133.168.67', '78.26.144.197', '46.133.225.88']; +const allowedIPs = ['195.66.140.39', '192.168.31.144', '127.0.0.1', '192.168.31.1', '192.168.31.192', '176.100.18.181', '46.219.250.22', '193.42.119.184', '46.133.168.67', '78.26.144.197', '46.133.225.88', '128.124.170.79']; const devMode = process.env.NODE_ENV !== 'production'; const useLocal = false;