import type { FC } from '../../lib/teact/teact'; import React, { memo, useCallback, useEffect, useLayoutEffect, useRef, } from '../../lib/teact/teact'; import { getActions, withGlobal } from '../../global'; import type { ActiveEmojiInteraction } from '../../global/types'; import { IS_ANDROID } from '../../util/windowEnvironment'; import useFlag from '../../hooks/useFlag'; import useMedia from '../../hooks/useMedia'; import buildClassName from '../../util/buildClassName'; import { selectAnimatedEmojiEffect, } from '../../global/selectors'; import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck'; import AnimatedSticker from '../common/AnimatedSticker'; import './EmojiInteractionAnimation.scss'; export type OwnProps = { activeEmojiInteraction: ActiveEmojiInteraction; }; type StateProps = { effectAnimationId?: string; }; const HIDE_ANIMATION_DURATION = 250; const PLAYING_DURATION = 3000; const EFFECT_SIZE = 309; const EmojiInteractionAnimation: FC = ({ effectAnimationId, activeEmojiInteraction, }) => { const { stopActiveEmojiInteraction } = getActions(); const [isHiding, startHiding] = useFlag(false); const [isPlaying, startPlaying] = useFlag(false); const timeoutRef = useRef(); const stop = useCallback(() => { startHiding(); if (timeoutRef.current) { clearTimeout(timeoutRef.current); } setTimeout(() => { stopActiveEmojiInteraction({ id: activeEmojiInteraction.id }); }, HIDE_ANIMATION_DURATION); }, [activeEmojiInteraction.id, startHiding, stopActiveEmojiInteraction]); const handleCancelAnimation = useCallback((e: UIEvent) => { if (!(e.target as HTMLElement)?.closest('.AnimatedEmoji')) { stop(); } }, [stop]); useEffect(() => { document.addEventListener('touchstart', handleCancelAnimation); document.addEventListener('touchmove', handleCancelAnimation); document.addEventListener('mousedown', handleCancelAnimation); document.addEventListener('wheel', handleCancelAnimation); return () => { document.removeEventListener('touchstart', handleCancelAnimation); document.removeEventListener('touchmove', handleCancelAnimation); document.removeEventListener('mousedown', handleCancelAnimation); document.removeEventListener('wheel', handleCancelAnimation); }; }, [handleCancelAnimation]); useLayoutEffect(() => { const dispatchHeavyAnimationStop = dispatchHeavyAnimationEvent(); timeoutRef.current = setTimeout(() => { stop(); dispatchHeavyAnimationStop(); }, PLAYING_DURATION); }, [stop]); const effectHash = effectAnimationId && `sticker${effectAnimationId}`; const effectTgsUrl = useMedia(effectHash, !effectAnimationId); if (!activeEmojiInteraction.startSize) { return undefined; } const scale = (activeEmojiInteraction.startSize || 0) / EFFECT_SIZE; return (
); }; export default memo(withGlobal( (global, { activeEmojiInteraction }): StateProps => { const animatedEffect = activeEmojiInteraction.animatedEffect !== undefined && selectAnimatedEmojiEffect(global, activeEmojiInteraction.animatedEffect); return { effectAnimationId: animatedEffect ? animatedEffect.id : undefined, }; }, )(EmojiInteractionAnimation));