From bdc48512107ac0c07215aa8eec001237a3925a60 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Tue, 1 Jun 2021 18:20:03 +0300 Subject: [PATCH] Avatar stripped thumbnails Render avatar thumb if have queue --- src/components/avatar.ts | 29 ++++++++---- src/helpers/dom/renderImageFromUrl.ts | 7 +-- src/lib/appManagers/appProfileManager.ts | 60 ++++++++++++++---------- src/scss/partials/_avatar.scss | 10 ++++ 4 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/components/avatar.ts b/src/components/avatar.ts index bc674d09..dba60847 100644 --- a/src/components/avatar.ts +++ b/src/components/avatar.ts @@ -179,6 +179,22 @@ export default class AvatarElement extends HTMLElement { } } + private r(onlyThumb = false) { + const res = appProfileManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle, onlyThumb); + const promise = res ? res.loadPromise : Promise.resolve(); + if(this.loadPromises) { + if(res && res.cached) { + this.loadPromises.push(promise); + } + + promise.finally(() => { + this.loadPromises = undefined; + }); + } + + return res; + } + public update() { if(this.lazyLoadQueue) { if(!seen.has(this.peerId)) { @@ -193,6 +209,8 @@ export default class AvatarElement extends HTMLElement { set.add(this); + this.r(true); + this.lazyLoadQueue.push({ div: this, load: () => { @@ -209,17 +227,8 @@ export default class AvatarElement extends HTMLElement { seen.add(this.peerId); - const res = appProfileManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle); + const res = this.r(); const promise = res ? res.loadPromise : Promise.resolve(); - if(this.loadPromises) { - if(res && res.cached) { - this.loadPromises.push(promise); - } - - promise.finally(() => { - this.loadPromises = undefined; - }); - } if(this.addedToQueue) { promise.finally(() => { diff --git a/src/helpers/dom/renderImageFromUrl.ts b/src/helpers/dom/renderImageFromUrl.ts index 8d840956..1c7f3f72 100644 --- a/src/helpers/dom/renderImageFromUrl.ts +++ b/src/helpers/dom/renderImageFromUrl.ts @@ -12,11 +12,11 @@ const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoE }; // проблема функции в том, что она не подходит для ссылок, пригодна только для blob'ов, потому что обычным ссылкам нужен 'load' каждый раз. -export default function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string, callback?: (err?: Event) => void, useCache = true): boolean { +export default async function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string, callback?: (err?: Event) => void, useCache = true) { if(!url) { console.error('renderImageFromUrl: no url?', elem, url); callback && callback(); - return false; + return; } if(((loadedURLs[url]/* && false */) && useCache) || elem instanceof HTMLVideoElement) { @@ -25,7 +25,6 @@ export default function renderImageFromUrl(elem: HTMLElement | HTMLImageElement } callback && callback(); - return true; } else { const isImage = elem instanceof HTMLImageElement; const loader = isImage ? elem as HTMLImageElement : new Image(); @@ -53,7 +52,5 @@ export default function renderImageFromUrl(elem: HTMLElement | HTMLImageElement if(callback) { loader.addEventListener('error', callback); } - - return false; } } diff --git a/src/lib/appManagers/appProfileManager.ts b/src/lib/appManagers/appProfileManager.ts index 7d2fdaa8..6069d3b2 100644 --- a/src/lib/appManagers/appProfileManager.ts +++ b/src/lib/appManagers/appProfileManager.ts @@ -512,9 +512,10 @@ export class AppProfileManager { return {cached, loadPromise: getAvatarPromise}; } - public putAvatar(div: HTMLElement, peerId: number, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize, img = new Image()) { - const {cached, loadPromise} = this.loadAvatar(peerId, photo, size); + public putAvatar(div: HTMLElement, peerId: number, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize, img = new Image(), onlyThumb = false) { + let {cached, loadPromise} = this.loadAvatar(peerId, photo, size); + let renderThumbPromise: Promise; let callback: () => void; if(cached) { // смотри в misc.ts: renderImageFromUrl @@ -528,41 +529,52 @@ export class AppProfileManager { img.classList.add('fade-in'); } + let thumbImage: HTMLImageElement; + if(photo.stripped_thumb) { + thumbImage = new Image(); + div.classList.add('avatar-relative'); + thumbImage.classList.add('avatar-photo', 'avatar-photo-thumbnail'); + img.classList.add('avatar-photo'); + const url = appPhotosManager.getPreviewURLFromBytes(photo.stripped_thumb); + renderThumbPromise = renderImageFromUrl(thumbImage, url).then(() => { + replaceContent(div, thumbImage); + }); + } + callback = () => { - replaceContent(div, img); + if(photo.stripped_thumb) { + div.append(img); + } else { + replaceContent(div, img); + } setTimeout(() => { if(div.childElementCount) { - div.dataset.color = ''; - - if(animate) { - sequentialDom.mutateElement(img, () => { + sequentialDom.mutateElement(img, () => { + div.dataset.color = ''; + + if(animate) { img.classList.remove('fade-in'); - }); - } + } + + if(thumbImage) { + thumbImage.remove(); + } + }); } }, animate ? 200 : 0); }; } - const renderPromise = loadPromise.then((url) => { - /* if(photo.stripped_thumb) { - url = appPhotosManager.getPreviewURLFromBytes(photo.stripped_thumb); - } */ - - return new Promise((resolve) => { - renderImageFromUrl(img, url, () => { - callback(); - resolve(); - }/* , false */); - }); - }); + const renderPromise = loadPromise + .then((url) => renderImageFromUrl(img, url/* , false */)) + .then(() => callback()); - return {cached, loadPromise: renderPromise}; + return {cached, loadPromise: renderThumbPromise || renderPromise}; } // peerId === peerId || title - public putPhoto(div: HTMLElement, peerId: number, isDialog = false, title = '') { + public putPhoto(div: HTMLElement, peerId: number, isDialog = false, title = '', onlyThumb = false) { const photo = appPeersManager.getPeerPhoto(peerId); const size: PeerPhotoSize = 'photo_small'; @@ -614,7 +626,7 @@ export class AppProfileManager { } if(avatarAvailable/* && false */) { - return this.putAvatar(div, peerId, photo, size); + return this.putAvatar(div, peerId, photo, size, undefined, onlyThumb); } } } diff --git a/src/scss/partials/_avatar.scss b/src/scss/partials/_avatar.scss index 360166e7..c940c305 100644 --- a/src/scss/partials/_avatar.scss +++ b/src/scss/partials/_avatar.scss @@ -124,6 +124,10 @@ avatar-element { cursor: pointer; } + &.avatar-relative { + position: relative; + } + /* &.avatar-54 { width: 54px; height: 54px; @@ -198,3 +202,9 @@ avatar-element { --multiplier: 3.375; } } + +.avatar-photo { + position: absolute; + top: 0; + left: 0; +}