tweb/src/lib/appManagers/appDialogsManager.ts

596 lines
18 KiB
TypeScript
Raw Normal View History

import apiManager from "../mtproto/apiManager";
import apiFileManager from '../mtproto/apiFileManager';
2020-04-08 17:46:43 +02:00
import { $rootScope, findUpTag, langPack, findUpClassName } from "../utils";
2020-02-06 16:43:07 +01:00
import appImManager from "./appImManager";
import appPeersManager from './appPeersManager';
import appMessagesManager from "./appMessagesManager";
import appUsersManager from "./appUsersManager";
import { RichTextProcessor } from "../richtextprocessor";
import { ripple } from "../../components/misc";
import appSidebarLeft from "./appSidebarLeft";
2020-02-22 12:20:43 +01:00
import Scrollable from "../../components/scrollable";
2020-02-06 16:43:07 +01:00
2020-02-07 07:38:55 +01:00
type DialogDom = {
avatarDiv: HTMLDivElement,
captionDiv: HTMLDivElement,
titleSpan: HTMLSpanElement,
statusSpan: HTMLSpanElement,
lastTimeSpan: HTMLSpanElement,
unreadMessagesSpan: HTMLSpanElement,
lastMessageSpan: HTMLSpanElement,
containerEl: HTMLDivElement,
2020-02-07 07:38:55 +01:00
listEl: HTMLLIElement
};
2020-02-06 16:43:07 +01:00
export class AppDialogsManager {
public chatList = document.getElementById('dialogs') as HTMLUListElement;
public chatListArchived = document.getElementById('dialogs-archived') as HTMLUListElement;
public pinnedDelimiter: HTMLDivElement;
2020-02-22 12:20:43 +01:00
public chatsHidden: Scrollable["hiddenElements"];
2020-04-08 17:46:43 +02:00
public chatsVisible: Scrollable["visibleElements"];
2020-02-22 12:20:43 +01:00
public chatsArchivedHidden: Scrollable["hiddenElements"];
2020-04-08 17:46:43 +02:00
public chatsArchivedVisible: Scrollable["visibleElements"];
2020-02-06 16:43:07 +01:00
public myID = 0;
public doms: {[peerID: number]: DialogDom} = {};
public domsArchived: {[peerID: number]: DialogDom} = {};
public lastActiveListElement: HTMLElement = null;
2020-02-06 16:43:07 +01:00
2020-03-02 18:15:11 +01:00
public savedAvatarURLs: {[peerID: number]: string} = {};
2020-02-06 16:43:07 +01:00
constructor() {
this.pinnedDelimiter = document.createElement('div');
this.pinnedDelimiter.classList.add('pinned-delimiter');
this.pinnedDelimiter.appendChild(document.createElement('span'));
apiManager.getUserID().then((id) => {
2020-02-06 16:43:07 +01:00
this.myID = id;
});
$rootScope.$on('user_auth', (e: CustomEvent) => {
let userAuth = e.detail;
this.myID = userAuth ? userAuth.id : 0;
});
//let chatClosedDiv = document.getElementById('chat-closed');
this.setListClickListener(this.chatList);
this.setListClickListener(this.chatListArchived);
2020-02-06 16:43:07 +01:00
}
public setListClickListener(list: HTMLUListElement, onFound?: () => void) {
list.addEventListener('click', (e: Event) => {
let target = e.target as HTMLElement;
2020-04-08 17:46:43 +02:00
let elem = target.classList.contains('rp') ? target : findUpClassName(target, 'rp');
2020-02-06 16:43:07 +01:00
if(!elem) {
return;
}
2020-04-08 17:46:43 +02:00
elem = elem.parentElement;
if(this.lastActiveListElement) {
this.lastActiveListElement.classList.remove('active');
2020-04-08 17:46:43 +02:00
}
2020-02-06 16:43:07 +01:00
if(elem) {
/* if(chatClosedDiv) {
chatClosedDiv.style.display = 'none';
} */
if(onFound) onFound();
let peerID = +elem.getAttribute('data-peerID');
let lastMsgID = +elem.getAttribute('data-mid');
appImManager.setPeer(peerID, lastMsgID);
elem.classList.add('active');
this.lastActiveListElement = elem;
2020-02-06 16:43:07 +01:00
} else /* if(chatClosedDiv) */ {
appImManager.setPeer(0);
2020-02-06 16:43:07 +01:00
//chatClosedDiv.style.display = '';
}
});
}
2020-03-02 18:15:11 +01:00
// peerID == peerID || title
public async loadDialogPhoto(div: HTMLDivElement, peerID: number, isDialog = false, title = ''): Promise<boolean> {
2020-02-06 16:43:07 +01:00
let inputPeer: any;
let location: any;
2020-03-02 18:15:11 +01:00
if(peerID) {
2020-02-06 16:43:07 +01:00
inputPeer = appPeersManager.getInputPeerByID(peerID);
location = appPeersManager.getPeerPhoto(peerID);
}
//console.log('loadDialogPhoto location:', location, inputPeer);
if(peerID == this.myID && (isDialog || $rootScope.selectedPeerID == this.myID)) {
if(div.firstChild) {
div.firstChild.remove();
}
2020-02-10 17:40:33 +01:00
div.style.backgroundColor = '';
2020-02-06 16:43:07 +01:00
div.classList.add('tgico-savedmessages');
return true;
}
2020-04-08 17:46:43 +02:00
if(peerID) {
let user = appUsersManager.getUser(peerID);
if(user && user.pFlags && user.pFlags.deleted) {
if(div.firstChild) {
div.firstChild.remove();
}
div.style.backgroundColor = '';
div.classList.add('tgico-avatar_deletedaccount');
return true;
}
}
2020-02-06 16:43:07 +01:00
//if(!location || location.empty || !location.photo_small) {
if(div.firstChild) {
div.firstChild.remove();
}
2020-02-10 17:08:10 +01:00
let color = '';
2020-03-02 18:15:11 +01:00
if(peerID && peerID != this.myID) {
2020-02-10 17:40:33 +01:00
color = appPeersManager.getPeerColorByID(peerID);
2020-02-10 17:08:10 +01:00
}
2020-04-08 17:46:43 +02:00
div.classList.remove('tgico-savedmessages', 'tgico-avatar_deletedaccount');
2020-02-10 17:08:10 +01:00
div.style.backgroundColor = color;
2020-02-06 16:43:07 +01:00
2020-03-02 18:15:11 +01:00
let abbrSplitted = (!title && peerID ? appPeersManager.getPeerTitle(peerID, true) : title).split(' ');
2020-02-06 16:43:07 +01:00
let abbr = (abbrSplitted.length == 2 ?
abbrSplitted[0][0] + abbrSplitted[1][0] :
abbrSplitted[0][0]).toUpperCase();
//div.innerText = peer.initials.toUpperCase();
div.innerText = abbr.toUpperCase();
//return Promise.resolve(true);
//}
if(!location || location.empty || !location.photo_small) {
return true;
}
2020-03-02 18:15:11 +01:00
if(!this.savedAvatarURLs[peerID]) {
let res = await apiFileManager.downloadSmallFile({
_: 'inputPeerPhotoFileLocation',
dc_id: location.dc_id,
flags: 0,
peer: inputPeer,
volume_id: location.photo_small.volume_id,
local_id: location.photo_small.local_id
});
this.savedAvatarURLs[peerID] = URL.createObjectURL(res);
}
2020-02-06 16:43:07 +01:00
let img = new Image();
2020-03-02 18:15:11 +01:00
img.src = this.savedAvatarURLs[peerID];
2020-02-06 16:43:07 +01:00
div.innerHTML = '';
2020-04-08 17:46:43 +02:00
//div.style.fontSize = '0'; // need
//div.style.backgroundColor = '';
2020-02-06 16:43:07 +01:00
div.append(img);
return true;
}
public sortDom(archived = false) {
2020-04-08 17:46:43 +02:00
//return;
//if(archived) return;
2020-02-08 12:58:22 +01:00
let dialogs = appMessagesManager.dialogsStorage.dialogs.slice();
2020-02-08 12:58:22 +01:00
2020-04-08 17:46:43 +02:00
let inUpper: Scrollable['hiddenElements']['up'] = [];
let inBottom: Scrollable['hiddenElements']['down'] = [];
let inVisible: Scrollable['visibleElements'] = [];
2020-02-08 12:58:22 +01:00
let pinnedDialogs = [];
let sorted = dialogs;
if(!archived) {
for(let i = 0; i < dialogs.length; ++i) {
let dialog = dialogs[i];
if(!dialog.pFlags.pinned) break;
pinnedDialogs.push(dialog);
}
if(pinnedDialogs.length) {
let dom = this.getDialogDom(pinnedDialogs[pinnedDialogs.length - 1].peerID);
if(dom) {
dom.listEl.append(this.pinnedDelimiter);
}
} else {
if(this.pinnedDelimiter.parentElement) {
this.pinnedDelimiter.parentElement.removeChild(this.pinnedDelimiter);
}
}
sorted = sorted.filter((d: any) => !d.pFlags.pinned && d.folder_id != 1);
} else {
sorted = sorted.filter((d: any) => d.folder_id == 1);
2020-02-08 12:58:22 +01:00
}
sorted = sorted.sort((a: any, b: any) => {
2020-02-06 16:43:07 +01:00
let timeA = appMessagesManager.getMessage(a.top_message).date;
let timeB = appMessagesManager.getMessage(b.top_message).date;
return timeB - timeA;
2020-02-08 12:58:22 +01:00
});
if(!archived) {
sorted = pinnedDialogs.concat(sorted);
}
//console.log('sortDom', sorted, this.chatsHidden, this.chatsHidden.up, this.chatsHidden.down);
let chatList = archived ? this.chatListArchived : this.chatList;
let chatsHidden = archived ? this.chatsArchivedHidden : this.chatsHidden;
2020-04-08 17:46:43 +02:00
let chatsVisible = archived ? this.chatsArchivedVisible : this.chatsVisible;
let hiddenLength: number = chatsHidden.up.length;
let inViewportLength = chatList.childElementCount;
2020-04-08 17:46:43 +02:00
let concated = chatsHidden.up.concat(chatsVisible, chatsHidden.down);
2020-02-22 12:20:43 +01:00
//console.log('sortDom clearing innerHTML', archived, hiddenLength, inViewportLength);
2020-02-08 12:58:22 +01:00
chatList.innerHTML = '';
let inViewportIndex = 0;
sorted.forEach((d: any, idx) => {
2020-02-06 16:43:07 +01:00
let dom = this.getDialogDom(d.peerID);
if(!dom) return;
2020-04-08 17:46:43 +02:00
let child = concated.find(obj => obj.element == dom.listEl);
if(!child) {
return console.error('no child by listEl:', dom.listEl, archived, concated);
}
if(inUpper.length < hiddenLength) {
2020-04-08 17:46:43 +02:00
inUpper.push(child);
} else if(inViewportIndex <= inViewportLength - 1) {
2020-02-13 16:42:39 +01:00
chatList.append(dom.listEl);
2020-04-08 17:46:43 +02:00
inVisible.push(child);
++inViewportIndex;
} else {
2020-04-08 17:46:43 +02:00
inBottom.push(child);
}
2020-02-06 16:43:07 +01:00
});
2020-02-08 12:58:22 +01:00
2020-02-22 12:20:43 +01:00
//console.log('sortDom', sorted.length, inUpper.length, chatList.childElementCount, inBottom.length);
chatsHidden.up = inUpper;
2020-04-08 17:46:43 +02:00
chatsVisible.length = 0;
chatsVisible.push(...inVisible);
chatsHidden.down = inBottom;
2020-02-06 16:43:07 +01:00
}
public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom) {
if(!lastMessage) {
lastMessage = appMessagesManager.getMessage(dialog.top_message);
}
2020-02-17 13:18:06 +01:00
///////console.log('setlastMessage:', lastMessage);
2020-02-06 16:43:07 +01:00
if(lastMessage._ == 'messageEmpty') return;
if(!dom) {
dom = this.getDialogDom(dialog.peerID);
}
let peer = dialog.peer;
let peerID = dialog.peerID;
//let peerID = appMessagesManager.getMessagePeer(lastMessage);
//console.log('setting last message:', lastMessage);
/* if(!dom.lastMessageSpan.classList.contains('user-typing')) */ {
let lastMessageText = '';
if(lastMessage.media) {
switch(lastMessage.media._) {
case 'messageMediaPhoto':
lastMessageText += '<i>Photo' + (lastMessage.message ? ', ' : '') + '</i>';
break;
case 'messageMediaGeo':
lastMessageText += '<i>Geolocation</i>';
break;
case 'messageMediaDocument':
let document = lastMessage.media.document;
let found = false;
for(let attribute of document.attributes) {
if(found) break;
switch(attribute._) {
case 'documentAttributeSticker':
lastMessageText += RichTextProcessor.wrapRichText(attribute.alt) + '<i>Sticker</i>';
found = true;
break;
case 'documentAttributeFilename':
lastMessageText += '<i>' + attribute.file_name + '</i>';
found = true;
break;
/* default:
console.warn('Got unknown document type!', lastMessage);
break; */
}
}
if(document.type == 'video') {
2020-02-07 07:38:55 +01:00
lastMessageText = '<i>Video' + (lastMessage.message ? ', ' : '') + '</i>';
2020-02-06 16:43:07 +01:00
found = true;
} else if(document.type == 'voice') {
2020-02-07 07:38:55 +01:00
lastMessageText = '<i>Voice message</i>';
2020-02-06 16:43:07 +01:00
found = true;
2020-02-07 03:10:08 +01:00
} else if(document.type == 'gif') {
2020-02-07 07:38:55 +01:00
lastMessageText = '<i>GIF' + (lastMessage.message ? ', ' : '') + '</i>';
2020-02-07 03:10:08 +01:00
found = true;
} else if(document.type == 'round') {
lastMessageText = '<i>Videomessage' + (lastMessage.message ? ', ' : '') + '</i>';
found = true;
2020-02-06 16:43:07 +01:00
}
if(found) {
break;
}
default:
2020-02-17 13:18:06 +01:00
///////console.warn('Got unknown lastMessage.media type!', lastMessage);
2020-02-06 16:43:07 +01:00
break;
}
}
if(lastMessage.action) {
// @ts-ignore
lastMessageText = langPack[lastMessage.action._];
}
2020-02-06 16:43:07 +01:00
dom.lastMessageSpan.innerHTML = lastMessageText +
(lastMessage.message ? RichTextProcessor.wrapRichText(lastMessage.message.replace(/\n/g, ' '), {noLinebreakers: true}) : '');
/* if(lastMessage.from_id == auth.id) { // You: */
if(peer._ != 'peerUser' && peerID != -lastMessage.from_id) {
let sender = appUsersManager.getUser(lastMessage.from_id);
if(sender && sender.id) {
let senderBold = document.createElement('b');
let str = '';
if(sender.id == this.myID) {
str = 'You';
} else {
str = sender.first_name || sender.last_name || sender.username;
}
senderBold.innerText = str + ': ';
//console.log(sender, senderBold.innerText);
dom.lastMessageSpan.prepend(senderBold);
2020-02-17 13:18:06 +01:00
} //////// else console.log('no sender', lastMessage, peerID);
2020-02-06 16:43:07 +01:00
}
}
let timeStr = '';
let timestamp = lastMessage.date;
let now = Date.now() / 1000;
let time = new Date(lastMessage.date * 1000);
if((now - timestamp) < 86400) { // if < 1 day
timeStr = ('0' + time.getHours()).slice(-2) +
':' + ('0' + time.getMinutes()).slice(-2);
} else if((now - timestamp) < (86400 * 7)) { // week
let date = new Date(timestamp * 1000);
timeStr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()];
} else {
let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
timeStr = months[time.getMonth()] +
' ' + ('0' + time.getDate()).slice(-2);
}
dom.lastTimeSpan.innerHTML = timeStr;
dom.listEl.setAttribute('data-mid', lastMessage.mid);
2020-04-08 17:46:43 +02:00
if(this.doms[peerID] || this.domsArchived[peerID]) {
2020-02-06 16:43:07 +01:00
this.setUnreadMessages(dialog);
}
}
public setUnreadMessages(dialog: any) {
let dom = this.getDialogDom(dialog.peerID);
dom.statusSpan.innerHTML = '';
let lastMessage = appMessagesManager.getMessage(dialog.top_message);
if(lastMessage._ != 'messageEmpty' &&
lastMessage.from_id == this.myID && lastMessage.peerID != this.myID &&
dialog.read_outbox_max_id) { // maybe comment, 06.20.2020
let outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread)
/* && dialog.read_outbox_max_id != 0 */; // maybe uncomment, 31.01.2020
2020-02-13 16:42:39 +01:00
//console.log('outgoing', outgoing, lastMessage);
2020-02-06 16:43:07 +01:00
if(outgoing) {
dom.statusSpan.classList.remove('tgico-checks');
dom.statusSpan.classList.add('tgico-check');
} else {
dom.statusSpan.classList.remove('tgico-check');
dom.statusSpan.classList.add('tgico-checks');
}
} else dom.statusSpan.classList.remove('tgico-check', 'tgico-checks');
dom.unreadMessagesSpan.innerHTML = '';
if(dialog.unread_count) {
dom.unreadMessagesSpan.innerHTML = dialog.unread_count;
dom.unreadMessagesSpan.classList.remove('tgico-pinnedchat');
dom.unreadMessagesSpan.classList.add(new Date(dialog.notify_settings.mute_until * 1000) > new Date() ?
'unread-muted' : 'unread');
} else if(dialog.pFlags.pinned) {
dom.unreadMessagesSpan.classList.remove('unread', 'unread-muted');
dom.unreadMessagesSpan.classList.add('tgico-pinnedchat');
}
// set archived new count
if(dialog.folder_id == 1) {
let sum = Object.keys(this.domsArchived).map(p => +p).reduce((acc: number, peerID: number) => {
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
if(dialog) {
return acc + dialog.unread_count;
}
return acc;
}, 0);
appSidebarLeft.archivedCount.innerText = '' + sum;
}
2020-02-06 16:43:07 +01:00
}
public getDialogDom(peerID: number) {
return this.doms[peerID] || this.domsArchived[peerID];
2020-02-06 16:43:07 +01:00
}
2020-02-07 08:39:00 +01:00
public addDialog(dialog: {
peerID: number,
pFlags: any,
peer: any,
folder_id?: number
2020-02-07 08:39:00 +01:00
}, container?: HTMLUListElement, drawStatus = true) {
2020-02-06 16:43:07 +01:00
let peerID: number = dialog.peerID;
if((this.doms[peerID] || this.domsArchived[peerID]) && !container) return;
2020-02-06 16:43:07 +01:00
let title = appPeersManager.getPeerTitle(peerID);
let avatarDiv = document.createElement('div');
avatarDiv.classList.add('user-avatar');
if(drawStatus && peerID != this.myID) {
let peer = dialog.peer;
switch(peer._) {
case 'peerUser':
let user = appUsersManager.getUser(peerID);
//console.log('found user', user);
if(user.status && user.status._ == 'userStatusOnline') {
avatarDiv.classList.add('is-online');
}
break;
default:
break;
}
}
let captionDiv = document.createElement('div');
captionDiv.classList.add('user-caption');
let titleSpan = document.createElement('span');
titleSpan.classList.add('user-title');
if(peerID == this.myID) {
title = 'Saved Messages';
}
//console.log('trying to load photo for:', title);
this.loadDialogPhoto(avatarDiv, dialog.peerID, true);
titleSpan.innerHTML = title;
2020-02-06 16:43:07 +01:00
//p.classList.add('')
let span = document.createElement('span');
span.classList.add('user-last-message');
//captionDiv.append(titleSpan);
//captionDiv.append(span);
let paddingDiv = document.createElement('div');
paddingDiv.classList.add('rp');
paddingDiv.append(avatarDiv, captionDiv);
ripple(paddingDiv);
2020-02-06 16:43:07 +01:00
let li = document.createElement('li');
li.append(paddingDiv);
li.setAttribute('data-peerID', '' + peerID);
2020-02-06 16:43:07 +01:00
let statusSpan = document.createElement('span');
statusSpan.classList.add('message-status');
let lastTimeSpan = document.createElement('span');
lastTimeSpan.classList.add('message-time');
let unreadMessagesSpan = document.createElement('span');
let titleP = document.createElement('p');
let rightSpan = document.createElement('span');
rightSpan.append(statusSpan, lastTimeSpan);
titleP.append(titleSpan, rightSpan);
let messageP = document.createElement('p');
messageP.append(span, unreadMessagesSpan);
captionDiv.append(titleP, messageP);
let dom: DialogDom = {
avatarDiv,
captionDiv,
titleSpan,
statusSpan,
lastTimeSpan,
unreadMessagesSpan,
lastMessageSpan: span,
containerEl: paddingDiv,
2020-02-06 16:43:07 +01:00
listEl: li
};
if(!container) {
if(dialog.folder_id && dialog.folder_id == 1) {
2020-04-08 17:46:43 +02:00
appSidebarLeft.scrollArchived.append(li);
this.domsArchived[dialog.peerID] = dom;
} else {
2020-02-22 12:20:43 +01:00
appSidebarLeft.scroll.append(li);
this.doms[dialog.peerID] = dom;
}
2020-02-08 12:58:22 +01:00
if(dialog.pFlags.pinned) {
li.classList.add('dialog-pinned');
//this.chatList.insertBefore(this.pinnedDelimiter, li.nextSibling);
dom.listEl.append(this.pinnedDelimiter);
2020-02-08 12:58:22 +01:00
}
2020-02-06 16:43:07 +01:00
this.setLastMessage(dialog);
} else {
container.append(li);
}
return {dom, dialog};
}
public setTyping(dialog: any, user: any) {
let dom = this.getDialogDom(dialog.peerID);
let str = '';
let senderBold = document.createElement('i');
if(dialog.peerID < 0) str = (user.first_name || user.last_name || user.username) + ' ';
str += 'typing...';
senderBold.innerText = str;
dom.lastMessageSpan.innerHTML = '';
dom.lastMessageSpan.append(senderBold);
dom.lastMessageSpan.classList.add('user-typing');
}
public unsetTyping(dialog: any) {
let dom = this.getDialogDom(dialog.peerID);
dom.lastMessageSpan.classList.remove('user-typing');
this.setLastMessage(dialog, null, dom);
}
}
export default new AppDialogsManager();