Refactored message ids again
This commit is contained in:
parent
f387ef8a27
commit
3047285307
@ -17,13 +17,22 @@ type MediaType = 'voice' | 'audio' | 'round';
|
||||
|
||||
class AppMediaPlaybackController {
|
||||
private container: HTMLElement;
|
||||
private media: {[mid: string]: HTMLMediaElement} = {};
|
||||
private media: {
|
||||
[peerId: string]: {
|
||||
[mid: string]: HTMLMediaElement
|
||||
}
|
||||
} = {};
|
||||
private playingMedia: HTMLMediaElement;
|
||||
|
||||
private waitingMediaForLoad: {[mid: string]: CancellablePromise<void>} = {};
|
||||
private waitingMediaForLoad: {
|
||||
[peerId: string]: {
|
||||
[mid: string]: CancellablePromise<void>
|
||||
}
|
||||
} = {};
|
||||
|
||||
public willBePlayedMedia: HTMLMediaElement;
|
||||
|
||||
private currentPeerId: number;
|
||||
private prevMid: number;
|
||||
private nextMid: number;
|
||||
|
||||
@ -35,7 +44,8 @@ class AppMediaPlaybackController {
|
||||
}
|
||||
|
||||
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 source = document.createElement('source');
|
||||
@ -55,6 +65,8 @@ class AppMediaPlaybackController {
|
||||
this.container.append(media);
|
||||
|
||||
media.addEventListener('playing', () => {
|
||||
this.currentPeerId = peerId;
|
||||
|
||||
if(this.playingMedia != media) {
|
||||
if(this.playingMedia && !this.playingMedia.paused) {
|
||||
this.playingMedia.pause();
|
||||
@ -76,8 +88,8 @@ class AppMediaPlaybackController {
|
||||
const onError = (e: Event) => {
|
||||
if(this.nextMid == mid) {
|
||||
this.loadSiblingsMedia(peerId, doc.type as MediaType, mid).then(() => {
|
||||
if(this.nextMid && this.media[this.nextMid]) {
|
||||
this.media[this.nextMid].play();
|
||||
if(this.nextMid && storage[this.nextMid]) {
|
||||
storage[this.nextMid].play();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -89,7 +101,8 @@ class AppMediaPlaybackController {
|
||||
if(autoload) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
this.waitingMediaForLoad[mid] = deferred;
|
||||
const waitingStorage = this.waitingMediaForLoad[peerId] ?? (this.waitingMediaForLoad[peerId] = {});
|
||||
waitingStorage[mid] = deferred;
|
||||
}
|
||||
|
||||
// если что - загрузит voice или round заранее, так правильнее
|
||||
@ -105,7 +118,7 @@ class AppMediaPlaybackController {
|
||||
media.src = doc.url;
|
||||
}, onError);
|
||||
|
||||
return this.media[mid] = media;
|
||||
return storage[mid] = media;
|
||||
}
|
||||
|
||||
// safari подгрузит последний чанк и песня включится,
|
||||
@ -136,11 +149,12 @@ class AppMediaPlaybackController {
|
||||
}/* , {once: true} */);
|
||||
}
|
||||
|
||||
public resolveWaitingForLoadMedia(mid: number) {
|
||||
const promise = this.waitingMediaForLoad[mid];
|
||||
public resolveWaitingForLoadMedia(peerId: number, mid: number) {
|
||||
const storage = this.waitingMediaForLoad[peerId] ?? (this.waitingMediaForLoad[peerId] = {});
|
||||
const promise = storage[mid];
|
||||
if(promise) {
|
||||
promise.resolve();
|
||||
delete this.waitingMediaForLoad[mid];
|
||||
delete storage[mid];
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,13 +181,13 @@ class AppMediaPlaybackController {
|
||||
//console.log('on media end');
|
||||
|
||||
if(this.nextMid) {
|
||||
const media = this.media[this.nextMid];
|
||||
const media = this.media[this.currentPeerId][this.nextMid];
|
||||
|
||||
/* if(isSafari) {
|
||||
media.autoplay = true;
|
||||
} */
|
||||
|
||||
this.resolveWaitingForLoadMedia(this.nextMid);
|
||||
this.resolveWaitingForLoadMedia(this.currentPeerId, this.nextMid);
|
||||
|
||||
setTimeout(() => {
|
||||
media.play()//.catch(() => {});
|
||||
@ -189,7 +203,7 @@ class AppMediaPlaybackController {
|
||||
//_: type == 'audio' ? 'inputMessagesFilterMusic' : (type == 'round' ? 'inputMessagesFilterRoundVideo' : 'inputMessagesFilterVoice')
|
||||
_: type == 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice'
|
||||
}, mid, 3, 0, 2).then(value => {
|
||||
if(this.playingMedia != media) {
|
||||
if(this.playingMedia !== media) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -61,10 +61,11 @@ export function decodeWaveform(waveform: Uint8Array | number[]) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function wrapVoiceMessage(peerId: number, doc: MyDocument, audioEl: AudioElement, mid: number) {
|
||||
function wrapVoiceMessage(audioEl: AudioElement) {
|
||||
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;
|
||||
let isUnread = message && message.pFlags.media_unread;
|
||||
if(isUnread) {
|
||||
@ -171,7 +172,7 @@ function wrapVoiceMessage(peerId: number, doc: MyDocument, audioEl: AudioElement
|
||||
audioEl.addAudioListener('playing', () => {
|
||||
if(isUnread && !isOut && audioEl.classList.contains('is-unread')) {
|
||||
audioEl.classList.remove('is-unread');
|
||||
appMessagesManager.readMessages(peerId, [mid]);
|
||||
appMessagesManager.readMessages(audioEl.message.peerId, [audioEl.message.mid]);
|
||||
isUnread = false;
|
||||
}
|
||||
|
||||
@ -249,9 +250,10 @@ function wrapVoiceMessage(peerId: number, doc: MyDocument, audioEl: AudioElement
|
||||
return onLoad;
|
||||
}
|
||||
|
||||
function wrapAudio(doc: MyDocument, audioEl: AudioElement) {
|
||||
const withTime = !!+audioEl.getAttribute('with-time');
|
||||
function wrapAudio(audioEl: AudioElement) {
|
||||
const withTime = audioEl.withTime;
|
||||
|
||||
const doc = audioEl.message.media.document;
|
||||
const title = doc.audioTitle || doc.file_name;
|
||||
let subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : '';
|
||||
|
||||
@ -314,6 +316,8 @@ function wrapAudio(doc: MyDocument, audioEl: AudioElement) {
|
||||
export default class AudioElement extends HTMLElement {
|
||||
public audio: HTMLAudioElement;
|
||||
public preloader: ProgressivePreloader;
|
||||
public message: any;
|
||||
public withTime = false;
|
||||
|
||||
private attachedHandlers: {[name: string]: any[]} = {};
|
||||
private onTypeDisconnect: () => void;
|
||||
@ -329,11 +333,8 @@ export default class AudioElement extends HTMLElement {
|
||||
|
||||
this.classList.add('audio');
|
||||
|
||||
const peerId = +this.getAttribute('peer-id');
|
||||
const mid = +this.getAttribute('message-id');
|
||||
const docId = this.getAttribute('doc-id');
|
||||
const doc = appDocsManager.getDoc(docId);
|
||||
const uploading = +doc.id < 0;
|
||||
const doc = this.message.media.document;
|
||||
const uploading = this.message.pFlags.is_outgoing;
|
||||
|
||||
const durationStr = String(doc.duration | 0).toHHMMSS(true);
|
||||
|
||||
@ -352,13 +353,13 @@ export default class AudioElement extends HTMLElement {
|
||||
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;
|
||||
audioTimeDiv.innerHTML = durationStr;
|
||||
|
||||
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();
|
||||
|
||||
@ -449,7 +450,7 @@ export default class AudioElement extends HTMLElement {
|
||||
const r = (e: Event) => {
|
||||
//onLoad();
|
||||
//cancelEvent(e);
|
||||
appMediaPlaybackController.resolveWaitingForLoadMedia(mid);
|
||||
appMediaPlaybackController.resolveWaitingForLoadMedia(this.message.peerId, this.message.mid);
|
||||
|
||||
appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio
|
||||
|
||||
@ -465,7 +466,7 @@ export default class AudioElement extends HTMLElement {
|
||||
preloader.attach(downloadDiv);
|
||||
this.append(downloadDiv);
|
||||
|
||||
new Promise((resolve) => {
|
||||
new Promise<void>((resolve) => {
|
||||
if(this.audio.readyState >= 2) resolve();
|
||||
else this.addAudioListener('canplay', resolve);
|
||||
}).then(() => {
|
||||
@ -473,7 +474,7 @@ export default class AudioElement extends HTMLElement {
|
||||
|
||||
//setTimeout(() => {
|
||||
// release loaded audio
|
||||
if(appMediaPlaybackController.willBePlayedMedia == this.audio) {
|
||||
if(appMediaPlaybackController.willBePlayedMedia === this.audio) {
|
||||
this.audio.play();
|
||||
appMediaPlaybackController.willBePlayedMedia = null;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import rootScope from "../../lib/rootScope";
|
||||
import { generatePathData } from "../../helpers/dom";
|
||||
import { MyMessage } from "../../lib/appManagers/appMessagesManager";
|
||||
import Chat from "./chat";
|
||||
|
||||
type Group = {bubble: HTMLDivElement, mid: number, timestamp: number}[];
|
||||
type BubbleGroup = {timestamp: number, fromId: number, mid: number, group: Group};
|
||||
@ -10,6 +11,10 @@ export default class BubbleGroups {
|
||||
//updateRAFs: Map<HTMLDivElement[], number> = new Map();
|
||||
private newGroupDiff = 121; // * 121 in scheduled messages
|
||||
|
||||
constructor(private chat: Chat) {
|
||||
|
||||
}
|
||||
|
||||
removeBubble(bubble: HTMLDivElement, mid: number) {
|
||||
const details = this.bubbles.findAndSplice(g => g.mid === mid);
|
||||
if(details && details.group.length) {
|
||||
@ -38,10 +43,37 @@ export default class BubbleGroups {
|
||||
|
||||
const insertObject = {bubble, mid, timestamp};
|
||||
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);
|
||||
return bubble.fromId === fromId && diff <= this.newGroupDiff;
|
||||
});
|
||||
}); */
|
||||
|
||||
if(!foundBubble) this.groups.push(group = [insertObject]);
|
||||
else {
|
||||
@ -70,8 +102,21 @@ export default class BubbleGroups {
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ import { AppChatsManager } from "../../lib/appManagers/appChatsManager";
|
||||
import Chat from "./chat";
|
||||
import ListenerSetter from "../../helpers/listenerSetter";
|
||||
import PollElement from "../poll";
|
||||
import AudioElement from "../audio";
|
||||
|
||||
const IGNORE_ACTIONS = ['messageActionHistoryClear'];
|
||||
|
||||
@ -120,7 +121,7 @@ export default class ChatBubbles {
|
||||
// * constructor end
|
||||
|
||||
this.log = this.chat.log;
|
||||
this.bubbleGroups = new BubbleGroups();
|
||||
this.bubbleGroups = new BubbleGroups(this.chat);
|
||||
this.preloader = new ProgressivePreloader(null, false);
|
||||
this.lazyLoadQueue = new LazyLoadQueue();
|
||||
this.lazyLoadQueue.queueId = ++queueId;
|
||||
@ -165,7 +166,7 @@ export default class ChatBubbles {
|
||||
|
||||
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) {
|
||||
const message = this.chat.getMessage(mid);
|
||||
const bubble = mounted.bubble;
|
||||
@ -175,7 +176,7 @@ export default class ChatBubbles {
|
||||
|
||||
// set new mids to album items for mediaViewer
|
||||
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;
|
||||
}
|
||||
|
||||
@ -190,9 +191,10 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
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('message-id', '' + mid);
|
||||
audio.message = message;
|
||||
}
|
||||
|
||||
/* bubble.classList.remove('is-sending');
|
||||
@ -219,7 +221,7 @@ export default class ChatBubbles {
|
||||
delete this.bubbles[tempId];
|
||||
|
||||
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;
|
||||
|
||||
this.bubbleGroups.removeBubble(bubble, tempId);
|
||||
@ -695,9 +697,7 @@ export default class ChatBubbles {
|
||||
return Array.from(bubble.querySelectorAll('.grouped-item')) as HTMLElement[];
|
||||
}
|
||||
|
||||
public getMountedBubble(mid: number) {
|
||||
const message = this.chat.getMessage(mid);
|
||||
|
||||
public getMountedBubble(mid: number, message = this.chat.getMessage(mid)) {
|
||||
if(message.grouped_id && this.appMessagesManager.getMidsByAlbum(message.grouped_id).length > 1) {
|
||||
const a = this.getGroupedBubble(message.grouped_id);
|
||||
if(a) {
|
||||
@ -1350,40 +1350,40 @@ export default class ChatBubbles {
|
||||
|
||||
public setBubblePosition(bubble: HTMLElement, message: any, reverse: boolean) {
|
||||
const dateMessage = this.getDateContainerByMessage(message, reverse);
|
||||
let children = Array.from(dateMessage.container.children).slice(1) as HTMLElement[];
|
||||
let i = 0, foundMidOnSameTimestamp = 0;
|
||||
for(; i < children.length; ++i) {
|
||||
const t = children[i];
|
||||
const timestamp = +t.dataset.timestamp;
|
||||
if(message.date < timestamp) {
|
||||
break;
|
||||
} else if(message.date === timestamp) {
|
||||
foundMidOnSameTimestamp = +t.dataset.mid;
|
||||
if(this.chat.type === 'scheduled' || this.chat.type === 'pinned') {
|
||||
let children = Array.from(dateMessage.container.children).slice(2) as HTMLElement[];
|
||||
let i = 0, foundMidOnSameTimestamp = 0;
|
||||
for(; i < children.length; ++i) {
|
||||
const t = children[i];
|
||||
const timestamp = +t.dataset.timestamp;
|
||||
if(message.date < timestamp) {
|
||||
break;
|
||||
} else if(message.date === timestamp) {
|
||||
foundMidOnSameTimestamp = +t.dataset.mid;
|
||||
}
|
||||
|
||||
if(foundMidOnSameTimestamp && message.mid < foundMidOnSameTimestamp) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundMidOnSameTimestamp && message.mid < foundMidOnSameTimestamp) {
|
||||
break;
|
||||
|
||||
// * 1 for date, 1 for date sentinel
|
||||
let index = 2 + i;
|
||||
if(bubble.parentElement) { // * if already mounted
|
||||
const currentIndex = whichChild(bubble);
|
||||
if(index > currentIndex) {
|
||||
index -= 1; // * minus for already mounted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// * 1 for date
|
||||
let index = 1 + 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);
|
||||
|
||||
//this.bubbleGroups.updateGroupByMessageId(message.mid);
|
||||
|
||||
/* if(reverse) {
|
||||
dateMessage.container.insertBefore(bubble, dateMessage.div.nextSibling);
|
||||
|
||||
positionElementByIndex(bubble, dateMessage.container, index);
|
||||
} else {
|
||||
dateMessage.container.append(bubble);
|
||||
} */
|
||||
if(reverse) {
|
||||
dateMessage.container.insertBefore(bubble, dateMessage.container.children[1].nextSibling);
|
||||
} else {
|
||||
dateMessage.container.append(bubble);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// * will change .cleaned in cleanup() and new instance will be created
|
||||
@ -1637,10 +1637,11 @@ export default class ChatBubbles {
|
||||
bubbleContainer.prepend(containerDiv);
|
||||
}
|
||||
|
||||
const isOutgoing = message.pFlags.is_outgoing/* && this.peerId != rootScope.myId */;
|
||||
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 = '';
|
||||
if(message.mid < 0) status = 'is-sending';
|
||||
if(isOutgoing) status = 'is-sending';
|
||||
else status = message.pFlags.unread ? 'is-sent' : 'is-read';
|
||||
bubble.classList.add(status);
|
||||
}
|
||||
@ -1839,7 +1840,9 @@ export default class ChatBubbles {
|
||||
});
|
||||
//}
|
||||
} else {
|
||||
const docDiv = wrapDocument(this.peerId, doc, false, false, message.mid);
|
||||
const docDiv = wrapDocument({
|
||||
message
|
||||
});
|
||||
preview.append(docDiv);
|
||||
preview.classList.add('preview-with-document');
|
||||
//messageDiv.classList.add((webpage.type || 'document') + '-message');
|
||||
|
@ -256,13 +256,24 @@ export default class PopupNewMedia extends PopupElement {
|
||||
params.objectURL = URL.createObjectURL(file);
|
||||
}
|
||||
|
||||
const docDiv = wrapDocument(0, {
|
||||
file: file,
|
||||
file_name: file.name || '',
|
||||
size: file.size,
|
||||
type: isPhoto ? 'photo' : 'doc',
|
||||
url: params.objectURL
|
||||
} as any, false, true);
|
||||
const docDiv = wrapDocument({
|
||||
message: {
|
||||
_: 'message',
|
||||
mid: 0,
|
||||
peerId: 0,
|
||||
media: {
|
||||
_: 'messageMediaDocument',
|
||||
document: {
|
||||
_: 'document',
|
||||
file: file,
|
||||
file_name: file.name || '',
|
||||
size: file.size,
|
||||
type: isPhoto ? 'photo' : 'doc',
|
||||
url: params.objectURL
|
||||
}
|
||||
}
|
||||
} as any
|
||||
});
|
||||
|
||||
const finish = () => {
|
||||
itemDiv.append(docDiv);
|
||||
|
@ -528,7 +528,11 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
case 'inputMessagesFilterMusic':
|
||||
case 'inputMessagesFilterDocument': {
|
||||
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;
|
||||
elemsToAppend.push(div);
|
||||
}
|
||||
|
@ -343,9 +343,21 @@ export const formatDate = (timestamp: number, monthShort = false, withYear = tru
|
||||
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') {
|
||||
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;
|
||||
return audioElement;
|
||||
}
|
||||
@ -438,15 +450,6 @@ export function wrapDocument(peerId: number, doc: MyDocument, withTime = false,
|
||||
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) {
|
||||
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
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});
|
||||
}
|
||||
|
||||
// * pending
|
||||
/* // * pending
|
||||
if(storage[0] < 0) {
|
||||
items.reverse();
|
||||
}
|
||||
} */
|
||||
|
||||
prepareAlbum({
|
||||
container: attachmentDiv,
|
||||
@ -979,15 +982,17 @@ export function wrapGroupedDocuments({albumMustBeRenderedFull, message, bubble,
|
||||
}) {
|
||||
let nameContainer: HTMLDivElement;
|
||||
const mids = albumMustBeRenderedFull ? chat.getMidsByMid(message.mid) : [message.mid];
|
||||
const isPending = message.mid < 0;
|
||||
if(isPending) {
|
||||
const isPending = message.pFlags.is_outgoing;
|
||||
/* if(isPending) {
|
||||
mids.reverse();
|
||||
}
|
||||
} */
|
||||
|
||||
mids.forEach((mid, idx) => {
|
||||
const message = chat.getMessage(mid);
|
||||
const doc = message.media.document;
|
||||
const div = wrapDocument(chat.peerId, doc, false, isPending, mid);
|
||||
const div = wrapDocument({
|
||||
message
|
||||
});
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.classList.add('document-container');
|
||||
|
@ -137,6 +137,10 @@ export class AppImManager {
|
||||
const hash = location.hash;
|
||||
const splitted = hash.split('?');
|
||||
|
||||
if(!splitted[1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params: any = {};
|
||||
splitted[1].split('&').forEach(item => {
|
||||
params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]);
|
||||
@ -148,7 +152,7 @@ export class AppImManager {
|
||||
case '#/im': {
|
||||
const p = params.p;
|
||||
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 => {
|
||||
const isUser = peer._ == 'user';
|
||||
const peerId = isUser ? peer.id : -peer.id;
|
||||
|
@ -78,7 +78,10 @@ export type PinnedStorage = Partial<{
|
||||
count: number,
|
||||
maxId: number
|
||||
}>;
|
||||
export type MessagesStorage = {[mid: string]: any};
|
||||
export type MessagesStorage = {
|
||||
//generateIndex: (message: any) => void
|
||||
[mid: string]: any
|
||||
};
|
||||
export class AppMessagesManager {
|
||||
public messagesStorageByPeerId: {[peerId: string]: MessagesStorage} = {};
|
||||
public groupedMessagesStorage: {[groupId: string]: MessagesStorage} = {}; // will be used for albums
|
||||
@ -107,7 +110,7 @@ export class AppMessagesManager {
|
||||
public pendingAfterMsgs: any = {};
|
||||
public pendingTopMsgs: {[peerId: string]: number} = {};
|
||||
public sendFilePromise: CancellablePromise<void> = Promise.resolve();
|
||||
public tempId = -1;
|
||||
public tempNum = 0;
|
||||
public tempFinalizeCallbacks: {
|
||||
[tempId: string]: {
|
||||
[callbackName: string]: Partial<{
|
||||
@ -231,7 +234,7 @@ export class AppMessagesManager {
|
||||
let removeUnread = 0;
|
||||
for(const mid of history) {
|
||||
const message = this.getMessageByPeer(dialog.peerId, mid);
|
||||
if(/* message._ != 'messageEmpty' && */message.id > 0) {
|
||||
if(/* message._ != 'messageEmpty' && */!message.pFlags.is_outgoing) {
|
||||
messages.push(message);
|
||||
|
||||
if(message.fromId != dialog.peerId) {
|
||||
@ -239,6 +242,7 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
dialog.top_message = message.mid;
|
||||
this.setDialogIndexByMessage(dialog, message);
|
||||
|
||||
break;
|
||||
} else if(message.pFlags && message.pFlags.unread) {
|
||||
@ -341,7 +345,7 @@ export class AppMessagesManager {
|
||||
|
||||
const {mid, peerId} = message;
|
||||
|
||||
if(mid < 0) {
|
||||
if(message.pFlags.is_outgoing) {
|
||||
return this.invokeAfterMessageIsSent(mid, 'edit', (message) => {
|
||||
this.log('invoke editMessage callback', message);
|
||||
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);
|
||||
return apiManager.invokeApi('messages.editMessage', {
|
||||
peer: appPeersManager.getInputPeerById(peerId),
|
||||
id: mid,
|
||||
id: message.id,
|
||||
message: text,
|
||||
media: options.newMedia,
|
||||
entities: entities ? this.getInputEntities(entities) : undefined,
|
||||
@ -426,10 +430,10 @@ export class AppMessagesManager {
|
||||
sendEntites = undefined;
|
||||
}
|
||||
|
||||
var messageId = this.tempId--;
|
||||
var messageId = this.generateTempMessageId(peerId);
|
||||
var randomIdS = randomLong();
|
||||
var pFlags: any = {};
|
||||
var replyToMsgId = options.replyToMsgId;
|
||||
var replyToMsgId = options.replyToMsgId ? this.getLocalMessageId(options.replyToMsgId) : undefined;
|
||||
var isChannel = appPeersManager.isChannel(peerId);
|
||||
var isMegagroup = isChannel && appPeersManager.isMegagroup(peerId);
|
||||
var asChannel = isChannel && !isMegagroup ? true : false;
|
||||
@ -589,10 +593,10 @@ export class AppMessagesManager {
|
||||
}> = {}) {
|
||||
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
|
||||
//this.checkSendOptions(options);
|
||||
const messageId = this.tempId--;
|
||||
const messageId = this.generateTempMessageId(peerId);
|
||||
const randomIdS = randomLong();
|
||||
const pFlags: any = {};
|
||||
const replyToMsgId = options.replyToMsgId;
|
||||
const replyToMsgId = options.replyToMsgId ? this.getLocalMessageId(options.replyToMsgId) : undefined;
|
||||
const isChannel = appPeersManager.isChannel(peerId);
|
||||
const isMegagroup = isChannel && appPeersManager.isMegagroup(peerId);
|
||||
const asChannel = !!(isChannel && !isMegagroup);
|
||||
@ -936,7 +940,7 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
|
||||
const replyToMsgId = options.replyToMsgId;
|
||||
const replyToMsgId = options.replyToMsgId ? this.getLocalMessageId(options.replyToMsgId) : undefined;
|
||||
|
||||
let caption = options.caption || '';
|
||||
let entities: MessageEntity[];
|
||||
@ -966,20 +970,24 @@ export class AppMessagesManager {
|
||||
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 => {
|
||||
message.grouped_id = groupId;
|
||||
});
|
||||
|
||||
const storage = options.scheduleDate ? this.getScheduledMessagesStorage(peerId) : this.getMessagesStorage(peerId);
|
||||
if(options.scheduleDate) {
|
||||
this.saveMessages(messages, {storage, isScheduled: true});
|
||||
this.saveMessages(messages, {storage, isScheduled: true, isOutgoing: true});
|
||||
rootScope.broadcast('scheduled_new', {peerId, mid: groupId});
|
||||
} else {
|
||||
this.saveMessages(messages, {storage});
|
||||
this.saveMessages(messages, {storage, isOutgoing: true});
|
||||
rootScope.broadcast('history_append', {peerId, messageId: groupId, my: true});
|
||||
|
||||
this.setDialogTopMessage(message);
|
||||
}
|
||||
|
||||
// * test pending
|
||||
//return;
|
||||
|
||||
const toggleError = (message: any, on: boolean) => {
|
||||
@ -1061,9 +1069,9 @@ export class AppMessagesManager {
|
||||
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
|
||||
|
||||
//this.checkSendOptions(options);
|
||||
const messageId = this.tempId--;
|
||||
const messageId = this.generateTempMessageId(peerId);
|
||||
const randomIdS = randomLong();
|
||||
const replyToMsgId = options.replyToMsgId;
|
||||
const replyToMsgId = options.replyToMsgId ? this.getLocalMessageId(options.replyToMsgId) : undefined;
|
||||
const isChannel = appPeersManager.isChannel(peerId);
|
||||
const isMegagroup = isChannel && appPeersManager.isMegagroup(peerId);
|
||||
const asChannel = isChannel && !isMegagroup ? true : false;
|
||||
@ -1266,16 +1274,19 @@ export class AppMessagesManager {
|
||||
|
||||
if(options.isScheduled) {
|
||||
if(!options.isGroupedItem) {
|
||||
this.saveMessages([message], {storage, isScheduled: true});
|
||||
this.saveMessages([message], {storage, isScheduled: true, isOutgoing: true});
|
||||
rootScope.broadcast('scheduled_new', {peerId, mid: messageId});
|
||||
}
|
||||
} else {
|
||||
const historyStorage = this.getHistoryStorage(peerId);
|
||||
historyStorage.pending.unshift(messageId);
|
||||
//historyStorage.pending.unshift(messageId);
|
||||
historyStorage.history.unshift(messageId);
|
||||
|
||||
if(!options.isGroupedItem) {
|
||||
this.saveMessages([message], {storage});
|
||||
this.saveMessages([message], {storage, isOutgoing: true});
|
||||
rootScope.broadcast('history_append', {peerId, messageId, my: true});
|
||||
|
||||
this.setDialogTopMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1284,6 +1295,25 @@ export class AppMessagesManager {
|
||||
if(!options.isGroupedItem) {
|
||||
setTimeout(message.send, 0);
|
||||
//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
|
||||
}> = {}) {
|
||||
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());
|
||||
|
||||
@ -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) {
|
||||
return this.messagesStorageByPeerId[peerId] ?? (this.messagesStorageByPeerId[peerId] = {});
|
||||
return this.messagesStorageByPeerId[peerId] ?? (this.messagesStorageByPeerId[peerId] = this.createMessageStorage());
|
||||
}
|
||||
|
||||
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', {
|
||||
peer: appPeersManager.getInputPeerById(peerId),
|
||||
unpin,
|
||||
silent,
|
||||
pm_oneside: oneSide,
|
||||
id: mid
|
||||
id
|
||||
}).then(updates => {
|
||||
this.log('pinned updates:', updates);
|
||||
apiUpdatesManager.processUpdateMessage(updates);
|
||||
@ -1789,9 +1841,47 @@ export class AppMessagesManager {
|
||||
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<{
|
||||
storage: MessagesStorage,
|
||||
isScheduled: true
|
||||
isScheduled: true,
|
||||
isOutgoing: true
|
||||
}> = {}) {
|
||||
let groups: Map<number, string>;
|
||||
messages.forEach((message) => {
|
||||
@ -1807,15 +1897,20 @@ export class AppMessagesManager {
|
||||
// defineNotNumerableProperties(message, ['rReply', 'mid', 'savedFrom', 'fwdFromId', 'fromId', 'peerId', 'reply_to_mid', 'viaBotId']);
|
||||
|
||||
const peerId = this.getMessagePeer(message);
|
||||
const storage = options.storage || this.getMessagesStorage(peerId);
|
||||
const isChannel = message.peer_id._ == 'peerChannel';
|
||||
const channelId = isChannel ? -peerId : 0;
|
||||
const isBroadcast = isChannel && appChatsManager.isBroadcast(channelId);
|
||||
|
||||
const mid = message.id;
|
||||
if(options.isScheduled) {
|
||||
message.pFlags.is_scheduled = true;
|
||||
}
|
||||
|
||||
if(options.isOutgoing) {
|
||||
message.pFlags.is_outgoing = true;
|
||||
}
|
||||
|
||||
const mid = this.generateMessageId(message.id);
|
||||
message.mid = mid;
|
||||
|
||||
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'])
|
||||
|
||||
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;
|
||||
if(!overwriting) {
|
||||
message.date -= serverTimeManager.serverTimeOffset;
|
||||
}
|
||||
|
||||
|
||||
//storage.generateIndex(message);
|
||||
const myId = appUsersManager.getSelf().id;
|
||||
|
||||
message.peerId = peerId;
|
||||
@ -1856,7 +1953,8 @@ export class AppMessagesManager {
|
||||
//if(peerId == myID) {
|
||||
if(fwdHeader.saved_from_peer && fwdHeader.saved_from_msg_id) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2019,10 +2117,9 @@ export class AppMessagesManager {
|
||||
if(message.message && message.message.length && !message.totalEntities) {
|
||||
const myEntities = RichTextProcessor.parseEntities(message.message);
|
||||
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;
|
||||
});
|
||||
|
||||
@ -2417,10 +2514,10 @@ export class AppMessagesManager {
|
||||
|
||||
let mid: number, message;
|
||||
if(dialog.top_message) {
|
||||
mid = dialog.top_message;
|
||||
mid = this.generateMessageId(dialog.top_message);//dialog.top_message;
|
||||
message = this.getMessageByPeer(peerId, mid);
|
||||
} else {
|
||||
mid = this.tempId--;
|
||||
mid = this.generateTempMessageId(peerId);
|
||||
message = {
|
||||
_: 'message',
|
||||
id: mid,
|
||||
@ -2432,7 +2529,7 @@ export class AppMessagesManager {
|
||||
date: 0,
|
||||
message: ''
|
||||
};
|
||||
this.saveMessages([message]);
|
||||
this.saveMessages([message], {isOutgoing: true});
|
||||
}
|
||||
|
||||
if(!message?.pFlags) {
|
||||
@ -2450,6 +2547,8 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
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._ == 'dialog') {
|
||||
@ -2536,7 +2635,7 @@ export class AppMessagesManager {
|
||||
if(lastReplyMarkup) {
|
||||
if(lastReplyMarkup.pFlags.single_use &&
|
||||
!lastReplyMarkup.pFlags.hidden &&
|
||||
(message.mid > lastReplyMarkup.mid || message.mid < 0) &&
|
||||
(message.mid > lastReplyMarkup.mid || message.pFlags.is_outgoing) &&
|
||||
message.message) {
|
||||
lastReplyMarkup.pFlags.hidden = true;
|
||||
// this.log('set', historyStorage.reply_markup)
|
||||
@ -2757,7 +2856,7 @@ export class AppMessagesManager {
|
||||
min_date: 0,
|
||||
max_date: 0,
|
||||
limit,
|
||||
offset_id: maxId || 0,
|
||||
offset_id: this.getLocalMessageId(maxId) || 0,
|
||||
add_offset: backLimit ? -backLimit : 0,
|
||||
max_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>;
|
||||
|
||||
mids = mids.map(mid => this.getLocalMessageId(mid));
|
||||
|
||||
if(peerId < 0 && appPeersManager.isChannel(-peerId)) {
|
||||
const channelId = -peerId;
|
||||
const channel = appChatsManager.getChat(channelId);
|
||||
if(!channel.pFlags.creator && !(channel.pFlags.editor && channel.pFlags.megagroup)) {
|
||||
const goodMsgIds: number[] = [];
|
||||
if (channel.pFlags.editor || channel.pFlags.megagroup) {
|
||||
msgIds.forEach((msgId, i) => {
|
||||
const message = this.getMessageByPeer(peerId, msgIds[i]);
|
||||
mids.forEach((msgId, i) => {
|
||||
const message = this.getMessageByPeer(peerId, mids[i]);
|
||||
if(message.pFlags.out) {
|
||||
goodMsgIds.push(msgId);
|
||||
}
|
||||
@ -2894,19 +2995,19 @@ export class AppMessagesManager {
|
||||
return;
|
||||
}
|
||||
|
||||
msgIds = goodMsgIds;
|
||||
mids = goodMsgIds;
|
||||
}
|
||||
|
||||
promise = apiManager.invokeApi('channels.deleteMessages', {
|
||||
channel: appChatsManager.getChannelInput(channelId),
|
||||
id: msgIds
|
||||
id: mids
|
||||
}).then((affectedMessages) => {
|
||||
apiUpdatesManager.processUpdateMessage({
|
||||
_: 'updateShort',
|
||||
update: {
|
||||
_: 'updateDeleteChannelMessages',
|
||||
channel_id: channelId,
|
||||
messages: msgIds,
|
||||
messages: mids,
|
||||
pts: affectedMessages.pts,
|
||||
pts_count: affectedMessages.pts_count
|
||||
}
|
||||
@ -2915,13 +3016,13 @@ export class AppMessagesManager {
|
||||
} else {
|
||||
promise = apiManager.invokeApi('messages.deleteMessages', {
|
||||
revoke: revoke || undefined,
|
||||
id: msgIds
|
||||
id: mids
|
||||
}).then((affectedMessages) => {
|
||||
apiUpdatesManager.processUpdateMessage({
|
||||
_: 'updateShort',
|
||||
update: {
|
||||
_: 'updateDeleteMessages',
|
||||
messages: msgIds,
|
||||
messages: mids,
|
||||
pts: affectedMessages.pts,
|
||||
pts_count: affectedMessages.pts_count
|
||||
}
|
||||
@ -3064,7 +3165,8 @@ export class AppMessagesManager {
|
||||
//this.log('AMM updateMessageID:', update, pendingData);
|
||||
if(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);
|
||||
if(!message.deleted) {
|
||||
const historyStorage = this.getHistoryStorage(peerId);
|
||||
@ -3150,16 +3252,10 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
const inboxUnread = !message.pFlags.out && message.pFlags.unread;
|
||||
dialog.top_message = message.mid;
|
||||
this.setDialogTopMessage(message);
|
||||
if(inboxUnread) {
|
||||
dialog.unread_count++;
|
||||
}
|
||||
if(!dialog.pFlags.pinned || !dialog.index) {
|
||||
dialog.index = this.dialogsStorage.generateDialogIndex(message.date);
|
||||
}
|
||||
|
||||
this.newDialogsToHandle[peerId] = dialog;
|
||||
this.scheduleHandleNewDialogs();
|
||||
|
||||
break;
|
||||
}
|
||||
@ -3331,7 +3427,8 @@ export class AppMessagesManager {
|
||||
case 'updateEditChannelMessage': {
|
||||
const message = update.message as MyMessage;
|
||||
const peerId = this.getMessagePeer(message);
|
||||
const mid = message.id;
|
||||
//const mid = message.id;
|
||||
const mid = this.generateMessageId(message.id);
|
||||
const storage = this.getMessagesStorage(peerId);
|
||||
if(storage[mid] === undefined) {
|
||||
break;
|
||||
@ -3388,7 +3485,8 @@ export class AppMessagesManager {
|
||||
case 'updateReadChannelInbox':
|
||||
case 'updateReadChannelOutbox': {
|
||||
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 isOut = update._ == 'updateReadHistoryOutbox' || update._ == 'updateReadChannelOutbox' ? true : undefined;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3493,7 +3591,8 @@ export class AppMessagesManager {
|
||||
case 'updateDeleteMessages':
|
||||
case 'updateDeleteChannelMessages': {
|
||||
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;
|
||||
|
||||
if(!peerId) {
|
||||
@ -3588,7 +3687,8 @@ export class AppMessagesManager {
|
||||
|
||||
case 'updateChannelMessageViews': {
|
||||
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);
|
||||
if(!message.deleted && message.views && message.views < views) {
|
||||
message.views = views;
|
||||
@ -3601,7 +3701,7 @@ export class AppMessagesManager {
|
||||
this.log('updateServiceNotification', update);
|
||||
const fromId = 777000;
|
||||
const peerId = fromId;
|
||||
const messageId = this.tempId--;
|
||||
const messageId = this.generateTempMessageId(peerId);
|
||||
const message: any = {
|
||||
_: 'message',
|
||||
id: messageId,
|
||||
@ -3623,7 +3723,7 @@ export class AppMessagesManager {
|
||||
phone: '42777'
|
||||
}]);
|
||||
}
|
||||
this.saveMessages([message]);
|
||||
this.saveMessages([message], {isOutgoing: true});
|
||||
|
||||
if(update.inbox_date) {
|
||||
this.pendingTopMsgs[peerId] = messageId;
|
||||
@ -3710,7 +3810,7 @@ export class AppMessagesManager {
|
||||
|
||||
const storage = this.scheduledMessagesStorage[peerId];
|
||||
if(storage) {
|
||||
const mid = message.id;
|
||||
const mid = this.generateMessageId(message.id);
|
||||
|
||||
const oldMessage = this.getMessageFromStorage(storage, mid);
|
||||
this.saveMessages([message], {storage, isScheduled: true});
|
||||
@ -3735,9 +3835,10 @@ export class AppMessagesManager {
|
||||
|
||||
const storage = this.scheduledMessagesStorage[peerId];
|
||||
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;
|
||||
@ -3836,6 +3937,7 @@ export class AppMessagesManager {
|
||||
|
||||
const message = this.getMessageFromStorage(storage, tempId);
|
||||
if(!message.deleted) {
|
||||
delete message.pFlags.is_outgoing;
|
||||
delete message.pending;
|
||||
delete message.error;
|
||||
delete message.random_id;
|
||||
@ -3913,7 +4015,7 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
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[]> {
|
||||
@ -4158,7 +4260,7 @@ export class AppMessagesManager {
|
||||
|
||||
const promise = apiManager.invokeApi('messages.getHistory', {
|
||||
peer: appPeersManager.getInputPeerById(peerId),
|
||||
offset_id: maxId || 0,
|
||||
offset_id: this.getLocalMessageId(maxId) || 0,
|
||||
offset_date: offsetDate,
|
||||
add_offset: offset,
|
||||
limit: limit,
|
||||
|
@ -170,7 +170,7 @@ export class AppPollsManager {
|
||||
const peerId = message.peerId;
|
||||
const inputPeer = appPeersManager.getInputPeerById(peerId);
|
||||
|
||||
if(messageId < 0) {
|
||||
if(message.pFlags.is_outgoing) {
|
||||
return appMessagesManager.invokeAfterMessageIsSent(messageId, 'sendVote', (message) => {
|
||||
this.log('invoke sendVote callback');
|
||||
return this.sendVote(message, optionIds);
|
||||
|
@ -513,7 +513,8 @@ export class ApiFileManager {
|
||||
(r.value as Promise<void>).then(process);
|
||||
};
|
||||
|
||||
const maxRequests = Infinity;
|
||||
//const maxRequests = Infinity;
|
||||
const maxRequests = 10;
|
||||
/* for(let i = 0; i < 10; ++i) {
|
||||
process();
|
||||
} */
|
||||
|
@ -364,7 +364,7 @@ namespace RichTextProcessor {
|
||||
return totalEntities;
|
||||
} */
|
||||
|
||||
export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[], fromApi?: boolean) {
|
||||
export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[]) {
|
||||
currentEntities = currentEntities.slice();
|
||||
const filtered = newEntities.filter(e => !currentEntities.find(_e => e._ == _e._ && e.offset == _e.offset && e.length == _e.length));
|
||||
currentEntities.push(...filtered);
|
||||
|
Loading…
x
Reference in New Issue
Block a user