Animated sticker panel
Fix lazyLoadQueue for panel
This commit is contained in:
parent
369536b9b7
commit
be8976e0d9
@ -50,16 +50,17 @@ export class AnimationIntersector {
|
||||
});
|
||||
}
|
||||
|
||||
public getAnimation(element: HTMLElement) {
|
||||
for(let group in this.byGroups) {
|
||||
for(let player of this.byGroups[group]) {
|
||||
public getAnimations(element: HTMLElement) {
|
||||
const found: AnimationItem[] = [];
|
||||
for(const group in this.byGroups) {
|
||||
for(const player of this.byGroups[group]) {
|
||||
if(player.el == element) {
|
||||
return player;
|
||||
found.push(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return found;
|
||||
}
|
||||
|
||||
public addAnimation(animation: RLottiePlayer | HTMLVideoElement, group = '') {
|
||||
|
@ -40,6 +40,18 @@ export class EmoticonsDropdown {
|
||||
public toggleEl: HTMLElement;
|
||||
private displayTimeout: number;
|
||||
|
||||
public events: {
|
||||
onClose: Array<() => void>,
|
||||
onCloseAfter: Array<() => void>,
|
||||
onOpen: Array<() => void>,
|
||||
onOpenAfter: Array<() => void>
|
||||
} = {
|
||||
onClose: [],
|
||||
onCloseAfter: [],
|
||||
onOpen: [],
|
||||
onOpenAfter: []
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.element = document.getElementById('emoji-dropdown') as HTMLDivElement;
|
||||
|
||||
@ -174,26 +186,30 @@ export class EmoticonsDropdown {
|
||||
}
|
||||
|
||||
if((this.element.style.display && enable === undefined) || enable) {
|
||||
this.element.style.display = '';
|
||||
void this.element.offsetLeft; // reflow
|
||||
this.element.classList.add('active');
|
||||
this.events.onOpen.forEach(cb => cb());
|
||||
|
||||
EmoticonsDropdown.lazyLoadQueue.lockIntersection();
|
||||
//EmoticonsDropdown.lazyLoadQueue.unlock();
|
||||
animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
||||
|
||||
this.element.style.display = '';
|
||||
void this.element.offsetLeft; // reflow
|
||||
this.element.classList.add('active');
|
||||
|
||||
clearTimeout(this.displayTimeout);
|
||||
this.displayTimeout = setTimeout(() => {
|
||||
animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
||||
EmoticonsDropdown.lazyLoadQueue.unlockIntersection();
|
||||
|
||||
this.events.onOpenAfter.forEach(cb => cb());
|
||||
}, touchSupport ? 0 : 200);
|
||||
|
||||
/* if(touchSupport) {
|
||||
this.restoreScroll();
|
||||
} */
|
||||
} else {
|
||||
this.element.classList.remove('active');
|
||||
|
||||
this.events.onClose.forEach(cb => cb());
|
||||
|
||||
EmoticonsDropdown.lazyLoadQueue.lockIntersection();
|
||||
//EmoticonsDropdown.lazyLoadQueue.lock();
|
||||
|
||||
@ -201,14 +217,17 @@ export class EmoticonsDropdown {
|
||||
animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
||||
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||
|
||||
this.element.classList.remove('active');
|
||||
|
||||
clearTimeout(this.displayTimeout);
|
||||
this.displayTimeout = setTimeout(() => {
|
||||
this.element.style.display = 'none';
|
||||
|
||||
// теперь можно убрать visible, чтобы они не включились после фокуса
|
||||
animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
||||
|
||||
EmoticonsDropdown.lazyLoadQueue.unlockIntersection();
|
||||
|
||||
this.events.onCloseAfter.forEach(cb => cb());
|
||||
}, touchSupport ? 0 : 200);
|
||||
|
||||
/* if(touchSupport) {
|
||||
@ -291,7 +310,9 @@ export class EmoticonsDropdown {
|
||||
|
||||
if(!target) return;
|
||||
|
||||
let fileID = target.dataset.docID;
|
||||
const fileID = target.dataset.docID;
|
||||
if(!fileID) return;
|
||||
|
||||
if(appImManager.chatInputC.sendMessageWithDocument(fileID)) {
|
||||
/* dropdown.classList.remove('active');
|
||||
toggleEl.classList.remove('active'); */
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { EmoticonsTab, EMOTICONSSTICKERGROUP, EmoticonsDropdown } from "..";
|
||||
import emoticonsDropdown, { EmoticonsTab, EMOTICONSSTICKERGROUP, EmoticonsDropdown } from "..";
|
||||
import { MTDocument } from "../../../types";
|
||||
import Scrollable from "../../scrollable_new";
|
||||
import { wrapSticker } from "../../wrappers";
|
||||
@ -11,6 +11,8 @@ import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
||||
import { $rootScope } from "../../../lib/utils";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import StickyIntersector from "../../stickyIntersector";
|
||||
import appDocsManager from "../../../lib/appManagers/appDocsManager";
|
||||
import animationIntersector from "../../animationIntersector";
|
||||
|
||||
export default class StickersTab implements EmoticonsTab {
|
||||
public content: HTMLElement;
|
||||
@ -33,6 +35,9 @@ export default class StickersTab implements EmoticonsTab {
|
||||
|
||||
private stickyIntersector: StickyIntersector;
|
||||
|
||||
private animatedDivs: Set<HTMLDivElement> = new Set();
|
||||
private animatedIntersector: IntersectionObserver;
|
||||
|
||||
categoryPush(categoryDiv: HTMLElement, categoryTitle: string, promise: Promise<MTDocument[]>, prepend?: boolean) {
|
||||
//if((docs.length % 5) != 0) categoryDiv.classList.add('not-full');
|
||||
|
||||
@ -71,8 +76,16 @@ export default class StickersTab implements EmoticonsTab {
|
||||
});
|
||||
}
|
||||
|
||||
renderSticker(doc: MTDocument) {
|
||||
const div = document.createElement('div');
|
||||
renderSticker(doc: MTDocument, div?: HTMLDivElement) {
|
||||
if(!div) {
|
||||
div = document.createElement('div');
|
||||
|
||||
if(doc.sticker == 2) {
|
||||
this.animatedDivs.add(div);
|
||||
this.animatedIntersector.observe(div);
|
||||
}
|
||||
}
|
||||
|
||||
wrapSticker({
|
||||
doc,
|
||||
div,
|
||||
@ -242,6 +255,101 @@ export default class StickersTab implements EmoticonsTab {
|
||||
this.mounted = true;
|
||||
});
|
||||
|
||||
const checkAnimationDiv = (div: HTMLDivElement) => {
|
||||
const players = animationIntersector.getAnimations(div);
|
||||
players.forEach(player => {
|
||||
if(!visible.has(div)) {
|
||||
animationIntersector.checkAnimation(player, true, true);
|
||||
} else {
|
||||
animationIntersector.checkAnimation(player, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const processInvisibleDiv = (div: HTMLDivElement) => {
|
||||
visible.delete(div);
|
||||
//console.log('STICKER INvisible:', target, docID);
|
||||
|
||||
const docID = div.dataset.docID;
|
||||
const doc = appDocsManager.getDoc(docID);
|
||||
|
||||
checkAnimationDiv(div);
|
||||
|
||||
div.innerHTML = '';
|
||||
this.renderSticker(doc, div);
|
||||
};
|
||||
|
||||
let locked = false;
|
||||
const visible: Set<HTMLDivElement> = new Set();
|
||||
this.animatedIntersector = new IntersectionObserver((entries) => {
|
||||
if(locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
entries.forEach(entry => {
|
||||
const {target, isIntersecting} = entry;
|
||||
|
||||
const div = target as HTMLDivElement;
|
||||
const docID = div.dataset.docID;
|
||||
const doc = appDocsManager.getDoc(docID);
|
||||
if(isIntersecting) {
|
||||
//console.log('STICKER visible:', target, docID);
|
||||
if(visible.has(div)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visible.add(div);
|
||||
|
||||
wrapSticker({
|
||||
doc,
|
||||
div,
|
||||
width: 80,
|
||||
height: 80,
|
||||
lazyLoadQueue: null,
|
||||
group: EMOTICONSSTICKERGROUP,
|
||||
onlyThumb: false,
|
||||
play: true,
|
||||
loop: true
|
||||
}).then(() => {
|
||||
checkAnimationDiv(div);
|
||||
});
|
||||
} else {
|
||||
processInvisibleDiv(div);
|
||||
}
|
||||
});
|
||||
|
||||
//animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP, false);
|
||||
});
|
||||
|
||||
emoticonsDropdown.events.onClose.push(() => {
|
||||
locked = true;
|
||||
});
|
||||
|
||||
emoticonsDropdown.events.onCloseAfter.push(() => {
|
||||
const divs = [...visible];
|
||||
|
||||
for(const div of divs) {
|
||||
processInvisibleDiv(div);
|
||||
}
|
||||
});
|
||||
|
||||
emoticonsDropdown.events.onOpenAfter.push(() => {
|
||||
locked = false;
|
||||
|
||||
// refresh
|
||||
this.animatedIntersector.disconnect();
|
||||
const divs = [...this.animatedDivs];
|
||||
for(const div of divs) {
|
||||
this.animatedIntersector.observe(div);
|
||||
}
|
||||
});
|
||||
|
||||
/* setInterval(() => {
|
||||
// @ts-ignore
|
||||
console.log('STICKERS RENDERED IN PANEL:', Object.values(lottieLoader.players).filter(p => p.width == 80).length);
|
||||
}, .25e3); */
|
||||
|
||||
|
||||
this.init = null;
|
||||
}
|
||||
|
||||
@ -255,7 +363,7 @@ export default class StickersTab implements EmoticonsTab {
|
||||
div = this.renderSticker(doc);
|
||||
}
|
||||
|
||||
const items = this.recentDiv.lastElementChild;
|
||||
const items = this.recentDiv.querySelector('.category-items');
|
||||
items.prepend(div);
|
||||
|
||||
if(items.childElementCount > 20) {
|
||||
|
@ -24,7 +24,7 @@ export default class LazyLoadQueue {
|
||||
if(noObserver) return;
|
||||
|
||||
this.observer = new IntersectionObserver(entries => {
|
||||
if(this.lockPromise) return;
|
||||
if(this.lockPromise || this.intersectionLocked) return;
|
||||
|
||||
const intersecting = entries.filter(entry => entry.isIntersecting);
|
||||
intersecting.forEachReverse(entry => {
|
||||
|
@ -578,7 +578,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
||||
|
||||
//appDocsManager.downloadDocNew(doc.id).promise.then(res => res.json()).then(async(json) => {
|
||||
//fetch(doc.url).then(res => res.json()).then(async(json) => {
|
||||
appDocsManager.downloadDocNew(doc.id)
|
||||
await appDocsManager.downloadDocNew(doc.id)
|
||||
.then(readBlobAsText)
|
||||
.then(JSON.parse)
|
||||
.then(async(json) => {
|
||||
|
Loading…
Reference in New Issue
Block a user