diff --git a/src/components/chat/replyContainer.ts b/src/components/chat/replyContainer.ts
index fa665e99..b9a89b6a 100644
--- a/src/components/chat/replyContainer.ts
+++ b/src/components/chat/replyContainer.ts
@@ -42,7 +42,7 @@ export function wrapReplyDivAndCaption(options: {
div: mediaEl,
lazyLoadQueue: appImManager.lazyLoadQueue,
group: CHAT_ANIMATION_GROUP,
- onlyThumb: media.document.sticker == 2,
+ //onlyThumb: media.document.sticker == 2,
width: 32,
height: 32
});
diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts
index 282c33ba..f2c9c7e4 100644
--- a/src/components/wrappers.ts
+++ b/src/components/wrappers.ts
@@ -564,8 +564,8 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
const toneIndex = emoji ? getEmojiToneIndex(emoji) : -1;
- if(doc.thumbs?.length && !div.firstElementChild && (!doc.downloaded || stickerType == 2 || onlyThumb) && toneIndex <= 0/* && doc.thumbs[0]._ != 'photoSizeEmpty' */) {
- const thumb = doc.thumbs[0];
+ if((doc.thumbs?.length || doc.stickerCachedThumbs) && !div.firstElementChild && (!doc.downloaded || stickerType == 2 || onlyThumb)/* && doc.thumbs[0]._ != 'photoSizeEmpty' */) {
+ const thumb = doc.stickerCachedThumbs && doc.stickerCachedThumbs[toneIndex] || doc.thumbs[0];
//console.log('wrap sticker', thumb, div);
@@ -580,23 +580,29 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
img = new Image();
renderImageFromUrl(img, thumb.url, afterRender);
} else if('bytes' in thumb) {
- img = new Image();
-
- if((webpWorkerController.isWebpSupported() || doc.pFlags.stickerThumbConverted || thumb.url)/* && false */) {
- renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true), afterRender);
- } else {
- webpWorkerController.convert(doc.id, thumb.bytes as Uint8Array).then(bytes => {
- thumb.bytes = bytes;
- doc.pFlags.stickerThumbConverted = true;
-
- if(middleware && !middleware()) return;
-
- if(!div.childElementCount) {
- renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true), afterRender);
- }
- }).catch(() => {});
+ if(thumb._ == 'photoPathSize') {
+ //if(!doc.w) console.error('no w', doc);
+ div.innerHTML = ``;
+ } else if(toneIndex <= 0) {
+ img = new Image();
+ if((webpWorkerController.isWebpSupported() || doc.pFlags.stickerThumbConverted || thumb.url)/* && false */) {
+ renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true), afterRender);
+ } else {
+ webpWorkerController.convert(doc.id, thumb.bytes as Uint8Array).then(bytes => {
+ thumb.bytes = bytes;
+ doc.pFlags.stickerThumbConverted = true;
+
+ if(middleware && !middleware()) return;
+
+ if(!div.childElementCount) {
+ renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true), afterRender);
+ }
+ }).catch(() => {});
+ }
}
- } else if(stickerType == 2 && (withThumb || onlyThumb)) {
+ } else if(stickerType == 2 && (withThumb || onlyThumb) && toneIndex <= 0) {
img = new Image();
const load = () => {
@@ -637,6 +643,9 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
console.log('loaded sticker:', doc, div);
} */
+ //await new Promise((resolve) => setTimeout(resolve, 500));
+ //return;
+
//console.time('download sticker' + doc.id);
//appDocsManager.downloadDocNew(doc.id).promise.then(res => res.json()).then(async(json) => {
@@ -649,7 +658,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
//console.log('loaded sticker:', doc, div/* , blob */);
if(middleware && !middleware()) return;
- let animation = await LottieLoader.loadAnimationWorker/* loadAnimation */({
+ let animation = await LottieLoader.loadAnimationWorker({
container: div,
loop: loop && !emoji,
autoplay: play,
@@ -661,12 +670,29 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
//const deferred = deferredPromise();
animation.addListener('firstFrame', () => {
- if(div.firstElementChild && div.firstElementChild.tagName == 'IMG') {
- div.firstElementChild.remove();
+ const element = div.firstElementChild;
+ const needFadeIn = !element || element.tagName === 'svg';
+
+ const cb = () => {
+ if(element && element != animation.canvas) {
+ element.remove();
+ }
+ };
+
+ if(!needFadeIn) {
+ cb();
} else {
animation.canvas.classList.add('fade-in');
+
+ if(element) {
+ setTimeout(() => {
+ cb();
+ }, element.tagName === 'svg' ? 50 : 200);
+ }
}
+ appDocsManager.saveLottiePreview(doc, animation.canvas, toneIndex);
+
//deferred.resolve();
}, true);
diff --git a/src/layer.d.ts b/src/layer.d.ts
index d11c3a4a..021bc267 100644
--- a/src/layer.d.ts
+++ b/src/layer.d.ts
@@ -2927,7 +2927,7 @@ export namespace Document {
date: number,
mime_type: string,
size: number,
- thumbs?: Array,
+ thumbs?: Array,
video_thumbs?: Array,
dc_id: number,
attributes: Array,
@@ -2948,6 +2948,7 @@ export namespace Document {
pFlags?: Partial<{
stickerThumbConverted?: true,
}>,
+ stickerCachedThumbs?: {[toneIndex: number]: {url: string, w: number, h: number}},
animated?: boolean,
supportsStreaming?: boolean
};
diff --git a/src/lib/appManagers/appDocsManager.ts b/src/lib/appManagers/appDocsManager.ts
index 99c47bfa..67b5644b 100644
--- a/src/lib/appManagers/appDocsManager.ts
+++ b/src/lib/appManagers/appDocsManager.ts
@@ -1,6 +1,5 @@
import { FileURLType, getFileNameByLocation, getFileURL } from '../../helpers/fileName';
import { safeReplaceArrayInObject, defineNotNumerableProperties, isObject } from '../../helpers/object';
-import { isSafari } from '../../helpers/userAgent';
import { Document, InputFileLocation, PhotoSize } from '../../layer';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';
@@ -16,6 +15,7 @@ export type MyDocument = Document.document;
class AppDocsManager {
private docs: {[docID: string]: MyDocument} = {};
+ private savingLottiePreview: {[docID: string]: true} = {};
public saveDoc(doc: Document, context?: ReferenceContext): MyDocument {
if(doc._ == 'documentEmpty') {
@@ -326,6 +326,66 @@ class AppDocsManager {
return download;
}
+ public saveLottiePreview(doc: MyDocument, canvas: HTMLCanvasElement, toneIndex: number) {
+ const key = doc.id + '-' + toneIndex;
+ if(this.savingLottiePreview[key]/* || true */) return;
+
+ if(!doc.stickerCachedThumbs) {
+ defineNotNumerableProperties(doc, ['stickerCachedThumbs']);
+ doc.stickerCachedThumbs = {};
+ }
+
+ const thumb = doc.stickerCachedThumbs[toneIndex];
+ if(thumb && thumb.w >= canvas.width && thumb.h >= canvas.height) {
+ return;
+ }
+
+ /* if(doc.thumbs.find(t => t._ == 'photoStrippedSize')
+ || (doc.stickerCachedThumb || (doc.stickerSavedThumbWidth >= canvas.width && doc.stickerSavedThumbHeight >= canvas.height))) {
+ return;
+ } */
+
+ this.savingLottiePreview[key] = true;
+ canvas.toBlob((blob) => {
+ //console.log('got lottie preview', doc, blob, URL.createObjectURL(blob));
+
+ const thumb = {
+ url: URL.createObjectURL(blob),
+ w: canvas.width,
+ h: canvas.height
+ };
+
+ doc.stickerCachedThumbs[toneIndex] = thumb;
+
+ delete this.savingLottiePreview[key];
+
+ /* const reader = new FileReader();
+ reader.onloadend = (e) => {
+ const uint8 = new Uint8Array(e.target.result as ArrayBuffer);
+ const thumb: PhotoSize.photoStrippedSize = {
+ _: 'photoStrippedSize',
+ bytes: uint8,
+ type: 'i'
+ };
+
+ doc.stickerSavedThumbWidth = canvas.width;
+ doc.stickerSavedThumbHeight = canvas.width;
+
+ defineNotNumerableProperties(thumb, ['url']);
+ thumb.url = URL.createObjectURL(blob);
+ doc.thumbs.findAndSplice(t => t._ == thumb._);
+ doc.thumbs.unshift(thumb);
+
+ if(!webpWorkerController.isWebpSupported()) {
+ doc.pFlags.stickerThumbConverted = true;
+ }
+
+ delete this.savingLottiePreview[doc.id];
+ };
+ reader.readAsArrayBuffer(blob); */
+ });
+ }
+
public saveDocFile(doc: MyDocument) {
const options = this.getFileDownloadOptions(doc);
return appDownloadManager.downloadToDisc(options, doc.file_name);
diff --git a/src/lib/appManagers/appPhotosManager.ts b/src/lib/appManagers/appPhotosManager.ts
index fe29d173..37ae88e8 100644
--- a/src/lib/appManagers/appPhotosManager.ts
+++ b/src/lib/appManagers/appPhotosManager.ts
@@ -158,6 +158,33 @@ export class AppPhotosManager {
return URL.createObjectURL(blob);
}
+ /**
+ * https://core.telegram.org/api/files#vector-thumbnails
+ */
+ public getPathFromPhotoPathSize(size: PhotoSize.photoPathSize) {
+ const bytes = size.bytes;
+ const lookup = "AACAAAAHAAALMAAAQASTAVAAAZaacaaaahaaalmaaaqastava.az0123456789-,";
+
+ let path = 'M';
+ for(let i = 0, length = bytes.length; i < length; ++i) {
+ const num = bytes[i];
+
+ if(num >= (128 + 64)) {
+ path += lookup[num - 128 - 64];
+ } else {
+ if(num >= 128) {
+ path += ',';
+ } else if(num >= 64) {
+ path += '-';
+ }
+ path += '' + (num & 63);
+ }
+ }
+ path += 'z';
+
+ return path;
+ }
+
public getPreviewURLFromThumb(thumb: PhotoSize.photoCachedSize | PhotoSize.photoStrippedSize, isSticker = false) {
return thumb.url ?? (defineNotNumerableProperties(thumb, ['url']), thumb.url = this.getPreviewURLFromBytes(thumb.bytes, isSticker));
}
diff --git a/src/lib/crypto/cryptoworker.ts b/src/lib/crypto/cryptoworker.ts
index 94837b00..109e2a14 100644
--- a/src/lib/crypto/cryptoworker.ts
+++ b/src/lib/crypto/cryptoworker.ts
@@ -1,3 +1,4 @@
+import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import CryptoWorkerMethods from './crypto_methods';
type Task = {
@@ -124,5 +125,6 @@ class CryptoWorker extends CryptoWorkerMethods {
}
const cryptoWorker = new CryptoWorker();
+MOUNT_CLASS_TO && (MOUNT_CLASS_TO.CryptoWorker = cryptoWorker);
//(window as any).CryptoWorker = cryptoWorker;
export default cryptoWorker;
diff --git a/src/scripts/in/schema_additional_params.json b/src/scripts/in/schema_additional_params.json
index f4ba7da3..2021f937 100644
--- a/src/scripts/in/schema_additional_params.json
+++ b/src/scripts/in/schema_additional_params.json
@@ -1,7 +1,7 @@
[{
"predicate": "document",
"params": [
- {"name": "thumbs", "type": "Array"},
+ {"name": "thumbs", "type": "Array"},
{"name": "type", "type": "'gif' | 'sticker' | 'audio' | 'voice' | 'video' | 'round' | 'photo'"},
{"name": "h", "type": "number"},
{"name": "w", "type": "number"},
@@ -17,6 +17,7 @@
{"name": "stickerEmojiRaw", "type": "string"},
{"name": "stickerSetInput", "type": "InputStickerSet.inputStickerSetID"},
{"name": "stickerThumbConverted", "type": "true"},
+ {"name": "stickerCachedThumbs", "type": "{[toneIndex: number]: {url: string, w: number, h: number}}"},
{"name": "animated", "type": "boolean"},
{"name": "supportsStreaming", "type": "boolean"}
]
diff --git a/src/scss/partials/popups/_stickers.scss b/src/scss/partials/popups/_stickers.scss
index cf05c82c..7db0e81e 100644
--- a/src/scss/partials/popups/_stickers.scss
+++ b/src/scss/partials/popups/_stickers.scss
@@ -65,6 +65,7 @@
margin-bottom: 2px;
justify-self: center;
cursor: pointer;
+ position: relative;
@include respond-to(handhelds) {
margin-bottom: 8px;
@@ -78,6 +79,8 @@
img {
max-width: 100%;
max-height: 100%;
+ width: 100%;
+ height: 100%;
}
}
}
diff --git a/src/scss/style.scss b/src/scss/style.scss
index c25c298d..6b6edee9 100644
--- a/src/scss/style.scss
+++ b/src/scss/style.scss
@@ -699,15 +699,21 @@ img.emoji {
pointer-events: none;
}
-.rlottie {
+.rlottie, .rlottie-vector {
+ position: absolute;
max-width: 100%;
max-height: 100%;
width: 100%;
height: 100%;
+ z-index: 1;
+}
- &.fade-in {
- animation: fade-in-opacity .2s ease forwards;
- }
+.rlottie.fade-in {
+ animation: fade-in-opacity .2s ease forwards;
+}
+
+.rlottie-vector {
+ fill: rgba(0, 0, 0, .08);
}
.fade-in-transition {