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.

211 lines
5.9 KiB

3 years ago
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
2 years ago
import type {MyDocument} from '../lib/appManagers/appDocsManager';
import {wrapVideo} from './wrappers';
import animationIntersector, {AnimationItemGroup} from './animationIntersector';
2 years ago
import Scrollable from './scrollable';
import deferredPromise, {CancellablePromise} from '../helpers/cancellablePromise';
import calcImageInBox from '../helpers/calcImageInBox';
import {doubleRaf} from '../helpers/schedulers';
import {AppManagers} from '../lib/appManagers/managers';
import rootScope from '../lib/rootScope';
import LazyLoadQueueRepeat2 from './lazyLoadQueueRepeat2';
3 years ago
const width = 400;
const maxSingleWidth = width - 100;
const height = 100;
export default class GifsMasonry {
public lazyLoadQueue: LazyLoadQueueRepeat2;
private scrollPromise: CancellablePromise<void> = Promise.resolve();
private timeout: number = 0;
3 years ago
private managers: AppManagers;
constructor(
2 years ago
private element: HTMLElement,
private group: AnimationItemGroup,
2 years ago
private scrollable: Scrollable,
3 years ago
attach = true
) {
this.managers = rootScope.managers;
3 years ago
this.lazyLoadQueue = new LazyLoadQueueRepeat2(undefined, ({target, visible}) => {
3 years ago
if(visible) {
this.processVisibleDiv(target);
} else {
this.processInvisibleDiv(target);
}
});
/* setInterval(() => {
// @ts-ignore
const players = animationIntersector.byGroups[group];
if(players) {
console.log(`GIFS RENDERED IN ${group}:`, players.length, players.filter((p) => !p.animation.paused).length, this.lazyLoadQueue.intersector.getVisible().length);
3 years ago
}
}, .25e3); */
if(attach) {
this.attach();
}
}
2 years ago
3 years ago
private onScroll = () => {
if(this.timeout) {
clearTimeout(this.timeout);
} else {
this.scrollPromise = deferredPromise<void>();
2 years ago
// animationIntersector.checkAnimations(true, group);
3 years ago
}
this.timeout = window.setTimeout(() => {
this.timeout = 0;
this.scrollPromise.resolve();
2 years ago
// animationIntersector.checkAnimations(false, group);
3 years ago
}, 150);
};
public attach() {
this.scrollable.container.addEventListener('scroll', this.onScroll);
}
public detach() {
this.clear();
this.scrollable.container.removeEventListener('scroll', this.onScroll);
}
public clear() {
this.lazyLoadQueue.clear();
}
private processVisibleDiv(div: HTMLElement) {
const video = div.querySelector('video');
if(video) {
return;
}
const load = () => {
const docId = div.dataset.docId;
const promise = Promise.all([this.managers.appDocsManager.getDoc(docId), this.scrollPromise]).then(async([doc]) => {
const res = await wrapVideo({
3 years ago
doc,
container: div as HTMLDivElement,
lazyLoadQueue: null,
2 years ago
// lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,
3 years ago
group: this.group,
2 years ago
noInfo: true,
noPreview: true
3 years ago
});
2 years ago
3 years ago
const promise = res.loadPromise;
promise.finally(() => {
const video = div.querySelector('video');
2 years ago
const thumb = div.querySelector('img, canvas');
3 years ago
2 years ago
// div.style.opacity = '';
thumb && thumb.classList.add('hide');
3 years ago
if(video && !video.parentElement) {
setTimeout(() => {
video.src = '';
video.load();
const animations = animationIntersector.getAnimations(video);
animations.forEach((item) => {
3 years ago
animationIntersector.checkAnimation(item, true, true);
});
}, 0);
}
2 years ago
// clearTimeout(timeout);
3 years ago
if(!this.lazyLoadQueue.intersector.isVisible(div)) {
this.processInvisibleDiv(div);
}
});
return promise;
});
/* let timeout = window.setTimeout(() => {
console.error('processVisibleDiv timeout', div, doc);
}, 1e3); */
return promise;
};
2 years ago
// return load();
3 years ago
this.lazyLoadQueue.push({div, load});
}
public processInvisibleDiv = (div: HTMLElement) => {
return this.scrollPromise.then(async() => {
2 years ago
// return;
3 years ago
if(this.lazyLoadQueue.intersector.isVisible(div)) {
return;
}
const video = div.querySelector('video');
2 years ago
const thumb = div.querySelector('img, canvas');
2 years ago
2 years ago
if(thumb) {
thumb.classList.remove('hide');
2 years ago
3 years ago
await doubleRaf();
}
if(this.lazyLoadQueue.intersector.isVisible(div)) {
return;
}
2 years ago
3 years ago
if(video) {
video.remove();
video.src = '';
video.load();
const animations = animationIntersector.getAnimations(video);
animations.forEach((item) => {
3 years ago
animationIntersector.checkAnimation(item, true, true);
});
}
});
};
public add(doc: MyDocument, appendTo = this.element) {
let gifWidth = doc.w;
let gifHeight = doc.h;
if(gifHeight < height) {
gifWidth = height / gifHeight * gifWidth;
gifHeight = height;
}
const willUseWidth = Math.min(maxSingleWidth, width, gifWidth);
const size = calcImageInBox(gifWidth, gifHeight, willUseWidth, height);
const div = document.createElement('div');
2 years ago
div.classList.add('gif'/* , 'fade-in-transition' */);
3 years ago
div.style.width = size.width + 'px';
2 years ago
// div.style.opacity = '0';
2 years ago
// div.style.height = h + 'px';
3 years ago
div.dataset.docId = '' + doc.id;
3 years ago
appendTo.append(div);
this.lazyLoadQueue.observe(div);
2 years ago
// let preloader = new ProgressivePreloader(div);
3 years ago
2 years ago
wrapVideo({
doc,
container: div as HTMLDivElement,
lazyLoadQueue: null,
noInfo: true,
onlyPreview: true
});
3 years ago
}
}