import type { FC } from '../../../../lib/teact/teact'; import React, { memo, useCallback, useEffect, useRef, useState, } from '../../../../lib/teact/teact'; import { withGlobal } from '../../../../global'; import type { GlobalState } from '../../../../global/types'; import type { ApiSticker } from '../../../../api/types'; import cycleRestrict from '../../../../util/cycleRestrict'; import useMedia from '../../../../hooks/useMedia'; import useFlag from '../../../../hooks/useFlag'; import AnimatedSticker from '../../../common/AnimatedSticker'; import styles from './PremiumFeaturePreviewStickers.module.scss'; type OwnProps = { isActive: boolean; }; type StateProps = { stickers: GlobalState['stickers']['premium']['stickers']; }; const EMOJI_SIZE_MULTIPLIER = 0.6; const EFFECT_SIZE_MULTIPLIER = 0.8; const MAX_EMOJIS = 15; const ENDED_DELAY = 150; const AnimatedCircleSticker: FC<{ size: number; realIndex: number; sticker: ApiSticker; index: number; maxLength: number; onClick: (index: number) => void; onEnded: NoneToVoidFunction; canPlay: boolean; }> = ({ size, realIndex, canPlay, sticker, index, maxLength, onClick, onEnded, }) => { const mediaData = useMedia(`sticker${sticker.id}`); const mediaDataAround = useMedia(`sticker${sticker.id}?size=f`); const isActivated = index === 0; const [isAnimated, animate, inanimate] = useFlag(isActivated); const circleSize = size - size * EMOJI_SIZE_MULTIPLIER; const width = circleSize * 3; const height = circleSize * 3.2; const a = index / maxLength; const angle = a * (Math.PI * 2); const scale = isActivated ? 1 : 0.66; const x = Math.cos(angle) * width - circleSize * 2.8; const y = Math.sin(angle) * height; const handleClick = useCallback(() => { onClick(realIndex); }, [onClick, realIndex]); const handleEnded = useCallback(() => { inanimate(); onEnded(); }, [inanimate, onEnded]); useEffect(() => { if (isActivated) { animate(); } }, [isActivated, animate]); return ( <> {isActivated && ( )} > ); }; const PremiumFeaturePreviewStickers: FC = ({ stickers, isActive, }) => { // eslint-disable-next-line no-null/no-null const containerRef = useRef(null); const [offset, setOffset] = useState(0); const [size, setSize] = useState(0); const renderedStickers = stickers?.slice(0, MAX_EMOJIS); const handleClick = useCallback((i: number) => { setOffset(-i); }, []); const handleEnded = useCallback(() => { setTimeout(() => { setOffset((current) => cycleRestrict(renderedStickers.length, current + 1)); }, ENDED_DELAY); }, [renderedStickers.length]); useEffect(() => { const container = containerRef.current; if (!container) return; setSize(container.closest('.modal-dialog')!.clientWidth); }, []); return ( {Boolean(size) && renderedStickers?.map((l, i) => { return ( ); })} ); }; export default memo(withGlobal( (global): StateProps => { return { stickers: global.stickers.premium.stickers, }; }, )(PremiumFeaturePreviewStickers));