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 { MyInputMessagesFilter , MyMessage } from '../lib/appManagers/appMessagesManager' ;
2023-01-06 20:27:29 +01:00
import appDialogsManager , { DIALOG_LIST_ELEMENT_TAG } from '../lib/appManagers/appDialogsManager' ;
2022-08-04 08:49:54 +02:00
import { logger } from '../lib/logger' ;
import rootScope from '../lib/rootScope' ;
import { SearchGroup , SearchGroupType } from './appSearch' ;
import { horizontalMenu } from './horizontalMenu' ;
import LazyLoadQueue from './lazyLoadQueue' ;
import { putPreloader } from './putPreloader' ;
import ripple from './ripple' ;
import Scrollable , { ScrollableX } from './scrollable' ;
import useHeavyAnimationCheck , { getHeavyAnimationPromise } from '../hooks/useHeavyAnimationCheck' ;
import I18n , { LangPackKey , i18n } from '../lib/langPack' ;
import findUpClassName from '../helpers/dom/findUpClassName' ;
2022-09-13 14:27:28 +02:00
import { getMiddleware , Middleware } from '../helpers/middleware' ;
2023-03-02 16:51:37 +01:00
import { ChannelParticipant , Chat , ChatFull , ChatParticipant , ChatParticipants , Document , Message , MessageMedia , Photo , User , WebPage } from '../layer' ;
2022-08-04 08:49:54 +02:00
import SortedUserList from './sortedUserList' ;
import findUpTag from '../helpers/dom/findUpTag' ;
import appSidebarRight from './sidebarRight' ;
import mediaSizes from '../helpers/mediaSizes' ;
import appImManager from '../lib/appManagers/appImManager' ;
import positionElementByIndex from '../helpers/dom/positionElementByIndex' ;
import cleanSearchText from '../helpers/cleanSearchText' ;
import IS_TOUCH_SUPPORTED from '../environment/touchSupport' ;
import handleTabSwipe from '../helpers/dom/handleTabSwipe' ;
import windowSize from '../helpers/windowSize' ;
import { formatPhoneNumber } from '../helpers/formatPhoneNumber' ;
2023-01-06 20:27:29 +01:00
import { ButtonMenuItemOptions , ButtonMenuSync } from './buttonMenu' ;
2022-08-04 08:49:54 +02:00
import PopupForward from './popups/forward' ;
import PopupDeleteMessages from './popups/deleteMessages' ;
import Row from './row' ;
import htmlToDocumentFragment from '../helpers/dom/htmlToDocumentFragment' ;
import { SearchSelection } from './chat/selection' ;
import cancelEvent from '../helpers/dom/cancelEvent' ;
import { attachClickEvent , simulateClickEvent } from '../helpers/dom/clickEvent' ;
import { MyDocument } from '../lib/appManagers/appDocsManager' ;
import AppMediaViewer from './appMediaViewer' ;
import lockTouchScroll from '../helpers/dom/lockTouchScroll' ;
import copy from '../helpers/object/copy' ;
import getObjectKeysAndSort from '../helpers/object/getObjectKeysAndSort' ;
import safeAssign from '../helpers/object/safeAssign' ;
import escapeRegExp from '../helpers/string/escapeRegExp' ;
import findAndSplice from '../helpers/array/findAndSplice' ;
import { ScrollStartCallbackDimensions } from '../helpers/fastSmoothScroll' ;
import setInnerHTML from '../helpers/dom/setInnerHTML' ;
import { AppManagers } from '../lib/appManagers/managers' ;
import choosePhotoSize from '../lib/appManagers/utils/photos/choosePhotoSize' ;
import wrapWebPageDescription from './wrappers/webPageDescription' ;
import wrapWebPageTitle from './wrappers/webPageTitle' ;
2023-01-06 20:27:29 +01:00
import wrapAbbreviation from '../lib/richTextProcessor/wrapAbbreviation' ;
2022-08-04 08:49:54 +02:00
import matchUrl from '../lib/richTextProcessor/matchUrl' ;
import wrapPlainText from '../lib/richTextProcessor/wrapPlainText' ;
import wrapRichText from '../lib/richTextProcessor/wrapRichText' ;
import wrapSenderToPeer from './wrappers/senderToPeer' ;
import wrapSentTime from './wrappers/sentTime' ;
import getMediaFromMessage from '../lib/appManagers/utils/messages/getMediaFromMessage' ;
import filterMessagesByInputFilter from '../lib/appManagers/utils/messages/filterMessagesByInputFilter' ;
import getChatMembersString from './wrappers/getChatMembersString' ;
import getUserStatusString from './wrappers/getUserStatusString' ;
import getParticipantPeerId from '../lib/appManagers/utils/chats/getParticipantPeerId' ;
import { Awaited } from '../types' ;
import { attachContextMenuListener } from '../helpers/dom/attachContextMenuListener' ;
import contextMenuController from '../helpers/contextMenuController' ;
import positionMenu from '../helpers/positionMenu' ;
import apiManagerProxy from '../lib/mtproto/mtprotoworker' ;
2022-08-09 17:35:11 +02:00
import ListenerSetter from '../helpers/listenerSetter' ;
import SwipeHandler from './swipeHandler' ;
2022-09-20 19:34:08 +02:00
import wrapDocument from './wrappers/document' ;
import wrapPhoto from './wrappers/photo' ;
import wrapVideo from './wrappers/video' ;
2022-11-27 14:09:10 +01:00
import noop from '../helpers/noop' ;
2023-01-12 16:13:22 +01:00
import wrapMediaSpoiler , { onMediaSpoilerClick } from './wrappers/mediaSpoiler' ;
2023-03-02 16:51:37 +01:00
import filterAsync from '../helpers/array/filterAsync' ;
2023-03-05 13:01:04 +01:00
import ChatContextMenu from './chat/contextMenu' ;
2023-03-07 22:25:07 +01:00
import PopupElement from './popups' ;
2023-03-08 19:48:55 +01:00
import getParticipantRank from '../lib/appManagers/utils/chats/getParticipantRank' ;
2022-08-04 08:49:54 +02:00
// const testScroll = false;
2020-12-25 00:19:34 +01:00
2021-04-07 19:11:08 +02:00
export type SearchSuperType = MyInputMessagesFilter /* | 'members' */ ;
2020-12-25 13:53:20 +01:00
export type SearchSuperContext = {
2021-10-21 15:16:43 +02:00
peerId : PeerId ,
2021-09-23 15:41:02 +02:00
inputFilter : { _ : MyInputMessagesFilter } ,
2020-12-25 13:53:20 +01:00
query? : string ,
maxId? : number ,
folderId? : number ,
threadId? : number ,
date? : number ,
2020-12-25 18:38:32 +01:00
nextRate? : number ,
minDate? : number ,
maxDate? : number
2020-12-25 13:53:20 +01:00
} ;
2023-03-02 16:51:37 +01:00
export type SearchSuperMediaType = 'members' | 'media' | 'files' | 'links' | 'music' | 'chats' | 'voice' | 'groups' ;
2021-04-07 19:11:08 +02:00
export type SearchSuperMediaTab = {
inputFilter : SearchSuperType ,
name : LangPackKey ,
type : SearchSuperMediaType ,
contentTab? : HTMLElement ,
menuTab? : HTMLElement ,
scroll ? : { scrollTop : number , scrollHeight : number }
} ;
2021-09-12 07:12:39 +02:00
class SearchContextMenu {
2022-06-17 18:01:43 +02:00
private buttons : ( ButtonMenuItemOptions & { verify ? : ( ) = > boolean | Promise < boolean > , withSelection? : true } ) [ ] ;
2021-09-12 07:12:39 +02:00
private element : HTMLElement ;
private target : HTMLElement ;
2021-10-21 15:16:43 +02:00
private peerId : PeerId ;
2021-09-12 07:12:39 +02:00
private mid : number ;
private isSelected : boolean ;
2022-04-25 16:54:30 +02:00
private managers : AppManagers ;
2023-03-05 13:01:04 +01:00
private noForwards : boolean ;
private message : MyMessage ;
private selectedMessages : MyMessage [ ] ;
2021-09-12 07:12:39 +02:00
constructor (
private attachTo : HTMLElement ,
2022-07-26 07:22:46 +02:00
private searchSuper : AppSearchSuper ,
private listenerSetter : ListenerSetter
2021-09-12 07:12:39 +02:00
) {
2022-04-25 16:54:30 +02:00
this . managers = searchSuper . managers ;
2023-01-17 20:28:27 +01:00
const onContextMenu : Parameters < typeof attachContextMenuListener > [ 0 ] [ 'callback' ] = ( e ) = > {
2021-09-12 07:12:39 +02:00
if ( this . init ) {
this . init ( ) ;
this . init = null ;
}
let item : HTMLElement ;
try {
item = findUpClassName ( e . target , 'search-super-item' ) ;
} catch ( e ) { }
if ( ! item ) return ;
if ( e instanceof MouseEvent ) e . preventDefault ( ) ;
if ( this . element . classList . contains ( 'active' ) ) {
return false ;
}
if ( e instanceof MouseEvent ) e . cancelBubble = true ;
2022-06-17 18:01:43 +02:00
const r = async ( ) = > {
this . target = item ;
this . peerId = item . dataset . peerId . toPeerId ( ) ;
this . mid = + item . dataset . mid ;
this . isSelected = searchSuper . selection . isMidSelected ( this . peerId , this . mid ) ;
2023-03-05 13:01:04 +01:00
this . message = await this . managers . appMessagesManager . getMessageByPeer ( this . peerId , this . mid ) ;
this . noForwards = searchSuper . selection . isSelecting ?
this . searchSuper . selection . selectionForwardBtn . classList . contains ( 'hide' ) :
! ( await this . managers . appMessagesManager . canForward ( this . message ) ) ;
this . selectedMessages = searchSuper . selection . isSelecting ? await searchSuper . selection . getSelectedMessages ( ) : undefined ;
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
await Promise . all ( this . buttons . map ( async ( button ) = > {
let good : boolean ;
2022-08-04 08:49:54 +02:00
2023-03-05 13:01:04 +01:00
if ( this . searchSuper . selection . isSelecting && ! button . withSelection ) {
2022-06-17 18:01:43 +02:00
good = false ;
} else {
2023-03-05 13:01:04 +01:00
good = button . verify ? ! ! ( await button . verify ( ) ) : true ;
2022-06-17 18:01:43 +02:00
}
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
button . element . classList . toggle ( 'hide' , ! good ) ;
} ) ) ;
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
item . classList . add ( 'menu-open' ) ;
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
positionMenu ( e , this . element ) ;
contextMenuController . openBtnMenu ( this . element , ( ) = > {
item . classList . remove ( 'menu-open' ) ;
} ) ;
} ;
2021-09-12 07:12:39 +02:00
2022-06-17 18:01:43 +02:00
r ( ) ;
2021-09-12 07:12:39 +02:00
} ;
2021-09-26 15:59:10 +02:00
if ( IS_TOUCH_SUPPORTED ) {
2021-09-12 07:12:39 +02:00
} else {
2023-01-17 20:28:27 +01:00
attachContextMenuListener ( {
element : attachTo ,
callback : onContextMenu as any ,
listenerSetter
} ) ;
2021-09-12 07:12:39 +02:00
}
}
private init() {
this . buttons = [ {
icon : 'forward' ,
text : 'Forward' ,
2022-01-08 13:52:14 +01:00
onClick : this.onForwardClick ,
2023-03-05 13:01:04 +01:00
verify : ( ) = > ! this . noForwards
2021-09-12 07:12:39 +02:00
} , {
icon : 'forward' ,
text : 'Message.Context.Selection.Forward' ,
onClick : this.onForwardClick ,
2023-03-05 13:01:04 +01:00
verify : ( ) = > this . searchSuper . selection . isSelecting && ! this . noForwards ,
withSelection : true
} , {
icon : 'download' ,
text : 'MediaViewer.Context.Download' ,
onClick : ( ) = > ChatContextMenu . onDownloadClick ( this . message , this . noForwards ) ,
verify : ( ) = > ! this . searchSuper . selection . isSelecting && ChatContextMenu . canDownload ( this . message , undefined , this . noForwards )
} , {
icon : 'download' ,
text : 'Message.Context.Selection.Download' ,
onClick : ( ) = > ChatContextMenu . onDownloadClick ( this . selectedMessages , this . noForwards ) ,
verify : ( ) = > this . searchSuper . selection . isSelecting && ChatContextMenu . canDownload ( this . selectedMessages , undefined , this . noForwards ) ,
2021-09-12 07:12:39 +02:00
withSelection : true
} , {
icon : 'message' ,
text : 'Message.Context.Goto' ,
onClick : this.onGotoClick ,
withSelection : true
} , {
icon : 'select' ,
text : 'Message.Context.Select' ,
2023-03-05 13:01:04 +01:00
onClick : this.onSelectClick ,
verify : ( ) = > ! this . isSelected ,
withSelection : true
2021-09-12 07:12:39 +02:00
} , {
icon : 'select' ,
text : 'Message.Context.Selection.Clear' ,
onClick : this.onClearSelectionClick ,
verify : ( ) = > this . isSelected ,
withSelection : true
} , {
icon : 'delete danger' ,
text : 'Delete' ,
onClick : this.onDeleteClick ,
2023-03-05 13:01:04 +01:00
verify : ( ) = > ! this . searchSuper . selection . isSelecting && this . managers . appMessagesManager . canDeleteMessage ( this . message )
2021-09-12 07:12:39 +02:00
} , {
icon : 'delete danger' ,
text : 'Message.Context.Selection.Delete' ,
onClick : this.onDeleteClick ,
2023-03-05 13:01:04 +01:00
verify : ( ) = > this . searchSuper . selection . isSelecting && ! this . searchSuper . selection . selectionDeleteBtn . classList . contains ( 'hide' ) ,
2021-09-12 07:12:39 +02:00
withSelection : true
} ] ;
2023-01-06 20:27:29 +01:00
this . element = ButtonMenuSync ( { buttons : this.buttons , listenerSetter : this.listenerSetter } ) ;
2021-09-12 07:12:39 +02:00
this . element . classList . add ( 'search-contextmenu' , 'contextmenu' ) ;
document . getElementById ( 'page-chats' ) . append ( this . element ) ;
}
private onGotoClick = ( ) = > {
2022-06-24 19:23:12 +02:00
appImManager . setInnerPeer ( {
2021-09-12 07:12:39 +02:00
peerId : this.peerId ,
2022-06-24 19:23:12 +02:00
lastMsgId : this.mid ,
2021-09-12 07:12:39 +02:00
threadId : this.searchSuper.searchContext.threadId
} ) ;
} ;
private onForwardClick = ( ) = > {
if ( this . searchSuper . selection . isSelecting ) {
simulateClickEvent ( this . searchSuper . selection . selectionForwardBtn ) ;
} else {
2023-03-07 22:25:07 +01:00
PopupElement . createPopup ( PopupForward , {
2021-09-12 07:12:39 +02:00
[ this . peerId ] : [ this . mid ]
} ) ;
}
} ;
private onSelectClick = ( ) = > {
this . searchSuper . selection . toggleByElement ( this . target ) ;
} ;
private onClearSelectionClick = ( ) = > {
this . searchSuper . selection . cancelSelection ( ) ;
} ;
private onDeleteClick = ( ) = > {
if ( this . searchSuper . selection . isSelecting ) {
simulateClickEvent ( this . searchSuper . selection . selectionDeleteBtn ) ;
} else {
2023-03-07 22:25:07 +01:00
PopupElement . createPopup ( PopupDeleteMessages , this . peerId , [ this . mid ] , 'chat' ) ;
2021-09-12 07:12:39 +02:00
}
} ;
}
2022-01-13 00:54:33 +01:00
export type ProcessSearchSuperResult = {
2022-08-04 08:49:54 +02:00
message : Message.message ,
2022-09-13 14:27:28 +02:00
middleware : Middleware ,
2022-08-04 08:49:54 +02:00
promises : Promise < any > [ ] ,
2022-01-13 00:54:33 +01:00
elemsToAppend : { element : HTMLElement , message : any } [ ] ,
inputFilter : MyInputMessagesFilter ,
searchGroup? : SearchGroup
} ;
2020-12-25 00:19:34 +01:00
export default class AppSearchSuper {
2020-12-25 13:53:20 +01:00
public tabs : { [ t in SearchSuperType ] : HTMLDivElement } = { } as any ;
2020-12-25 00:19:34 +01:00
2021-04-07 19:11:08 +02:00
public mediaTab : SearchSuperMediaTab ;
2020-12-25 00:19:34 +01:00
public container : HTMLElement ;
2020-12-25 18:38:32 +01:00
public nav : HTMLElement ;
2021-09-12 07:12:39 +02:00
public navScrollableContainer : HTMLDivElement ;
public tabsContainer : HTMLElement ;
public navScrollable : ScrollableX ;
2021-01-18 19:34:41 +01:00
private tabsMenu : HTMLElement ;
2020-12-25 00:19:34 +01:00
private prevTabId = - 1 ;
2022-08-04 08:49:54 +02:00
2020-12-25 00:19:34 +01:00
private lazyLoadQueue = new LazyLoadQueue ( ) ;
2021-04-07 19:11:08 +02:00
public middleware = getMiddleware ( ) ;
2020-12-25 00:19:34 +01:00
2021-10-21 15:16:43 +02:00
public historyStorage : Partial < { [ type in SearchSuperType ] : { mid : number , peerId : PeerId } [ ] } > = { } ;
2020-12-25 13:53:20 +01:00
public usedFromHistory : Partial < { [ type in SearchSuperType ] : number } > = { } ;
2020-12-25 00:19:34 +01:00
2021-09-12 07:12:39 +02:00
public searchContext : SearchSuperContext ;
2020-12-25 00:19:34 +01:00
public loadMutex : Promise < any > = Promise . resolve ( ) ;
2020-12-25 13:53:20 +01:00
private nextRates : Partial < { [ type in SearchSuperType ] : number } > = { } ;
private loadPromises : Partial < { [ type in SearchSuperType ] : Promise < void > } > = { } ;
private loaded : Partial < { [ type in SearchSuperType ] : boolean } > = { } ;
private loadedChats = false ;
2021-04-14 10:30:14 +02:00
private firstLoad = true ;
2020-12-25 00:19:34 +01:00
2020-12-25 13:53:20 +01:00
private log = logger ( 'SEARCH-SUPER' ) ;
public selectTab : ReturnType < typeof horizontalMenu > ;
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
private monthContainers : Partial < {
[ type in SearchSuperType ] : {
[ timestamp : number ] : {
container : HTMLElement ,
items : HTMLElement
}
}
} > = { } ;
2020-12-25 18:38:32 +01:00
private searchGroupMedia : SearchGroup ;
2021-04-07 19:11:08 +02:00
public mediaTabsMap : Map < SearchSuperMediaType , SearchSuperMediaTab > = new Map ( ) ;
2021-04-11 01:14:57 +02:00
private membersList : SortedUserList ;
2021-04-18 13:55:56 +02:00
private skipScroll : boolean ;
2021-04-07 19:11:08 +02:00
// * arguments
public mediaTabs : SearchSuperMediaTab [ ] ;
public scrollable : Scrollable ;
public searchGroups ? : { [ group in SearchGroupType ] : SearchGroup } ;
public asChatList ? = false ;
public groupByMonth ? = true ;
public hideEmptyTabs ? = true ;
2021-04-10 15:52:21 +02:00
public onChangeTab ? : ( mediaTab : SearchSuperMediaTab ) = > void ;
2021-04-10 21:39:36 +02:00
public showSender ? = false ;
2021-04-07 19:11:08 +02:00
2021-09-12 07:12:39 +02:00
private searchContextMenu : SearchContextMenu ;
public selection : SearchSelection ;
2022-04-05 21:13:51 +02:00
public scrollStartCallback : ( dimensions : ScrollStartCallbackDimensions ) = > void ;
2022-04-25 16:54:30 +02:00
public managers : AppManagers ;
2022-06-17 18:01:43 +02:00
private loadFirstTimePromise : Promise < void > ;
2022-04-25 16:54:30 +02:00
2022-07-26 07:22:46 +02:00
private listenerSetter : ListenerSetter ;
private swipeHandler : SwipeHandler ;
2022-04-25 16:54:30 +02:00
constructor ( options : Pick < AppSearchSuper , ' mediaTabs ' | ' scrollable ' | ' searchGroups ' | ' asChatList ' | ' groupByMonth ' | ' hideEmptyTabs ' | ' onChangeTab ' | ' showSender ' | ' managers ' > ) {
2021-04-07 19:11:08 +02:00
safeAssign ( this , options ) ;
2021-03-11 23:39:57 +01:00
2020-12-25 00:19:34 +01:00
this . container = document . createElement ( 'div' ) ;
this . container . classList . add ( 'search-super' ) ;
2022-07-26 07:22:46 +02:00
this . listenerSetter = new ListenerSetter ( ) ;
this . searchContextMenu = new SearchContextMenu ( this . container , this , this . listenerSetter ) ;
this . selection = new SearchSelection ( this , this . managers , this . listenerSetter ) ;
2021-09-12 07:12:39 +02:00
2021-04-18 13:55:56 +02:00
const navScrollableContainer = this . navScrollableContainer = document . createElement ( 'div' ) ;
2021-04-13 18:19:52 +02:00
navScrollableContainer . classList . add ( 'search-super-tabs-scrollable' , 'menu-horizontal-scrollable' , 'sticky' ) ;
2020-12-25 18:38:32 +01:00
2021-09-12 07:12:39 +02:00
const navScrollable = this . navScrollable = new ScrollableX ( navScrollableContainer ) ;
navScrollable . container . classList . add ( 'search-super-nav-scrollable' ) ;
2020-12-25 18:38:32 +01:00
const nav = this . nav = document . createElement ( 'nav' ) ;
2021-01-18 19:34:41 +01:00
nav . classList . add ( 'search-super-tabs' , 'menu-horizontal-div' ) ;
this . tabsMenu = nav ;
2020-12-25 00:19:34 +01:00
2020-12-25 18:38:32 +01:00
navScrollable . container . append ( nav ) ;
2021-04-07 19:11:08 +02:00
for ( const mediaTab of this . mediaTabs ) {
2021-01-18 19:34:41 +01:00
const menuTab = document . createElement ( 'div' ) ;
menuTab . classList . add ( 'menu-horizontal-div-item' ) ;
2020-12-25 00:19:34 +01:00
const span = document . createElement ( 'span' ) ;
const i = document . createElement ( 'i' ) ;
2021-04-07 19:11:08 +02:00
span . append ( i18n ( mediaTab . name ) ) ;
2020-12-25 00:19:34 +01:00
span . append ( i ) ;
2021-01-18 19:34:41 +01:00
menuTab . append ( span ) ;
2020-12-25 00:19:34 +01:00
2021-01-18 19:34:41 +01:00
ripple ( menuTab ) ;
2020-12-25 00:19:34 +01:00
2021-01-18 19:34:41 +01:00
this . tabsMenu . append ( menuTab ) ;
2021-04-07 19:11:08 +02:00
this . mediaTabsMap . set ( mediaTab . type , mediaTab ) ;
mediaTab . menuTab = menuTab ;
2020-12-25 00:19:34 +01:00
}
this . tabsContainer = document . createElement ( 'div' ) ;
this . tabsContainer . classList . add ( 'search-super-tabs-container' , 'tabs-container' ) ;
2021-10-21 15:16:43 +02:00
let unlockScroll : ReturnType < typeof lockTouchScroll > ;
2021-09-26 15:59:10 +02:00
if ( IS_TOUCH_SUPPORTED ) {
2022-07-26 07:22:46 +02:00
this . swipeHandler = handleTabSwipe ( {
2022-08-04 08:49:54 +02:00
element : this.tabsContainer ,
2021-10-21 15:16:43 +02:00
onSwipe : ( xDiff , yDiff , e ) = > {
2023-01-13 15:50:48 +01:00
xDiff *= - 1 ;
yDiff *= - 1 ;
2021-10-21 15:16:43 +02:00
const prevId = this . selectTab . prevId ( ) ;
const children = Array . from ( this . tabsMenu . children ) as HTMLElement [ ] ;
let idx : number ;
if ( xDiff > 0 ) {
for ( let i = prevId + 1 ; i < children . length ; ++ i ) {
if ( ! children [ i ] . classList . contains ( 'hide' ) ) {
idx = i ;
break ;
}
}
} else {
for ( let i = prevId - 1 ; i >= 0 ; -- i ) {
if ( ! children [ i ] . classList . contains ( 'hide' ) ) {
idx = i ;
break ;
}
}
}
if ( idx !== undefined ) {
unlockScroll = lockTouchScroll ( this . tabsContainer ) ;
this . selectTab ( idx ) ;
}
2023-01-31 15:38:29 +01:00
} ,
verifyTouchTarget : ( e ) = > {
return ! findUpClassName ( e . target , 'scrollable-x' ) ;
2021-10-21 15:16:43 +02:00
}
2021-08-25 00:19:05 +02:00
} ) ;
}
2021-04-07 19:11:08 +02:00
for ( const mediaTab of this . mediaTabs ) {
2020-12-25 00:19:34 +01:00
const container = document . createElement ( 'div' ) ;
2021-08-20 15:55:23 +02:00
container . classList . add ( 'search-super-container-' + mediaTab . type , 'tabs-tab' ) ;
2020-12-25 00:19:34 +01:00
const content = document . createElement ( 'div' ) ;
2021-04-07 19:11:08 +02:00
content . classList . add ( 'search-super-content-' + mediaTab . type ) ;
2020-12-25 00:19:34 +01:00
container . append ( content ) ;
this . tabsContainer . append ( container ) ;
2021-04-07 19:11:08 +02:00
this . tabs [ mediaTab . inputFilter ] = content ;
mediaTab . contentTab = content ;
2020-12-25 00:19:34 +01:00
}
2020-12-25 18:38:32 +01:00
this . container . append ( navScrollableContainer , this . tabsContainer ) ;
2020-12-25 00:19:34 +01:00
// * construct end
2021-05-13 01:19:41 +02:00
this . searchGroupMedia = new SearchGroup ( false , 'messages' , true ) ;
2020-12-25 18:38:32 +01:00
2020-12-25 00:19:34 +01:00
this . scrollable . onScrolledBottom = ( ) = > {
2022-06-17 18:01:43 +02:00
if ( this . mediaTab . contentTab && this . canLoadMediaTab ( this . mediaTab ) /* && false */ ) {
2022-08-04 08:49:54 +02:00
// this.log('onScrolledBottom will load media');
2020-12-25 00:19:34 +01:00
this . load ( true ) ;
}
} ;
2022-08-04 08:49:54 +02:00
// this.scroll.attachSentinels(undefined, 400);
2021-03-11 23:39:57 +01:00
2021-04-18 13:55:56 +02:00
this . selectTab = horizontalMenu ( this . tabsMenu , this . tabsContainer , ( id , tabContent , animate ) = > {
if ( this . prevTabId === id && ! this . skipScroll ) {
2022-01-08 13:52:14 +01:00
this . scrollable . scrollIntoViewNew ( {
2022-08-04 08:49:54 +02:00
element : this.container ,
2022-04-05 21:13:51 +02:00
position : 'start' ,
startCallback : this.scrollStartCallback
2022-01-08 13:52:14 +01:00
} ) ;
2021-04-18 13:55:56 +02:00
return ;
2020-12-25 00:19:34 +01:00
}
2022-08-04 08:49:54 +02:00
2021-04-07 19:11:08 +02:00
const newMediaTab = this . mediaTabs [ id ] ;
2021-04-18 13:55:56 +02:00
if ( this . onChangeTab ) {
this . onChangeTab ( newMediaTab ) ;
2021-03-11 23:39:57 +01:00
}
2022-08-04 08:49:54 +02:00
2021-04-18 13:55:56 +02:00
const fromMediaTab = this . mediaTab ;
this . mediaTab = newMediaTab ;
2021-03-11 23:39:57 +01:00
2021-04-18 13:55:56 +02:00
if ( this . prevTabId !== - 1 && animate ) {
this . onTransitionStart ( ) ;
2020-12-25 00:19:34 +01:00
}
2021-04-18 13:55:56 +02:00
if ( this . skipScroll ) {
this . skipScroll = false ;
} else {
const offsetTop = this . container . offsetTop ;
let scrollTop = this . scrollable . scrollTop ;
if ( scrollTop < offsetTop ) {
2022-01-08 13:52:14 +01:00
this . scrollable . scrollIntoViewNew ( {
2022-08-04 08:49:54 +02:00
element : this.container ,
2022-04-05 21:13:51 +02:00
position : 'start' ,
startCallback : this.scrollStartCallback
2022-01-08 13:52:14 +01:00
} ) ;
2021-04-18 13:55:56 +02:00
scrollTop = offsetTop ;
}
2022-08-04 08:49:54 +02:00
2021-04-18 13:55:56 +02:00
fromMediaTab . scroll = { scrollTop : scrollTop , scrollHeight : this.scrollable.scrollHeight } ;
2022-08-04 08:49:54 +02:00
2021-04-18 13:55:56 +02:00
if ( newMediaTab . scroll === undefined ) {
const rect = this . container . getBoundingClientRect ( ) ;
const rect2 = this . container . parentElement . getBoundingClientRect ( ) ;
const diff = rect . y - rect2 . y ;
2022-08-04 08:49:54 +02:00
2021-04-18 13:55:56 +02:00
if ( scrollTop > diff ) {
newMediaTab . scroll = { scrollTop : diff , scrollHeight : 0 } ;
}
}
2022-08-04 08:49:54 +02:00
2021-04-18 13:55:56 +02:00
if ( newMediaTab . scroll ) {
const diff = fromMediaTab . scroll . scrollTop - newMediaTab . scroll . scrollTop ;
2022-08-04 08:49:54 +02:00
// console.log('what you gonna do', this.goingHard, diff);
// this.scrollable.scrollTop = scrollTop;
2021-04-18 13:55:56 +02:00
if ( diff /* && diff < 0 */ ) {
/ * i f ( d i f f > - ( f r o m M e d i a T a b . c o n t e n t T a b . s c r o l l H e i g h t + t h i s . n a v . s c r o l l H e i g h t ) ) {
fromMediaTab . contentTab . style . transform = ` translateY( ${ diff } px) ` ;
this . scrollable . scrollTop = scrollTop - diff ;
} else { * /
2022-08-04 08:49:54 +02:00
newMediaTab . contentTab . style . transform = ` translateY( ${ diff } px) ` ;
// }
2021-04-18 13:55:56 +02:00
}
}
2021-04-10 15:52:21 +02:00
}
2022-08-04 08:49:54 +02:00
2021-03-11 23:39:57 +01:00
/ * i f ( t h i s . p r e v T a b I d ! = = - 1 & & n a v . o f f s e t T o p ) {
this . scrollable . scrollTop -= nav . offsetTop ;
} * /
2020-12-25 00:19:34 +01:00
/ * t h i s . l o g ( ' s e t V i r t u a l C o n t a i n e r ' , i d , t h i s . s h a r e d M e d i a S e l e c t e d , t h i s . s h a r e d M e d i a S e l e c t e d . c h i l d E l e m e n t C o u n t ) ;
this . scroll . setVirtualContainer ( this . sharedMediaSelected ) ; * /
2021-04-18 13:55:56 +02:00
if ( this . prevTabId !== - 1 && ! newMediaTab . contentTab . childElementCount ) { // quick brown fix
2022-08-04 08:49:54 +02:00
// this.contentContainer.classList.remove('loaded');
2020-12-25 00:19:34 +01:00
this . load ( true ) ;
}
this . prevTabId = id ;
} , ( ) = > {
this . scrollable . onScroll ( ) ;
2022-08-04 08:49:54 +02:00
// console.log('what y', this.tabSelected.style.transform);
2021-04-07 19:11:08 +02:00
if ( this . mediaTab . scroll !== undefined ) {
2021-04-18 13:55:56 +02:00
this . mediaTab . contentTab . style . transform = '' ;
2021-04-07 19:11:08 +02:00
this . scrollable . scrollTop = this . mediaTab . scroll . scrollTop ;
2021-03-11 23:39:57 +01:00
}
2021-10-21 15:16:43 +02:00
if ( unlockScroll ) {
unlockScroll ( ) ;
unlockScroll = undefined ;
}
2020-12-25 00:19:34 +01:00
this . onTransitionEnd ( ) ;
2022-07-26 07:22:46 +02:00
} , undefined , navScrollable , this . listenerSetter ) ;
2021-09-12 07:12:39 +02:00
attachClickEvent ( this . tabsContainer , ( e ) = > {
if ( this . selection . isSelecting ) {
cancelEvent ( e ) ;
this . selection . toggleByElement ( findUpClassName ( e . target , 'search-super-item' ) ) ;
}
2022-07-26 07:22:46 +02:00
} , { capture : true , passive : false , listenerSetter : this.listenerSetter } ) ;
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
const onMediaClick = async ( className : string , targetClassName : string , inputFilter : MyInputMessagesFilter , e : MouseEvent ) = > {
2021-08-21 13:55:44 +02:00
const target = findUpClassName ( e . target as HTMLDivElement , className ) ;
2021-09-23 15:41:02 +02:00
if ( ! target ) return ;
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
const mid = + target . dataset . mid ;
if ( ! mid ) {
this . log . warn ( 'no messageId by click on target:' , target ) ;
2020-12-25 00:19:34 +01:00
return ;
}
2020-12-25 13:53:20 +01:00
2023-01-12 16:13:22 +01:00
const mediaSpoiler : HTMLElement = target . querySelector ( '.media-spoiler-container' ) ;
if ( mediaSpoiler ) {
onMediaSpoilerClick ( {
event : e ,
mediaSpoiler
} )
return ;
}
2021-10-21 15:16:43 +02:00
const peerId = target . dataset . peerId . toPeerId ( ) ;
2020-12-25 13:53:20 +01:00
2022-06-17 18:01:43 +02:00
const targets = ( Array . from ( this . tabs [ inputFilter ] . querySelectorAll ( '.' + targetClassName ) ) as HTMLElement [ ] ) . map ( ( el ) = > {
2021-08-21 13:55:44 +02:00
const containerEl = findUpClassName ( el , className ) ;
return {
2022-08-04 08:49:54 +02:00
element : el ,
mid : + containerEl . dataset . mid ,
2021-10-21 15:16:43 +02:00
peerId : containerEl.dataset.peerId.toPeerId ( )
2021-08-21 13:55:44 +02:00
} ;
2020-12-25 00:19:34 +01:00
} ) ;
2020-12-25 13:53:20 +01:00
2022-08-04 08:49:54 +02:00
// const ids = Object.keys(this.mediaDivsByIds).map((k) => +k).sort((a, b) => a - b);
2022-06-17 18:01:43 +02:00
const idx = targets . findIndex ( ( item ) = > item . mid === mid && item . peerId === peerId ) ;
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
const message = await this . managers . appMessagesManager . getMessageByPeer ( peerId , mid ) ;
2020-12-25 13:53:20 +01:00
new AppMediaViewer ( )
2021-08-21 13:55:44 +02:00
. setSearchContext ( this . copySearchContext ( inputFilter ) )
2023-03-03 16:47:02 +01:00
. openMedia ( {
message ,
target : targets [ idx ] . element ,
fromRight : 0 ,
reverse : false ,
prevTargets : targets.slice ( 0 , idx ) ,
nextTargets : targets.slice ( idx + 1 )
} ) ;
2021-08-21 13:55:44 +02:00
} ;
2022-07-26 07:22:46 +02:00
attachClickEvent ( this . tabs . inputMessagesFilterPhotoVideo , onMediaClick . bind ( null , 'grid-item' , 'grid-item' , 'inputMessagesFilterPhotoVideo' ) , { listenerSetter : this.listenerSetter } ) ;
attachClickEvent ( this . tabs . inputMessagesFilterDocument , onMediaClick . bind ( null , 'document-with-thumb' , 'media-container' , 'inputMessagesFilterDocument' ) , { listenerSetter : this.listenerSetter } ) ;
2021-09-12 07:12:39 +02:00
2021-09-14 06:36:28 +02:00
/ * a t t a c h C l i c k E v e n t ( t h i s . t a b s . i n p u t M e s s a g e s F i l t e r U r l , ( e ) = > {
2021-09-12 07:12:39 +02:00
const target = e . target as HTMLElement ;
if ( target . tagName === 'A' ) {
return ;
}
try {
const a = findUpClassName ( target , 'row' ) . querySelector ( '.anchor-url:last-child' ) as HTMLAnchorElement ;
a . click ( ) ;
} catch ( err ) { }
2021-09-14 06:36:28 +02:00
} ) ; * /
2020-12-25 13:53:20 +01:00
2021-04-07 19:11:08 +02:00
this . mediaTab = this . mediaTabs [ 0 ] ;
2021-01-18 19:34:41 +01:00
useHeavyAnimationCheck ( ( ) = > {
this . lazyLoadQueue . lock ( ) ;
} , ( ) = > {
this . lazyLoadQueue . unlockAndRefresh ( ) ; // ! maybe not so efficient
2022-07-26 07:22:46 +02:00
} , this . listenerSetter ) ;
2020-12-25 00:19:34 +01:00
}
private onTransitionStart = ( ) = > {
2021-06-02 12:35:30 +02:00
this . container . classList . add ( 'sliding' ) ;
2020-12-25 00:19:34 +01:00
} ;
private onTransitionEnd = ( ) = > {
this . container . classList . remove ( 'sliding' ) ;
} ;
2020-12-25 13:53:20 +01:00
public filterMessagesByType ( messages : any [ ] , type : SearchSuperType ) : MyMessage [ ] {
2022-06-17 18:01:43 +02:00
return filterMessagesByInputFilter ( type , messages , messages . length ) ;
2020-12-25 00:19:34 +01:00
}
2022-01-13 00:54:33 +01:00
private processEmptyFilter ( { message , searchGroup } : ProcessSearchSuperResult ) {
2022-06-24 19:23:12 +02:00
const loadPromises : Promise < any > [ ] = [ ] ;
2023-01-06 20:27:29 +01:00
const dialogElement = appDialogsManager . addDialogNew ( {
2022-08-04 08:49:54 +02:00
peerId : message.peerId ,
container : searchGroup.list ,
2022-11-27 14:09:10 +01:00
avatarSize : 'bigger' ,
2022-06-24 19:23:12 +02:00
loadPromises
2022-01-13 00:54:33 +01:00
} ) ;
2022-06-24 19:23:12 +02:00
const setLastMessagePromise = appDialogsManager . setLastMessageN ( {
dialog : {
_ : 'dialog' ,
peerId : message.peerId
2022-08-04 08:49:54 +02:00
} as any ,
lastMessage : message ,
2023-01-06 20:27:29 +01:00
dialogElement ,
2022-06-24 19:23:12 +02:00
highlightWord : this.searchContext.query
} ) ;
loadPromises . push ( setLastMessagePromise ) ;
2022-11-27 14:09:10 +01:00
return Promise . all ( loadPromises ) . then ( noop ) ;
2022-01-13 00:54:33 +01:00
}
2022-06-17 18:01:43 +02:00
private async processPhotoVideoFilter ( { message , promises , middleware } : ProcessSearchSuperResult ) {
2023-02-27 14:11:37 +01:00
const media = getMediaFromMessage ( message , true ) ;
2022-01-13 00:54:33 +01:00
const div = document . createElement ( 'div' ) ;
div . classList . add ( 'grid-item' ) ;
2022-08-04 08:49:54 +02:00
// this.log(message, photo);
2022-01-13 00:54:33 +01:00
2022-06-17 18:01:43 +02:00
let wrapped : Awaited < ReturnType < typeof wrapPhoto > > ;
2022-04-25 16:54:30 +02:00
const size = choosePhotoSize ( media , 200 , 200 ) ;
2022-01-13 00:54:33 +01:00
if ( media . _ !== 'photo' ) {
2022-06-17 18:01:43 +02:00
wrapped = await ( await wrapVideo ( {
2022-01-13 00:54:33 +01:00
doc : media ,
message ,
container : div ,
boxWidth : 0 ,
boxHeight : 0 ,
lazyLoadQueue : this.lazyLoadQueue ,
middleware ,
onlyPreview : true ,
withoutPreloader : true ,
noPlayButton : true ,
2022-08-28 18:50:04 +02:00
photoSize : size
2022-06-17 18:01:43 +02:00
} ) ) . thumb ;
2022-01-13 00:54:33 +01:00
} else {
2022-06-17 18:01:43 +02:00
wrapped = await wrapPhoto ( {
2022-01-13 00:54:33 +01:00
photo : media ,
message ,
container : div ,
boxWidth : 0 ,
boxHeight : 0 ,
lazyLoadQueue : this.lazyLoadQueue ,
middleware ,
withoutPreloader : true ,
noBlur : true ,
size
} ) ;
}
2023-01-12 16:13:22 +01:00
if ( ( message . media as MessageMedia . messageMediaPhoto ) . pFlags . spoiler ) {
const mediaSpoiler = await wrapMediaSpoiler ( {
animationGroup : 'chat' ,
media ,
middleware ,
width : 140 ,
height : 140 ,
multiply : 0.3
} ) ;
div . append ( mediaSpoiler ) ;
}
[
wrapped . images . thumb ,
wrapped . images . full
] . filter ( Boolean ) . forEach ( ( image ) = > {
2022-01-13 00:54:33 +01:00
image . classList . add ( 'grid-item-media' ) ;
} ) ;
promises . push ( wrapped . loadPromises . thumb ) ;
2022-06-17 18:01:43 +02:00
return { element : div , message } ;
2022-01-13 00:54:33 +01:00
}
2022-06-17 18:01:43 +02:00
private async processDocumentFilter ( { message , inputFilter } : ProcessSearchSuperResult ) {
2023-02-27 14:11:37 +01:00
const document = getMediaFromMessage ( message , true ) as Document . document ;
2022-01-13 00:54:33 +01:00
const showSender = this . showSender || ( [ 'voice' , 'round' ] as MyDocument [ 'type' ] [ ] ) . includes ( document . type ) ;
2022-06-17 18:01:43 +02:00
const div = await wrapDocument ( {
2022-01-13 00:54:33 +01:00
message ,
withTime : ! showSender ,
fontWeight : 400 ,
voiceAsMusic : true ,
showSender ,
searchContext : this.copySearchContext ( inputFilter ) ,
lazyLoadQueue : this.lazyLoadQueue ,
2023-02-03 16:44:58 +01:00
autoDownloadSize : 0 ,
getSize : ( ) = > 320
2022-01-13 00:54:33 +01:00
} ) ;
if ( ( [ 'audio' , 'voice' , 'round' ] as MyDocument [ 'type' ] [ ] ) . includes ( document . type ) ) {
div . classList . add ( 'audio-48' ) ;
}
2022-06-17 18:01:43 +02:00
return { message , element : div } ;
2022-01-13 00:54:33 +01:00
}
2022-06-17 18:01:43 +02:00
private async processUrlFilter ( { message , promises , middleware } : ProcessSearchSuperResult ) {
2023-01-06 20:27:29 +01:00
let webPage = ( message . media as MessageMedia . messageMediaWebPage ) ? . webpage as WebPage . webPage | WebPage . webPageEmpty ;
2022-01-13 00:54:33 +01:00
2023-01-06 20:27:29 +01:00
if ( ! webPage ) {
2022-01-13 00:54:33 +01:00
const entity = message . totalEntities ? message . totalEntities . find ( ( e : any ) = > e . _ === 'messageEntityUrl' || e . _ === 'messageEntityTextUrl' ) : null ;
let url : string , display_url : string , sliced : string ;
if ( ! entity ) {
2022-04-25 16:54:30 +02:00
const match = matchUrl ( message . message ) ;
2022-01-13 00:54:33 +01:00
if ( ! match ) {
return ;
}
url = match [ 0 ] ;
} else {
sliced = message . message . slice ( entity . offset , entity . offset + entity . length ) ;
}
if ( entity ? . _ === 'messageEntityTextUrl' ) {
url = entity . url ;
2022-08-04 08:49:54 +02:00
// display_url = sliced;
2022-01-13 00:54:33 +01:00
} else {
url = url || sliced ;
}
display_url = url ;
const same = message . message === url ;
if ( ! url . match ( /^(ftp|http|https):\/\// ) ) {
display_url = 'https://' + url ;
url = url . includes ( '@' ) ? url : 'https://' + url ;
}
display_url = new URL ( display_url ) . hostname ;
2023-01-06 20:27:29 +01:00
webPage = {
2022-01-13 00:54:33 +01:00
_ : 'webPage' ,
url ,
display_url ,
id : '' ,
hash : 0
} ;
if ( ! same ) {
2023-01-06 20:27:29 +01:00
webPage . description = message . message ;
2022-01-13 00:54:33 +01:00
}
}
2023-01-06 20:27:29 +01:00
if ( webPage . _ === 'webPageEmpty' ) {
return ;
}
2022-08-04 08:49:54 +02:00
const previewDiv = document . createElement ( 'div' ) ;
2022-11-27 14:09:10 +01:00
previewDiv . classList . add ( 'preview' ) ;
2022-08-04 08:49:54 +02:00
// this.log('wrapping webpage', webpage);
2023-01-06 20:27:29 +01:00
if ( webPage . photo ) {
2022-01-13 00:54:33 +01:00
const res = wrapPhoto ( {
container : previewDiv ,
message : null ,
2023-01-06 20:27:29 +01:00
photo : webPage.photo as Photo . photo ,
2022-01-13 00:54:33 +01:00
boxWidth : 0 ,
boxHeight : 0 ,
withoutPreloader : true ,
lazyLoadQueue : this.lazyLoadQueue ,
middleware ,
2023-01-06 20:27:29 +01:00
size : choosePhotoSize ( webPage . photo as Photo . photo , 60 , 60 , false ) ,
2022-01-13 00:54:33 +01:00
loadPromises : promises ,
noBlur : true
} ) ;
} else {
previewDiv . classList . add ( 'empty' ) ;
2023-01-06 20:27:29 +01:00
setInnerHTML ( previewDiv , wrapAbbreviation ( webPage . title || webPage . display_url || webPage . description || webPage . url , true ) ) ;
2022-01-13 00:54:33 +01:00
}
2022-08-04 08:49:54 +02:00
2023-01-06 20:27:29 +01:00
const title = wrapWebPageTitle ( webPage ) ;
2022-01-13 00:54:33 +01:00
2023-01-06 20:27:29 +01:00
const subtitleFragment = wrapWebPageDescription ( webPage ) ;
const aFragment = htmlToDocumentFragment ( wrapRichText ( webPage . url || '' ) ) ;
2022-01-13 00:54:33 +01:00
const a = aFragment . firstElementChild ;
if ( a instanceof HTMLAnchorElement ) {
try { // can have 'URIError: URI malformed'
a . innerText = decodeURIComponent ( a . href ) ;
} catch ( err ) {
}
}
if ( subtitleFragment . firstChild ) {
subtitleFragment . append ( '\n' ) ;
}
subtitleFragment . append ( a ) ;
if ( this . showSender ) {
2022-06-17 18:01:43 +02:00
subtitleFragment . append ( '\n' , await wrapSenderToPeer ( message ) ) ;
2022-01-13 00:54:33 +01:00
}
2022-08-04 08:49:54 +02:00
2022-04-19 21:33:56 +02:00
if ( ! title . textContent ) {
2022-08-04 08:49:54 +02:00
// title = new URL(webpage.url).hostname;
2023-01-06 20:27:29 +01:00
title . append ( wrapPlainText ( webPage . display_url . split ( '/' , 1 ) [ 0 ] ) ) ;
2022-01-13 00:54:33 +01:00
}
const row = new Row ( {
title ,
2022-04-25 16:54:30 +02:00
titleRight : wrapSentTime ( message ) ,
2022-01-13 00:54:33 +01:00
subtitle : subtitleFragment ,
havePadding : true ,
clickable : true ,
noRipple : true
} ) ;
2022-11-27 14:09:10 +01:00
row . applyMediaElement ( previewDiv , 'big' ) ;
2022-08-04 08:49:54 +02:00
2022-01-13 00:54:33 +01:00
if ( row . container . innerText . trim ( ) . length ) {
2022-06-17 18:01:43 +02:00
return { message , element : row.container } ;
2022-01-13 00:54:33 +01:00
}
}
2022-08-04 08:49:54 +02:00
2021-04-10 21:39:36 +02:00
public async performSearchResult ( messages : any [ ] , mediaTab : SearchSuperMediaTab , append = true ) {
2020-12-25 13:53:20 +01:00
const elemsToAppend : { element : HTMLElement , message : any } [ ] = [ ] ;
2021-04-10 21:39:36 +02:00
const sharedMediaDiv : HTMLElement = mediaTab . contentTab ;
2020-12-25 00:19:34 +01:00
const promises : Promise < any > [ ] = [ ] ;
2021-04-07 19:11:08 +02:00
const middleware = this . middleware . get ( ) ;
2021-04-10 21:39:36 +02:00
let inputFilter = mediaTab . inputFilter ;
2021-01-18 19:34:41 +01:00
await getHeavyAnimationPromise ( ) ;
2022-08-04 08:49:54 +02:00
2020-12-25 18:38:32 +01:00
let searchGroup : SearchGroup ;
2021-04-10 21:39:36 +02:00
if ( inputFilter === 'inputMessagesFilterPhotoVideo' && ! ! this . searchContext . query . trim ( ) ) {
inputFilter = 'inputMessagesFilterEmpty' ;
2020-12-25 18:38:32 +01:00
searchGroup = this . searchGroupMedia ;
sharedMediaDiv . append ( searchGroup . container ) ;
2021-04-10 21:39:36 +02:00
} else if ( inputFilter === 'inputMessagesFilterEmpty' ) {
2020-12-25 18:38:32 +01:00
searchGroup = this . searchGroups . messages ;
}
2022-01-13 00:54:33 +01:00
const options : ProcessSearchSuperResult = {
elemsToAppend ,
inputFilter ,
message : undefined ,
middleware ,
promises ,
searchGroup
} ;
let processCallback : ( options : ProcessSearchSuperResult ) = > any ;
2020-12-25 00:19:34 +01:00
// https://core.telegram.org/type/MessagesFilter
2021-04-10 21:39:36 +02:00
switch ( inputFilter ) {
2020-12-25 13:53:20 +01:00
case 'inputMessagesFilterEmpty' : {
2022-01-13 00:54:33 +01:00
processCallback = this . processEmptyFilter ;
2020-12-25 13:53:20 +01:00
break ;
}
2020-12-25 00:19:34 +01:00
case 'inputMessagesFilterPhotoVideo' : {
2022-01-13 00:54:33 +01:00
processCallback = this . processPhotoVideoFilter ;
2020-12-25 00:19:34 +01:00
break ;
}
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
case 'inputMessagesFilterVoice' :
2021-09-26 18:03:45 +02:00
case 'inputMessagesFilterRoundVoice' :
2020-12-25 00:19:34 +01:00
case 'inputMessagesFilterMusic' :
case 'inputMessagesFilterDocument' : {
2022-01-13 00:54:33 +01:00
processCallback = this . processDocumentFilter ;
2020-12-25 00:19:34 +01:00
break ;
}
2022-08-04 08:49:54 +02:00
2020-12-25 00:19:34 +01:00
case 'inputMessagesFilterUrl' : {
2022-01-13 00:54:33 +01:00
processCallback = this . processUrlFilter ;
2020-12-25 00:19:34 +01:00
break ;
}
default :
2022-08-04 08:49:54 +02:00
// this.log.warn('death is my friend', messages);
2020-12-25 00:19:34 +01:00
break ;
}
2022-01-13 00:54:33 +01:00
if ( processCallback ) {
processCallback = processCallback . bind ( this ) ;
2022-06-17 18:01:43 +02:00
type K = { element : HTMLElement , message : Message.message | Message . messageService } ;
const results : ( Promise < K > | K ) [ ] = messages . map ( async ( message ) = > {
2022-01-13 00:54:33 +01:00
try {
options . message = message ;
2022-06-17 18:01:43 +02:00
return await processCallback ( options ) ;
2022-01-13 00:54:33 +01:00
} catch ( err ) {
this . log . error ( 'error rendering filter' , inputFilter , options , message , err ) ;
}
2022-06-17 18:01:43 +02:00
} ) ;
const awaited = ( await Promise . all ( results ) ) . filter ( Boolean ) ;
2023-01-06 20:27:29 +01:00
elemsToAppend . push ( . . . awaited ) ;
2022-01-13 00:54:33 +01:00
}
2022-08-04 08:49:54 +02:00
2022-01-13 00:54:33 +01:00
if ( searchGroup && searchGroup . list . childElementCount ) {
searchGroup . setActive ( ) ;
}
2020-12-25 00:19:34 +01:00
if ( this . loadMutex ) {
promises . push ( this . loadMutex ) ;
}
if ( promises . length ) {
await Promise . all ( promises ) ;
2020-12-25 13:53:20 +01:00
if ( ! middleware ( ) ) {
2022-08-04 08:49:54 +02:00
// this.log.warn('peer changed');
2020-12-25 00:19:34 +01:00
return ;
}
}
2022-08-04 08:49:54 +02:00
2020-12-25 00:19:34 +01:00
if ( elemsToAppend . length ) {
2020-12-25 13:53:20 +01:00
const method = append ? 'append' : 'prepend' ;
2022-06-17 18:01:43 +02:00
elemsToAppend . forEach ( ( details ) = > {
2020-12-25 13:53:20 +01:00
const { element , message } = details ;
2022-11-27 14:09:10 +01:00
if ( ! message ) {
debugger ;
}
2021-04-10 21:39:36 +02:00
const monthContainer = this . getMonthContainerByTimestamp ( this . groupByMonth ? message.date : 0 , inputFilter ) ;
2020-12-25 13:53:20 +01:00
element . classList . add ( 'search-super-item' ) ;
element . dataset . mid = '' + message . mid ;
element . dataset . peerId = '' + message . peerId ;
monthContainer . items [ method ] ( element ) ;
2021-09-12 07:12:39 +02:00
2022-07-26 07:22:46 +02:00
if ( this . selection ? . isSelecting ) {
2021-09-12 07:12:39 +02:00
this . selection . toggleElementCheckbox ( element , true ) ;
}
2020-12-25 13:53:20 +01:00
} ) ;
2020-12-25 00:19:34 +01:00
}
2022-08-04 08:49:54 +02:00
// if(type !== 'inputMessagesFilterEmpty') {
2023-01-06 20:27:29 +01:00
this . afterPerforming ( inputFilter === 'inputMessagesFilterEmpty' ? 1 : elemsToAppend.length , sharedMediaDiv ) ;
2022-08-04 08:49:54 +02:00
// }
2020-12-25 13:53:20 +01:00
}
2021-04-07 19:11:08 +02:00
private afterPerforming ( length : number , contentTab : HTMLElement ) {
if ( contentTab ) {
const parent = contentTab . parentElement ;
2022-06-17 18:01:43 +02:00
Array . from ( parent . children ) . slice ( 1 ) . forEach ( ( child ) = > {
2020-12-25 00:19:34 +01:00
child . remove ( ) ;
} ) ;
2022-08-04 08:49:54 +02:00
// this.contentContainer.classList.add('loaded');
2020-12-25 00:19:34 +01:00
2021-04-07 19:11:08 +02:00
if ( ! length && ! contentTab . childElementCount ) {
2020-12-25 00:19:34 +01:00
const div = document . createElement ( 'div' ) ;
div . innerText = 'Nothing interesting here yet...' ;
div . classList . add ( 'position-center' , 'text-center' , 'content-empty' , 'no-select' ) ;
parent . append ( div ) ;
}
}
}
2020-12-25 13:53:20 +01:00
private loadChats() {
2021-10-21 15:16:43 +02:00
const renderedPeerIds : Set < PeerId > = new Set ( ) ;
2021-04-07 19:11:08 +02:00
const middleware = this . middleware . get ( ) ;
2020-12-25 13:53:20 +01:00
2022-08-04 08:49:54 +02:00
for ( const i in this . searchGroups ) {
2020-12-25 13:53:20 +01:00
const group = this . searchGroups [ i as SearchGroupType ] ;
this . tabs . inputMessagesFilterEmpty . append ( group . container ) ;
group . clear ( ) ;
}
const query = this . searchContext . query ;
if ( query ) {
2021-10-21 15:16:43 +02:00
const setResults = ( results : PeerId [ ] , group : SearchGroup , showMembersCount = false ) = > {
2022-06-17 18:01:43 +02:00
results . map ( ( peerId ) = > {
2020-12-25 13:53:20 +01:00
if ( renderedPeerIds . has ( peerId ) ) {
return ;
}
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
renderedPeerIds . add ( peerId ) ;
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
const { dom } = appDialogsManager . addDialogNew ( {
2022-08-04 08:49:54 +02:00
peerId : peerId ,
container : group.list ,
2022-11-27 14:09:10 +01:00
avatarSize : 'abitbigger' ,
2020-12-25 13:53:20 +01:00
autonomous : group.autonomous
} ) ;
2022-06-17 18:01:43 +02:00
return { dom , peerId } ;
2022-11-27 14:09:10 +01:00
} ) . filter ( Boolean ) . forEach ( async ( { dom , peerId } ) = > {
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 ( showMembersCount && ( ( peer as Chat . channel ) . participants_count || ( peer as any ) . participants ) ) {
2021-05-18 16:17:54 +02:00
const regExp = new RegExp ( ` ( ${ escapeRegExp ( query ) } | ${ escapeRegExp ( cleanSearchText ( query ) ) } ) ` , 'gi' ) ;
2020-12-25 13:53:20 +01:00
dom . titleSpan . innerHTML = dom . titleSpan . innerHTML . replace ( regExp , '<i>$1</i>' ) ;
2022-06-17 18:01:43 +02:00
dom . lastMessageSpan . append ( await getChatMembersString ( peerId . toChatId ( ) ) ) ;
2020-12-25 13:53:20 +01:00
} else if ( peerId === rootScope . myId ) {
2021-03-28 20:37:11 +02:00
dom . lastMessageSpan . append ( i18n ( 'Presence.YourChat' ) ) ;
2020-12-25 13:53:20 +01:00
} else {
2022-06-17 18:01:43 +02:00
let username = await this . managers . appPeersManager . getPeerUsername ( peerId ) ;
2020-12-25 13:53:20 +01:00
if ( ! username ) {
2022-06-17 18:01:43 +02:00
const user = await this . managers . appUsersManager . getUser ( peerId ) ;
2020-12-25 13:53:20 +01:00
if ( user && user . phone ) {
username = '+' + formatPhoneNumber ( user . phone ) . formatted ;
}
} else {
username = '@' + username ;
}
2022-08-04 08:49:54 +02:00
2022-11-27 14:09:10 +01:00
dom . lastMessageSpan . textContent = username ;
2020-12-25 13:53:20 +01:00
}
} ) ;
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
group . toggle ( ) ;
} ;
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
const onLoad = < T > ( arg : T ) = > {
if ( ! middleware ( ) ) {
return ;
}
2022-08-04 08:49:54 +02:00
// this.loadedContacts = true;
2020-12-25 13:53:20 +01:00
return arg ;
} ;
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
return Promise . all ( [
2022-11-27 14:09:10 +01:00
this . managers . appUsersManager . getContactsPeerIds ( query , true , undefined , 10 )
2020-12-25 13:53:20 +01:00
. then ( onLoad )
. then ( ( contacts ) = > {
if ( contacts ) {
setResults ( contacts , this . searchGroups . contacts , true ) ;
}
} ) ,
2022-08-04 08:49:54 +02:00
2022-04-25 16:54:30 +02:00
this . managers . appUsersManager . searchContacts ( query , 20 )
2020-12-25 13:53:20 +01:00
. then ( onLoad )
. then ( ( contacts ) = > {
if ( contacts ) {
setResults ( contacts . my_results , this . searchGroups . contacts , true ) ;
2020-12-25 18:38:32 +01:00
setResults ( contacts . results /* .concat(contacts.results, contacts.results, contacts.results) */ , this . searchGroups . globalContacts ) ;
2021-12-20 09:34:34 +01:00
this . searchGroups . globalContacts . container . classList . add ( 'is-short' ) ;
if ( this . searchGroups . globalContacts . nameEl . lastElementChild !== this . searchGroups . globalContacts . nameEl . firstElementChild ) {
2020-12-25 18:38:32 +01:00
this . searchGroups . globalContacts . nameEl . lastElementChild . remove ( ) ;
}
2022-08-04 08:49:54 +02:00
2020-12-25 18:38:32 +01:00
if ( this . searchGroups . globalContacts . list . childElementCount > 3 ) {
const showMore = document . createElement ( 'div' ) ;
showMore . classList . add ( 'search-group__show-more' ) ;
2021-12-20 09:34:34 +01:00
const intlElement = new I18n . IntlElement ( {
key : 'Separator.ShowMore'
} ) ;
showMore . append ( intlElement . element ) ;
2020-12-25 18:38:32 +01:00
this . searchGroups . globalContacts . nameEl . append ( showMore ) ;
2022-02-11 15:36:00 +01:00
attachClickEvent ( showMore , ( ) = > {
2020-12-25 18:38:32 +01:00
const isShort = this . searchGroups . globalContacts . container . classList . toggle ( 'is-short' ) ;
2021-12-20 09:34:34 +01:00
intlElement . key = isShort ? 'Separator.ShowMore' : 'Separator.ShowLess' ;
intlElement . update ( ) ;
2020-12-25 18:38:32 +01:00
} ) ;
}
2020-12-25 13:53:20 +01:00
}
} ) ,
2022-08-04 08:49:54 +02:00
2023-01-06 20:27:29 +01:00
this . managers . dialogsStorage . getDialogs ( { query , offsetIndex : 0 , limit : 20 , filterId : 0 } )
2020-12-25 13:53:20 +01:00
. then ( onLoad )
2022-06-17 18:01:43 +02:00
. then ( ( value ) = > {
2020-12-25 13:53:20 +01:00
if ( value ) {
2022-06-17 18:01:43 +02:00
setResults ( value . dialogs . map ( ( d ) = > d . peerId ) , this . searchGroups . contacts , true ) ;
2020-12-25 13:53:20 +01:00
}
} )
] ) ;
2020-12-25 19:20:43 +01:00
} else if ( ! this . searchContext . peerId && ! this . searchContext . minDate ) {
2020-12-25 13:53:20 +01:00
const renderRecentSearch = ( setActive = true ) = > {
2022-06-17 18:01:43 +02:00
return apiManagerProxy . getState ( ) . then ( ( state ) = > {
2020-12-25 13:53:20 +01:00
if ( ! middleware ( ) ) {
return ;
}
2022-08-04 08:49:54 +02:00
2023-01-06 20:27:29 +01:00
this . searchGroups . recent . list . replaceChildren ( ) ;
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
state . recentSearch . slice ( 0 , 20 ) . forEach ( async ( peerId ) = > {
2022-08-04 08:49:54 +02:00
const { dom } = appDialogsManager . addDialogNew ( {
2022-06-17 18:01:43 +02:00
peerId : peerId ,
2020-12-25 13:53:20 +01:00
container : this.searchGroups.recent.list ,
meAsSaved : true ,
2022-11-27 14:09:10 +01:00
avatarSize : 'abitbigger' ,
2021-01-26 01:40:53 +01:00
autonomous : true
2020-12-25 13:53:20 +01:00
} ) ;
2022-08-04 08:49:54 +02:00
dom . lastMessageSpan . append ( await ( peerId . isUser ( ) ?
getUserStatusString ( await this . managers . appUsersManager . getUser ( peerId . toUserId ( ) ) ) :
2022-06-17 18:01:43 +02:00
getChatMembersString ( peerId . toChatId ( ) ) ) ) ;
2020-12-25 13:53:20 +01:00
} ) ;
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
if ( ! state . recentSearch . length ) {
this . searchGroups . recent . clear ( ) ;
} else if ( setActive ) {
this . searchGroups . recent . setActive ( ) ;
}
} ) ;
} ;
return Promise . all ( [
2022-06-17 18:01:43 +02:00
this . managers . appUsersManager . getTopPeers ( 'correspondents' ) . then ( ( peers ) = > {
2020-12-25 13:53:20 +01:00
if ( ! middleware ( ) ) return ;
2022-06-17 18:01:43 +02:00
const idx = peers . findIndex ( ( peer ) = > peer . id === rootScope . myId ) ;
2021-06-20 18:21:28 +02:00
if ( idx !== - 1 ) {
peers = peers . slice ( ) ;
peers . splice ( idx , 1 ) ;
}
2022-11-27 14:09:10 +01:00
2023-01-06 20:27:29 +01:00
peers . forEach ( ( peer ) = > {
const { dom } = appDialogsManager . addDialogNew ( {
peerId : peer.id ,
container : this.searchGroups.people.list ,
onlyFirstName : true ,
avatarSize : 'bigger' ,
autonomous : false ,
noIcons : this.searchGroups.people.noIcons
2020-12-25 13:53:20 +01:00
} ) ;
2022-08-04 08:49:54 +02:00
2023-01-06 20:27:29 +01:00
dom . subtitleEl . remove ( ) ;
} ) ;
this . searchGroups . people . toggle ( ) ;
2020-12-25 13:53:20 +01:00
} ) ,
renderRecentSearch ( )
] ) ;
2020-12-25 19:20:43 +01:00
} else return Promise . resolve ( ) ;
2020-12-25 13:53:20 +01:00
}
2021-01-20 11:01:18 +01:00
2022-06-17 18:01:43 +02:00
private async loadMembers ( mediaTab : SearchSuperMediaTab ) {
2023-03-02 16:51:37 +01:00
const chatId = mediaTab . type === 'members' ? this . searchContext . peerId . toChatId ( ) : undefined ;
const userId = mediaTab . type === 'groups' ? this . searchContext . peerId . toUserId ( ) : undefined ;
2021-04-09 18:44:43 +02:00
const middleware = this . middleware . get ( ) ;
let promise : Promise < void > ;
2023-03-02 16:51:37 +01:00
const renderParticipants = async ( participants : ( ChatParticipant | ChannelParticipant | Chat ) [ ] ) = > {
2021-04-09 18:44:43 +02:00
if ( this . loadMutex ) {
await this . loadMutex ;
if ( ! middleware ( ) ) {
return ;
}
}
2022-08-04 08:49:54 +02:00
2023-02-03 10:14:08 +01:00
let membersList = this . membersList ;
if ( ! membersList ) {
2023-03-02 16:51:37 +01:00
membersList = this . membersList = new SortedUserList ( {
2022-08-04 08:49:54 +02:00
lazyLoadQueue : this.lazyLoadQueue ,
2022-04-25 16:54:30 +02:00
rippleEnabled : false ,
2022-06-17 18:01:43 +02:00
managers : this.managers
2022-04-25 16:54:30 +02:00
} ) ;
2023-02-03 10:14:08 +01:00
attachClickEvent ( membersList . list , ( e ) = > {
2022-06-17 18:01:43 +02:00
const li = findUpTag ( e . target , DIALOG_LIST_ELEMENT_TAG ) ;
2021-04-14 10:30:14 +02:00
if ( ! li ) {
return ;
}
2021-10-21 15:16:43 +02:00
const peerId = li . dataset . peerId . toPeerId ( ) ;
2021-04-14 10:30:14 +02:00
let promise : Promise < any > = Promise . resolve ( ) ;
if ( mediaSizes . isMobile ) {
promise = appSidebarRight . toggleSidebar ( false ) ;
}
2022-08-04 08:49:54 +02:00
2021-04-14 10:30:14 +02:00
promise . then ( ( ) = > {
2022-01-13 00:54:33 +01:00
appImManager . setInnerPeer ( { peerId } ) ;
2021-04-14 10:30:14 +02:00
} ) ;
} ) ;
2023-02-03 10:14:08 +01:00
mediaTab . contentTab . append ( membersList . list ) ;
2021-04-09 18:44:43 +02:00
this . afterPerforming ( 1 , mediaTab . contentTab ) ;
}
2023-03-10 10:08:06 +01:00
const peerIds : { peerId : PeerId , rank : ReturnType < typeof getParticipantRank > } [ ] = participants . map ( ( participant ) = > {
2023-03-02 16:51:37 +01:00
const peerId = userId ? ( participant as Chat . chat ) . id . toPeerId ( true ) : getParticipantPeerId ( participant as ChannelParticipant ) ;
if ( chatId ? peerId . isAnyChat ( ) : peerId . isUser ( ) ) {
return ;
2021-05-03 22:02:53 +02:00
}
2023-03-08 19:48:55 +01:00
return {
peerId ,
2023-03-10 10:08:06 +01:00
rank : getParticipantRank ( participant as ChannelParticipant ) as any
2023-03-08 19:48:55 +01:00
} ;
2023-03-02 16:51:37 +01:00
} ) . filter ( Boolean ) ;
2023-03-08 19:48:55 +01:00
const filtered = await filterAsync ( peerIds , async ( { peerId } ) = > {
2023-03-02 16:51:37 +01:00
const peer : User | Chat = await this . managers . appPeersManager . getPeer ( peerId ) ;
2023-02-03 10:14:08 +01:00
if ( ! middleware ( ) ) {
2023-03-02 16:51:37 +01:00
return false ;
2023-02-03 10:14:08 +01:00
}
2023-03-02 16:51:37 +01:00
if ( ! peer || ( peer as User . user ) . pFlags . deleted ) {
return false ;
2021-04-11 01:14:57 +02:00
}
2021-04-09 18:44:43 +02:00
2023-03-02 16:51:37 +01:00
return true ;
} ) ;
2023-03-08 19:48:55 +01:00
for ( const { peerId , rank } of filtered ) {
if ( rank ) {
membersList . ranks . set ( peerId , rank ) ;
}
2023-02-03 10:14:08 +01:00
membersList . add ( peerId ) ;
2022-06-17 18:01:43 +02:00
}
2021-04-09 18:44:43 +02:00
} ;
2023-03-02 16:51:37 +01:00
if ( userId ) {
const LOAD_COUNT = ! this . membersList ? 50 : 200 ;
promise = this . managers . appUsersManager . getCommonChats ( userId , LOAD_COUNT , this . nextRates [ mediaTab . inputFilter ] ) . then ( ( messagesChats ) = > {
if ( ! middleware ( ) ) {
return ;
}
// const list = mediaTab.contentTab.firstElementChild as HTMLUListElement;
const lastChat = messagesChats . chats [ messagesChats . chats . length - 1 ] ;
this . nextRates [ mediaTab . inputFilter ] = lastChat ? . id as number ;
if ( messagesChats . chats . length < LOAD_COUNT ) {
this . loaded [ mediaTab . inputFilter ] = true ;
}
return renderParticipants ( messagesChats . chats ) ;
} ) ;
} else if ( await this . managers . appChatsManager . isChannel ( chatId ) ) {
2021-04-11 01:14:57 +02:00
const LOAD_COUNT = ! this . membersList ? 50 : 200 ;
2023-03-02 16:51:37 +01:00
promise = this . managers . appProfileManager . getChannelParticipants ( chatId , undefined , LOAD_COUNT , this . nextRates [ mediaTab . inputFilter ] ) . then ( ( participants ) = > {
2021-04-09 18:44:43 +02:00
if ( ! middleware ( ) ) {
return ;
}
2022-08-04 08:49:54 +02:00
const list = mediaTab . contentTab . firstElementChild as HTMLUListElement ;
2021-04-09 18:44:43 +02:00
this . nextRates [ mediaTab . inputFilter ] = ( list ? list.childElementCount : 0 ) + participants . participants . length ;
if ( participants . participants . length < LOAD_COUNT ) {
this . loaded [ mediaTab . inputFilter ] = true ;
}
return renderParticipants ( participants . participants ) ;
} ) ;
} else {
2023-03-02 16:51:37 +01:00
promise = this . managers . appProfileManager . getChatFull ( chatId ) . then ( ( chatFull ) = > {
2021-04-09 18:44:43 +02:00
if ( ! middleware ( ) ) {
return ;
}
2022-08-04 08:49:54 +02:00
// console.log('anymore', chatFull);
2021-04-09 18:44:43 +02:00
this . loaded [ mediaTab . inputFilter ] = true ;
2022-02-08 20:18:01 +01:00
const participants = ( chatFull as ChatFull . chatFull ) . participants ;
2021-04-16 05:51:47 +02:00
if ( participants . _ === 'chatParticipantsForbidden' ) {
return ;
}
2022-08-04 08:49:54 +02:00
2021-04-16 05:51:47 +02:00
return renderParticipants ( participants . participants ) ;
2021-04-09 18:44:43 +02:00
} ) ;
}
2022-08-04 08:49:54 +02:00
return this . loadPromises [ mediaTab . inputFilter ] = promise . finally ( ( ) = > {
2021-04-09 18:44:43 +02:00
if ( ! middleware ( ) ) {
return ;
}
this . loadPromises [ mediaTab . inputFilter ] = null ;
} ) ;
}
2021-04-07 19:11:08 +02:00
private loadType ( mediaTab : SearchSuperMediaTab , justLoad : boolean , loadCount : number , middleware : ( ) = > boolean ) {
const type = mediaTab . inputFilter ;
2020-12-25 00:19:34 +01:00
2021-04-07 19:11:08 +02:00
if ( this . loadPromises [ type ] ) {
return this . loadPromises [ type ] ;
}
2020-12-25 00:19:34 +01:00
2023-03-02 16:51:37 +01:00
if ( mediaTab . type === 'members' || mediaTab . type === 'groups' ) {
2021-04-09 18:44:43 +02:00
return this . loadMembers ( mediaTab ) ;
}
2023-01-06 20:27:29 +01:00
const history = this . historyStorage [ type ] ? ? = [ ] ;
2020-12-25 00:19:34 +01:00
2021-04-07 19:11:08 +02:00
if ( type === 'inputMessagesFilterEmpty' && ! history . length ) {
if ( ! this . loadedChats ) {
this . loadChats ( ) ;
this . loadedChats = true ;
}
2020-12-25 13:53:20 +01:00
2021-04-07 19:11:08 +02:00
if ( ! this . searchContext . query . trim ( ) && ! this . searchContext . peerId && ! this . searchContext . minDate ) {
this . loaded [ type ] = true ;
return Promise . resolve ( ) ;
}
}
2020-12-25 13:53:20 +01:00
2022-06-17 18:01:43 +02:00
const promise = this . loadPromises [ type ] = Promise . resolve ( ) . then ( async ( ) = > {
// render from cache
if ( history . length && this . usedFromHistory [ type ] < history . length && ! justLoad ) {
2022-08-04 08:49:54 +02:00
const messages : any [ ] = [ ] ;
2022-06-17 18:01:43 +02:00
let used = Math . max ( 0 , this . usedFromHistory [ type ] ) ;
let slicedLength = 0 ;
2020-12-25 00:19:34 +01:00
2022-06-17 18:01:43 +02:00
do {
2022-08-04 08:49:54 +02:00
const ids = history . slice ( used , used + loadCount ) ;
2022-06-17 18:01:43 +02:00
used += ids . length ;
slicedLength += ids . length ;
2020-12-25 13:53:20 +01:00
2022-06-17 18:01:43 +02:00
const notFilteredMessages = await Promise . all ( ids . map ( ( m ) = > this . managers . appMessagesManager . getMessageByPeer ( m . peerId , m . mid ) ) ) ;
2020-12-25 13:53:20 +01:00
2022-06-17 18:01:43 +02:00
messages . push ( . . . this . filterMessagesByType ( notFilteredMessages , type ) ) ;
} while ( slicedLength < loadCount && used < history . length ) ;
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
// если перебор
/ * i f ( s l i c e d L e n g t h > l o a d C o u n t ) {
let diff = messages . length - loadCount ;
messages = messages . slice ( 0 , messages . length - diff ) ;
used -= diff ;
} * /
this . usedFromHistory [ type ] = used ;
2022-08-04 08:49:54 +02:00
// if(messages.length) {
return this . performSearchResult ( messages , mediaTab ) . finally ( ( ) = > {
setTimeout ( ( ) = > {
this . scrollable . checkForTriggers ( ) ;
} , 0 ) ;
} ) ;
// }
2022-06-17 18:01:43 +02:00
}
2022-08-04 08:49:54 +02:00
const maxId = history . length ? history [ history . length - 1 ] . mid : 0 ;
2022-06-17 18:01:43 +02:00
const value = await this . managers . appMessagesManager . getSearch ( {
. . . this . searchContext ,
inputFilter : { _ : type } ,
2022-08-04 08:49:54 +02:00
maxId ,
2022-06-17 18:01:43 +02:00
limit : loadCount ,
nextRate : this.nextRates [ type ] ? ? = 0
} ) ;
2020-12-25 00:19:34 +01:00
2022-06-17 18:01:43 +02:00
history . push ( . . . value . history . map ( ( m ) = > ( { mid : m.mid , peerId : m.peerId } ) ) ) ;
2020-12-25 00:19:34 +01:00
2021-04-07 19:11:08 +02:00
if ( ! middleware ( ) ) {
2022-08-04 08:49:54 +02:00
// this.log.warn('peer changed');
2021-04-07 19:11:08 +02:00
return ;
}
// ! Фикс случая, когда не загружаются документы при открытой панели разработчиков (происходит из-за того, что не совпадают критерии отбора документов в getSearch)
2021-09-26 18:03:45 +02:00
if ( value . history . length < loadCount || ( this . searchContext . folderId !== undefined && ! value . next_rate ) || value . history . length === value . count ) {
2022-08-04 08:49:54 +02:00
// if((value.count || history.length === value.count) && history.length >= value.count) {
// this.log(logStr + 'loaded all media', value, loadCount);
2021-04-07 19:11:08 +02:00
this . loaded [ type ] = true ;
}
2020-12-25 00:19:34 +01:00
2021-04-07 19:11:08 +02:00
this . nextRates [ type ] = value . next_rate ;
if ( justLoad ) {
2022-06-17 18:01:43 +02:00
return ;
2020-12-25 00:19:34 +01:00
}
2021-04-07 19:11:08 +02:00
this . usedFromHistory [ type ] = history . length ;
if ( ! this . loaded [ type ] ) {
2022-06-17 18:01:43 +02:00
promise . then ( ( ) = > {
2021-04-07 19:11:08 +02:00
setTimeout ( ( ) = > {
if ( ! middleware ( ) ) return ;
2022-08-04 08:49:54 +02:00
// this.log('will preload more');
2021-04-07 19:11:08 +02:00
if ( this . mediaTab === mediaTab ) {
const promise = this . load ( true , true ) ;
if ( promise ) {
promise . then ( ( ) = > {
if ( ! middleware ( ) ) return ;
2022-08-04 08:49:54 +02:00
// this.log('preloaded more');
2021-04-07 19:11:08 +02:00
setTimeout ( ( ) = > {
this . scrollable . checkForTriggers ( ) ;
} , 0 ) ;
} ) ;
}
}
} , 0 ) ;
} ) ;
}
2020-12-25 00:19:34 +01:00
2022-08-04 08:49:54 +02:00
// if(value.history.length) {
return this . performSearchResult ( this . filterMessagesByType ( value . history , type ) , mediaTab ) ;
// }
2022-06-17 18:01:43 +02:00
} ) . catch ( ( err ) = > {
2021-04-07 19:11:08 +02:00
this . log . error ( 'load error:' , err ) ;
} ) . finally ( ( ) = > {
this . loadPromises [ type ] = null ;
} ) ;
2022-06-17 18:01:43 +02:00
return promise ;
2021-04-07 19:11:08 +02:00
}
2020-12-25 00:19:34 +01:00
2022-06-17 18:01:43 +02:00
private canLoadMediaTab ( mediaTab : SearchSuperMediaTab ) {
const inputFilter = mediaTab . inputFilter ;
return ! this . loaded [ inputFilter ] || ( this . historyStorage [ inputFilter ] && this . usedFromHistory [ inputFilter ] < this . historyStorage [ inputFilter ] . length ) ;
}
private async loadFirstTime() {
2021-04-14 10:30:14 +02:00
const middleware = this . middleware . get ( ) ;
2023-01-06 20:27:29 +01:00
const { peerId , threadId } = this . searchContext ;
2022-06-17 18:01:43 +02:00
if ( ! this . hideEmptyTabs ) {
return ;
}
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
const mediaTabs = this . mediaTabs . filter ( ( mediaTab ) = > mediaTab . inputFilter !== 'inputMessagesFilterEmpty' ) ;
const filters = mediaTabs . map ( ( mediaTab ) = > ( { _ : mediaTab.inputFilter } ) ) ;
2021-04-14 10:30:14 +02:00
2023-03-02 16:51:37 +01:00
const [ counters , canViewMembers , canViewGroups ] = await Promise . all ( [
2023-01-06 20:27:29 +01:00
this . managers . appMessagesManager . getSearchCounters ( peerId , filters , undefined , threadId ) ,
2023-03-02 16:51:37 +01:00
this . canViewMembers ( ) ,
this . canViewGroups ( )
2022-06-17 18:01:43 +02:00
] ) ;
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
if ( ! middleware ( ) ) {
return ;
}
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
if ( this . loadMutex ) {
await this . loadMutex ;
if ( ! middleware ( ) ) {
return ;
}
}
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
let firstMediaTab : SearchSuperMediaTab ;
let count = 0 ;
mediaTabs . forEach ( ( mediaTab ) = > {
const counter = counters . find ( ( c ) = > c . filter . _ === mediaTab . inputFilter ) ;
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
mediaTab . menuTab . classList . toggle ( 'hide' , ! counter . count ) ;
mediaTab . menuTab . classList . remove ( 'active' ) ;
2022-08-04 08:49:54 +02:00
// mediaTab.contentTab.classList.toggle('hide', !counter.count);
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
if ( counter . count ) {
if ( firstMediaTab === undefined ) {
firstMediaTab = mediaTab ;
}
2021-04-18 13:55:56 +02:00
2022-06-17 18:01:43 +02:00
++ count ;
}
} ) ;
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
const membersTab = this . mediaTabsMap . get ( 'members' ) ;
2023-03-02 16:51:37 +01:00
const a : [ SearchSuperMediaTab , boolean ] [ ] = [
[ membersTab , canViewMembers ] ,
[ this . mediaTabsMap . get ( 'groups' ) , canViewGroups ]
] ;
a . forEach ( ( [ tab , value ] ) = > {
if ( ! tab ) {
return ;
}
tab . menuTab . classList . toggle ( 'hide' , ! value ) ;
if ( value ) {
++ count ;
}
} ) ;
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
if ( canViewMembers ) {
firstMediaTab = membersTab ;
}
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
this . container . classList . toggle ( 'hide' , ! firstMediaTab ) ;
this . container . parentElement . classList . toggle ( 'search-empty' , ! firstMediaTab ) ;
if ( firstMediaTab ) {
this . skipScroll = true ;
this . selectTab ( this . mediaTabs . indexOf ( firstMediaTab ) , false ) ;
// firstMediaTab.menuTab.classList.add('active');
2021-04-18 13:55:56 +02:00
2022-06-17 18:01:43 +02:00
this . navScrollableContainer . classList . toggle ( 'hide' , count <= 1 ) ;
}
}
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
public async load ( single = false , justLoad = false ) {
const peerId = this . searchContext . peerId ;
this . log ( 'load' , single , peerId , this . loadPromises ) ;
const middleware = this . middleware . get ( ) ;
if ( this . firstLoad ) {
await ( this . loadFirstTimePromise ? ? = this . loadFirstTime ( ) ) ;
if ( ! middleware ( ) ) {
return ;
2021-04-14 10:30:14 +02:00
}
2022-06-17 18:01:43 +02:00
this . loadFirstTimePromise = undefined ;
2021-04-14 10:30:14 +02:00
this . firstLoad = false ;
}
2022-08-04 08:49:54 +02:00
2022-06-17 18:01:43 +02:00
let toLoad = single ? [ this . mediaTab ] : this . mediaTabs . filter ( ( t ) = > t !== this . mediaTab ) ;
toLoad = toLoad . filter ( ( mediaTab ) = > {
return this . canLoadMediaTab ( mediaTab ) ;
2021-04-07 19:11:08 +02:00
} ) ;
2020-12-25 13:53:20 +01:00
2021-10-21 15:16:43 +02:00
if ( peerId . isUser ( ) ) {
2022-06-17 18:01:43 +02:00
findAndSplice ( toLoad , ( mediaTab ) = > mediaTab . type === 'members' ) ;
2023-03-02 16:51:37 +01:00
} else {
findAndSplice ( toLoad , ( mediaTab ) = > mediaTab . type === 'groups' ) ;
2021-05-03 22:02:53 +02:00
}
2021-04-07 19:11:08 +02:00
if ( ! toLoad . length ) {
return ;
}
2020-12-25 00:19:34 +01:00
2021-12-11 17:37:08 +01:00
const loadCount = justLoad ? 50 : Math.round ( ( windowSize . height / 130 | 0 ) * 3 * 1.25 ) ; // that's good for all types
2020-12-25 00:19:34 +01:00
2022-06-17 18:01:43 +02:00
const promises : Promise < any > [ ] = toLoad . map ( ( mediaTab ) = > {
return this . loadType ( mediaTab , justLoad , loadCount , middleware ) ;
2020-12-25 00:19:34 +01:00
} ) ;
2021-04-14 10:30:14 +02:00
2022-06-17 18:01:43 +02:00
return Promise . all ( promises ) . catch ( ( err ) = > {
2020-12-25 13:53:20 +01:00
this . log . error ( 'Load error all promises:' , err ) ;
2020-12-25 00:19:34 +01:00
} ) ;
}
2022-08-04 08:49:54 +02:00
2023-01-06 20:27:29 +01:00
private getMonthContainerByTimestamp ( timestamp : number , type : SearchSuperType ) {
2020-12-25 13:53:20 +01:00
const date = new Date ( timestamp * 1000 ) ;
date . setHours ( 0 , 0 , 0 ) ;
date . setDate ( 1 ) ;
const dateTimestamp = date . getTime ( ) ;
const containers = this . monthContainers [ type ] ? ? ( this . monthContainers [ type ] = { } ) ;
if ( ! ( dateTimestamp in containers ) ) {
const container = document . createElement ( 'div' ) ;
container . className = 'search-super-month' ;
const name = document . createElement ( 'div' ) ;
name . classList . add ( 'search-super-month-name' ) ;
2021-09-26 18:03:45 +02:00
const options : Intl.DateTimeFormatOptions = {
month : 'long'
} ;
if ( date . getFullYear ( ) !== new Date ( ) . getFullYear ( ) ) {
options . year = 'numeric' ;
}
const dateElement = new I18n . IntlDateElement ( {
date ,
options
} ) . element ;
name . append ( dateElement ) ;
2020-12-25 13:53:20 +01:00
container . append ( name ) ;
const items = document . createElement ( 'div' ) ;
items . classList . add ( 'search-super-month-items' ) ;
container . append ( name , items ) ;
const haveTimestamps = getObjectKeysAndSort ( containers , 'desc' ) ;
let i = 0 ;
for ( ; i < haveTimestamps . length ; ++ i ) {
const t = haveTimestamps [ i ] ;
if ( dateTimestamp > t ) {
break ;
}
}
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
containers [ dateTimestamp ] = { container , items } ;
positionElementByIndex ( container , this . tabs [ type ] , i ) ;
}
return containers [ dateTimestamp ] ;
}
2020-12-25 00:19:34 +01:00
2021-04-09 18:44:43 +02:00
public canViewMembers() {
2023-01-06 20:27:29 +01:00
const { peerId } = this . searchContext ;
const isAnyChat = peerId . isAnyChat ( ) ;
2023-03-02 16:51:37 +01:00
if ( ! isAnyChat || ! this . mediaTabsMap . has ( 'members' ) ) return Promise . resolve ( false ) ;
2023-01-06 20:27:29 +01:00
const chatId = peerId . toChatId ( ) ;
2022-06-17 18:01:43 +02:00
return Promise . all ( [
2023-01-06 20:27:29 +01:00
this . managers . appChatsManager . isBroadcast ( chatId ) ,
this . managers . appChatsManager . hasRights ( chatId , 'view_participants' ) ,
this . managers . appChatsManager . isForum ( chatId )
] ) . then ( ( [ isBroadcast , hasRights , isForum ] ) = > {
return ! isBroadcast && hasRights && ( ! this . searchContext . threadId || ! isForum ) ;
2022-06-17 18:01:43 +02:00
} ) ;
2021-04-09 18:44:43 +02:00
}
2023-03-02 16:51:37 +01:00
public async canViewGroups() {
const { peerId } = this . searchContext ;
if ( ! peerId . isUser ( ) || ! this . mediaTabsMap . has ( 'groups' ) ) return false ;
const userFull = await this . managers . appProfileManager . getProfile ( peerId . toUserId ( ) ) ;
return ! ! userFull . common_chats_count ;
}
2020-12-25 00:19:34 +01:00
public cleanup() {
this . loadPromises = { } ;
this . loaded = { } ;
2020-12-25 13:53:20 +01:00
this . loadedChats = false ;
this . nextRates = { } ;
2021-04-14 10:30:14 +02:00
this . firstLoad = true ;
2022-06-17 18:01:43 +02:00
this . prevTabId = - 1 ;
2020-12-25 00:19:34 +01:00
this . lazyLoadQueue . clear ( ) ;
2022-06-17 18:01:43 +02:00
this . mediaTabs . forEach ( ( mediaTab ) = > {
2021-04-07 19:11:08 +02:00
this . usedFromHistory [ mediaTab . inputFilter ] = - 1 ;
2020-12-25 00:19:34 +01:00
} ) ;
2022-07-26 07:22:46 +02:00
if ( this . selection ? . isSelecting ) {
2021-09-12 07:12:39 +02:00
this . selection . cancelSelection ( ) ;
}
2021-04-09 18:44:43 +02:00
// * must go to first tab (это костыль)
2021-04-14 10:30:14 +02:00
/ * c o n s t m e m b e r s T a b = t h i s . m e d i a T a b s M a p . g e t ( ' m e m b e r s ' ) ;
2021-04-09 18:44:43 +02:00
if ( membersTab ) {
const tab = this . canViewMembers ( ) ? membersTab : this.mediaTabs [ this . mediaTabs . indexOf ( membersTab ) + 1 ] ;
this . mediaTab = tab ;
2021-04-14 10:30:14 +02:00
} * /
2021-04-09 18:44:43 +02:00
2021-04-07 19:11:08 +02:00
this . middleware . clean ( ) ;
2022-06-17 18:01:43 +02:00
this . loadFirstTimePromise = undefined ;
2021-04-07 19:11:08 +02:00
this . cleanScrollPositions ( ) ;
2021-04-11 01:14:57 +02:00
this . membersList = undefined ;
2021-04-07 19:11:08 +02:00
}
public cleanScrollPositions() {
2022-06-17 18:01:43 +02:00
this . mediaTabs . forEach ( ( mediaTab ) = > {
2021-04-07 19:11:08 +02:00
mediaTab . scroll = undefined ;
} ) ;
2020-12-25 00:19:34 +01:00
}
2021-04-09 18:44:43 +02:00
public cleanupHTML ( goFirst = false ) {
2021-04-07 19:11:08 +02:00
this . mediaTabs . forEach ( ( tab ) = > {
2023-01-06 20:27:29 +01:00
tab . contentTab . replaceChildren ( ) ;
2020-12-25 13:53:20 +01:00
2021-04-14 10:30:14 +02:00
if ( this . hideEmptyTabs ) {
2022-08-04 08:49:54 +02:00
// tab.menuTab.classList.add('hide');
2021-04-14 10:30:14 +02:00
this . container . classList . add ( 'hide' ) ;
this . container . parentElement . classList . add ( 'search-empty' ) ;
}
2021-04-09 18:44:43 +02:00
2021-04-07 19:11:08 +02:00
if ( tab . type === 'chats' ) {
2020-12-25 13:53:20 +01:00
return ;
}
2022-08-04 08:49:54 +02:00
2021-04-07 19:11:08 +02:00
if ( ! this . historyStorage [ tab . inputFilter ] ) {
const parent = tab . contentTab . parentElement ;
2022-08-04 08:49:54 +02:00
// if(!testScroll) {
if ( ! parent . querySelector ( '.preloader' ) ) {
putPreloader ( parent , true ) ;
}
// }
2020-12-25 00:19:34 +01:00
const empty = parent . querySelector ( '.content-empty' ) ;
if ( empty ) {
empty . remove ( ) ;
}
}
} ) ;
2021-04-07 19:11:08 +02:00
2021-04-14 10:30:14 +02:00
/ * i f ( g o F i r s t ) {
2021-04-09 18:44:43 +02:00
const membersTab = this . mediaTabsMap . get ( 'members' ) ;
if ( membersTab ) {
let idx = this . canViewMembers ( ) ? 0 : 1 ;
membersTab . menuTab . classList . toggle ( 'hide' , idx !== 0 ) ;
this . selectTab ( idx , false ) ;
} else {
this . selectTab ( 0 , false ) ;
}
2021-04-14 10:30:14 +02:00
} * /
2021-04-09 18:44:43 +02:00
2020-12-25 13:53:20 +01:00
this . monthContainers = { } ;
2020-12-25 18:38:32 +01:00
this . searchGroupMedia . clear ( ) ;
2021-03-11 23:39:57 +01:00
this . scrollable . scrollTop = 0 ;
2020-12-25 00:19:34 +01:00
2021-03-11 23:39:57 +01:00
/ * i f ( t e s t S c r o l l ) {
2020-12-25 00:19:34 +01:00
for ( let i = 0 ; i < 1500 ; ++ i ) {
let div = document . createElement ( 'div' ) ;
div . insertAdjacentHTML ( 'beforeend' , ` <img class="media-image" src="assets/img/camomile.jpg"> ` ) ;
div . classList . add ( 'grid-item' ) ;
div . dataset . id = '' + ( i / 3 | 0 ) ;
//div.innerText = '' + (i / 3 | 0);
this . tabs . inputMessagesFilterPhotoVideo . append ( div ) ;
}
2021-03-11 23:39:57 +01:00
} * /
2020-12-25 13:53:20 +01:00
}
private copySearchContext ( newInputFilter : MyInputMessagesFilter ) {
const context = copy ( this . searchContext ) ;
2021-09-23 15:41:02 +02:00
context . inputFilter = { _ : newInputFilter } ;
2020-12-25 13:53:20 +01:00
context . nextRate = this . nextRates [ newInputFilter ] ;
return context ;
2020-12-25 00:19:34 +01:00
}
2020-12-25 18:38:32 +01:00
public setQuery ( { peerId , query , threadId , historyStorage , folderId , minDate , maxDate } : {
2022-08-04 08:49:54 +02:00
peerId : PeerId ,
query? : string ,
threadId? : number ,
historyStorage? : AppSearchSuper [ 'historyStorage' ] ,
2020-12-25 18:38:32 +01:00
folderId? : number ,
minDate? : number ,
maxDate? : number
2020-12-25 13:53:20 +01:00
} ) {
this . searchContext = {
2021-10-21 15:16:43 +02:00
peerId ,
2020-12-25 13:53:20 +01:00
query : query || '' ,
2021-09-23 15:41:02 +02:00
inputFilter : { _ : this.mediaTab.inputFilter } ,
2020-12-25 13:53:20 +01:00
threadId ,
2020-12-25 18:38:32 +01:00
folderId ,
minDate ,
maxDate
2020-12-25 13:53:20 +01:00
} ;
2022-08-04 08:49:54 +02:00
2020-12-25 13:53:20 +01:00
this . historyStorage = historyStorage ? ? { } ;
2020-12-25 00:19:34 +01:00
this . cleanup ( ) ;
}
2022-07-26 07:22:46 +02:00
public destroy() {
2023-01-12 16:13:22 +01:00
this . cleanup ( ) ;
2022-07-26 07:22:46 +02:00
this . listenerSetter . removeAll ( ) ;
this . scrollable . destroy ( ) ;
this . swipeHandler ? . removeListeners ( ) ;
this . selection ? . cleanup ( ) ;
2022-08-09 17:35:11 +02:00
2022-07-26 07:22:46 +02:00
this . scrollStartCallback = undefined ;
this . onChangeTab = undefined ;
this . selectTab = undefined ;
this . searchContextMenu = undefined ;
this . swipeHandler = undefined ;
this . selection = undefined ;
}
2021-03-11 23:39:57 +01:00
}