Telegram Web K with changes to work inside I2P https://web.telegram.i2p/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2444 lines
82 KiB

import apiManager from '../mtproto/apiManager';
import { $rootScope, isElementInViewport, numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, calcImageInBox, findUpTag, getRichValue, getRichValueWithCaret, getSelectedText, langPack } from "../utils";
5 years ago
import appUsersManager from "./appUsersManager";
import appMessagesManager from "./appMessagesManager";
import appPeersManager from "./appPeersManager";
import appProfileManager from "./appProfileManager";
//import { ProgressivePreloader, wrapDocument, wrapSticker, wrapVideo, wrapPhoto, openBtnMenu, LazyLoadQueue } from "../../components/misc";
5 years ago
import appDialogsManager from "./appDialogsManager";
import { RichTextProcessor } from "../richtextprocessor";
import appPhotosManager from "./appPhotosManager";
import appSidebarRight from './appSidebarRight';
import Scrollable from '../../components/scrollable';
5 years ago
import { logger } from "../polyfill";
import lottieLoader from "../lottieLoader";
import appMediaViewer from "./appMediaViewer";
import appSidebarLeft from "./appSidebarLeft";
import appChatsManager from "./appChatsManager";
import appMessagesIDsManager from "./appMessagesIDsManager";
import apiUpdatesManager from './apiUpdatesManager';
import initEmoticonsDropdown, { EMOTICONSSTICKERGROUP } from '../../components/emoticonsDropdown';
import LazyLoadQueue from '../../components/lazyLoadQueue';
5 years ago
import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply } from '../../components/wrappers';
import ProgressivePreloader from '../../components/preloader';
import { openBtnMenu } from '../../components/misc';
import appWebPagesManager from './appWebPagesManager';
5 years ago
console.log('appImManager included!');
let testScroll = false;
class ScrollPosition {
public previousScrollHeightMinusTop = 0;
public readyFor = 'up';
public container: HTMLElement;
constructor(public node: HTMLElement) {
this.container = node.parentElement;
}
/* public restore() {
if(!this.scroll) return;
//console.log('restore', this.readyFor, this.previousScrollHeightMinusTop);
//if(this.readyFor === 'up') {
this.scroll.update(true);
//console.log('restore 2', this.node.scrollHeight, (this.node.scrollHeight
//- this.previousScrollHeightMinusTop) + 'px')
this.scroll.scroll({y: (this.node.scrollHeight
- this.previousScrollHeightMinusTop) + 'px'});
//}
// 'down' doesn't need to be special cased unless the
// content was flowing upwards, which would only happen
// if the container is position: absolute, bottom: 0 for
// a Facebook messages effect
}
public prepareFor(direction: string) {
if(!this.scroll) return;
this.readyFor = direction || 'up';
this.scroll.update(true);
let pos = this.scroll.scroll();
this.previousScrollHeightMinusTop = this.node.scrollHeight
- pos.position.y;
} */
public restore() {
//console.log('scrollPosition restore 2', this.node.scrollHeight, (this.node.scrollHeight
//- this.previousScrollHeightMinusTop) + 'px', this.container);
if(this.readyFor === 'up' || appImManager.scroll.parentElement.classList.contains('scrolled-down')) {
5 years ago
this.container.scrollTop = this.node.scrollHeight
- this.previousScrollHeightMinusTop;
}
5 years ago
// 'down' doesn't need to be special cased unless the
// content was flowing upwards, which would only happen
// if the container is position: absolute, bottom: 0 for
// a Facebook messages effect
}
public prepareFor(direction: string) {
this.readyFor = direction || 'up';
this.previousScrollHeightMinusTop = this.node.scrollHeight
- this.container.scrollTop;
//console.log('scrollPosition prepareFor', direction, this.node.scrollHeight, this.previousScrollHeightMinusTop + 'px')
}
}
class ChatInput {
public pageEl = document.querySelector('.page-chats') as HTMLDivElement;
public messageInput = document.getElementById('input-message') as HTMLDivElement/* HTMLInputElement */;
public fileInput = document.getElementById('input-file') as HTMLInputElement;
public inputMessageContainer = document.getElementsByClassName('input-message-container')[0] as HTMLDivElement;
public inputScroll = new Scrollable(this.inputMessageContainer);
public btnSend = document.getElementById('btn-send') as HTMLButtonElement;
public emoticonsDropdown: HTMLDivElement = null;
public emoticonsTimeout: number = 0;
public toggleEmoticons: HTMLButtonElement;
public emoticonsLazyLoadQueue: LazyLoadQueue = null;
public lastUrl = '';
public lastTimeType = 0;
public attachMenu: {
container?: HTMLButtonElement,
media?: HTMLDivElement,
document?: HTMLDivElement,
poll?: HTMLDivElement
} = {};
public attachMediaPopUp: {
container?: HTMLDivElement,
titleEl?: HTMLDivElement,
sendBtn?: HTMLButtonElement,
mediaContainer?: HTMLDivElement,
captionInput?: HTMLInputElement
} = {};
public replyElements: {
container?: HTMLDivElement,
cancelBtn?: HTMLButtonElement,
titleEl?: HTMLDivElement,
subtitleEl?: HTMLDivElement
} = {};
public willSendWebPage: any = null;
public replyToMsgID = 0;
public editMsgID = 0;
public noWebPage = false;
constructor() {
this.toggleEmoticons = this.pageEl.querySelector('.toggle-emoticons') as HTMLButtonElement;
this.attachMenu.container = document.getElementById('attach-file') as HTMLButtonElement;
this.attachMenu.media = this.attachMenu.container.querySelector('.menu-media') as HTMLDivElement;
this.attachMenu.document = this.attachMenu.container.querySelector('.menu-document') as HTMLDivElement;
this.attachMenu.poll = this.attachMenu.container.querySelector('.menu-poll') as HTMLDivElement;
this.attachMediaPopUp.container = this.pageEl.querySelector('.popup-send-photo') as HTMLDivElement;
this.attachMediaPopUp.titleEl = this.attachMediaPopUp.container.querySelector('.popup-title') as HTMLDivElement;
this.attachMediaPopUp.sendBtn = this.attachMediaPopUp.container.querySelector('.btn-primary') as HTMLButtonElement;
this.attachMediaPopUp.mediaContainer = this.attachMediaPopUp.container.querySelector('.popup-photo') as HTMLDivElement;
this.attachMediaPopUp.captionInput = this.attachMediaPopUp.container.querySelector('input') as HTMLInputElement;
this.replyElements.container = this.pageEl.querySelector('.reply-wrapper') as HTMLDivElement;
this.replyElements.cancelBtn = this.replyElements.container.querySelector('.reply-cancel') as HTMLButtonElement;
this.replyElements.titleEl = this.replyElements.container.querySelector('.reply-title') as HTMLDivElement;
this.replyElements.subtitleEl = this.replyElements.container.querySelector('.reply-subtitle') as HTMLDivElement;
this.messageInput.addEventListener('keydown', (e: KeyboardEvent) => {
if(e.key == 'Enter') {
/* if(e.ctrlKey || e.metaKey) {
this.messageInput.innerHTML += '<br>';
placeCaretAtEnd(this.message)
return;
} */
if(e.shiftKey || e.ctrlKey || e.metaKey) {
return;
}
this.sendMessage();
}
});
this.messageInput.addEventListener('input', (e) => {
//console.log('messageInput input', this.messageInput.innerText, this.serializeNodes(Array.from(this.messageInput.childNodes)));
let value = this.messageInput.innerText;
let entities = RichTextProcessor.parseEntities(value);
//console.log('messageInput entities', entities);
let entityUrl = entities.find(e => e._ == 'messageEntityUrl');
if(entityUrl) { // need to get webpage
let url = value.slice(entityUrl.offset, entityUrl.offset + entityUrl.length);
//console.log('messageInput url:', url);
if(this.lastUrl != url) {
this.lastUrl = url;
this.willSendWebPage = null;
apiManager.invokeApi('messages.getWebPage', {
url: url,
hash: 0
}).then((webpage: any) => {
appWebPagesManager.saveWebPage(webpage);
if(this.lastUrl != url) return;
console.log('got webpage: ', webpage);
this.setTopInfo(webpage.site_name || webpage.title, webpage.description || webpage.url);
this.replyToMsgID = 0;
this.noWebPage = false;
this.willSendWebPage = webpage;
});
}
}
if(!value.trim() && !this.serializeNodes(Array.from(this.messageInput.childNodes)).trim()) {
this.messageInput.innerHTML = '';
this.btnSend.classList.remove('tgico-send');
this.btnSend.classList.add('tgico-microphone2');
appImManager.setTyping('sendMessageCancelAction');
} else if(!this.btnSend.classList.contains('tgico-send')) {
this.btnSend.classList.add('tgico-send');
this.btnSend.classList.remove('tgico-microphone2');
let time = Date.now();
if(time - this.lastTimeType >= 6000) {
this.lastTimeType = time;
appImManager.setTyping('sendMessageTypingAction');
}
}
});
5 years ago
if(!RichTextProcessor.emojiSupported) {
this.messageInput.addEventListener('copy', (e) => {
const selection = document.getSelection();
let range = selection.getRangeAt(0);
let ancestorContainer = range.commonAncestorContainer;
let str = '';
let selectedNodes = Array.from(ancestorContainer.childNodes).slice(range.startOffset, range.endOffset);
if(selectedNodes.length) {
str = this.serializeNodes(selectedNodes);
} else {
str = selection.toString();
}
//console.log('messageInput copy', str, ancestorContainer.childNodes, range);
5 years ago
//let str = getRichValueWithCaret(this.messageInput);
//console.log('messageInput childNode copy:', str);
// @ts-ignore
event.clipboardData.setData('text/plain', str);
event.preventDefault();
});
}
this.messageInput.addEventListener('paste', (e) => {
5 years ago
//console.log('messageInput paste');
e.preventDefault();
// @ts-ignore
let text = (e.originalEvent || e).clipboardData.getData('text/plain');
// console.log('messageInput paste', text);
text = RichTextProcessor.wrapEmojiText(text);
// console.log('messageInput paste after', text);
// @ts-ignore
//let html = (e.originalEvent || e).clipboardData.getData('text/html');
// @ts-ignore
//console.log('paste text', text, );
window.document.execCommand('insertHTML', false, text);
});
let attachFile = (file: File) => {
console.log('selected file:', file, typeof(file));
willAttachFile = file;
this.fileInput.value = '';
this.attachMediaPopUp.captionInput.value = '';
this.attachMediaPopUp.mediaContainer.innerHTML = '';
this.attachMediaPopUp.mediaContainer.style.width = '';
this.attachMediaPopUp.mediaContainer.style.height = '';
this.attachMediaPopUp.mediaContainer.classList.remove('is-document');
5 years ago
if(file.type.indexOf('video/') === 0) {
willAttach = 'document';
} else if(file.type.indexOf('image/') === -1 && willAttach == 'media') {
willAttach = 'document';
}
switch(willAttach) {
case 'media': {
let img = new Image();
img.src = URL.createObjectURL(file);
img.onload = () => {
willAttachWidth = img.naturalWidth;
willAttachHeight = img.naturalHeight;
let {w, h} = calcImageInBox(willAttachWidth, willAttachHeight, 378, 256);
this.attachMediaPopUp.mediaContainer.style.width = w + 'px';
this.attachMediaPopUp.mediaContainer.style.height = h + 'px';
this.attachMediaPopUp.mediaContainer.append(img);
};
this.attachMediaPopUp.titleEl.innerText = 'Send Photo';
this.attachMediaPopUp.container.classList.add('active');
break;
}
case 'document': {
let docDiv = wrapDocument({
file: file,
file_name: file.name || '',
size: file.size,
type: ['image/jpeg',
'image/png',
'image/gif',
'image/webp',
'image/bmp'].indexOf(file.type) !== -1 ? 'photo' : 'doc'
5 years ago
} as any, false, true);
this.attachMediaPopUp.titleEl.innerText = 'Send File';
this.attachMediaPopUp.mediaContainer.append(docDiv);
this.attachMediaPopUp.mediaContainer.classList.add('is-document');
this.attachMediaPopUp.container.classList.add('active');
break;
}
}
};
let willAttach = '';
let willAttachFile: File = null;
let willAttachWidth = 0, willAttachHeight = 0;
this.fileInput.addEventListener('change', (e) => {
var file = (e.target as HTMLInputElement & EventTarget).files[0];
if(!file) {
return;
}
attachFile(file);
}, false);
this.attachMenu.media.addEventListener('click', () => {
willAttach = 'media';
this.fileInput.click();
});
this.attachMenu.document.addEventListener('click', () => {
willAttach = 'document';
this.fileInput.click();
});
document.addEventListener('paste', (event) => {
if(!appImManager.peerID || this.attachMediaPopUp.container.classList.contains('active')) {
return;
}
5 years ago
//console.log('document paste');
// @ts-ignore
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
//console.log('item', event.clipboardData.getData());
for(let i = 0; i < items.length; ++i) {
if(items[i].kind == 'file') {
5 years ago
event.preventDefault()
event.cancelBubble = true;
event.stopPropagation();
let file = items[i].getAsFile();
//console.log(items[i], file);
if(!file) continue;
willAttach = file.type.indexOf('image/') === 0 ? 'media' : "document";
attachFile(file);
}
}
}, true);
this.attachMediaPopUp.sendBtn.addEventListener('click', () => {
this.attachMediaPopUp.container.classList.remove('active');
let caption = this.attachMediaPopUp.captionInput.value;
appMessagesManager.sendFile(appImManager.peerID, willAttachFile, {
isMedia: true,
caption,
width: willAttachWidth,
height: willAttachHeight
});
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
5 years ago
let dialog = appMessagesManager.getDialogByPeerID(appImManager.peerID)[0];
if(dialog && dialog.top_message) {
appMessagesManager.readHistory(appImManager.peerID, dialog.top_message); // lol
}
});
this.btnSend.addEventListener('click', () => {
if(this.btnSend.classList.contains('tgico-send')) {
this.sendMessage();
}
});
this.toggleEmoticons.onmouseover = (e) => {
clearTimeout(this.emoticonsTimeout);
this.emoticonsTimeout = setTimeout(() => {
if(!this.emoticonsDropdown) {
let res = initEmoticonsDropdown(this.pageEl, appImManager,
appMessagesManager, this.messageInput, this.toggleEmoticons, this.btnSend);
this.emoticonsDropdown = res.dropdown;
this.emoticonsLazyLoadQueue = res.lazyLoadQueue;
this.toggleEmoticons.onmouseout = this.emoticonsDropdown.onmouseout = (e) => {
clearTimeout(this.emoticonsTimeout);
this.emoticonsTimeout = setTimeout(() => {
this.emoticonsDropdown.classList.remove('active');
this.toggleEmoticons.classList.remove('active');
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
}, 200);
};
this.emoticonsDropdown.onmouseover = (e) => {
clearTimeout(this.emoticonsTimeout);
};
} else {
this.emoticonsDropdown.classList.add('active');
this.emoticonsLazyLoadQueue.check();
}
this.toggleEmoticons.classList.add('active');
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
}, 0/* 200 */);
};
this.replyElements.cancelBtn.addEventListener('click', () => {
this.replyElements.container.classList.remove('active');
this.replyToMsgID = 0;
if(this.editMsgID) {
if(this.willSendWebPage) {
let message = appMessagesManager.getMessage(this.editMsgID);
this.setTopInfo('Editing', message.message);
} else {
this.editMsgID = 0;
this.messageInput.innerHTML = '';
this.btnSend.classList.remove('tgico-send');
this.btnSend.classList.add('tgico-microphone2');
}
}
this.noWebPage = true;
this.willSendWebPage = null;
});
}
public serializeNodes(nodes: Node[]): string {
return nodes.reduce((str, child: any) => {
//console.log('childNode', str, child, typeof(child), typeof(child) === 'string', child.innerText);
if(typeof(child) === 'object' && child.textContent) return str += child.textContent;
if(child.innerText) return str += child.innerText;
5 years ago
if(child.tagName == 'IMG' && child.classList && child.classList.contains('emoji')) return str += child.getAttribute('alt');
return str;
}, '');
};
public sendMessage() {
5 years ago
//let str = this.serializeNodes(Array.from(this.messageInput.childNodes));
let str = getRichValue(this.messageInput);
//console.log('childnode str after:', str/* , getRichValue(this.messageInput) */);
5 years ago
//return;
this.lastUrl = '';
if(this.editMsgID) {
appMessagesManager.editMessage(this.editMsgID, str, {
noWebPage: this.noWebPage
});
} else {
appMessagesManager.sendText(appImManager.peerID, str, {
replyToMsgID: this.replyToMsgID == 0 ? undefined : this.replyToMsgID,
noWebPage: this.noWebPage,
webPage: this.willSendWebPage
});
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
}
5 years ago
let dialog = appMessagesManager.getDialogByPeerID(appImManager.peerID)[0];
if(dialog && dialog.top_message) {
appMessagesManager.readHistory(appImManager.peerID, dialog.top_message); // lol
}
this.editMsgID = 0;
this.replyToMsgID = 0;
this.noWebPage = false;
this.replyElements.container.classList.remove('active');
this.willSendWebPage = null;
this.messageInput.innerText = '';
this.btnSend.classList.remove('tgico-send');
this.btnSend.classList.add('tgico-microphone2');
};
5 years ago
public setTopInfo(title: string, subtitle: string, input?: string, media?: any) {
//appImManager.scrollPosition.prepareFor('down');
5 years ago
if(this.replyElements.container.lastElementChild.tagName == 'DIV') {
this.replyElements.container.lastElementChild.remove();
this.replyElements.container.append(wrapReply(title, subtitle, media));
}
//this.replyElements.titleEl.innerHTML = title ? RichTextProcessor.wrapEmojiText(title) : '';
//this.replyElements.subtitleEl.innerHTML = subtitle ? RichTextProcessor.wrapEmojiText(subtitle) : '';
this.replyElements.container.classList.add('active');
if(input !== undefined) {
this.messageInput.innerHTML = input ? RichTextProcessor.wrapRichText(input) : '';
this.btnSend.classList.remove('tgico-microphone2');
this.btnSend.classList.add('tgico-send');
}
//appImManager.scrollPosition.restore();
}
}
5 years ago
export class AppImManager {
public pageEl = document.querySelector('.page-chats') as HTMLDivElement;
public btnMute = this.pageEl.querySelector('.tool-mute') as HTMLButtonElement;
public btnMenuMute = this.pageEl.querySelector('.menu-mute') as HTMLButtonElement;
5 years ago
public avatarEl = document.getElementById('im-avatar') as HTMLDivElement;
public titleEl = document.getElementById('im-title') as HTMLDivElement;
public subtitleEl = document.getElementById('im-subtitle') as HTMLDivElement;
public chatInner = document.getElementById('bubbles-inner') as HTMLDivElement;
public searchBtn = this.pageEl.querySelector('.chat-search-button') as HTMLButtonElement;
public goDownBtn = this.pageEl.querySelector('#bubbles-go-down') as HTMLButtonElement;
5 years ago
public firstContainerDiv: HTMLDivElement;
public lastContainerDiv: HTMLDivElement;
private getHistoryPromise: Promise<boolean>;
private getHistoryTimeout = 0;
private chatInputC: ChatInput = null;
5 years ago
public myID = 0;
public peerID = 0;
public muted = false;
5 years ago
public bubbles: {[mid: number]: HTMLDivElement} = {};
public dateMessages: {[timestamp: number]: { div: HTMLDivElement, firstTimestamp: number }} = {};
public unreaded: number[] = [];
public unreadOut: number[] = [];
public needUpdate: {replyMid: number, mid: number}[] = []; // if need wrapSingleMessage
5 years ago
public offline = false;
public updateStatusInterval = 0;
public pinnedMsgID = 0;
private pinnedMessageContainer = this.pageEl.querySelector('.pinned-message') as HTMLDivElement;
private pinnedMessageContent = this.pinnedMessageContainer.querySelector('.pinned-message-subtitle') as HTMLDivElement;
private firstTopMsgID = 0;
public loadMediaQueue: Array<() => Promise<void>> = [];
private loadMediaQueuePromise: Promise<void[]> = null;
private loadingMedia = 0;
5 years ago
public scroll: HTMLDivElement = null;
public scrollPosition: ScrollPosition = null;
public log: ReturnType<typeof logger>;
5 years ago
private preloader: ProgressivePreloader = null;
private typingTimeouts: {[peerID: number]: number} = {};
private typingUsers: {[userID: number]: number} = {} // to peerID
private topbar: HTMLDivElement = null;
private chatInput: HTMLDivElement = null;
private scrolledAll: boolean;
private scrolledAllDown: boolean;
public contextMenu = document.getElementById('bubble-contextmenu') as HTMLDivElement;
private contextMenuPin = this.contextMenu.querySelector('.menu-pin') as HTMLDivElement;
private contextMenuEdit = this.contextMenu.querySelector('.menu-edit') as HTMLDivElement;
private contextMenuMsgID: number;
private popupDeleteMessage: {
popupEl?: HTMLDivElement,
deleteBothBtn?: HTMLButtonElement,
deleteMeBtn?: HTMLButtonElement,
cancelBtn?: HTMLButtonElement
} = {};
private setPeerPromise: Promise<boolean> = null;
5 years ago
constructor() {
this.log = logger('IM');
this.chatInputC = new ChatInput();
5 years ago
this.preloader = new ProgressivePreloader(null, false);
this.popupDeleteMessage.popupEl = this.pageEl.querySelector('.popup-delete-message') as HTMLDivElement;
this.popupDeleteMessage.deleteBothBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-delete-both') as HTMLButtonElement;
this.popupDeleteMessage.deleteMeBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-delete-me') as HTMLButtonElement;
this.popupDeleteMessage.cancelBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-close') as HTMLButtonElement;
apiManager.getUserID().then((id) => {
5 years ago
this.myID = id;
});
this.topbar = document.getElementById('topbar') as HTMLDivElement;
this.chatInput = document.getElementById('chat-input') as HTMLDivElement;
5 years ago
$rootScope.$on('user_auth', (e: CustomEvent) => {
let userAuth = e.detail;
this.myID = userAuth ? userAuth.id : 0;
});
$rootScope.$on('history_append', (e: CustomEvent) => {
let details = e.detail;
this.renderMessagesByIDs([details.messageID]);
});
$rootScope.$on('history_update', (e: CustomEvent) => {
let details = e.detail;
if(details.mid && details.peerID == this.peerID) {
let mid = details.mid;
let bubble = this.bubbles[mid];
if(!bubble) return;
let message = appMessagesManager.getMessage(mid);
//this.log('history_update', this.bubbles[mid], mid, message);
this.renderMessage(message, false, false, bubble);
this.deleteEmptySideDivs();
}
});
5 years ago
$rootScope.$on('history_multiappend', (e: CustomEvent) => {
let msgIDsByPeer = e.detail;
if(!(this.peerID in msgIDsByPeer)) return;
let msgIDs = msgIDsByPeer[this.peerID];
this.renderMessagesByIDs(msgIDs);
appDialogsManager.sortDom();
});
$rootScope.$on('history_delete', (e: CustomEvent) => {
let detail: {
peerID: string,
msgs: {[x: number]: boolean}
} = e.detail;
this.deleteMessagesByIDs(Object.keys(detail.msgs).map(s => +s));
5 years ago
setTimeout(() => {
this.deleteEmptySideDivs();
}, 0);
5 years ago
});
// Calls when message successfully sent and we have an ID
5 years ago
$rootScope.$on('message_sent', (e: CustomEvent) => {
let {tempID, mid} = e.detail;
5 years ago
////this.log('message_sent', e.detail);
5 years ago
let bubble = this.bubbles[tempID];
if(bubble) {
this.bubbles[mid] = bubble;
5 years ago
/////this.log('message_sent', bubble);
let media = bubble.querySelector('img, video');
if(media) {
media.setAttribute('message-id', mid);
}
bubble.classList.remove('is-sending');
bubble.classList.add('is-sent');
5 years ago
delete this.bubbles[tempID];
} else {
this.log.warn('message_sent there is no bubble', e.detail);
5 years ago
}
let length = this.unreadOut.length;
for(let i = 0; i < length; i++) {
if(this.unreadOut[i] == tempID) {
this.unreadOut[i] = mid;
}
}
});
$rootScope.$on('message_edit', (e: CustomEvent) => {
let {peerID, mid, id, justMedia} = e.detail;
if(peerID != this.peerID) return;
let bubble = this.bubbles[mid];
if(!bubble) return;
let message = appMessagesManager.getMessage(mid);
this.renderMessage(message, false, false, bubble, false);
});
5 years ago
$rootScope.$on('messages_downloaded', (e: CustomEvent) => {
let mids: number[] = e.detail;
5 years ago
mids.forEach(mid => {
if(this.pinnedMsgID == mid) {
let message = appMessagesManager.getMessage(mid);
5 years ago
/////this.log('setting pinned message', message);
this.pinnedMessageContainer.dataset.mid = '' + mid;
this.pinnedMessageContainer.style.display = '';
this.pinnedMessageContent.innerHTML = RichTextProcessor.wrapEmojiText(message.message);
}
let length = this.needUpdate.length;
for(let i = length - 1; i >= 0; --i) {
if(this.needUpdate[i].replyMid == mid) {
let {mid, replyMid} = this.needUpdate.splice(i, 1)[0];
//this.log('messages_downloaded', mid, replyMid, i, this.needUpdate, this.needUpdate.length, mids, this.bubbles[mid]);
let bubble = this.bubbles[mid];
if(!bubble) return;
let message = appMessagesManager.getMessage(mid);
let repliedMessage = appMessagesManager.getMessage(replyMid);
if(repliedMessage.deleted) { // чтобы не пыталось бесконечно загрузить удалённое сообщение
delete message.reply_to_mid; // WARNING!
}
this.renderMessage(message, false, false, bubble, false);
}
}
});
5 years ago
});
$rootScope.$on('apiUpdate', (e: CustomEvent) => {
let update = e.detail;
this.handleUpdate(update);
});
5 years ago
window.addEventListener('blur', () => {
lottieLoader.checkAnimations(true);
this.offline = true;
this.updateStatus();
clearInterval(this.updateStatusInterval);
window.addEventListener('focus', () => {
lottieLoader.checkAnimations(false);
this.offline = false;
this.updateStatus();
this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);
}, {once: true});
});
(this.pageEl.querySelector('.person') as HTMLDivElement).addEventListener('click', (e) => {
appSidebarRight.toggleSidebar(true);
});
this.chatInner.addEventListener('click', (e) => {
let target = e.target as HTMLElement;
let bubble: HTMLDivElement = null;
try {
bubble = findUpClassName(e.target, 'bubble');
} catch(err) {}
if(!bubble) return;
if(['IMG', 'VIDEO', 'SVG', 'DIV'].indexOf(target.tagName) === -1) target = findUpTag(target, 'DIV');
/* if(target.tagName == 'VIDEO' && bubble.classList.contains('round')) {
let video = target as HTMLVideoElement;
video.currentTime = 0;
if(video.paused) {
video.play();
video.volume = 1;
} else {
video.pause();
video.volume = 0;
}
return;
} */
5 years ago
if(target.tagName == 'DIV') {
if(target.classList.contains('forward')) {
let savedFrom = bubble.dataset.savedFrom;
let splitted = savedFrom.split('_');
let peerID = +splitted[0];
let msgID = +splitted[1];
5 years ago
////this.log('savedFrom', peerID, msgID);
this.setPeer(peerID, msgID, true);
return;
} else if(target.classList.contains('user-avatar') || target.classList.contains('name')) {
let peerID = +target.dataset.peerID;
if(!isNaN(peerID)) {
this.setPeer(peerID);
}
return;
}
let isReplyClick = false;
try {
5 years ago
isReplyClick = !!findUpClassName(e.target, 'reply');
} catch(err) {}
if(isReplyClick && bubble.classList.contains('is-reply')/* || bubble.classList.contains('forwarded') */) {
let originalMessageID = +bubble.getAttribute('data-original-mid');
this.setPeer(this.peerID, originalMessageID);
}
} else if(bubble.classList.contains('round')) {
} else if(target.tagName == 'IMG' && target.parentElement.classList.contains('user-avatar')) {
let peerID = +target.parentElement.dataset.peerID;
if(!isNaN(peerID)) {
this.setPeer(peerID);
}
} else if((target.tagName == 'IMG' && !target.classList.contains('emoji')) || target.tagName == 'VIDEO') {
let messageID = +target.getAttribute('message-id');
let message = appMessagesManager.getMessage(messageID);
if(!message) {
this.log.warn('no message by messageID:', messageID);
return;
}
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => {
let message = appMessagesManager.getMessage(id);
return message.media && (message.media.photo
|| (message.media.document && (message.media.document.type == 'video' || message.media.document.type == 'gif'))
|| (message.media.webpage && (message.media.webpage.document || message.media.webpage.photo)));
}).sort();
let idx = ids.findIndex(i => i == messageID);
let prev = ids[idx + 1] || null;
let next = ids[idx - 1] || null;
let prevTarget = this.bubbles[prev] ? this.bubbles[prev].querySelector('img, video') as HTMLElement : null;
let nextTarget = this.bubbles[next] ? this.bubbles[next].querySelector('img, video') as HTMLElement : null;
5 years ago
/////this.log('ids', ids, idx, this.bubbles[prev], this.bubbles[next]);
appMediaViewer.openMedia(message, target, nextTarget, prevTarget);
//appMediaViewer.openMedia(message, target as HTMLImageElement);
5 years ago
}
//console.log('chatInner click', e);
});
this.searchBtn.addEventListener('click', (e) => {
if(this.peerID) {
appSidebarLeft.beginSearch(this.peerID);
}
});
this.pinnedMessageContainer.addEventListener('click', (e) => {
e.preventDefault();
e.cancelBubble = true;
let mid = +this.pinnedMessageContainer.getAttribute('data-mid');
this.setPeer(this.peerID, mid);
});
this.btnMenuMute.addEventListener('click', () => this.mutePeer());
this.btnMute.addEventListener('click', () => this.mutePeer());
let onKeyDown = (e: KeyboardEvent) => {
let target = e.target as HTMLElement;
//if(target.tagName == 'INPUT') return;
//this.log('onkeydown', e);
if(this.chatInputC.attachMediaPopUp.container.classList.contains('active')) {
if(target.tagName != 'INPUT') {
this.chatInputC.attachMediaPopUp.captionInput.focus();
}
if(e.key == 'Enter') {
this.chatInputC.attachMediaPopUp.sendBtn.click();
} else if(e.key == 'Escape') {
this.chatInputC.attachMediaPopUp.container.classList.remove('active');
}
return;
}
5 years ago
if(e.key == 'Meta' || e.key == 'Control') {
return;
} else if(e.key == 'c' && (e.ctrlKey || e.metaKey) && target.tagName != 'INPUT') {
return;
}
if(e.target != this.chatInputC.messageInput && target.tagName != 'INPUT') {
this.chatInputC.messageInput.focus();
placeCaretAtEnd(this.chatInputC.messageInput);
}
};
document.body.addEventListener('keydown', onKeyDown);
/* this.chatInner.addEventListener('mouseover', () => {
document.body.addEventListener('keydown', onKeyDown);
this.log('mouseover');
this.chatInner.addEventListener('mouseout', () => {
document.body.removeEventListener('keydown', onKeyDown);
}, {once: true});
}); */
this.chatInner.addEventListener('contextmenu', e => {
let bubble: HTMLDivElement = null;
try {
bubble = findUpClassName(e.target, 'bubble');
} catch(e) {}
if(bubble) {
e.preventDefault();
e.cancelBubble = true;
let msgID = 0;
for(let id in this.bubbles) {
if(this.bubbles[id] === bubble) {
msgID = +id;
break;
}
}
if(!msgID) return;
if(this.myID == this.peerID ||
(this.peerID < 0 && !appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID))) {
this.contextMenuPin.style.display = '';
} else this.contextMenuPin.style.display = 'none';
this.contextMenuMsgID = msgID;
let side = bubble.parentElement.classList.contains('in') ? 'left' : 'right';
this.contextMenuEdit.style.display = side == 'right' ? '' : 'none';
this.contextMenu.classList.remove('bottom-left', 'bottom-right');
this.contextMenu.classList.add(side == 'left' ? 'bottom-right' : 'bottom-left');
let {clientX, clientY} = e;
this.contextMenu.style.left = (side == 'right' ? clientX - this.contextMenu.scrollWidth : clientX) + 'px';
if((clientY + this.contextMenu.scrollHeight) > window.innerHeight) {
this.contextMenu.style.top = (window.innerHeight - this.contextMenu.scrollHeight) + 'px';
} else {
this.contextMenu.style.top = clientY + 'px';
}
//this.contextMenu.classList.add('active');
openBtnMenu(this.contextMenu);
5 years ago
/////this.log('contextmenu', e, bubble, msgID, side);
}
});
this.contextMenu.querySelector('.menu-copy').addEventListener('click', () => {
let message = appMessagesManager.getMessage(this.contextMenuMsgID);
let str = message ? message.message : '';
var textArea = document.createElement("textarea");
textArea.value = str;
textArea.style.position = "fixed"; //avoid scrolling to bottom
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
} catch (err) {
console.error('Oops, unable to copy', err);
}
document.body.removeChild(textArea);
});
this.contextMenu.querySelector('.menu-delete').addEventListener('click', () => {
if(this.peerID == this.myID) {
this.popupDeleteMessage.deleteBothBtn.style.display = 'none';
this.popupDeleteMessage.deleteMeBtn.innerText = 'DELETE';
} else {
this.popupDeleteMessage.deleteBothBtn.style.display = '';
this.popupDeleteMessage.deleteMeBtn.innerText = 'DELETE JUST FOR ME';
if(this.peerID > 0) {
let title = appPeersManager.getPeerTitle(this.peerID);
this.popupDeleteMessage.deleteBothBtn.innerHTML = 'DELETE FOR ME AND ' + title;
} else {
this.popupDeleteMessage.deleteBothBtn.innerText = 'DELETE FOR ALL';
}
}
this.popupDeleteMessage.popupEl.classList.add('active');
});
this.contextMenu.querySelector('.menu-reply').addEventListener('click', () => {
let message = appMessagesManager.getMessage(this.contextMenuMsgID);
5 years ago
this.chatInputC.setTopInfo(appPeersManager.getPeerTitle(message.fromID, true), message.message, undefined, message.media);
this.chatInputC.replyToMsgID = this.contextMenuMsgID;
this.chatInputC.editMsgID = 0;
});
this.contextMenuEdit.addEventListener('click', () => {
let message = appMessagesManager.getMessage(this.contextMenuMsgID);
5 years ago
this.chatInputC.setTopInfo('Editing', message.message, message.message, message.media);
this.chatInputC.replyToMsgID = 0;
this.chatInputC.editMsgID = this.contextMenuMsgID;
});
this.contextMenuPin.addEventListener('click', () => {
apiManager.invokeApi('messages.updatePinnedMessage', {
flags: 0,
peer: appPeersManager.getInputPeerByID(this.peerID),
id: this.contextMenuMsgID
}).then(updates => {
5 years ago
/////this.log('pinned updates:', updates);
apiUpdatesManager.processUpdateMessage(updates);
});
});
this.popupDeleteMessage.deleteBothBtn.addEventListener('click', () => {
this.deleteMessages(true);
this.popupDeleteMessage.cancelBtn.click();
});
this.popupDeleteMessage.deleteMeBtn.addEventListener('click', () => {
this.deleteMessages(false);
this.popupDeleteMessage.cancelBtn.click();
});
this.goDownBtn.addEventListener('click', () => {
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
if(dialog) {
this.setPeer(this.peerID, dialog.top_message);
} else {
this.scroll.scrollTop = this.scroll.scrollHeight;
}
});
5 years ago
this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);
this.updateStatus();
setInterval(() => this.setPeerStatus(), 60e3);
this.loadMediaQueueProcess();
}
public deleteMessages(revoke = false) {
let flags = revoke ? 1 : 0;
let ids = [this.contextMenuMsgID];
apiManager.invokeApi('messages.deleteMessages', {
flags: flags,
revoke: revoke,
id: ids
}).then((affectedMessages: any) => {
5 years ago
/////this.log('deleted messages:', affectedMessages);
apiUpdatesManager.processUpdateMessage({
_: 'updateShort',
update: {
_: 'updatePts',
pts: affectedMessages.pts,
pts_count: affectedMessages.pts_count
}
});
apiUpdatesManager.processUpdateMessage({
_: 'updateShort',
update: {
_: 'updateDeleteMessages',
messages: ids
}
});
});
}
public deleteEmptySideDivs() {
let nodes = Array.from(this.chatInner.childNodes) as HTMLDivElement[];
nodes.filter((node) => {
let childElementCount = node.childElementCount;
if(!childElementCount) {
node.remove();
return false;
} else if(childElementCount == 1) {
let child = node.firstElementChild;
if(child.classList.contains('service')) {
node.remove();
return false;
}
}
return true;
}).forEach(node => {
let nextNode = node.nextElementSibling;
if(nextNode && node.className == nextNode.className) {
(Array.from(node.childNodes) as HTMLDivElement[]).reverse().forEach(div => {
nextNode.prepend(div);
});
node.remove();
}
});
}
5 years ago
public loadMediaQueuePush(cb: () => Promise<void>) {
this.loadMediaQueue.push(cb);
this.loadMediaQueueProcess();
}
public async loadMediaQueueProcessOld(): Promise<void[]> {
if(this.loadMediaQueuePromise /* || 1 == 1 */) return this.loadMediaQueuePromise;
5 years ago
let woo = this.loadMediaQueue.splice(-5, 5).reverse().map(f => f());
if(woo.length) {
5 years ago
///this.log('Will load more media:', woo.length);
5 years ago
woo.forEach(async(promise) => {
try {
await promise;
} catch(err) {
this.log.error('loadMediaQueue error:', err);
}
this.loadingMedia--;
});
5 years ago
try {
this.loadMediaQueuePromise = Promise.all(woo);
await this.loadMediaQueuePromise;
} catch(err) {
this.log.error('loadMediaQueue error:', err);
}
}
this.loadMediaQueuePromise = null;
if(this.loadMediaQueue.length) return this.loadMediaQueueProcess();
return this.loadMediaQueuePromise;
}
public async loadMediaQueueProcess(): Promise<void[]> {
if(this.loadingMedia >= 5) return;
let item = this.loadMediaQueue.pop();
if(item) {
this.loadingMedia++;
let peerID = this.peerID;
let promise = item();
try {
await promise;
} catch(err) {
this.log.error('loadMediaQueue error:', err);
}
if(peerID == this.peerID) {
this.loadingMedia--;
}
}
if(this.loadMediaQueue.length) return this.loadMediaQueueProcess();
}
5 years ago
public updateStatus() {
if(!this.myID) return Promise.resolve();
appUsersManager.setUserStatus(this.myID, this.offline);
return apiManager.invokeApi('account.updateStatus', {
5 years ago
offline: this.offline
}, {noErrorBox: true});
}
public onScroll() {
let length = this.unreaded.length;
let readed: number[] = [];
for(let i = length - 1; i >= 0; --i) {
let msgID = this.unreaded[i];
let bubble = this.bubbles[msgID];
if(isElementInViewport(bubble)) {
readed.push(msgID);
this.unreaded.splice(i, 1);
}
}
lottieLoader.checkAnimations();
if(readed.length) {
let max = Math.max(...readed);
5 years ago
let min = Math.min(...readed);
5 years ago
if(this.peerID < 0) {
max = appMessagesIDsManager.getMessageIDInfo(max)[0];
min = appMessagesIDsManager.getMessageIDInfo(min)[0];
}
5 years ago
//appMessagesManager.readMessages(readed);
appMessagesManager.readHistory(this.peerID, max, min).catch((err: any) => {
this.log.error('readHistory err:', err);
appMessagesManager.readHistory(this.peerID, max, min);
});
5 years ago
}
if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) {
this.scroll.parentElement.classList.add('scrolled-down');
} else if(this.scroll.parentElement.classList.contains('scrolled-down')) {
this.scroll.parentElement.classList.remove('scrolled-down');
}
// load more history
if(!this.getHistoryPromise && !this.getHistoryTimeout && !testScroll) {
5 years ago
this.getHistoryTimeout = setTimeout(() => { // must be
let history = Object.keys(this.bubbles).map(id => +id).sort();
/* let history = appMessagesManager.historiesStorage[this.peerID].history;
let length = history.length; */
// filter negative ids
let lastBadIndex = -1;
for(let i = 0; i < history.length; ++i) {
if(history[i] <= 0) lastBadIndex = i;
else break;
}
if(lastBadIndex != -1) {
history = history.slice(lastBadIndex + 1);
}
5 years ago
this.getHistoryTimeout = 0;
let willLoad = false;
if(!this.scrolledAll) {
let length = history.length < 10 ? history.length : 10;
for(let i = 0; i < length; ++i) {
let msgID = history[i];
let bubble = this.bubbles[msgID];
if(!bubble) {
this.log.error('no bubble by msgID:', msgID);
continue;
}
if(isElementInViewport(bubble)) {
willLoad = true;
5 years ago
5 years ago
////this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history, bubble);
/* false && */!testScroll && this.getHistory(history[0], true).then(() => { // uncomment
this.onScroll();
}).catch(err => {
this.log.warn('Could not load more history, err:', err);
});
break;
}
5 years ago
}
}
if(this.scrolledAllDown) return;
5 years ago
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
/* if(!dialog) {
this.log.warn('no dialog for load history');
return;
} */
5 years ago
// if scroll down after search
if(!willLoad && (!dialog || history.indexOf(dialog.top_message) === -1)) {
5 years ago
let lastMsgIDs = history.slice(-10);
for(let msgID of lastMsgIDs) {
let bubble = this.bubbles[msgID];
if(isElementInViewport(bubble)) {
willLoad = true;
5 years ago
////this.log('Will load more (down) history by maxID:', lastMsgIDs[lastMsgIDs.length - 1], lastMsgIDs, bubble);
5 years ago
/* false && */!testScroll && this.getHistory(lastMsgIDs[lastMsgIDs.length - 1], false, true).then(() => { // uncomment
this.onScroll();
}).catch(err => {
this.log.warn('Could not load more history, err:', err);
});
break;
}
}
}
}, 0);
}
}
public setScroll(scroll: HTMLDivElement) {
this.scroll = scroll;
this.scrollPosition = new ScrollPosition(this.chatInner);
this.scroll.addEventListener('scroll', this.onScroll.bind(this));
this.scroll.parentElement.classList.add('scrolled-down');
5 years ago
}
public setPeerStatus() {
if(!this.myID) return;
// set subtitle
this.subtitleEl.innerText = appSidebarRight.profileElements.subtitle.innerText = '';
this.subtitleEl.classList.remove('online');
appSidebarRight.profileElements.subtitle.classList.remove('online');
if(this.peerID < 0) { // not human
let chat = appPeersManager.getPeer(this.peerID);
let isChannel = appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID);
5 years ago
///////this.log('setPeerStatus', chat);
Promise.all([
appPeersManager.isMegagroup(this.peerID) ? apiManager.invokeApi('messages.getOnlines', {
peer: appPeersManager.getInputPeerByID(this.peerID)
}) as Promise<any> : Promise.resolve(),
// will redirect if wrong
appProfileManager.getChatFull(chat.id)
]).then(results => {
let [chatOnlines, chatInfo] = results;
let onlines = chatOnlines ? chatOnlines.onlines : 1;
5 years ago
///////////this.log('chatInfo res:', chatInfo);
if(chatInfo.pinned_msg_id) { // request pinned message
this.pinnedMsgID = chatInfo.pinned_msg_id;
appMessagesManager.wrapSingleMessage(chatInfo.pinned_msg_id);
5 years ago
}
let participants_count = chatInfo.participants_count || chatInfo.participants.participants.length;
5 years ago
let subtitle = numberWithCommas(participants_count) + ' ' + (isChannel ? 'subscribers' : 'members');
if(onlines > 1) {
subtitle += ', ' + numberWithCommas(onlines) + ' online';
}
5 years ago
this.subtitleEl.innerText = appSidebarRight.profileElements.subtitle.innerText = subtitle;
});
} else if(!appUsersManager.isBot(this.peerID)) { // user
let user = appUsersManager.getUser(this.peerID);
//this.subtitleEl.classList.remove('online');
if(user && user.status && this.myID != this.peerID) {
let subtitle = '';
switch(user.status._) {
case 'userStatusRecently':
subtitle += 'last seen recently';
break;
case 'userStatusOffline':
subtitle = 'last seen ';
let date = user.status.was_online;
let now = Date.now() / 1000;
if((now - date) < 60) {
subtitle += ' just now';
} else if((now - date) < 3600) {
subtitle += ((now - date) / 60 | 0) + ' minutes ago';
} else if(now - date < 86400) {
subtitle += ((now - date) / 3600 | 0) + ' hours ago';
} else {
let d = new Date(date * 1000);
subtitle += ('0' + d.getDate()).slice(-2) + '.' + ('0' + (d.getMonth() + 1)).slice(-2) + ' at ' +
('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2);
}
break;
case 'userStatusOnline':
this.subtitleEl.classList.add('online');
appSidebarRight.profileElements.subtitle.classList.add('online');
subtitle = 'online';
break;
}
appSidebarRight.profileElements.subtitle.innerText = subtitle;
if(this.typingUsers[this.peerID] == this.peerID) {
this.subtitleEl.innerText = 'typing...';
this.subtitleEl.classList.add('online');
} else this.subtitleEl.innerText = subtitle;
}
}
}
public cleanup() {
this.peerID = $rootScope.selectedPeerID = 0;
this.scrolledAll = false;
this.scrolledAllDown = false;
this.muted = false;
5 years ago
if(this.lastContainerDiv) this.lastContainerDiv.remove();
if(this.firstContainerDiv) this.firstContainerDiv.remove();
this.lastContainerDiv = undefined;
this.firstContainerDiv = undefined;
for(let i in this.bubbles) {
let bubble = this.bubbles[i];
bubble.remove();
}
this.bubbles = {};
this.dateMessages = {};
this.unreaded = [];
this.unreadOut = [];
this.loadMediaQueue = [];
this.loadingMedia = 0;
this.needUpdate.length = 0;
5 years ago
lottieLoader.checkAnimations(false, 'chat', true);
// clear input
this.chatInputC.messageInput.innerHTML = '';
this.chatInputC.replyElements.cancelBtn.click();
5 years ago
// clear messages
5 years ago
this.chatInner.innerHTML = '';
//appSidebarRight.minMediaID = {};
}
public setPeer(peerID: number, lastMsgID = 0, forwarding = false) {
if(peerID == 0) {
appSidebarRight.toggleSidebar(false);
this.topbar.style.display = this.chatInput.style.display = this.goDownBtn.style.display = 'none';
this.cleanup();
return Promise.resolve(false);
}
5 years ago
let samePeer = this.peerID == peerID;
if(this.setPeerPromise && samePeer) return this.setPeerPromise;
if(lastMsgID) {
appMessagesManager.readHistory(peerID, lastMsgID); // lol
}
if(samePeer) {
if(!testScroll && !lastMsgID) {
return Promise.resolve(true);
}
5 years ago
if(this.bubbles[lastMsgID]) {
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
if(dialog && lastMsgID == dialog.top_message) {
this.scroll.scrollTop = this.scroll.scrollHeight;
} else {
this.bubbles[lastMsgID].scrollIntoView();
}
5 years ago
return Promise.resolve(true);
}
}
// clear
this.cleanup();
// set new
this.peerID = $rootScope.selectedPeerID = peerID;
// no dialog
/* if(!appMessagesManager.getDialogByPeerID(this.peerID).length) {
5 years ago
this.log.error('No dialog by peerID:', this.peerID);
return Promise.reject();
} */
5 years ago
this.pinnedMessageContainer.style.display = 'none';
this.preloader.attach(this.chatInner);
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0] || null;
5 years ago
//////this.log('setPeer peerID:', this.peerID, dialog, lastMsgID);
appDialogsManager.loadDialogPhoto(this.avatarEl, this.peerID);
appDialogsManager.loadDialogPhoto(appSidebarRight.profileElements.avatar, this.peerID);
if(!samePeer && appDialogsManager.lastActiveListElement) {
appDialogsManager.lastActiveListElement.classList.remove('active');
}
5 years ago
this.firstTopMsgID = dialog ? dialog.top_message : 0;
5 years ago
/* let dom = appDialogsManager.getDialogDom(this.peerID);
5 years ago
if(!dom) {
this.log.warn('No rendered dialog by peerID:', this.peerID);
appDialogsManager.addDialog(dialog);
dom = appDialogsManager.getDialogDom(this.peerID);
}
// warning need check
dom.listEl.classList.add('active'); */
5 years ago
this.setPeerStatus();
//this.titleEl.innerHTML = appSidebarRight.profileElements.name.innerHTML = dom.titleSpan.innerHTML;
this.titleEl.innerHTML = appSidebarRight.profileElements.name.innerHTML = appPeersManager.getPeerTitle(this.peerID);
5 years ago
this.topbar.style.display = this.goDownBtn.style.display = '';
5 years ago
appSidebarRight.toggleSidebar(true);
this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : '';
if(appPeersManager.isAnyGroup(peerID)) {
this.chatInner.classList.add('is-chat');
} else {
this.chatInner.classList.remove('is-chat');
}
return this.setPeerPromise = Promise.all([
this.getHistory(forwarding ? lastMsgID + 1 : lastMsgID).then(() => {
5 years ago
////this.log('setPeer removing preloader');
5 years ago
if(lastMsgID) {
if(!forwarding) {
let message = appMessagesManager.getMessage(lastMsgID);
5 years ago
//////this.log('setPeer render last message:', message, lastMsgID);
this.renderMessage(message);
}
5 years ago
if(!dialog || lastMsgID != dialog.top_message) {
let bubble = this.bubbles[lastMsgID];
if(bubble) this.bubbles[lastMsgID].scrollIntoView();
else this.log.warn('no bubble by lastMsgID:', lastMsgID);
} else {
this.scroll.scrollTop = this.scroll.scrollHeight;
5 years ago
}
} else if(dialog && dialog.top_message) { // add last message, bc in getHistory will load < max_id
5 years ago
this.renderMessage(appMessagesManager.getMessage(dialog.top_message));
}
if(this.scroll) {
this.onScroll();
}
this.preloader.detach();
//setTimeout(() => {
5 years ago
//appSidebarRight.fillProfileElements();
appSidebarRight.loadSidebarMedia();
//}, 500);
5 years ago
return true;
})/* .catch(err => {
this.log.error(err);
}) */,
appSidebarRight.fillProfileElements()
]).then(() => {
if(this.peerID == peerID) {
this.setPeerPromise = null;
}
return true;
}).catch(err => {
if(this.peerID == peerID) {
this.setPeerPromise = null;
}
5 years ago
this.log.error('setPeer promises error:', err);
return false;
5 years ago
});
}
public setTyping(action: any): Promise<boolean> {
if(!this.peerID) return Promise.resolve(false);
if(typeof(action) == 'string') {
action = {_: action};
}
let input = appPeersManager.getInputPeerByID(this.peerID);
return apiManager.invokeApi('messages.setTyping', {
peer: input,
action: action
}) as Promise<boolean>;
}
5 years ago
public updateUnreadByDialog(dialog: any) {
let maxID = this.peerID == this.myID ? dialog.read_inbox_max_id : dialog.read_outbox_max_id;
5 years ago
///////this.log('updateUnreadByDialog', maxID, dialog, this.unreadOut);
5 years ago
let length = this.unreadOut.length;
for(let i = length - 1; i >= 0; --i) {
let msgID = this.unreadOut[i];
if(msgID > 0 && msgID <= maxID) {
5 years ago
let bubble = this.bubbles[msgID];
bubble.classList.remove('is-sent');
bubble.classList.add('is-read');
5 years ago
this.unreadOut.splice(i, 1);
}
}
}
public deleteMessagesByIDs(msgIDs: number[]) {
msgIDs.forEach(id => {
if(this.firstTopMsgID == id) {
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
if(dialog) {
5 years ago
///////this.log('setting firstTopMsgID after delete:', id, dialog.top_message, dialog);
this.firstTopMsgID = dialog.top_message;
}
}
5 years ago
if(!(id in this.bubbles)) return;
let bubble = this.bubbles[id];
let parent = bubble.parentNode as HTMLDivElement;
delete this.bubbles[id];
bubble.remove();
if(!parent.childNodes.length) {
parent.remove();
}
});
lottieLoader.checkAnimations();
}
public renderMessagesByIDs(msgIDs: number[]) {
if(!this.bubbles[this.firstTopMsgID] && Object.keys(this.bubbles).length) { // seems search active
5 years ago
//////this.log('seems search is active, skipping render:', msgIDs);
5 years ago
return;
}
msgIDs.forEach((msgID: number) => {
let message = appMessagesManager.getMessage(msgID);
5 years ago
/////////this.log('got new message to append:', message);
5 years ago
//this.unreaded.push(msgID);
this.renderMessage(message);
});
}
public renderMessage(message: any, reverse = false, multipleRender?: boolean, bubble: HTMLDivElement = null, updatePosition = true) {
5 years ago
/////this.log('message to render:', message);
if(message.deleted) return;
5 years ago
let peerID = this.peerID;
let our = message.fromID == this.myID;
let messageDiv = document.createElement('div');
messageDiv.classList.add('message');
//messageDiv.innerText = message.message;
if(!multipleRender) {
this.scrollPosition.prepareFor(reverse ? 'up' : 'down'); // лагает из-за этого
}
// bubble
if(!bubble) {
bubble = document.createElement('div');
bubble.classList.add('bubble');
this.bubbles[+message.mid] = bubble;
} else {
bubble.className = 'bubble';
bubble.innerHTML = '';
}
5 years ago
// time section
let date = new Date(message.date * 1000);
let time = ('0' + date.getHours()).slice(-2) +
':' + ('0' + date.getMinutes()).slice(-2);
if(message.views) {
bubble.classList.add('channel-post');
time = formatNumber(message.views, 1) + ' <i class="tgico-channelviews"></i> ' + time;
}
if(message.edit_date) {
bubble.classList.add('is-edited');
time = '<i class="edited">edited</i> ' + time;
}
5 years ago
let timeSpan = document.createElement('span');
timeSpan.classList.add('time');
let timeInner = document.createElement('div');
timeInner.classList.add('inner', 'tgico');
timeInner.innerHTML = time;
5 years ago
let richText = RichTextProcessor.wrapRichText(message.message, {
entities: message.totalEntities
});
if(message.totalEntities) {
let emojiEntities = message.totalEntities.filter((e: any) => e._ == 'messageEntityEmoji');
let strLength = message.message.length;
let emojiStrLength = emojiEntities.reduce((acc: number, curr: any) => acc + curr.length, 0);
if(emojiStrLength == strLength && emojiEntities.length <= 3) {
let attachmentDiv = document.createElement('div');
attachmentDiv.classList.add('attachment');
attachmentDiv.innerHTML = richText;
messageDiv.classList.add('message-empty');
bubble.classList.add('emoji-' + emojiEntities.length + 'x', 'emoji-big');
bubble.append(attachmentDiv);
} else {
messageDiv.innerHTML = richText;
}
/* if(strLength == emojiStrLength) {
messageDiv.classList.add('emoji-only');
messageDiv.classList.add('message-empty');
} */
} else {
messageDiv.innerHTML = richText;
}
//messageDiv.innerHTML = 'samsung samsung samsung';
timeSpan.appendChild(timeInner);
messageDiv.append(timeSpan);
bubble.prepend(messageDiv);
//bubble.prepend(timeSpan, messageDiv); // that's bad
5 years ago
if(our) {
if(message.pFlags.unread || message.mid < 0) this.unreadOut.push(message.mid); // message.mid < 0 added 11.02.2020
let status = '';
if(message.mid < 0) status = 'is-sending';
else status = message.pFlags.unread ? 'is-sent' : 'is-read';
5 years ago
bubble.classList.add(status);
} else {
//this.log('not our message', message, message.pFlags.unread);
5 years ago
if(message.pFlags.unread) this.unreaded.push(message.mid);
}
// media
if(message.media) {
let attachmentDiv = document.createElement('div');
attachmentDiv.classList.add('attachment');
if(!message.message) {
messageDiv.classList.add('message-empty');
}
let processingWebPage = false;
switch(message.media._) {
case 'messageMediaPending': {
let pending = message.media;
let preloader = pending.preloader as ProgressivePreloader;
switch(pending.type) {
case 'photo': {
if(pending.size < 5e6) {
let img = new Image();
img.src = URL.createObjectURL(pending.file);
let {w, h} = calcImageInBox(pending.w, pending.h, 380, 380);
attachmentDiv.style.width = w + 'px';
attachmentDiv.style.height = h + 'px';
attachmentDiv.append(img);
preloader.attach(attachmentDiv, false);
bubble.classList.add('hide-name', 'photo');
break;
}
}
case 'audio':
case 'document': {
5 years ago
let docDiv = wrapDocument(pending, false, true);
let icoDiv = docDiv.querySelector('.document-ico');
preloader.attach(icoDiv, false);
messageDiv.classList.remove('message-empty');
messageDiv.append(docDiv);
processingWebPage = true;
break;
}
}
break;
}
5 years ago
case 'messageMediaPhoto': {
let photo = message.media.photo;
5 years ago
////////this.log('messageMediaPhoto', photo);
5 years ago
bubble.classList.add('hide-name', 'photo');
5 years ago
wrapPhoto.call(this, photo, message, attachmentDiv);
5 years ago
break;
}
case 'messageMediaWebPage': {
processingWebPage = true;
let webpage = message.media.webpage;
5 years ago
////////this.log('messageMediaWebPage', webpage);
5 years ago
if(webpage._ == 'webPageEmpty') {
break;
}
bubble.classList.add('webpage');
let box = document.createElement('div');
box.classList.add('box', 'web');
let quote = document.createElement('div');
quote.classList.add('quote');
let nameEl = document.createElement('a');
nameEl.classList.add('name');
let titleDiv = document.createElement('div');
titleDiv.classList.add('title');
let textDiv = document.createElement('div');
textDiv.classList.add('text');
let preview: HTMLDivElement = null;
if(webpage.photo || webpage.document) {
preview = document.createElement('div');
preview.classList.add('preview');
}
let doc: any = null;
if(webpage.document) {
doc = webpage.document;
if(doc.type == 'gif' || doc.type == 'video') {
//if(doc.size <= 20e6) {
bubble.classList.add('video');
wrapVideo.call(this, doc, preview, message);
//}
5 years ago
} else {
doc = null;
}
}
if(webpage.photo && !doc) {
bubble.classList.add('photo');
//appPhotosManager.savePhoto(webpage.photo); // hot-fix because no webpage manager
5 years ago
wrapPhoto.call(this, webpage.photo, message, preview);
5 years ago
}
if(preview) {
quote.append(preview);
}
nameEl.setAttribute('target', '_blank');
nameEl.href = webpage.url || '#';
nameEl.innerHTML = webpage.site_name ? RichTextProcessor.wrapEmojiText(webpage.site_name) : '';
5 years ago
if(webpage.description) {
textDiv.innerHTML = RichTextProcessor.wrapRichText(webpage.description);
}
if(webpage.title) {
titleDiv.innerHTML = RichTextProcessor.wrapRichText(webpage.title);
}
5 years ago
quote.append(nameEl, titleDiv, textDiv);
box.append(quote);
//bubble.prepend(box);
bubble.prepend(timeSpan, box);
5 years ago
//this.log('night running', bubble.scrollHeight);
break;
}
case 'messageMediaDocument': {
let doc = message.media.document;
/* if(document.size > 1e6) { // 1mb
break;
} */
5 years ago
////////this.log('messageMediaDocument', doc);
5 years ago
if(doc.sticker && doc.size <= 1e6) {
bubble.classList.add('sticker');
if(doc.animated) {
bubble.classList.add('sticker-animated');
}
appPhotosManager.setAttachmentSize(doc, attachmentDiv, undefined, undefined, true);
let preloader = new ProgressivePreloader(attachmentDiv, false);
5 years ago
bubble.style.height = attachmentDiv.style.height;
bubble.style.width = attachmentDiv.style.width;
//appPhotosManager.setAttachmentSize(doc, bubble);
let load = () => wrapSticker(doc, attachmentDiv, () => {
if(this.peerID != peerID) {
this.log.warn('peer changed, canceling sticker attach');
return false;
}
return true;
}, null, 'chat', false, !!message.pending || !multipleRender).then(() => {
preloader.detach();
/* attachmentDiv.style.width = '';
attachmentDiv.style.height = ''; */
});
5 years ago
this.loadMediaQueuePush(load);
break;
} else if(doc.mime_type == 'video/mp4' && doc.size <= 20e6) {
5 years ago
////////this.log('never get free 2', doc);
5 years ago
if(doc.type == 'round') {
bubble.classList.add('round');
}
5 years ago
bubble.classList.add('video');
wrapVideo.call(this, doc, attachmentDiv, message, true, null, false, doc.type == 'round');
5 years ago
break;
} else {
let docDiv = wrapDocument(doc);
messageDiv.classList.remove('message-empty');
messageDiv.append(docDiv);
processingWebPage = true;
break;
}
}
default:
messageDiv.classList.remove('message-empty');
messageDiv.innerHTML = 'unrecognized media type: ' + message.media._;
messageDiv.append(timeSpan);
this.log.warn('unrecognized media type:', message.media._, message);
break;
}
if(!processingWebPage) {
bubble.append(attachmentDiv);
}
}
if((this.peerID < 0 && !our) || message.fwd_from || message.reply_to_mid) { // chat
5 years ago
let title = appPeersManager.getPeerTitle(message.fwdFromID || message.fromID);
let isHidden = message.fwd_from && !message.fwd_from.from_id && !message.fwd_from.channel_id;
if(isHidden) {
5 years ago
///////this.log('message to render hidden', message);
title = message.fwd_from.from_name;
bubble.classList.add('hidden-profile');
}
5 years ago
//this.log(title);
if(message.fwdFromID || message.fwd_from) {
5 years ago
bubble.classList.add('forwarded');
if(message.savedFrom) {
let fwd = document.createElement('div');
fwd.classList.add('forward'/* , 'tgico-forward' */);
fwd.innerHTML = `
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">
<defs>
<path d="M13.55 3.24L13.64 3.25L13.73 3.27L13.81 3.29L13.9 3.32L13.98 3.35L14.06 3.39L14.14 3.43L14.22 3.48L14.29 3.53L14.36 3.59L14.43 3.64L22.23 10.85L22.36 10.99L22.48 11.15L22.57 11.31L22.64 11.48L22.69 11.66L22.72 11.85L22.73 12.04L22.71 12.22L22.67 12.41L22.61 12.59L22.53 12.76L22.42 12.93L22.29 13.09L22.23 13.15L14.43 20.36L14.28 20.48L14.12 20.58L13.95 20.66L13.77 20.72L13.58 20.76L13.4 20.77L13.22 20.76L13.03 20.73L12.85 20.68L12.68 20.61L12.52 20.52L12.36 20.4L12.22 20.27L12.16 20.2L12.1 20.13L12.05 20.05L12.01 19.98L11.96 19.9L11.93 19.82L11.89 19.73L11.87 19.65L11.84 19.56L11.83 19.47L11.81 19.39L11.81 19.3L11.8 19.2L11.8 16.42L11 16.49L10.23 16.58L9.51 16.71L8.82 16.88L8.18 17.09L7.57 17.33L7.01 17.6L6.48 17.91L5.99 18.26L5.55 18.64L5.14 19.05L4.77 19.51L4.43 19.99L4.29 20.23L4.21 20.35L4.11 20.47L4 20.57L3.88 20.65L3.75 20.72L3.62 20.78L3.48 20.82L3.33 20.84L3.19 20.84L3.04 20.83L2.9 20.79L2.75 20.74L2.62 20.68L2.53 20.62L2.45 20.56L2.38 20.5L2.31 20.43L2.25 20.36L2.2 20.28L2.15 20.19L2.11 20.11L2.07 20.02L2.04 19.92L2.02 19.83L2.01 19.73L2 19.63L2.04 17.99L2.19 16.46L2.46 15.05L2.85 13.75L3.35 12.58L3.97 11.53L4.7 10.6L5.55 9.8L6.51 9.12L7.59 8.56L8.77 8.13L10.07 7.83L11.48 7.65L11.8 7.63L11.8 4.8L11.91 4.56L12.02 4.35L12.14 4.16L12.25 3.98L12.37 3.82L12.48 3.68L12.61 3.56L12.73 3.46L12.85 3.38L12.98 3.31L13.11 3.27L13.24 3.24L13.37 3.23L13.46 3.23L13.55 3.24Z" id="b13RmHDQtl"></path>
</defs>
<use xlink:href="#b13RmHDQtl" opacity="1" fill="#fff" fill-opacity="1"></use>
</svg>`;
bubble.append(fwd);
bubble.dataset.savedFrom = message.savedFrom;
}
5 years ago
if(!bubble.classList.contains('sticker')) {
let nameDiv = document.createElement('div');
nameDiv.classList.add('name');
nameDiv.innerHTML = 'Forwarded from ' + title;
nameDiv.dataset.peerID = message.fwdFromID;
//nameDiv.style.color = appPeersManager.getPeerColorByID(message.fromID, false);
5 years ago
bubble.append(nameDiv);
}
} else {
if(message.reply_to_mid) {
let originalMessage = appMessagesManager.getMessage(message.reply_to_mid);
5 years ago
let originalPeerTitle = appPeersManager.getPeerTitle(originalMessage.fromID, true) || '';
5 years ago
5 years ago
/////////this.log('message to render reply', originalMessage, originalPeerTitle, bubble, message);
// need to download separately
if(originalMessage._ == 'messageEmpty') {
5 years ago
//////////this.log('message to render reply empty, need download', message, message.reply_to_mid);
appMessagesManager.wrapSingleMessage(message.reply_to_mid);
this.needUpdate.push({replyMid: message.reply_to_mid, mid: message.mid});
originalPeerTitle = 'Loading...';
}
if(originalMessage.mid) {
bubble.setAttribute('data-original-mid', originalMessage.mid);
} else {
bubble.setAttribute('data-original-mid', message.reply_to_mid);
}
5 years ago
bubble.append(wrapReply(originalPeerTitle, originalMessage.message || '', originalMessage.media));
bubble.classList.add('is-reply');
5 years ago
}
if(!bubble.classList.contains('sticker') && (peerID < 0 && peerID != message.fromID)) {
5 years ago
let nameDiv = document.createElement('div');
nameDiv.classList.add('name');
nameDiv.innerHTML = title;
nameDiv.style.color = appPeersManager.getPeerColorByID(message.fromID, false);
nameDiv.dataset.peerID = message.fromID;
5 years ago
bubble.append(nameDiv);
} else /* if(!message.reply_to_mid) */ {
bubble.classList.add('hide-name');
5 years ago
}
//bubble.prepend(avatarDiv);
/* if(messageDiv.nextElementSibling) {
bubble.insertBefore(avatarDiv, messageDiv.nextElementSibling);
} else { */
//}
}
if(!our && this.peerID < 0 &&
(!appPeersManager.isChannel(this.peerID) || appPeersManager.isMegagroup(this.peerID))) {
let avatarDiv = document.createElement('div');
avatarDiv.classList.add('user-avatar');
5 years ago
/////////this.log('exec loadDialogPhoto', message);
if(message.fromID) { // if no - user hidden
appDialogsManager.loadDialogPhoto(avatarDiv, message.fromID);
} else if(!title && message.fwd_from && message.fwd_from.from_name) {
title = message.fwd_from.from_name;
5 years ago
appDialogsManager.loadDialogPhoto(avatarDiv, title);
}
avatarDiv.dataset.peerID = message.fromID;
bubble.append(avatarDiv);
5 years ago
}
} else {
bubble.classList.add('hide-name');
5 years ago
}
if(message._ == 'messageService') {
bubble.className = 'service';
5 years ago
let action = message.action;
5 years ago
let title = appPeersManager.getPeerTitle(message.fromID);
let name = document.createElement('div');
name.classList.add('name');
name.dataset.peerID = message.fromID;
name.innerHTML = title;
5 years ago
let _ = action._;
if(_ == "messageActionPhoneCall") {
_ += '.' + action.type;
}
// @ts-ignore
5 years ago
let str = (name.innerText ? name.outerHTML + ' ' : '') + langPack[_];
bubble.innerHTML = `<div class="service-msg">${str}</div>`;
5 years ago
}
if(updatePosition) {
let type = our ? 'out' : 'in';
let containerDiv = reverse ? this.firstContainerDiv : this.lastContainerDiv;
if(!containerDiv || !containerDiv.classList.contains(type)) {
/* if(containerDiv) {
if(reverse) this.chatInner.prepend(containerDiv);
else this.chatInner.append(containerDiv);
} */
containerDiv = document.createElement('div');
containerDiv.classList.add(type);
if(!this.firstContainerDiv) this.firstContainerDiv = containerDiv;
if(reverse) this.firstContainerDiv = containerDiv;
else this.lastContainerDiv = containerDiv;
5 years ago
}
if(reverse) {
/* if(!multipleRender) {
this.scrollPosition.prepareFor('up'); // лагает из-за этого
} */
containerDiv.prepend(bubble);
this.chatInner.prepend(containerDiv);
} else {
/* if(!multipleRender) {
this.scrollPosition.prepareFor('down'); // лагает из-за этого
} */
containerDiv.append(bubble);
this.chatInner.append(containerDiv);
5 years ago
}
let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
let dateTimestamp = justDate.getTime();
if(!(dateTimestamp in this.dateMessages)) {
let str = '';
5 years ago
let today = new Date();
today.setHours(0);
today.setMinutes(0);
today.setSeconds(0);
5 years ago
if(today < date) {
str = 'Today';
} else {
const months = ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'];
str = justDate.getFullYear() == new Date().getFullYear() ?
months[justDate.getMonth()] + ' ' + justDate.getDate() :
justDate.toISOString().split('T')[0].split('-').reverse().join('.');
}
let div = document.createElement('div');
div.classList.add('service');
div.innerHTML = `<div class="service-msg">${str}</div>`;
5 years ago
////////this.log('need to render date message', dateTimestamp, str);
this.dateMessages[dateTimestamp] = {
div,
firstTimestamp: date.getTime()
};
//this.chatInner.insertBefore(div, containerDiv);
containerDiv.insertBefore(div, bubble);
} else {
let dateMessage = this.dateMessages[dateTimestamp];
if(dateMessage.firstTimestamp > date.getTime()) {
//this.chatInner.insertBefore(dateMessage.div, containerDiv);
containerDiv.insertBefore(dateMessage.div, bubble);
}
}
}
5 years ago
/* if(bubble.classList.contains('webpage')) {
this.log('night running', bubble, bubble.scrollHeight);
} */
5 years ago
//return //this.scrollPosition.restore();
5 years ago
if(!multipleRender) {
this.scrollPosition.restore(); // лагает из-за этого
}
//this.log('history msg', message);
}
// reverse means scroll up
public getHistory(maxID = 0, reverse = false, isBackLimit = false) {
let peerID = this.peerID;
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
if(!maxID && dialog && dialog.top_message) {
maxID = dialog.top_message/* + 1 */;
5 years ago
}
let loadCount = Object.keys(this.bubbles).length > 0 ?
20 :
(this.chatInner.parentElement.parentElement.scrollHeight) / 30 * 1.25 | 0;
if(testScroll) {
loadCount = 1;
//if(Object.keys(this.bubbles).length > 0)
return Promise.resolve(true);
}
5 years ago
//console.time('render getHistory');
//console.time('render history total');
5 years ago
let backLimit = 0;
if(isBackLimit) {
backLimit = loadCount;
loadCount = 0;
maxID += 1;
}
return this.getHistoryPromise = appMessagesManager.getHistory(this.peerID, maxID, loadCount, backLimit)
.then((result: any) => {
5 years ago
///////this.log('getHistory result by maxID:', maxID, reverse, isBackLimit, result);
5 years ago
5 years ago
//console.timeEnd('render getHistory');
5 years ago
if(this.peerID != peerID) {
this.log.warn('peer changed');
5 years ago
//console.timeEnd('render history total');
5 years ago
return Promise.reject();
}
if(!result || !result.history) {
5 years ago
//console.timeEnd('render history total');
5 years ago
return true;
}
// commented bot getProfile in getHistory!
if(!result.history/* .filter((id: number) => id > 0) */.length) {
if(!isBackLimit) {
this.scrolledAll = true;
} else {
this.scrolledAllDown = true;
}
}
5 years ago
//this.chatInner.innerHTML = '';
let history = result.history.slice();
if(reverse) history.reverse();
5 years ago
//console.time('render history');
5 years ago
if(!isBackLimit) {
this.scrollPosition.prepareFor(reverse ? 'up' : 'down');
}
let length = history.length;
for(let i = length - 1; i >= 0; --i) {
let msgID = history[i];
let message = appMessagesManager.getMessage(msgID);
this.renderMessage(message, reverse, true);
}
if(!isBackLimit) {
this.scrollPosition.restore();
}
5 years ago
//console.timeEnd('render history');
5 years ago
this.getHistoryPromise = undefined;
5 years ago
//console.timeEnd('render history total');
5 years ago
return true;
});
}
public setMutedState(muted = false) {
appSidebarRight.profileElements.notificationsCheckbox.checked = !muted;
appSidebarRight.profileElements.notificationsStatus.innerText = muted ? 'Disabled' : 'Enabled';
let peerID = this.peerID;
this.muted = muted;
if(peerID < 0) { // not human
let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
if(isChannel) {
this.btnMute.classList.remove('tgico-mute', 'tgico-unmute');
this.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');
this.btnMute.style.display = '';
} else {
this.btnMute.style.display = 'none';
}
} else {
this.btnMute.style.display = 'none';
}
this.btnMenuMute.classList.remove('tgico-mute', 'tgico-unmute');
this.btnMenuMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');
let rp = this.btnMenuMute.firstElementChild;
this.btnMenuMute.innerText = muted ? 'Unmute' : 'Mute';
this.btnMenuMute.appendChild(rp);
}
public mutePeer() {
let inputPeer = appPeersManager.getInputPeerByID(this.peerID);
let inputNotifyPeer = {
_: 'inputNotifyPeer',
peer: inputPeer
};
let settings: any = {
_: 'inputPeerNotifySettings',
flags: 0,
mute_until: 0
};
if(!this.muted) {
settings.flags |= 1 << 2;
settings.mute_until = 2147483646;
} else {
settings.flags |= 2;
}
apiManager.invokeApi('account.updateNotifySettings', {
peer: inputNotifyPeer,
settings: settings
}).then(res => {
this.handleUpdate({_: 'updateNotifySettings', peer: inputNotifyPeer, notify_settings: settings});
});
/* return apiManager.invokeApi('account.getNotifySettings', {
peer: inputNotifyPeer
}).then((settings: any) => {
settings.flags |= 2 << 1;
settings.mute_until = 2000000000; // 2147483646
return apiManager.invokeApi('account.updateNotifySettings', {
peer: inputNotifyPeer,
settings: Object.assign(settings, {
_: 'inputPeerNotifySettings'
})
}).then(res => {
this.log('mute result:', res);
});
}); */
}
public handleUpdate(update: any) {
switch(update._) {
case 'updateUserTyping':
case 'updateChatUserTyping':
if(this.myID == update.user_id) {
return;
}
var peerID = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id;
this.typingUsers[update.user_id] = peerID;
if(!appUsersManager.hasUser(update.user_id)) {
if(update.chat_id &&
appChatsManager.hasChat(update.chat_id) &&
!appChatsManager.isChannel(update.chat_id)) {
appProfileManager.getChatFull(update.chat_id);
}
//return;
}
appUsersManager.forceUserOnline(update.user_id);
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
let currentPeer = this.peerID == peerID;
if(this.typingTimeouts[peerID]) clearTimeout(this.typingTimeouts[peerID]);
else if(dialog) {
appDialogsManager.setTyping(dialog, appUsersManager.getUser(update.user_id));
if(currentPeer) { // user
this.setPeerStatus();
}
}
this.typingTimeouts[peerID] = setTimeout(() => {
this.typingTimeouts[peerID] = 0;
delete this.typingUsers[update.user_id];
if(dialog) {
appDialogsManager.unsetTyping(dialog);
}
// лень просчитывать случаи
this.setPeerStatus();
}, 6000);
break;
case 'updateNotifySettings': {
let {peer, notify_settings} = update;
// peer was NotifyPeer
peer = peer.peer;
let peerID = appPeersManager.getPeerID(peer);
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
if(dialog) {
dialog.notify_settings = notify_settings;
}
if(peerID == this.peerID) {
let muted = notify_settings.mute_until ? new Date(notify_settings.mute_until * 1000) > new Date() : false;
this.setMutedState(muted);
}
5 years ago
/////this.log('updateNotifySettings', peerID, notify_settings);
break;
}
case 'updateChatPinnedMessage':
case 'updateUserPinnedMessage': {
let {id} = update;
5 years ago
/////this.log('updateUserPinnedMessage', update);
this.pinnedMsgID = id;
// hz nado li tut appMessagesIDsManager.getFullMessageID(update.max_id, channelID);
let peerID = update.user_id || -update.chat_id || -update.channel_id;
if(peerID == this.peerID) {
appMessagesManager.wrapSingleMessage(id);
}
break;
}
}
}
5 years ago
}
const appImManager = new AppImManager();
export default appImManager;