Browse Source

GIF sending & fix blink after message send

master
morethanwords 5 years ago
parent
commit
2a5ad412f1
  1. 56
      src/components/chatInput.ts
  2. 37
      src/components/emoticonsDropdown.ts
  3. 16
      src/components/wrappers.ts
  4. 22
      src/lib/appManagers/appDocsManager.ts
  5. 35
      src/lib/appManagers/appImManager.ts
  6. 2
      src/lib/appManagers/appMediaViewer.ts
  7. 228
      src/lib/appManagers/appMessagesManager.ts
  8. 129
      src/lib/appManagers/appPhotosManager.ts
  9. 9
      src/lib/appManagers/appSidebarRight.ts
  10. 2
      src/lib/appManagers/appStickersManager.ts
  11. 16
      src/lib/appManagers/appWebPagesManager.ts
  12. 2
      src/pages/pageIm.ts
  13. 4
      src/scss/partials/_chat.scss
  14. 2
      src/scss/partials/_emojiDropdown.scss
  15. 1
      tsconfig.json

56
src/components/chatInput.ts

@ -189,6 +189,7 @@ export class ChatInput {
console.log('selected file:', file, typeof(file)); console.log('selected file:', file, typeof(file));
willAttachFile = file; willAttachFile = file;
willAttachObjectURL = '';
this.fileInput.value = ''; this.fileInput.value = '';
@ -207,7 +208,7 @@ export class ChatInput {
switch(willAttach) { switch(willAttach) {
case 'media': { case 'media': {
let img = new Image(); let img = new Image();
img.src = URL.createObjectURL(file); img.src = willAttachObjectURL = URL.createObjectURL(file);
img.onload = () => { img.onload = () => {
willAttachWidth = img.naturalWidth; willAttachWidth = img.naturalWidth;
willAttachHeight = img.naturalHeight; willAttachHeight = img.naturalHeight;
@ -248,6 +249,7 @@ export class ChatInput {
let willAttach = ''; let willAttach = '';
let willAttachFile: File = null; let willAttachFile: File = null;
let willAttachObjectURL = '';
let willAttachWidth = 0, willAttachHeight = 0; let willAttachWidth = 0, willAttachHeight = 0;
this.fileInput.addEventListener('change', (e) => { this.fileInput.addEventListener('change', (e) => {
var file = (e.target as HTMLInputElement & EventTarget).files[0]; var file = (e.target as HTMLInputElement & EventTarget).files[0];
@ -302,14 +304,11 @@ export class ChatInput {
isMedia: true, isMedia: true,
caption, caption,
width: willAttachWidth, width: willAttachWidth,
height: willAttachHeight height: willAttachHeight,
objectURL: willAttachObjectURL
}); });
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
this.onMessageSent();
let dialog = appMessagesManager.getDialogByPeerID(appImManager.peerID)[0];
if(dialog && dialog.top_message) {
appMessagesManager.readHistory(appImManager.peerID, dialog.top_message); // lol
}
}); });
this.btnSend.addEventListener('click', () => { this.btnSend.addEventListener('click', () => {
@ -384,6 +383,29 @@ export class ChatInput {
}, ''); }, '');
}; };
public onMessageSent(scrollDown = true, clearInput = true) {
if(scrollDown) {
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
}
let dialog = appMessagesManager.getDialogByPeerID(appImManager.peerID)[0];
if(dialog && dialog.top_message) {
appMessagesManager.readHistory(appImManager.peerID, dialog.top_message); // lol
}
if(clearInput) {
this.lastUrl = '';
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');
}
}
public sendMessage() { public sendMessage() {
//let str = this.serializeNodes(Array.from(this.messageInput.childNodes)); //let str = this.serializeNodes(Array.from(this.messageInput.childNodes));
let str = getRichValue(this.messageInput); let str = getRichValue(this.messageInput);
@ -391,7 +413,6 @@ export class ChatInput {
//console.log('childnode str after:', str/* , getRichValue(this.messageInput) */); //console.log('childnode str after:', str/* , getRichValue(this.messageInput) */);
//return; //return;
this.lastUrl = '';
if(this.editMsgID) { if(this.editMsgID) {
appMessagesManager.editMessage(this.editMsgID, str, { appMessagesManager.editMessage(this.editMsgID, str, {
@ -403,24 +424,9 @@ export class ChatInput {
noWebPage: this.noWebPage, noWebPage: this.noWebPage,
webPage: this.willSendWebPage webPage: this.willSendWebPage
}); });
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
} }
let dialog = appMessagesManager.getDialogByPeerID(appImManager.peerID)[0]; this.onMessageSent(!this.editMsgID);
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');
}; };
public setTopInfo(title: string, subtitle: string, input?: string, media?: any) { public setTopInfo(title: string, subtitle: string, input?: string, media?: any) {

37
src/components/emoticonsDropdown.ts

@ -206,6 +206,22 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
emoticonsMenuOnClick(menu, heights, emojiScroll); emoticonsMenuOnClick(menu, heights, emojiScroll);
} }
let onMediaClick = (e: MouseEvent) => {
let target = e.target as HTMLDivElement;
target = findUpTag(target, 'DIV');
let fileID = target.dataset.docID;
let document = appDocsManager.getDoc(fileID);
if(document._ != 'documentEmpty') {
appMessagesManager.sendFile(appImManager.peerID, document, {isMedia: true});
appImManager.chatInputC.onMessageSent(true, false);
dropdown.classList.remove('active');
toggleEl.classList.remove('active');
} else {
console.warn('got no doc by id:', fileID);
}
};
let stickersInit = () => { let stickersInit = () => {
let contentStickersDiv = document.getElementById('content-stickers') as HTMLDivElement; let contentStickersDiv = document.getElementById('content-stickers') as HTMLDivElement;
//let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement; //let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;
@ -236,22 +252,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
} }
}); });
stickersDiv.addEventListener('click', (e) => { stickersDiv.addEventListener('click', onMediaClick);
let target = e.target as HTMLDivElement;
target = findUpTag(target, 'DIV');
let fileID = target.getAttribute('file-id');
let document = appStickersManager.getSticker(fileID);
if(document) {
appMessagesManager.sendFile(appImManager.peerID, document, {isMedia: true});
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
dropdown.classList.remove('active');
toggleEl.classList.remove('active');
} else {
console.warn('got no sticker by id:', fileID);
}
});
let heights: number[] = []; let heights: number[] = [];
@ -403,6 +404,8 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
let contentDiv = document.getElementById('content-gifs') as HTMLDivElement; let contentDiv = document.getElementById('content-gifs') as HTMLDivElement;
let masonry = contentDiv.firstElementChild as HTMLDivElement; let masonry = contentDiv.firstElementChild as HTMLDivElement;
masonry.addEventListener('click', onMediaClick);
let scroll = new Scrollable(contentDiv, 'y', 500, 'GIFS', null); let scroll = new Scrollable(contentDiv, 'y', 500, 'GIFS', null);
scroll.container.addEventListener('scroll', (e) => { scroll.container.addEventListener('scroll', (e) => {
@ -459,7 +462,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
let div = document.createElement('div'); let div = document.createElement('div');
div.style.width = w + 'px'; div.style.width = w + 'px';
//div.style.height = h + 'px'; //div.style.height = h + 'px';
div.dataset.documentID = gif.id; div.dataset.docID = gif.id;
masonry.append(div); masonry.append(div);

16
src/components/wrappers.ts

@ -596,7 +596,7 @@ function wrapMediaWithTail(photo: any, message: {mid: number, message: string},
return image; return image;
} }
export async function wrapPhoto(photoID: string, message: any, container: HTMLDivElement, boxWidth = 380, boxHeight = 380, withTail = true, isOut = false, lazyLoadQueue: LazyLoadQueue, middleware: () => boolean) { export function wrapPhoto(photoID: string, message: any, container: HTMLDivElement, boxWidth = 380, boxHeight = 380, withTail = true, isOut = false, lazyLoadQueue: LazyLoadQueue, middleware: () => boolean) {
let photo = appPhotosManager.getPhoto(photoID); let photo = appPhotosManager.getPhoto(photoID);
let size: MTPhotoSize; let size: MTPhotoSize;
@ -615,6 +615,12 @@ export async function wrapPhoto(photoID: string, message: any, container: HTMLDi
console.log('wrapPhoto downloaded:', photo, photo.downloaded, container); console.log('wrapPhoto downloaded:', photo, photo.downloaded, container);
// так нельзя делать, потому что может быть загружен неправильный размер картинки
/* if(photo.downloaded && photo.url) {
renderImageFromUrl(image, photo.url);
return;
} */
let preloader: ProgressivePreloader; let preloader: ProgressivePreloader;
if(!photo.downloaded) preloader = new ProgressivePreloader(container, false); if(!photo.downloaded) preloader = new ProgressivePreloader(container, false);
let load = () => { let load = () => {
@ -625,7 +631,7 @@ export async function wrapPhoto(photoID: string, message: any, container: HTMLDi
} }
return promise.then(() => { return promise.then(() => {
if(!middleware()) return; if(middleware && !middleware()) return;
renderImageFromUrl(image, photo.url); renderImageFromUrl(image, photo.url);
}); });
@ -680,7 +686,7 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
div.append(img); div.append(img);
div.setAttribute('file-id', doc.id); div.dataset.docID = doc.id;
appStickersManager.saveSticker(doc); appStickersManager.saveSticker(doc);
}); });
@ -778,7 +784,7 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
div.append(img); div.append(img);
} }
div.setAttribute('file-id', doc.id); div.dataset.docID = doc.id;
appStickersManager.saveSticker(doc); appStickersManager.saveSticker(doc);
}); });
@ -827,7 +833,7 @@ export function wrapReply(title: string, subtitle: string, media?: any) {
appPhotosManager.preloadPhoto(photo, appPhotosManager.choosePhotoSize(photo, 32, 32)) appPhotosManager.preloadPhoto(photo, appPhotosManager.choosePhotoSize(photo, 32, 32))
.then(blob => { .then(blob => {
renderImageFromUrl(replyMedia, photo.url || URL.createObjectURL(blob)); renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : URL.createObjectURL(blob));
}); });
replyContent.append(replyMedia); replyContent.append(replyMedia);

