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.
 
 
 
 
 

370 lines
11 KiB

/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import emoticonsDropdown, { EmoticonsDropdown, EMOTICONSSTICKERGROUP, EmoticonsTab } from "..";
import { readBlobAsText } from "../../../helpers/blob";
import renderImageFromUrl from "../../../helpers/dom/renderImageFromUrl";
import mediaSizes from "../../../helpers/mediaSizes";
import { MessagesAllStickers, StickerSet } from "../../../layer";
import appDocsManager, { MyDocument } from "../../../lib/appManagers/appDocsManager";
import appDownloadManager from "../../../lib/appManagers/appDownloadManager";
import appStickersManager from "../../../lib/appManagers/appStickersManager";
import lottieLoader from "../../../lib/lottieLoader";
import { RichTextProcessor } from "../../../lib/richtextprocessor";
import rootScope from "../../../lib/rootScope";
import animationIntersector from "../../animationIntersector";
import LazyLoadQueue, { LazyLoadQueueRepeat } from "../../lazyLoadQueue";
import { putPreloader } from "../../misc";
import Scrollable, { ScrollableX } from "../../scrollable";
import StickyIntersector from "../../stickyIntersector";
import { wrapSticker } from "../../wrappers";
export class SuperStickerRenderer {
lazyLoadQueue: LazyLoadQueueRepeat;
animatedDivs: Set<HTMLDivElement> = new Set();
constructor(private regularLazyLoadQueue: LazyLoadQueue, private group: string) {
this.lazyLoadQueue = new LazyLoadQueueRepeat(undefined, (target, visible) => {
if(!visible) {
this.processInvisibleDiv(target as HTMLDivElement);
}
});
}
renderSticker(doc: MyDocument, div?: HTMLDivElement, loadPromises?: Promise<any>[]) {
if(!div) {
div = document.createElement('div');
div.classList.add('grid-item', 'super-sticker');
if(doc.sticker === 2) {
this.animatedDivs.add(div);
this.lazyLoadQueue.observe({
div,
load: this.processVisibleDiv
});
}
}
// * This will wrap only a thumb
wrapSticker({
doc,
div,
lazyLoadQueue: this.regularLazyLoadQueue,
group: this.group,
onlyThumb: doc.sticker === 2,
loadPromises
});
return div;
}
checkAnimationContainer = (div: HTMLElement, visible: boolean) => {
//console.error('checkAnimationContainer', div, visible);
const players = animationIntersector.getAnimations(div);
players.forEach(player => {
if(!visible) {
animationIntersector.checkAnimation(player, true, true);
} else {
animationIntersector.checkAnimation(player, false);
}
});
};
processVisibleDiv = (div: HTMLElement) => {
const docId = div.dataset.docId;
const doc = appDocsManager.getDoc(docId);
const size = mediaSizes.active.esgSticker.width;
//console.log('processVisibleDiv:', div);
const promise = wrapSticker({
doc,
div: div as HTMLDivElement,
width: size,
height: size,
lazyLoadQueue: null,
group: this.group,
onlyThumb: false,
play: true,
loop: true
});
promise.then(() => {
//clearTimeout(timeout);
this.checkAnimationContainer(div, this.lazyLoadQueue.intersector.isVisible(div));
});
/* let timeout = window.setTimeout(() => {
console.error('processVisibleDiv timeout', div, doc);
}, 1e3); */
return promise;
};
processInvisibleDiv = (div: HTMLElement) => {
const docId = div.dataset.docId;
const doc = appDocsManager.getDoc(docId);
//console.log('STICKER INvisible:', /* div, */docId);
this.checkAnimationContainer(div, false);
div.innerHTML = '';
this.renderSticker(doc, div as HTMLDivElement);
};
}
export default class StickersTab implements EmoticonsTab {
public content: HTMLElement;
private stickersDiv: HTMLElement;
private stickerSets: {[id: string]: {
stickers: HTMLElement,
tab: HTMLElement
}} = {};
private recentDiv: HTMLElement;
private recentStickers: MyDocument[] = [];
private scroll: Scrollable;
private menu: HTMLElement;
private mounted = false;
private queueCategoryPush: {element: HTMLElement, prepend: boolean}[] = [];
private stickyIntersector: StickyIntersector;
private superStickerRenderer: SuperStickerRenderer;
categoryPush(categoryDiv: HTMLElement, categoryTitle: string, promise: Promise<MyDocument[]>, prepend?: boolean) {
//if((docs.length % 5) !== 0) categoryDiv.classList.add('not-full');
const itemsDiv = document.createElement('div');
itemsDiv.classList.add('category-items', 'super-stickers');
const titleDiv = document.createElement('div');
titleDiv.classList.add('category-title');
titleDiv.innerHTML = categoryTitle;
categoryDiv.append(titleDiv, itemsDiv);
this.stickyIntersector.observeStickyHeaderChanges(categoryDiv);
this.queueCategoryPush.push({element: categoryDiv, prepend});
promise.then(documents => {
documents.forEach(doc => {
//if(doc._ === 'documentEmpty') return;
itemsDiv.append(this.superStickerRenderer.renderSticker(doc));
});
if(this.queueCategoryPush.length) {
this.queueCategoryPush.forEach(({element, prepend}) => {
if(prepend) {
if(this.recentDiv.parentElement) {
this.stickersDiv.prepend(element);
this.stickersDiv.prepend(this.recentDiv);
} else {
this.stickersDiv.prepend(element);
}
} else this.stickersDiv.append(element);
});
this.queueCategoryPush.length = 0;
}
});
}
async renderStickerSet(set: StickerSet.stickerSet, prepend = false) {
const categoryDiv = document.createElement('div');
categoryDiv.classList.add('sticker-category');
const button = document.createElement('button');
button.classList.add('btn-icon', 'menu-horizontal-div-item');
this.stickerSets[set.id] = {
stickers: categoryDiv,
tab: button
};
if(prepend) {
this.menu.insertBefore(button, this.menu.firstElementChild.nextSibling);
} else {
this.menu.append(button);
}
//stickersScroll.append(categoryDiv);
const promise = appStickersManager.getStickerSet(set);
this.categoryPush(categoryDiv, RichTextProcessor.wrapEmojiText(set.title), promise.then(stickerSet => stickerSet.documents as MyDocument[]), prepend);
const stickerSet = await promise;
//console.log('got stickerSet', stickerSet, li);
if(stickerSet.set.thumbs?.length) {
const downloadOptions = appStickersManager.getStickerSetThumbDownloadOptions(stickerSet.set);
const promise = appDownloadManager.download(downloadOptions);
if(stickerSet.set.pFlags.animated) {
promise
.then(readBlobAsText)
//.then(JSON.parse)
.then(json => {
lottieLoader.loadAnimationWorker({
container: button,
loop: true,
autoplay: false,
animationData: json,
width: 32,
height: 32,
needUpscale: true
}, EMOTICONSSTICKERGROUP);
});
} else {
const image = new Image();
promise.then(blob => {
renderImageFromUrl(image, URL.createObjectURL(blob), () => {
button.append(image);
});
});
}
} else if(stickerSet.documents[0]._ !== 'documentEmpty') { // as thumb will be used first sticker
wrapSticker({
doc: stickerSet.documents[0],
div: button as any,
group: EMOTICONSSTICKERGROUP
}); // kostil
}
}
init() {
this.content = document.getElementById('content-stickers');
//let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;
this.recentDiv = document.createElement('div');
this.recentDiv.classList.add('sticker-category');
let menuWrapper = this.content.previousElementSibling as HTMLDivElement;
this.menu = menuWrapper.firstElementChild as HTMLUListElement;
let menuScroll = new ScrollableX(menuWrapper);
this.stickersDiv = document.createElement('div');
this.stickersDiv.classList.add('stickers-categories');
this.content.append(this.stickersDiv);
/* stickersDiv.addEventListener('mouseover', (e) => {
let target = e.target as HTMLElement;
if(target.tagName === 'CANVAS') { // turn on sticker
let animation = lottieLoader.getAnimation(target.parentElement, EMOTICONSSTICKERGROUP);
if(animation) {
// @ts-ignore
if(animation.currentFrame === animation.totalFrames - 1) {
animation.goToAndPlay(0, true);
} else {
animation.play();
}
}
}
}); */
rootScope.on('stickers_installed', (e) => {
const set: StickerSet.stickerSet = e;
if(!this.stickerSets[set.id] && this.mounted) {
this.renderStickerSet(set, true);
}
});
rootScope.on('stickers_deleted', (e) => {
const set: StickerSet.stickerSet = e;
if(this.stickerSets[set.id] && this.mounted) {
const elements = this.stickerSets[set.id];
elements.stickers.remove();
elements.tab.remove();
delete this.stickerSets[set.id];
}
});
this.stickersDiv.addEventListener('click', EmoticonsDropdown.onMediaClick);
this.scroll = new Scrollable(this.content, 'STICKERS');
this.scroll.setVirtualContainer(this.stickersDiv);
this.stickyIntersector = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll);
const preloader = putPreloader(this.content, true);
Promise.all([
appStickersManager.getRecentStickers().then(stickers => {
this.recentStickers = stickers.stickers.slice(0, 20) as MyDocument[];
//stickersScroll.prepend(categoryDiv);
this.stickerSets['recent'] = {
stickers: this.recentDiv,
tab: this.menu.firstElementChild as HTMLElement
};
preloader.remove();
this.categoryPush(this.recentDiv, 'Recent', Promise.resolve(this.recentStickers), true);
}),
appStickersManager.getAllStickers().then((res) => {
preloader.remove();
for(let set of (res as MessagesAllStickers.messagesAllStickers).sets) {
this.renderStickerSet(set);
}
})
]).finally(() => {
this.mounted = true;
});
this.superStickerRenderer = new SuperStickerRenderer(EmoticonsDropdown.lazyLoadQueue, EMOTICONSSTICKERGROUP);
emoticonsDropdown.addLazyLoadQueueRepeat(this.superStickerRenderer.lazyLoadQueue, this.superStickerRenderer.processInvisibleDiv);
/* setInterval(() => {
// @ts-ignore
const players = Object.values(lottieLoader.players).filter(p => p.width === 80);
console.log('STICKERS RENDERED IN PANEL:', players.length, players.filter(p => !p.paused).length, this.superStickerRenderer.lazyLoadQueue.intersector.getVisible().length);
}, .25e3); */
this.init = null;
}
pushRecentSticker(doc: MyDocument) {
if(!this.recentDiv?.parentElement) {
return;
}
let div = this.recentDiv.querySelector(`[data-doc-id="${doc.id}"]`);
if(!div) {
div = this.superStickerRenderer.renderSticker(doc);
}
const items = this.recentDiv.querySelector('.category-items');
items.prepend(div);
if(items.childElementCount > 20) {
(Array.from(items.children) as HTMLElement[]).slice(20).forEach(el => el.remove());
}
}
onClose() {
}
}