tweb/src/components/appSelectPeers.ts

707 lines
22 KiB
TypeScript
Raw Normal View History

2021-04-08 15:52:31 +02:00
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
2022-08-04 08:49:54 +02:00
import type {ChatRights} from '../lib/appManagers/appChatsManager';
import type {Dialog} from '../lib/appManagers/appMessagesManager';
2022-11-27 14:09:10 +01:00
import appDialogsManager, {DialogElementSize as DialogElementSize} from '../lib/appManagers/appDialogsManager';
2022-08-04 08:49:54 +02:00
import rootScope from '../lib/rootScope';
import Scrollable from './scrollable';
import {FocusDirection} from '../helpers/fastSmoothScroll';
import CheckboxField from './checkboxField';
import {i18n, LangPackKey, _i18n} from '../lib/langPack';
import findUpAttribute from '../helpers/dom/findUpAttribute';
import findUpClassName from '../helpers/dom/findUpClassName';
import PeerTitle from './peerTitle';
import cancelEvent from '../helpers/dom/cancelEvent';
import replaceContent from '../helpers/dom/replaceContent';
import debounce from '../helpers/schedulers/debounce';
import windowSize from '../helpers/windowSize';
import type {IsPeerType} from '../lib/appManagers/appPeersManager';
2022-08-09 17:35:11 +02:00
import {attachClickEvent, simulateClickEvent} from '../helpers/dom/clickEvent';
2022-08-04 08:49:54 +02:00
import filterUnique from '../helpers/array/filterUnique';
import indexOfAndSplice from '../helpers/array/indexOfAndSplice';
import safeAssign from '../helpers/object/safeAssign';
import findAndSplice from '../helpers/array/findAndSplice';
import AvatarElement from './avatar';
import {AppManagers} from '../lib/appManagers/managers';
import filterAsync from '../helpers/array/filterAsync';
import getParticipantPeerId from '../lib/appManagers/utils/chats/getParticipantPeerId';
import getChatMembersString from './wrappers/getChatMembersString';
import getUserStatusString from './wrappers/getUserStatusString';
import {ChannelsChannelParticipants, Chat, User} from '../layer';
2022-08-04 08:49:54 +02:00
import canSendToUser from '../lib/appManagers/utils/users/canSendToUser';
import hasRights from '../lib/appManagers/utils/chats/hasRights';
import getDialogIndex from '../lib/appManagers/utils/dialogs/getDialogIndex';
2023-01-06 20:27:29 +01:00
import {generateDelimiter} from './generateDelimiter';
import SettingSection from './settingSection';
2023-03-01 11:20:49 +01:00
import liteMode from '../helpers/liteMode';
2020-05-09 14:02:07 +02:00
type SelectSearchPeerType = 'contacts' | 'dialogs' | 'channelParticipants';
2020-08-31 18:48:46 +02:00
// TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени
export default class AppSelectPeers {
2020-05-09 14:02:07 +02:00
public container = document.createElement('div');
2021-03-19 13:14:42 +01:00
public list = appDialogsManager.createChatList(/* {
handheldsSize: 66,
avatarSize: 48
} */);
private chatsContainer = document.createElement('div');
2020-06-19 13:49:55 +02:00
public scrollable: Scrollable;
private selectedScrollable: Scrollable;
2022-08-04 08:49:54 +02:00
private selectedContainer: HTMLElement;
public input: HTMLInputElement;
2022-08-04 08:49:54 +02:00
// public selected: {[peerId: PeerId]: HTMLElement} = {};
2021-10-21 15:16:43 +02:00
public selected = new Set<PeerId | string>();
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 = '';
2021-10-21 15:16:43 +02:00
private cachedContacts: PeerId[];
2021-03-19 13:14:42 +01:00
private loadedWhat: Partial<{[k in 'dialogs' | 'archived' | 'contacts' | 'channelParticipants']: true}> = {};
2021-10-21 15:16:43 +02:00
private renderedPeerIds: Set<PeerId> = new Set();
private appendTo: HTMLElement;
private onChange: (length: number) => void;
private peerType: SelectSearchPeerType[] = ['dialogs'];
private renderResultsFunc: (peerIds: PeerId[]) => void | Promise<void>;
private chatRightsActions: ChatRights[];
private multiSelect = true;
2021-01-20 02:38:59 +01:00
private rippleEnabled = true;
2022-11-27 14:09:10 +01:00
private avatarSize: DialogElementSize = 'abitbigger';
private exceptSelf = false;
private filterPeerTypeBy: IsPeerType[];
2021-03-19 13:14:42 +01:00
private tempIds: {[k in keyof AppSelectPeers['loadedWhat']]: number} = {};
2021-10-21 15:16:43 +02:00
private peerId: PeerId;
2021-03-25 19:07:00 +01:00
private placeholder: LangPackKey;
2021-07-08 08:07:32 +02:00
private selfPresence: LangPackKey = 'Presence.YourChat';
2022-08-04 08:49:54 +02:00
2021-07-16 14:47:30 +02:00
private needSwitchList = false;
private sectionNameLangPackKey: LangPackKey;
2022-04-25 16:54:30 +02:00
private managers: AppManagers;
2022-08-04 08:49:54 +02:00
2022-11-27 14:09:10 +01:00
private design: 'round' | 'square' = 'round';
constructor(options: {
2022-08-04 08:49:54 +02:00
appendTo: AppSelectPeers['appendTo'],
onChange?: AppSelectPeers['onChange'],
peerType?: AppSelectPeers['peerType'],
peerId?: AppSelectPeers['peerId'],
2022-08-04 08:49:54 +02:00
onFirstRender?: () => void,
renderResultsFunc?: AppSelectPeers['renderResultsFunc'],
chatRightsActions?: AppSelectPeers['chatRightsActions'],
2021-01-20 02:38:59 +01:00
multiSelect?: AppSelectPeers['multiSelect'],
rippleEnabled?: AppSelectPeers['rippleEnabled'],
2021-03-19 13:14:42 +01:00
avatarSize?: AppSelectPeers['avatarSize'],
placeholder?: AppSelectPeers['placeholder'],
selfPresence?: AppSelectPeers['selfPresence'],
exceptSelf?: AppSelectPeers['exceptSelf'],
filterPeerTypeBy?: AppSelectPeers['filterPeerTypeBy'],
2022-04-25 16:54:30 +02:00
sectionNameLangPackKey?: AppSelectPeers['sectionNameLangPackKey'],
2022-11-27 14:09:10 +01:00
managers: AppSelectPeers['managers'],
design?: AppSelectPeers['design']
}) {
2021-03-21 15:36:14 +01:00
safeAssign(this, options);
2022-11-27 14:09:10 +01:00
this.container.classList.add('selector', 'selector-' + this.design);
2020-05-09 14:02:07 +02:00
const f = (this.renderResultsFunc || this.renderResults).bind(this);
this.renderResultsFunc = async(peerIds) => {
2021-07-16 14:47:30 +02:00
if(this.needSwitchList) {
2021-03-19 13:14:42 +01:00
this.scrollable.splitUp.replaceWith(this.list);
this.scrollable.setVirtualContainer(this.list);
2021-07-16 14:47:30 +02:00
this.needSwitchList = false;
2021-03-19 13:14:42 +01:00
}
2022-08-04 08:49:54 +02:00
peerIds = peerIds.filter((peerId) => {
const notRendered = !this.renderedPeerIds.has(peerId);
if(notRendered) this.renderedPeerIds.add(peerId);
return notRendered;
});
if(this.filterPeerTypeBy) {
peerIds = await filterAsync(peerIds, async(peerId) => {
if(peerId.isPeerId()) {
const peer = await this.managers.appPeersManager.getPeer(peerId);
2023-01-06 20:27:29 +01:00
if(peer) {
for(const method of this.filterPeerTypeBy) {
if(await this.managers.appPeersManager[method](peerId)) {
return true;
}
}
}
}
return true;
});
}
return f(peerIds);
};
2020-06-19 13:49:55 +02:00
this.input = document.createElement('input');
this.input.classList.add('selector-search-input');
2021-03-25 19:07:00 +01:00
if(this.placeholder) {
_i18n(this.input, this.placeholder, undefined, 'placeholder');
} else {
_i18n(this.input, 'SendMessageTo', undefined, 'placeholder');
2021-03-25 19:07:00 +01:00
}
2020-05-09 14:02:07 +02:00
this.input.type = 'text';
if(this.multiSelect) {
const section = new SettingSection({});
section.innerContainer.classList.add('selector-search-section');
2022-08-04 08:49:54 +02:00
const topContainer = document.createElement('div');
topContainer.classList.add('selector-search-container');
2022-08-04 08:49:54 +02:00
this.selectedContainer = document.createElement('div');
this.selectedContainer.classList.add('selector-search');
2022-08-04 08:49:54 +02:00
this.selectedContainer.append(this.input);
topContainer.append(this.selectedContainer);
this.selectedScrollable = new Scrollable(topContainer);
2022-08-04 08:49:54 +02:00
// let delimiter = document.createElement('hr');
2022-02-11 15:36:00 +01:00
attachClickEvent(this.selectedContainer, (e) => {
if(this.freezed) return;
let target = e.target as HTMLElement;
target = findUpClassName(target, 'selector-user');
2022-08-04 08:49:54 +02:00
if(!target) return;
2022-08-04 08:49:54 +02:00
const peerId = target.dataset.key;
const li = this.chatsContainer.querySelector('[data-peer-id="' + peerId + '"]') as HTMLElement;
if(!li) {
2021-10-21 15:16:43 +02:00
this.remove(peerId.toPeerId());
} else {
2022-07-26 08:20:30 +02:00
simulateClickEvent(li);
}
});
section.content.append(topContainer);
this.container.append(section.container/* , delimiter */);
}
2020-05-09 14:02:07 +02:00
this.chatsContainer.classList.add('chatlist-container');
// this.chatsContainer.append(this.list);
const section = new SettingSection({
name: this.sectionNameLangPackKey,
noShadow: true
});
section.content.append(this.list);
this.chatsContainer.append(section.container);
2020-05-09 14:02:07 +02:00
this.scrollable = new Scrollable(this.chatsContainer);
this.scrollable.setVirtualContainer(this.list);
2020-05-09 14:02:07 +02:00
2022-02-11 15:36:00 +01:00
attachClickEvent(this.chatsContainer, (e) => {
const target = findUpAttribute(e.target, 'data-peer-id') 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
2021-10-21 15:16:43 +02:00
let key: PeerId | string = target.dataset.peerId;
key = key.isPeerId() ? key.toPeerId() : key;
if(!this.multiSelect) {
this.add(key);
return;
}
2022-08-04 08:49:54 +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;
});
2021-07-16 14:47:30 +02:00
const debouncedInput = debounce(this.onInput, 200, false, true);
this.input.addEventListener('input', debouncedInput);
2020-05-09 14:02:07 +02:00
this.scrollable.onScrolledBottom = () => {
this.getMoreResults();
};
this.scrollable.container.prepend(generateDelimiter());
this.container.append(this.chatsContainer);
this.appendTo.append(this.container);
2020-05-09 14:02:07 +02:00
2020-06-19 13:49:55 +02:00
// WARNING TIMEOUT
setTimeout(() => {
2022-08-04 08:49:54 +02:00
const getResultsPromise = this.getMoreResults() as Promise<any>;
if(options.onFirstRender) {
2020-06-19 13:49:55 +02:00
getResultsPromise.then(() => {
options.onFirstRender();
2020-06-19 13:49:55 +02:00
});
}
}, 0);
2020-05-09 14:02:07 +02:00
}
2021-07-16 14:47:30 +02:00
private onInput = () => {
const value = this.input.value;
if(this.query !== value) {
2021-10-21 15:16:43 +02:00
if(this.peerType.includes('contacts') || this.peerType.includes('dialogs')) {
2023-01-06 20:27:29 +01:00
this.cachedContacts = undefined;
2021-07-16 14:47:30 +02:00
}
2022-08-04 08:49:54 +02:00
2021-07-16 14:47:30 +02:00
if(this.peerType.includes('dialogs')) {
this.folderId = 0;
this.offsetIndex = 0;
}
2022-08-04 08:49:54 +02:00
for(const i in this.tempIds) {
2021-07-16 14:47:30 +02:00
// @ts-ignore
++this.tempIds[i];
}
this.list = appDialogsManager.createChatList();
2023-01-06 20:27:29 +01:00
this.promise = undefined;
2021-07-16 14:47:30 +02:00
this.loadedWhat = {};
this.query = value;
this.renderedPeerIds.clear();
this.needSwitchList = true;
2022-08-04 08:49:54 +02:00
// console.log('selectPeers input:', this.query);
2021-07-16 14:47:30 +02:00
this.getMoreResults();
}
};
private async renderSaved() {
if(
2022-08-04 08:49:54 +02:00
!this.exceptSelf &&
!this.offsetIndex &&
this.folderId === 0 &&
this.peerType.includes('dialogs') &&
(!this.query || await this.managers.appUsersManager.testSelfSearch(this.query))
) {
await this.renderResultsFunc([rootScope.myId]);
}
}
2021-03-19 15:27:02 +01:00
private getTempId(type: keyof AppSelectPeers['tempIds']) {
2023-01-06 20:27:29 +01:00
this.tempIds[type] ??= 0;
const tempId = ++this.tempIds[type];
return {
tempId,
middleware: () => this.tempIds[type] === tempId
};
2021-03-19 15:27:02 +01:00
}
private async getMoreDialogs(): Promise<any> {
if(this.loadedWhat.dialogs && this.loadedWhat.archived) {
return;
}
2022-08-04 08:49:54 +02:00
2020-05-09 14:02:07 +02:00
// в десктопе - сначала без группы, потом архивные, потом контакты без сообщений
2022-11-27 14:09:10 +01:00
const pageCount = windowSize.height / 56 * 1.25 | 0;
2020-05-09 14:02:07 +02:00
2023-01-06 20:27:29 +01:00
const {middleware} = this.getTempId('dialogs');
const promise = this.managers.dialogsStorage.getDialogs({
query: this.query,
offsetIndex: this.offsetIndex,
limit: pageCount,
filterId: this.folderId,
skipMigrated: true
});
promise.catch(() => {
if(!middleware()) {
return;
}
this.loadedWhat[this.loadedWhat.dialogs ? 'archived' : 'dialogs'] = true;
});
2021-07-16 14:47:30 +02:00
const value = await promise;
2023-01-06 20:27:29 +01:00
if(!middleware()) {
2021-03-19 13:14:42 +01:00
return;
}
let dialogs = value.dialogs as Dialog[];
if(dialogs.length) {
const newOffsetIndex = getDialogIndex(dialogs[dialogs.length - 1]) || 0;
2020-08-31 18:48:46 +02:00
dialogs = dialogs.slice();
2022-03-26 02:55:57 +01:00
findAndSplice(dialogs, d => d.peerId === rootScope.myId); // no my account
2020-08-31 18:48:46 +02:00
if(this.chatRightsActions) {
dialogs = await filterAsync(dialogs, (d) => this.filterByRights(d.peerId));
2023-01-06 20:27:29 +01:00
if(!middleware()) {
return;
}
}
await this.renderSaved();
2023-01-06 20:27:29 +01:00
if(!middleware()) {
return;
}
this.offsetIndex = newOffsetIndex;
2021-07-16 14:47:30 +02:00
}
2021-10-21 15:16:43 +02:00
this.renderResultsFunc(dialogs.map((dialog) => dialog.peerId));
2022-08-04 08:49:54 +02:00
2021-07-16 14:47:30 +02:00
if(value.isEnd) {
if(!this.loadedWhat.dialogs) {
await this.renderSaved();
2023-01-06 20:27:29 +01:00
if(!middleware()) {
return;
}
this.loadedWhat.dialogs = true;
this.offsetIndex = 0;
this.folderId = 1;
return this.getMoreDialogs();
} else {
this.loadedWhat.archived = true;
2021-10-21 15:16:43 +02:00
if(!this.loadedWhat.contacts/* && this.peerType.includes('contacts') */) {
return this.getMoreContacts();
}
}
}
2020-05-09 14:02:07 +02:00
}
private async filterByRights(peerId: PeerId) {
const peer: User | Chat = await this.managers.appPeersManager.getPeer(peerId);
if(peerId.isUser()) {
return this.chatRightsActions[0] !== 'send_plain' || canSendToUser(peer as User.user);
} else if(this.chatRightsActions.every((action) => hasRights(peer as Chat.chat, action))) {
return true;
}
2021-07-16 14:47:30 +02:00
}
2020-05-09 14:02:07 +02:00
private async getMoreContacts() {
if(this.loadedWhat.contacts) {
return;
}
2021-10-21 15:16:43 +02:00
const isGlobalSearch = this.peerType.includes('contacts');
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(); */
2023-01-06 20:27:29 +01:00
const {middleware} = this.getTempId('contacts');
2021-07-16 14:47:30 +02:00
const promise = Promise.all([
2022-04-25 16:54:30 +02:00
isGlobalSearch ? this.managers.appUsersManager.getContactsPeerIds(this.query) : [],
this.query ? this.managers.appUsersManager.searchContacts(this.query) : undefined
2021-07-16 14:47:30 +02:00
]);
2023-01-06 20:27:29 +01:00
promise.catch(() => {
if(!middleware()) {
return;
}
this.loadedWhat.contacts = true;
});
2022-08-04 08:49:54 +02:00
const [cachedContacts, searchResult] = await promise;
2023-01-06 20:27:29 +01:00
if(!middleware()) {
2021-03-19 13:14:42 +01:00
return;
}
2021-07-16 14:47:30 +02:00
if(searchResult) {
2021-10-21 15:16:43 +02:00
// do not add global result if only dialogs needed
let resultPeerIds = isGlobalSearch ? searchResult.my_results.concat(searchResult.results) : searchResult.my_results;
2021-07-16 14:47:30 +02:00
if(this.chatRightsActions) {
resultPeerIds = await filterAsync(resultPeerIds, (peerId) => this.filterByRights(peerId));
2023-01-06 20:27:29 +01:00
if(!middleware()) {
return;
}
2021-07-16 14:47:30 +02:00
}
if(!this.peerType.includes('dialogs')) {
resultPeerIds = resultPeerIds.filter((peerId) => peerId.isUser());
2021-07-16 14:47:30 +02:00
}
this.cachedContacts = filterUnique(cachedContacts.concat(resultPeerIds));
} else this.cachedContacts = cachedContacts.slice();
2021-10-21 15:16:43 +02:00
indexOfAndSplice(this.cachedContacts, rootScope.myId); // no my account
2020-05-09 14:02:07 +02:00
}
2021-10-21 15:16:43 +02:00
// if(this.cachedContacts.length) {
2022-11-27 14:09:10 +01:00
const pageCount = windowSize.height / 56 * 1.25 | 0;
2022-08-04 08:49:54 +02:00
const arr = this.cachedContacts.splice(0, pageCount);
this.renderResultsFunc(arr);
2021-10-21 15:16:43 +02:00
// }
2022-08-04 08:49:54 +02:00
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')) {
2020-08-31 18:48:46 +02:00
return this.getMoreDialogs();
} */
2020-05-09 14:02:07 +02:00
}
}
2021-03-19 13:14:42 +01:00
private async getMoreChannelParticipants() {
if(this.loadedWhat.channelParticipants) {
return;
}
const pageCount = 50; // same as in group permissions to use cache
2023-01-06 20:27:29 +01:00
const {middleware} = this.getTempId('channelParticipants');
const promise = this.managers.appProfileManager.getParticipants(
2023-01-06 20:27:29 +01:00
this.peerId.toChatId(),
{
_: 'channelParticipantsSearch',
q: this.query
},
pageCount,
this.list.childElementCount
);
promise.catch(() => {
if(!middleware()) {
return;
}
this.loadedWhat.channelParticipants = true;
});
const chatParticipants = await promise;
2023-01-06 20:27:29 +01:00
if(!middleware()) {
2021-03-19 13:14:42 +01:00
return;
}
2022-08-04 08:49:54 +02:00
const {participants} = chatParticipants;
const peerIds = participants.map((participant) => getParticipantPeerId(participant));
2021-10-21 15:16:43 +02:00
indexOfAndSplice(peerIds, rootScope.myId);
2021-05-03 22:02:53 +02:00
this.renderResultsFunc(peerIds);
2021-03-19 13:14:42 +01:00
const count = (chatParticipants as ChannelsChannelParticipants.channelsChannelParticipants).count ?? participants.length;
if(this.list.childElementCount >= count || participants.length < pageCount) {
2021-03-19 13:14:42 +01:00
this.loadedWhat.channelParticipants = true;
}
}
checkForTriggers = () => {
this.scrollable.checkForTriggers();
};
2020-08-31 18:48:46 +02:00
private getMoreResults() {
2023-01-06 20:27:29 +01:00
if(this.promise) {
return this.promise;
}
2022-08-04 08:49:54 +02:00
2023-01-06 20:27:29 +01:00
const get = () => {
if((this.peerType.includes('dialogs')/* || this.loadedWhat.contacts */) && !this.loadedWhat.archived) { // to load non-contacts
2023-01-06 20:27:29 +01:00
return this.getMoreSomething('dialogs');
}
2022-08-04 08:49:54 +02:00
2021-10-21 15:16:43 +02:00
if((this.peerType.includes('contacts') || this.peerType.includes('dialogs')) && !this.loadedWhat.contacts) {
2023-01-06 20:27:29 +01:00
return this.getMoreSomething('contacts');
}
2021-03-19 13:14:42 +01:00
if(this.peerType.includes('channelParticipants') && !this.loadedWhat.channelParticipants) {
2023-01-06 20:27:29 +01:00
return this.getMoreSomething('channelParticipants');
2021-03-19 13:14:42 +01:00
}
};
2022-08-04 08:49:54 +02:00
2023-01-06 20:27:29 +01:00
const loadPromise = get();
if(!loadPromise) {
return Promise.resolve();
}
2023-01-06 20:27:29 +01:00
const promise = this.promise = loadPromise.catch((err) => {
console.error('get more result error', err);
}).finally(() => {
if(this.promise === promise) {
this.promise = undefined;
}
this.checkForTriggers();
});
return promise;
}
private getMoreSomething(peerType: SelectSearchPeerType) {
const map: {[type in SelectSearchPeerType]: () => Promise<any>} = {
dialogs: this.getMoreDialogs,
contacts: this.getMoreContacts,
channelParticipants: this.getMoreChannelParticipants
};
const promise = map[peerType].call(this);
return promise;
2020-05-09 14:02:07 +02:00
}
private async renderResults(peerIds: PeerId[]) {
2022-08-04 08:49:54 +02:00
// console.log('will renderResults:', peerIds);
2020-08-31 18:48:46 +02:00
// оставим только неконтакты с диалогов
if(!this.peerType.includes('dialogs') && this.loadedWhat.contacts) {
peerIds = await filterAsync(peerIds, (peerId) => {
2022-04-25 16:54:30 +02:00
return this.managers.appUsersManager.isNonContactUser(peerId);
2020-08-31 18:48:46 +02:00
});
}
peerIds.forEach(async(peerId) => {
const {dom} = appDialogsManager.addDialogNew({
peerId: peerId,
container: this.scrollable,
2021-03-19 13:14:42 +01:00
rippleEnabled: this.rippleEnabled,
avatarSize: this.avatarSize
});
2020-06-19 13:49:55 +02:00
if(this.multiSelect) {
const selected = this.selected.has(peerId);
const checkboxField = new CheckboxField();
2021-01-20 02:38:59 +01:00
if(selected) {
2022-08-04 08:49:54 +02:00
// dom.listEl.classList.add('active');
2021-01-20 02:38:59 +01:00
checkboxField.input.checked = true;
}
dom.containerEl.prepend(checkboxField.label);
}
2020-05-09 14:02:07 +02:00
2021-03-28 20:37:11 +02:00
let subtitleEl: HTMLElement;
2021-10-21 15:16:43 +02:00
if(peerId.isAnyChat()) {
subtitleEl = await getChatMembersString(peerId.toChatId());
2021-02-04 01:30:23 +01:00
} else if(peerId === rootScope.myId) {
2021-07-08 08:07:32 +02:00
subtitleEl = i18n(this.selfPresence);
2020-05-09 14:02:07 +02:00
} else {
subtitleEl = getUserStatusString(await this.managers.appUsersManager.getUser(peerId.toUserId()));
2020-05-09 14:02:07 +02:00
}
2021-03-28 20:37:11 +02:00
dom.lastMessageSpan.append(subtitleEl);
2020-05-09 14:02:07 +02:00
});
}
2021-10-21 15:16:43 +02:00
public add(key: PeerId | string, title?: string | HTMLElement, scroll = true) {
2022-08-04 08:49:54 +02:00
// console.trace('add');
2021-10-21 15:16:43 +02:00
this.selected.add(key);
if(!this.multiSelect) {
this.onChange(this.selected.size);
return;
}
2021-07-16 14:47:30 +02:00
if(this.query.trim()) {
this.input.value = '';
this.onInput();
}
const div = document.createElement('div');
2020-05-09 14:02:07 +02:00
div.classList.add('selector-user', 'scale-in');
2022-03-29 23:01:12 +02:00
const avatarEl = new AvatarElement();
avatarEl.classList.add('selector-user-avatar', 'tgico', 'avatar-32');
avatarEl.isDialog = true;
2020-05-09 14:02:07 +02:00
2021-10-21 15:16:43 +02:00
div.dataset.key = '' + key;
if(key.isPeerId()) {
2020-06-19 13:49:55 +02:00
if(title === undefined) {
2023-01-06 20:27:29 +01:00
const peerTitle = new PeerTitle();
peerTitle.update({peerId: key.toPeerId(), dialog: true});
title = peerTitle.element;
2020-06-19 13:49:55 +02:00
}
2022-03-29 23:01:12 +02:00
avatarEl.updateWithOptions({
peerId: key as PeerId
});
2020-06-19 13:49:55 +02:00
}
if(title) {
2021-03-21 15:36:14 +01:00
if(typeof(title) === 'string') {
div.innerHTML = title;
} else {
replaceContent(div, title);
2021-03-21 15:36:14 +01:00
div.append(title);
}
2020-06-19 13:49:55 +02:00
}
div.insertAdjacentElement('afterbegin', avatarEl);
2020-05-09 14:02:07 +02:00
this.selectedContainer.insertBefore(div, this.input);
2022-08-04 08:49:54 +02:00
// this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight;
2022-11-01 18:39:23 +01:00
this.onChange?.(this.selected.size);
2022-08-04 08:49:54 +02:00
if(scroll) {
this.selectedScrollable.scrollIntoViewNew({
2022-08-04 08:49:54 +02:00
element: this.input,
position: 'center'
});
}
2022-08-04 08:49:54 +02:00
2020-06-19 13:49:55 +02:00
return div;
2020-05-09 14:02:07 +02:00
}
2021-10-21 15:16:43 +02:00
public remove(key: PeerId | string) {
if(!this.multiSelect) return;
2022-08-04 08:49:54 +02:00
// const div = this.selected[peerId];
2020-06-19 13:49:55 +02:00
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');
2021-01-03 16:59:13 +01:00
const onAnimationEnd = () => {
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);
2021-01-03 16:59:13 +01:00
};
2023-03-01 11:20:49 +01:00
if(liteMode.isAvailable('animations')) {
2021-01-03 16:59:13 +01:00
div.addEventListener('animationend', onAnimationEnd, {once: true});
} else {
onAnimationEnd();
}
2020-05-09 14:02:07 +02:00
}
public getSelected() {
2020-06-19 13:49:55 +02:00
return [...this.selected];
2020-05-09 14:02:07 +02:00
}
public addInitial(values: any[]) {
values.forEach((value) => {
this.add(value, undefined, false);
});
window.requestAnimationFrame(() => { // ! not the best place for this raf though it works
this.selectedScrollable.scrollIntoViewNew({
2022-08-04 08:49:54 +02:00
element: this.input,
position: 'center',
forceDirection: FocusDirection.Static
});
});
}
2021-03-19 13:14:42 +01:00
}