From b2ddf3dd0a194f51bc07bcb617dc490fcb047339 Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Fri, 14 Feb 2020 12:04:44 +0700 Subject: [PATCH] fix reply unknown messages & reply sticker background & minor css fixes --- src/components/wrappers.ts | 4 +- src/lib/appManagers/appDialogsManager.ts | 7 +- src/lib/appManagers/appImManager.ts | 207 ++++++++++++------- src/lib/appManagers/appMessagesIDsManager.ts | 4 +- src/lib/appManagers/appMessagesManager.ts | 43 ++-- src/lib/utils.js | 2 +- src/scss/partials/_chat.scss | 88 ++++++-- src/scss/style.scss | 4 + tsconfig.json | 2 +- 9 files changed, 240 insertions(+), 121 deletions(-) diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index 5292a6d4..4027b3f1 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -54,7 +54,7 @@ export function wrapVideo(this: any, doc: MTDocument, container: HTMLDivElement, //container.classList.add('video'); let img = container.firstElementChild as HTMLImageElement || new Image(); - img.setAttribute('message-id', '' + message.id); + img.setAttribute('message-id', '' + message.mid); if(!container.contains(img)) { container.append(img); @@ -93,7 +93,7 @@ export function wrapVideo(this: any, doc: MTDocument, container: HTMLDivElement, video.volume = 0; } */ - video.setAttribute('message-id', '' + message.id); + video.setAttribute('message-id', '' + message.mid); let source = document.createElement('source'); //source.src = doc.url; diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 40b0d820..5c2b1327 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -1,6 +1,6 @@ import apiManager from "../mtproto/apiManager"; import apiFileManager from '../mtproto/apiFileManager'; -import { $rootScope, findUpTag, isElementInViewport } from "../utils"; +import { $rootScope, findUpTag, isElementInViewport, langPack } from "../utils"; import appImManager from "./appImManager"; import appPeersManager from './appPeersManager'; import appMessagesManager from "./appMessagesManager"; @@ -314,6 +314,11 @@ export class AppDialogsManager { break; } } + + if(lastMessage.action) { + // @ts-ignore + lastMessageText = langPack[lastMessage.action._]; + } dom.lastMessageSpan.innerHTML = lastMessageText + (lastMessage.message ? RichTextProcessor.wrapRichText(lastMessage.message.replace(/\n/g, ' '), {noLinebreakers: true}) : ''); diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index 5d93ce69..5db55e0f 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -1,5 +1,5 @@ import apiManager from '../mtproto/apiManager'; -import { $rootScope, isElementInViewport, numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, calcImageInBox, findUpTag, getRichValue, getRichValueWithCaret, getSelectedText } from "../utils"; +import { $rootScope, isElementInViewport, numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, calcImageInBox, findUpTag, getRichValue, getRichValueWithCaret, getSelectedText, langPack } from "../utils"; import appUsersManager from "./appUsersManager"; import appMessagesManager from "./appMessagesManager"; import appPeersManager from "./appPeersManager"; @@ -259,6 +259,7 @@ class ChatInput { this.attachMediaPopUp.mediaContainer.innerHTML = ''; this.attachMediaPopUp.mediaContainer.style.width = ''; this.attachMediaPopUp.mediaContainer.style.height = ''; + this.attachMediaPopUp.mediaContainer.classList.remove('is-document'); switch(willAttach) { case 'media': { @@ -295,6 +296,7 @@ class ChatInput { this.attachMediaPopUp.titleEl.innerText = 'Send File'; this.attachMediaPopUp.mediaContainer.append(docDiv); + this.attachMediaPopUp.mediaContainer.classList.add('is-document'); this.attachMediaPopUp.container.classList.add('active'); break; } @@ -465,6 +467,7 @@ export class AppImManager { public dateMessages: {[timestamp: number]: { div: HTMLDivElement, firstTimestamp: number }} = {}; public unreaded: number[] = []; public unreadOut: number[] = []; + public needUpdate: {replyMid: number, mid: number}[] = []; // if need wrapSingleMessage public offline = false; public updateStatusInterval = 0; @@ -628,19 +631,37 @@ export class AppImManager { if(!bubble) return; let message = appMessagesManager.getMessage(mid); - this.renderMessage(message, false, false, bubble); + this.renderMessage(message, false, false, bubble, false); }); $rootScope.$on('messages_downloaded', (e: CustomEvent) => { - let mid = e.detail; + let mids: number[] = e.detail; - if(this.pinnedMsgID == mid) { - let message = appMessagesManager.getMessage(mid); - this.log('setting pinned message', message); - this.pinnedMessageContainer.setAttribute('data-mid', mid); - this.pinnedMessageContainer.style.display = ''; - this.pinnedMessageContent.innerHTML = RichTextProcessor.wrapEmojiText(message.message); - } + mids.forEach(mid => { + if(this.pinnedMsgID == mid) { + let message = appMessagesManager.getMessage(mid); + this.log('setting pinned message', message); + this.pinnedMessageContainer.dataset.mid = '' + mid; + this.pinnedMessageContainer.style.display = ''; + this.pinnedMessageContent.innerHTML = RichTextProcessor.wrapEmojiText(message.message); + } + + let idx = this.needUpdate.findIndex(v => v.replyMid == mid); + if(idx !== -1) { + let {mid, replyMid} = this.needUpdate.splice(idx, 1)[0]; + let bubble = this.bubbles[mid]; + if(!bubble) return; + + let message = appMessagesManager.getMessage(mid); + + let repliedMessage = appMessagesManager.getMessage(replyMid); + if(repliedMessage.deleted) { // чтобы не пыталось бесконечно загрузить удалённое сообщение + delete message.reply_to_mid; // WARNING! + } + + this.renderMessage(message, false, false, bubble, false); + } + }); }); $rootScope.$on('apiUpdate', (e: CustomEvent) => { @@ -1285,6 +1306,7 @@ export class AppImManager { this.unreadOut = []; this.loadMediaQueue = []; this.loadingMedia = 0; + this.needUpdate.length = 0; lottieLoader.checkAnimations(false, 'chat', true); @@ -1344,7 +1366,7 @@ export class AppImManager { this.log('setPeer peerID:', this.peerID, dialog, lastMsgID); appDialogsManager.loadDialogPhoto(this.avatarEl, this.peerID); appDialogsManager.loadDialogPhoto(appSidebarRight.profileElements.avatar, this.peerID); - if(appDialogsManager.lastActiveListElement) { + if(!samePeer && appDialogsManager.lastActiveListElement) { appDialogsManager.lastActiveListElement.classList.remove('active'); } @@ -1483,7 +1505,7 @@ export class AppImManager { }); } - public renderMessage(message: any, reverse = false, multipleRender?: boolean, bubble: HTMLDivElement = null) { + public renderMessage(message: any, reverse = false, multipleRender?: boolean, bubble: HTMLDivElement = null, updatePosition = true) { this.log('message to render:', message); if(message.deleted) return; @@ -1844,6 +1866,16 @@ export class AppImManager { this.log('message to render reply', originalMessage, originalPeerTitle, bubble, message); + // need to download separately + if(originalMessage._ == 'messageEmpty') { + this.log('message to render reply empty, need download'); + if(appMessagesManager.wrapSingleMessage(message.reply_to_mid).loading) { + this.needUpdate.push({replyMid: message.reply_to_mid, mid: message.mid}); + } + + originalPeerTitle = 'Loading...'; + } + let originalText = ''; if(originalMessage.message) { originalText = RichTextProcessor.wrapRichText(originalMessage.message, { @@ -1871,6 +1903,8 @@ export class AppImManager { if(originalMessage.mid) { bubble.setAttribute('data-original-mid', originalMessage.mid); + } else { + bubble.setAttribute('data-original-mid', message.reply_to_mid); } bubble.append(box); @@ -1927,86 +1961,107 @@ export class AppImManager { bubble.append(avatarDiv); } } - - let type = our ? 'out' : 'in'; - let containerDiv = reverse ? this.firstContainerDiv : this.lastContainerDiv; - if(!containerDiv || !containerDiv.classList.contains(type)) { - /* if(containerDiv) { - if(reverse) this.chatInner.prepend(containerDiv); - else this.chatInner.append(containerDiv); - } */ - - containerDiv = document.createElement('div'); - containerDiv.classList.add(type); + if(message._ == 'messageService') { + bubble.className = 'service'; - if(!this.firstContainerDiv) this.firstContainerDiv = containerDiv; + let action = message.action; - if(reverse) this.firstContainerDiv = containerDiv; - else this.lastContainerDiv = containerDiv; + let title = appPeersManager.getPeerTitle(message.fromID); + let name = document.createElement('div'); + name.classList.add('name'); + name.dataset.peerID = message.fromID; + name.innerHTML = title; + + // @ts-ignore + let str = name.outerHTML + ' ' + langPack[action._]; + bubble.innerHTML = `
${str}
`; } - if(reverse) { - if(!multipleRender) { - this.scrollPosition.prepareFor('up'); // лагает из-за этого + if(!multipleRender) { + this.scrollPosition.prepareFor(reverse ? 'up' : 'down'); // лагает из-за этого + } + + if(updatePosition) { + let type = our ? 'out' : 'in'; + let containerDiv = reverse ? this.firstContainerDiv : this.lastContainerDiv; + if(!containerDiv || !containerDiv.classList.contains(type)) { + /* if(containerDiv) { + if(reverse) this.chatInner.prepend(containerDiv); + else this.chatInner.append(containerDiv); + } */ + + containerDiv = document.createElement('div'); + containerDiv.classList.add(type); + + if(!this.firstContainerDiv) this.firstContainerDiv = containerDiv; + + if(reverse) this.firstContainerDiv = containerDiv; + else this.lastContainerDiv = containerDiv; } - - containerDiv.prepend(bubble); - this.chatInner.prepend(containerDiv); - } else { - if(!multipleRender) { - this.scrollPosition.prepareFor('down'); // лагает из-за этого + + if(reverse) { + /* if(!multipleRender) { + this.scrollPosition.prepareFor('up'); // лагает из-за этого + } */ + + containerDiv.prepend(bubble); + this.chatInner.prepend(containerDiv); + } else { + /* if(!multipleRender) { + this.scrollPosition.prepareFor('down'); // лагает из-за этого + } */ + + containerDiv.append(bubble); + this.chatInner.append(containerDiv); } - containerDiv.append(bubble); - this.chatInner.append(containerDiv); - } - - /* if(bubble.classList.contains('webpage')) { - this.log('night running', bubble, bubble.scrollHeight); - } */ + let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); + let dateTimestamp = justDate.getTime(); + if(!(dateTimestamp in this.dateMessages)) { + let str = ''; - //return //this.scrollPosition.restore(); + let today = new Date(); + today.setHours(0); + today.setMinutes(0); + today.setSeconds(0); - let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); - let dateTimestamp = justDate.getTime(); - if(!(dateTimestamp in this.dateMessages)) { - let str = ''; + if(today < date) { + str = 'Today'; + } else { + const months = ['January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December']; + str = justDate.getFullYear() == new Date().getFullYear() ? + months[justDate.getMonth()] + ' ' + justDate.getDate() : + justDate.toISOString().split('T')[0].split('-').reverse().join('.'); + } - let today = new Date(); - today.setHours(0); - today.setMinutes(0); - today.setSeconds(0); + let div = document.createElement('div'); + div.classList.add('service'); + div.innerHTML = `
${str}
`; + this.log('need to render date message', dateTimestamp, str); + + this.dateMessages[dateTimestamp] = { + div, + firstTimestamp: date.getTime() + }; - if(today < date) { - str = 'Today'; + //this.chatInner.insertBefore(div, containerDiv); + containerDiv.insertBefore(div, bubble); } else { - const months = ['January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', 'November', 'December']; - str = justDate.getFullYear() == new Date().getFullYear() ? - months[justDate.getMonth()] + ' ' + justDate.getDate() : - justDate.toISOString().split('T')[0].split('-').reverse().join('.'); + let dateMessage = this.dateMessages[dateTimestamp]; + if(dateMessage.firstTimestamp > date.getTime()) { + //this.chatInner.insertBefore(dateMessage.div, containerDiv); + containerDiv.insertBefore(dateMessage.div, bubble); + } } + } - let div = document.createElement('div'); - div.classList.add('service'); - div.innerHTML = `
${str}
`; - this.log('need to render date message', dateTimestamp, str); - - this.dateMessages[dateTimestamp] = { - div, - firstTimestamp: date.getTime() - }; + /* if(bubble.classList.contains('webpage')) { + this.log('night running', bubble, bubble.scrollHeight); + } */ - //this.chatInner.insertBefore(div, containerDiv); - containerDiv.insertBefore(div, bubble); - } else { - let dateMessage = this.dateMessages[dateTimestamp]; - if(dateMessage.firstTimestamp > date.getTime()) { - //this.chatInner.insertBefore(dateMessage.div, containerDiv); - containerDiv.insertBefore(dateMessage.div, bubble); - } - } + //return //this.scrollPosition.restore(); if(!multipleRender) { this.scrollPosition.restore(); // лагает из-за этого diff --git a/src/lib/appManagers/appMessagesIDsManager.ts b/src/lib/appManagers/appMessagesIDsManager.ts index f8f59f23..441eee72 100644 --- a/src/lib/appManagers/appMessagesIDsManager.ts +++ b/src/lib/appManagers/appMessagesIDsManager.ts @@ -37,8 +37,8 @@ export class AppMessagesIDsManager { } public splitMessageIDsByChannels (mids: any[]) { - var msgIDsByChannels: any = {}; - var midsByChannels: any = {}; + var msgIDsByChannels: {[channelID: number]: number[]} = {}; + var midsByChannels: {[channelID: number]: number[]} = {}; var i; var mid, msgChannel; var channelID; diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index e32e83bf..558e8eed 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -3206,7 +3206,7 @@ export class AppMessagesManager { }); } - public wrapForDialog(msgID: number, dialog?: any) { + /* public wrapForDialog(msgID: number, dialog?: any) { var useCache = msgID && dialog !== undefined; var unreadCount = dialog && dialog.unread_count; @@ -3255,7 +3255,7 @@ export class AppMessagesManager { } return message; - } + } */ public fetchSingleMessages() { if(this.fetchSingleMessagesPromise) { @@ -3263,20 +3263,21 @@ export class AppMessagesManager { } var mids = this.needSingleMessages.slice(); - this.needSingleMessages = []; + this.needSingleMessages.length = 0; var splitted = appMessagesIDsManager.splitMessageIDsByChannels(mids); let promises: Promise[] = []; Object.keys(splitted.msgIDs).forEach((channelID: number | string) => { - let msgIDs = splitted.msgIDs[channelID].map((mid: number) => { + channelID = +channelID; + + let msgIDs = splitted.msgIDs[channelID].map((msgID: number) => { return { _: 'inputMessageID', - id: mid + id: msgID }; }); var promise; - channelID = +channelID; if(channelID > 0) { promise = apiManager.invokeApi('channels.getMessages', { channel: appChatsManager.getChannelInput(channelID), @@ -3293,43 +3294,39 @@ export class AppMessagesManager { appChatsManager.saveApiChats(getMessagesResult.chats); this.saveMessages(getMessagesResult.messages); - $rootScope.$broadcast('messages_downloaded', splitted.mids[channelID]) + $rootScope.$broadcast('messages_downloaded', splitted.mids[+channelID]); })); }); return this.fetchSingleMessagesPromise = Promise.all(promises).then(() => { + this.fetchSingleMessagesTimeout = 0; this.fetchSingleMessagesPromise = null; if(this.needSingleMessages.length) this.fetchSingleMessages(); }).catch(() => { + this.fetchSingleMessagesTimeout = 0; this.fetchSingleMessagesPromise = null; if(this.needSingleMessages.length) this.fetchSingleMessages(); }); } - /* public wrapSingleMessage(msgID: number) { + public wrapSingleMessage(msgID: number) { if(this.messagesStorage[msgID]) { - return this.wrapForDialog(msgID); + //let ret = this.wrapForDialog(msgID); // hm + $rootScope.$broadcast('messages_downloaded', [msgID]); + //return ret; + return {mid: msgID, loading: false}; } if(this.needSingleMessages.indexOf(msgID) == -1) { this.needSingleMessages.push(msgID); if(this.fetchSingleMessagesTimeout == 0) { - this.fetchSingleMessagesTimeout = window.setTimeout(this.fetchSingleMessages.bind(this), 100); + this.fetchSingleMessagesTimeout = window.setTimeout(this.fetchSingleMessages.bind(this), 25); } - } - return {mid: msgID, loading: true}; - } */ - public wrapSingleMessage(msgID: number) { - if(this.messagesStorage[msgID]) { - $rootScope.$broadcast('messages_downloaded', msgID); - return; - } - - if(this.needSingleMessages.indexOf(msgID) == -1) { - this.needSingleMessages.push(msgID); - this.fetchSingleMessages(); - } + return {mid: msgID, loading: true}; + } + + return {mid: msgID, loading: false}; } } diff --git a/src/lib/utils.js b/src/lib/utils.js index 4be362f3..ab6e275e 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -324,11 +324,11 @@ export const langPack = { "messageActionChatLeave": "left group", "messageActionChatDeleteUser": "removed user", "messageActionChatJoinedByLink": "joined the group", + "messageActionPinMessage": "pinned message", "messageActionChannelCreate": "Channel created", "messageActionChannelEditTitle": "Channel renamed", "messageActionChannelEditPhoto": "Channel photo updated", "messageActionChannelDeletePhoto": "Channel photo removed", - "messageActionPinMessage": "pinned message", "messageActionPhoneCall.in_ok": "Incoming Call", "messageActionPhoneCall.out_ok": "Outgoing Call", diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss index a18cb806..f5b4a628 100644 --- a/src/scss/partials/_chat.scss +++ b/src/scss/partials/_chat.scss @@ -178,9 +178,8 @@ } .service { - justify-content: center; - align-self: center; margin: 1rem 0; + align-self: center; .service-msg { color: #fff; @@ -190,6 +189,14 @@ font-size: 15px; border-radius: 12px; user-select: none; + display: flex; + align-items: center; + justify-content: center; + + .name { + cursor: pointer; + margin-right: 5px; + } } } @@ -487,6 +494,20 @@ cursor: pointer; } } + + &.is-reply { + &.emoji-big, &.sticker { + .box { + padding: 10px; + border-radius: 12px; + border: 1px solid #ccc; + max-width: 300px; + white-space: nowrap; + position: absolute; + top: 0; + } + } + } .message { font-size: 16px; @@ -542,7 +563,7 @@ position: absolute; bottom: 0; right: 0; - font-size: .75rem; + font-size: 12px; display: flex; align-items: center; line-height: 1; @@ -571,6 +592,20 @@ &.is-edited .time { width: 90px; } + + .message.message-empty .time { + padding: 0; + display: flex; + align-items: center; + width: auto; + + .inner { + margin-bottom: 0; + position: relative; + padding: 0 2.5px; + bottom: 0; + } + } .user-avatar { position: absolute; @@ -658,6 +693,15 @@ .box:hover { background-color: $light; } + + .bubble.is-reply { + &.emoji-big, &.sticker { + .box { + left: calc(100% + 10px); + background-color: #fff; + } + } + } .quote { border-left: 2px $darkblue solid; @@ -673,11 +717,11 @@ } .time { - color: rgba($darkgrey, 0.6); - width: 2rem; + color: #a3adb6; + width: 36px; .inner { - padding: 0 .35rem; + padding: 0 7px 0 5px; margin-bottom: 4px; } } @@ -705,8 +749,8 @@ } &.forwarded .attachment, - &.is-reply .attachment, - &:not(.hide-name):not(.sticker) .attachment { + &.is-reply .attachment/* , + &:not(.hide-name):not(.sticker) .attachment */ { border-top-left-radius: 0; border-top-right-radius: 0; } @@ -723,6 +767,16 @@ .box:hover { background-color: rgba($green, 0.12); } + + .bubble.is-reply { + &.emoji-big, &.sticker { + .box { + background-color: #eeffde; + right: calc(100% + 10px); + border-color: rgba($green, .12); + } + } + } .quote { border-left: 2px $darkgreen solid; @@ -734,20 +788,20 @@ .time { color: $darkgreen; - width: 48px; + width: 50px; display: inline-block; .inner { - padding: 0 .25rem; + padding: 0 4px 0 4px; bottom: 1px; } } .bubble { .time .tgico:after { - font-size: 1.1rem; + font-size: 19px; vertical-align: middle; - margin-left: .1rem; + margin-left: 1px; } } @@ -901,6 +955,12 @@ background-image: url('../../assets/img/msg-tail-left.svg'); transform: scaleX(-1); } + + #attach-file { + &.menu-open { + color: $blue; + } + } > div { display: flex; @@ -950,7 +1010,7 @@ color: $placeholder-color; font-size: 1.5rem; line-height: 1.5rem; - + transition: .2s color; flex: 0 0 auto; &.active { @@ -1307,8 +1367,6 @@ .popup { &.popup-delete-message { - - .popup-header { margin-bottom: 1rem; } diff --git a/src/scss/style.scss b/src/scss/style.scss index 24ac6102..f82cc5b9 100644 --- a/src/scss/style.scss +++ b/src/scss/style.scss @@ -1385,6 +1385,10 @@ div.scrollable::-webkit-scrollbar-thumb { margin: 0 auto; /* align-items: center; */ + &.is-document { + margin-left: 0; + } + .document { max-width: 100%; overflow: hidden; diff --git a/tsconfig.json b/tsconfig.json index a8858639..83a369f9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -65,8 +65,8 @@ "node_modules", "public", "coverage", + "./src/lib/StackBlur.js", "./src/lib/*.js", - "src/lib/StackBlur.js", "./src/*.js", "*.js", ]