Skip to content

Commit

Permalink
Update reply box when original message is deleted
Browse files Browse the repository at this point in the history
  • Loading branch information
morethanwords committed Nov 8, 2024
1 parent 49d26ab commit 7af3c67
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 90 deletions.
177 changes: 95 additions & 82 deletions src/components/chat/bubbles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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<any>)[] = [];

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<Message.message>
]);

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<HTMLAnchorElement>('.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,
Expand Down Expand Up @@ -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}) => {
Expand Down Expand Up @@ -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<any>)[] = [];

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<Message.message>
]);

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<HTMLAnchorElement>('.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);
Expand Down
28 changes: 21 additions & 7 deletions src/components/chat/messageRender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '&nbsp;';

Expand Down Expand Up @@ -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,
Expand All @@ -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();
Expand All @@ -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;
Expand All @@ -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');
Expand Down
11 changes: 10 additions & 1 deletion src/lib/appManagers/appMessagesManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ export class AppMessagesManager extends AppManager {
private fetchSingleMessagesPromise: Promise<void>;
private extendedMedia: Map<PeerId, Map<number, CancellablePromise<void>>> = new Map();

private deletedMessages: Set<string> = new Set();

private maxSeenId = 0;

public migratedFromTo: {[peerId: PeerId]: PeerId} = {};
Expand Down Expand Up @@ -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));
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 7af3c67

Please sign in to comment.