diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 394c2376..4e2b42ee 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -37,7 +37,7 @@ import Chat from "./chat"; import ListenerSetter from "../../helpers/listenerSetter"; import PollElement from "../poll"; import AudioElement from "../audio"; -import { MessageEntity, MessageReplies, MessageReplyHeader } from "../../layer"; +import { Message, MessageEntity, MessageReplies, MessageReplyHeader } from "../../layer"; import { DEBUG, MOUNT_CLASS_TO } from "../../lib/mtproto/mtproto_config"; const IGNORE_ACTIONS = ['messageActionHistoryClear']; @@ -524,12 +524,11 @@ export default class ChatBubbles { const commentsDiv: HTMLElement = findUpClassName(target, 'replies'); if(commentsDiv) { - const mid = +bubble.dataset.mid; - const message = this.chat.getMessage(mid); - const replies = message.replies as MessageReplies; + const bubbleMid = +bubble.dataset.mid; + const message = this.appMessagesManager.filterMessages(this.chat.getMessage(bubbleMid), message => !!(message as Message.message).replies)[0] as Message.message; + const replies = message.replies; if(replies) { - this.appMessagesManager.getDiscussionMessage(this.peerId, mid).then(result => { - const message = result.messages[0]; + this.appMessagesManager.getDiscussionMessage(this.peerId, message.mid).then(message => { this.chat.appImManager.setInnerPeer(-replies.channel_id, (message as MyMessage).mid, 'discussion'); }); } @@ -1452,7 +1451,7 @@ export default class ChatBubbles { public renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = null, updatePosition = true) { this.log.debug('message to render:', message); //return; - const albumMustBeRenderedFull = this.chat.type === 'chat' || this.chat.type === 'scheduled'; + const albumMustBeRenderedFull = this.chat.type !== 'pinned'; if(message.deleted) return; else if(message.grouped_id && albumMustBeRenderedFull) { // will render only last album's message const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id]; @@ -1701,7 +1700,8 @@ export default class ChatBubbles { bubble.classList.add(status); } - const withReplyFooter = message.replies && message.replies.pFlags.comments && message.replies.channel_id !== 777; + let messageWithReplies: Message.message = this.appMessagesManager.filterMessages(message, message => !!(message as Message.message).replies)[0] as any; + const withReplies = messageWithReplies && messageWithReplies.replies && messageWithReplies.replies.pFlags.comments && messageWithReplies.replies.channel_id !== 777; const isOut = our && (!message.fwd_from || this.peerId != rootScope.myId); let nameContainer = bubbleContainer; @@ -1743,7 +1743,7 @@ export default class ChatBubbles { const photo = this.appPhotosManager.getPhoto(message.id); //if(photo._ == 'photoEmpty') break; this.log('will wrap pending photo:', pending, message, photo); - const withTail = !isAndroid && !message.message && !withReplyFooter; + const withTail = !isAndroid && !message.message && !withReplies; if(withTail) bubble.classList.add('with-media-tail'); wrapPhoto({ photo, message, @@ -1764,7 +1764,7 @@ export default class ChatBubbles { let doc = this.appDocsManager.getDoc(message.id); //if(doc._ == 'documentEmpty') break; this.log('will wrap pending video:', pending, message, doc); - const withTail = !isAndroid && !isApple && doc.type != 'round' && !message.message && !withReplyFooter; + const withTail = !isAndroid && !isApple && doc.type != 'round' && !message.message && !withReplies; if(withTail) bubble.classList.add('with-media-tail'); wrapVideo({ doc, @@ -1839,7 +1839,7 @@ export default class ChatBubbles { break; } - const withTail = !isAndroid && !message.message && !withReplyFooter; + const withTail = !isAndroid && !message.message && !withReplies; if(withTail) bubble.classList.add('with-media-tail'); wrapPhoto({ photo, @@ -2023,7 +2023,7 @@ export default class ChatBubbles { chat: this.chat }); } else { - const withTail = !isAndroid && !isApple && doc.type != 'round' && !message.message && withReplyFooter; + const withTail = !isAndroid && !isApple && doc.type != 'round' && !message.message && withReplies; if(withTail) bubble.classList.add('with-media-tail'); wrapVideo({ doc, @@ -2241,7 +2241,7 @@ export default class ChatBubbles { savedFrom = `${this.chat.peerId}_${message.mid}`; } - if(message.mid === this.chat.threadId) { + if(messageWithReplies && messageWithReplies.mid === this.chat.threadId) { bubble.classList.add('is-thread-starter'); } @@ -2262,11 +2262,11 @@ export default class ChatBubbles { this.bubbleGroups.updateGroupByMessageId(message.mid); } - if(withReplyFooter) { + if(withReplies) { MessageRender.renderReplies({ bubble, bubbleContainer, - message, + message: messageWithReplies, messageDiv }); } @@ -2508,7 +2508,7 @@ export default class ChatBubbles { if(isTopEnd) { const serviceStartMessageId = this.appMessagesManager.threadsServiceMessagesIdsStorage[this.peerId + '_' + this.chat.threadId]; if(serviceStartMessageId) historyResult.history.push(serviceStartMessageId); - historyResult.history.push(this.chat.threadId); + historyResult.history.push(...this.chat.getMidsByMid(this.chat.threadId).reverse()); this.scrolledAll = true; } } @@ -2639,7 +2639,7 @@ export default class ChatBubbles { // preload more //if(!isFirstMessageRender) { - if(this.chat.type === 'chat' || this.chat.type === 'discussion') { + if(this.chat.type === 'chat'/* || this.chat.type === 'discussion' */) { const storage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId); const isMaxIdInHistory = storage.history.indexOf(maxId) !== -1; if(isMaxIdInHistory) { // * otherwise it is a search or jump diff --git a/src/components/chat/messageRender.ts b/src/components/chat/messageRender.ts index 7fd9539b..39e42ad1 100644 --- a/src/components/chat/messageRender.ts +++ b/src/components/chat/messageRender.ts @@ -1,12 +1,8 @@ import { getFullDate } from "../../helpers/date"; import { formatNumber } from "../../helpers/number"; -import { Message } from "../../layer"; -import appMessagesManager from "../../lib/appManagers/appMessagesManager"; -import appPeersManager from "../../lib/appManagers/appPeersManager"; import RichTextProcessor from "../../lib/richtextprocessor"; -import rootScope from "../../lib/rootScope"; -import { ripple } from "../ripple"; import Chat from "./chat"; +import RepliesElement from "./replies"; export namespace MessageRender { /* export const setText = () => { @@ -75,76 +71,3 @@ export namespace MessageRender { bubbleContainer.prepend(repliesFooter); }; } - -rootScope.on('replies_updated', (e) => { - const message = e.detail; - (Array.from(document.querySelectorAll(`replies-footer-element[data-post-key="${message.peerId}_${message.mid}"]`)) as RepliesElement[]).forEach(element => { - element.message = message; - element.render(); - }); -}); - -class RepliesElement extends HTMLElement { - public message: Message.message; - public type: 'footer' | 'beside'; - - private updated = false; - - constructor() { - super(); - } - - connectedCallback() { - this.render(); - this.dataset.postKey = this.message.peerId + '_' + this.message.mid; - this.classList.add('replies', 'replies-' + this.type); - } - - public render() { - const replies = this.message.replies; - - if(this.type === 'footer') { - let leftHTML = '', lastStyle = ''; - if(replies.recent_repliers) { - leftHTML += ''; - } else { - leftHTML = ''; - } - - let text: string; - if(replies.replies) { - text = replies.replies + ' ' + (replies.replies > 1 ? 'Comments' : 'Comment'); - } else { - text = 'Leave a Comment'; - } - - const historyStorage = appMessagesManager.getHistoryStorage(-replies.channel_id); - if(replies.read_max_id < replies.max_id && (!historyStorage.readMaxId || historyStorage.readMaxId < replies.max_id)) { - this.classList.add('is-unread'); - } - - this.innerHTML = `${leftHTML}${text}`; - - const rippleContainer = document.createElement('div'); - this.append(rippleContainer); - ripple(rippleContainer); - } else { - this.classList.add('bubble-beside-button'); - this.innerHTML = `${replies.replies ? formatNumber(replies.replies, 0) : ''}`; - } - - if(!this.updated) { - appMessagesManager.subscribeRepliesThread(this.message.peerId, this.message.mid); - appMessagesManager.updateMessage(this.message.peerId, this.message.mid, 'replies_updated'); - this.updated = true; - } - } -} - -customElements.define('replies-element', RepliesElement); \ No newline at end of file diff --git a/src/components/chat/replies.ts b/src/components/chat/replies.ts new file mode 100644 index 00000000..3942e8be --- /dev/null +++ b/src/components/chat/replies.ts @@ -0,0 +1,79 @@ +import { formatNumber } from "../../helpers/number"; +import { Message } from "../../layer"; +import appMessagesManager from "../../lib/appManagers/appMessagesManager"; +import appPeersManager from "../../lib/appManagers/appPeersManager"; +import rootScope from "../../lib/rootScope"; +import { ripple } from "../ripple"; + +rootScope.on('replies_updated', (e) => { + const message = e.detail; + (Array.from(document.querySelectorAll(`replies-footer-element[data-post-key="${message.peerId}_${message.mid}"]`)) as RepliesElement[]).forEach(element => { + element.message = message; + element.render(); + }); +}); + +export default class RepliesElement extends HTMLElement { + public message: Message.message; + public type: 'footer' | 'beside'; + + private updated = false; + + constructor() { + super(); + } + + connectedCallback() { + this.render(); + this.dataset.postKey = this.message.peerId + '_' + this.message.mid; + this.classList.add('replies', 'replies-' + this.type); + } + + public render() { + const replies = this.message.replies; + + if(this.type === 'footer') { + let leftHTML = '', lastStyle = ''; + if(replies.recent_repliers) { + leftHTML += ''; + } else { + leftHTML = ''; + } + + let text: string; + if(replies.replies) { + text = replies.replies + ' ' + (replies.replies > 1 ? 'Comments' : 'Comment'); + } else { + text = 'Leave a Comment'; + } + + const historyStorage = appMessagesManager.getHistoryStorage(-replies.channel_id); + if(replies.read_max_id < replies.max_id && (!historyStorage.readMaxId || historyStorage.readMaxId < replies.max_id)) { + this.classList.add('is-unread'); + } + + this.innerHTML = `${leftHTML}${text}`; + + const rippleContainer = document.createElement('div'); + this.append(rippleContainer); + ripple(rippleContainer); + } else { + this.classList.add('bubble-beside-button'); + this.innerHTML = `${replies.replies ? formatNumber(replies.replies, 0) : ''}`; + } + + if(!this.updated) { + appMessagesManager.subscribeRepliesThread(this.message.peerId, this.message.mid); + appMessagesManager.updateMessage(this.message.peerId, this.message.mid, 'replies_updated'); + this.updated = true; + } + } +} + +customElements.define('replies-element', RepliesElement); \ No newline at end of file diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 80ed6bfe..c045ecc2 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -1908,6 +1908,25 @@ export class AppMessagesManager { else return [message.mid]; } + public filterMessages(message: any, verify: (message: MyMessage) => boolean) { + const out: MyMessage[] = []; + if(message.grouped_id) { + const storage = this.groupedMessagesStorage[message.grouped_id]; + for(const mid in storage) { + const message = storage[mid]; + if(verify(message)) { + out.push(message); + } + } + } else { + if(verify(message)) { + out.push(message); + } + } + + return out; + } + public generateTempMessageId(peerId: number) { const dialog = this.getDialogByPeerId(peerId)[0]; return this.generateMessageId(dialog?.top_message || 0, true); @@ -3046,7 +3065,7 @@ export class AppMessagesManager { appUsersManager.saveApiUsers(result.users); this.saveMessages(result.messages); - const message = result.messages[0] as MyMessage; + const message = this.filterMessages(result.messages[0], message => !!(message as Message.message).replies)[0] as Message.message; const threadKey = message.peerId + '_' + message.mid; if(!this.threadsServiceMessagesIdsStorage[threadKey]) { @@ -3076,7 +3095,7 @@ export class AppMessagesManager { this.threadsToReplies[threadKey] = peerId + '_' + mid; - return result; + return message; }); } @@ -3355,6 +3374,7 @@ export class AppMessagesManager { const pendingMessage = this.checkPendingMessage(message); const historyStorage = this.getHistoryStorage(peerId); + this.updateMessageRepliesIfNeeded(message); const history = message.mid > 0 ? historyStorage.history : historyStorage.pending; if(history.indexOf(message.mid) !== -1) { @@ -3390,8 +3410,6 @@ export class AppMessagesManager { this.newMessagesHandlePromise = window.setTimeout(this.handleNewMessages, 0); } } - - this.updateMessageRepliesIfNeeded(message); const dialog = foundDialog[0]; if(dialog) { diff --git a/src/scss/partials/_chatBubble.scss b/src/scss/partials/_chatBubble.scss index 585c1c11..bf46fc50 100644 --- a/src/scss/partials/_chatBubble.scss +++ b/src/scss/partials/_chatBubble.scss @@ -1221,7 +1221,7 @@ $bubble-margin: .25rem; color: #fff; display: flex; align-items: center; - padding: 0 2.5px 0 4px; + padding: 0 2.5px; line-height: 18px; pointer-events: all; // show title white-space: nowrap; @@ -1428,6 +1428,8 @@ $bubble-margin: .25rem; } .replies { + user-select: none; + .rp { width: 100%; height: 100%; @@ -1470,7 +1472,6 @@ $bubble-margin: .25rem; border-bottom-right-radius: inherit; color: $color-blue; min-width: 15rem; - user-select: none; .tgico-comments, .tgico-next { font-size: 1.4375rem;