[Perf] Premium Modal: Optimizations (#1957)
This commit is contained in:
parent
fcf3aa857d
commit
a5219b69f7
@ -65,7 +65,6 @@ export const PREMIUM_FEATURE_SECTIONS = [
|
||||
const PREMIUM_BOTTOM_VIDEOS: string[] = [
|
||||
'faster_download',
|
||||
'voice_to_text',
|
||||
'no_ads',
|
||||
'advanced_chat_management',
|
||||
'profile_badge',
|
||||
'animated_userpics',
|
||||
@ -241,7 +240,7 @@ const PremiumFeatureModal: FC<OwnProps> = ({
|
||||
return (
|
||||
<div className={styles.slide}>
|
||||
<div className={styles.frame}>
|
||||
<PremiumFeaturePreviewReactions />
|
||||
<PremiumFeaturePreviewReactions isActive={currentSlideIndex === index} />
|
||||
</div>
|
||||
<h1 className={styles.title}>
|
||||
{lang(PREMIUM_FEATURE_TITLES.reactions)}
|
||||
@ -257,7 +256,7 @@ const PremiumFeatureModal: FC<OwnProps> = ({
|
||||
return (
|
||||
<div className={styles.slide}>
|
||||
<div className={styles.frame}>
|
||||
<PremiumFeaturePreviewStickers />
|
||||
<PremiumFeaturePreviewStickers isActive={currentSlideIndex === index} />
|
||||
</div>
|
||||
<h1 className={styles.title}>
|
||||
{lang(PREMIUM_FEATURE_TITLES.stickers)}
|
||||
@ -275,6 +274,7 @@ const PremiumFeatureModal: FC<OwnProps> = ({
|
||||
<div className={styles.slide}>
|
||||
<div className={styles.frame}>
|
||||
<PremiumFeaturePreviewVideo
|
||||
isActive={currentSlideIndex === index}
|
||||
videoId={promo.videos[i].id!}
|
||||
videoThumbnail={promo.videos[i].thumbnail!}
|
||||
isDown={PREMIUM_BOTTOM_VIDEOS.includes(section)}
|
||||
|
||||
@ -16,6 +16,10 @@ import AnimatedSticker from '../../../common/AnimatedSticker';
|
||||
|
||||
import styles from './PremiumFeaturePreviewReactions.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
isActive: boolean;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
availableReactions: GlobalState['availableReactions'];
|
||||
};
|
||||
@ -34,8 +38,9 @@ const AnimatedCircleReaction: FC<{
|
||||
maxLength: number;
|
||||
handleClick: (index: number) => void;
|
||||
isActivated: boolean;
|
||||
canPlay: boolean;
|
||||
}> = ({
|
||||
size, realIndex, isActivated,
|
||||
size, realIndex, isActivated, canPlay,
|
||||
reaction, index, maxLength, handleClick,
|
||||
}) => {
|
||||
const mediaData = useMedia(`document${reaction.activateAnimation?.id}`);
|
||||
@ -71,7 +76,7 @@ const AnimatedCircleReaction: FC<{
|
||||
<AnimatedSticker
|
||||
className={styles.effectSticker}
|
||||
tgsUrl={mediaDataAround}
|
||||
play
|
||||
play={canPlay}
|
||||
isLowPriority
|
||||
noLoop
|
||||
size={EFFECT_SIZE_MULTIPLIER * size}
|
||||
@ -83,7 +88,7 @@ const AnimatedCircleReaction: FC<{
|
||||
className={styles.sticker}
|
||||
tgsUrl={mediaData}
|
||||
onClick={handleClickEmoji}
|
||||
play={isAnimated}
|
||||
play={isAnimated && canPlay}
|
||||
noLoop
|
||||
size={EMOJI_SIZE_MULTIPLIER * size}
|
||||
style={`--x: ${x}px; --y: ${y}px; --scale: ${scale};`}
|
||||
@ -92,8 +97,8 @@ const AnimatedCircleReaction: FC<{
|
||||
</>
|
||||
);
|
||||
};
|
||||
const PremiumFeaturePreviewReactions: FC<StateProps> = ({
|
||||
availableReactions,
|
||||
const PremiumFeaturePreviewReactions: FC<OwnProps & StateProps> = ({
|
||||
availableReactions, isActive,
|
||||
}) => {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
@ -106,7 +111,7 @@ const PremiumFeaturePreviewReactions: FC<StateProps> = ({
|
||||
|
||||
useInterval(() => {
|
||||
setOffset((current) => cycleRestrict(renderedReactions.length, current + 1));
|
||||
}, isIntervalPaused ? undefined : ROTATE_INTERVAL);
|
||||
}, isIntervalPaused || !isActive ? undefined : ROTATE_INTERVAL);
|
||||
|
||||
const handleClickEmoji = useCallback((i: number) => {
|
||||
setOffset(i);
|
||||
@ -139,6 +144,7 @@ const PremiumFeaturePreviewReactions: FC<StateProps> = ({
|
||||
maxLength={renderedReactions.length}
|
||||
handleClick={handleClickEmoji}
|
||||
isActivated={offset === i}
|
||||
canPlay={isActive}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@ -146,7 +152,7 @@ const PremiumFeaturePreviewReactions: FC<StateProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(withGlobal(
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global): StateProps => {
|
||||
return {
|
||||
availableReactions: global.availableReactions,
|
||||
|
||||
@ -15,6 +15,10 @@ import AnimatedSticker from '../../../common/AnimatedSticker';
|
||||
|
||||
import styles from './PremiumFeaturePreviewStickers.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
isActive: boolean;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
stickers: GlobalState['stickers']['premium']['stickers'];
|
||||
};
|
||||
@ -32,8 +36,9 @@ const AnimatedCircleSticker: FC<{
|
||||
maxLength: number;
|
||||
onClick: (index: number) => void;
|
||||
onEnded: NoneToVoidFunction;
|
||||
canPlay: boolean;
|
||||
}> = ({
|
||||
size, realIndex,
|
||||
size, realIndex, canPlay,
|
||||
sticker, index, maxLength, onClick, onEnded,
|
||||
}) => {
|
||||
const mediaData = useMedia(`sticker${sticker.id}`);
|
||||
@ -75,7 +80,7 @@ const AnimatedCircleSticker: FC<{
|
||||
<AnimatedSticker
|
||||
className={styles.effectSticker}
|
||||
tgsUrl={mediaDataAround}
|
||||
play
|
||||
play={canPlay}
|
||||
isLowPriority
|
||||
noLoop
|
||||
size={EFFECT_SIZE_MULTIPLIER * size}
|
||||
@ -85,7 +90,7 @@ const AnimatedCircleSticker: FC<{
|
||||
<AnimatedSticker
|
||||
className={styles.sticker}
|
||||
tgsUrl={mediaData}
|
||||
play={isAnimated}
|
||||
play={canPlay && isAnimated}
|
||||
noLoop
|
||||
size={EMOJI_SIZE_MULTIPLIER * size}
|
||||
style={`--x: ${x}px; --y: ${y}px; --opacity: ${scale}`}
|
||||
@ -95,8 +100,8 @@ const AnimatedCircleSticker: FC<{
|
||||
</>
|
||||
);
|
||||
};
|
||||
const PremiumFeaturePreviewStickers: FC<StateProps> = ({
|
||||
stickers,
|
||||
const PremiumFeaturePreviewStickers: FC<OwnProps & StateProps> = ({
|
||||
stickers, isActive,
|
||||
}) => {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
@ -137,6 +142,7 @@ const PremiumFeaturePreviewStickers: FC<StateProps> = ({
|
||||
maxLength={renderedStickers.length}
|
||||
onClick={handleClick}
|
||||
onEnded={handleEnded}
|
||||
canPlay={isActive}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@ -144,7 +150,7 @@ const PremiumFeaturePreviewStickers: FC<StateProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(withGlobal(
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global): StateProps => {
|
||||
return {
|
||||
stickers: global.stickers.premium.stickers,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { FC } from '../../../../lib/teact/teact';
|
||||
import React, { memo } from '../../../../lib/teact/teact';
|
||||
import React, { memo, useEffect, useRef } from '../../../../lib/teact/teact';
|
||||
|
||||
import type { ApiThumbnail } from '../../../../api/types';
|
||||
|
||||
@ -7,6 +7,7 @@ import useMedia from '../../../../hooks/useMedia';
|
||||
import buildClassName from '../../../../util/buildClassName';
|
||||
import useCanvasBlur from '../../../../hooks/useCanvasBlur';
|
||||
import useMediaTransition from '../../../../hooks/useMediaTransition';
|
||||
import safePlay from '../../../../util/safePlay';
|
||||
|
||||
import DeviceFrame from '../../../../assets/premium/DeviceFrame.svg';
|
||||
|
||||
@ -18,6 +19,7 @@ type OwnProps = {
|
||||
isDown: boolean;
|
||||
videoThumbnail: ApiThumbnail;
|
||||
index: number;
|
||||
isActive: boolean;
|
||||
};
|
||||
|
||||
const PremiumFeaturePreviewVideo: FC<OwnProps> = ({
|
||||
@ -26,10 +28,24 @@ const PremiumFeaturePreviewVideo: FC<OwnProps> = ({
|
||||
isDown,
|
||||
videoThumbnail,
|
||||
index,
|
||||
isActive,
|
||||
}) => {
|
||||
const mediaData = useMedia(`document${videoId}`);
|
||||
const thumbnailRef = useCanvasBlur(videoThumbnail.dataUri);
|
||||
const transitionClassNames = useMediaTransition(mediaData);
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const video = videoRef.current;
|
||||
if (!video) return;
|
||||
|
||||
if (isActive) {
|
||||
safePlay(video);
|
||||
} else {
|
||||
video.pause();
|
||||
}
|
||||
}, [isActive]);
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
@ -44,12 +60,13 @@ const PremiumFeaturePreviewVideo: FC<OwnProps> = ({
|
||||
<img src={DeviceFrame} alt="" className={styles.frame} />
|
||||
<canvas ref={thumbnailRef} className={styles.video} />
|
||||
<video
|
||||
ref={videoRef}
|
||||
className={buildClassName(
|
||||
styles.video,
|
||||
transitionClassNames,
|
||||
)}
|
||||
src={mediaData}
|
||||
autoPlay
|
||||
autoPlay={isActive}
|
||||
disablePictureInPicture
|
||||
playsInline
|
||||
muted
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user