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' ;
2023-02-27 14:11:37 +01:00
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
2021-10-21 16:15:31 +02:00
type SelectSearchPeerType = 'contacts' | 'dialogs' | 'channelParticipants' ;
2020-08-31 18:48:46 +02:00
// TODO: правильная сортировка для addMembers, т.е . для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени
2020-10-20 01:39:36 +02:00
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
} * / ) ;
2022-01-08 13:52:14 +01:00
private chatsContainer = document . createElement ( 'div' ) ;
2020-06-19 13:49:55 +02:00
public scrollable : Scrollable ;
2022-01-08 13:52:14 +01:00
private selectedScrollable : Scrollable ;
2022-08-04 08:49:54 +02:00
2022-01-08 13:52:14 +01:00
private selectedContainer : HTMLElement ;
2020-10-20 01:39:36 +02:00
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 ;
2020-12-11 03:06:16 +01:00
private folderId = 0 ;
2020-05-09 14:02:07 +02:00
private offsetIndex = 0 ;
2020-05-30 08:44:54 +02:00
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 [ ] ;
2020-08-30 23:50:25 +02:00
2021-03-19 13:14:42 +01:00
private loadedWhat : Partial < { [ k in 'dialogs' | 'archived' | 'contacts' | 'channelParticipants' ] : true } > = { } ;
2020-10-21 01:25:36 +02:00
2021-10-21 15:16:43 +02:00
private renderedPeerIds : Set < PeerId > = new Set ( ) ;
2021-01-07 13:36:21 +01:00
private appendTo : HTMLElement ;
private onChange : ( length : number ) = > void ;
2021-10-21 16:15:31 +02:00
private peerType : SelectSearchPeerType [ ] = [ 'dialogs' ] ;
2022-06-17 18:01:43 +02:00
private renderResultsFunc : ( peerIds : PeerId [ ] ) = > void | Promise < void > ;
2023-02-27 14:11:37 +01:00
private chatRightsActions : ChatRights [ ] ;
2021-01-07 13:36:21 +01:00
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' ;
2021-10-21 16:15:31 +02:00
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
2021-07-16 15:07:53 +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 ;
2022-01-08 13:52:14 +01:00
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' ;
2021-01-07 13:36:21 +01:00
constructor ( options : {
2022-08-04 08:49:54 +02:00
appendTo : AppSelectPeers [ 'appendTo' ] ,
onChange? : AppSelectPeers [ 'onChange' ] ,
peerType? : AppSelectPeers [ 'peerType' ] ,
2021-10-21 16:15:31 +02:00
peerId? : AppSelectPeers [ 'peerId' ] ,
2022-08-04 08:49:54 +02:00
onFirstRender ? : ( ) = > void ,
renderResultsFunc? : AppSelectPeers [ 'renderResultsFunc' ] ,
2023-02-27 14:11:37 +01:00
chatRightsActions? : AppSelectPeers [ 'chatRightsActions' ] ,
2021-01-20 02:38:59 +01:00
multiSelect? : AppSelectPeers [ 'multiSelect' ] ,
2021-10-21 16:15:31 +02:00
rippleEnabled? : AppSelectPeers [ 'rippleEnabled' ] ,
2021-03-19 13:14:42 +01:00
avatarSize? : AppSelectPeers [ 'avatarSize' ] ,
2021-10-21 16:15:31 +02:00
placeholder? : AppSelectPeers [ 'placeholder' ] ,
selfPresence? : AppSelectPeers [ 'selfPresence' ] ,
exceptSelf? : AppSelectPeers [ 'exceptSelf' ] ,
2022-01-08 13:52:14 +01:00
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-01-07 13:36:21 +01:00
} ) {
2021-03-21 15:36:14 +01:00
safeAssign ( this , options ) ;
2021-01-07 13:36:21 +01:00
2022-11-27 14:09:10 +01:00
this . container . classList . add ( 'selector' , 'selector-' + this . design ) ;
2020-05-09 14:02:07 +02:00
2021-01-07 13:36:21 +01:00
const f = ( this . renderResultsFunc || this . renderResults ) . bind ( this ) ;
2022-06-17 18:01:43 +02:00
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
2022-06-17 18:01:43 +02:00
peerIds = peerIds . filter ( ( peerId ) = > {
2020-12-11 03:06:16 +01:00
const notRendered = ! this . renderedPeerIds . has ( peerId ) ;
if ( notRendered ) this . renderedPeerIds . add ( peerId ) ;
2020-10-21 01:25:36 +02:00
return notRendered ;
} ) ;
2021-10-21 16:15:31 +02:00
if ( this . filterPeerTypeBy ) {
2022-06-17 18:01:43 +02:00
peerIds = await filterAsync ( peerIds , async ( peerId ) = > {
2021-10-21 16:15:31 +02:00
if ( peerId . isPeerId ( ) ) {
2022-06-17 18:01:43 +02:00
const peer = await this . managers . appPeersManager . getPeer ( peerId ) ;
2023-01-06 20:27:29 +01:00
if ( peer ) {
2022-06-17 18:01:43 +02:00
for ( const method of this . filterPeerTypeBy ) {
if ( await this . managers . appPeersManager [ method ] ( peerId ) ) {
return true ;
}
}
2021-10-21 16:15:31 +02:00
}
}
return true ;
} ) ;
}
2020-12-11 03:06:16 +01:00
return f ( peerIds ) ;
2020-10-21 01:25:36 +02:00
} ;
2020-06-19 13:49:55 +02:00
2020-10-20 01:39:36 +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 {
2021-03-27 16:34:08 +01:00
_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' ;
2021-01-07 13:36:21 +01:00
if ( this . multiSelect ) {
2022-01-08 13:52:14 +01:00
const section = new SettingSection ( { } ) ;
section . innerContainer . classList . add ( 'selector-search-section' ) ;
2022-08-04 08:49:54 +02:00
const topContainer = document . createElement ( 'div' ) ;
2020-10-20 01:39:36 +02:00
topContainer . classList . add ( 'selector-search-container' ) ;
2022-08-04 08:49:54 +02:00
2020-10-20 01:39:36 +02:00
this . selectedContainer = document . createElement ( 'div' ) ;
this . selectedContainer . classList . add ( 'selector-search' ) ;
2022-08-04 08:49:54 +02:00
2020-10-20 01:39:36 +02:00
this . selectedContainer . append ( this . input ) ;
topContainer . append ( this . selectedContainer ) ;
this . selectedScrollable = new Scrollable ( topContainer ) ;
2022-08-04 08:49:54 +02:00
2022-01-08 13:52:14 +01:00
// let delimiter = document.createElement('hr');
2020-10-20 01:39:36 +02:00
2022-02-11 15:36:00 +01:00
attachClickEvent ( this . selectedContainer , ( e ) = > {
2020-10-20 01:39:36 +02:00
if ( this . freezed ) return ;
let target = e . target as HTMLElement ;
target = findUpClassName ( target , 'selector-user' ) ;
2022-08-04 08:49:54 +02:00
2020-10-20 01:39:36 +02:00
if ( ! target ) return ;
2022-08-04 08:49:54 +02:00
2020-12-11 03:06:16 +01:00
const peerId = target . dataset . key ;
2021-01-12 12:22:00 +01:00
const li = this . chatsContainer . querySelector ( '[data-peer-id="' + peerId + '"]' ) as HTMLElement ;
2020-10-20 01:39:36 +02:00
if ( ! li ) {
2021-10-21 15:16:43 +02:00
this . remove ( peerId . toPeerId ( ) ) ;
2020-10-20 01:39:36 +02:00
} else {
2022-07-26 08:20:30 +02:00
simulateClickEvent ( li ) ;
2020-10-20 01:39:36 +02:00
}
} ) ;
2022-01-08 13:52:14 +01:00
section . content . append ( topContainer ) ;
this . container . append ( section . container /* , delimiter */ ) ;
2020-10-20 01:39:36 +02:00
}
2020-05-09 14:02:07 +02:00
2020-12-01 16:38:36 +01:00
this . chatsContainer . classList . add ( 'chatlist-container' ) ;
2022-01-08 13:52:14 +01:00
// 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 ) ;
2020-05-30 08:44:54 +02:00
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 ) = > {
2021-01-12 12:22:00 +01:00
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 ;
2020-10-20 01:39:36 +02:00
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 ( ) ;
} ;
2022-01-08 13:52:14 +01:00
this . scrollable . container . prepend ( generateDelimiter ( ) ) ;
2020-10-20 01:39:36 +02:00
this . container . append ( this . chatsContainer ) ;
2021-01-07 13:36:21 +01:00
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 > ;
2021-01-07 13:36:21 +01:00
if ( options . onFirstRender ) {
2020-06-19 13:49:55 +02:00
getResultsPromise . then ( ( ) = > {
2021-01-07 13:36:21 +01:00
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 ( ) ;
}
} ;
2022-06-17 18:01:43 +02:00
private async renderSaved() {
if (
2022-08-04 08:49:54 +02:00
! this . exceptSelf &&
! this . offsetIndex &&
this . folderId === 0 &&
this . peerType . includes ( 'dialogs' ) &&
2022-06-17 18:01:43 +02:00
( ! this . query || await this . managers . appUsersManager . testSelfSearch ( this . query ) )
) {
await this . renderResultsFunc ( [ rootScope . myId ] ) ;
2020-10-07 15:57:33 +02:00
}
}
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
}
2020-08-30 23:50:25 +02: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 ;
}
2020-05-30 08:44:54 +02:00
let dialogs = value . dialogs as Dialog [ ] ;
2020-08-30 23:50:25 +02:00
if ( dialogs . length ) {
2022-06-17 18:01:43 +02:00
const newOffsetIndex = getDialogIndex ( dialogs [ dialogs . length - 1 ] ) || 0 ;
2020-08-30 23:50:25 +02:00
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
2023-02-27 14:11:37 +01:00
if ( this . chatRightsActions ) {
2022-06-17 18:01:43 +02:00
dialogs = await filterAsync ( dialogs , ( d ) = > this . filterByRights ( d . peerId ) ) ;
2023-01-06 20:27:29 +01:00
if ( ! middleware ( ) ) {
return ;
}
2020-10-07 22:49:52 +02:00
}
2022-06-17 18:01:43 +02:00
await this . renderSaved ( ) ;
2023-01-06 20:27:29 +01:00
if ( ! middleware ( ) ) {
return ;
}
2020-05-30 08:44:54 +02:00
2020-08-30 23:50:25 +02:00
this . offsetIndex = newOffsetIndex ;
2021-07-16 14:47:30 +02:00
}
2021-10-21 15:16:43 +02:00
2022-06-17 18:01: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 ) {
2020-08-30 23:50:25 +02:00
if ( ! this . loadedWhat . dialogs ) {
2022-06-17 18:01:43 +02:00
await this . renderSaved ( ) ;
2023-01-06 20:27:29 +01:00
if ( ! middleware ( ) ) {
return ;
}
2020-10-07 15:57:33 +02:00
2020-08-30 23:50:25 +02:00
this . loadedWhat . dialogs = true ;
this . offsetIndex = 0 ;
2020-12-11 03:06:16 +01:00
this . folderId = 1 ;
2020-08-30 23:50:25 +02:00
return this . getMoreDialogs ( ) ;
} else {
this . loadedWhat . archived = true ;
2021-10-21 15:16:43 +02:00
if ( ! this . loadedWhat . contacts /* && this.peerType.includes('contacts') */ ) {
2020-08-30 23:50:25 +02:00
return this . getMoreContacts ( ) ;
}
}
}
2020-05-09 14:02:07 +02:00
}
2022-06-17 18:01:43 +02:00
private async filterByRights ( peerId : PeerId ) {
const peer : User | Chat = await this . managers . appPeersManager . getPeer ( peerId ) ;
if ( peerId . isUser ( ) ) {
2023-02-27 14:11:37 +01:00
return this . chatRightsActions [ 0 ] !== 'send_plain' || canSendToUser ( peer as User . user ) ;
} else if ( this . chatRightsActions . every ( ( action ) = > hasRights ( peer as Chat . chat , action ) ) ) {
2022-06-17 18:01:43 +02:00
return true ;
}
2021-07-16 14:47:30 +02:00
}
2020-05-09 14:02:07 +02:00
private async getMoreContacts() {
2020-08-30 23:50:25 +02:00
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
/ * c o n s t p r o m i s e s : P r o m i s e < a n y > [ ] = [ a p p U s e r s M a n a g e r . g e t C o n t a c t s ( t h i s . q u e r y ) ] ;
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
2023-02-27 14:11:37 +01:00
if ( this . chatRightsActions ) {
2022-06-17 18:01:43 +02:00
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' ) ) {
2022-06-17 18:01:43 +02:00
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 ) {
2020-08-30 23:50:25 +02:00
this . loadedWhat . contacts = true ;
2020-08-31 18:48:46 +02:00
// need to load non-contacts
2021-07-15 17:34:34 +02:00
/ * i f ( ! t h i s . p e e r T y p e . i n c l u d e s ( ' d i a l o g s ' ) ) {
2020-08-31 18:48:46 +02:00
return this . getMoreDialogs ( ) ;
2021-07-15 17:34:34 +02:00
} * /
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' ) ;
2023-02-27 14:11:37 +01:00
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 ;
} ) ;
2023-02-27 14:11:37 +01:00
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
2023-02-27 14:11:37 +01: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
2023-02-27 14:11:37 +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 ;
}
}
2020-10-08 00:20:38 +02:00
checkForTriggers = ( ) = > {
this . scrollable . checkForTriggers ( ) ;
} ;
2020-08-31 18:48:46 +02:00
2020-10-08 00:20:38 +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 = ( ) = > {
2021-07-15 17:34:34 +02:00
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' ) ;
2020-10-08 00:20:38 +02:00
}
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' ) ;
2020-10-08 00:20:38 +02:00
}
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
}
2020-10-08 00:20:38 +02: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 ( ) ;
2020-08-30 23:50:25 +02:00
}
2020-10-28 17:11:57 +01:00
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 ) ;
2020-10-28 17:11:57 +01:00
return promise ;
2020-05-09 14:02:07 +02:00
}
2022-06-17 18:01:43 +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 ) {
2022-06-17 18:01:43 +02:00
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
} ) ;
}
2022-06-17 18:01:43 +02:00
peerIds . forEach ( async ( peerId ) = > {
2020-12-14 01:19:36 +01:00
const { dom } = appDialogsManager . addDialogNew ( {
2022-06-17 18:01:43 +02:00
peerId : peerId ,
2020-12-14 01:19:36 +01:00
container : this.scrollable ,
2021-03-19 13:14:42 +01:00
rippleEnabled : this.rippleEnabled ,
avatarSize : this.avatarSize
2020-12-14 01:19:36 +01:00
} ) ;
2020-06-19 13:49:55 +02:00
2020-10-20 01:39:36 +02:00
if ( this . multiSelect ) {
2020-12-11 03:06:16 +01:00
const selected = this . selected . has ( peerId ) ;
2021-03-08 23:15:44 +01:00
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-10-20 01:39:36 +02:00
}
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 ( ) ) {
2022-06-17 18:01:43 +02:00
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 {
2022-06-17 18:01:43 +02:00
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 ) ;
2020-10-20 01:39:36 +02:00
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 ( ) ;
}
2020-05-30 08:44:54 +02:00
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 {
2021-04-10 20:29:58 +02:00
replaceContent ( div , title ) ;
2021-03-21 15:36:14 +01:00
div . append ( title ) ;
}
2020-06-19 13:49:55 +02:00
}
2020-05-13 17:26:40 +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
2021-01-07 13:36:21 +01:00
if ( scroll ) {
2022-01-08 13:52:14 +01:00
this . selectedScrollable . scrollIntoViewNew ( {
2022-08-04 08:49:54 +02:00
element : this.input ,
2022-01-08 13:52:14 +01:00
position : 'center'
} ) ;
2021-01-07 13:36:21 +01:00
}
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 ) {
2020-10-20 01:39:36 +02:00
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
}
2021-01-07 13:36:21 +01:00
public addInitial ( values : any [ ] ) {
2022-06-17 18:01:43 +02:00
values . forEach ( ( value ) = > {
2021-01-07 13:36:21 +01:00
this . add ( value , undefined , false ) ;
} ) ;
2021-02-28 21:14:01 +01:00
window . requestAnimationFrame ( ( ) = > { // ! not the best place for this raf though it works
2022-01-08 13:52:14 +01:00
this . selectedScrollable . scrollIntoViewNew ( {
2022-08-04 08:49:54 +02:00
element : this.input ,
position : 'center' ,
2022-01-08 13:52:14 +01:00
forceDirection : FocusDirection.Static
} ) ;
2021-02-28 21:14:01 +01:00
} ) ;
2021-01-07 13:36:21 +01:00
}
2021-03-19 13:14:42 +01:00
}