tweb/src/components/appSelectPeers.ts

332 lines
11 KiB
TypeScript
Raw Normal View History

2020-05-09 14:02:07 +02:00
import Scrollable from "./scrollable_new";
import appMessagesManager, { Dialog } from "../lib/appManagers/appMessagesManager";
2020-08-31 18:48:46 +02:00
import { $rootScope, cancelEvent, findUpClassName, findUpAttribute } from "../lib/utils";
2020-05-09 14:02:07 +02:00
import appDialogsManager from "../lib/appManagers/appDialogsManager";
import appChatsManager from "../lib/appManagers/appChatsManager";
import appUsersManager from "../lib/appManagers/appUsersManager";
import appPeersManager from "../lib/appManagers/appPeersManager";
2020-05-09 14:02:07 +02:00
import appPhotosManager from "../lib/appManagers/appPhotosManager";
2020-08-31 18:48:46 +02:00
type PeerType = 'contacts' | 'dialogs';
// TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени
let loadedAllDialogs = false;
2020-05-09 14:02:07 +02:00
export class AppSelectPeers {
public container = document.createElement('div');
2020-06-19 13:49:55 +02:00
public list = document.createElement('ul');
public chatsContainer = document.createElement('div');
public scrollable: Scrollable;
public selectedScrollable: Scrollable;
2020-05-09 14:02:07 +02:00
2020-06-19 13:49:55 +02:00
public selectedContainer = document.createElement('div');
public input = document.createElement('input');
2020-05-09 14:02:07 +02:00
2020-06-19 13:49:55 +02:00
//public selected: {[peerID: number]: HTMLElement} = {};
public selected = new Set<any>();
2020-05-09 14:02:07 +02:00
public freezed = false;
private folderID = 0;
2020-05-09 14:02:07 +02:00
private offsetIndex = 0;
private promise: Promise<any>;
2020-05-09 14:02:07 +02:00
private query = '';
private cachedContacts: number[];
private loadedWhat: Partial<{[k in 'dialogs' | 'archived' | 'contacts']: true}> = {};
2020-05-09 14:02:07 +02:00
2020-08-31 18:48:46 +02:00
constructor(private appendTo: HTMLElement, private onChange?: (length: number) => void, private peerType: PeerType[] = ['dialogs'], onFirstRender?: () => void, private renderResultsFunc?: (peerIDs: number[]) => void) {
2020-05-09 14:02:07 +02:00
this.container.classList.add('selector');
2020-06-19 13:49:55 +02:00
if(!this.renderResultsFunc) {
this.renderResultsFunc = this.renderResults;
}
2020-05-09 14:02:07 +02:00
let topContainer = document.createElement('div');
topContainer.classList.add('selector-search-container');
this.selectedContainer.classList.add('selector-search');
2020-08-31 18:48:46 +02:00
this.input.placeholder = !peerType.includes('dialogs') ? 'Add People...' : 'Select chat';
2020-05-09 14:02:07 +02:00
this.input.type = 'text';
this.selectedContainer.append(this.input);
topContainer.append(this.selectedContainer);
this.selectedScrollable = new Scrollable(topContainer);
let delimiter = document.createElement('hr');
this.chatsContainer.classList.add('chats-container');
this.chatsContainer.append(this.list);
this.scrollable = new Scrollable(this.chatsContainer);
this.scrollable.setVirtualContainer(this.list);
2020-05-09 14:02:07 +02:00
2020-06-19 13:49:55 +02:00
this.chatsContainer.addEventListener('click', (e) => {
const target = findUpAttribute(e.target, 'data-peerID') as HTMLElement;
2020-05-09 14:02:07 +02:00
cancelEvent(e);
if(!target) return;
2020-06-19 13:49:55 +02:00
if(this.freezed) return;
2020-05-09 14:02:07 +02:00
2020-06-19 13:49:55 +02:00
let key: any = target.getAttribute('data-peerID');
key = +key || key;
2020-05-09 14:02:07 +02:00
target.classList.toggle('active');
2020-06-19 13:49:55 +02:00
if(this.selected.has(key)) {
this.remove(key);
2020-05-09 14:02:07 +02:00
} else {
2020-06-19 13:49:55 +02:00
this.add(key);
2020-05-09 14:02:07 +02:00
}
2020-06-19 13:49:55 +02:00
const checkbox = target.querySelector('input') as HTMLInputElement;
2020-05-09 14:02:07 +02:00
checkbox.checked = !checkbox.checked;
});
this.selectedContainer.addEventListener('click', (e) => {
if(this.freezed) return;
let target = e.target as HTMLElement;
target = findUpClassName(target, 'selector-user');
if(!target) return;
2020-06-19 13:49:55 +02:00
const peerID = target.dataset.key;
const li = this.chatsContainer.querySelector('[data-peerid="' + peerID + '"]') as HTMLElement;
if(!li) {
this.remove(+peerID || peerID);
} else {
li.click();
}
2020-05-09 14:02:07 +02:00
});
this.input.addEventListener('input', () => {
2020-08-31 18:48:46 +02:00
const value = this.input.value;
2020-05-09 14:02:07 +02:00
if(this.query != value) {
2020-08-31 18:48:46 +02:00
if(this.peerType.includes('contacts')) {
delete this.loadedWhat.contacts;
2020-05-09 14:02:07 +02:00
this.cachedContacts = null;
}
2020-08-31 18:48:46 +02:00
//if(this.peerType.includes('dialogs')) {
delete this.loadedWhat.dialogs;
delete this.loadedWhat.archived;
this.folderID = 0;
this.offsetIndex = 0;
2020-08-31 18:48:46 +02:00
//}
2020-05-09 14:02:07 +02:00
this.promise = null;
2020-05-09 14:02:07 +02:00
this.list.innerHTML = '';
this.query = value;
2020-06-16 22:48:08 +02:00
//console.log('selectPeers input:', this.query);
2020-05-09 14:02:07 +02:00
this.getMoreResults();
}
});
this.scrollable.onScrolledBottom = () => {
this.getMoreResults();
};
this.container.append(topContainer, delimiter, this.chatsContainer);
appendTo.append(this.container);
2020-06-19 13:49:55 +02:00
// WARNING TIMEOUT
setTimeout(() => {
let getResultsPromise = this.getMoreResults() as Promise<any>;
if(onFirstRender) {
getResultsPromise.then(() => {
onFirstRender();
});
}
}, 0);
2020-05-09 14:02:07 +02:00
}
private async getMoreDialogs(): Promise<any> {
if(this.promise) return this.promise;
if(this.loadedWhat.dialogs && this.loadedWhat.archived) {
return;
}
2020-05-09 14:02:07 +02:00
// в десктопе - сначала без группы, потом архивные, потом контакты без сообщений
const pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;
2020-05-09 14:02:07 +02:00
this.promise = appMessagesManager.getConversations(this.query, this.offsetIndex, pageCount, this.folderID);
const value = await this.promise;
2020-08-31 18:48:46 +02:00
this.promise = null;
let dialogs = value.dialogs as Dialog[];
if(dialogs.length) {
const newOffsetIndex = dialogs[dialogs.length - 1].index || 0;
2020-08-31 18:48:46 +02:00
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({
2020-08-31 18:48:46 +02:00
peerID: $rootScope.myID,
pFlags: {}
} as any);
}
this.offsetIndex = newOffsetIndex;
this.renderResultsFunc(dialogs.map(dialog => dialog.peerID));
} else {
if(!this.loadedWhat.dialogs) {
this.loadedWhat.dialogs = true;
this.offsetIndex = 0;
this.folderID = 1;
return this.getMoreDialogs();
} else {
this.loadedWhat.archived = true;
2020-08-31 18:48:46 +02:00
if(!this.loadedWhat.contacts && this.peerType.includes('contacts')) {
return this.getMoreContacts();
}
}
}
2020-05-09 14:02:07 +02:00
}
private async getMoreContacts() {
if(this.promise) return this.promise;
if(this.loadedWhat.contacts) {
return;
}
2020-05-09 14:02:07 +02:00
if(!this.cachedContacts) {
2020-08-31 18:48:46 +02:00
/* const promises: Promise<any>[] = [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(); */
2020-05-09 14:02:07 +02:00
this.promise = appUsersManager.getContacts(this.query);
this.cachedContacts = (await this.promise).slice();
2020-08-31 18:48:46 +02:00
this.cachedContacts.findAndSplice(userID => userID == $rootScope.myID); // no my account
2020-05-09 14:02:07 +02:00
this.promise = null;
}
if(this.cachedContacts.length) {
const pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;
const arr = this.cachedContacts.splice(0, pageCount);
2020-06-19 13:49:55 +02:00
this.renderResultsFunc(arr);
2020-08-31 18:48:46 +02:00
}
if(!this.cachedContacts.length) {
this.loadedWhat.contacts = true;
2020-08-31 18:48:46 +02:00
// need to load non-contacts
if(!this.peerType.includes('dialogs')) {
return this.getMoreDialogs();
}
2020-05-09 14:02:07 +02:00
}
}
private getMoreResults() {
const promises: Promise<any>[] = [];
2020-08-31 18:48:46 +02:00
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) {
return Promise.all(promises);
}
2020-05-09 14:02:07 +02:00
}
2020-08-31 18:48:46 +02:00
if(this.peerType.includes('contacts') && !this.loadedWhat.contacts) {
promises.push(this.getMoreContacts());
}
return Promise.all(promises);
2020-05-09 14:02:07 +02:00
}
private renderResults(peerIDs: number[]) {
2020-06-16 22:48:08 +02:00
//console.log('will renderResults:', peerIDs);
2020-08-31 18:48:46 +02:00
// оставим только неконтакты с диалогов
if(!this.peerType.includes('dialogs') && this.loadedWhat.contacts) {
peerIDs = peerIDs.filter(peerID => {
return appUsersManager.isNonContactUser(peerID);
});
}
2020-05-09 14:02:07 +02:00
peerIDs.forEach(peerID => {
const {dom} = appDialogsManager.addDialog(peerID, this.scrollable, false, false);
2020-06-19 13:49:55 +02:00
const selected = this.selected.has(peerID);
dom.containerEl.insertAdjacentHTML('afterbegin', `<div class="checkbox"><label><input type="checkbox" ${selected ? 'checked' : ''}><span></span></label></div>`);
if(selected) dom.listEl.classList.add('active');
2020-05-09 14:02:07 +02:00
let subtitle = '';
if(peerID < 0) {
subtitle = appChatsManager.getChatMembersString(-peerID);
2020-08-31 18:48:46 +02:00
} else if(peerID == $rootScope.myID) {
2020-05-09 14:02:07 +02:00
subtitle = 'chat with yourself';
} else {
subtitle = appUsersManager.getUserStatusString(peerID);
if(subtitle == 'online') {
subtitle = `<i>${subtitle}</i>`;
}
}
dom.lastMessageSpan.innerHTML = subtitle;
});
}
2020-06-19 13:49:55 +02:00
public add(peerID: any, title?: string) {
2020-06-20 03:11:24 +02:00
//console.trace('add');
const div = document.createElement('div');
2020-05-09 14:02:07 +02:00
div.classList.add('selector-user', 'scale-in');
const avatarEl = document.createElement('avatar-element');
avatarEl.classList.add('selector-user-avatar', 'tgico');
avatarEl.setAttribute('dialog', '1');
2020-05-09 14:02:07 +02:00
2020-06-19 13:49:55 +02:00
div.dataset.key = '' + peerID;
this.selected.add(peerID);
if(typeof(peerID) === 'number') {
if(title === undefined) {
title = peerID == $rootScope.myID ? 'Saved' : appPeersManager.getPeerTitle(peerID, false, true);
}
avatarEl.setAttribute('peer', '' + peerID);
}
if(title) {
div.innerHTML = title;
}
div.insertAdjacentElement('afterbegin', avatarEl);
2020-05-09 14:02:07 +02:00
this.selectedContainer.insertBefore(div, this.input);
2020-06-19 13:49:55 +02:00
//this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight;
this.selectedScrollable.scrollTo(this.selectedScrollable.scrollHeight, 'top', true, true);
2020-06-19 13:49:55 +02:00
this.onChange && this.onChange(this.selected.size);
return div;
2020-05-09 14:02:07 +02:00
}
2020-06-19 13:49:55 +02:00
public remove(key: any) {
//const div = this.selected[peerID];
const div = this.selectedContainer.querySelector(`[data-key="${key}"]`) as HTMLElement;
2020-05-09 14:02:07 +02:00
div.classList.remove('scale-in');
void div.offsetWidth;
div.classList.add('scale-out');
div.addEventListener('animationend', () => {
2020-06-19 13:49:55 +02:00
this.selected.delete(key);
2020-05-09 14:02:07 +02:00
div.remove();
2020-06-19 13:49:55 +02:00
this.onChange && this.onChange(this.selected.size);
2020-05-09 14:02:07 +02:00
}, {once: true});
}
public getSelected() {
2020-06-19 13:49:55 +02:00
return [...this.selected];
2020-05-09 14:02:07 +02:00
}
}