Chat list new search (alpha)
This commit is contained in:
parent
2a6a699bc5
commit
d9cd7b217e
@ -199,10 +199,17 @@ class AppMediaPlaybackController {
|
||||
const media = this.playingMedia;
|
||||
this.prevMid = this.nextMid = 0;
|
||||
|
||||
return appMessagesManager.getSearch(peerId, '', {
|
||||
//_: type == 'audio' ? 'inputMessagesFilterMusic' : (type == 'round' ? 'inputMessagesFilterRoundVideo' : 'inputMessagesFilterVoice')
|
||||
_: type == 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice'
|
||||
}, mid, 3, 0, 2).then(value => {
|
||||
return appMessagesManager.getSearchNew({
|
||||
peerId,
|
||||
query: '',
|
||||
inputFilter: {
|
||||
//_: type == 'audio' ? 'inputMessagesFilterMusic' : (type == 'round' ? 'inputMessagesFilterRoundVideo' : 'inputMessagesFilterVoice')
|
||||
_: type == 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice'
|
||||
},
|
||||
maxId: mid,
|
||||
limit: 3,
|
||||
backLimit: 2
|
||||
}).then(value => {
|
||||
if(this.playingMedia !== media) {
|
||||
return;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import Scrollable from "./scrollable";
|
||||
import appSidebarRight, { AppSidebarRight } from "./sidebarRight";
|
||||
import SwipeHandler from "./swipeHandler";
|
||||
import { months, ONE_DAY } from "../helpers/date";
|
||||
import { SearchSuperContext } from "./appSearchSuper.";
|
||||
|
||||
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
|
||||
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
|
||||
@ -804,7 +805,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
prevTargets: TargetType[] = [], nextTargets: TargetType[] = [], needLoadMore = true) {
|
||||
if(this.setMoverPromise) return this.setMoverPromise;
|
||||
|
||||
this.log('openMedia:', media, fromId);
|
||||
this.log('openMedia:', media, fromId, prevTargets, nextTargets);
|
||||
|
||||
this.setAuthorInfo(fromId, timestamp);
|
||||
|
||||
@ -1105,14 +1106,15 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
|
||||
type AppMediaViewerTargetType = {
|
||||
element: HTMLElement,
|
||||
mid: number
|
||||
mid: number,
|
||||
peerId: number
|
||||
};
|
||||
export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delete' | 'forward', AppMediaViewerTargetType> {
|
||||
public currentMessageId = 0;
|
||||
public peerId: number;
|
||||
public threadId: number;
|
||||
public currentPeerId = 0;
|
||||
public searchContext: SearchSuperContext;
|
||||
|
||||
constructor(private inputFilter: 'inputMessagesFilterPhotoVideo' | 'inputMessagesFilterChatPhotos' = 'inputMessagesFilterPhotoVideo') {
|
||||
constructor() {
|
||||
super(['delete', 'forward']);
|
||||
|
||||
/* const stub = document.createElement('div');
|
||||
@ -1165,27 +1167,29 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
} */
|
||||
|
||||
onPrevClick = (target: AppMediaViewerTargetType) => {
|
||||
this.nextTargets.unshift({element: this.lastTarget, mid: this.currentMessageId});
|
||||
this.openMedia(appMessagesManager.getMessageByPeer(this.peerId, target.mid), target.element);
|
||||
this.nextTargets.unshift({element: this.lastTarget, mid: this.currentMessageId, peerId: this.currentPeerId});
|
||||
this.openMedia(appMessagesManager.getMessageByPeer(target.peerId, target.mid), target.element, -1);
|
||||
};
|
||||
|
||||
onNextClick = (target: AppMediaViewerTargetType) => {
|
||||
this.prevTargets.push({element: this.lastTarget, mid: this.currentMessageId});
|
||||
this.openMedia(appMessagesManager.getMessageByPeer(this.peerId, target.mid), target.element);
|
||||
this.prevTargets.push({element: this.lastTarget, mid: this.currentMessageId, peerId: this.currentPeerId});
|
||||
this.openMedia(appMessagesManager.getMessageByPeer(target.peerId, target.mid), target.element, 1);
|
||||
};
|
||||
|
||||
onForwardClick = () => {
|
||||
if(this.currentMessageId) {
|
||||
//appSidebarRight.forwardTab.open([this.currentMessageId]);
|
||||
new PopupForward(this.peerId, [this.currentMessageId], () => {
|
||||
new PopupForward(this.currentPeerId, [this.currentMessageId], () => {
|
||||
return this.close();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onAuthorClick = (e: MouseEvent) => {
|
||||
if(this.currentMessageId && this.currentMessageId != Number.MAX_SAFE_INTEGER) {
|
||||
if(this.currentMessageId && this.currentMessageId !== Number.MAX_SAFE_INTEGER) {
|
||||
const mid = this.currentMessageId;
|
||||
const peerId = this.currentPeerId;
|
||||
const threadId = this.searchContext.threadId;
|
||||
this.close(e)
|
||||
//.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve())
|
||||
.then(() => {
|
||||
@ -1193,14 +1197,14 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
appSidebarRight.closeTab(AppSidebarRight.SLIDERITEMSIDS.sharedMedia);
|
||||
}
|
||||
|
||||
const message = appMessagesManager.getMessageByPeer(this.peerId, mid);
|
||||
appImManager.setInnerPeer(message.peerId, mid, this.threadId ? 'discussion' : undefined, this.threadId);
|
||||
const message = appMessagesManager.getMessageByPeer(peerId, mid);
|
||||
appImManager.setInnerPeer(message.peerId, mid, threadId ? 'discussion' : undefined, threadId);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onDownloadClick = () => {
|
||||
const message = appMessagesManager.getMessageByPeer(this.peerId, this.currentMessageId);
|
||||
const message = appMessagesManager.getMessageByPeer(this.currentPeerId, this.currentMessageId);
|
||||
if(message.media.photo) {
|
||||
appPhotosManager.savePhotoFile(message.media.photo, appImManager.chat.bubbles.lazyLoadQueue.queueId);
|
||||
} else {
|
||||
@ -1230,7 +1234,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
const backLimit = older ? 0 : loadCount;
|
||||
let maxId = this.currentMessageId;
|
||||
|
||||
let anchor: {element: HTMLElement, mid: number};
|
||||
let anchor: AppMediaViewerTargetType;
|
||||
if(older) {
|
||||
anchor = this.reverse ? this.prevTargets[0] : this.nextTargets[this.nextTargets.length - 1];
|
||||
} else {
|
||||
@ -1240,18 +1244,25 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
if(anchor) maxId = anchor.mid;
|
||||
if(!older) maxId = appMessagesManager.incrementMessageId(maxId, 1);
|
||||
|
||||
const peerId = this.peerId;
|
||||
const threadId = this.threadId;
|
||||
|
||||
const promise = appMessagesManager.getSearch(peerId, '',
|
||||
{_: this.inputFilter}, maxId, backLimit ? 0 : loadCount/* older ? loadCount : 0 */, 0, backLimit, threadId).then(value => {
|
||||
if(this.peerId !== peerId || this.threadId !== threadId) {
|
||||
this.log.warn('peer changed');
|
||||
return;
|
||||
}
|
||||
|
||||
const promise = appMessagesManager.getSearchNew({
|
||||
peerId: this.searchContext.peerId,
|
||||
query: this.searchContext.query,
|
||||
inputFilter: {
|
||||
_: this.searchContext.inputFilter
|
||||
},
|
||||
maxId,
|
||||
limit: backLimit ? 0 : loadCount,
|
||||
backLimit,
|
||||
threadId: this.searchContext.threadId,
|
||||
folderId: this.searchContext.folderId,
|
||||
nextRate: this.searchContext.nextRate
|
||||
}).then(value => {
|
||||
this.log('loaded more media by maxId:', maxId, value, older, this.reverse);
|
||||
|
||||
if(value.next_rate) {
|
||||
this.searchContext.nextRate = value.next_rate;
|
||||
}
|
||||
|
||||
if(value.history.length < loadCount) {
|
||||
/* if(this.reverse) {
|
||||
if(older) this.loadedAllMediaUp = true;
|
||||
@ -1264,13 +1275,13 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
|
||||
const method = older ? value.history.forEach : value.history.forEachReverse;
|
||||
method.call(value.history, message => {
|
||||
const mid = message.mid
|
||||
const {mid, peerId} = message;
|
||||
const media = this.getMediaFromMessage(message);
|
||||
|
||||
if(!media) return;
|
||||
//if(media._ == 'document' && media.type != 'video') return;
|
||||
|
||||
const t = {element: null as HTMLElement, mid: mid};
|
||||
const t = {element: null as HTMLElement, mid, peerId};
|
||||
if(older) {
|
||||
if(this.reverse) this.prevTargets.unshift(t);
|
||||
else this.nextTargets.push(t);
|
||||
@ -1311,26 +1322,30 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
}
|
||||
}
|
||||
|
||||
public async openMedia(message: any, target?: HTMLElement, reverse = false,
|
||||
prevTargets: AppMediaViewer['prevTargets'] = [], nextTargets: AppMediaViewer['prevTargets'] = [], needLoadMore = true, threadId?: number) {
|
||||
public setSearchContext(context: SearchSuperContext) {
|
||||
this.searchContext = context;
|
||||
|
||||
if(this.searchContext.folderId !== undefined) {
|
||||
this.loadedAllMediaUp = true;
|
||||
|
||||
if(this.searchContext.nextRate === undefined) {
|
||||
this.loadedAllMediaDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public async openMedia(message: any, target?: HTMLElement, fromRight = 0, reverse = false,
|
||||
prevTargets: AppMediaViewer['prevTargets'] = [], nextTargets: AppMediaViewer['prevTargets'] = [], needLoadMore = true) {
|
||||
if(this.setMoverPromise) return this.setMoverPromise;
|
||||
|
||||
const mid = message.mid;
|
||||
const fromId = message.fromId;
|
||||
const media = this.getMediaFromMessage(message);
|
||||
|
||||
let fromRight = 0;
|
||||
if(!this.isFirstOpen) {
|
||||
//if(this.lastTarget === prevTarget) {
|
||||
if(this.reverse) fromRight = this.currentMessageId < mid ? 1 : -1;
|
||||
else fromRight = this.currentMessageId > mid ? 1 : -1;
|
||||
} else {
|
||||
this.reverse = reverse;
|
||||
this.peerId = message.peerId;
|
||||
this.threadId = threadId;
|
||||
}
|
||||
|
||||
this.currentMessageId = mid;
|
||||
this.currentPeerId = message.peerId;
|
||||
const promise = super._openMedia(media, message.date, fromId, fromRight, target, reverse, prevTargets, nextTargets, needLoadMore);
|
||||
this.setCaption(message);
|
||||
|
||||
|
@ -1,14 +1,7 @@
|
||||
import appDialogsManager from "../lib/appManagers/appDialogsManager";
|
||||
import Scrollable from "./scrollable";
|
||||
import appUsersManager from "../lib/appManagers/appUsersManager";
|
||||
import appPeersManager from '../lib/appManagers/appPeersManager';
|
||||
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||
import { formatPhoneNumber } from "./misc";
|
||||
import appChatsManager from "../lib/appManagers/appChatsManager";
|
||||
import InputSearch from "./inputSearch";
|
||||
import rootScope from "../lib/rootScope";
|
||||
import { escapeRegExp } from "../helpers/string";
|
||||
import searchIndexManager from "../lib/searchIndexManager";
|
||||
|
||||
export class SearchGroup {
|
||||
container: HTMLDivElement;
|
||||
@ -57,17 +50,12 @@ export class SearchGroup {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * Saved будет использована только для вывода одного элемента - избранное
|
||||
*/
|
||||
type SearchGroupType = 'saved' | 'contacts' | 'globalContacts' | 'messages' | string;
|
||||
export type SearchGroupType = 'contacts' | 'globalContacts' | 'messages' | string;
|
||||
|
||||
export default class AppSearch {
|
||||
private minMsgId = 0;
|
||||
private loadedCount = -1;
|
||||
private foundCount = -1;
|
||||
private offsetRate = 0;
|
||||
private loadedContacts = false;
|
||||
|
||||
private searchPromise: Promise<void> = null;
|
||||
private searchTimeout: number = 0;
|
||||
@ -126,8 +114,6 @@ export default class AppSearch {
|
||||
this.minMsgId = 0;
|
||||
this.loadedCount = -1;
|
||||
this.foundCount = -1;
|
||||
this.offsetRate = 0;
|
||||
this.loadedContacts = false;
|
||||
|
||||
for(let i in this.searchGroups) {
|
||||
this.searchGroups[i as SearchGroupType].clear();
|
||||
@ -164,112 +150,36 @@ export default class AppSearch {
|
||||
|
||||
const maxId = this.minMsgId || 0;
|
||||
|
||||
if(!this.peerId && !maxId && !this.loadedContacts) {
|
||||
const renderedPeerIds: Set<number> = new Set();
|
||||
|
||||
const setResults = (results: number[], group: SearchGroup, showMembersCount = false) => {
|
||||
results.forEach((peerId) => {
|
||||
if(renderedPeerIds.has(peerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderedPeerIds.add(peerId);
|
||||
|
||||
const peer = appPeersManager.getPeer(peerId);
|
||||
|
||||
//////////this.log('contacts peer', peer);
|
||||
|
||||
const {dom} = appDialogsManager.addDialogNew({
|
||||
dialog: peerId,
|
||||
container: group.list,
|
||||
drawStatus: false,
|
||||
avatarSize: 48,
|
||||
autonomous: group.autonomous
|
||||
});
|
||||
|
||||
if(showMembersCount && (peer.participants_count || peer.participants)) {
|
||||
const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(searchIndexManager.cleanSearchText(query))})`, 'gi');
|
||||
dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');
|
||||
dom.lastMessageSpan.innerText = appChatsManager.getChatMembersString(-peerId);
|
||||
} else if(peerId == rootScope.myId) {
|
||||
dom.lastMessageSpan.innerHTML = 'chat with yourself';
|
||||
} else {
|
||||
let username = appPeersManager.getPeerUsername(peerId);
|
||||
if(!username) {
|
||||
const user = appUsersManager.getUser(peerId);
|
||||
if(user && user.phone) {
|
||||
username = '+' + formatPhoneNumber(user.phone).formatted;
|
||||
}
|
||||
} else {
|
||||
username = '@' + username;
|
||||
}
|
||||
|
||||
dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';
|
||||
}
|
||||
});
|
||||
|
||||
group.toggle();
|
||||
};
|
||||
|
||||
const onLoad = <T>(arg: T) => {
|
||||
if(this.searchInput.value != query) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadedContacts = true;
|
||||
|
||||
return arg;
|
||||
};
|
||||
|
||||
appUsersManager.getContacts(query, true)
|
||||
.then(onLoad)
|
||||
.then((contacts) => {
|
||||
if(contacts) {
|
||||
setResults(contacts, this.searchGroups.contacts, true);
|
||||
}
|
||||
});
|
||||
|
||||
appUsersManager.searchContacts(query, 20)
|
||||
.then(onLoad)
|
||||
.then((contacts) => {
|
||||
if(contacts) {
|
||||
setResults(contacts.my_results, this.searchGroups.contacts, true);
|
||||
setResults(contacts.results, this.searchGroups.globalContacts);
|
||||
}
|
||||
});
|
||||
|
||||
appMessagesManager.getConversations(query, 0, 20, 0)
|
||||
.then(onLoad)
|
||||
.then(value => {
|
||||
if(value) {
|
||||
setResults(value.dialogs.map(d => d.peerId), this.searchGroups.contacts, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this.searchPromise = appMessagesManager.getSearch(this.peerId, query, {_: 'inputMessagesFilterEmpty'}, maxId, 20, this.offsetRate, undefined, this.threadId).then(res => {
|
||||
return this.searchPromise = appMessagesManager.getSearchNew({
|
||||
peerId: this.peerId,
|
||||
query,
|
||||
inputFilter: {_: 'inputMessagesFilterEmpty'},
|
||||
maxId,
|
||||
limit: 20,
|
||||
threadId: this.threadId
|
||||
}).then(res => {
|
||||
this.searchPromise = null;
|
||||
|
||||
if(this.searchInput.value != query) {
|
||||
if(this.searchInput.value !== query) {
|
||||
return;
|
||||
}
|
||||
|
||||
//console.log('input search result:', this.peerId, query, null, maxId, 20, res);
|
||||
|
||||
const {count, history, next_rate} = res;
|
||||
const {count, history} = res;
|
||||
|
||||
if(history.length && history[0].mid == this.minMsgId) {
|
||||
if(history.length && history[0].mid === this.minMsgId) {
|
||||
history.shift();
|
||||
}
|
||||
|
||||
const searchGroup = this.searchGroups.messages;
|
||||
|
||||
history.forEach((message: any) => {
|
||||
history.forEach((message) => {
|
||||
const {dialog, dom} = appDialogsManager.addDialogNew({
|
||||
dialog: message.peerId,
|
||||
container: this.scrollable/* searchGroup.list */,
|
||||
drawStatus: false,
|
||||
avatarSize: 48
|
||||
avatarSize: 54
|
||||
});
|
||||
appDialogsManager.setLastMessage(dialog, message, dom, query);
|
||||
});
|
||||
@ -277,14 +187,13 @@ export default class AppSearch {
|
||||
searchGroup.toggle();
|
||||
|
||||
this.minMsgId = history.length && history[history.length - 1].mid;
|
||||
this.offsetRate = next_rate;
|
||||
|
||||
if(this.loadedCount == -1) {
|
||||
if(this.loadedCount === -1) {
|
||||
this.loadedCount = 0;
|
||||
}
|
||||
this.loadedCount += history.length;
|
||||
|
||||
if(this.foundCount == -1) {
|
||||
if(this.foundCount === -1) {
|
||||
this.foundCount = count;
|
||||
this.onSearch && this.onSearch(this.foundCount);
|
||||
}
|
||||
|
@ -1,21 +1,45 @@
|
||||
import { limitSymbols } from "../helpers/string";
|
||||
import appMessagesManager, { MyInputMessagesFilter } from "../lib/appManagers/appMessagesManager";
|
||||
import { formatDateAccordingToToday, months } from "../helpers/date";
|
||||
import { findUpClassName, positionElementByIndex } from "../helpers/dom";
|
||||
import { copy, getObjectKeysAndSort } from "../helpers/object";
|
||||
import { escapeRegExp, limitSymbols } from "../helpers/string";
|
||||
import appChatsManager from "../lib/appManagers/appChatsManager";
|
||||
import appDialogsManager from "../lib/appManagers/appDialogsManager";
|
||||
import appMessagesManager, { MyInputMessagesFilter, MyMessage } from "../lib/appManagers/appMessagesManager";
|
||||
import appPeersManager from "../lib/appManagers/appPeersManager";
|
||||
import appPhotosManager from "../lib/appManagers/appPhotosManager";
|
||||
import appStateManager from "../lib/appManagers/appStateManager";
|
||||
import appUsersManager from "../lib/appManagers/appUsersManager";
|
||||
import { logger } from "../lib/logger";
|
||||
import RichTextProcessor from "../lib/richtextprocessor";
|
||||
import rootScope from "../lib/rootScope";
|
||||
import searchIndexManager from "../lib/searchIndexManager";
|
||||
import AppMediaViewer from "./appMediaViewer";
|
||||
import { SearchGroup, SearchGroupType } from "./appSearch";
|
||||
import { horizontalMenu } from "./horizontalMenu";
|
||||
import LazyLoadQueue from "./lazyLoadQueue";
|
||||
import { renderImageFromUrl, putPreloader } from "./misc";
|
||||
import { renderImageFromUrl, putPreloader, formatPhoneNumber } from "./misc";
|
||||
import { ripple } from "./ripple";
|
||||
import Scrollable from "./scrollable";
|
||||
import { wrapDocument } from "./wrappers";
|
||||
|
||||
const testScroll = false;
|
||||
|
||||
export default class AppSearchSuper {
|
||||
public tabs: {[t in MyInputMessagesFilter]: HTMLDivElement} = {} as any;
|
||||
export type SearchSuperType = MyInputMessagesFilter/* | 'chats' */;
|
||||
export type SearchSuperContext = {
|
||||
peerId: number,
|
||||
inputFilter: MyInputMessagesFilter,
|
||||
query?: string,
|
||||
maxId?: number,
|
||||
folderId?: number,
|
||||
threadId?: number,
|
||||
date?: number,
|
||||
nextRate?: number
|
||||
};
|
||||
|
||||
public type: MyInputMessagesFilter;
|
||||
export default class AppSearchSuper {
|
||||
public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any;
|
||||
|
||||
public type: SearchSuperType;
|
||||
public tabSelected: HTMLElement;
|
||||
|
||||
public container: HTMLElement;
|
||||
@ -23,23 +47,34 @@ export default class AppSearchSuper {
|
||||
private tabsMenu: HTMLUListElement;
|
||||
private prevTabId = -1;
|
||||
|
||||
public mediaDivsByIds: {[mid: number]: HTMLDivElement} = {};
|
||||
|
||||
private lazyLoadQueue = new LazyLoadQueue();
|
||||
private cleanupObj = {cleaned: false};
|
||||
|
||||
public historyStorage: Partial<{[type in MyInputMessagesFilter]: number[]}> = {};
|
||||
public usedFromHistory: Partial<{[type in MyInputMessagesFilter]: number}> = {};
|
||||
public historyStorage: Partial<{[type in SearchSuperType]: {mid: number, peerId: number}[]}> = {};
|
||||
public usedFromHistory: Partial<{[type in SearchSuperType]: number}> = {};
|
||||
public urlsToRevoke: string[] = [];
|
||||
|
||||
private peerId = 0;
|
||||
private threadId = 0;
|
||||
private query = '';
|
||||
private searchContext: SearchSuperContext;
|
||||
public loadMutex: Promise<any> = Promise.resolve();
|
||||
|
||||
private loadPromises: Partial<{[type in MyInputMessagesFilter]: Promise<void>}> = {};
|
||||
private loaded: Partial<{[type in MyInputMessagesFilter]: boolean}> = {};
|
||||
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;
|
||||
|
||||
constructor(public types: {inputFilter: MyInputMessagesFilter, name: string}[], public scrollable: Scrollable) {
|
||||
private log = logger('SEARCH-SUPER');
|
||||
public selectTab: ReturnType<typeof horizontalMenu>;
|
||||
|
||||
private monthContainers: Partial<{
|
||||
[type in SearchSuperType]: {
|
||||
[timestamp: number]: {
|
||||
container: HTMLElement,
|
||||
items: HTMLElement
|
||||
}
|
||||
}
|
||||
}> = {};
|
||||
|
||||
constructor(public types: {inputFilter: SearchSuperType, name: string}[], public scrollable: Scrollable, public searchGroups?: {[group in SearchGroupType]: SearchGroup}, public asChatList = false) {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('search-super');
|
||||
|
||||
@ -92,24 +127,24 @@ export default class AppSearchSuper {
|
||||
};
|
||||
//this.scroll.attachSentinels(undefined, 400);
|
||||
|
||||
horizontalMenu(this.tabsMenu, this.tabsContainer, (id, tabContent) => {
|
||||
if(this.prevTabId == id) return;
|
||||
this.selectTab = horizontalMenu(this.tabsMenu, this.tabsContainer, (id, tabContent) => {
|
||||
if(this.prevTabId === id) return;
|
||||
|
||||
if(this.prevTabId != -1) {
|
||||
if(this.prevTabId !== -1) {
|
||||
this.onTransitionStart();
|
||||
}
|
||||
|
||||
this.type = this.types[id].inputFilter;
|
||||
this.tabSelected = tabContent.firstElementChild as HTMLDivElement;
|
||||
|
||||
if(this.prevTabId != -1 && nav.offsetTop) {
|
||||
if(this.prevTabId !== -1 && nav.offsetTop) {
|
||||
this.scrollable.scrollTop -= nav.offsetTop;
|
||||
}
|
||||
|
||||
/* this.log('setVirtualContainer', id, this.sharedMediaSelected, this.sharedMediaSelected.childElementCount);
|
||||
this.scroll.setVirtualContainer(this.sharedMediaSelected); */
|
||||
|
||||
if(this.prevTabId != -1 && !this.tabSelected.childElementCount) { // quick brown fix
|
||||
if(this.prevTabId !== -1 && !this.tabSelected.childElementCount) { // quick brown fix
|
||||
//this.contentContainer.classList.remove('loaded');
|
||||
this.load(true);
|
||||
}
|
||||
@ -121,27 +156,30 @@ export default class AppSearchSuper {
|
||||
});
|
||||
|
||||
this.tabs.inputMessagesFilterPhotoVideo.addEventListener('click', (e) => {
|
||||
const target = e.target as HTMLDivElement;
|
||||
const target = findUpClassName(e.target as HTMLDivElement, 'grid-item');
|
||||
|
||||
const messageId = +target.dataset.mid;
|
||||
if(!messageId) {
|
||||
console.warn('no messageId by click on target:', target);
|
||||
const mid = +target.dataset.mid;
|
||||
if(!mid) {
|
||||
this.log.warn('no messageId by click on target:', target);
|
||||
return;
|
||||
}
|
||||
|
||||
const message = appMessagesManager.getMessageByPeer(this.peerId, messageId);
|
||||
|
||||
const ids = Object.keys(this.mediaDivsByIds).map(k => +k).sort((a, b) => a - b);
|
||||
const idx = ids.findIndex(i => i == messageId);
|
||||
|
||||
const targets = ids.map(id => {
|
||||
const element = this.mediaDivsByIds[id] as HTMLElement;
|
||||
//element = element.querySelector('img') || element;
|
||||
return {element, mid: id};
|
||||
|
||||
const peerId = +target.dataset.peerId;
|
||||
|
||||
const targets = (Array.from(this.tabs.inputMessagesFilterPhotoVideo.querySelectorAll('.grid-item')) as HTMLElement[]).map(el => {
|
||||
return {element: el, mid: +el.dataset.mid, peerId: +el.dataset.peerId};
|
||||
});
|
||||
|
||||
//const ids = Object.keys(this.mediaDivsByIds).map(k => +k).sort((a, b) => a - b);
|
||||
const idx = targets.findIndex(item => item.mid === mid && item.peerId === peerId);
|
||||
|
||||
new AppMediaViewer().openMedia(message, target, false, targets.slice(idx + 1).reverse(), targets.slice(0, idx).reverse(), true/* , this.threadId */);
|
||||
const message = appMessagesManager.getMessageByPeer(peerId, mid);
|
||||
new AppMediaViewer()
|
||||
.setSearchContext(this.copySearchContext(this.type))
|
||||
.openMedia(message, target, 0, false, targets.slice(0, idx), targets.slice(idx + 1));
|
||||
});
|
||||
|
||||
this.type = this.types[0].inputFilter;
|
||||
}
|
||||
|
||||
private onTransitionStart = () => {
|
||||
@ -163,18 +201,24 @@ export default class AppSearchSuper {
|
||||
this.container.classList.remove('sliding');
|
||||
};
|
||||
|
||||
public filterMessagesByType(ids: number[], type: MyInputMessagesFilter) {
|
||||
let messages: any[] = [];
|
||||
public filterMessagesByType(messages: any[], type: SearchSuperType): MyMessage[] {
|
||||
if(type === 'inputMessagesFilterEmpty') return messages;
|
||||
|
||||
if(type != 'inputMessagesFilterUrl') {
|
||||
for(let mid of ids) {
|
||||
let message = appMessagesManager.getMessageByPeer(this.peerId, mid);
|
||||
if(message.media) messages.push(message);
|
||||
}
|
||||
} else {
|
||||
messages = ids.slice().map(mid => appMessagesManager.getMessageByPeer(this.peerId, mid));
|
||||
if(type !== 'inputMessagesFilterUrl') {
|
||||
messages = messages.filter(message => !!message.media);
|
||||
}
|
||||
|
||||
/* if(!this.peerId) {
|
||||
messages = messages.filter(message => {
|
||||
if(message.peerId === rootScope.myId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const dialog = appMessagesManager.getDialogByPeerId(message.fromId)[0];
|
||||
return dialog && dialog.folder_id === 0;
|
||||
});
|
||||
} */
|
||||
|
||||
let filtered: any[] = [];
|
||||
|
||||
switch(type) {
|
||||
@ -186,7 +230,7 @@ export default class AppSearchSuper {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(media._ == 'document' && media.type != 'video'/* && media.type != 'gif' */) {
|
||||
if(media._ === 'document' && media.type !== 'video'/* && media.type !== 'gif' */) {
|
||||
//this.log('broken video', media);
|
||||
continue;
|
||||
}
|
||||
@ -209,9 +253,9 @@ export default class AppSearchSuper {
|
||||
}
|
||||
|
||||
case 'inputMessagesFilterUrl': {
|
||||
console.log('inputMessagesFilterUrl', messages);
|
||||
//this.log('inputMessagesFilterUrl', messages);
|
||||
for(let message of messages) {
|
||||
//if((message.media.webpage && message.media.webpage._ != 'webPageEmpty')) {
|
||||
//if((message.media.webpage && message.media.webpage._ !== 'webPageEmpty')) {
|
||||
filtered.push(message);
|
||||
//}
|
||||
}
|
||||
@ -221,7 +265,19 @@ export default class AppSearchSuper {
|
||||
|
||||
case 'inputMessagesFilterMusic': {
|
||||
for(let message of messages) {
|
||||
if(!message.media.document || message.media.document.type != 'audio') {
|
||||
if(!message.media.document || message.media.document.type !== 'audio') {
|
||||
continue;
|
||||
}
|
||||
|
||||
filtered.push(message);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'inputMessagesFilterVoice': {
|
||||
for(let message of messages) {
|
||||
if(!message.media.document || message.media.document.type !== 'voice') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -238,31 +294,39 @@ export default class AppSearchSuper {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
public async performSearchResult(messages: any[], type: MyInputMessagesFilter, append = true) {
|
||||
const peerId = this.peerId;
|
||||
const threadId = this.threadId;
|
||||
const elemsToAppend: HTMLElement[] = [];
|
||||
public async performSearchResult(messages: any[], type: SearchSuperType, append = true) {
|
||||
const elemsToAppend: {element: HTMLElement, message: any}[] = [];
|
||||
const promises: Promise<any>[] = [];
|
||||
const sharedMediaDiv = this.tabs[type];
|
||||
const sharedMediaDiv: HTMLElement = type === 'inputMessagesFilterEmpty' ? this.searchGroups.messages.list : this.tabs[type];
|
||||
|
||||
/* for(let contentType in contentToSharedMap) {
|
||||
if(contentToSharedMap[contentType as ContentType] == type) {
|
||||
sharedMediaDiv = this.sharedMedia[contentType as ContentType];
|
||||
}
|
||||
} */
|
||||
const middleware = this.getMiddleware();
|
||||
|
||||
// https://core.telegram.org/type/MessagesFilter
|
||||
switch(type) {
|
||||
case 'inputMessagesFilterEmpty': {
|
||||
for(const message of messages) {
|
||||
const {dialog, dom} = appDialogsManager.addDialogNew({
|
||||
dialog: message.peerId,
|
||||
container: sharedMediaDiv as HTMLUListElement/* searchGroup.list */,
|
||||
drawStatus: false,
|
||||
avatarSize: 54
|
||||
});
|
||||
appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);
|
||||
}
|
||||
|
||||
this.searchGroups.messages.setActive();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'inputMessagesFilterPhotoVideo': {
|
||||
for(const message of messages) {
|
||||
const media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('grid-item');
|
||||
div.dataset.mid = '' + message.mid;
|
||||
//console.log(message, photo);
|
||||
//this.log(message, photo);
|
||||
|
||||
const isPhoto = media._ == 'photo';
|
||||
const isPhoto = media._ === 'photo';
|
||||
|
||||
const photo = isPhoto ? appPhotosManager.getPhoto(media.id) : null;
|
||||
let isDownloaded: boolean;
|
||||
@ -280,7 +344,7 @@ export default class AppSearchSuper {
|
||||
span.classList.add('video-time');
|
||||
div.append(span);
|
||||
|
||||
if(media.type != 'gif') {
|
||||
if(media.type !== 'gif') {
|
||||
span.innerText = (media.duration + '').toHHMMSS(false);
|
||||
|
||||
/* const spanPlay = document.createElement('span');
|
||||
@ -293,8 +357,8 @@ export default class AppSearchSuper {
|
||||
|
||||
const load = () => appPhotosManager.preloadPhoto(isPhoto ? media.id : media, appPhotosManager.choosePhotoSize(media, 200, 200))
|
||||
.then(() => {
|
||||
if(this.peerId != peerId || this.threadId != threadId) {
|
||||
console.warn('peer changed');
|
||||
if(!middleware()) {
|
||||
//this.log.warn('peer changed');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -343,7 +407,7 @@ export default class AppSearchSuper {
|
||||
});
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
//console.log('didn\'t load', thumb, media, isDownloaded, sizes);
|
||||
//this.log('didn\'t load', thumb, media, isDownloaded, sizes);
|
||||
reject();
|
||||
}, 1e3);
|
||||
});
|
||||
@ -356,26 +420,28 @@ export default class AppSearchSuper {
|
||||
else this.lazyLoadQueue.push({div, load});
|
||||
}
|
||||
|
||||
elemsToAppend.push(div);
|
||||
this.mediaDivsByIds[message.mid] = div;
|
||||
elemsToAppend.push({element: div, message});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'inputMessagesFilterVoice':
|
||||
case 'inputMessagesFilterMusic':
|
||||
case 'inputMessagesFilterDocument': {
|
||||
for(const message of messages) {
|
||||
const div = wrapDocument({
|
||||
message,
|
||||
withTime: true,
|
||||
fontWeight: 400
|
||||
withTime: !this.asChatList,
|
||||
fontWeight: 400,
|
||||
voiceAsMusic: true,
|
||||
showSender: this.asChatList,
|
||||
searchContext: this.copySearchContext(type)
|
||||
});
|
||||
if(message.media.document.type === 'audio') {
|
||||
div.classList.add('audio-48');
|
||||
}
|
||||
div.dataset.mid = '' + message.mid;
|
||||
elemsToAppend.push(div);
|
||||
elemsToAppend.push({element: div, message});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -432,7 +498,6 @@ export default class AppSearchSuper {
|
||||
}
|
||||
|
||||
let div = document.createElement('div');
|
||||
div.dataset.mid = '' + message.mid;
|
||||
|
||||
let previewDiv = document.createElement('div');
|
||||
previewDiv.classList.add('preview');
|
||||
@ -444,8 +509,8 @@ export default class AppSearchSuper {
|
||||
if(webpage.photo) {
|
||||
let load = () => appPhotosManager.preloadPhoto(webpage.photo.id, appPhotosManager.choosePhotoSize(webpage.photo, 60, 60))
|
||||
.then(() => {
|
||||
if(this.peerId != peerId || this.threadId != threadId) {
|
||||
console.warn('peer changed');
|
||||
if(!middleware()) {
|
||||
//this.log.warn('peer changed');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -467,19 +532,23 @@ export default class AppSearchSuper {
|
||||
title = RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]);
|
||||
}
|
||||
|
||||
/* if(webpage.description?.includes('Еще в начале')) {
|
||||
console.error('FROM THE START', webpage);
|
||||
} */
|
||||
|
||||
let sender = this.asChatList ? `<div class="subtitle sender">${appMessagesManager.getSenderToPeerText(message)}</div>` : '';
|
||||
|
||||
let titleAdditionHTML = '';
|
||||
if(this.asChatList) {
|
||||
titleAdditionHTML = `<div class="sent-time">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;
|
||||
}
|
||||
|
||||
div.append(previewDiv);
|
||||
div.insertAdjacentHTML('beforeend', `
|
||||
<div class="title">${title}</button>
|
||||
<div class="title">${title}${titleAdditionHTML}</div>
|
||||
<div class="subtitle">${subtitle}</div>
|
||||
<div class="url">${url}</div>
|
||||
${sender}
|
||||
`);
|
||||
|
||||
if(div.innerText.trim().length) {
|
||||
elemsToAppend.push(div);
|
||||
elemsToAppend.push({element: div, message});
|
||||
}
|
||||
|
||||
}
|
||||
@ -488,7 +557,7 @@ export default class AppSearchSuper {
|
||||
}
|
||||
|
||||
default:
|
||||
//console.warn('death is my friend', messages);
|
||||
//this.log.warn('death is my friend', messages);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -498,25 +567,39 @@ export default class AppSearchSuper {
|
||||
|
||||
if(promises.length) {
|
||||
await Promise.all(promises);
|
||||
if(this.peerId !== peerId || this.threadId !== threadId) {
|
||||
console.warn('peer changed');
|
||||
if(!middleware()) {
|
||||
//this.log.warn('peer changed');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(elemsToAppend.length) {
|
||||
sharedMediaDiv[append ? 'append' : 'prepend'](...elemsToAppend);
|
||||
const method = append ? 'append' : 'prepend';
|
||||
elemsToAppend.forEach(details => {
|
||||
const {element, message} = details;
|
||||
const monthContainer = this.getMonthContainerByTimestamp(message.date, type);
|
||||
element.classList.add('search-super-item');
|
||||
element.dataset.mid = '' + message.mid;
|
||||
element.dataset.peerId = '' + message.peerId;
|
||||
monthContainer.items[method](element);
|
||||
});
|
||||
}
|
||||
|
||||
if(sharedMediaDiv) {
|
||||
const parent = sharedMediaDiv.parentElement;
|
||||
if(type !== 'inputMessagesFilterEmpty') {
|
||||
this.afterPerforming(messages.length, sharedMediaDiv);
|
||||
}
|
||||
}
|
||||
|
||||
private afterPerforming(length: number, tab: HTMLElement) {
|
||||
if(tab) {
|
||||
const parent = tab.parentElement;
|
||||
Array.from(parent.children).slice(1).forEach(child => {
|
||||
child.remove();
|
||||
});
|
||||
|
||||
//this.contentContainer.classList.add('loaded');
|
||||
|
||||
if(!messages.length && !sharedMediaDiv.childElementCount) {
|
||||
if(!length && !tab.childElementCount) {
|
||||
const div = document.createElement('div');
|
||||
div.innerText = 'Nothing interesting here yet...';
|
||||
div.classList.add('position-center', 'text-center', 'content-empty', 'no-select');
|
||||
@ -525,20 +608,166 @@ export default class AppSearchSuper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private loadChats() {
|
||||
const renderedPeerIds: Set<number> = new Set();
|
||||
const middleware = this.getMiddleware();
|
||||
|
||||
for(let i in this.searchGroups) {
|
||||
const group = this.searchGroups[i as SearchGroupType];
|
||||
this.tabs.inputMessagesFilterEmpty.append(group.container);
|
||||
group.clear();
|
||||
}
|
||||
|
||||
const query = this.searchContext.query;
|
||||
if(query) {
|
||||
const setResults = (results: number[], group: SearchGroup, showMembersCount = false) => {
|
||||
results.forEach((peerId) => {
|
||||
if(renderedPeerIds.has(peerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderedPeerIds.add(peerId);
|
||||
|
||||
const peer = appPeersManager.getPeer(peerId);
|
||||
|
||||
//////////this.log('contacts peer', peer);
|
||||
|
||||
const {dom} = appDialogsManager.addDialogNew({
|
||||
dialog: peerId,
|
||||
container: group.list,
|
||||
drawStatus: false,
|
||||
avatarSize: 48,
|
||||
autonomous: group.autonomous
|
||||
});
|
||||
|
||||
if(showMembersCount && (peer.participants_count || peer.participants)) {
|
||||
const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(searchIndexManager.cleanSearchText(query))})`, 'gi');
|
||||
dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');
|
||||
dom.lastMessageSpan.innerText = appChatsManager.getChatMembersString(-peerId);
|
||||
} else if(peerId === rootScope.myId) {
|
||||
dom.lastMessageSpan.innerHTML = 'chat with yourself';
|
||||
} else {
|
||||
let username = appPeersManager.getPeerUsername(peerId);
|
||||
if(!username) {
|
||||
const user = appUsersManager.getUser(peerId);
|
||||
if(user && user.phone) {
|
||||
username = '+' + formatPhoneNumber(user.phone).formatted;
|
||||
}
|
||||
} else {
|
||||
username = '@' + username;
|
||||
}
|
||||
|
||||
dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';
|
||||
}
|
||||
});
|
||||
|
||||
group.toggle();
|
||||
};
|
||||
|
||||
const onLoad = <T>(arg: T) => {
|
||||
if(!middleware()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//this.loadedContacts = true;
|
||||
|
||||
return arg;
|
||||
};
|
||||
|
||||
return Promise.all([
|
||||
appUsersManager.getContacts(query, true)
|
||||
.then(onLoad)
|
||||
.then((contacts) => {
|
||||
if(contacts) {
|
||||
setResults(contacts, this.searchGroups.contacts, true);
|
||||
}
|
||||
}),
|
||||
|
||||
appUsersManager.searchContacts(query, 20)
|
||||
.then(onLoad)
|
||||
.then((contacts) => {
|
||||
if(contacts) {
|
||||
setResults(contacts.my_results, this.searchGroups.contacts, true);
|
||||
setResults(contacts.results, this.searchGroups.globalContacts);
|
||||
}
|
||||
}),
|
||||
|
||||
appMessagesManager.getConversations(query, 0, 20, 0)
|
||||
.then(onLoad)
|
||||
.then(value => {
|
||||
if(value) {
|
||||
setResults(value.dialogs.map(d => d.peerId), this.searchGroups.contacts, true);
|
||||
}
|
||||
})
|
||||
]);
|
||||
} else {
|
||||
const renderRecentSearch = (setActive = true) => {
|
||||
return appStateManager.getState().then(state => {
|
||||
if(!middleware()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.searchGroups.recent.list.innerHTML = '';
|
||||
|
||||
state.recentSearch.slice(0, 20).forEach(peerId => {
|
||||
let {dialog, dom} = appDialogsManager.addDialogNew({
|
||||
dialog: peerId,
|
||||
container: this.searchGroups.recent.list,
|
||||
drawStatus: false,
|
||||
meAsSaved: true,
|
||||
avatarSize: 48,
|
||||
autonomous: false
|
||||
});
|
||||
|
||||
dom.lastMessageSpan.innerText = peerId > 0 ? appUsersManager.getUserStatusString(peerId) : appChatsManager.getChatMembersString(peerId);
|
||||
});
|
||||
|
||||
if(!state.recentSearch.length) {
|
||||
this.searchGroups.recent.clear();
|
||||
} else if(setActive) {
|
||||
this.searchGroups.recent.setActive();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return Promise.all([
|
||||
appUsersManager.getTopPeers().then(peers => {
|
||||
if(!middleware()) return;
|
||||
|
||||
//console.log('got top categories:', categories);
|
||||
if(peers.length) {
|
||||
peers.forEach((peerId) => {
|
||||
appDialogsManager.addDialogNew({
|
||||
dialog: peerId,
|
||||
container: this.searchGroups.people.list,
|
||||
drawStatus: false,
|
||||
onlyFirstName: true,
|
||||
avatarSize: 54,
|
||||
autonomous: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.searchGroups.people.setActive();
|
||||
}),
|
||||
|
||||
renderRecentSearch()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public load(single = false, justLoad = false) {
|
||||
if(testScroll/* || 1 == 1 */) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('loadSidebarMedia', single, this.peerId, this.loadPromises);
|
||||
const peerId = this.searchContext.peerId;
|
||||
this.log('load', single, peerId, this.loadPromises);
|
||||
|
||||
const peerId = this.peerId;
|
||||
const threadId = this.threadId;
|
||||
|
||||
let typesToLoad = single ? [this.type] : this.types.filter(t => t.inputFilter !== this.type && t.inputFilter !== 'inputMessagesFilterEmpty').map(t => t.inputFilter);
|
||||
let typesToLoad = single ? [this.type] : this.types.filter(t => t.inputFilter !== this.type).map(t => t.inputFilter);
|
||||
typesToLoad = typesToLoad.filter(type => !this.loaded[type]
|
||||
|| this.usedFromHistory[type] < this.historyStorage[type].length);
|
||||
|| (this.historyStorage[type] && this.usedFromHistory[type] < this.historyStorage[type].length));
|
||||
|
||||
if(!typesToLoad.length) return;
|
||||
|
||||
@ -546,12 +775,26 @@ export default class AppSearchSuper {
|
||||
|
||||
const historyStorage = this.historyStorage ?? (this.historyStorage = {});
|
||||
|
||||
const promises = typesToLoad.map(type => {
|
||||
const middleware = this.getMiddleware();
|
||||
|
||||
const promises: Promise<any>[] = typesToLoad.map(type => {
|
||||
if(this.loadPromises[type]) return this.loadPromises[type];
|
||||
|
||||
|
||||
const history = historyStorage[type] ?? (historyStorage[type] = []);
|
||||
|
||||
const logStr = 'loadSidebarMedia [' + type + ']: ';
|
||||
if(type === 'inputMessagesFilterEmpty' && !history.length) {
|
||||
if(!this.loadedChats) {
|
||||
this.loadChats();
|
||||
this.loadedChats = true;
|
||||
}
|
||||
|
||||
if(!this.searchContext.query.trim()) {
|
||||
this.loaded[type] = true;
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
const logStr = 'load [' + type + ']: ';
|
||||
|
||||
// render from cache
|
||||
if(history.length && this.usedFromHistory[type] < history.length && !justLoad) {
|
||||
@ -561,11 +804,11 @@ export default class AppSearchSuper {
|
||||
|
||||
do {
|
||||
let ids = history.slice(used, used + loadCount);
|
||||
console.log(logStr + 'will render from cache', used, history, ids, loadCount);
|
||||
//this.log(logStr + 'will render from cache', used, history, ids, loadCount);
|
||||
used += ids.length;
|
||||
slicedLength += ids.length;
|
||||
|
||||
messages.push(...this.filterMessagesByType(ids, type));
|
||||
messages.push(...this.filterMessagesByType(ids.map(m => appMessagesManager.getMessageByPeer(m.peerId, m.mid)), type));
|
||||
} while(slicedLength < loadCount && used < history.length);
|
||||
|
||||
// если перебор
|
||||
@ -577,36 +820,49 @@ export default class AppSearchSuper {
|
||||
|
||||
this.usedFromHistory[type] = used;
|
||||
//if(messages.length) {
|
||||
return this.performSearchResult(messages, type);
|
||||
return this.performSearchResult(messages, type).finally(() => {
|
||||
setTimeout(() => {
|
||||
this.scrollable.checkForTriggers();
|
||||
}, 0);
|
||||
});
|
||||
//}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let maxId = history[history.length - 1] || 0;
|
||||
let maxId = history.length ? history[history.length - 1].mid : 0;
|
||||
|
||||
console.log(logStr + 'search house of glass pre', type, maxId);
|
||||
//this.log(logStr + 'search house of glass pre', type, maxId);
|
||||
|
||||
//let loadCount = history.length ? 50 : 15;
|
||||
return this.loadPromises[type] = appMessagesManager.getSearch(peerId, '', {_: type}, maxId, loadCount, undefined, undefined/* , this.threadId */)
|
||||
.then(value => {
|
||||
const mids = value.history.map(message => message.mid);
|
||||
history.push(...mids);
|
||||
return this.loadPromises[type] = appMessagesManager.getSearchNew({
|
||||
peerId,
|
||||
query: this.searchContext.query,
|
||||
inputFilter: {_: type},
|
||||
maxId,
|
||||
limit: loadCount,
|
||||
nextRate: this.nextRates[type] ?? (this.nextRates[type] = 0),
|
||||
threadId: this.searchContext.threadId,
|
||||
folderId: this.searchContext.folderId
|
||||
}).then(value => {
|
||||
history.push(...value.history.map(m => ({mid: m.mid, peerId: m.peerId})));
|
||||
|
||||
console.log(logStr + 'search house of glass', type, value);
|
||||
this.log(logStr + 'search house of glass', type, value);
|
||||
|
||||
if(this.peerId !== peerId || this.threadId !== threadId) {
|
||||
//console.warn('peer changed');
|
||||
if(!middleware()) {
|
||||
//this.log.warn('peer changed');
|
||||
return;
|
||||
}
|
||||
|
||||
// ! Фикс случая, когда не загружаются документы при открытой панели разработчиков (происходит из-за того, что не совпадают критерии отбора документов в getSearch)
|
||||
if(value.history.length < loadCount) {
|
||||
//if((value.count || history.length == value.count) && history.length >= value.count) {
|
||||
console.log(logStr + 'loaded all media', value, loadCount);
|
||||
//this.log(logStr + 'loaded all media', value, loadCount);
|
||||
this.loaded[type] = true;
|
||||
}
|
||||
|
||||
this.nextRates[type] = value.next_rate;
|
||||
|
||||
if(justLoad) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@ -616,46 +872,89 @@ export default class AppSearchSuper {
|
||||
if(!this.loaded[type]) {
|
||||
this.loadPromises[type].then(() => {
|
||||
setTimeout(() => {
|
||||
console.log('will preload more');
|
||||
const promise = this.load(true, true);
|
||||
if(promise) {
|
||||
promise.then(() => {
|
||||
console.log('preloaded more');
|
||||
this.scrollable.checkForTriggers();
|
||||
});
|
||||
//this.log('will preload more');
|
||||
if(this.type === type) {
|
||||
const promise = this.load(true, true);
|
||||
if(promise) {
|
||||
promise.then(() => {
|
||||
//this.log('preloaded more');
|
||||
setTimeout(() => {
|
||||
this.scrollable.checkForTriggers();
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
//if(value.history.length) {
|
||||
return this.performSearchResult(this.filterMessagesByType(mids, type), type);
|
||||
return this.performSearchResult(this.filterMessagesByType(value.history, type), type);
|
||||
//}
|
||||
}).catch(err => {
|
||||
console.error('load error:', err);
|
||||
this.log.error('load error:', err);
|
||||
}).finally(() => {
|
||||
this.loadPromises[type] = null;
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(promises).catch(err => {
|
||||
console.error('Load error all promises:', err);
|
||||
this.log.error('Load error all promises:', err);
|
||||
});
|
||||
}
|
||||
|
||||
public getMonthContainerByTimestamp(timestamp: number, type: SearchSuperType) {
|
||||
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 str = months[date.getMonth()] + ' ' + date.getFullYear();
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.className = 'search-super-month';
|
||||
|
||||
const name = document.createElement('div');
|
||||
name.classList.add('search-super-month-name');
|
||||
name.innerText = str;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
containers[dateTimestamp] = {container, items};
|
||||
positionElementByIndex(container, this.tabs[type], i);
|
||||
}
|
||||
|
||||
return containers[dateTimestamp];
|
||||
}
|
||||
|
||||
public cleanup() {
|
||||
this.loadPromises = {};
|
||||
this.loaded = {};
|
||||
this.loadedChats = false;
|
||||
this.nextRates = {};
|
||||
|
||||
this.prevTabId = -1;
|
||||
this.mediaDivsByIds = {};
|
||||
this.lazyLoadQueue.clear();
|
||||
|
||||
this.types.forEach(type => {
|
||||
this.usedFromHistory[type.inputFilter] = -1;
|
||||
});
|
||||
|
||||
this.type = 'inputMessagesFilterPhotoVideo';
|
||||
this.cleanupObj.cleaned = true;
|
||||
this.cleanupObj = {cleaned: false};
|
||||
}
|
||||
|
||||
public cleanupHTML() {
|
||||
@ -666,11 +965,15 @@ export default class AppSearchSuper {
|
||||
this.urlsToRevoke.length = 0;
|
||||
}
|
||||
|
||||
(Object.keys(this.tabs) as MyInputMessagesFilter[]).forEach(sharedMediaType => {
|
||||
this.tabs[sharedMediaType].innerHTML = '';
|
||||
(Object.keys(this.tabs) as SearchSuperType[]).forEach(type => {
|
||||
this.tabs[type].innerHTML = '';
|
||||
|
||||
if(type === 'inputMessagesFilterEmpty') {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.historyStorage || !this.historyStorage[sharedMediaType]) {
|
||||
const parent = this.tabs[sharedMediaType].parentElement;
|
||||
if(!this.historyStorage || !this.historyStorage[type]) {
|
||||
const parent = this.tabs[type].parentElement;
|
||||
if(!testScroll) {
|
||||
if(!parent.querySelector('.preloader')) {
|
||||
putPreloader(parent, true);
|
||||
@ -683,6 +986,8 @@ export default class AppSearchSuper {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.monthContainers = {};
|
||||
|
||||
if(testScroll) {
|
||||
for(let i = 0; i < 1500; ++i) {
|
||||
@ -694,15 +999,39 @@ export default class AppSearchSuper {
|
||||
this.tabs.inputMessagesFilterPhotoVideo.append(div);
|
||||
}
|
||||
}
|
||||
|
||||
(this.tabsMenu.firstElementChild as HTMLLIElement).click(); // set media
|
||||
}
|
||||
|
||||
public setQuery(peerId: number, query: string, threadId: number, historyStorage: AppSearchSuper['historyStorage'] = {}) {
|
||||
this.peerId = peerId;
|
||||
this.query = query;
|
||||
this.threadId = threadId;
|
||||
this.historyStorage = historyStorage;
|
||||
// * will change .cleaned in cleanup() and new instance will be created
|
||||
public getMiddleware() {
|
||||
const cleanupObj = this.cleanupObj;
|
||||
return () => {
|
||||
return !cleanupObj.cleaned;
|
||||
};
|
||||
}
|
||||
|
||||
private copySearchContext(newInputFilter: MyInputMessagesFilter) {
|
||||
const context = copy(this.searchContext);
|
||||
context.inputFilter = newInputFilter;
|
||||
context.nextRate = this.nextRates[newInputFilter];
|
||||
return context;
|
||||
}
|
||||
|
||||
public setQuery({peerId, query, threadId, historyStorage, folderId}: {
|
||||
peerId: number,
|
||||
query?: string,
|
||||
threadId?: number,
|
||||
historyStorage?: AppSearchSuper['historyStorage'],
|
||||
folderId?: number
|
||||
}) {
|
||||
this.searchContext = {
|
||||
peerId: peerId || 0,
|
||||
query: query || '',
|
||||
inputFilter: this.type,
|
||||
threadId,
|
||||
folderId
|
||||
};
|
||||
|
||||
this.historyStorage = historyStorage ?? {};
|
||||
|
||||
this.cleanup();
|
||||
}
|
||||
|
@ -12,6 +12,9 @@ import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||
import rootScope from "../lib/rootScope";
|
||||
import './middleEllipsis';
|
||||
import { attachClickEvent, cancelEvent, detachClickEvent } from "../helpers/dom";
|
||||
import appPeersManager from "../lib/appManagers/appPeersManager";
|
||||
import { SearchSuperContext } from "./appSearchSuper.";
|
||||
import { formatDateAccordingToToday } from "../helpers/date";
|
||||
|
||||
rootScope.on('messages_media_read', e => {
|
||||
const {mids, peerId} = e.detail;
|
||||
@ -254,21 +257,39 @@ function wrapVoiceMessage(audioEl: AudioElement) {
|
||||
function wrapAudio(audioEl: AudioElement) {
|
||||
const withTime = audioEl.withTime;
|
||||
|
||||
const doc = audioEl.message.media.document || audioEl.message.media.webpage.document;
|
||||
const title = doc.audioTitle || doc.file_name;
|
||||
let subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : '';
|
||||
const message = audioEl.message;
|
||||
const doc: MyDocument = message.media.document || message.media.webpage.document;
|
||||
|
||||
if(withTime) {
|
||||
subtitle += (subtitle ? ' • ' : '') + formatDate(doc.date);
|
||||
} else if(!subtitle) {
|
||||
subtitle = 'Unknown Artist';
|
||||
const senderTitle = audioEl.showSender ? appMessagesManager.getSenderToPeerText(message) : '';
|
||||
|
||||
let title = doc.type === 'voice' ? senderTitle : (doc.audioTitle || doc.file_name);
|
||||
let subtitle: string;
|
||||
|
||||
if(doc.type === 'voice') {
|
||||
subtitle = '';
|
||||
} else {
|
||||
subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : '';
|
||||
if(withTime) {
|
||||
subtitle += (subtitle ? ' • ' : '') + formatDate(doc.date);
|
||||
} else if(!subtitle) {
|
||||
subtitle = 'Unknown Artist';
|
||||
}
|
||||
|
||||
if(audioEl.showSender) {
|
||||
subtitle += ' • ' + senderTitle;
|
||||
} else {
|
||||
subtitle = ' • ' + subtitle;
|
||||
}
|
||||
}
|
||||
|
||||
subtitle = ' • ' + subtitle;
|
||||
let titleAdditionHTML = '';
|
||||
if(audioEl.showSender) {
|
||||
titleAdditionHTML = `<div class="sent-time">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;
|
||||
}
|
||||
|
||||
const html = `
|
||||
<div class="audio-details">
|
||||
<div class="audio-title"><middle-ellipsis-element data-font-weight="${audioEl.dataset.fontWeight}">${title}</middle-ellipsis-element></div>
|
||||
<div class="audio-title"><middle-ellipsis-element data-font-weight="${audioEl.dataset.fontWeight}">${title}</middle-ellipsis-element>${titleAdditionHTML}</div>
|
||||
<div class="audio-subtitle"><div class="audio-time"></div>${subtitle}</div>
|
||||
</div>`;
|
||||
|
||||
@ -319,6 +340,9 @@ export default class AudioElement extends HTMLElement {
|
||||
public preloader: ProgressivePreloader;
|
||||
public message: any;
|
||||
public withTime = false;
|
||||
public voiceAsMusic = false;
|
||||
public searchContext: SearchSuperContext;
|
||||
public showSender = false;
|
||||
|
||||
private attachedHandlers: {[name: string]: any[]} = {};
|
||||
private onTypeDisconnect: () => void;
|
||||
@ -332,7 +356,7 @@ export default class AudioElement extends HTMLElement {
|
||||
this.classList.add('audio');
|
||||
|
||||
const doc = this.message.media.document || this.message.media.webpage.document;
|
||||
const isVoice = doc.type == 'voice';
|
||||
const isVoice = !this.voiceAsMusic && doc.type == 'voice';
|
||||
const uploading = this.message.pFlags.is_outgoing;
|
||||
|
||||
const durationStr = String(doc.duration | 0).toHHMMSS();
|
||||
|
@ -52,7 +52,13 @@ export default class AvatarElement extends HTMLElement {
|
||||
if(peerId < 0) {
|
||||
const maxId = Number.MAX_SAFE_INTEGER;
|
||||
const inputFilter = 'inputMessagesFilterChatPhotos';
|
||||
let message: any = await appMessagesManager.getSearch(peerId, '', {_: inputFilter}, maxId, 2, 0, 1).then(value => {
|
||||
let message: any = await appMessagesManager.getSearchNew({
|
||||
peerId,
|
||||
inputFilter: {_: inputFilter},
|
||||
maxId,
|
||||
limit: 2,
|
||||
backLimit: 1
|
||||
}).then(value => {
|
||||
//console.log(lol);
|
||||
// ! by descend
|
||||
return value.history[0];
|
||||
@ -78,7 +84,12 @@ export default class AvatarElement extends HTMLElement {
|
||||
}
|
||||
|
||||
const good = Array.from(this.querySelectorAll('img')).find(img => !img.classList.contains('emoji'));
|
||||
new AppMediaViewer(inputFilter).openMedia(message, good ? this : null);
|
||||
new AppMediaViewer()
|
||||
.setSearchContext({
|
||||
peerId,
|
||||
inputFilter,
|
||||
})
|
||||
.openMedia(message, good ? this : null);
|
||||
loading = false;
|
||||
return;
|
||||
}
|
||||
|
@ -586,7 +586,7 @@ export default class ChatBubbles {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets: {element: HTMLElement, mid: number}[] = [];
|
||||
let targets: {element: HTMLElement, mid: number, peerId: number}[] = [];
|
||||
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => {
|
||||
//if(!this.scrollable.visibleElements.find(e => e.element == this.bubbles[id])) return false;
|
||||
|
||||
@ -609,7 +609,8 @@ export default class ChatBubbles {
|
||||
let albumItem = findUpClassName(element, 'album-item');
|
||||
targets.push({
|
||||
element,
|
||||
mid: +albumItem?.dataset.mid || id
|
||||
mid: +albumItem?.dataset.mid || id,
|
||||
peerId: this.peerId
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -625,8 +626,13 @@ export default class ChatBubbles {
|
||||
return;
|
||||
}
|
||||
|
||||
new AppMediaViewer().openMedia(message, targets[idx].element, true,
|
||||
targets.slice(0, idx), targets.slice(idx + 1), undefined, this.chat.threadId/* , !message.grouped_id */);
|
||||
new AppMediaViewer()
|
||||
.setSearchContext({
|
||||
threadId: this.chat.threadId,
|
||||
peerId: this.peerId,
|
||||
inputFilter: 'inputMessagesFilterPhotoVideo'
|
||||
})
|
||||
.openMedia(message, targets[idx].element, 0, true, targets.slice(0, idx), targets.slice(idx + 1));
|
||||
|
||||
cancelEvent(e);
|
||||
//appMediaViewer.openMedia(message, target as HTMLImageElement);
|
||||
@ -2344,7 +2350,13 @@ export default class ChatBubbles {
|
||||
if(this.chat.type === 'chat' || this.chat.type === 'discussion') {
|
||||
return this.appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit, this.chat.threadId);
|
||||
} else if(this.chat.type === 'pinned') {
|
||||
const promise = this.appMessagesManager.getSearch(this.peerId, '', {_: 'inputMessagesFilterPinned'}, maxId, loadCount, 0, backLimit)
|
||||
const promise = this.appMessagesManager.getSearchNew({
|
||||
peerId: this.peerId,
|
||||
inputFilter: {_: 'inputMessagesFilterPinned'},
|
||||
maxId,
|
||||
limit: loadCount,
|
||||
backLimit
|
||||
})
|
||||
.then(value => ({history: value.history.map(m => m.mid)}));
|
||||
|
||||
return promise;
|
||||
|
@ -410,7 +410,13 @@ export default class ChatPinnedMessage {
|
||||
try {
|
||||
let gotRest = false;
|
||||
const promises = [
|
||||
this.appMessagesManager.getSearch(this.topbar.peerId, '', {_: 'inputMessagesFilterPinned'}, mid, ChatPinnedMessage.LOAD_COUNT, 0, ChatPinnedMessage.LOAD_COUNT)
|
||||
this.appMessagesManager.getSearchNew({
|
||||
peerId: this.topbar.peerId,
|
||||
inputFilter: {_: 'inputMessagesFilterPinned'},
|
||||
maxId: mid,
|
||||
limit: ChatPinnedMessage.LOAD_COUNT,
|
||||
backLimit: ChatPinnedMessage.LOAD_COUNT
|
||||
})
|
||||
.then(r => {
|
||||
gotRest = true;
|
||||
return r;
|
||||
|
@ -5,6 +5,54 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?
|
||||
const selectTab = TransitionSlider(content, tabs || content.dataset.slider == 'tabs' ? 'tabs' : 'navigation', transitionTime, onTransitionEnd);
|
||||
|
||||
if(tabs) {
|
||||
const proxy = new Proxy(selectTab, {
|
||||
apply: (target, that, args) => {
|
||||
const id = +args[0];
|
||||
const animate = args[1] !== undefined ? args[1] : true;
|
||||
|
||||
const el = (tabs.querySelector(`[data-tab="${id}"]`) || tabs.children[id]) as HTMLElement;
|
||||
selectTarget(el, id, animate);
|
||||
}
|
||||
});
|
||||
|
||||
const selectTarget = (target: HTMLElement, id: number, animate = true) => {
|
||||
const tabContent = content.children[id] as HTMLDivElement;
|
||||
|
||||
if(onClick) onClick(id, tabContent);
|
||||
if(target.classList.contains('active') || id === selectTab.prevId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const prev = tabs.querySelector(tagName.toLowerCase() + '.active') as HTMLElement;
|
||||
prev && prev.classList.remove('active');
|
||||
|
||||
// stripe from ZINCHUK
|
||||
if(useStripe && selectTab.prevId !== -1 && animate) {
|
||||
const indicator = target.querySelector('i')!;
|
||||
const currentIndicator = target.parentElement.children[selectTab.prevId].querySelector('i')!;
|
||||
|
||||
currentIndicator.classList.remove('animate');
|
||||
indicator.classList.remove('animate');
|
||||
|
||||
// We move and resize our indicator so it repeats the position and size of the previous one.
|
||||
const shiftLeft = currentIndicator.parentElement.parentElement.offsetLeft - indicator.parentElement.parentElement.offsetLeft;
|
||||
const scaleFactor = currentIndicator.clientWidth / indicator.clientWidth;
|
||||
indicator.style.transform = `translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`;
|
||||
|
||||
//console.log(`translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
// Now we remove the transform to let it animate to its own position and size.
|
||||
indicator.classList.add('animate');
|
||||
indicator.style.transform = 'none';
|
||||
});
|
||||
}
|
||||
// stripe END
|
||||
|
||||
target.classList.add('active');
|
||||
selectTab(id, animate);
|
||||
};
|
||||
|
||||
const useStripe = !tabs.classList.contains('no-stripe');
|
||||
|
||||
const tagName = tabs.classList.contains('menu-horizontal-div') ? 'BUTTON' : 'LI';//tabs.firstElementChild.tagName;
|
||||
@ -29,42 +77,10 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?
|
||||
id = whichChild(target);
|
||||
}
|
||||
|
||||
const tabContent = content.children[id] as HTMLDivElement;
|
||||
|
||||
if(onClick) onClick(id, tabContent);
|
||||
if(target.classList.contains('active') || id == selectTab.prevId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const prev = tabs.querySelector(tagName.toLowerCase() + '.active') as HTMLElement;
|
||||
prev && prev.classList.remove('active');
|
||||
|
||||
// stripe from ZINCHUK
|
||||
if(useStripe && selectTab.prevId != -1) {
|
||||
const indicator = target.querySelector('i')!;
|
||||
const currentIndicator = target.parentElement.children[selectTab.prevId].querySelector('i')!;
|
||||
|
||||
currentIndicator.classList.remove('animate');
|
||||
indicator.classList.remove('animate');
|
||||
|
||||
// We move and resize our indicator so it repeats the position and size of the previous one.
|
||||
const shiftLeft = currentIndicator.parentElement.parentElement.offsetLeft - indicator.parentElement.parentElement.offsetLeft;
|
||||
const scaleFactor = currentIndicator.clientWidth / indicator.clientWidth;
|
||||
indicator.style.transform = `translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`;
|
||||
|
||||
//console.log(`translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
// Now we remove the transform to let it animate to its own position and size.
|
||||
indicator.classList.add('animate');
|
||||
indicator.style.transform = 'none';
|
||||
});
|
||||
}
|
||||
// stripe END
|
||||
|
||||
target.classList.add('active');
|
||||
selectTab(id);
|
||||
selectTarget(target, id);
|
||||
});
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
return selectTab;
|
||||
|
@ -45,7 +45,7 @@ export default class InputSearch {
|
||||
|
||||
//this.input.classList.toggle('is-empty', !value.trim());
|
||||
|
||||
if(value != this.prevValue) {
|
||||
if(value !== this.prevValue) {
|
||||
this.prevValue = value;
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = window.setTimeout(() => {
|
||||
|
@ -12,7 +12,7 @@ import { attachClickEvent, findUpClassName, findUpTag } from "../../helpers/dom"
|
||||
import AppSearch, { SearchGroup } from "../appSearch";
|
||||
import "../avatar";
|
||||
import { parseMenuButtonsTo } from "../misc";
|
||||
import { ScrollableX } from "../scrollable";
|
||||
import Scrollable, { ScrollableX } from "../scrollable";
|
||||
import InputSearch from "../inputSearch";
|
||||
import SidebarSlider from "../slider";
|
||||
import { TransitionSlider } from "../transition";
|
||||
@ -28,6 +28,7 @@ import AppNewGroupTab from "./tabs/newGroup";
|
||||
import AppSettingsTab from "./tabs/settings";
|
||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||
import apiManagerProxy from "../../lib/mtproto/mtprotoworker";
|
||||
import AppSearchSuper from "../appSearchSuper.";
|
||||
|
||||
const newChannelTab = new AppNewChannelTab();
|
||||
const addMembersTab = new AppAddMembersTab();
|
||||
@ -39,30 +40,6 @@ const editFolderTab = new AppEditFolderTab();
|
||||
const includedChatsTab = new AppIncludedChatsTab();
|
||||
const archivedTab = new AppArchivedTab();
|
||||
|
||||
/* const Transition = (container: HTMLElement, duration: number, from: HTMLElement, to: HTMLElement) => {
|
||||
if(to.classList.contains('active')) return Promise.resolve();
|
||||
|
||||
container.classList.add('animating');
|
||||
|
||||
const backwards = whichChild(to) < whichChild(from);
|
||||
|
||||
if(backwards) {
|
||||
container.classList.add('backwards');
|
||||
}
|
||||
|
||||
from.classList.add('from');
|
||||
to.classList.add('to');
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
from.classList.remove('from', 'active');
|
||||
container.classList.remove('animating', 'backwards');
|
||||
to.classList.replace('to', 'active');
|
||||
resolve();
|
||||
}, duration);
|
||||
});
|
||||
}; */
|
||||
|
||||
export class AppSidebarLeft extends SidebarSlider {
|
||||
public static SLIDERITEMSIDS = {
|
||||
archived: 1,
|
||||
@ -79,7 +56,6 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
|
||||
private toolsBtn: HTMLButtonElement;
|
||||
private backBtn: HTMLButtonElement;
|
||||
private searchContainer: HTMLDivElement;
|
||||
//private searchInput = document.getElementById('global-search') as HTMLInputElement;
|
||||
private inputSearch: InputSearch;
|
||||
|
||||
@ -115,12 +91,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
//private log = logger('SL');
|
||||
|
||||
private searchGroups: {[k in 'contacts' | 'globalContacts' | 'messages' | 'people' | 'recent']: SearchGroup} = {} as any;
|
||||
private globalSearch: AppSearch;
|
||||
|
||||
// peerIds
|
||||
private recentSearch: number[] = [];
|
||||
private recentSearchLoaded = false;
|
||||
private recentSearchClearBtn: HTMLElement;
|
||||
searchSuper: AppSearchSuper;
|
||||
|
||||
constructor() {
|
||||
super(document.getElementById('column-left') as HTMLDivElement);
|
||||
@ -146,7 +117,6 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
|
||||
this.toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;
|
||||
this.backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;
|
||||
this.searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;
|
||||
|
||||
this.archivedTab = archivedTab;
|
||||
this.newChannelTab = newChannelTab;
|
||||
@ -161,138 +131,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
this.menuEl = this.toolsBtn.querySelector('.btn-menu');
|
||||
this.newBtnMenu = this.sidebarEl.querySelector('#new-menu');
|
||||
|
||||
this.inputSearch.input.addEventListener('focus', () => {
|
||||
this.searchGroups = {
|
||||
//saved: new SearchGroup('', 'contacts'),
|
||||
contacts: new SearchGroup('Chats', 'contacts'),
|
||||
globalContacts: new SearchGroup('Global Search', 'contacts'),
|
||||
messages: new SearchGroup('Global Search', 'messages'),
|
||||
people: new SearchGroup('People', 'contacts', false, 'search-group-people', true, false),
|
||||
recent: new SearchGroup('Recent', 'contacts', false, 'search-group-recent', true, false)
|
||||
};
|
||||
|
||||
this.globalSearch = new AppSearch(this.searchContainer, this.inputSearch, this.searchGroups, (count) => {
|
||||
if(!count && !this.inputSearch.value.trim()) {
|
||||
this.globalSearch.reset();
|
||||
this.searchGroups.people.toggle();
|
||||
this.renderRecentSearch();
|
||||
}
|
||||
});
|
||||
this.searchContainer.addEventListener('click', (e) => {
|
||||
const target = findUpTag(e.target, 'LI') as HTMLElement;
|
||||
if(!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
const searchGroup = findUpClassName(target, 'search-group');
|
||||
if(!searchGroup || searchGroup.classList.contains('search-group-recent') || searchGroup.classList.contains('search-group-people')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const peerId = +target.getAttribute('data-peerId');
|
||||
if(this.recentSearch[0] != peerId) {
|
||||
this.recentSearch.findAndSplice(p => p == peerId);
|
||||
this.recentSearch.unshift(peerId);
|
||||
if(this.recentSearch.length > 20) {
|
||||
this.recentSearch.length = 20;
|
||||
}
|
||||
|
||||
this.renderRecentSearch();
|
||||
appStateManager.pushToState('recentSearch', this.recentSearch);
|
||||
for(const peerId of this.recentSearch) {
|
||||
appStateManager.setPeer(peerId, appPeersManager.getPeer(peerId));
|
||||
}
|
||||
|
||||
clearRecentSearchBtn.style.display = '';
|
||||
}
|
||||
}, {capture: true});
|
||||
|
||||
let peopleContainer = document.createElement('div');
|
||||
peopleContainer.classList.add('search-group-scrollable');
|
||||
peopleContainer.append(this.searchGroups.people.list);
|
||||
this.searchGroups.people.container.append(peopleContainer);
|
||||
let peopleScrollable = new ScrollableX(peopleContainer);
|
||||
|
||||
appUsersManager.getTopPeers().then(peers => {
|
||||
//console.log('got top categories:', categories);
|
||||
if(peers.length) {
|
||||
peers.forEach((peerId) => {
|
||||
appDialogsManager.addDialogNew({
|
||||
dialog: peerId,
|
||||
container: this.searchGroups.people.list,
|
||||
drawStatus: false,
|
||||
onlyFirstName: true,
|
||||
avatarSize: 54,
|
||||
autonomous: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.searchGroups.people.toggle();
|
||||
});
|
||||
|
||||
let hideNewBtnMenuTimeout: number;
|
||||
//const transition = Transition.bind(null, this.searchContainer.parentElement, 150);
|
||||
const transition = TransitionSlider(this.searchContainer.parentElement, 'zoom-fade', 150, (id) => {
|
||||
if(hideNewBtnMenuTimeout) clearTimeout(hideNewBtnMenuTimeout);
|
||||
|
||||
if(id == 0) {
|
||||
this.globalSearch.reset();
|
||||
hideNewBtnMenuTimeout = window.setTimeout(() => {
|
||||
hideNewBtnMenuTimeout = 0;
|
||||
this.newBtnMenu.classList.remove('is-hidden');
|
||||
}, 150);
|
||||
}
|
||||
});
|
||||
|
||||
transition(0);
|
||||
|
||||
const onFocus = () => {
|
||||
this.toolsBtn.classList.remove('active');
|
||||
this.backBtn.classList.add('active');
|
||||
this.newBtnMenu.classList.add('is-hidden');
|
||||
|
||||
transition(1);
|
||||
|
||||
if(firstTime) {
|
||||
this.searchGroups.people.toggle();
|
||||
this.renderRecentSearch();
|
||||
firstTime = false;
|
||||
}
|
||||
|
||||
/* this.searchInput.addEventListener('blur', (e) => {
|
||||
if(!this.searchInput.value) {
|
||||
this.toolsBtn.classList.add('active');
|
||||
this.backBtn.classList.remove('active');
|
||||
this.backBtn.click();
|
||||
}
|
||||
}, {once: true}); */
|
||||
};
|
||||
|
||||
let firstTime = true;
|
||||
this.inputSearch.input.addEventListener('focus', onFocus);
|
||||
onFocus();
|
||||
|
||||
this.backBtn.addEventListener('click', (e) => {
|
||||
//appDialogsManager.chatsArchivedContainer.classList.remove('active');
|
||||
this.toolsBtn.classList.add('active');
|
||||
this.backBtn.classList.remove('active');
|
||||
firstTime = true;
|
||||
|
||||
transition(0);
|
||||
});
|
||||
|
||||
this.renderRecentSearch();
|
||||
const clearRecentSearchBtn = this.recentSearchClearBtn = document.createElement('button');
|
||||
clearRecentSearchBtn.classList.add('btn-icon', 'tgico-close');
|
||||
this.searchGroups.recent.nameEl.append(clearRecentSearchBtn);
|
||||
clearRecentSearchBtn.addEventListener('click', () => {
|
||||
this.recentSearch = [];
|
||||
appStateManager.pushToState('recentSearch', this.recentSearch);
|
||||
this.renderRecentSearch(false);
|
||||
clearRecentSearchBtn.style.display = 'none';
|
||||
});
|
||||
}, {once: true});
|
||||
this.inputSearch.input.addEventListener('focus', () => this.initSearch(), {once: true});
|
||||
|
||||
parseMenuButtonsTo(this.buttons, this.menuEl.children);
|
||||
parseMenuButtonsTo(this.newButtons, this.newBtnMenu.firstElementChild.children);
|
||||
@ -339,38 +178,133 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
appUsersManager.getTopPeers();
|
||||
}
|
||||
|
||||
public renderRecentSearch(setActive = true) {
|
||||
appStateManager.getState().then(state => {
|
||||
if(state && !this.recentSearchLoaded && Array.isArray(state.recentSearch)) {
|
||||
this.recentSearch = state.recentSearch;
|
||||
this.recentSearchLoaded = true;
|
||||
}
|
||||
private initSearch() {
|
||||
const searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;
|
||||
|
||||
if(this.inputSearch.value.trim()) {
|
||||
const scrollable = new Scrollable(searchContainer);
|
||||
|
||||
this.searchGroups = {
|
||||
contacts: new SearchGroup('Chats', 'contacts'),
|
||||
globalContacts: new SearchGroup('Global Search', 'contacts'),
|
||||
messages: new SearchGroup('Messages', 'messages'),
|
||||
people: new SearchGroup('', 'contacts', true, 'search-group-people', true, false),
|
||||
recent: new SearchGroup('Recent', 'contacts', true, 'search-group-recent', true, false)
|
||||
};
|
||||
|
||||
const searchSuper = this.searchSuper = new AppSearchSuper([{
|
||||
inputFilter: 'inputMessagesFilterEmpty',
|
||||
name: 'Chats'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterPhotoVideo',
|
||||
name: 'Media'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterUrl',
|
||||
name: 'Links'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterDocument',
|
||||
name: 'Files'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterMusic',
|
||||
name: 'Music'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterVoice',
|
||||
name: 'Voice'
|
||||
}], scrollable, this.searchGroups, true);
|
||||
|
||||
scrollable.container.append(searchSuper.container);
|
||||
|
||||
searchSuper.setQuery({
|
||||
peerId: 0,
|
||||
folderId: 0
|
||||
});
|
||||
searchSuper.selectTab(0);
|
||||
searchSuper.load(true);
|
||||
|
||||
this.inputSearch.onChange = (value) => {
|
||||
searchSuper.cleanupHTML();
|
||||
searchSuper.setQuery({
|
||||
peerId: 0,
|
||||
folderId: 0,
|
||||
query: value
|
||||
});
|
||||
searchSuper.load(true);
|
||||
};
|
||||
|
||||
searchSuper.tabs.inputMessagesFilterEmpty.addEventListener('click', (e) => {
|
||||
const target = findUpTag(e.target, 'LI') as HTMLElement;
|
||||
if(!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.searchGroups.recent.list.innerHTML = '';
|
||||
this.recentSearchClearBtn.style.display = this.recentSearch.length ? '' : 'none';
|
||||
|
||||
this.recentSearch.slice(0, 20).forEach(peerId => {
|
||||
let {dialog, dom} = appDialogsManager.addDialogNew({
|
||||
dialog: peerId,
|
||||
container: this.searchGroups.recent.list,
|
||||
drawStatus: false,
|
||||
meAsSaved: true,
|
||||
avatarSize: 48,
|
||||
autonomous: false
|
||||
});
|
||||
|
||||
dom.lastMessageSpan.innerText = peerId > 0 ? appUsersManager.getUserStatusString(peerId) : appChatsManager.getChatMembersString(peerId);
|
||||
});
|
||||
|
||||
if(!this.recentSearch.length) {
|
||||
this.searchGroups.recent.clear();
|
||||
} else if(setActive) {
|
||||
this.searchGroups.recent.setActive();
|
||||
const searchGroup = findUpClassName(target, 'search-group');
|
||||
if(!searchGroup || searchGroup.classList.contains('search-group-recent') || searchGroup.classList.contains('search-group-people')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const peerId = +target.getAttribute('data-peerId');
|
||||
appStateManager.getState().then(state => {
|
||||
const recentSearch = state.recentSearch || [];
|
||||
if(recentSearch[0] != peerId) {
|
||||
recentSearch.findAndSplice(p => p == peerId);
|
||||
recentSearch.unshift(peerId);
|
||||
if(recentSearch.length > 20) {
|
||||
recentSearch.length = 20;
|
||||
}
|
||||
|
||||
appStateManager.pushToState('recentSearch', recentSearch);
|
||||
for(const peerId of recentSearch) {
|
||||
appStateManager.setPeer(peerId, appPeersManager.getPeer(peerId));
|
||||
}
|
||||
}
|
||||
});
|
||||
}, {capture: true});
|
||||
|
||||
let peopleContainer = document.createElement('div');
|
||||
peopleContainer.classList.add('search-group-scrollable');
|
||||
peopleContainer.append(this.searchGroups.people.list);
|
||||
this.searchGroups.people.container.append(peopleContainer);
|
||||
let peopleScrollable = new ScrollableX(peopleContainer);
|
||||
|
||||
let hideNewBtnMenuTimeout: number;
|
||||
//const transition = Transition.bind(null, searchContainer.parentElement, 150);
|
||||
const transition = TransitionSlider(searchContainer.parentElement, 'zoom-fade', 150, (id) => {
|
||||
if(hideNewBtnMenuTimeout) clearTimeout(hideNewBtnMenuTimeout);
|
||||
|
||||
if(id === 0) {
|
||||
this.inputSearch.onClearClick();
|
||||
hideNewBtnMenuTimeout = window.setTimeout(() => {
|
||||
hideNewBtnMenuTimeout = 0;
|
||||
this.newBtnMenu.classList.remove('is-hidden');
|
||||
}, 150);
|
||||
}
|
||||
});
|
||||
|
||||
transition(0);
|
||||
|
||||
const onFocus = () => {
|
||||
this.toolsBtn.classList.remove('active');
|
||||
this.backBtn.classList.add('active');
|
||||
this.newBtnMenu.classList.add('is-hidden');
|
||||
|
||||
transition(1);
|
||||
};
|
||||
|
||||
this.inputSearch.input.addEventListener('focus', onFocus);
|
||||
onFocus();
|
||||
|
||||
this.backBtn.addEventListener('click', (e) => {
|
||||
this.toolsBtn.classList.add('active');
|
||||
this.backBtn.classList.remove('active');
|
||||
|
||||
transition(0);
|
||||
});
|
||||
|
||||
const clearRecentSearchBtn = document.createElement('button');
|
||||
clearRecentSearchBtn.classList.add('btn-icon', 'tgico-close');
|
||||
this.searchGroups.recent.nameEl.append(clearRecentSearchBtn);
|
||||
clearRecentSearchBtn.addEventListener('click', () => {
|
||||
this.searchGroups.recent.clear();
|
||||
appStateManager.pushToState('recentSearch', []);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import appImManager from "../../../lib/appManagers/appImManager";
|
||||
import appMessagesManager, { MyInputMessagesFilter } from "../../../lib/appManagers/appMessagesManager";
|
||||
import appMessagesManager, { MyInputMessagesFilter, MyMessage } from "../../../lib/appManagers/appMessagesManager";
|
||||
import appPeersManager from "../../../lib/appManagers/appPeersManager";
|
||||
import appProfileManager from "../../../lib/appManagers/appProfileManager";
|
||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||
import { logger } from "../../../lib/logger";
|
||||
import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
||||
import rootScope from "../../../lib/rootScope";
|
||||
import AppSearchSuper from "../../appSearchSuper.";
|
||||
import AppSearchSuper, { SearchSuperType } from "../../appSearchSuper.";
|
||||
import AvatarElement from "../../avatar";
|
||||
import Scrollable from "../../scrollable";
|
||||
import { SliderTab } from "../../slider";
|
||||
@ -48,7 +48,7 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
|
||||
public historiesStorage: {
|
||||
[peerId: number]: Partial<{
|
||||
[type in MyInputMessagesFilter]: number[]
|
||||
[type in SearchSuperType]: {mid: number, peerId: number}[]
|
||||
}>
|
||||
} = {};
|
||||
|
||||
@ -118,13 +118,13 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
name: 'Media'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterDocument',
|
||||
name: 'Docs'
|
||||
name: 'Files'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterUrl',
|
||||
name: 'Links'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterMusic',
|
||||
name: 'Audio'
|
||||
name: 'Music'
|
||||
}], this.scroll);
|
||||
|
||||
this.profileContentEl.append(this.searchSuper.container);
|
||||
@ -155,10 +155,10 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
mids = mids.slice().reverse(); // ! because it will be ascend sorted array
|
||||
for(const type of this.searchSuper.types) {
|
||||
const inputFilter = type.inputFilter;
|
||||
const filtered = this.searchSuper.filterMessagesByType(mids, inputFilter);
|
||||
const filtered = this.searchSuper.filterMessagesByType(mids.map(mid => appMessagesManager.getMessageByPeer(peerId, mid)), inputFilter);
|
||||
if(filtered.length) {
|
||||
if(this.historiesStorage[peerId][inputFilter]) {
|
||||
this.historiesStorage[peerId][inputFilter].unshift(...mids);
|
||||
this.historiesStorage[peerId][inputFilter].unshift(...filtered.map(message => ({mid: message.mid, peerId: message.peerId})));
|
||||
}
|
||||
|
||||
if(this.peerId == peerId && this.searchSuper.usedFromHistory[inputFilter] !== -1) {
|
||||
@ -183,18 +183,14 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
if(!this.historiesStorage[peerId][inputFilter]) continue;
|
||||
|
||||
const history = this.historiesStorage[peerId][inputFilter];
|
||||
const idx = history.findIndex(m => m == mid);
|
||||
const idx = history.findIndex(m => m.mid === mid);
|
||||
if(idx !== -1) {
|
||||
history.splice(idx, 1);
|
||||
|
||||
if(this.peerId == peerId) {
|
||||
const container = this.searchSuper.tabs[inputFilter];
|
||||
const div = container.querySelector(`div[data-mid="${mid}"]`);
|
||||
const div = container.querySelector(`div[data-mid="${mid}"][data-peer-id="${peerId}"]`);
|
||||
if(div) {
|
||||
if(inputFilter == 'inputMessagesFilterPhotoVideo') {
|
||||
delete this.searchSuper.mediaDivsByIds[mid];
|
||||
}
|
||||
|
||||
div.remove();
|
||||
}
|
||||
|
||||
@ -220,6 +216,7 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
this.profileElements.notificationsStatus.innerText = 'Enabled';
|
||||
|
||||
this.searchSuper.cleanupHTML();
|
||||
this.searchSuper.selectTab(0, false);
|
||||
}
|
||||
|
||||
public setLoadMutex(promise: Promise<any>) {
|
||||
@ -236,7 +233,11 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
|
||||
this.peerId = peerId;
|
||||
this.threadId = threadId;
|
||||
this.searchSuper.setQuery(peerId, '', threadId, this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {}));
|
||||
this.searchSuper.setQuery({
|
||||
peerId,
|
||||
//threadId,
|
||||
historyStorage: this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {})
|
||||
});
|
||||
this.cleaned = true;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { getEmojiToneIndex } from '../emoji';
|
||||
import { readBlobAsText } from '../helpers/blob';
|
||||
import { deferredPromise } from '../helpers/cancellablePromise';
|
||||
import { months } from '../helpers/date';
|
||||
import { formatDateAccordingToToday, months } from '../helpers/date';
|
||||
import mediaSizes from '../helpers/mediaSizes';
|
||||
import { formatBytes } from '../helpers/number';
|
||||
import { isAppleMobile, isSafari } from '../helpers/userAgent';
|
||||
@ -28,6 +28,7 @@ import { nextRandomInt } from '../helpers/random';
|
||||
import RichTextProcessor from '../lib/richtextprocessor';
|
||||
import appImManager from '../lib/appManagers/appImManager';
|
||||
import Chat from './chat/chat';
|
||||
import { SearchSuperContext } from './appSearchSuper.';
|
||||
|
||||
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB
|
||||
|
||||
@ -343,10 +344,13 @@ export const formatDate = (timestamp: number, monthShort = false, withYear = tru
|
||||
return str + ' at ' + date.getHours() + ':' + ('0' + date.getMinutes()).slice(-2);
|
||||
};
|
||||
|
||||
export function wrapDocument({message, withTime, fontWeight}: {
|
||||
export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showSender, searchContext}: {
|
||||
message: any,
|
||||
withTime?: boolean,
|
||||
fontWeight?: number
|
||||
fontWeight?: number,
|
||||
voiceAsMusic?: boolean,
|
||||
showSender?: boolean,
|
||||
searchContext?: SearchSuperContext
|
||||
}): HTMLElement {
|
||||
if(!fontWeight) fontWeight = 500;
|
||||
|
||||
@ -359,6 +363,11 @@ export function wrapDocument({message, withTime, fontWeight}: {
|
||||
audioElement.setAttribute('peer-id', '' + message.peerId);
|
||||
audioElement.withTime = withTime;
|
||||
audioElement.message = message;
|
||||
|
||||
if(voiceAsMusic) audioElement.voiceAsMusic = voiceAsMusic;
|
||||
if(searchContext) audioElement.searchContext = searchContext;
|
||||
if(showSender) audioElement.showSender = showSender;
|
||||
|
||||
audioElement.dataset.fontWeight = '' + fontWeight;
|
||||
audioElement.render();
|
||||
return audioElement;
|
||||
@ -403,10 +412,19 @@ export function wrapDocument({message, withTime, fontWeight}: {
|
||||
if(withTime) {
|
||||
size += ' · ' + formatDate(doc.date);
|
||||
}
|
||||
|
||||
if(showSender) {
|
||||
size += ' · ' + appMessagesManager.getSenderToPeerText(message);
|
||||
}
|
||||
|
||||
let titleAdditionHTML = '';
|
||||
if(showSender) {
|
||||
titleAdditionHTML = `<div class="sent-time">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;
|
||||
}
|
||||
|
||||
docDiv.innerHTML = `
|
||||
${!uploading ? `<div class="document-download"><div class="tgico-download"></div></div>` : ''}
|
||||
<div class="document-name"><middle-ellipsis-element data-font-weight="${fontWeight}">${fileName}</middle-ellipsis-element></div>
|
||||
<div class="document-name"><middle-ellipsis-element data-font-weight="${fontWeight}">${fileName}</middle-ellipsis-element>${titleAdditionHTML}</div>
|
||||
<div class="document-size">${size}</div>
|
||||
`;
|
||||
|
||||
|
@ -1887,7 +1887,12 @@ export class AppMessagesManager {
|
||||
if(p.promise) return p.promise;
|
||||
else if(p.maxId) return Promise.resolve(p);
|
||||
|
||||
return p.promise = this.getSearch(peerId, '', {_: 'inputMessagesFilterPinned'}, 0, 1).then(result => {
|
||||
return p.promise = this.getSearchNew({
|
||||
peerId,
|
||||
inputFilter: {_: 'inputMessagesFilterPinned'},
|
||||
maxId: 0,
|
||||
limit: 1
|
||||
}).then(result => {
|
||||
p.count = result.count;
|
||||
p.maxId = result.history[0]?.mid;
|
||||
return p;
|
||||
@ -2380,8 +2385,7 @@ export class AppMessagesManager {
|
||||
|
||||
let messageWrapped = '';
|
||||
if(text) {
|
||||
// * 80 for chatlist in landscape orientation
|
||||
text = limitSymbols(text, 75, 80);
|
||||
text = limitSymbols(text, 100);
|
||||
|
||||
const entities = RichTextProcessor.parseEntities(text.replace(/\n/g, ' '));
|
||||
|
||||
@ -2396,6 +2400,21 @@ export class AppMessagesManager {
|
||||
return messageText + messageWrapped;
|
||||
}
|
||||
|
||||
public getSenderToPeerText(message: MyMessage) {
|
||||
let senderTitle = '', peerTitle: string;
|
||||
|
||||
senderTitle = message.pFlags.out ? 'You' : appPeersManager.getPeerTitle(message.fromId, false, false);
|
||||
peerTitle = appPeersManager.isAnyGroup(message.peerId) || (message.pFlags.out && message.peerId !== rootScope.myId) ?
|
||||
appPeersManager.getPeerTitle(message.peerId, false, false) :
|
||||
'';
|
||||
|
||||
if(peerTitle) {
|
||||
senderTitle += ' ➝ ' + peerTitle;
|
||||
}
|
||||
|
||||
return senderTitle;
|
||||
}
|
||||
|
||||
public wrapMessageActionText(message: any) {
|
||||
const action = message.action as MessageAction;
|
||||
|
||||
@ -2868,24 +2887,25 @@ export class AppMessagesManager {
|
||||
});
|
||||
}
|
||||
|
||||
public getSearchNew({peerId, query, inputFilter, maxId, limit, offsetRate, backLimit, threadId}: {
|
||||
peerId: number,
|
||||
maxId: number,
|
||||
public getSearchNew({peerId, query, inputFilter, maxId, limit, nextRate, backLimit, threadId, folderId}: {
|
||||
peerId?: number,
|
||||
maxId?: number,
|
||||
limit?: number,
|
||||
offsetRate?: number,
|
||||
nextRate?: number,
|
||||
backLimit?: number,
|
||||
threadId?: number,
|
||||
folderId?: number,
|
||||
query?: string,
|
||||
inputFilter?: {
|
||||
_: MyInputMessagesFilter
|
||||
},
|
||||
}) {
|
||||
return this.getSearch(peerId, query, inputFilter, maxId, limit, offsetRate, backLimit, threadId);
|
||||
return this.getSearch(peerId, query, inputFilter, maxId, limit, nextRate, backLimit, threadId, folderId);
|
||||
}
|
||||
|
||||
public getSearch(peerId = 0, query: string = '', inputFilter: {
|
||||
_: MyInputMessagesFilter
|
||||
} = {_: 'inputMessagesFilterEmpty'}, maxId: number, limit = 20, offsetRate = 0, backLimit = 0, threadId = 0): Promise<{
|
||||
} = {_: 'inputMessagesFilterEmpty'}, maxId: number, limit = 20, nextRate = 0, backLimit = 0, threadId?: number, folderId?: number): Promise<{
|
||||
count: number,
|
||||
next_rate: number,
|
||||
offset_id_offset: number,
|
||||
@ -3052,7 +3072,7 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
let apiPromise: Promise<any>;
|
||||
if(peerId || !query) {
|
||||
if(peerId && !nextRate && folderId === undefined/* || !query */) {
|
||||
apiPromise = apiManager.invokeApi('messages.search', {
|
||||
peer: appPeersManager.getInputPeerById(peerId),
|
||||
q: query || '',
|
||||
@ -3087,10 +3107,11 @@ export class AppMessagesManager {
|
||||
filter: inputFilter as any as MessagesFilter,
|
||||
min_date: 0,
|
||||
max_date: 0,
|
||||
offset_rate: offsetRate,
|
||||
offset_rate: nextRate,
|
||||
offset_peer: appPeersManager.getInputPeerById(offsetPeerId),
|
||||
offset_id: offsetId,
|
||||
limit,
|
||||
folder_id: folderId
|
||||
}, {
|
||||
//timeout: APITIMEOUT,
|
||||
noErrorBox: true
|
||||
@ -3110,7 +3131,7 @@ export class AppMessagesManager {
|
||||
storage.count = searchResult.count;
|
||||
}
|
||||
|
||||
this.log('messages.search result:', inputFilter, searchResult);
|
||||
this.log('getSearch result:', inputFilter, searchResult);
|
||||
|
||||
const foundCount: number = searchResult.count || (foundMsgs.length + searchResult.messages.length);
|
||||
|
||||
@ -4298,7 +4319,7 @@ export class AppMessagesManager {
|
||||
}
|
||||
} else if(message.media.document) {
|
||||
const doc = appDocsManager.getDoc('' + tempId);
|
||||
if(/* doc._ != 'documentEmpty' && */doc?.type && doc.type != 'sticker') {
|
||||
if(/* doc._ != 'documentEmpty' && */doc?.type && doc.type !== 'sticker') {
|
||||
const newDoc = message.media.document;
|
||||
newDoc.downloaded = doc.downloaded;
|
||||
newDoc.url = doc.url;
|
||||
@ -4325,7 +4346,7 @@ export class AppMessagesManager {
|
||||
AppStorage.set({max_seen_msg: maxId});
|
||||
|
||||
apiManager.invokeApi('messages.receivedMessages', {
|
||||
max_id: maxId
|
||||
max_id: this.getLocalMessageId(maxId)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ export class AppPeersManager {
|
||||
|
||||
return plainText ? title : RichTextProcessor.wrapEmojiText(title);
|
||||
}
|
||||
|
||||
|
||||
public getOutputPeer(peerId: number): Peer {
|
||||
if(peerId > 0) {
|
||||
return {_: 'peerUser', user_id: peerId};
|
||||
|
@ -295,8 +295,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.is-floating .pinned-message-subtitle {
|
||||
max-width: 280px;
|
||||
&.is-floating {
|
||||
.chat:not(.type-discussion) & {
|
||||
.pinned-container-wrapper {
|
||||
padding-right: 3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
|
@ -230,20 +230,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
#shared-media-container {
|
||||
.search-super {
|
||||
top: 100%;
|
||||
min-height: calc((var(--vh, 1vh) * 100) - 100% - 56px);
|
||||
|
||||
&.sliding {
|
||||
max-height: calc((var(--vh, 1vh) * 100) - 100% - 56px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-super {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
//overflow: hidden;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
//min-height: 100vh; /* Fallback for browsers that do not support Custom Properties */
|
||||
//min-height: calc(var(--vh, 1vh) * 100);
|
||||
min-height: calc((var(--vh, 1vh) * 100) - 100% - 56px);
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&.sliding {
|
||||
max-height: calc((var(--vh, 1vh) * 100) - 100% - 56px);
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
&-tabs {
|
||||
@ -304,19 +311,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-month:first-of-type &-month-name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-content-media {
|
||||
width: 100%;
|
||||
padding: 7.5px;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3,1fr);
|
||||
grid-auto-rows: 1fr;
|
||||
grid-gap: 3.5px;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding: 7.5px 7.5px 7.5px 6.5px;
|
||||
}
|
||||
|
||||
.video-time {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
@ -353,7 +352,23 @@
|
||||
} */
|
||||
}
|
||||
|
||||
&-content-docs {
|
||||
&-content-media &-month {
|
||||
&-items {
|
||||
width: 100%;
|
||||
padding: 7.5px;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3,1fr);
|
||||
grid-auto-rows: 1fr;
|
||||
grid-gap: 3.5px;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding: 7.5px 7.5px 7.5px 6.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-content-files {
|
||||
padding: 7px 20px;
|
||||
|
||||
.document {
|
||||
@ -385,7 +400,7 @@
|
||||
&-content-links {
|
||||
padding: 0 30px 15px 15px;
|
||||
|
||||
> div {
|
||||
.search-super-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 20px;
|
||||
@ -438,16 +453,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-content-audio {
|
||||
&-content-music, &-content-voice {
|
||||
padding: 20px 15px 15px 20px;
|
||||
|
||||
> div {
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.preloader-container {
|
||||
.preloader-circular {
|
||||
background-color: rgba(0, 0, 0, 0.35);
|
||||
background-color: rgba(0, 0, 0, .35);
|
||||
}
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
@ -497,6 +508,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
#search-container {
|
||||
.search-super-content-music {
|
||||
.audio:not(.audio-show-progress) .audio-time {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.document-name, .audio-title, .title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.sent-time {
|
||||
flex: 0 0 auto;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
#stickers-container {
|
||||
.sticker-sets {
|
||||
display: flex;
|
||||
|
@ -42,6 +42,7 @@ $slider-time: .25s;
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&.active {
|
||||
@ -121,6 +122,7 @@ $slider-time: .25s;
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
Loading…
x
Reference in New Issue
Block a user