Browse Source

Refactored message ids again

master
Eduard Kuzmenko 4 years ago
parent
commit
3047285307
  1. 40
      src/components/appMediaPlaybackController.ts
  2. 31
      src/components/audio.ts
  3. 51
      src/components/chat/bubbleGroups.ts
  4. 85
      src/components/chat/bubbles.ts
  5. 25
      src/components/popups/newMedia.ts
  6. 6
      src/components/sidebarRight/tabs/sharedMedia.ts
  7. 39
      src/components/wrappers.ts
  8. 6
      src/lib/appManagers/appImManager.ts
  9. 226
      src/lib/appManagers/appMessagesManager.ts
  10. 2
      src/lib/appManagers/appPollsManager.ts
  11. 3
      src/lib/mtproto/apiFileManager.ts
  12. 2
      src/lib/richtextprocessor.ts

40
src/components/appMediaPlaybackController.ts

@ -17,13 +17,22 @@ type MediaType = 'voice' | 'audio' | 'round';
class AppMediaPlaybackController { class AppMediaPlaybackController {
private container: HTMLElement; private container: HTMLElement;
private media: {[mid: string]: HTMLMediaElement} = {}; private media: {
[peerId: string]: {
[mid: string]: HTMLMediaElement
}
} = {};
private playingMedia: HTMLMediaElement; private playingMedia: HTMLMediaElement;
private waitingMediaForLoad: {[mid: string]: CancellablePromise<void>} = {}; private waitingMediaForLoad: {
[peerId: string]: {
[mid: string]: CancellablePromise<void>
}
} = {};
public willBePlayedMedia: HTMLMediaElement; public willBePlayedMedia: HTMLMediaElement;
private currentPeerId: number;
private prevMid: number; private prevMid: number;
private nextMid: number; private nextMid: number;
@ -35,7 +44,8 @@ class AppMediaPlaybackController {
} }
public addMedia(peerId: number, doc: MyDocument, mid: number, autoload = true): HTMLMediaElement { public addMedia(peerId: number, doc: MyDocument, mid: number, autoload = true): HTMLMediaElement {
if(this.media[mid]) return this.media[mid]; const storage = this.media[peerId] ?? (this.media[peerId] = {});
if(storage[mid]) return storage[mid];
const media = document.createElement(doc.type == 'round' ? 'video' : 'audio'); const media = document.createElement(doc.type == 'round' ? 'video' : 'audio');
//const source = document.createElement('source'); //const source = document.createElement('source');
@ -55,6 +65,8 @@ class AppMediaPlaybackController {
this.container.append(media); this.container.append(media);
media.addEventListener('playing', () => { media.addEventListener('playing', () => {
this.currentPeerId = peerId;
if(this.playingMedia != media) { if(this.playingMedia != media) {
if(this.playingMedia && !this.playingMedia.paused) { if(this.playingMedia && !this.playingMedia.paused) {
this.playingMedia.pause(); this.playingMedia.pause();
@ -76,8 +88,8 @@ class AppMediaPlaybackController {
const onError = (e: Event) => { const onError = (e: Event) => {
if(this.nextMid == mid) { if(this.nextMid == mid) {
this.loadSiblingsMedia(peerId, doc.type as MediaType, mid).then(() => { this.loadSiblingsMedia(peerId, doc.type as MediaType, mid).then(() => {
if(this.nextMid && this.media[this.nextMid]) { if(this.nextMid && storage[this.nextMid]) {
this.media[this.nextMid].play(); storage[this.nextMid].play();
} }
}); });
} }
@ -89,7 +101,8 @@ class AppMediaPlaybackController {
if(autoload) { if(autoload) {
deferred.resolve(); deferred.resolve();
} else { } else {
this.waitingMediaForLoad[mid] = deferred; const waitingStorage = this.waitingMediaForLoad[peerId] ?? (this.waitingMediaForLoad[peerId] = {});
waitingStorage[mid] = deferred;
} }
// если что - загрузит voice или round заранее, так правильнее // если что - загрузит voice или round заранее, так правильнее
@ -105,7 +118,7 @@ class AppMediaPlaybackController {
media.src = doc.url; media.src = doc.url;
}, onError); }, onError);
return this.media[mid] = media; return storage[mid] = media;
} }
// safari подгрузит последний чанк и песня включится, // safari подгрузит последний чанк и песня включится,
@ -136,11 +149,12 @@ class AppMediaPlaybackController {
}/* , {once: true} */); }/* , {once: true} */);
} }
public resolveWaitingForLoadMedia(mid: number) { public resolveWaitingForLoadMedia(peerId: number, mid: number) {
const promise = this.waitingMediaForLoad[mid]; const storage = this.waitingMediaForLoad[peerId] ?? (this.waitingMediaForLoad[peerId] = {});
const promise = storage[mid];
if(promise) { if(promise) {
promise.resolve(); promise.resolve();
delete this.waitingMediaForLoad[mid]; delete storage[mid];
} }
} }
@ -167,13 +181,13 @@ class AppMediaPlaybackController {
//console.log('on media end'); //console.log('on media end');
if(this.nextMid) { if(this.nextMid) {
const media = this.media[this.nextMid]; const media = this.media[this.currentPeerId][this.nextMid];
/* if(isSafari) { /* if(isSafari) {
media.autoplay = true; media.autoplay = true;
} */ } */
this.resolveWaitingForLoadMedia(this.nextMid); this.resolveWaitingForLoadMedia(this.currentPeerId, this.nextMid);
setTimeout(() => { setTimeout(() => {
media.play()//.catch(() => {}); media.play()//.catch(() => {});
@ -189,7 +203,7 @@ class AppMediaPlaybackController {
//_: type == 'audio' ? 'inputMessagesFilterMusic' : (type == 'round' ? 'inputMessagesFilterRoundVideo' : 'inputMessagesFilterVoice') //_: type == 'audio' ? 'inputMessagesFilterMusic' : (type == 'round' ? 'inputMessagesFilterRoundVideo' : 'inputMessagesFilterVoice')
_: type == 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice' _: type == 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice'
}, mid, 3, 0, 2).then(value => { }, mid, 3, 0, 2).then(value => {
if(this.playingMedia != media) { if(this.playingMedia !== media) {
return; return;
} }

31
src/components/audio.ts

@ -61,10 +61,11 @@ export function decodeWaveform(waveform: Uint8Array | number[]) {
return result; return result;
} }
function wrapVoiceMessage(peerId: number, doc: MyDocument, audioEl: AudioElement, mid: number) { function wrapVoiceMessage(audioEl: AudioElement) {
audioEl.classList.add('is-voice'); audioEl.classList.add('is-voice');
const message = appMessagesManager.getMessageByPeer(peerId, mid); const message = audioEl.message;
const doc = message.media.document as MyDocument;
const isOut = message.fromId == rootScope.myId && message.peerId != rootScope.myId; const isOut = message.fromId == rootScope.myId && message.peerId != rootScope.myId;
let isUnread = message && message.pFlags.media_unread; let isUnread = message && message.pFlags.media_unread;
if(isUnread) { if(isUnread) {
@ -171,7 +172,7 @@ function wrapVoiceMessage(peerId: number, doc: MyDocument, audioEl: AudioElement
audioEl.addAudioListener('playing', () => { audioEl.addAudioListener('playing', () => {
if(isUnread && !isOut && audioEl.classList.contains('is-unread')) { if(isUnread && !isOut && audioEl.classList.contains('is-unread')) {
audioEl.classList.remove('is-unread'); audioEl.classList.remove('is-unread');
appMessagesManager.readMessages(peerId, [mid]); appMessagesManager.readMessages(audioEl.message.peerId, [audioEl.message.mid]);
isUnread = false; isUnread = false;
} }
@ -249,9 +250,10 @@ function wrapVoiceMessage(peerId: number, doc: MyDocument, audioEl: AudioElement
return onLoad; return onLoad;
} }
function wrapAudio(doc: MyDocument, audioEl: AudioElement) { function wrapAudio(audioEl: AudioElement) {
const withTime = !!+audioEl.getAttribute('with-time'); const withTime = audioEl.withTime;
const doc = audioEl.message.media.document;
const title = doc.audioTitle || doc.file_name; const title = doc.audioTitle || doc.file_name;
let subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : ''; let subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : '';
@ -314,6 +316,8 @@ function wrapAudio(doc: MyDocument, audioEl: AudioElement) {
export default class AudioElement extends HTMLElement { export default class AudioElement extends HTMLElement {
public audio: HTMLAudioElement; public audio: HTMLAudioElement;
public preloader: ProgressivePreloader; public preloader: ProgressivePreloader;
public message: any;
public withTime = false;
private attachedHandlers: {[name: string]: any[]} = {}; private attachedHandlers: {[name: string]: any[]} = {};
private onTypeDisconnect: () => void; private onTypeDisconnect: () => void;
@ -329,11 +333,8 @@ export default class AudioElement extends HTMLElement {
this.classList.add('audio'); this.classList.add('audio');
const peerId = +this.getAttribute('peer-id'); const doc = this.message.media.document;
const mid = +this.getAttribute('message-id'); const uploading = this.message.pFlags.is_outgoing;
const docId = this.getAttribute('doc-id');
const doc = appDocsManager.getDoc(docId);
const uploading = +doc.id < 0;
const durationStr = String(doc.duration | 0).toHHMMSS(true); const durationStr = String(doc.duration | 0).toHHMMSS(true);
@ -352,13 +353,13 @@ export default class AudioElement extends HTMLElement {
this.append(downloadDiv); this.append(downloadDiv);
} }
const onTypeLoad = doc.type == 'voice' ? wrapVoiceMessage(peerId, doc, this, mid) : wrapAudio(doc, this); const onTypeLoad = doc.type == 'voice' ? wrapVoiceMessage(this) : wrapAudio(this);
const audioTimeDiv = this.querySelector('.audio-time') as HTMLDivElement; const audioTimeDiv = this.querySelector('.audio-time') as HTMLDivElement;
audioTimeDiv.innerHTML = durationStr; audioTimeDiv.innerHTML = durationStr;
const onLoad = (autoload = true) => { const onLoad = (autoload = true) => {
const audio = this.audio = appMediaPlaybackController.addMedia(peerId, doc, mid, autoload); const audio = this.audio = appMediaPlaybackController.addMedia(this.message.peerId, this.message.media.document, this.message.mid, autoload);
this.onTypeDisconnect = onTypeLoad(); this.onTypeDisconnect = onTypeLoad();
@ -449,7 +450,7 @@ export default class AudioElement extends HTMLElement {
const r = (e: Event) => { const r = (e: Event) => {
//onLoad(); //onLoad();
//cancelEvent(e); //cancelEvent(e);
appMediaPlaybackController.resolveWaitingForLoadMedia(mid); appMediaPlaybackController.resolveWaitingForLoadMedia(this.message.peerId, this.message.mid);
appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio
@ -465,7 +466,7 @@ export default class AudioElement extends HTMLElement {
preloader.attach(downloadDiv); preloader.attach(downloadDiv);
this.append(downloadDiv); this.append(downloadDiv);
new Promise((resolve) => { new Promise<void>((resolve) => {
if(this.audio.readyState >= 2) resolve(); if(this.audio.readyState >= 2) resolve();
else this.addAudioListener('canplay', resolve); else this.addAudioListener('canplay', resolve);
}).then(() => { }).then(() => {
@ -473,7 +474,7 @@ export default class AudioElement extends HTMLElement {
//setTimeout(() => { //setTimeout(() => {
// release loaded audio // release loaded audio
if(appMediaPlaybackController.willBePlayedMedia == this.audio) { if(appMediaPlaybackController.willBePlayedMedia === this.audio) {
this.audio.play(); this.audio.play();
appMediaPlaybackController.willBePlayedMedia = null; appMediaPlaybackController.willBePlayedMedia = null;
} }

51
src/components/chat/bubbleGroups.ts

@ -1,6 +1,7 @@
import rootScope from "../../lib/rootScope"; import rootScope from "../../lib/rootScope";
import { generatePathData } from "../../helpers/dom"; import { generatePathData } from "../../helpers/dom";
import { MyMessage } from "../../lib/appManagers/appMessagesManager"; import { MyMessage } from "../../lib/appManagers/appMessagesManager";
import Chat from "./chat";
type Group = {bubble: HTMLDivElement, mid: number, timestamp: number}[]; type Group = {bubble: HTMLDivElement, mid: number, timestamp: number}[];
type BubbleGroup = {timestamp: number, fromId: number, mid: number, group: Group}; type BubbleGroup = {timestamp: number, fromId: number, mid: number, group: Group};
@ -10,6 +11,10 @@ export default class BubbleGroups {
//updateRAFs: Map<HTMLDivElement[], number> = new Map(); //updateRAFs: Map<HTMLDivElement[], number> = new Map();
private newGroupDiff = 121; // * 121 in scheduled messages private newGroupDiff = 121; // * 121 in scheduled messages
constructor(private chat: Chat) {
}
removeBubble(bubble: HTMLDivElement, mid: number) { removeBubble(bubble: HTMLDivElement, mid: number) {
const details = this.bubbles.findAndSplice(g => g.mid === mid); const details = this.bubbles.findAndSplice(g => g.mid === mid);
if(details && details.group.length) { if(details && details.group.length) {
@ -38,10 +43,37 @@ export default class BubbleGroups {
const insertObject = {bubble, mid, timestamp}; const insertObject = {bubble, mid, timestamp};
if(this.bubbles.length) { if(this.bubbles.length) {
const foundBubble = this.bubbles.find(bubble => { let foundBubble: BubbleGroup;
let foundAtIndex = -1;
for(let i = 0; i < this.bubbles.length; ++i) {
const bubble = this.bubbles[i];
const diff = Math.abs(bubble.timestamp - timestamp);
const good = bubble.fromId === fromId && diff <= this.newGroupDiff;
if(good) {
foundAtIndex = i;
if(this.chat.type === 'scheduled') {
break;
}
} else {
foundAtIndex = -1;
}
if(this.chat.type !== 'scheduled') {
if(mid > bubble.mid) {
break;
}
}
}
if(foundAtIndex !== -1) {
foundBubble = this.bubbles[foundAtIndex];
}
/* const foundBubble = this.bubbles.find(bubble => {
const diff = Math.abs(bubble.timestamp - timestamp); const diff = Math.abs(bubble.timestamp - timestamp);
return bubble.fromId === fromId && diff <= this.newGroupDiff; return bubble.fromId === fromId && diff <= this.newGroupDiff;
}); }); */
if(!foundBubble) this.groups.push(group = [insertObject]); if(!foundBubble) this.groups.push(group = [insertObject]);
else { else {
@ -70,8 +102,21 @@ export default class BubbleGroups {
} }
//console.log('[BUBBLE]: addBubble', bubble, message.mid, fromId, reverse, group); //console.log('[BUBBLE]: addBubble', bubble, message.mid, fromId, reverse, group);
if(mid > 0) {
let insertIndex = 0;
for(; insertIndex < this.bubbles.length; ++insertIndex) {
if(this.bubbles[insertIndex].mid < mid) {
break;
}
}
this.bubbles.splice(insertIndex, 0, {timestamp, fromId, mid: message.mid, group});
} else {
this.bubbles.unshift({timestamp, fromId, mid: message.mid, group});
}
this.bubbles.push({timestamp, fromId, mid: message.mid, group}); //this.bubbles.push({timestamp, fromId, mid: message.mid, group});
this.updateGroup(group); this.updateGroup(group);
} }

85
src/components/chat/bubbles.ts

@ -36,6 +36,7 @@ import { AppChatsManager } from "../../lib/appManagers/appChatsManager";
import Chat from "./chat"; import Chat from "./chat";
import ListenerSetter from "../../helpers/listenerSetter"; import ListenerSetter from "../../helpers/listenerSetter";
import PollElement from "../poll"; import PollElement from "../poll";
import AudioElement from "../audio";
const IGNORE_ACTIONS = ['messageActionHistoryClear']; const IGNORE_ACTIONS = ['messageActionHistoryClear'];
@ -120,7 +121,7 @@ export default class ChatBubbles {
// * constructor end // * constructor end
this.log = this.chat.log; this.log = this.chat.log;
this.bubbleGroups = new BubbleGroups(); this.bubbleGroups = new BubbleGroups(this.chat);
this.preloader = new ProgressivePreloader(null, false); this.preloader = new ProgressivePreloader(null, false);
this.lazyLoadQueue = new LazyLoadQueue(); this.lazyLoadQueue = new LazyLoadQueue();
this.lazyLoadQueue.queueId = ++queueId; this.lazyLoadQueue.queueId = ++queueId;
@ -165,7 +166,7 @@ export default class ChatBubbles {
this.log('message_sent', e.detail); this.log('message_sent', e.detail);
const mounted = this.getMountedBubble(tempId) || this.getMountedBubble(mid); const mounted = this.getMountedBubble(tempId, tempMessage) || this.getMountedBubble(mid);
if(mounted) { if(mounted) {
const message = this.chat.getMessage(mid); const message = this.chat.getMessage(mid);
const bubble = mounted.bubble; const bubble = mounted.bubble;
@ -175,7 +176,7 @@ export default class ChatBubbles {
// set new mids to album items for mediaViewer // set new mids to album items for mediaViewer
if(message.grouped_id) { if(message.grouped_id) {
const item = bubble.querySelector(`.grouped-item[data-mid="${tempId}"]`) as HTMLElement; const item = (bubble.querySelector(`.grouped-item[data-mid="${tempId}"]`) as HTMLElement) || bubble; // * it can be .document-container
item.dataset.mid = '' + mid; item.dataset.mid = '' + mid;
} }
@ -190,9 +191,10 @@ export default class ChatBubbles {
} }
if(['audio', 'voice'].includes(message.media?.document?.type)) { if(['audio', 'voice'].includes(message.media?.document?.type)) {
const audio = bubble.querySelector(`audio-element[message-id="${tempId}"]`); const audio = bubble.querySelector(`audio-element[message-id="${tempId}"]`) as AudioElement;
audio.setAttribute('doc-id', message.media.document.id); audio.setAttribute('doc-id', message.media.document.id);
audio.setAttribute('message-id', '' + mid); audio.setAttribute('message-id', '' + mid);
audio.message = message;
} }
/* bubble.classList.remove('is-sending'); /* bubble.classList.remove('is-sending');
@ -219,7 +221,7 @@ export default class ChatBubbles {
delete this.bubbles[tempId]; delete this.bubbles[tempId];
bubble.classList.remove('is-sending'); bubble.classList.remove('is-sending');
bubble.classList.add('is-sent'); bubble.classList.add(this.peerId === rootScope.myId && this.chat.type !== 'scheduled' ? 'is-read' : 'is-sent');
bubble.dataset.mid = '' + mid; bubble.dataset.mid = '' + mid;
this.bubbleGroups.removeBubble(bubble, tempId); this.bubbleGroups.removeBubble(bubble, tempId);
@ -695,9 +697,7 @@ export default class ChatBubbles {
return Array.from(bubble.querySelectorAll('.grouped-item')) as HTMLElement[]; return Array.from(bubble.querySelectorAll('.grouped-item')) as HTMLElement[];
} }
public getMountedBubble(mid: number) { public getMountedBubble(mid: number, message = this.chat.getMessage(mid)) {
const message = this.chat.getMessage(mid);
if(message.grouped_id && this.appMessagesManager.getMidsByAlbum(message.grouped_id).length > 1) { if(message.grouped_id && this.appMessagesManager.getMidsByAlbum(message.grouped_id).length > 1) {
const a = this.getGroupedBubble(message.grouped_id); const a = this.getGroupedBubble(message.grouped_id);
if(a) { if(a) {
@ -1350,40 +1350,40 @@ export default class ChatBubbles {
public setBubblePosition(bubble: HTMLElement, message: any, reverse: boolean) { public setBubblePosition(bubble: HTMLElement, message: any, reverse: boolean) {
const dateMessage = this.getDateContainerByMessage(message, reverse); const dateMessage = this.getDateContainerByMessage(message, reverse);
let children = Array.from(dateMessage.container.children).slice(1) as HTMLElement[]; if(this.chat.type === 'scheduled' || this.chat.type === 'pinned') {
let i = 0, foundMidOnSameTimestamp = 0; let children = Array.from(dateMessage.container.children).slice(2) as HTMLElement[];
for(; i < children.length; ++i) { let i = 0, foundMidOnSameTimestamp = 0;
const t = children[i]; for(; i < children.length; ++i) {
const timestamp = +t.dataset.timestamp; const t = children[i];
if(message.date < timestamp) { const timestamp = +t.dataset.timestamp;
break; if(message.date < timestamp) {
} else if(message.date === timestamp) { break;
foundMidOnSameTimestamp = +t.dataset.mid; } else if(message.date === timestamp) {
foundMidOnSameTimestamp = +t.dataset.mid;
}
if(foundMidOnSameTimestamp && message.mid < foundMidOnSameTimestamp) {
break;
}
} }
if(foundMidOnSameTimestamp && message.mid < foundMidOnSameTimestamp) { // * 1 for date, 1 for date sentinel
break; let index = 2 + i;
if(bubble.parentElement) { // * if already mounted
const currentIndex = whichChild(bubble);
if(index > currentIndex) {
index -= 1; // * minus for already mounted
}
} }
}
positionElementByIndex(bubble, dateMessage.container, index);
// * 1 for date } else {
let index = 1 + i; if(reverse) {
if(bubble.parentElement) { // * if already mounted dateMessage.container.insertBefore(bubble, dateMessage.container.children[1].nextSibling);
const currentIndex = whichChild(bubble); } else {
if(index > currentIndex) { dateMessage.container.append(bubble);
index -= 1; // * minus for already mounted
} }
} }
positionElementByIndex(bubble, dateMessage.container, index);
//this.bubbleGroups.updateGroupByMessageId(message.mid);
/* if(reverse) {
dateMessage.container.insertBefore(bubble, dateMessage.div.nextSibling);
} else {
dateMessage.container.append(bubble);
} */
} }
// * will change .cleaned in cleanup() and new instance will be created // * will change .cleaned in cleanup() and new instance will be created
@ -1637,10 +1637,11 @@ export default class ChatBubbles {
bubbleContainer.prepend(containerDiv); bubbleContainer.prepend(containerDiv);
} }
const isOutgoing = message.pFlags.is_outgoing/* && this.peerId != rootScope.myId */;
if(our) { if(our) {
if(message.pFlags.unread || message.mid < 0) this.unreadOut.add(message.mid); // message.mid < 0 added 11.02.2020 if(message.pFlags.unread || isOutgoing) this.unreadOut.add(message.mid);
let status = ''; let status = '';
if(message.mid < 0) status = 'is-sending'; if(isOutgoing) status = 'is-sending';
else status = message.pFlags.unread ? 'is-sent' : 'is-read'; else status = message.pFlags.unread ? 'is-sent' : 'is-read';
bubble.classList.add(status); bubble.classList.add(status);
} }
@ -1839,7 +1840,9 @@ export default class ChatBubbles {
}); });
//} //}
} else { } else {
const docDiv = wrapDocument(this.peerId, doc, false, false, message.mid); const docDiv = wrapDocument({
message
});
preview.append(docDiv); preview.append(docDiv);
preview.classList.add('preview-with-document'); preview.classList.add('preview-with-document');
//messageDiv.classList.add((webpage.type || 'document') + '-message'); //messageDiv.classList.add((webpage.type || 'document') + '-message');

25
src/components/popups/newMedia.ts

@ -256,13 +256,24 @@ export default class PopupNewMedia extends PopupElement {
params.objectURL = URL.createObjectURL(file); params.objectURL = URL.createObjectURL(file);
} }
const docDiv = wrapDocument(0, { const docDiv = wrapDocument({
file: file, message: {
file_name: file.name || '', _: 'message',
size: file.size, mid: 0,
type: isPhoto ? 'photo' : 'doc', peerId: 0,
url: params.objectURL media: {
} as any, false, true); _: 'messageMediaDocument',
document: {
_: 'document',
file: file,
file_name: file.name || '',
size: file.size,
type: isPhoto ? 'photo' : 'doc',
url: params.objectURL
}
}
} as any
});
const finish = () => { const finish = () => {
itemDiv.append(docDiv); itemDiv.append(docDiv);

6
src/components/sidebarRight/tabs/sharedMedia.ts

@ -528,7 +528,11 @@ export default class AppSharedMediaTab implements SliderTab {
case 'inputMessagesFilterMusic': case 'inputMessagesFilterMusic':
case 'inputMessagesFilterDocument': { case 'inputMessagesFilterDocument': {
for(const message of messages) { for(const message of messages) {
const div = wrapDocument(this.peerId, message.media.document, true, false, message.mid, 400); const div = wrapDocument({
message,
withTime: true,
fontWeight: 400
});
div.dataset.mid = '' + message.mid; div.dataset.mid = '' + message.mid;
elemsToAppend.push(div); elemsToAppend.push(div);
} }

39
src/components/wrappers.ts

@ -343,9 +343,21 @@ export const formatDate = (timestamp: number, monthShort = false, withYear = tru
return str + ' at ' + date.getHours() + ':' + ('0' + date.getMinutes()).slice(-2); return str + ' at ' + date.getHours() + ':' + ('0' + date.getMinutes()).slice(-2);
}; };
export function wrapDocument(peerId: number, doc: MyDocument, withTime = false, uploading = false, mid?: number, fontWeight = 500): HTMLElement { export function wrapDocument({message, withTime, uploading, fontWeight}: {
message: any,
withTime?: boolean,
uploading?: boolean,
fontWeight?: number
}): HTMLElement {
if(!fontWeight) fontWeight = 500;
const doc = message.media.document;
if(doc.type == 'audio' || doc.type == 'voice') { if(doc.type == 'audio' || doc.type == 'voice') {
const audioElement = wrapAudio(peerId, doc, withTime, mid); const audioElement = new AudioElement();
audioElement.setAttribute('message-id', '' + message.mid);
audioElement.setAttribute('peer-id', '' + message.peerId);
audioElement.withTime = withTime;
audioElement.message = message;
audioElement.dataset.fontWeight = '' + fontWeight; audioElement.dataset.fontWeight = '' + fontWeight;
return audioElement; return audioElement;
} }
@ -438,15 +450,6 @@ export function wrapDocument(peerId: number, doc: MyDocument, withTime = false,
return docDiv; return docDiv;
} }
export function wrapAudio(peerId: number, doc: MyDocument, withTime = false, mid?: number): HTMLElement {
let elem = new AudioElement();
elem.setAttribute('peer-id', '' + peerId);
elem.setAttribute('doc-id', doc.id);
elem.setAttribute('with-time', '' + +withTime);
elem.setAttribute('message-id', '' + mid);
return elem;
}
function wrapMediaWithTail(photo: MyPhoto | MyDocument, message: {mid: number, message: string}, container: HTMLElement, boxWidth: number, boxHeight: number, isOut: boolean) { function wrapMediaWithTail(photo: MyPhoto | MyDocument, message: {mid: number, message: string}, container: HTMLElement, boxWidth: number, boxHeight: number, isOut: boolean) {
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.classList.add('bubble__media-container', isOut ? 'is-out' : 'is-in'); svg.classList.add('bubble__media-container', isOut ? 'is-out' : 'is-in');
@ -921,10 +924,10 @@ export function wrapAlbum({groupId, attachmentDiv, middleware, uploading, lazyLo
items.push({size, media, message: m}); items.push({size, media, message: m});
} }
// * pending /* // * pending
if(storage[0] < 0) { if(storage[0] < 0) {
items.reverse(); items.reverse();
} } */
prepareAlbum({ prepareAlbum({
container: attachmentDiv, container: attachmentDiv,
@ -979,15 +982,17 @@ export function wrapGroupedDocuments({albumMustBeRenderedFull, message, bubble,
}) { }) {
let nameContainer: HTMLDivElement; let nameContainer: HTMLDivElement;
const mids = albumMustBeRenderedFull ? chat.getMidsByMid(message.mid) : [message.mid]; const mids = albumMustBeRenderedFull ? chat.getMidsByMid(message.mid) : [message.mid];
const isPending = message.mid < 0; const isPending = message.pFlags.is_outgoing;
if(isPending) { /* if(isPending) {
mids.reverse(); mids.reverse();
} } */
mids.forEach((mid, idx) => { mids.forEach((mid, idx) => {
const message = chat.getMessage(mid); const message = chat.getMessage(mid);
const doc = message.media.document; const doc = message.media.document;
const div = wrapDocument(chat.peerId, doc, false, isPending, mid); const div = wrapDocument({
message
});
const container = document.createElement('div'); const container = document.createElement('div');
container.classList.add('document-container'); container.classList.add('document-container');

6
src/lib/appManagers/appImManager.ts

@ -137,6 +137,10 @@ export class AppImManager {
const hash = location.hash; const hash = location.hash;
const splitted = hash.split('?'); const splitted = hash.split('?');
if(!splitted[1]) {
return;
}
const params: any = {}; const params: any = {};
splitted[1].split('&').forEach(item => { splitted[1].split('&').forEach(item => {
params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]); params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]);
@ -148,7 +152,7 @@ export class AppImManager {
case '#/im': { case '#/im': {
const p = params.p; const p = params.p;
if(p[0] === '@') { if(p[0] === '@') {
let postId = params.post !== undefined ? +params.post : undefined; let postId = params.post !== undefined ? appMessagesManager.generateMessageId(+params.post) : undefined;
appUsersManager.resolveUsername(p).then(peer => { appUsersManager.resolveUsername(p).then(peer => {
const isUser = peer._ == 'user'; const isUser = peer._ == 'user';
const peerId = isUser ? peer.id : -peer.id; const peerId = isUser ? peer.id : -peer.id;

226
src/lib/appManagers/appMessagesManager.ts

@ -78,7 +78,10 @@ export type PinnedStorage = Partial<{
count: number, count: number,
maxId: number maxId: number
}>; }>;
export type MessagesStorage = {[mid: string]: any}; export type MessagesStorage = {
//generateIndex: (message: any) => void
[mid: string]: any
};
export class AppMessagesManager { export class AppMessagesManager {
public messagesStorageByPeerId: {[peerId: string]: MessagesStorage} = {}; public messagesStorageByPeerId: {[peerId: string]: MessagesStorage} = {};
public groupedMessagesStorage: {[groupId: string]: MessagesStorage} = {}; // will be used for albums public groupedMessagesStorage: {[groupId: string]: MessagesStorage} = {}; // will be used for albums
@ -107,7 +110,7 @@ export class AppMessagesManager {
public pendingAfterMsgs: any = {}; public pendingAfterMsgs: any = {};
public pendingTopMsgs: {[peerId: string]: number} = {}; public pendingTopMsgs: {[peerId: string]: number} = {};
public sendFilePromise: CancellablePromise<void> = Promise.resolve(); public sendFilePromise: CancellablePromise<void> = Promise.resolve();
public tempId = -1; public tempNum = 0;
public tempFinalizeCallbacks: { public tempFinalizeCallbacks: {
[tempId: string]: { [tempId: string]: {
[callbackName: string]: Partial<{ [callbackName: string]: Partial<{
@ -231,7 +234,7 @@ export class AppMessagesManager {
let removeUnread = 0; let removeUnread = 0;
for(const mid of history) { for(const mid of history) {
const message = this.getMessageByPeer(dialog.peerId, mid); const message = this.getMessageByPeer(dialog.peerId, mid);
if(/* message._ != 'messageEmpty' && */message.id > 0) { if(/* message._ != 'messageEmpty' && */!message.pFlags.is_outgoing) {
messages.push(message); messages.push(message);
if(message.fromId != dialog.peerId) { if(message.fromId != dialog.peerId) {
@ -239,6 +242,7 @@ export class AppMessagesManager {
} }
dialog.top_message = message.mid; dialog.top_message = message.mid;
this.setDialogIndexByMessage(dialog, message);
break; break;
} else if(message.pFlags && message.pFlags.unread) { } else if(message.pFlags && message.pFlags.unread) {
@ -341,7 +345,7 @@ export class AppMessagesManager {
const {mid, peerId} = message; const {mid, peerId} = message;
if(mid < 0) { if(message.pFlags.is_outgoing) {
return this.invokeAfterMessageIsSent(mid, 'edit', (message) => { return this.invokeAfterMessageIsSent(mid, 'edit', (message) => {
this.log('invoke editMessage callback', message); this.log('invoke editMessage callback', message);
return this.editMessage(message, text, options); return this.editMessage(message, text, options);
@ -357,7 +361,7 @@ export class AppMessagesManager {
const schedule_date = options.scheduleDate || (message.pFlags.is_scheduled ? message.date : undefined); const schedule_date = options.scheduleDate || (message.pFlags.is_scheduled ? message.date : undefined);
return apiManager.invokeApi('messages.editMessage', { return apiManager.invokeApi('messages.editMessage', {
peer: appPeersManager.getInputPeerById(peerId), peer: appPeersManager.getInputPeerById(peerId),
id: mid, id: message.id,
message: text, message: text,
media: options.newMedia, media: options.newMedia,
entities: entities ? this.getInputEntities(entities) : undefined, entities: entities ? this.getInputEntities(entities) : undefined,
@ -426,10 +430,10 @@ export class AppMessagesManager {
sendEntites = undefined; sendEntites = undefined;
} }
var messageId = this.tempId--; var messageId = this.generateTempMessageId(peerId);
var randomIdS = randomLong(); var randomIdS = randomLong();
var pFlags: any = {}; var pFlags: any = {};
var replyToMsgId = options.replyToMsgId; var replyToMsgId = options.replyToMsgId ? this.getLocalMessageId(options.replyToMsgId) : undefined;
var isChannel = appPeersManager.isChannel(peerId); var isChannel = appPeersManager.isChannel(peerId);
var isMegagroup = isChannel && appPeersManager.isMegagroup(peerId); var isMegagroup = isChannel && appPeersManager.isMegagroup(peerId);
var asChannel = isChannel && !isMegagroup ? true : false; var asChannel = isChannel && !isMegagroup ? true : false;
@ -589,10 +593,10 @@ export class AppMessagesManager {
}> = {}) { }> = {}) {
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId; peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
//this.checkSendOptions(options); //this.checkSendOptions(options);
const messageId = this.tempId--; const messageId = this.generateTempMessageId(peerId);
const randomIdS = randomLong(); const randomIdS = randomLong();
const pFlags: any = {}; const pFlags: any = {};
const replyToMsgId = options.replyToMsgId; const replyToMsgId = options.replyToMsgId ? this.getLocalMessageId(options.replyToMsgId) : undefined;
const isChannel = appPeersManager.isChannel(peerId); const isChannel = appPeersManager.isChannel(peerId);
const isMegagroup = isChannel && appPeersManager.isMegagroup(peerId); const isMegagroup = isChannel && appPeersManager.isMegagroup(peerId);
const asChannel = !!(isChannel && !isMegagroup); const asChannel = !!(isChannel && !isMegagroup);
@ -936,7 +940,7 @@ export class AppMessagesManager {
} }
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId; peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
const replyToMsgId = options.replyToMsgId; const replyToMsgId = options.replyToMsgId ? this.getLocalMessageId(options.replyToMsgId) : undefined;
let caption = options.caption || ''; let caption = options.caption || '';
let entities: MessageEntity[]; let entities: MessageEntity[];
@ -966,20 +970,24 @@ export class AppMessagesManager {
return this.sendFile(peerId, file, o).message; return this.sendFile(peerId, file, o).message;
}); });
const groupId = messages[0].id; const message = messages[messages.length - 1];
const groupId = message.id;
messages.forEach(message => { messages.forEach(message => {
message.grouped_id = groupId; message.grouped_id = groupId;
}); });
const storage = options.scheduleDate ? this.getScheduledMessagesStorage(peerId) : this.getMessagesStorage(peerId); const storage = options.scheduleDate ? this.getScheduledMessagesStorage(peerId) : this.getMessagesStorage(peerId);
if(options.scheduleDate) { if(options.scheduleDate) {
this.saveMessages(messages, {storage, isScheduled: true}); this.saveMessages(messages, {storage, isScheduled: true, isOutgoing: true});
rootScope.broadcast('scheduled_new', {peerId, mid: groupId}); rootScope.broadcast('scheduled_new', {peerId, mid: groupId});
} else { } else {
this.saveMessages(messages, {storage}); this.saveMessages(messages, {storage, isOutgoing: true});
rootScope.broadcast('history_append', {peerId, messageId: groupId, my: true}); rootScope.broadcast('history_append', {peerId, messageId: groupId, my: true});
this.setDialogTopMessage(message);
} }
// * test pending
//return; //return;
const toggleError = (message: any, on: boolean) => { const toggleError = (message: any, on: boolean) => {
@ -1061,9 +1069,9 @@ export class AppMessagesManager {
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId; peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
//this.checkSendOptions(options); //this.checkSendOptions(options);
const messageId = this.tempId--; const messageId = this.generateTempMessageId(peerId);
const randomIdS = randomLong(); const randomIdS = randomLong();
const replyToMsgId = options.replyToMsgId; const replyToMsgId = options.replyToMsgId ? this.getLocalMessageId(options.replyToMsgId) : undefined;
const isChannel = appPeersManager.isChannel(peerId); const isChannel = appPeersManager.isChannel(peerId);
const isMegagroup = isChannel && appPeersManager.isMegagroup(peerId); const isMegagroup = isChannel && appPeersManager.isMegagroup(peerId);
const asChannel = isChannel && !isMegagroup ? true : false; const asChannel = isChannel && !isMegagroup ? true : false;
@ -1266,16 +1274,19 @@ export class AppMessagesManager {
if(options.isScheduled) { if(options.isScheduled) {
if(!options.isGroupedItem) { if(!options.isGroupedItem) {
this.saveMessages([message], {storage, isScheduled: true}); this.saveMessages([message], {storage, isScheduled: true, isOutgoing: true});
rootScope.broadcast('scheduled_new', {peerId, mid: messageId}); rootScope.broadcast('scheduled_new', {peerId, mid: messageId});
} }
} else { } else {
const historyStorage = this.getHistoryStorage(peerId); const historyStorage = this.getHistoryStorage(peerId);
historyStorage.pending.unshift(messageId); //historyStorage.pending.unshift(messageId);
historyStorage.history.unshift(messageId);
if(!options.isGroupedItem) { if(!options.isGroupedItem) {
this.saveMessages([message], {storage}); this.saveMessages([message], {storage, isOutgoing: true});
rootScope.broadcast('history_append', {peerId, messageId, my: true}); rootScope.broadcast('history_append', {peerId, messageId, my: true});
this.setDialogTopMessage(message);
} }
} }
@ -1284,6 +1295,25 @@ export class AppMessagesManager {
if(!options.isGroupedItem) { if(!options.isGroupedItem) {
setTimeout(message.send, 0); setTimeout(message.send, 0);
//setTimeout(message.send, 4000); //setTimeout(message.send, 4000);
//setTimeout(message.send, 7000);
}
}
private setDialogIndexByMessage(dialog: MTDialog.dialog, message: MyMessage) {
if(!dialog.pFlags.pinned || !dialog.index) {
dialog.index = this.dialogsStorage.generateDialogIndex(message.date);
}
}
public setDialogTopMessage(message: MyMessage) {
const dialog = this.getDialogByPeerId(message.peerId)[0];
if(dialog) {
dialog.top_message = message.mid;
this.setDialogIndexByMessage(dialog, message);
this.newDialogsToHandle[message.peerId] = dialog;
this.scheduleHandleNewDialogs();
} }
} }
@ -1526,7 +1556,7 @@ export class AppMessagesManager {
scheduleDate: number scheduleDate: number
}> = {}) { }> = {}) {
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId; peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
msgIds = msgIds.slice().sort((a, b) => a - b); msgIds = msgIds.slice().sort((a, b) => a - b).map(mid => this.getLocalMessageId(mid));
const randomIds: string[] = msgIds.map(() => randomLong()); const randomIds: string[] = msgIds.map(() => randomLong());
@ -1564,8 +1594,30 @@ export class AppMessagesManager {
}; };
} }
private createMessageStorage() {
const storage: MessagesStorage = {} as any;
/* let num = 0;
Object.defineProperty(storage, 'num', {
get: () => ++num,
set: (_num: number) => num = _num,
enumerable: false
});
Object.defineProperty(storage, 'generateIndex', {
value: (message: any) => {
if(message.index === undefined) {
message.index = (message.date * 0x10000) + (storage.num & 0xFFFF);
}
},
enumerable: false
}); */
return storage;
}
public getMessagesStorage(peerId: number) { public getMessagesStorage(peerId: number) {
return this.messagesStorageByPeerId[peerId] ?? (this.messagesStorageByPeerId[peerId] = {}); return this.messagesStorageByPeerId[peerId] ?? (this.messagesStorageByPeerId[peerId] = this.createMessageStorage());
} }
public getMessageById(messageId: number) { public getMessageById(messageId: number) {
@ -1712,13 +1764,13 @@ export class AppMessagesManager {
}); });
} }
public updatePinnedMessage(peerId: number, mid: number, unpin?: true, silent?: true, oneSide?: true) { public updatePinnedMessage(peerId: number, id: number, unpin?: true, silent?: true, oneSide?: true) {
return apiManager.invokeApi('messages.updatePinnedMessage', { return apiManager.invokeApi('messages.updatePinnedMessage', {
peer: appPeersManager.getInputPeerById(peerId), peer: appPeersManager.getInputPeerById(peerId),
unpin, unpin,
silent, silent,
pm_oneside: oneSide, pm_oneside: oneSide,
id: mid id
}).then(updates => { }).then(updates => {
this.log('pinned updates:', updates); this.log('pinned updates:', updates);
apiUpdatesManager.processUpdateMessage(updates); apiUpdatesManager.processUpdateMessage(updates);
@ -1789,9 +1841,47 @@ export class AppMessagesManager {
else return [message.mid]; else return [message.mid];
} }
public generateTempMessageId(peerId: number) {
const dialog = this.getDialogByPeerId(peerId)[0];
return this.generateMessageId(dialog?.top_message || 0, true);
}
public generateMessageId(messageId: number, temp = false) {
const q = 0xFFFFFFFF;
const num = temp ? ++this.tempNum : 0;
if(messageId > q) {
if(temp) {
return messageId + (num & 0xFFFF);
}
return messageId;
}
return q + (messageId * 0x10000 + (num & 0xFFFF));
}
/**
* * will ignore outgoing offset
*/
public getLocalMessageId(messageId: number) {
const q = 0xFFFFFFFF;
if(messageId < q) {
return messageId;
}
const l = 0xFFFF;
const used = messageId & l;
if(used !== l) {
messageId -= used + 1;
}
return (messageId - q) / 0x10000;
}
public saveMessages(messages: any[], options: Partial<{ public saveMessages(messages: any[], options: Partial<{
storage: MessagesStorage, storage: MessagesStorage,
isScheduled: true isScheduled: true,
isOutgoing: true
}> = {}) { }> = {}) {
let groups: Map<number, string>; let groups: Map<number, string>;
messages.forEach((message) => { messages.forEach((message) => {
@ -1807,15 +1897,20 @@ export class AppMessagesManager {
// defineNotNumerableProperties(message, ['rReply', 'mid', 'savedFrom', 'fwdFromId', 'fromId', 'peerId', 'reply_to_mid', 'viaBotId']); // defineNotNumerableProperties(message, ['rReply', 'mid', 'savedFrom', 'fwdFromId', 'fromId', 'peerId', 'reply_to_mid', 'viaBotId']);
const peerId = this.getMessagePeer(message); const peerId = this.getMessagePeer(message);
const storage = options.storage || this.getMessagesStorage(peerId);
const isChannel = message.peer_id._ == 'peerChannel'; const isChannel = message.peer_id._ == 'peerChannel';
const channelId = isChannel ? -peerId : 0; const channelId = isChannel ? -peerId : 0;
const isBroadcast = isChannel && appChatsManager.isBroadcast(channelId); const isBroadcast = isChannel && appChatsManager.isBroadcast(channelId);
const mid = message.id;
if(options.isScheduled) { if(options.isScheduled) {
message.pFlags.is_scheduled = true; message.pFlags.is_scheduled = true;
} }
if(options.isOutgoing) {
message.pFlags.is_outgoing = true;
}
const mid = this.generateMessageId(message.id);
message.mid = mid; message.mid = mid;
if(message.grouped_id) { if(message.grouped_id) {
@ -1834,14 +1929,16 @@ export class AppMessagesManager {
// this.log(dT(), 'msg unread', mid, apiMessage.pFlags.out, dialog && dialog[apiMessage.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) // this.log(dT(), 'msg unread', mid, apiMessage.pFlags.out, dialog && dialog[apiMessage.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id'])
if(message.reply_to && message.reply_to.reply_to_msg_id) { if(message.reply_to && message.reply_to.reply_to_msg_id) {
message.reply_to_mid = message.reply_to.reply_to_msg_id; //message.reply_to_mid = message.reply_to.reply_to_msg_id;
message.reply_to_mid = this.generateMessageId(message.reply_to.reply_to_msg_id);
} }
const overwriting = !!message.peerId; const overwriting = !!message.peerId;
if(!overwriting) { if(!overwriting) {
message.date -= serverTimeManager.serverTimeOffset; message.date -= serverTimeManager.serverTimeOffset;
} }
//storage.generateIndex(message);
const myId = appUsersManager.getSelf().id; const myId = appUsersManager.getSelf().id;
message.peerId = peerId; message.peerId = peerId;
@ -1856,7 +1953,8 @@ export class AppMessagesManager {
//if(peerId == myID) { //if(peerId == myID) {
if(fwdHeader.saved_from_peer && fwdHeader.saved_from_msg_id) { if(fwdHeader.saved_from_peer && fwdHeader.saved_from_msg_id) {
const savedFromPeerId = appPeersManager.getPeerId(fwdHeader.saved_from_peer); const savedFromPeerId = appPeersManager.getPeerId(fwdHeader.saved_from_peer);
const savedFromMid = fwdHeader.saved_from_msg_id; //const savedFromMid = fwdHeader.saved_from_msg_id;
const savedFromMid = this.generateMessageId(fwdHeader.saved_from_msg_id);
message.savedFrom = savedFromPeerId + '_' + savedFromMid; message.savedFrom = savedFromPeerId + '_' + savedFromMid;
} }
@ -2019,10 +2117,9 @@ export class AppMessagesManager {
if(message.message && message.message.length && !message.totalEntities) { if(message.message && message.message.length && !message.totalEntities) {
const myEntities = RichTextProcessor.parseEntities(message.message); const myEntities = RichTextProcessor.parseEntities(message.message);
const apiEntities = message.entities || []; const apiEntities = message.entities || [];
message.totalEntities = RichTextProcessor.mergeEntities(apiEntities, myEntities, !message.pending); // ! only in this order, otherwise bold and emoji formatting won't work message.totalEntities = RichTextProcessor.mergeEntities(apiEntities, myEntities); // ! only in this order, otherwise bold and emoji formatting won't work
} }
const storage = options.storage || this.getMessagesStorage(peerId);
storage[mid] = message; storage[mid] = message;
}); });
@ -2417,10 +2514,10 @@ export class AppMessagesManager {
let mid: number, message; let mid: number, message;
if(dialog.top_message) { if(dialog.top_message) {
mid = dialog.top_message; mid = this.generateMessageId(dialog.top_message);//dialog.top_message;
message = this.getMessageByPeer(peerId, mid); message = this.getMessageByPeer(peerId, mid);
} else { } else {
mid = this.tempId--; mid = this.generateTempMessageId(peerId);
message = { message = {
_: 'message', _: 'message',
id: mid, id: mid,
@ -2432,7 +2529,7 @@ export class AppMessagesManager {
date: 0, date: 0,
message: '' message: ''
}; };
this.saveMessages([message]); this.saveMessages([message], {isOutgoing: true});
} }
if(!message?.pFlags) { if(!message?.pFlags) {
@ -2450,6 +2547,8 @@ export class AppMessagesManager {
} }
dialog.top_message = mid; dialog.top_message = mid;
dialog.read_inbox_max_id = this.generateMessageId(dialog.read_inbox_max_id);
dialog.read_outbox_max_id = this.generateMessageId(dialog.read_outbox_max_id);
if(!dialog.hasOwnProperty('folder_id')) { if(!dialog.hasOwnProperty('folder_id')) {
if(dialog._ == 'dialog') { if(dialog._ == 'dialog') {
@ -2536,7 +2635,7 @@ export class AppMessagesManager {
if(lastReplyMarkup) { if(lastReplyMarkup) {
if(lastReplyMarkup.pFlags.single_use && if(lastReplyMarkup.pFlags.single_use &&
!lastReplyMarkup.pFlags.hidden && !lastReplyMarkup.pFlags.hidden &&
(message.mid > lastReplyMarkup.mid || message.mid < 0) && (message.mid > lastReplyMarkup.mid || message.pFlags.is_outgoing) &&
message.message) { message.message) {
lastReplyMarkup.pFlags.hidden = true; lastReplyMarkup.pFlags.hidden = true;
// this.log('set', historyStorage.reply_markup) // this.log('set', historyStorage.reply_markup)
@ -2757,7 +2856,7 @@ export class AppMessagesManager {
min_date: 0, min_date: 0,
max_date: 0, max_date: 0,
limit, limit,
offset_id: maxId || 0, offset_id: this.getLocalMessageId(maxId) || 0,
add_offset: backLimit ? -backLimit : 0, add_offset: backLimit ? -backLimit : 0,
max_id: 0, max_id: 0,
min_id: 0, min_id: 0,
@ -2873,17 +2972,19 @@ export class AppMessagesManager {
} }
} }
public deleteMessages(peerId: number, msgIds: number[], revoke: boolean) { public deleteMessages(peerId: number, mids: number[], revoke: boolean) {
let promise: Promise<any>; let promise: Promise<any>;
mids = mids.map(mid => this.getLocalMessageId(mid));
if(peerId < 0 && appPeersManager.isChannel(-peerId)) { if(peerId < 0 && appPeersManager.isChannel(-peerId)) {
const channelId = -peerId; const channelId = -peerId;
const channel = appChatsManager.getChat(channelId); const channel = appChatsManager.getChat(channelId);
if(!channel.pFlags.creator && !(channel.pFlags.editor && channel.pFlags.megagroup)) { if(!channel.pFlags.creator && !(channel.pFlags.editor && channel.pFlags.megagroup)) {
const goodMsgIds: number[] = []; const goodMsgIds: number[] = [];
if (channel.pFlags.editor || channel.pFlags.megagroup) { if (channel.pFlags.editor || channel.pFlags.megagroup) {
msgIds.forEach((msgId, i) => { mids.forEach((msgId, i) => {
const message = this.getMessageByPeer(peerId, msgIds[i]); const message = this.getMessageByPeer(peerId, mids[i]);
if(message.pFlags.out) { if(message.pFlags.out) {
goodMsgIds.push(msgId); goodMsgIds.push(msgId);
} }
@ -2894,19 +2995,19 @@ export class AppMessagesManager {
return; return;
} }
msgIds = goodMsgIds; mids = goodMsgIds;
} }
promise = apiManager.invokeApi('channels.deleteMessages', { promise = apiManager.invokeApi('channels.deleteMessages', {
channel: appChatsManager.getChannelInput(channelId), channel: appChatsManager.getChannelInput(channelId),
id: msgIds id: mids
}).then((affectedMessages) => { }).then((affectedMessages) => {
apiUpdatesManager.processUpdateMessage({ apiUpdatesManager.processUpdateMessage({
_: 'updateShort', _: 'updateShort',
update: { update: {
_: 'updateDeleteChannelMessages', _: 'updateDeleteChannelMessages',
channel_id: channelId, channel_id: channelId,
messages: msgIds, messages: mids,
pts: affectedMessages.pts, pts: affectedMessages.pts,
pts_count: affectedMessages.pts_count pts_count: affectedMessages.pts_count
} }
@ -2915,13 +3016,13 @@ export class AppMessagesManager {
} else { } else {
promise = apiManager.invokeApi('messages.deleteMessages', { promise = apiManager.invokeApi('messages.deleteMessages', {
revoke: revoke || undefined, revoke: revoke || undefined,
id: msgIds id: mids
}).then((affectedMessages) => { }).then((affectedMessages) => {
apiUpdatesManager.processUpdateMessage({ apiUpdatesManager.processUpdateMessage({
_: 'updateShort', _: 'updateShort',
update: { update: {
_: 'updateDeleteMessages', _: 'updateDeleteMessages',
messages: msgIds, messages: mids,
pts: affectedMessages.pts, pts: affectedMessages.pts,
pts_count: affectedMessages.pts_count pts_count: affectedMessages.pts_count
} }
@ -3064,7 +3165,8 @@ export class AppMessagesManager {
//this.log('AMM updateMessageID:', update, pendingData); //this.log('AMM updateMessageID:', update, pendingData);
if(pendingData) { if(pendingData) {
const {peerId, tempId, storage} = pendingData; const {peerId, tempId, storage} = pendingData;
const mid = update.id; //const mid = update.id;
const mid = this.generateMessageId(update.id);
const message = this.getMessageFromStorage(storage, mid); const message = this.getMessageFromStorage(storage, mid);
if(!message.deleted) { if(!message.deleted) {
const historyStorage = this.getHistoryStorage(peerId); const historyStorage = this.getHistoryStorage(peerId);
@ -3150,16 +3252,10 @@ export class AppMessagesManager {
} }
const inboxUnread = !message.pFlags.out && message.pFlags.unread; const inboxUnread = !message.pFlags.out && message.pFlags.unread;
dialog.top_message = message.mid; this.setDialogTopMessage(message);
if(inboxUnread) { if(inboxUnread) {
dialog.unread_count++; dialog.unread_count++;
} }
if(!dialog.pFlags.pinned || !dialog.index) {
dialog.index = this.dialogsStorage.generateDialogIndex(message.date);
}
this.newDialogsToHandle[peerId] = dialog;
this.scheduleHandleNewDialogs();
break; break;
} }
@ -3331,7 +3427,8 @@ export class AppMessagesManager {
case 'updateEditChannelMessage': { case 'updateEditChannelMessage': {
const message = update.message as MyMessage; const message = update.message as MyMessage;
const peerId = this.getMessagePeer(message); const peerId = this.getMessagePeer(message);
const mid = message.id; //const mid = message.id;
const mid = this.generateMessageId(message.id);
const storage = this.getMessagesStorage(peerId); const storage = this.getMessagesStorage(peerId);
if(storage[mid] === undefined) { if(storage[mid] === undefined) {
break; break;
@ -3388,7 +3485,8 @@ export class AppMessagesManager {
case 'updateReadChannelInbox': case 'updateReadChannelInbox':
case 'updateReadChannelOutbox': { case 'updateReadChannelOutbox': {
const channelId: number = (update as Update.updateReadChannelInbox).channel_id; const channelId: number = (update as Update.updateReadChannelInbox).channel_id;
const maxId = update.max_id; //const maxId = update.max_id;
const maxId = this.generateMessageId(update.max_id);
const peerId = channelId ? -channelId : appPeersManager.getPeerId((update as Update.updateReadHistoryInbox).peer); const peerId = channelId ? -channelId : appPeersManager.getPeerId((update as Update.updateReadHistoryInbox).peer);
const isOut = update._ == 'updateReadHistoryOutbox' || update._ == 'updateReadChannelOutbox' ? true : undefined; const isOut = update._ == 'updateReadHistoryOutbox' || update._ == 'updateReadChannelOutbox' ? true : undefined;
const foundDialog = this.getDialogByPeerId(peerId)[0]; const foundDialog = this.getDialogByPeerId(peerId)[0];
@ -3470,7 +3568,7 @@ export class AppMessagesManager {
} }
} }
rootScope.broadcast('messages_media_read', {peerId, mids: messages}); rootScope.broadcast('messages_media_read', {peerId, mids: messages.map(id => this.generateMessageId(id))});
break; break;
} }
@ -3493,7 +3591,8 @@ export class AppMessagesManager {
case 'updateDeleteMessages': case 'updateDeleteMessages':
case 'updateDeleteChannelMessages': { case 'updateDeleteChannelMessages': {
const channelId: number = (update as Update.updateDeleteChannelMessages).channel_id; const channelId: number = (update as Update.updateDeleteChannelMessages).channel_id;
const messages = (update as any as Update.updateDeleteChannelMessages).messages; //const messages = (update as any as Update.updateDeleteChannelMessages).messages;
const messages = (update as any as Update.updateDeleteChannelMessages).messages.map(id => this.generateMessageId(id));
const peerId = channelId ? -channelId : this.getMessageById(messages[0]).peerId; const peerId = channelId ? -channelId : this.getMessageById(messages[0]).peerId;
if(!peerId) { if(!peerId) {
@ -3588,7 +3687,8 @@ export class AppMessagesManager {
case 'updateChannelMessageViews': { case 'updateChannelMessageViews': {
const views = update.views; const views = update.views;
const mid = update.id; //const mid = update.id;
const mid = this.generateMessageId(update.id);
const message = this.getMessageByPeer(-update.channel_id, mid); const message = this.getMessageByPeer(-update.channel_id, mid);
if(!message.deleted && message.views && message.views < views) { if(!message.deleted && message.views && message.views < views) {
message.views = views; message.views = views;
@ -3601,7 +3701,7 @@ export class AppMessagesManager {
this.log('updateServiceNotification', update); this.log('updateServiceNotification', update);
const fromId = 777000; const fromId = 777000;
const peerId = fromId; const peerId = fromId;
const messageId = this.tempId--; const messageId = this.generateTempMessageId(peerId);
const message: any = { const message: any = {
_: 'message', _: 'message',
id: messageId, id: messageId,
@ -3623,7 +3723,7 @@ export class AppMessagesManager {
phone: '42777' phone: '42777'
}]); }]);
} }
this.saveMessages([message]); this.saveMessages([message], {isOutgoing: true});
if(update.inbox_date) { if(update.inbox_date) {
this.pendingTopMsgs[peerId] = messageId; this.pendingTopMsgs[peerId] = messageId;
@ -3710,7 +3810,7 @@ export class AppMessagesManager {
const storage = this.scheduledMessagesStorage[peerId]; const storage = this.scheduledMessagesStorage[peerId];
if(storage) { if(storage) {
const mid = message.id; const mid = this.generateMessageId(message.id);
const oldMessage = this.getMessageFromStorage(storage, mid); const oldMessage = this.getMessageFromStorage(storage, mid);
this.saveMessages([message], {storage, isScheduled: true}); this.saveMessages([message], {storage, isScheduled: true});
@ -3735,9 +3835,10 @@ export class AppMessagesManager {
const storage = this.scheduledMessagesStorage[peerId]; const storage = this.scheduledMessagesStorage[peerId];
if(storage) { if(storage) {
this.handleDeletedMessages(peerId, storage, update.messages); const mids = update.messages.map(id => this.generateMessageId(id));
this.handleDeletedMessages(peerId, storage, mids);
rootScope.broadcast('scheduled_delete', {peerId, mids: update.messages}); rootScope.broadcast('scheduled_delete', {peerId, mids});
} }
break; break;
@ -3836,6 +3937,7 @@ export class AppMessagesManager {
const message = this.getMessageFromStorage(storage, tempId); const message = this.getMessageFromStorage(storage, tempId);
if(!message.deleted) { if(!message.deleted) {
delete message.pFlags.is_outgoing;
delete message.pending; delete message.pending;
delete message.error; delete message.error;
delete message.random_id; delete message.random_id;
@ -3913,7 +4015,7 @@ export class AppMessagesManager {
} }
public getScheduledMessagesStorage(peerId: number) { public getScheduledMessagesStorage(peerId: number) {
return this.scheduledMessagesStorage[peerId] ?? (this.scheduledMessagesStorage[peerId] = {}); return this.scheduledMessagesStorage[peerId] ?? (this.scheduledMessagesStorage[peerId] = this.createMessageStorage());
} }
public getScheduledMessages(peerId: number): Promise<number[]> { public getScheduledMessages(peerId: number): Promise<number[]> {
@ -4158,7 +4260,7 @@ export class AppMessagesManager {
const promise = apiManager.invokeApi('messages.getHistory', { const promise = apiManager.invokeApi('messages.getHistory', {
peer: appPeersManager.getInputPeerById(peerId), peer: appPeersManager.getInputPeerById(peerId),
offset_id: maxId || 0, offset_id: this.getLocalMessageId(maxId) || 0,
offset_date: offsetDate, offset_date: offsetDate,
add_offset: offset, add_offset: offset,
limit: limit, limit: limit,

2
src/lib/appManagers/appPollsManager.ts

@ -170,7 +170,7 @@ export class AppPollsManager {
const peerId = message.peerId; const peerId = message.peerId;
const inputPeer = appPeersManager.getInputPeerById(peerId); const inputPeer = appPeersManager.getInputPeerById(peerId);
if(messageId < 0) { if(message.pFlags.is_outgoing) {
return appMessagesManager.invokeAfterMessageIsSent(messageId, 'sendVote', (message) => { return appMessagesManager.invokeAfterMessageIsSent(messageId, 'sendVote', (message) => {
this.log('invoke sendVote callback'); this.log('invoke sendVote callback');
return this.sendVote(message, optionIds); return this.sendVote(message, optionIds);

3
src/lib/mtproto/apiFileManager.ts

@ -513,7 +513,8 @@ export class ApiFileManager {
(r.value as Promise<void>).then(process); (r.value as Promise<void>).then(process);
}; };
const maxRequests = Infinity; //const maxRequests = Infinity;
const maxRequests = 10;
/* for(let i = 0; i < 10; ++i) { /* for(let i = 0; i < 10; ++i) {
process(); process();
} */ } */

2
src/lib/richtextprocessor.ts

@ -364,7 +364,7 @@ namespace RichTextProcessor {
return totalEntities; return totalEntities;
} */ } */
export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[], fromApi?: boolean) { export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[]) {
currentEntities = currentEntities.slice(); currentEntities = currentEntities.slice();
const filtered = newEntities.filter(e => !currentEntities.find(_e => e._ == _e._ && e.offset == _e.offset && e.length == _e.length)); const filtered = newEntities.filter(e => !currentEntities.find(_e => e._ == _e._ && e.offset == _e.offset && e.length == _e.length));
currentEntities.push(...filtered); currentEntities.push(...filtered);

Loading…
Cancel
Save