-
Notifications
You must be signed in to change notification settings - Fork 661
/
Copy pathuseHeavyAnimationCheck.ts
107 lines (86 loc) · 3.1 KB
/
useHeavyAnimationCheck.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
// * Jolly Cobra's useHeavyAnimationCheck.ts, patched
import {AnyToVoidFunction} from '../types';
import ListenerSetter from '../helpers/listenerSetter';
import deferredPromise, {CancellablePromise} from '../helpers/cancellablePromise';
import DEBUG from '../config/debug';
import pause from '../helpers/schedulers/pause';
import EventListenerBase from '../helpers/eventListenerBase';
const eventListener = new EventListenerBase<{
start: () => void,
end: () => void
}>();
const ANIMATION_START_EVENT = 'start';
const ANIMATION_END_EVENT = 'end';
let isAnimating = false;
let heavyAnimationPromise: CancellablePromise<void> = deferredPromise<void>();
let promisesInQueue = 0;
heavyAnimationPromise.resolve();
const log = console.log.bind(console.log, '[HEAVY-ANIMATION]:');
export function dispatchHeavyAnimationEvent(promise: Promise<any>, timeout?: number) {
if(!isAnimating) {
heavyAnimationPromise = deferredPromise<void>();
eventListener.dispatchEvent(ANIMATION_START_EVENT);
isAnimating = true;
DEBUG && log('start');
}
++promisesInQueue;
DEBUG && log('attach promise, length:', promisesInQueue, timeout);
const promises = [
timeout !== undefined ? pause(timeout) : undefined,
promise.finally(() => {})
].filter(Boolean);
const perf = performance.now();
const _heavyAnimationPromise = heavyAnimationPromise;
Promise.race(promises).then(() => {
if(heavyAnimationPromise !== _heavyAnimationPromise || heavyAnimationPromise.isFulfilled) { // interrupted
return;
}
--promisesInQueue;
DEBUG && log('promise end, length:', promisesInQueue, performance.now() - perf);
if(promisesInQueue <= 0) {
onHeavyAnimationEnd();
}
});
return heavyAnimationPromise;
}
(window as any).dispatchHeavyAnimationEvent = dispatchHeavyAnimationEvent;
function onHeavyAnimationEnd() {
if(heavyAnimationPromise.isFulfilled) {
return;
}
isAnimating = false;
promisesInQueue = 0;
eventListener.dispatchEvent(ANIMATION_END_EVENT);
heavyAnimationPromise.resolve();
DEBUG && log('end');
}
export function interruptHeavyAnimation() {
onHeavyAnimationEnd();
}
export function getHeavyAnimationPromise() {
return heavyAnimationPromise;
}
export default function(
handleAnimationStart: AnyToVoidFunction,
handleAnimationEnd: AnyToVoidFunction,
listenerSetter?: ListenerSetter
) {
// useEffect(() => {
if(isAnimating) {
handleAnimationStart();
}
const add = listenerSetter ? listenerSetter.add(eventListener) : eventListener.addEventListener.bind(eventListener);
const remove = listenerSetter ? listenerSetter.removeManual.bind(listenerSetter, eventListener) : eventListener.removeEventListener.bind(eventListener);
add(ANIMATION_START_EVENT, handleAnimationStart);
add(ANIMATION_END_EVENT, handleAnimationEnd);
return () => {
remove(ANIMATION_END_EVENT, handleAnimationEnd);
remove(ANIMATION_START_EVENT, handleAnimationStart);
};
// }, [handleAnimationEnd, handleAnimationStart]);
}