Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
724 lines
24 KiB
724 lines
24 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
*/ |
|
|
|
import IS_WEBP_SUPPORTED from '../../environment/webpSupport'; |
|
import assumeType from '../../helpers/assumeType'; |
|
import getPathFromBytes from '../../helpers/bytes/getPathFromBytes'; |
|
import deferredPromise from '../../helpers/cancellablePromise'; |
|
import computeLockColor from '../../helpers/computeLockColor'; |
|
import cancelEvent from '../../helpers/dom/cancelEvent'; |
|
import {attachClickEvent} from '../../helpers/dom/clickEvent'; |
|
import createVideo from '../../helpers/dom/createVideo'; |
|
import findUpClassName from '../../helpers/dom/findUpClassName'; |
|
import renderImageFromUrl from '../../helpers/dom/renderImageFromUrl'; |
|
import getImageFromStrippedThumb from '../../helpers/getImageFromStrippedThumb'; |
|
import getPreviewURLFromThumb from '../../helpers/getPreviewURLFromThumb'; |
|
import makeError from '../../helpers/makeError'; |
|
import {makeMediaSize} from '../../helpers/mediaSize'; |
|
import mediaSizes from '../../helpers/mediaSizes'; |
|
import noop from '../../helpers/noop'; |
|
import onMediaLoad from '../../helpers/onMediaLoad'; |
|
import {isSavingLottiePreview, saveLottiePreview} from '../../helpers/saveLottiePreview'; |
|
import throttle from '../../helpers/schedulers/throttle'; |
|
import sequentialDom from '../../helpers/sequentialDom'; |
|
import {PhotoSize, VideoSize} from '../../layer'; |
|
import {MyDocument} from '../../lib/appManagers/appDocsManager'; |
|
import appDownloadManager from '../../lib/appManagers/appDownloadManager'; |
|
import appImManager from '../../lib/appManagers/appImManager'; |
|
import {AppManagers} from '../../lib/appManagers/managers'; |
|
import getServerMessageId from '../../lib/appManagers/utils/messageId/getServerMessageId'; |
|
import choosePhotoSize from '../../lib/appManagers/utils/photos/choosePhotoSize'; |
|
import getStickerEffectThumb from '../../lib/appManagers/utils/stickers/getStickerEffectThumb'; |
|
import lottieLoader from '../../lib/rlottie/lottieLoader'; |
|
import rootScope from '../../lib/rootScope'; |
|
import type {ThumbCache} from '../../lib/storages/thumbs'; |
|
import webpWorkerController from '../../lib/webp/webpWorkerController'; |
|
import {Awaited, SendMessageEmojiInteractionData} from '../../types'; |
|
import {getEmojiToneIndex} from '../../vendor/emoji'; |
|
import animationIntersector, {AnimationItemGroup} from '../animationIntersector'; |
|
import LazyLoadQueue from '../lazyLoadQueue'; |
|
import PopupStickers from '../popups/stickers'; |
|
import {hideToast, toastNew} from '../toast'; |
|
import wrapStickerAnimation from './stickerAnimation'; |
|
|
|
// https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp#L40 |
|
export const STICKER_EFFECT_MULTIPLIER = 1 + 0.245 * 2; |
|
const EMOJI_EFFECT_MULTIPLIER = 3; |
|
|
|
const locksUrls: {[docId: string]: string} = {}; |
|
|
|
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}: { |
|
doc: MyDocument, |
|
div: HTMLElement | HTMLElement[], |
|
middleware?: () => boolean, |
|
loadStickerMiddleware?: () => boolean, |
|
lazyLoadQueue?: LazyLoadQueue, |
|
exportLoad?: boolean, |
|
group?: AnimationItemGroup, |
|
play?: boolean, |
|
onlyThumb?: boolean, |
|
emoji?: string, |
|
width?: number, |
|
height?: number, |
|
withThumb?: boolean, |
|
loop?: boolean, |
|
loadPromises?: Promise<any>[], |
|
needFadeIn?: boolean, |
|
needUpscale?: boolean, |
|
skipRatio?: number, |
|
static?: boolean, |
|
managers?: AppManagers, |
|
fullThumb?: PhotoSize | VideoSize, |
|
isOut?: boolean, |
|
noPremium?: boolean, |
|
withLock?: boolean, |
|
relativeEffect?: boolean, |
|
loopEffect?: boolean, |
|
isCustomEmoji?: boolean |
|
}) { |
|
div = Array.isArray(div) ? div : [div]; |
|
|
|
const stickerType = doc.sticker; |
|
if(stickerType === 1) { |
|
asStatic = true; |
|
} |
|
|
|
if(!width && !height) { |
|
const sizes = mediaSizes.active; |
|
const boxSize = emoji ? sizes.emojiSticker : (doc.animated ? sizes.animatedSticker : sizes.staticSticker); |
|
const size = makeMediaSize(doc.w, doc.h).aspectFitted(boxSize); |
|
width = size.width; |
|
height = size.height; |
|
} |
|
|
|
if(stickerType === 2) { |
|
// LottieLoader.loadLottie(); |
|
lottieLoader.loadLottieWorkers(); |
|
} |
|
|
|
div.forEach((div) => { |
|
div.dataset.docId = '' + doc.id; |
|
div.classList.add('media-sticker-wrapper'); |
|
}); |
|
|
|
/* if(stickerType === 3) { |
|
const videoRes = wrapVideo({ |
|
doc, |
|
boxWidth: width, |
|
boxHeight: height, |
|
container: div, |
|
group, |
|
lazyLoadQueue, |
|
middleware, |
|
withoutPreloader: true, |
|
loadPromises, |
|
noPlayButton: true, |
|
noInfo: true |
|
}); |
|
|
|
if(videoRes.thumb) { |
|
if(videoRes.thumb.images.thumb) { |
|
videoRes.thumb.images.thumb.classList.add('media-sticker', 'thumbnail'); |
|
} |
|
|
|
if(videoRes.thumb.images.full) { |
|
videoRes.thumb.images.full.classList.add('media-sticker'); |
|
} |
|
} |
|
|
|
return videoRes.loadPromise; |
|
} */ |
|
|
|
// console.log('wrap sticker', doc, div, onlyThumb); |
|
|
|
let cacheContext: ThumbCache; |
|
const getCacheContext = async(type: string = cacheContext?.type) => { |
|
return cacheContext = await managers.thumbsStorage.getCacheContext(doc, type); |
|
}; |
|
|
|
const isAnimated = !asStatic && (stickerType === 2 || stickerType === 3); |
|
|
|
const effectThumb = getStickerEffectThumb(doc); |
|
if(isOut !== undefined && effectThumb && !isOut) { |
|
div.forEach((div) => div.classList.add('reflect-x')); |
|
} |
|
|
|
const willHaveLock = effectThumb && withLock; |
|
if(willHaveLock) { |
|
const lockUrl = locksUrls[doc.id]; |
|
div.forEach((div) => { |
|
div.classList.add('is-premium-sticker', 'tgico-premium_lock'); |
|
lockUrl && div.style.setProperty('--lock-url', `url(${lockUrl})`); |
|
}); |
|
} |
|
|
|
if(asStatic && stickerType !== 1) { |
|
const thumb = choosePhotoSize(doc, width, height, false) as PhotoSize.photoSize; |
|
await getCacheContext(thumb.type); |
|
} else { |
|
await getCacheContext(fullThumb?.type); |
|
} |
|
|
|
const toneIndex = emoji ? getEmojiToneIndex(emoji) : -1; |
|
const downloaded = cacheContext.downloaded && !needFadeIn; |
|
|
|
const isThumbNeededForType = isAnimated; |
|
const lottieCachedThumb = stickerType === 2 || stickerType === 3 ? await managers.appDocsManager.getLottieCachedThumb(doc.id, toneIndex) : undefined; |
|
|
|
const ret = {render: undefined as typeof loadPromise, load: undefined as typeof load}; |
|
let loadThumbPromise = deferredPromise<void>(); |
|
let haveThumbCached = false; |
|
if(( |
|
doc.thumbs?.length || |
|
lottieCachedThumb |
|
) && |
|
!div[0].firstElementChild && ( |
|
!downloaded || |
|
isThumbNeededForType || |
|
onlyThumb |
|
) && withThumb !== false/* && doc.thumbs[0]._ !== 'photoSizeEmpty' */ |
|
) { |
|
let thumb = lottieCachedThumb || doc.thumbs[0]; |
|
|
|
// console.log('wrap sticker', thumb, div); |
|
|
|
const afterRender = (div: HTMLElement, thumbImage: HTMLElement) => { |
|
if(!div.childElementCount) { |
|
thumbImage.classList.add('media-sticker', 'thumbnail'); |
|
|
|
sequentialDom.mutateElement(div, () => { |
|
div.append(thumbImage); |
|
loadThumbPromise.resolve(); |
|
}); |
|
} |
|
}; |
|
|
|
if('url' in thumb) { |
|
haveThumbCached = true; |
|
div.forEach((div) => { |
|
const thumbImage = new Image(); |
|
renderImageFromUrl(thumbImage, (thumb as any).url, () => afterRender(div, thumbImage)); |
|
}); |
|
} else if('bytes' in thumb) { |
|
if(thumb._ === 'photoPathSize') { |
|
if(!thumb.bytes.length) { |
|
thumb = doc.thumbs.find((t) => (t as PhotoSize.photoStrippedSize).bytes?.length) || thumb; |
|
} |
|
|
|
const d = getPathFromBytes((thumb as PhotoSize.photoStrippedSize).bytes); |
|
const ns = 'http://www.w3.org/2000/svg'; |
|
const svg = document.createElementNS(ns, 'svg'); |
|
svg.classList.add('rlottie-vector', 'media-sticker', 'thumbnail'); |
|
svg.setAttributeNS(null, 'viewBox', `0 0 ${doc.w || 512} ${doc.h || 512}`); |
|
|
|
// const defs = document.createElementNS(ns, 'defs'); |
|
// const linearGradient = document.createElementNS(ns, 'linearGradient'); |
|
// linearGradient.setAttributeNS(null, 'id', 'g'); |
|
// linearGradient.setAttributeNS(null, 'x1', '-300%'); |
|
// linearGradient.setAttributeNS(null, 'x2', '-200%'); |
|
// linearGradient.setAttributeNS(null, 'y1', '0'); |
|
// linearGradient.setAttributeNS(null, 'y2', '0'); |
|
// const stops = [ |
|
// ['-10%', '.1'], |
|
// ['30%', '.07'], |
|
// ['70%', '.07'], |
|
// ['110%', '.1'] |
|
// ].map(([offset, stopOpacity]) => { |
|
// const stop = document.createElementNS(ns, 'stop'); |
|
// stop.setAttributeNS(null, 'offset', offset); |
|
// stop.setAttributeNS(null, 'stop-opacity', stopOpacity); |
|
// return stop; |
|
// }); |
|
// const animates = [ |
|
// ['-300%', '1200%'], |
|
// ['-200%', '1300%'] |
|
// ].map(([from, to], idx) => { |
|
// const animate = document.createElementNS(ns, 'animate'); |
|
// animate.setAttributeNS(null, 'attributeName', 'x' + (idx + 1)); |
|
// animate.setAttributeNS(null, 'from', from); |
|
// animate.setAttributeNS(null, 'to', to); |
|
// animate.setAttributeNS(null, 'dur', '3s'); |
|
// animate.setAttributeNS(null, 'repeatCount', 'indefinite'); |
|
// return animate; |
|
// }); |
|
// linearGradient.append(...stops, ...animates); |
|
// defs.append(linearGradient); |
|
// svg.append(defs); |
|
|
|
const path = document.createElementNS(ns, 'path'); |
|
path.setAttributeNS(null, 'd', d); |
|
if(rootScope.settings.animationsEnabled && !isCustomEmoji) path.setAttributeNS(null, 'fill', 'url(#g)'); |
|
svg.append(path); |
|
div.forEach((div, idx) => div.append(idx > 0 ? svg.cloneNode(true) : svg)); |
|
haveThumbCached = true; |
|
loadThumbPromise.resolve(); |
|
} else if(toneIndex <= 0) { |
|
const r = () => { |
|
(div as HTMLElement[]).forEach((div) => { |
|
const thumbImage = new Image(); |
|
const url = getPreviewURLFromThumb(doc, thumb as PhotoSize.photoStrippedSize, true); |
|
renderImageFromUrl(thumbImage, url, () => afterRender(div, thumbImage)); |
|
}); |
|
}; |
|
|
|
if((IS_WEBP_SUPPORTED || doc.pFlags.stickerThumbConverted || cacheContext.url)/* && false */) { |
|
haveThumbCached = true; |
|
r(); |
|
} else { |
|
haveThumbCached = true; |
|
webpWorkerController.convert('main-' + doc.id, thumb.bytes).then((bytes) => { |
|
managers.appDocsManager.saveWebPConvertedStrippedThumb(doc.id, bytes); |
|
(thumb as PhotoSize.photoStrippedSize).bytes = bytes; |
|
doc.pFlags.stickerThumbConverted = true; |
|
|
|
if((middleware && !middleware()) || (div as HTMLElement[])[0].childElementCount) { |
|
loadThumbPromise.resolve(); |
|
return; |
|
} |
|
|
|
r(); |
|
}).catch(() => loadThumbPromise.resolve()); |
|
} |
|
} |
|
} else if(((stickerType === 2 && toneIndex <= 0) || stickerType === 3) && (withThumb || onlyThumb)) { |
|
const load = async() => { |
|
if((div as HTMLElement[])[0].childElementCount || (middleware && !middleware())) { |
|
loadThumbPromise.resolve(); |
|
return; |
|
} |
|
|
|
const r = (div: HTMLElement, thumbImage: HTMLElement) => { |
|
if(div.childElementCount || (middleware && !middleware())) { |
|
loadThumbPromise.resolve(); |
|
return; |
|
} |
|
|
|
renderImageFromUrl(thumbImage, cacheContext.url, () => afterRender(div, thumbImage)); |
|
}; |
|
|
|
await getCacheContext(); |
|
(div as HTMLElement[]).forEach((div) => { |
|
if(cacheContext.url) { |
|
r(div, new Image()); |
|
} else if('bytes' in thumb) { |
|
const res = getImageFromStrippedThumb(doc, thumb as PhotoSize.photoStrippedSize, true); |
|
res.loadPromise.then(() => r(div, res.image)); |
|
|
|
// return managers.appDocsManager.getThumbURL(doc, thumb as PhotoSize.photoStrippedSize).promise.then(r); |
|
} else { |
|
appDownloadManager.downloadMediaURL({ |
|
media: doc, |
|
thumb: thumb as PhotoSize |
|
}).then(async() => { |
|
await getCacheContext(); |
|
return r(div, new Image()); |
|
}); |
|
} |
|
}); |
|
}; |
|
|
|
if(lazyLoadQueue && onlyThumb) { |
|
lazyLoadQueue.push({div: div[0], load}); |
|
loadThumbPromise.resolve(); |
|
return ret; |
|
} else { |
|
load(); |
|
|
|
if((thumb as any).url) { |
|
haveThumbCached = true; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if(loadPromises && haveThumbCached) { |
|
loadPromises.push(loadThumbPromise); |
|
} |
|
|
|
if(onlyThumb/* || true */) { // for sticker panel |
|
return ret; |
|
} |
|
|
|
const middlewareError = makeError('MIDDLEWARE'); |
|
const load = async() => { |
|
if(middleware && !middleware()) { |
|
throw middlewareError; |
|
} |
|
|
|
if(stickerType === 2 && !asStatic) { |
|
return appDownloadManager.downloadMedia({media: doc, queueId: lazyLoadQueue?.queueId, thumb: fullThumb}) |
|
.then(async(blob) => { |
|
if(middleware && !middleware()) { |
|
throw middlewareError; |
|
} |
|
|
|
const animation = await lottieLoader.loadAnimationWorker({ |
|
container: (div as HTMLElement[])[0], |
|
loop: loop && !emoji, |
|
autoplay: play, |
|
animationData: blob, |
|
width, |
|
height, |
|
name: 'doc' + doc.id, |
|
needUpscale, |
|
skipRatio, |
|
toneIndex, |
|
sync: isCustomEmoji |
|
}, group, loadStickerMiddleware ?? middleware); |
|
|
|
// const deferred = deferredPromise<void>(); |
|
|
|
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}); |
|
}); |
|
} |
|
}; |
|
|
|
animation.addEventListener('firstFrame', () => { |
|
const canvas = animation.canvas[0]; |
|
if(withThumb !== false) { |
|
saveLottiePreview(doc, canvas, toneIndex); |
|
} |
|
|
|
if(willHaveLock) { |
|
setLockColor(); |
|
} |
|
|
|
if(!isCustomEmoji) { |
|
(div as HTMLElement[]).forEach((container, idx) => { |
|
onFirstFrame(container, animation.canvas[idx]); |
|
}); |
|
} |
|
}, {once: true}); |
|
|
|
if(emoji) { |
|
const data: SendMessageEmojiInteractionData = { |
|
a: [], |
|
v: 1 |
|
}; |
|
|
|
let sendInteractionThrottled: () => void; |
|
|
|
managers.appStickersManager.preloadAnimatedEmojiStickerAnimation(emoji); |
|
|
|
const container = (div as HTMLElement[])[0]; |
|
attachClickEvent(container, async(e) => { |
|
cancelEvent(e); |
|
const animation = lottieLoader.getAnimation(container); |
|
|
|
if(animation.paused) { |
|
const doc = await managers.appStickersManager.getAnimatedEmojiSoundDocument(emoji); |
|
if(doc) { |
|
const audio = document.createElement('audio'); |
|
audio.style.display = 'none'; |
|
container.parentElement.append(audio); |
|
|
|
try { |
|
const url = await appDownloadManager.downloadMediaURL({media: doc}); |
|
|
|
audio.src = url; |
|
audio.play(); |
|
await onMediaLoad(audio, undefined, true); |
|
|
|
audio.addEventListener('ended', () => { |
|
audio.src = ''; |
|
audio.remove(); |
|
}, {once: true}); |
|
} catch(err) { |
|
|
|
} |
|
} |
|
|
|
animation.autoplay = true; |
|
animation.restart(); |
|
} |
|
|
|
const peerId = appImManager.chat.peerId; |
|
if(!peerId.isUser()) { |
|
return; |
|
} |
|
|
|
const doc = await managers.appStickersManager.getAnimatedEmojiSticker(emoji, true); |
|
if(!doc) { |
|
return; |
|
} |
|
|
|
const {animationDiv} = wrapStickerAnimation({ |
|
doc, |
|
middleware, |
|
side: isOut ? 'right' : 'left', |
|
size: 280, |
|
target: container, |
|
play: true, |
|
withRandomOffset: true |
|
}); |
|
|
|
if(isOut !== undefined && !isOut) { |
|
animationDiv.classList.add('reflect-x'); |
|
} |
|
|
|
if(!sendInteractionThrottled) { |
|
sendInteractionThrottled = throttle(() => { |
|
const length = data.a.length; |
|
if(!length) { |
|
return; |
|
} |
|
|
|
const firstTime = data.a[0].t; |
|
|
|
data.a.forEach((a) => { |
|
a.t = (a.t - firstTime) / 1000; |
|
}); |
|
|
|
const bubble = findUpClassName(container, 'bubble'); |
|
managers.appMessagesManager.setTyping(appImManager.chat.peerId, { |
|
_: 'sendMessageEmojiInteraction', |
|
msg_id: getServerMessageId(+bubble.dataset.mid), |
|
emoticon: emoji, |
|
interaction: { |
|
_: 'dataJSON', |
|
data: JSON.stringify(data) |
|
} |
|
}, true); |
|
|
|
data.a.length = 0; |
|
}, 1000, false); |
|
} |
|
|
|
// using a trick here: simulated event from interlocutor's interaction won't fire ours |
|
if(e.isTrusted) { |
|
data.a.push({ |
|
i: 1, |
|
t: Date.now() |
|
}); |
|
|
|
sendInteractionThrottled(); |
|
} |
|
}); |
|
} |
|
|
|
return animation; |
|
|
|
// return deferred; |
|
// await new Promise((resolve) => setTimeout(resolve, 5e3)); |
|
}); |
|
} else if(asStatic || stickerType === 3) { |
|
const media: HTMLElement[] = (div as HTMLElement[]).map(() => { |
|
let media: HTMLElement; |
|
if(asStatic) { |
|
media = new Image(); |
|
} else { |
|
const video = media = createVideo(); |
|
video.muted = true; |
|
if(play) video.autoplay = true; |
|
if(loop) video.loop = true; |
|
} |
|
|
|
media.classList.add('media-sticker'); |
|
return media; |
|
}); |
|
|
|
const thumbImage = (div as HTMLElement[]).map((div, idx) => (div.firstElementChild as HTMLElement) !== media[idx] && div.firstElementChild) as HTMLElement[]; |
|
if(needFadeIn !== false) { |
|
needFadeIn = (needFadeIn || !downloaded || (asStatic ? thumbImage[0] : (!thumbImage[0] || thumbImage[0].tagName === 'svg'))) && rootScope.settings.animationsEnabled; |
|
} |
|
|
|
if(needFadeIn) { |
|
media.forEach((media) => media.classList.add('fade-in')); |
|
} |
|
|
|
return new Promise<HTMLVideoElement | HTMLImageElement>(async(resolve, reject) => { |
|
const r = async() => { |
|
if(middleware && !middleware()) { |
|
reject(middlewareError); |
|
return; |
|
} |
|
|
|
const onLoad = (div: HTMLElement, media: HTMLElement, thumbImage: HTMLElement) => { |
|
sequentialDom.mutateElement(div, () => { |
|
div.append(media); |
|
thumbImage && thumbImage.classList.add('fade-out'); |
|
|
|
if(stickerType === 3 && !isSavingLottiePreview(doc, toneIndex)) { |
|
// const perf = performance.now(); |
|
assumeType<HTMLVideoElement>(media); |
|
const canvas = document.createElement('canvas'); |
|
canvas.width = width * window.devicePixelRatio; |
|
canvas.height = height * window.devicePixelRatio; |
|
const ctx = canvas.getContext('2d'); |
|
ctx.drawImage(media, 0, 0, canvas.width, canvas.height); |
|
saveLottiePreview(doc, canvas, toneIndex); |
|
// console.log('perf', performance.now() - perf); |
|
} |
|
|
|
if(stickerType === 3 && group) { |
|
animationIntersector.addAnimation(media as HTMLVideoElement, group); |
|
} |
|
|
|
resolve(media as any); |
|
|
|
if(needFadeIn) { |
|
media.addEventListener('animationend', () => { |
|
media.classList.remove('fade-in'); |
|
thumbImage?.remove(); |
|
}, {once: true}); |
|
} |
|
}); |
|
}; |
|
|
|
await getCacheContext(); |
|
media.forEach((media, idx) => { |
|
const cb = () => onLoad((div as HTMLElement[])[idx], media, thumbImage[idx]); |
|
if(asStatic) { |
|
renderImageFromUrl(media, cacheContext.url, cb); |
|
} else { |
|
(media as HTMLVideoElement).src = cacheContext.url; |
|
onMediaLoad(media as HTMLVideoElement).then(cb); |
|
} |
|
}); |
|
}; |
|
|
|
await getCacheContext(); |
|
if(cacheContext.url) r(); |
|
else { |
|
let promise: Promise<any>; |
|
if(stickerType !== 1 && asStatic) { |
|
const thumb = choosePhotoSize(doc, width, height, false) as PhotoSize.photoSize; |
|
// promise = managers.appDocsManager.getThumbURL(doc, thumb).promise |
|
promise = appDownloadManager.downloadMediaURL({media: doc, thumb, queueId: lazyLoadQueue?.queueId}); |
|
} else { |
|
promise = appDownloadManager.downloadMediaURL({media: doc, queueId: lazyLoadQueue?.queueId}); |
|
} |
|
|
|
promise.then(r, reject); |
|
} |
|
}); |
|
} |
|
}; |
|
|
|
if(exportLoad && (!downloaded || isAnimated)) { |
|
ret.load = load; |
|
return ret; |
|
} |
|
|
|
const loadPromise: Promise<Awaited<ReturnType<typeof load>> | void> = lazyLoadQueue && (!downloaded || isAnimated) ? |
|
(lazyLoadQueue.push({div: div[0], load}), Promise.resolve()) : |
|
load(); |
|
|
|
if(downloaded && (asStatic/* || stickerType === 3 */)) { |
|
loadThumbPromise = loadPromise as any; |
|
if(loadPromises) { |
|
loadPromises.push(loadThumbPromise); |
|
} |
|
} |
|
|
|
if(stickerType === 2 && effectThumb && isOut !== undefined && !noPremium) { |
|
attachStickerEffectHandler({ |
|
container: div[0], |
|
doc, |
|
managers, |
|
middleware, |
|
isOut, |
|
width, |
|
loadPromise, |
|
relativeEffect, |
|
loopEffect |
|
}); |
|
} |
|
|
|
ret.render = loadPromise as any; |
|
return ret; |
|
} |
|
|
|
function attachStickerEffectHandler({container, doc, managers, middleware, isOut, width, loadPromise, relativeEffect, loopEffect}: { |
|
container: HTMLElement, |
|
doc: MyDocument, |
|
managers: AppManagers, |
|
middleware: () => boolean, |
|
isOut: boolean, |
|
width: number, |
|
loadPromise: Promise<any>, |
|
relativeEffect?: boolean, |
|
loopEffect?: boolean |
|
}) { |
|
managers.appStickersManager.preloadSticker(doc.id, true); |
|
|
|
let playing = false; |
|
attachClickEvent(container, async(e) => { |
|
cancelEvent(e); |
|
if(playing) { |
|
const a = document.createElement('a'); |
|
a.onclick = () => { |
|
hideToast(); |
|
new PopupStickers(doc.stickerSetInput).show(); |
|
}; |
|
|
|
toastNew({ |
|
langPackKey: 'Sticker.Premium.Click.Info', |
|
langPackArguments: [a] |
|
}); |
|
|
|
return; |
|
} |
|
|
|
playing = true; |
|
|
|
await loadPromise; |
|
const {animationDiv, stickerPromise} = wrapStickerAnimation({ |
|
doc, |
|
middleware, |
|
side: isOut ? 'right' : 'left', |
|
size: width * STICKER_EFFECT_MULTIPLIER, |
|
target: container, |
|
play: true, |
|
fullThumb: getStickerEffectThumb(doc), |
|
relativeEffect, |
|
loopEffect |
|
}); |
|
|
|
if(isOut !== undefined && !isOut/* && !relativeEffect */) { |
|
animationDiv.classList.add('reflect-x'); |
|
} |
|
|
|
stickerPromise.then((player) => { |
|
player.addEventListener('destroy', () => { |
|
playing = false; |
|
}); |
|
}); |
|
}); |
|
}
|
|
|