diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 0e009aa7d..99ec1d13b 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -599,6 +599,12 @@ export default class ChatBubbles { this.changedMids.set(tempId, mid); + this.needUpdate.forEach((obj) => { + if(obj.peerId === tempMessage.peerId && obj.mid === tempId) { + obj.mid = mid; + } + }); + const fullTempMid = makeFullMid(tempMessage); const fullMid = makeFullMid(message); @@ -989,87 +995,8 @@ export default class ChatBubbles { }); } - const updateMessageReply = async(options: { - peerId: PeerId, - mids?: number[], - ids?: number[] - }) => { - const middleware = this.getMiddleware(); - await getHeavyAnimationPromise(); - if(!middleware()) return; - - const callbacks: (() => Promise)[] = []; - - const peerId = options.peerId; - const ids = options.mids || options.ids; - const needUpdate = this.needUpdate; - const property: keyof typeof needUpdate[0] = options.mids ? 'replyMid' : 'replyStoryId'; - const promises = ids.map((id) => { - const filtered: typeof needUpdate[0][] = []; - forEachReverse(needUpdate, (obj, idx) => { - if(obj[property] === id && (obj.replyToPeerId === peerId || !peerId)) { - needUpdate.splice(idx, 1)[0]; - filtered.push(obj); - } - }); - - const promises = filtered.map(async({peerId, mid, replyMid, replyToPeerId}) => { - const fullMid = makeFullMid(peerId, mid); - const bubble = this.getBubble(fullMid); - if(!bubble) return; - - const [message, originalMessage] = await Promise.all([ - this.chat.getMessage(fullMid) as Message.message, - replyMid && this.managers.appMessagesManager.getMessageByPeer(replyToPeerId, replyMid) as Promise - ]); - - callbacks.push(async() => { - const promise = MessageRender.setReply({ - chat: this.chat, - bubble, - message, - middleware: bubble.middlewareHelper.get(), - lazyLoadQueue: this.lazyLoadQueue, - needUpdate: this.needUpdate, - isStandaloneMedia: bubble.classList.contains('just-media'), - isOut: bubble.classList.contains('is-out') - }); - - if(!originalMessage) { - return promise; - } - - await promise; - - let maxMediaTimestamp: number; - const timestamps = bubble.querySelectorAll('.timestamp'); - if(maxMediaTimestamp = getMediaDurationFromMessage(originalMessage)) { - timestamps.forEach((timestamp) => { - const value = +timestamp.dataset.timestamp; - if(value < maxMediaTimestamp) { - timestamp.classList.remove('is-disabled'); - } else { - timestamp.removeAttribute('href'); - } - }); - } - }); - }); - - return Promise.all(promises); - }); - - await Promise.all(promises); - if(!middleware() || !callbacks.length) return; - - const scrollSaver = this.createScrollSaver(true); - scrollSaver.save(); - await Promise.all(callbacks.map((callback) => callback())); - scrollSaver.restore(); - }; - - !DO_NOT_UPDATE_MESSAGE_REPLY && this.listenerSetter.add(rootScope)('messages_downloaded', updateMessageReply); - !DO_NOT_UPDATE_MESSAGE_REPLY && this.listenerSetter.add(rootScope)('stories_downloaded', updateMessageReply); + !DO_NOT_UPDATE_MESSAGE_REPLY && this.listenerSetter.add(rootScope)('messages_downloaded', this.updateMessageReply); + !DO_NOT_UPDATE_MESSAGE_REPLY && this.listenerSetter.add(rootScope)('stories_downloaded', this.updateMessageReply); attachStickerViewerListeners({ listenTo: this.scrollable.container, @@ -1424,7 +1351,13 @@ export default class ChatBubbles { return; } - this.deleteMessagesByIds([...msgs.keys()].map((mid) => makeFullMid(peerId, mid))); + const mids = [...msgs.keys()]; + const fullMids = mids.map((mid) => makeFullMid(peerId, mid)); + this.deleteMessagesByIds(fullMids); + this.updateMessageReply({ + peerId, + mids + }); }); this.listenerSetter.add(rootScope)('history_delete_key', ({historyKey, mid}) => { @@ -1899,6 +1832,86 @@ export default class ChatBubbles { this.resizeObserver = undefined; } + private updateMessageReply = async(options: { + peerId: PeerId, + mids?: number[], + ids?: number[] + }) => { + const middleware = this.getMiddleware(); + await getHeavyAnimationPromise(); + if(!middleware()) return; + + const callbacks: (() => Promise)[] = []; + + const peerId = options.peerId; + const ids = options.mids || options.ids; + const needUpdate = this.needUpdate; + const property: keyof typeof needUpdate[0] = options.mids ? 'replyMid' : 'replyStoryId'; + const promises = ids.map((id) => { + const filtered: typeof needUpdate[0][] = []; + forEachReverse(needUpdate, (obj, idx) => { + if(obj[property] === id && (obj.replyToPeerId === peerId || !peerId)) { + // needUpdate.splice(idx, 1)[0]; + filtered.push(obj); + } + }); + + const promises = filtered.map(async({peerId, mid, replyMid, replyToPeerId}) => { + const fullMid = makeFullMid(peerId, mid); + const bubble = this.getBubble(fullMid); + if(!bubble) return; + + const [message, originalMessage] = await Promise.all([ + this.chat.getMessage(fullMid) as Message.message, + replyMid && this.managers.appMessagesManager.getMessageByPeer(replyToPeerId, replyMid) as Promise + ]); + + callbacks.push(async() => { + const promise = MessageRender.setReply({ + chat: this.chat, + bubble, + message, + middleware: bubble.middlewareHelper.get(), + lazyLoadQueue: this.lazyLoadQueue, + needUpdate: this.needUpdate, + isStandaloneMedia: bubble.classList.contains('just-media'), + isOut: bubble.classList.contains('is-out'), + fromUpdate: true + }); + + if(!originalMessage) { + return promise; + } + + await promise; + + let maxMediaTimestamp: number; + const timestamps = bubble.querySelectorAll('.timestamp'); + if(maxMediaTimestamp = getMediaDurationFromMessage(originalMessage)) { + timestamps.forEach((timestamp) => { + const value = +timestamp.dataset.timestamp; + if(value < maxMediaTimestamp) { + timestamp.classList.remove('is-disabled'); + } else { + timestamp.removeAttribute('href'); + } + }); + } + }); + }); + + return Promise.all(promises); + }); + + await Promise.all(promises); + if(!middleware() || !callbacks.length) return; + + const scrollSaver = this.createScrollSaver(true); + scrollSaver.save(); + await Promise.all(callbacks.map((callback) => callback())); + scrollSaver.restore(); + }; + private onBubblesMouseMove = async(e: MouseEvent) => { const mediaVideoContainer = findUpClassName(e.target, 'media-video-mini'); (mediaVideoContainer as any)?.onMouseMove?.(e); diff --git a/src/components/chat/messageRender.ts b/src/components/chat/messageRender.ts index 545d114d3..010479dee 100644 --- a/src/components/chat/messageRender.ts +++ b/src/components/chat/messageRender.ts @@ -29,6 +29,7 @@ import getStickerEffectThumb from '../../lib/appManagers/utils/stickers/getStick import wrapStickerAnimation from '../wrappers/stickerAnimation'; import Scrollable from '../scrollable'; import appDownloadManager from '../../lib/appManagers/appDownloadManager'; +import indexOfAndSplice from '../../helpers/array/indexOfAndSplice'; const NBSP = ' '; @@ -330,7 +331,7 @@ export namespace MessageRender { return isFooter; }; - export const setReply = async({chat, bubble, bubbleContainer, message, appendCallback, middleware, lazyLoadQueue, needUpdate, isStandaloneMedia, isOut}: { + export const setReply = async({chat, bubble, bubbleContainer, message, appendCallback, middleware, lazyLoadQueue, needUpdate, isStandaloneMedia, isOut, fromUpdate}: { chat: Chat, bubble: HTMLElement, bubbleContainer?: HTMLElement, @@ -340,14 +341,15 @@ export namespace MessageRender { lazyLoadQueue: LazyLoadQueue, needUpdate: ChatBubbles['needUpdate'], isStandaloneMedia: boolean, - isOut: boolean + isOut: boolean, + fromUpdate?: boolean }) => { const isReplacing = !bubbleContainer; if(isReplacing) { bubbleContainer = bubble.querySelector('.bubble-content'); } - const currentReplyDiv = isReplacing ? bubbleContainer.querySelector('.reply') : null; + const currentReplyDiv = isReplacing ? bubbleContainer.querySelector('.reply') as HTMLElement : null; const replyTo = message.reply_to; if(!replyTo) { currentReplyDiv?.remove(); @@ -370,12 +372,24 @@ export namespace MessageRender { let originalPeerTitle: string | HTMLElement | DocumentFragment; let isReplyFromAnotherPeer = false; - let titlePeerId: PeerId, setColorPeerId: PeerId; + let titlePeerId: PeerId, setColorPeerId: PeerId, forUpdate: typeof needUpdate[0]; + + if(!fromUpdate) { + if(isStoryReply) { + needUpdate.push(forUpdate = {replyToPeerId, replyStoryId: replyTo.story_id, mid: message.mid, peerId: message.peerId}); + } else { + needUpdate.push(forUpdate = {replyToPeerId, replyMid: message.reply_to_mid, mid: message.mid, peerId: message.peerId}); + } + + middleware.onClean(() => { + indexOfAndSplice(needUpdate, forUpdate); + }); + } + if(isStoryReply) { if(!originalStory.cached) { - needUpdate.push({replyToPeerId, replyStoryId: replyTo.story_id, mid: message.mid, peerId: message.peerId}); rootScope.managers.appMessagesManager.fetchMessageReplyTo(message); - + // needUpdate.push(forUpdate = {replyToPeerId, replyStoryId: replyTo.story_id, mid: message.mid, peerId: message.peerId}); originalPeerTitle = i18n('Loading'); } else { titlePeerId = replyToPeerId; @@ -399,7 +413,7 @@ export namespace MessageRender { fromName: getFwdFromName(replyTo.reply_from) }).element; } else { - needUpdate.push({replyToPeerId, replyMid: message.reply_to_mid, mid: message.mid, peerId: message.peerId}); + // needUpdate.push(forUpdate = {replyToPeerId, replyMid: message.reply_to_mid, mid: message.mid, peerId: message.peerId}); rootScope.managers.appMessagesManager.fetchMessageReplyTo(message); originalPeerTitle = i18n('Loading'); diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 5777755a8..54311a60a 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -317,6 +317,8 @@ export class AppMessagesManager extends AppManager { private fetchSingleMessagesPromise: Promise; private extendedMedia: Map>> = new Map(); + private deletedMessages: Set = new Set(); + private maxSeenId = 0; public migratedFromTo: {[peerId: PeerId]: PeerId} = {}; @@ -8004,6 +8006,8 @@ export class AppMessagesManager extends AppManager { if(map.size) { for(const [mid, promise] of map) { + const deletedPeerId = peerId.isAnyChat() && isLegacyMessageId(mid) ? GLOBAL_HISTORY_PEER_ID : peerId; + this.deletedMessages.add(`${deletedPeerId}_${mid}`); promise.resolve(this.generateEmptyMessage(mid)); } } @@ -8037,7 +8041,7 @@ export class AppMessagesManager extends AppManager { } const message = this.getMessageByPeer(peerId, mid); - if(message && !overwrite) { + if(this.deletedMessages.has(`${peerId}_${mid}`) || (message && !overwrite)) { this.rootScope.dispatchEvent('messages_downloaded', {peerId, mids: [mid]}); return Promise.resolve(message); } else { @@ -8243,6 +8247,11 @@ export class AppMessagesManager extends AppManager { this.handleReleasingMessage(message, storage); + { + const deletedPeerId = peerId.isAnyChat() && isLegacyMessageId(mid) ? GLOBAL_HISTORY_PEER_ID : peerId; + this.deletedMessages.add(`${deletedPeerId}_${message.mid}`); + } + this.updateMessageRepliesIfNeeded(message, false); if(!message.pFlags.out && !message.pFlags.is_outgoing && message.pFlags.unread) {