diff --git a/src/components/appMediaViewerBase.ts b/src/components/appMediaViewerBase.ts index 1724864ca..8645c99e3 100644 --- a/src/components/appMediaViewerBase.ts +++ b/src/components/appMediaViewerBase.ts @@ -4,12 +4,12 @@ * https://github.com/morethanwords/tweb/blob/master/LICENSE */ +import type {MyDocument} from '../lib/appManagers/appDocsManager'; +import type {MyPhoto} from '../lib/appManagers/appPhotosManager'; import deferredPromise from '../helpers/cancellablePromise'; import mediaSizes from '../helpers/mediaSizes'; import IS_TOUCH_SUPPORTED from '../environment/touchSupport'; import {IS_MOBILE, IS_MOBILE_SAFARI, IS_SAFARI} from '../environment/userAgent'; -import type {MyDocument} from '../lib/appManagers/appDocsManager'; -import type {MyPhoto} from '../lib/appManagers/appPhotosManager'; import {logger} from '../lib/logger'; import VideoPlayer from '../lib/mediaPlayer'; import rootScope from '../lib/rootScope'; @@ -48,7 +48,6 @@ import setAttachmentSize from '../helpers/setAttachmentSize'; import wrapEmojiText from '../lib/richTextProcessor/wrapEmojiText'; import LazyLoadQueueBase from './lazyLoadQueueBase'; import overlayCounter from '../helpers/overlayCounter'; -import {ThumbCache} from '../lib/storages/thumbs'; import appDownloadManager from '../lib/appManagers/appDownloadManager'; import wrapPeerTitle from './wrappers/peerTitle'; import {toastNew} from './toast'; @@ -329,10 +328,11 @@ export default class AppMediaViewerBase< return false; }, - verifyTouchTarget: (evt) => { - console.log('verify'); + verifyTouchTarget: (e) => { // * Fix for seek input - if((evt.target as HTMLElement).tagName === 'INPUT' || findUpClassName(evt.target, 'media-viewer-caption')) { + if(findUpClassName(e.target, 'ckin__controls') || + findUpClassName(e.target, 'media-viewer-caption') || + findUpClassName(e.target, 'media-viewer-topbar')) { return false; } diff --git a/src/components/sidebarLeft/tabs/generalSettings.ts b/src/components/sidebarLeft/tabs/generalSettings.ts index d8b1474e3..cd8b4e211 100644 --- a/src/components/sidebarLeft/tabs/generalSettings.ts +++ b/src/components/sidebarLeft/tabs/generalSettings.ts @@ -267,7 +267,7 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable { managers: this.managers, loadPromises, middleware: this.middlewareHelper.get(), - play: rootScope.settings.animationsEnabled + play: false }).then(({render}) => render).then((player) => { k.player = player as RLottiePlayer; }); diff --git a/src/components/wrappers/sticker.ts b/src/components/wrappers/sticker.ts index e056b514b..59d00db64 100644 --- a/src/components/wrappers/sticker.ts +++ b/src/components/wrappers/sticker.ts @@ -54,6 +54,16 @@ const locksUrls: {[docId: string]: string} = {}; export const videosCache: {[key: string]: Promise} = {}; +const onAnimationEnd = (element: HTMLElement, onAnimationEnd: () => void, timeout: number) => { + const onEnd = () => { + element.removeEventListener('animationend', onEnd); + onAnimationEnd(); + clearTimeout(_timeout); + }; + element.addEventListener('animationend', onEnd); + const _timeout = setTimeout(onEnd, timeout); +}; + export default async function wrapSticker({doc, div, middleware, loadStickerMiddleware, lazyLoadQueue, exportLoad, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn, needUpscale, skipRatio, static: asStatic, managers = rootScope.managers, fullThumb, isOut, noPremium, withLock, relativeEffect, loopEffect, isCustomEmoji, syncedVideo}: { doc: MyDocument, div: HTMLElement | HTMLElement[], @@ -200,10 +210,12 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd const afterRender = (div: HTMLElement, thumbImage: HTMLElement) => { if(!div.childElementCount) { - thumbImage.classList.add('media-sticker', 'thumbnail'); - sequentialDom.mutateElement(div, () => { - div.append(thumbImage); + if(!div.childElementCount) { + thumbImage.classList.add('media-sticker', 'thumbnail'); + div.append(thumbImage); + } + loadThumbPromise.resolve(); }); } else { @@ -364,94 +376,92 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd } if(stickerType === 2 && !asStatic) { - return appDownloadManager.downloadMedia({media: doc, queueId: lazyLoadQueue?.queueId, thumb: fullThumb}) - .then(async(blob) => { - if(middleware && !middleware()) { - throw middlewareError; + const blob = await appDownloadManager.downloadMedia({media: doc, queueId: lazyLoadQueue?.queueId, thumb: fullThumb}); + if(middleware && !middleware()) { + throw middlewareError; + } + + const animation = await lottieLoader.loadAnimationWorker({ + container: (div as HTMLElement[])[0], + loop: !!(!emoji || isCustomEmoji) && loop, + autoplay: play, + animationData: blob, + width, + height, + name: 'doc' + doc.id, + needUpscale, + skipRatio, + toneIndex, + sync: isCustomEmoji, + middleware: loadStickerMiddleware ?? middleware, + group + }); + + // const deferred = deferredPromise(); + + const setLockColor = willHaveLock ? () => { + const lockUrl = locksUrls[doc.id] ??= computeLockColor(animation.canvas[0]); + (div as HTMLElement[]).forEach((div) => div.style.setProperty('--lock-url', `url(${lockUrl})`)); + } : undefined; + + const onFirstFrame = (container: HTMLElement, canvas: HTMLCanvasElement) => { + const element = container.firstElementChild !== canvas && container.firstElementChild as HTMLElement; + if(needFadeIn !== false) { + needFadeIn = (needFadeIn || !element || element.tagName === 'svg') && rootScope.settings.animationsEnabled; } - const animation = await lottieLoader.loadAnimationWorker({ - container: (div as HTMLElement[])[0], - loop: !!(!emoji || isCustomEmoji) && loop, - autoplay: play, - animationData: blob, - width, - height, - name: 'doc' + doc.id, - needUpscale, - skipRatio, - toneIndex, - sync: isCustomEmoji, - middleware: loadStickerMiddleware ?? middleware, - group - }); - - // const deferred = deferredPromise(); - - const setLockColor = willHaveLock ? () => { - const lockUrl = locksUrls[doc.id] ??= computeLockColor(animation.canvas[0]); - (div as HTMLElement[]).forEach((div) => div.style.setProperty('--lock-url', `url(${lockUrl})`)); - } : undefined; - - const onFirstFrame = (container: HTMLElement, canvas: HTMLCanvasElement) => { - const element = container.firstElementChild; - if(needFadeIn !== false) { - needFadeIn = (needFadeIn || !element || element.tagName === 'svg') && rootScope.settings.animationsEnabled; - } - - const cb = () => { - if(element && element !== canvas && element.tagName !== 'DIV') { - element.remove(); - } - }; - - if(!needFadeIn) { - if(element) { - sequentialDom.mutate(cb); - } - } else { - sequentialDom.mutate(() => { - canvas && canvas.classList.add('fade-in'); - if(element) { - element.classList.add('fade-out'); - } - - (canvas || element).addEventListener('animationend', () => { - sequentialDom.mutate(() => { - canvas && canvas.classList.remove('fade-in'); - cb(); - }); - }, {once: true}); - }); + const cb = () => { + if(element && element !== canvas && element.tagName !== 'DIV') { + element.remove(); } }; - animation.addEventListener('firstFrame', () => { - const canvas = animation.canvas[0]; - if(withThumb !== false || isCustomEmoji) { - saveLottiePreview(doc, canvas, toneIndex); + if(!needFadeIn) { + if(element) { + sequentialDom.mutate(cb); } + } else { + sequentialDom.mutate(() => { + canvas && canvas.classList.add('fade-in'); + if(element) { + element.classList.add('fade-out'); + } - if(willHaveLock) { - setLockColor(); - } + onAnimationEnd(canvas || element, () => { + sequentialDom.mutate(() => { + canvas && canvas.classList.remove('fade-in'); + cb(); + }); + }, 400); + }); + } + }; - if(!isCustomEmoji) { - (div as HTMLElement[]).forEach((container, idx) => { - onFirstFrame(container, animation.canvas[idx]); - }); - } - }, {once: true}); - - if(emoji) { - managers.appStickersManager.preloadAnimatedEmojiStickerAnimation(emoji); + animation.addEventListener('firstFrame', () => { + const canvas = animation.canvas[0]; + if(withThumb !== false || isCustomEmoji) { + saveLottiePreview(doc, canvas, toneIndex); } - return animation; + if(willHaveLock) { + setLockColor(); + } - // return deferred; - // await new Promise((resolve) => setTimeout(resolve, 5e3)); - }); + if(!isCustomEmoji) { + (div as HTMLElement[]).forEach((container, idx) => { + onFirstFrame(container, animation.canvas[idx]); + }); + } + }, {once: true}); + + if(emoji) { + managers.appStickersManager.preloadAnimatedEmojiStickerAnimation(emoji); + } + + return animation; + + // return deferred; + // await new Promise((resolve) => setTimeout(resolve, 5e3)); } else if(asStatic || stickerType === 3) { const isSingleVideo = isAnimated && syncedVideo; const cacheName = isSingleVideo ? framesCache.generateName('' + doc.id, 0, 0, undefined, undefined) : undefined; @@ -550,10 +560,10 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd if(needFadeIn) { thumbImage && thumbImage.classList.add('fade-out'); - media.addEventListener('animationend', () => { + onAnimationEnd(media, () => { media.classList.remove('fade-in'); thumbImage?.remove(); - }, {once: true}); + }, 400); } else { thumbImage?.remove(); } diff --git a/src/components/wrappers/stickerEmoji.ts b/src/components/wrappers/stickerEmoji.ts index fccc614b5..48835811c 100644 --- a/src/components/wrappers/stickerEmoji.ts +++ b/src/components/wrappers/stickerEmoji.ts @@ -25,9 +25,9 @@ export default async function wrapStickerEmoji(options: Modify theme.name === 'night'), e); + console.log(e.style.cssText); + style.textContent = `.night {${e.style.cssText}}`; this.applyHighlightningColor(); } @@ -188,7 +202,7 @@ export class ThemeController { } // theme applier - private bindColorApplier(options: Pick[0], 'element'>) { + private bindColorApplier(options: Pick[0], 'element' | 'isNight'>) { const appliedColors: Set = new Set(); return { applyAppColor: (_options: Omit[0], keyof typeof options>) => { @@ -196,12 +210,13 @@ export class ThemeController { return this.applyAppColor({..._options, ...options}); }, finalize: () => { - const isNight = this.isNight(); + const isNight = options.isNight; for(const name in appColorMap) { if(!appliedColors.has(name as AppColorName)) { this.applyAppColor({ name: name as AppColorName, - hex: colorMap[isNight ? 'night' : 'day'][name as AppColorName] + hex: colorMap[isNight ? 'night' : 'day'][name as AppColorName], + ...options }); } } @@ -212,23 +227,25 @@ export class ThemeController { private applyAppColor({ name, hex, - element = document.documentElement, + element, lightenAlpha = 0.08, darkenAlpha = lightenAlpha, - mixColor + mixColor, + isNight }: { name: AppColorName, hex: string, - element?: HTMLElement, + element: HTMLElement, lightenAlpha?: number darkenAlpha?: number, - mixColor?: ColorRgb + mixColor?: ColorRgb, + isNight?: boolean }) { const appColor = appColorMap[name]; const rgb = hexToRgb(hex); const hsla = rgbaToHsla(...rgb); - mixColor ??= hexToRgb(colorMap[themeController.isNight() ? 'night' : 'day']['surface-color']); + mixColor ??= hexToRgb(colorMap[isNight ? 'night' : 'day']['surface-color']); const lightenedRgb = mixColors(rgb, mixColor, lightenAlpha); const darkenedHsla: typeof hsla = { @@ -236,16 +253,22 @@ export class ThemeController { l: hsla.l - darkenAlpha * 100 }; - element.style.setProperty('--' + name, hex); - appColor.rgb && element.style.setProperty('--' + name + '-rgb', rgb.join(',')); - appColor.light && element.style.setProperty('--light-' + name, `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${lightenAlpha})`); - appColor.lightFilled && element.style.setProperty('--light-filled-' + name, rgbaToHexa(lightenedRgb)); - appColor.dark && element.style.setProperty('--dark-' + name, `hsl(${darkenedHsla.h}, ${darkenedHsla.s}%, ${darkenedHsla.l}%)`); - // appColor.darkFilled && element.style.setProperty('--dark-' + name, `hsl(${darkenedHsla.h}, ${darkenedHsla.s}%, ${darkenedHsla.l}%)`); + const properties: [string, string][] = [ + [name, hex], + appColor.rgb && [name + '-rgb', rgb.join(',')], + appColor.light && ['light-' + name, `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${lightenAlpha})`], + appColor.lightFilled && ['light-filled-' + name, rgbaToHexa(lightenedRgb)], + appColor.dark && ['dark-' + name, `hsl(${darkenedHsla.h}, ${darkenedHsla.s}%, ${darkenedHsla.l}%)`] + // appColor.darkFilled && ['dark-' + name, `hsl(${darkenedHsla.h}, ${darkenedHsla.s}%, ${darkenedHsla.l}%)`] + ]; + + properties.filter(Boolean).forEach(([name, value]) => { + element.style.setProperty('--' + name, value); + }); } public async applyNewTheme(theme: Theme) { - const isNight = this.isNight(); + const isNight = this.isNightTheme(theme); const currentTheme = this.getTheme(); const themes = rootScope.settings.themes; const themeSettings = theme.settings.find((themeSettings) => themeSettings.base_theme._ === (isNight ? 'baseThemeNight' : 'baseThemeClassic')); @@ -264,8 +287,12 @@ export class ThemeController { rootScope.dispatchEvent('theme_change'); } - public async applyTheme(theme: Theme | AppTheme, element = document.documentElement) { - const isNight = themeController.isNight(); + private isNightTheme(theme: Theme | AppTheme) { + return (theme as AppTheme).name === 'night' || this.isNight(); + } + + public applyTheme(theme: Theme | AppTheme, element = document.documentElement) { + const isNight = this.isNightTheme(theme); const themeSettings = Array.isArray(theme.settings) ? theme.settings.find((settings) => settings.base_theme._ === (isNight ? 'baseThemeNight' : 'baseThemeClassic')) : theme.settings; @@ -282,7 +309,7 @@ export class ThemeController { ); const newAccentHex = rgbaToHexa(newAccentRgb); - const {applyAppColor, finalize} = this.bindColorApplier({element}); + const {applyAppColor, finalize} = this.bindColorApplier({element, isNight}); applyAppColor({ name: 'primary-color', @@ -295,7 +322,7 @@ export class ThemeController { hex: newAccentHex, lightenAlpha: 0.64, mixColor: [255, 255, 255] - }) + }); if(!themeSettings.message_colors?.length) { return; @@ -357,4 +384,5 @@ export class ThemeController { } const themeController = new ThemeController(); +MOUNT_CLASS_TO && (MOUNT_CLASS_TO.themeController = themeController); export default themeController; diff --git a/src/lib/appManagers/uiNotificationsManager.ts b/src/lib/appManagers/uiNotificationsManager.ts index 2bec02afd..9c84b7985 100644 --- a/src/lib/appManagers/uiNotificationsManager.ts +++ b/src/lib/appManagers/uiNotificationsManager.ts @@ -327,16 +327,15 @@ export class UiNotificationsManager { notification.image = url; } else { - const WIDTH = 54, HEIGHT = WIDTH; let {avatarCanvas, avatarContext} = this; if(!this.avatarCanvas) { avatarCanvas = this.avatarCanvas = document.createElement('canvas'); avatarContext = this.avatarContext = avatarCanvas.getContext('2d'); - const dpr = window.devicePixelRatio; + const SIZE = 54; + const dpr = 1; avatarCanvas.dpr = dpr; - avatarCanvas.width = 54 * dpr; - avatarCanvas.height = 54 * dpr; + avatarCanvas.width = avatarCanvas.height = SIZE * dpr; this.avatarGradients = {}; } else { @@ -346,7 +345,7 @@ export class UiNotificationsManager { const color = getPeerColorById(peerId, true); let gradient = this.avatarGradients[color]; if(!gradient) { - gradient = this.avatarGradients[color] = avatarContext.createLinearGradient(WIDTH / 2, 0, WIDTH / 2, HEIGHT); + gradient = this.avatarGradients[color] = avatarContext.createLinearGradient(avatarCanvas.width / 2, 0, avatarCanvas.width / 2, avatarCanvas.height); const colorTop = customProperties.getProperty(`peer-avatar-${color}-top`); const colorBottom = customProperties.getProperty(`peer-avatar-${color}-bottom`); @@ -356,10 +355,10 @@ export class UiNotificationsManager { avatarContext.fillStyle = gradient; - drawCircle(avatarContext, WIDTH / 2, HEIGHT / 2, WIDTH / 2); + drawCircle(avatarContext, avatarCanvas.width / 2, avatarCanvas.height / 2, avatarCanvas.width / 2); avatarContext.fill(); - const fontSize = 20 * window.devicePixelRatio; + const fontSize = 20 * avatarCanvas.dpr; const abbreviation = getAbbreviation(peerTitle); avatarContext.font = `700 ${fontSize}px ${FontFamily}`; diff --git a/src/scss/partials/_button.scss b/src/scss/partials/_button.scss index a8c086b31..6c49dbc06 100644 --- a/src/scss/partials/_button.scss +++ b/src/scss/partials/_button.scss @@ -863,9 +863,9 @@ $btn-menu-z-index: 4; transition: background-color var(--transition-standard-in), opacity var(--transition-standard-in); } - & + &, - &-container + &-container { - margin-inline-start: var(--call-button-margin); + &, + &-container { + margin: 0 var(--call-button-margin); } } diff --git a/src/scss/partials/popups/_groupCall.scss b/src/scss/partials/popups/_groupCall.scss index 4615dd706..4f9fbf805 100644 --- a/src/scss/partials/popups/_groupCall.scss +++ b/src/scss/partials/popups/_groupCall.scss @@ -37,7 +37,7 @@ } .group-call { - --call-button-margin: 1.25rem; + --call-button-margin: .625rem; width: 100%; height: 100%; padding: 0 .5rem;