22
src/lib/appManagers/appDocsManager.ts

@ -5,19 +5,31 @@ import { CancellablePromise } from '../polyfill';
import { MTDocument } from '../../components/wrappers'; import { MTDocument } from '../../components/wrappers';
class AppDocsManager { class AppDocsManager {
private docs: any = {}; private docs: {[docID: string]: MTDocument} = {};
public saveDoc(apiDoc: MTDocument/* any */, context?: any) { public saveDoc(apiDoc: MTDocument/* any */, context?: any) {
console.log('saveDoc', apiDoc, this.docs[apiDoc.id]); console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);
if(this.docs[apiDoc.id]) return this.docs[apiDoc.id]; if(this.docs[apiDoc.id]) {
let d = this.docs[apiDoc.id];
this.docs[apiDoc.id] = apiDoc; if(apiDoc.thumbs) {
if(!d.thumbs) d.thumbs = apiDoc.thumbs;
else if(apiDoc.thumbs[0].bytes && !d.thumbs[0].bytes) {
d.thumbs.unshift(apiDoc.thumbs[0]);
}
}
return context ? Object.assign(d, context) : d;
}
/* if(context) { if(context) {
Object.assign(apiDoc, context); Object.assign(apiDoc, context);
} */ }
this.docs[apiDoc.id] = apiDoc;
if(apiDoc.thumb && apiDoc.thumb._ == 'photoCachedSize') { if(apiDoc.thumb && apiDoc.thumb._ == 'photoCachedSize') {
console.warn('this will happen!!!');
apiFileManager.saveSmallFile(apiDoc.thumb.location, apiDoc.thumb.bytes); apiFileManager.saveSmallFile(apiDoc.thumb.location, apiDoc.thumb.bytes);
// Memory // Memory

35
src/lib/appManagers/appImManager.ts

@ -44,7 +44,7 @@ export class AppImManager {
private getHistoryTopPromise: Promise<boolean>; private getHistoryTopPromise: Promise<boolean>;
private getHistoryBottomPromise: Promise<boolean>; private getHistoryBottomPromise: Promise<boolean>;
private chatInputC: ChatInput = null; public chatInputC: ChatInput = null;
public myID = 0; public myID = 0;
public peerID = 0; public peerID = 0;
@ -158,7 +158,12 @@ export class AppImManager {
let message = appMessagesManager.getMessage(mid); let message = appMessagesManager.getMessage(mid);
//this.log('history_update', this.bubbles[mid], mid, message); //this.log('history_update', this.bubbles[mid], mid, message);
this.renderMessage(message, false, false, bubble); let dateMessage = this.getDateContainerByMessage(message, false);
dateMessage.container.append(bubble);
this.bubbleGroups.addBubble(bubble, message, false);
//this.renderMessage(message, false, false, bubble);
} }
}); });
@ -191,9 +196,21 @@ export class AppImManager {
this.bubbles[mid] = bubble; this.bubbles[mid] = bubble;
/////this.log('message_sent', bubble); /////this.log('message_sent', bubble);
// set cached url to media
let message = appMessagesManager.getMessage(mid);
if(message.media && message.media.photo) {
let photo = appPhotosManager.getPhoto(tempID);
if(photo) {
let newPhoto = message.media.photo;
newPhoto.downloaded = photo.downloaded;
newPhoto.url = photo.url;
}
}
bubble.classList.remove('is-sending'); bubble.classList.remove('is-sending');
bubble.classList.add('is-sent'); bubble.classList.add('is-sent');
bubble.dataset.mid = mid;
this.bubbleGroups.removeBubble(bubble, tempID); this.bubbleGroups.removeBubble(bubble, tempID);
@ -1163,7 +1180,7 @@ export class AppImManager {
// reverse means top // reverse means top
public renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = null, updatePosition = true) { public renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = null, updatePosition = true) {
/////this.log('message to render:', message); this.log('message to render:', message);
if(message.deleted) return; if(message.deleted) return;
let peerID = this.peerID; let peerID = this.peerID;
@ -1323,15 +1340,9 @@ export class AppImManager {
switch(pending.type) { switch(pending.type) {
case 'photo': { case 'photo': {
if(pending.size < 5e6) { if(pending.size < 5e6) {
let img = new Image(); this.log('will wrap pending photo:', pending, message, appPhotosManager.getPhoto(message.id));
img.src = URL.createObjectURL(pending.file); wrapPhoto(message.id, message, attachmentDiv, undefined, undefined, true, true, this.lazyLoadQueue, null);
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); preloader.attach(attachmentDiv, false);
bubble.classList.add('hide-name', 'photo'); bubble.classList.add('hide-name', 'photo');

2
src/lib/appManagers/appMediaViewer.ts

@ -693,7 +693,7 @@ export class AppMediaViewer {
this.preloader.attach(mover); this.preloader.attach(mover);
let cancellablePromise = appPhotosManager.preloadPhoto(media.id, size); let cancellablePromise = appPhotosManager.preloadPhoto(media.id, size);
cancellablePromise.then((blob) => { cancellablePromise.then(() => {
if(this.currentMessageID != message.mid) { if(this.currentMessageID != message.mid) {
this.log.warn('media viewer changed photo'); this.log.warn('media viewer changed photo');
return; return;

228
src/lib/appManagers/appMessagesManager.ts

@ -14,7 +14,7 @@ import ServerTimeManager from "../mtproto/serverTimeManager";
import apiFileManager from "../mtproto/apiFileManager"; import apiFileManager from "../mtproto/apiFileManager";
import appDocsManager from "./appDocsManager"; import appDocsManager from "./appDocsManager";
import appImManager from "./appImManager"; import appImManager from "./appImManager";
import { MTDocument } from "../../components/wrappers"; import { MTDocument, MTPhotoSize } from "../../components/wrappers";
import ProgressivePreloader from "../../components/preloader"; import ProgressivePreloader from "../../components/preloader";
import serverTimeManager from "../mtproto/serverTimeManager"; import serverTimeManager from "../mtproto/serverTimeManager";
import apiManager from "../mtproto/apiManager"; import apiManager from "../mtproto/apiManager";
@ -37,7 +37,6 @@ export type HistoryResult = {
export class AppMessagesManager { export class AppMessagesManager {
public messagesStorage: any = {}; public messagesStorage: any = {};
public messagesForHistory: any = {};
public messagesForDialogs: any = {}; public messagesForDialogs: any = {};
public historiesStorage: { public historiesStorage: {
[peerID: string]: HistoryStorage [peerID: string]: HistoryStorage
@ -107,20 +106,14 @@ export class AppMessagesManager {
$rootScope.$on('webpage_updated', (e: CustomEvent) => { $rootScope.$on('webpage_updated', (e: CustomEvent) => {
let eventData = e.detail; let eventData = e.detail;
eventData.msgs.forEach((msgID: number) => { eventData.msgs.forEach((msgID: number) => {
var historyMessage = this.messagesForHistory[msgID]; let message = this.getMessage(msgID);
if(historyMessage) { message.webpage = appWebPagesManager.getWebPage(eventData.id); // warning
historyMessage.media = { $rootScope.$broadcast('message_edit', {
_: 'messageMediaWebPage', peerID: this.getMessagePeer(message),
webpage: appWebPagesManager.wrapForHistory(eventData.id) id: message.id,
}; mid: msgID,
justMedia: true
$rootScope.$broadcast('message_edit', { });
peerID: this.getMessagePeer(historyMessage),
id: historyMessage.id,
mid: msgID,
justMedia: true
});
}
}); });
}); });
@ -327,17 +320,10 @@ export class AppMessagesManager {
} }
var toggleError = (on: any) => { var toggleError = (on: any) => {
var historyMessage = this.messagesForHistory[messageID];
if(on) { if(on) {
message.error = true; message.error = true;
if(historyMessage) {
historyMessage.error = true;
}
} else { } else {
delete message.error; delete message.error;
if(historyMessage) {
delete historyMessage.error;
}
} }
$rootScope.$broadcast('messages_pending'); $rootScope.$broadcast('messages_pending');
} }
@ -467,7 +453,8 @@ export class AppMessagesManager {
caption?: string, caption?: string,
entities?: any[], entities?: any[],
width?: number, width?: number,
height?: number height?: number,
objectURL?: string
} = {}) { } = {}) {
peerID = AppPeersManager.getPeerMigratedTo(peerID) || peerID; peerID = AppPeersManager.getPeerMigratedTo(peerID) || peerID;
var messageID = this.tempID--; var messageID = this.tempID--;
@ -487,6 +474,8 @@ export class AppMessagesManager {
let isDocument = !(file instanceof File) && !(file instanceof Blob); let isDocument = !(file instanceof File) && !(file instanceof Blob);
let caption = options.caption || ''; let caption = options.caption || '';
let date = tsNow(true) + ServerTimeManager.serverTimeOffset;
if(caption) { if(caption) {
let entities = options.entities || []; let entities = options.entities || [];
caption = RichTextProcessor.parseMarkdown(caption, entities); caption = RichTextProcessor.parseMarkdown(caption, entities);
@ -497,13 +486,31 @@ export class AppMessagesManager {
attachType = 'document'; attachType = 'document';
apiFileName = 'document.' + fileType.split('/')[1]; apiFileName = 'document.' + fileType.split('/')[1];
actionName = 'sendMessageUploadDocumentAction'; actionName = 'sendMessageUploadDocumentAction';
} else if(isDocument) { // maybe it's a sticker } else if(isDocument) { // maybe it's a sticker or gif
attachType = 'document'; attachType = 'document';
apiFileName = ''; apiFileName = '';
} else if(['image/jpeg', 'image/png', 'image/bmp'].indexOf(fileType) >= 0) { } else if(['image/jpeg', 'image/png', 'image/bmp'].indexOf(fileType) >= 0) {
attachType = 'photo'; attachType = 'photo';
apiFileName = 'photo.' + fileType.split('/')[1]; apiFileName = 'photo.' + fileType.split('/')[1];
actionName = 'sendMessageUploadPhotoAction'; actionName = 'sendMessageUploadPhotoAction';
let photo: any = {
_: 'photo',
id: '' + messageID,
sizes: [{
_: 'photoSize',
w: options.width,
h: options.height,
type: 'm',
size: file.size
} as MTPhotoSize],
w: options.width,
h: options.height,
downloaded: file.size,
url: options.objectURL || ''
};
appPhotosManager.savePhoto(photo);
} else if(fileType.substr(0, 6) == 'audio/' || ['video/ogg'].indexOf(fileType) >= 0) { } else if(fileType.substr(0, 6) == 'audio/' || ['video/ogg'].indexOf(fileType) >= 0) {
attachType = 'audio'; attachType = 'audio';
apiFileName = 'audio.' + (fileType.split('/')[1] == 'ogg' ? 'ogg' : 'mp3'); apiFileName = 'audio.' + (fileType.split('/')[1] == 'ogg' ? 'ogg' : 'mp3');
@ -559,6 +566,7 @@ export class AppMessagesManager {
preloader: preloader, preloader: preloader,
w: options.width, w: options.width,
h: options.height, h: options.height,
url: options.objectURL,
progress: { progress: {
percent: 1, percent: 1,
total: file.size, total: file.size,
@ -580,7 +588,7 @@ export class AppMessagesManager {
to_id: AppPeersManager.getOutputPeer(peerID), to_id: AppPeersManager.getOutputPeer(peerID),
flags: flags, flags: flags,
pFlags: pFlags, pFlags: pFlags,
date: tsNow(true) + ServerTimeManager.serverTimeOffset, date: date,
message: caption, message: caption,
media: isDocument ? { media: isDocument ? {
_: 'messageMediaDocument', _: 'messageMediaDocument',
@ -595,19 +603,10 @@ export class AppMessagesManager {
}; };
var toggleError = (on: boolean) => { var toggleError = (on: boolean) => {
var historyMessage = this.messagesForHistory[messageID];
if(on) { if(on) {
message.error = true; message.error = true;
if(historyMessage) {
historyMessage.error = true;
}
} else { } else {
delete message.error; delete message.error;
if(historyMessage) {
delete historyMessage.error;
}
} }
$rootScope.$broadcast('messages_pending'); $rootScope.$broadcast('messages_pending');
@ -677,6 +676,8 @@ export class AppMessagesManager {
} }
uploadPromise && uploadPromise.then((inputFile) => { uploadPromise && uploadPromise.then((inputFile) => {
console.log('appMessagesManager: sendFile uploaded:', inputFile);
inputFile.name = apiFileName; inputFile.name = apiFileName;
uploaded = true; uploaded = true;
var inputMedia; var inputMedia;
@ -767,7 +768,6 @@ export class AppMessagesManager {
historyStorage.pending.splice(pos, 1); historyStorage.pending.splice(pos, 1);
} }
delete this.messagesForHistory[tempID];
delete this.messagesStorage[tempID]; delete this.messagesStorage[tempID];
return true; return true;
@ -2177,10 +2177,6 @@ export class AppMessagesManager {
if(message && !message.pFlags.out) { if(message && !message.pFlags.out) {
message.pFlags.unread = false; message.pFlags.unread = false;
if(this.messagesForHistory[messageID]) {
this.messagesForHistory[messageID].pFlags.unread = false;
}
if(this.messagesForDialogs[messageID]) { if(this.messagesForDialogs[messageID]) {
this.messagesForDialogs[messageID].pFlags.unread = false; this.messagesForDialogs[messageID].pFlags.unread = false;
} }
@ -2235,7 +2231,7 @@ export class AppMessagesManager {
} }
public handleUpdate(update: any) { public handleUpdate(update: any) {
//console.log('AMM: handleUpdate:', update._); console.log('AMM: handleUpdate:', update._);
switch(update._) { switch(update._) {
case 'updateMessageID': { case 'updateMessageID': {
var randomID = update.random_id; var randomID = update.random_id;
@ -2252,14 +2248,8 @@ export class AppMessagesManager {
if(pos != -1) { if(pos != -1) {
historyStorage.pending.splice(pos, 1); historyStorage.pending.splice(pos, 1);
} }
delete this.messagesForHistory[tempID];
delete this.messagesStorage[tempID]; delete this.messagesStorage[tempID];
var msgs: any = {}
msgs[tempID] = true;
//$rootScope.$broadcast('history_delete', {peerID: peerID, msgs: msgs}); // commented 11.02.2020
this.finalizePendingMessageCallbacks(tempID, mid); this.finalizePendingMessageCallbacks(tempID, mid);
} else { } else {
this.pendingByMessageID[mid] = randomID; this.pendingByMessageID[mid] = randomID;
@ -2489,23 +2479,11 @@ export class AppMessagesManager {
this.saveMessages([message], {isEdited: true}); this.saveMessages([message], {isEdited: true});
safeReplaceObject(this.messagesStorage[mid], message); safeReplaceObject(this.messagesStorage[mid], message);
var wasForHistory = this.messagesForHistory[mid];
if(wasForHistory !== undefined) {
delete this.messagesForHistory[mid];
var newForHistory = this.wrapForHistory(mid);
safeReplaceObject(wasForHistory, newForHistory);
this.messagesForHistory[mid] = wasForHistory;
}
var dialog = this.getDialogByPeerID(peerID)[0]; var dialog = this.getDialogByPeerID(peerID)[0];
var isTopMessage = dialog && dialog.top_message == mid; var isTopMessage = dialog && dialog.top_message == mid;
if(message.clear_history) { // that's will never happen if(message.clear_history) { // that's will never happen
if(isTopMessage) { if(isTopMessage) {
$rootScope.$broadcast('dialog_flush', {peerID: peerID}); $rootScope.$broadcast('dialog_flush', {peerID: peerID});
} else {
var msgs: any = {};
msgs[mid] = true;
/////////$rootScope.$broadcast('history_delete', {peerID: peerID, msgs: msgs}); // commented 11.02.2020
} }
} else { } else {
$rootScope.$broadcast('message_edit', { $rootScope.$broadcast('message_edit', {
@ -2562,11 +2540,8 @@ export class AppMessagesManager {
// console.warn('read', messageID, message.pFlags.unread, message) // console.warn('read', messageID, message.pFlags.unread, message)
if(message && message.pFlags.unread) { if(message && message.pFlags.unread) {
message.pFlags.unread = false message.pFlags.unread = false
if(this.messagesForHistory[messageID]) { if(!foundAffected) {
this.messagesForHistory[messageID].pFlags.unread = false; foundAffected = true;
if(!foundAffected) {
foundAffected = true;
}
} }
if(this.messagesForDialogs[messageID]) { if(this.messagesForDialogs[messageID]) {
this.messagesForDialogs[messageID].pFlags.unread = false; this.messagesForDialogs[messageID].pFlags.unread = false;
@ -2614,15 +2589,11 @@ export class AppMessagesManager {
var len = messages.length; var len = messages.length;
var i; var i;
var messageID: number, message; var messageID: number, message;
var historyMessage;
for(i = 0; i < len; i++) { for(i = 0; i < len; i++) {
messageID = messages[i]; messageID = messages[i];
if(message = this.messagesStorage[messageID]) { if(message = this.messagesStorage[messageID]) {
delete message.pFlags.media_unread; delete message.pFlags.media_unread;
} }
if(historyMessage = this.messagesForHistory[messageID]) {
delete historyMessage.pFlags.media_unread;
}
} }
break; break;
} }
@ -2668,10 +2639,6 @@ export class AppMessagesManager {
history.count++; history.count++;
history.msgs[messageID] = true; history.msgs[messageID] = true;
if(this.messagesForHistory[messageID]) {
this.messagesForHistory[messageID].deleted = true;
delete this.messagesForHistory[messageID];
}
if(this.messagesForDialogs[messageID]) { if(this.messagesForDialogs[messageID]) {
this.messagesForDialogs[messageID].deleted = true; this.messagesForDialogs[messageID].deleted = true;
delete this.messagesForDialogs[messageID]; delete this.messagesForDialogs[messageID];
@ -2842,7 +2809,6 @@ export class AppMessagesManager {
}); });
} }
if(update.pFlags.popup && update.message) { if(update.pFlags.popup && update.message) {
var historyMessage = this.wrapForHistory(messageID);
//ErrorService.show({error: {code: 400, type: 'UPDATE_SERVICE_NOTIFICATION'}, historyMessage: historyMessage}); // warning //ErrorService.show({error: {code: 400, type: 'UPDATE_SERVICE_NOTIFICATION'}, historyMessage: historyMessage}); // warning
} }
break; break;
@ -2850,106 +2816,6 @@ export class AppMessagesManager {
} }
} }
public wrapForHistory(msgID: number) {
if(this.messagesForHistory[msgID] !== undefined) {
return this.messagesForHistory[msgID];
}
var message = copy(this.messagesStorage[msgID]) || {id: msgID};
if(message.media && message.media.progress !== undefined) {
message.media.progress = this.messagesStorage[msgID].media.progress;
}
var fromUser = message.from_id && appUsersManager.getUser(message.from_id);
var fromBot = fromUser && fromUser.pFlags.bot && fromUser.username || false;
var withBot = (fromBot ||
message.to_id && (
message.to_id.chat_id ||
message.to_id.user_id && appUsersManager.isBot(message.to_id.user_id)
)
)
if(message.media) {
if(message.media.caption &&
message.media.caption.length) {
message.media.rCaption = RichTextProcessor.wrapRichText(message.media.caption, {
noCommands: !withBot,
fromBot: fromBot
})
}
switch (message.media._) {
case 'messageMediaPhoto':
message.media.photo = appPhotosManager.wrapForHistory(message.media.photo.id)
break
/* case 'messageMediaDocument':
message.media.document = appDocsManager.wrapForHistory(message.media.document.id)
break */
case 'messageMediaGeo':
var mapUrl = 'https://maps.google.com/?q=' + message.media.geo['lat'] + ',' + message.media.geo['long']
message.media.mapUrl = mapUrl;//$sce.trustAsResourceUrl(mapUrl) // warning
break
case 'messageMediaVenue':
var mapUrl: string;
if(message.media.provider == 'foursquare' &&
message.media.venue_id) {
mapUrl = 'https://foursquare.com/v/' + encodeURIComponent(message.media.venue_id)
} else {
mapUrl = 'https://maps.google.com/?q=' + message.media.geo['lat'] + ',' + message.media.geo['long']
}
message.media.mapUrl = mapUrl;//$sce.trustAsResourceUrl(mapUrl) // warning
break
case 'messageMediaContact':
message.media.rFullName = RichTextProcessor.wrapRichText(
message.media.first_name + ' ' + (message.media.last_name || ''),
{noLinks: true, noLinebreaks: true}
)
break
case 'messageMediaWebPage':
if(!message.media.webpage ||
message.media.webpage._ == 'webPageEmpty') {
delete message.media
break
}
message.media.webpage = appWebPagesManager.wrapForHistory(message.media.webpage.id)
break
/*case 'messageMediaGame':
message.media.game = AppGamesManager.wrapForHistory(message.media.game.id)
break */
}
} else if(message.action) {
switch (message.action._) {
case 'messageActionChatEditPhoto':
case 'messageActionChannelEditPhoto':
message.action.photo = appPhotosManager.wrapForHistory(message.action.photo.id);
break
case 'messageActionChatCreate':
case 'messageActionChatEditTitle':
case 'messageActionChannelCreate':
case 'messageActionChannelEditTitle':
message.action.rTitle = RichTextProcessor.wrapRichText(message.action.title, {noLinebreaks: true}) || 'chat_title_deleted';
break
case 'messageActionBotIntro':
message.action.rDescription = RichTextProcessor.wrapRichText(message.action.description, {
noCommands: !withBot,
fromBot: fromBot
});
break;
}
}
return this.messagesForHistory[msgID] = message;
}
public finalizePendingMessage(randomID: number, finalMessage: any) { public finalizePendingMessage(randomID: number, finalMessage: any) {
var pendingData = this.pendingByRandomID[randomID]; var pendingData = this.pendingByRandomID[randomID];
// console.log('pdata', randomID, pendingData) // console.log('pdata', randomID, pendingData)
@ -2958,8 +2824,7 @@ export class AppMessagesManager {
var peerID = pendingData[0]; var peerID = pendingData[0];
var tempID = pendingData[1]; var tempID = pendingData[1];
var historyStorage = this.historiesStorage[peerID], var historyStorage = this.historiesStorage[peerID],
message, message;
historyMessage;
// console.log('pending', randomID, historyStorage.pending) // console.log('pending', randomID, historyStorage.pending)
var pos = historyStorage.pending.indexOf(tempID); var pos = historyStorage.pending.indexOf(tempID);
@ -2972,19 +2837,10 @@ export class AppMessagesManager {
delete message.error; delete message.error;
delete message.random_id; delete message.random_id;
delete message.send; delete message.send;
}
if(historyMessage = this.messagesForHistory[tempID]) {
this.messagesForHistory[finalMessage.mid] = Object.assign(historyMessage, this.wrapForHistory(finalMessage.mid));
delete historyMessage.pending;
delete historyMessage.error;
delete historyMessage.random_id;
delete historyMessage.send;
$rootScope.$broadcast('messages_pending'); $rootScope.$broadcast('messages_pending');
} }
delete this.messagesForHistory[tempID];
delete this.messagesStorage[tempID]; delete this.messagesStorage[tempID];
this.finalizePendingMessageCallbacks(tempID, finalMessage.mid); this.finalizePendingMessageCallbacks(tempID, finalMessage.mid);
@ -2995,10 +2851,6 @@ export class AppMessagesManager {
return false return false
} }
/* public finalizePendingMessageCallbacks(tempID: number, mid: number) {
$rootScope.$broadcast('message_sent', {tempID, mid});
} */
public finalizePendingMessageCallbacks(tempID: number, mid: number) { public finalizePendingMessageCallbacks(tempID: number, mid: number) {
var callbacks = this.tempFinalizeCallbacks[tempID]; var callbacks = this.tempFinalizeCallbacks[tempID];
console.warn(dT(), callbacks, tempID); console.warn(dT(), callbacks, tempID);

129
src/lib/appManagers/appPhotosManager.ts

@ -1,12 +1,12 @@
import appUsersManager from "./appUsersManager"; import appUsersManager from "./appUsersManager";
import { copy, calcImageInBox } from "../utils"; import { calcImageInBox, isObject } from "../utils";
import fileManager from '../filemanager'; import fileManager from '../filemanager';
import { bytesFromHex } from "../bin_utils"; import { bytesFromHex } from "../bin_utils";
import { MTPhotoSize, MTDocument } from "../../components/wrappers"; import { MTPhotoSize } from "../../components/wrappers";
import apiFileManager from "../mtproto/apiFileManager"; import apiFileManager from "../mtproto/apiFileManager";
import apiManager from "../mtproto/apiManager"; import apiManager from "../mtproto/apiManager";
type MTPhoto = { export type MTPhoto = {
_: 'photo' | 'photoEmpty' | string, _: 'photo' | 'photoEmpty' | string,
pFlags: any, pFlags: any,
flags: number, flags: number,
@ -51,7 +51,7 @@ export class AppPhotosManager {
if(!photo.id) { if(!photo.id) {
console.warn('no apiPhoto.id', photo); console.warn('no apiPhoto.id', photo);
} else this.photos[photo.id] = photo; } else this.photos[photo.id] = photo as any;
/* if(!('sizes' in photo)) return; /* if(!('sizes' in photo)) return;
@ -241,98 +241,61 @@ export class AppPhotosManager {
return photoSize; return photoSize;
} }
public preloadPhoto(photoID: any, photoSize?: MTPhotoSize): Promise<Blob | string> { public preloadPhoto(photoID: any, photoSize?: MTPhotoSize): Promise<Blob | void> {
let photo: MTPhoto = null; let photo = this.getPhoto(photoID);
if(typeof(photoID) === 'string') {
photo = this.photos[photoID];
if(!photo) return Promise.reject();
} else {
photo = photoID;
}
if(!photoSize) { if(!photoSize) {
let fullWidth = this.windowW/* - (Config.Mobile ? 20 : 32) */; let fullWidth = this.windowW;
let fullHeight = this.windowH/* - (Config.Mobile ? 150 : 116) */; let fullHeight = this.windowH;
photoSize = this.choosePhotoSize(photo, fullWidth, fullHeight); photoSize = this.choosePhotoSize(photo, fullWidth, fullHeight);
} }
if(photoSize && photoSize._ != 'photoSizeEmpty') {
// maybe it's a thumb
let isPhoto = photoSize.size && photo.access_hash && photo.file_reference;
let location = isPhoto ? {
_: photo._ == 'document' ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',
id: photo.id,
access_hash: photo.access_hash,
file_reference: photo.file_reference,
thumb_size: photoSize.type
} : photoSize.location;
let promise: Promise<Blob>; if(photo.downloaded >= photoSize.size && photo.url) {
return Promise.resolve();
}
/* if(photo.downloaded == photoSize.size && photo.url) { if(!photoSize || photoSize._ == 'photoSizeEmpty') {
return Promise.resolve(photo.url); console.error('no photoSize by photo:', photo);
} */ return Promise.reject('no photoSize');
}
// maybe it's a thumb
let isPhoto = photoSize.size && photo.access_hash && photo.file_reference;
let location = isPhoto ? {
_: photo._ == 'document' ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',
id: photo.id,
access_hash: photo.access_hash,
file_reference: photo.file_reference,
thumb_size: photoSize.type
} : photoSize.location;
if(isPhoto/* && photoSize.size >= 1e6 */) { let promise: Promise<Blob>;
//console.log('Photos downloadFile exec', photo); if(isPhoto/* && photoSize.size >= 1e6 */) {
promise = apiFileManager.downloadFile(photo.dc_id, location, photoSize.size); //console.log('Photos downloadFile exec', photo);
} else { promise = apiFileManager.downloadFile(photo.dc_id, location, photoSize.size);
//console.log('Photos downloadSmallFile exec', photo, location); } else {
promise = apiFileManager.downloadSmallFile(location); //console.log('Photos downloadSmallFile exec', photo, location);
} promise = apiFileManager.downloadSmallFile(location);
}
if(typeof(photoID) === 'string') { if(typeof(photoID) === 'string') {
let photo = this.photos[photoID]; let photo = this.photos[photoID];
promise.then(blob => { promise.then(blob => {
if(!photo.downloaded || photo.downloaded < blob.size) { if(!photo.downloaded || photo.downloaded < blob.size) {
photo.downloaded = blob.size; photo.downloaded = blob.size;
photo.url = URL.createObjectURL(blob); photo.url = URL.createObjectURL(blob);
console.log('wrote photo:', photo, photoSize, blob); console.log('wrote photo:', photo, photoSize, blob);
} }
}); });
} }
return promise; return promise;
} else return Promise.reject('no photoSize');
}
public getPhoto(photoID: string) {
return this.photos[photoID] || {_: 'photoEmpty'} as unknown as Partial<MTPhoto>;
} }
public wrapForHistory(photoID: string, options: any = {}) { public getPhoto(photoID: any): MTPhoto {
var photo = copy(this.photos[photoID]) || {_: 'photoEmpty'}; return isObject(photoID) ? photoID : this.photos[photoID];
var width = options.website ? 64 : Math.min(this.windowW - 80, Config.Mobile ? 210 : 260);
var height = options.website ? 64 : Math.min(this.windowH - 100, Config.Mobile ? 210 : 260);
var thumbPhotoSize = this.choosePhotoSize(photo, width, height);
var thumb: any = {
width: width,
height: height
};
if(options.website && Config.Mobile) {
width = 50;
height = 50;
}
// console.log('chosen photo size', photoID, thumbPhotoSize)
if(thumbPhotoSize && thumbPhotoSize._ != 'photoSizeEmpty') {
var dim = calcImageInBox(thumbPhotoSize.w, thumbPhotoSize.h, width, height);
thumb.width = dim.w;
thumb.height = dim.h;
thumb.location = thumbPhotoSize.location;
thumb.size = thumbPhotoSize.size;
} else {
thumb.width = 100;
thumb.height = 100;
}
photo.thumb = thumb;
return photo;
} }
public downloadPhoto(photoID: string) { public downloadPhoto(photoID: string) {

9
src/lib/appManagers/appSidebarRight.ts

@ -348,19 +348,14 @@ class AppSidebarRight {
//this.log('wrapping webpage', webpage); //this.log('wrapping webpage', webpage);
if(webpage.photo) { if(webpage.photo) {
let load = () => appPhotosManager.preloadPhoto(webpage.photo.id, appPhotosManager.choosePhotoSize(webpage.photo, 380, 0)) let load = () => appPhotosManager.preloadPhoto(webpage.photo.id, appPhotosManager.choosePhotoSize(webpage.photo, 60, 60))
.then((blob) => { .then(() => {
if($rootScope.selectedPeerID != peerID) { if($rootScope.selectedPeerID != peerID) {
this.log.warn('peer changed'); this.log.warn('peer changed');
return; return;
} }
renderImageFromUrl(previewDiv, webpage.photo.url); renderImageFromUrl(previewDiv, webpage.photo.url);
/* let url = URL.createObjectURL(blob);
this.urlsToRevoke.push(url);
previewDiv.style.backgroundImage = 'url(' + url + ')'; */
}); });
this.lazyLoadQueueSidebar.push({div: previewDiv, load}); this.lazyLoadQueueSidebar.push({div: previewDiv, load});

2
src/lib/appManagers/appStickersManager.ts

@ -81,7 +81,7 @@ class appStickersManager {
doc.file_reference = Array.from(doc.file_reference); doc.file_reference = Array.from(doc.file_reference);
appDocsManager.saveDoc(doc); doc = appDocsManager.saveDoc(doc);
this.documents[doc.id] = doc; this.documents[doc.id] = doc;
return doc; return doc;

16
src/lib/appManagers/appWebPagesManager.ts

@ -19,7 +19,7 @@ class AppWebPagesManager {
}); });
} }
saveWebPage(apiWebPage: any, messageID?: number, mediaContext?: any) { public saveWebPage(apiWebPage: any, messageID?: number, mediaContext?: any) {
if(apiWebPage.photo && apiWebPage.photo._ === 'photo') { if(apiWebPage.photo && apiWebPage.photo._ === 'photo') {
//appPhotosManager.savePhoto(apiWebPage.photo, mediaContext); //appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);
apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext); apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);
@ -102,19 +102,9 @@ class AppWebPagesManager {
}); });
} }
} }
wrapForHistory(webPageID: number) {
var webPage = copy(this.webpages[webPageID]) || {_: 'webPageEmpty'};
if(webPage.photo && webPage.photo.id) {
webPage.photo = appPhotosManager.wrapForHistory(webPage.photo.id, {website: webPage.type != 'photo' && webPage.type != 'video'});
}
/* if (webPage.document && webPage.document.id) { public getWebPage(id: string) {
webPage.document = appDocsManager.wrapForHistory(webPage.document.id) return this.webpages[id];
} */ // warning
return webPage;
} }
} }

2
src/pages/pageIm.ts

@ -42,6 +42,8 @@ let onFirstMount = () => import('../lib/appManagers/appImManager').then(() => {/
toggleEmoticons.classList.toggle('active'); toggleEmoticons.classList.toggle('active');
}; */ }; */
import('../lib/services');
(Array.from(document.getElementsByClassName('rp')) as HTMLElement[]).forEach(el => ripple(el)); (Array.from(document.getElementsByClassName('rp')) as HTMLElement[]).forEach(el => ripple(el));
Array.from(document.getElementsByClassName('btn-menu-toggle')).forEach((el) => { Array.from(document.getElementsByClassName('btn-menu-toggle')).forEach((el) => {

4
src/scss/partials/_chat.scss

@ -476,6 +476,10 @@ $chat-max-width: 696px;
.attachment { .attachment {
max-width: 200px; max-width: 200px;
max-height: 200px; max-height: 200px;
img {
border-radius: 50%;
}
} }
} }

2
src/scss/partials/_emojiDropdown.scss

@ -15,7 +15,7 @@
overflow: hidden; overflow: hidden;
transition: all 0.2s ease-out; transition: all 0.2s ease-out;
//transform: scale(0); transform: scale(0);
transform-origin: 0 100%; transform-origin: 0 100%;
&.active { &.active {

1
tsconfig.json

@ -66,6 +66,7 @@
"public", "public",
"coverage", "coverage",
"./src/lib/ckin.js", "./src/lib/ckin.js",
"./src/lib/config.js",
"./src/lib/StackBlur.js", "./src/lib/StackBlur.js",
"./src/lib/*.js", "./src/lib/*.js",
"./src/*.js", "./src/*.js",

Loading…
Cancel
Save