From cc92edeb2698782bd5eeb408b668e892c02a86c5 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Tue, 19 Jan 2021 18:35:23 +0400 Subject: [PATCH] Fix blinking avatars in chat, replies footer --- src/components/avatar.ts | 33 ++++++----- src/components/chat/bubbles.ts | 6 +- src/components/chat/messageRender.ts | 7 ++- src/components/chat/replies.ts | 85 ++++++++++++++++++++++++---- src/scss/partials/_avatar.scss | 1 - 5 files changed, 102 insertions(+), 30 deletions(-) diff --git a/src/components/avatar.ts b/src/components/avatar.ts index 6a13a658..2f575cce 100644 --- a/src/components/avatar.ts +++ b/src/components/avatar.ts @@ -4,7 +4,7 @@ import rootScope from "../lib/rootScope"; import { attachClickEvent, cancelEvent } from "../helpers/dom"; import AppMediaViewer, { AppMediaViewerAvatar } from "./appMediaViewer"; import { Photo } from "../layer"; -import type { LazyLoadQueueIntersector } from "./lazyLoadQueue"; +//import type { LazyLoadQueueIntersector } from "./lazyLoadQueue"; rootScope.on('avatar_update', (e) => { let peerId = e; @@ -20,8 +20,9 @@ export default class AvatarElement extends HTMLElement { private peerId: number; private isDialog = false; public peerTitle: string; - public lazyLoadQueue: LazyLoadQueueIntersector; - private addedToQueue = false; + public loadPromises: Promise[]; + //public lazyLoadQueue: LazyLoadQueueIntersector; + //private addedToQueue = false; constructor() { super(); @@ -105,13 +106,13 @@ export default class AvatarElement extends HTMLElement { } } - disconnectedCallback() { + /* disconnectedCallback() { // браузер вызывает этот метод при удалении элемента из документа // (может вызываться много раз, если элемент многократно добавляется/удаляется) if(this.lazyLoadQueue) { this.lazyLoadQueue.unobserve(this); } - } + } */ static get observedAttributes(): string[] { return ['peer', 'dialog', 'peer-title'/* массив имён атрибутов для отслеживания их изменений */]; @@ -120,22 +121,22 @@ export default class AvatarElement extends HTMLElement { attributeChangedCallback(name: string, oldValue: string, newValue: string) { //console.log('avatar changed attribute:', name, oldValue, newValue); // вызывается при изменении одного из перечисленных выше атрибутов - if(name == 'peer') { - if(this.peerId == +newValue) { + if(name === 'peer') { + if(this.peerId === +newValue) { return; } this.peerId = +newValue; this.update(); - } else if(name == 'peer-title') { + } else if(name === 'peer-title') { this.peerTitle = newValue; - } else if(name == 'dialog') { + } else if(name === 'dialog') { this.isDialog = !!+newValue; } } public update() { - if(this.lazyLoadQueue) { + /* if(this.lazyLoadQueue) { if(this.addedToQueue) return; this.lazyLoadQueue.push({ div: this, @@ -146,9 +147,15 @@ export default class AvatarElement extends HTMLElement { } }); this.addedToQueue = true; - } else { - appProfileManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle); - } + } else { */ + const res = appProfileManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle); + if(this.loadPromises && res && res.cached) { + this.loadPromises.push(res.loadPromise); + res.loadPromise.finally(() => { + this.loadPromises = undefined; + }); + } + //} } } diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index aca153ff..83b606cd 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -2256,13 +2256,14 @@ export default class ChatBubbles { let avatarElem = new AvatarElement(); //avatarElem.lazyLoadQueue = this.lazyLoadQueue; avatarElem.classList.add('user-avatar', 'avatar-40'); + avatarElem.loadPromises = loadPromises; if(!message.fwdFromId && message.fwd_from && message.fwd_from.from_name) { avatarElem.setAttribute('peer-title', /* '🔥 FF 🔥' */message.fwd_from.from_name); } avatarElem.setAttribute('peer', '' + (((message.fwd_from && (this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID)) || isForwardFromChannel ? message.fwdFromId : message.fromId) || 0)); - avatarElem.update(); + //avatarElem.update(); //this.log('exec loadDialogPhoto', message); @@ -2305,7 +2306,8 @@ export default class ChatBubbles { bubble, bubbleContainer, message: messageWithReplies, - messageDiv + messageDiv, + loadPromises }); if(isFooter) { diff --git a/src/components/chat/messageRender.ts b/src/components/chat/messageRender.ts index fdf7c579..920d9891 100644 --- a/src/components/chat/messageRender.ts +++ b/src/components/chat/messageRender.ts @@ -58,16 +58,19 @@ export namespace MessageRender { return timeSpan; }; - export const renderReplies = ({bubble, bubbleContainer, message, messageDiv}: { + export const renderReplies = ({bubble, bubbleContainer, message, messageDiv, loadPromises}: { bubble: HTMLElement, bubbleContainer: HTMLElement, message: any, - messageDiv: HTMLElement + messageDiv: HTMLElement, + loadPromises?: Promise[] }) => { const isFooter = !bubble.classList.contains('sticker') && !bubble.classList.contains('emoji-big') && !bubble.classList.contains('round'); const repliesFooter = new RepliesElement(); repliesFooter.message = message; repliesFooter.type = isFooter ? 'footer' : 'beside'; + repliesFooter.loadPromises = loadPromises; + repliesFooter.init(); bubbleContainer.prepend(repliesFooter); return isFooter; }; diff --git a/src/components/chat/replies.ts b/src/components/chat/replies.ts index d3cc9957..a129d4a4 100644 --- a/src/components/chat/replies.ts +++ b/src/components/chat/replies.ts @@ -4,6 +4,7 @@ import appMessagesManager from "../../lib/appManagers/appMessagesManager"; import appPeersManager from "../../lib/appManagers/appPeersManager"; import rootScope from "../../lib/rootScope"; import { ripple } from "../ripple"; +import AvatarElement from "../avatar"; const TAG_NAME = 'replies-element'; @@ -18,6 +19,7 @@ rootScope.on('replies_updated', (e) => { export default class RepliesElement extends HTMLElement { public message: Message.message; public type: 'footer' | 'beside'; + public loadPromises: Promise[]; private updated = false; @@ -25,7 +27,7 @@ export default class RepliesElement extends HTMLElement { super(); } - connectedCallback() { + public init() { this.render(); this.dataset.postKey = this.message.peerId + '_' + this.message.mid; this.classList.add('replies', 'replies-' + this.type); @@ -34,17 +36,62 @@ export default class RepliesElement extends HTMLElement { public render() { const replies = this.message.replies; + /* if(this.firstChild) { + this.innerHTML = ''; + } */ + if(this.type === 'footer') { - let leftHTML = ''; + let leftPart: HTMLElement; + if(this.firstElementChild) { + leftPart = this.firstElementChild as HTMLElement; + } + if(replies?.recent_repliers) { - leftHTML += ''; + + // if were 3 and became 2 + (Array.from(leftPart.children) as HTMLElement[]).slice(replies.recent_repliers.length).forEach(el => el.remove()); } else { - leftHTML = ''; + if(leftPart && !leftPart.classList.contains('tgico-comments')) { + leftPart.remove(); + leftPart = null; + } + + if(!leftPart) { + leftPart = document.createElement('span'); + leftPart.classList.add('tgico-comments'); + } + } + + if(!leftPart.parentElement) { + this.append(leftPart); } let text: string; @@ -63,11 +110,21 @@ export default class RepliesElement extends HTMLElement { this.classList.toggle('is-unread', replies.read_max_id < replies.max_id && (!historyStorage.readMaxId || historyStorage.readMaxId < replies.max_id)); } - this.innerHTML = `${leftHTML}${text}`; + let textSpan = this.children[1] as HTMLElement; + if(!textSpan) { + textSpan = document.createElement('span'); + textSpan.classList.add('replies-footer-text'); + + const iconSpan = document.createElement('span'); + iconSpan.classList.add('tgico-next'); + + const rippleContainer = document.createElement('div'); + ripple(rippleContainer); - const rippleContainer = document.createElement('div'); - this.append(rippleContainer); - ripple(rippleContainer); + this.append(textSpan, iconSpan, rippleContainer); + } + + textSpan.innerHTML = text; } else { this.classList.add('bubble-beside-button'); this.innerHTML = `${replies?.replies ? formatNumber(replies.replies, 0) : ''}`; @@ -78,6 +135,10 @@ export default class RepliesElement extends HTMLElement { appMessagesManager.updateMessage(this.message.peerId, this.message.mid, 'replies_updated'); this.updated = true; } + + if(this.loadPromises) { + this.loadPromises = undefined; + } } } diff --git a/src/scss/partials/_avatar.scss b/src/scss/partials/_avatar.scss index 509ae797..6f505e08 100644 --- a/src/scss/partials/_avatar.scss +++ b/src/scss/partials/_avatar.scss @@ -66,7 +66,6 @@ avatar-element { width: 100%; height: 100%; border-radius: inherit; - user-select: none; &.fade-in { animation: fade-in-opacity .2s ease forwards;