From 513ed97988800b315fca130146e310b1e36426cf Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Thu, 10 Feb 2022 21:19:47 +0400 Subject: [PATCH] Larger reactions --- src/components/chat/reaction.ts | 23 ++++++------- src/components/wrappers.ts | 56 ++++++++++++++++++++++++-------- src/helpers/sequentialDom.ts | 9 +++-- src/scss/partials/_reaction.scss | 48 +++++++++++++++++++-------- 4 files changed, 96 insertions(+), 40 deletions(-) diff --git a/src/components/chat/reaction.ts b/src/components/chat/reaction.ts index 8f9a110e..9d5e8b86 100644 --- a/src/components/chat/reaction.ts +++ b/src/components/chat/reaction.ts @@ -17,7 +17,7 @@ import { wrapSticker, wrapStickerAnimation } from "../wrappers"; const CLASS_NAME = 'reaction'; const TAG_NAME = CLASS_NAME + '-element'; const REACTION_INLINE_SIZE = 14; -const REACTION_BLOCK_SIZE = 16; +const REACTION_BLOCK_SIZE = 22; export const REACTION_DISPLAY_INLINE_COUNTER_AT = 2; export const REACTION_DISPLAY_BLOCK_COUNTER_AT = 4; @@ -73,9 +73,10 @@ export default class ReactionElement extends HTMLElement { const size = this.type === 'inline' ? REACTION_INLINE_SIZE : REACTION_BLOCK_SIZE; wrapSticker({ div: this.stickerContainer, - doc: availableReaction.static_icon, + doc: availableReaction.center_icon, width: size, - height: size + height: size, + static: true }); }); } @@ -120,7 +121,7 @@ export default class ReactionElement extends HTMLElement { if(!this.stackedAvatars) { this.stackedAvatars = new StackedAvatars({ - avatarSize: 16 + avatarSize: 24 }); this.append(this.stackedAvatars.container); @@ -139,7 +140,7 @@ export default class ReactionElement extends HTMLElement { public fireAroundAnimation() { callbackify(appReactionsManager.getReaction(this.reactionCount.reaction), (availableReaction) => { - const size = (this.type === 'inline' ? REACTION_INLINE_SIZE : REACTION_BLOCK_SIZE) + 14; + const size = this.type === 'inline' ? REACTION_INLINE_SIZE + 14 : REACTION_BLOCK_SIZE + 18; const div = document.createElement('div'); div.classList.add(CLASS_NAME + '-sticker-activate'); @@ -165,17 +166,17 @@ export default class ReactionElement extends HTMLElement { skipRatio: 1, play: false }).stickerPromise - ]).then(([activatePlayer, aroundPlayer]) => { - activatePlayer.addEventListener('enterFrame', (frameNo) => { - if(frameNo === activatePlayer.maxFrame) { - activatePlayer.remove(); + ]).then(([iconPlayer, aroundPlayer]) => { + iconPlayer.addEventListener('enterFrame', (frameNo) => { + if(frameNo === iconPlayer.maxFrame) { + iconPlayer.remove(); div.remove(); } }); - activatePlayer.addEventListener('firstFrame', () => { + iconPlayer.addEventListener('firstFrame', () => { this.stickerContainer.prepend(div); - activatePlayer.play(); + iconPlayer.play(); aroundPlayer.play(); }, {once: true}); }); diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index 2ab0399c..b012f4d4 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -1222,7 +1222,7 @@ export function wrapStickerAnimation({ return {animationDiv, stickerPromise}; } -export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn, needUpscale, skipRatio}: { +export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn, needUpscale, skipRatio, static: asStatic}: { doc: MyDocument, div: HTMLElement, middleware?: () => boolean, @@ -1238,9 +1238,13 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o loadPromises?: Promise[], needFadeIn?: boolean, needUpscale?: boolean, - skipRatio?: number + skipRatio?: number, + static?: boolean }): Promise { const stickerType = doc.sticker; + if(stickerType === 1) { + asStatic = true; + } if(!width) { width = !emoji ? 200 : undefined; @@ -1293,14 +1297,32 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o //console.log('wrap sticker', doc, div, onlyThumb); - const cacheContext = appDownloadManager.getCacheContext(doc); + let cacheContext: ThumbCache; + if(asStatic && stickerType !== 1) { + const thumb = appPhotosManager.choosePhotoSize(doc, width, height, false) as PhotoSize.photoSize; + cacheContext = appDownloadManager.getCacheContext(doc, thumb.type); + } else { + cacheContext = appDownloadManager.getCacheContext(doc); + } const toneIndex = emoji ? getEmojiToneIndex(emoji) : -1; const downloaded = cacheContext.downloaded && !needFadeIn; + + const isAnimated = !asStatic && (stickerType === 2 || stickerType === 3); + const isThumbNeededForType = isAnimated; let loadThumbPromise = deferredPromise(); let haveThumbCached = false; - if((doc.thumbs?.length || doc.stickerCachedThumbs) && !div.firstElementChild && (!downloaded || stickerType === 2 || stickerType === 3 || onlyThumb) && withThumb !== false/* && doc.thumbs[0]._ !== 'photoSizeEmpty' */) { + if(( + doc.thumbs?.length || + doc.stickerCachedThumbs + ) && + !div.firstElementChild && ( + !downloaded || + isThumbNeededForType || + onlyThumb + ) && withThumb !== false/* && doc.thumbs[0]._ !== 'photoSizeEmpty' */ + ) { let thumb = doc.stickerCachedThumbs && doc.stickerCachedThumbs[toneIndex] || doc.thumbs[0]; //console.log('wrap sticker', thumb, div); @@ -1395,7 +1417,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o const load = async() => { if(middleware && !middleware()) return; - if(stickerType === 2) { + if(stickerType === 2 && !asStatic) { /* if(doc.id === '1860749763008266301') { console.log('loaded sticker:', doc, div); } */ @@ -1588,9 +1610,9 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o }); //console.timeEnd('render sticker' + doc.id); - } else if(stickerType === 1 || stickerType === 3) { + } else if(asStatic || stickerType === 3) { let media: HTMLElement; - if(stickerType === 1) { + if(asStatic) { media = new Image(); } else { media = document.createElement('video'); @@ -1605,7 +1627,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o const thumbImage = div.firstElementChild !== media && div.firstElementChild; if(needFadeIn !== false) { - needFadeIn = (needFadeIn || !downloaded || (stickerType === 1 ? thumbImage : (!thumbImage || thumbImage.tagName === 'svg'))) && rootScope.settings.animationsEnabled; + needFadeIn = (needFadeIn || !downloaded || (asStatic ? thumbImage : (!thumbImage || thumbImage.tagName === 'svg'))) && rootScope.settings.animationsEnabled; } media.classList.add('media-sticker'); @@ -1654,27 +1676,35 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o }); }; - if(stickerType === 1) { + if(asStatic) { renderImageFromUrl(media, cacheContext.url, onLoad); } else { (media as HTMLVideoElement).src = cacheContext.url; onMediaLoad(media as HTMLVideoElement).then(onLoad); } }; - + if(cacheContext.url) r(); else { - appDocsManager.downloadDoc(doc, /* undefined, */lazyLoadQueue?.queueId).then(r, resolve); + let promise: Promise; + if(stickerType === 2 && asStatic) { + const thumb = appPhotosManager.choosePhotoSize(doc, width, height, false) as PhotoSize.photoSize; + promise = appDocsManager.getThumbURL(doc, thumb).promise + } else { + promise = appDocsManager.downloadDoc(doc, /* undefined, */lazyLoadQueue?.queueId); + } + + promise.then(r, resolve); } }); } }; - const loadPromise: Promise = lazyLoadQueue && (!downloaded || stickerType === 2 || stickerType === 3) ? + const loadPromise: Promise = lazyLoadQueue && (!downloaded || isAnimated) ? (lazyLoadQueue.push({div, load}), Promise.resolve()) : load(); - if(downloaded && (stickerType === 1/* || stickerType === 3 */)) { + if(downloaded && (asStatic/* || stickerType === 3 */)) { loadThumbPromise = loadPromise as any; if(loadPromises) { loadPromises.push(loadThumbPromise); diff --git a/src/helpers/sequentialDom.ts b/src/helpers/sequentialDom.ts index bc612deb..fef80c6f 100644 --- a/src/helpers/sequentialDom.ts +++ b/src/helpers/sequentialDom.ts @@ -45,10 +45,15 @@ class SequentialDom { * @param callback */ public mutateElement(element: HTMLElement, callback?: VoidFunction) { - const promise = isInDOM(element) ? this.mutate() : Promise.resolve(); + const isConnected = isInDOM(element); + const promise = isConnected ? this.mutate() : Promise.resolve(); if(callback !== undefined) { - promise.then(() => callback()); + if(isConnected) { + callback(); + } else { + promise.then(() => callback()); + } } return promise; diff --git a/src/scss/partials/_reaction.scss b/src/scss/partials/_reaction.scss index 02427810..8073bf0a 100644 --- a/src/scss/partials/_reaction.scss +++ b/src/scss/partials/_reaction.scss @@ -28,15 +28,16 @@ position: relative; width: var(--reaction-size); height: var(--reaction-size); - + display: flex; + align-items: center; + justify-content: center; + &-activate { - --offset: -.4375rem; - // --offset: 0; position: absolute; - top: var(--offset); - right: var(--offset); - bottom: var(--offset); - left: var(--offset); + top: var(--reaction-offset); + right: var(--reaction-offset); + bottom: var(--reaction-offset); + left: var(--reaction-offset); // animation: reaction-activate 2s linear forwards; & + .media-sticker { @@ -47,6 +48,7 @@ &-inline { --reaction-size: .875rem; + --reaction-offset: -.4375rem; min-width: var(--reaction-size); min-height: var(--reaction-size); } @@ -58,10 +60,12 @@ } &-block { - --additional-height: .625rem; - --margin: .25rem; + --additional-height: .5rem; + // --padding-horizontal: .5rem; + --margin: .375rem; // --reaction-size: 1.0625rem; - --reaction-size: 1rem; + --reaction-size: 1.375rem; + --reaction-offset: -.5625rem; --background-color: var(--message-highlightning-color); --chosen-background-color: var(--message-primary-color); --counter-color: #fff; @@ -69,6 +73,8 @@ height: var(--reaction-total-size); border-radius: var(--reaction-total-size); // padding: 0 .375rem 0 .625rem; + // padding: 0 var(--padding-horizontal) 0 calc(var(--padding-horizontal) + var(--reaction-size)); + // padding: 0 var(--padding-horizontal); padding: 0 .5rem; background-color: var(--background-color); cursor: pointer; @@ -128,16 +134,30 @@ .stacked-avatars { --border-color: transparent; - margin-left: .25rem; + --border-size: .125rem; + --margin-right: -.875rem; + margin-left: .1875rem; // margin-right: .0625rem; } } &-block &-counter { - font-size: .875rem !important; + font-size: .9375rem !important; font-weight: 500; - margin: 0 .125rem 0 .375rem; - line-height: 1; + margin: 0 .0625rem 0 .375rem; + line-height: 1.125rem; position: relative; } + + .media-sticker { + --size: calc(var(--reaction-size) + var(--reaction-offset) * -2); + width: var(--size) !important; + height: var(--size) !important; + max-width: var(--size); + max-height: var(--size); + top: auto; + right: auto; + bottom: auto; + left: auto; + } }