From 3bffde60cba12948b29a9c4627dc501f77fe8d62 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Tue, 1 Nov 2022 18:53:26 +0100 Subject: [PATCH] Sticker Set Cover: Fix pausing when hidden --- src/components/common/StickerButton.tsx | 2 +- src/components/common/StickerSetCard.tsx | 38 ++++++------ .../middle/composer/CustomEmojiPicker.tsx | 22 +++---- .../middle/composer/StickerPicker.tsx | 26 ++++---- src/components/middle/composer/StickerSet.tsx | 6 +- .../composer/StickerSetCover.module.scss | 3 + .../middle/composer/StickerSetCover.tsx | 59 ++++++++++++++----- .../composer/StickerSetCoverAnimated.tsx | 57 ------------------ 8 files changed, 88 insertions(+), 125 deletions(-) create mode 100644 src/components/middle/composer/StickerSetCover.module.scss delete mode 100644 src/components/middle/composer/StickerSetCoverAnimated.tsx diff --git a/src/components/common/StickerButton.tsx b/src/components/common/StickerButton.tsx index c000c2674..3392d0a41 100644 --- a/src/components/common/StickerButton.tsx +++ b/src/components/common/StickerButton.tsx @@ -29,13 +29,13 @@ type OwnProps = { noAnimate?: boolean; title?: string; className?: string; - clickArg: T; noContextMenu?: boolean; isSavedMessages?: boolean; canViewSet?: boolean; isCurrentUserPremium?: boolean; observeIntersection: ObserveFn; onClick?: (arg: OwnProps['clickArg'], isSilent?: boolean, shouldSchedule?: boolean) => void; + clickArg: T; onFaveClick?: (sticker: ApiSticker) => void; onUnfaveClick?: (sticker: ApiSticker) => void; onRemoveRecentClick?: (sticker: ApiSticker) => void; diff --git a/src/components/common/StickerSetCard.tsx b/src/components/common/StickerSetCard.tsx index 151b61bd2..bd53fc96b 100644 --- a/src/components/common/StickerSetCard.tsx +++ b/src/components/common/StickerSetCard.tsx @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useMemo } from '../../lib/teact/teact'; +import React, { memo, useCallback } from '../../lib/teact/teact'; import type { ApiSticker, ApiStickerSet } from '../../api/types'; import type { FC } from '../../lib/teact/teact'; @@ -11,7 +11,6 @@ import useLang from '../../hooks/useLang'; import ListItem from '../ui/ListItem'; import Button from '../ui/Button'; -import StickerSetCoverAnimated from '../middle/composer/StickerSetCoverAnimated'; import StickerSetCover from '../middle/composer/StickerSetCover'; import StickerButton from './StickerButton'; @@ -19,6 +18,7 @@ import './StickerSetCard.scss'; type OwnProps = { stickerSet?: ApiStickerSet; + noAnimate?: boolean; className?: string; observeIntersection: ObserveFn; onClick: (value: ApiSticker) => void; @@ -26,6 +26,7 @@ type OwnProps = { const StickerSetCard: FC = ({ stickerSet, + noAnimate, className, observeIntersection, onClick, @@ -38,7 +39,11 @@ const StickerSetCard: FC = ({ if (firstSticker) onClick(firstSticker); }, [firstSticker, onClick]); - const preview = useMemo(() => { + if (!stickerSet || !stickerSet.stickers) { + return undefined; + } + + function renderPreview() { if (!stickerSet) return undefined; if (stickerSet.hasThumbnail || !firstSticker) { return ( @@ -47,18 +52,12 @@ const StickerSetCard: FC = ({ color="translucent" isRtl={lang.isRtl} > - {stickerSet.isLottie ? ( - - ) : ( - - )} + ); } else { @@ -67,17 +66,14 @@ const StickerSetCard: FC = ({ sticker={firstSticker} size={STICKER_SIZE_GENERAL_SETTINGS} title={stickerSet.title} + noAnimate={noAnimate} observeIntersection={observeIntersection} - clickArg={undefined} noContextMenu isCurrentUserPremium + clickArg={undefined} /> ); } - }, [firstSticker, lang.isRtl, observeIntersection, stickerSet]); - - if (!stickerSet || !stickerSet.stickers) { - return undefined; } return ( @@ -87,7 +83,7 @@ const StickerSetCard: FC = ({ inactive={!firstSticker} onClick={handleCardClick} > - {preview} + {renderPreview()}
{stickerSet.title}
{lang('StickerPack.StickerCount', stickerSet.count, 'i')}
diff --git a/src/components/middle/composer/CustomEmojiPicker.tsx b/src/components/middle/composer/CustomEmojiPicker.tsx index aac57ba43..1193ebc16 100644 --- a/src/components/middle/composer/CustomEmojiPicker.tsx +++ b/src/components/middle/composer/CustomEmojiPicker.tsx @@ -33,7 +33,6 @@ import Button from '../../ui/Button'; import StickerButton from '../../common/StickerButton'; import StickerSet from './StickerSet'; import StickerSetCover from './StickerSetCover'; -import StickerSetCoverAnimated from './StickerSetCoverAnimated'; import './StickerPicker.scss'; @@ -50,7 +49,7 @@ type StateProps = { addedCustomEmojiIds?: string[]; recentCustomEmoji: ApiSticker[]; featuredCustomEmojiIds?: string[]; - shouldPlay?: boolean; + canAnimate?: boolean; isSavedMessages?: boolean; isCurrentUserPremium?: boolean; }; @@ -68,7 +67,7 @@ const CustomEmojiPicker: FC = ({ recentCustomEmoji, stickerSetsById, featuredCustomEmojiIds, - shouldPlay, + canAnimate, isSavedMessages, isCurrentUserPremium, onCustomEmojiSelect, @@ -199,14 +198,10 @@ const CustomEmojiPicker: FC = ({ > {stickerSet.id === RECENT_SYMBOL_SET_ID ? ( - ) : stickerSet.isLottie ? ( - ) : ( )} @@ -220,11 +215,12 @@ const CustomEmojiPicker: FC = ({ size={STICKER_SIZE_PICKER_HEADER} title={stickerSet.title} className={buttonClassName} + noAnimate={!canAnimate || !loadAndPlay} observeIntersection={observeIntersectionForCovers} - onClick={selectStickerSet} - clickArg={index} noContextMenu isCurrentUserPremium + onClick={selectStickerSet} + clickArg={index} /> ); } @@ -260,14 +256,14 @@ const CustomEmojiPicker: FC = ({ = i - 1 && activeSetIndex <= i + 1} - onStickerSelect={handleEmojiSelect} isSavedMessages={isSavedMessages} isCustomEmojiPicker isCurrentUserPremium={isCurrentUserPremium} + onStickerSelect={handleEmojiSelect} /> ))}
@@ -288,7 +284,7 @@ export default memo(withGlobal( return { stickerSetsById: setsById, addedCustomEmojiIds: global.customEmojis.added.setIds, - shouldPlay: global.settings.byKey.shouldLoopStickers, + canAnimate: global.settings.byKey.shouldLoopStickers, isSavedMessages, isCurrentUserPremium: selectIsCurrentUserPremium(global), recentCustomEmoji, diff --git a/src/components/middle/composer/StickerPicker.tsx b/src/components/middle/composer/StickerPicker.tsx index a3e0edf4e..617435981 100644 --- a/src/components/middle/composer/StickerPicker.tsx +++ b/src/components/middle/composer/StickerPicker.tsx @@ -35,7 +35,6 @@ import Button from '../../ui/Button'; import StickerButton from '../../common/StickerButton'; import StickerSet from './StickerSet'; import StickerSetCover from './StickerSetCover'; -import StickerSetCoverAnimated from './StickerSetCoverAnimated'; import PremiumIcon from '../../common/PremiumIcon'; import './StickerPicker.scss'; @@ -56,7 +55,7 @@ type StateProps = { premiumStickers: ApiSticker[]; stickerSetsById: Record; addedSetIds?: string[]; - shouldPlay?: boolean; + canAnimate?: boolean; isSavedMessages?: boolean; isCurrentUserPremium?: boolean; }; @@ -78,7 +77,7 @@ const StickerPicker: FC = ({ premiumStickers, addedSetIds, stickerSetsById, - shouldPlay, + canAnimate, isSavedMessages, isCurrentUserPremium, onStickerSelect, @@ -286,14 +285,10 @@ const StickerPicker: FC = ({ ) : stickerSet.id === CHAT_STICKER_SET_ID ? ( - ) : stickerSet.isLottie ? ( - ) : ( )} @@ -307,11 +302,12 @@ const StickerPicker: FC = ({ size={STICKER_SIZE_PICKER_HEADER} title={stickerSet.title} className={buttonClassName} + noAnimate={!canAnimate || !loadAndPlay} observeIntersection={observeIntersectionForCovers} - onClick={selectStickerSet} - clickArg={index} noContextMenu isCurrentUserPremium + onClick={selectStickerSet} + clickArg={index} /> ); } @@ -350,17 +346,17 @@ const StickerPicker: FC = ({ = i - 1 && activeSetIndex <= i + 1} + favoriteStickers={favoriteStickers} + isSavedMessages={isSavedMessages} + isCurrentUserPremium={isCurrentUserPremium} onStickerSelect={handleStickerSelect} onStickerUnfave={handleStickerUnfave} onStickerFave={handleStickerFave} onStickerRemoveRecent={handleRemoveRecentSticker} - favoriteStickers={favoriteStickers} - isSavedMessages={isSavedMessages} - isCurrentUserPremium={isCurrentUserPremium} /> ))} @@ -388,7 +384,7 @@ export default memo(withGlobal( premiumStickers: premiumSet.stickers, stickerSetsById: setsById, addedSetIds: added.setIds, - shouldPlay: global.settings.byKey.shouldLoopStickers, + canAnimate: global.settings.byKey.shouldLoopStickers, isSavedMessages, isCurrentUserPremium: selectIsCurrentUserPremium(global), }; diff --git a/src/components/middle/composer/StickerSet.tsx b/src/components/middle/composer/StickerSet.tsx index f6c27a119..21f59aa7c 100644 --- a/src/components/middle/composer/StickerSet.tsx +++ b/src/components/middle/composer/StickerSet.tsx @@ -166,15 +166,15 @@ const StickerSet: FC = ({ size={itemSize} observeIntersection={observeIntersection} noAnimate={!loadAndPlay} + isSavedMessages={isSavedMessages} + canViewSet + isCurrentUserPremium={isCurrentUserPremium} onClick={onStickerSelect} clickArg={sticker} onUnfaveClick={stickerSet.id === FAVORITE_SYMBOL_SET_ID && favoriteStickerIdsSet?.has(sticker.id) ? onStickerUnfave : undefined} onFaveClick={!favoriteStickerIdsSet?.has(sticker.id) ? onStickerFave : undefined} onRemoveRecentClick={isRecent ? onStickerRemoveRecent : undefined} - isSavedMessages={isSavedMessages} - canViewSet - isCurrentUserPremium={isCurrentUserPremium} /> ))} {!isExpanded && stickerSet.count > itemsBeforeCutout && ( diff --git a/src/components/middle/composer/StickerSetCover.module.scss b/src/components/middle/composer/StickerSetCover.module.scss new file mode 100644 index 000000000..11e7b0e1c --- /dev/null +++ b/src/components/middle/composer/StickerSetCover.module.scss @@ -0,0 +1,3 @@ +.video { + width: 100%; +} diff --git a/src/components/middle/composer/StickerSetCover.tsx b/src/components/middle/composer/StickerSetCover.tsx index 0f55c48a9..8b371a3d9 100644 --- a/src/components/middle/composer/StickerSetCover.tsx +++ b/src/components/middle/composer/StickerSetCover.tsx @@ -1,44 +1,73 @@ import type { FC } from '../../../lib/teact/teact'; -import React, { memo, useMemo, useRef } from '../../../lib/teact/teact'; +import React, { memo, useRef } from '../../../lib/teact/teact'; import type { ApiStickerSet } from '../../../api/types'; +import type { ObserveFn } from '../../../hooks/useIntersectionObserver'; +import { STICKER_SIZE_PICKER_HEADER } from '../../../config'; import { IS_WEBM_SUPPORTED } from '../../../util/environment'; import { getFirstLetters } from '../../../util/textFormat'; -import type { ObserveFn } from '../../../hooks/useIntersectionObserver'; +import buildClassName from '../../../util/buildClassName'; import { useIsIntersecting } from '../../../hooks/useIntersectionObserver'; import useMedia from '../../../hooks/useMedia'; import useMediaTransition from '../../../hooks/useMediaTransition'; +import AnimatedSticker from '../../common/AnimatedSticker'; import OptimizedVideo from '../../ui/OptimizedVideo'; +import styles from './StickerSetCover.module.scss'; + type OwnProps = { stickerSet: ApiStickerSet; + size?: number; + noAnimate?: boolean; observeIntersection: ObserveFn; }; -const StickerSetCover: FC = ({ stickerSet, observeIntersection }) => { +const StickerSetCover: FC = ({ + stickerSet, + size = STICKER_SIZE_PICKER_HEADER, + noAnimate, + observeIntersection, +}) => { // eslint-disable-next-line no-null/no-null const ref = useRef(null); + const { hasThumbnail, isLottie, isVideos: isVideo } = stickerSet; + const isIntersecting = useIsIntersecting(ref, observeIntersection); - const mediaData = useMedia(stickerSet.hasThumbnail && `stickerSet${stickerSet.id}`, !isIntersecting); - const transitionClassNames = useMediaTransition(mediaData); - const isVideo = stickerSet.isVideos; - - const firstLetters = useMemo(() => { - if ((isVideo && !IS_WEBM_SUPPORTED) || !mediaData) return getFirstLetters(stickerSet.title, 2); - return undefined; - }, [isVideo, mediaData, stickerSet.title]); + const mediaData = useMedia((hasThumbnail || isLottie) && `stickerSet${stickerSet.id}`, !isIntersecting); + const isReady = mediaData && (!isVideo || IS_WEBM_SUPPORTED); + const transitionClassNames = useMediaTransition(isReady); return (
- {firstLetters} - {isVideo ? ( - + {isReady ? ( + isLottie ? ( + + ) : isVideo ? ( + + ) : ( + + ) ) : ( - + getFirstLetters(stickerSet.title, 2) )}
); diff --git a/src/components/middle/composer/StickerSetCoverAnimated.tsx b/src/components/middle/composer/StickerSetCoverAnimated.tsx deleted file mode 100644 index 904a2c39f..000000000 --- a/src/components/middle/composer/StickerSetCoverAnimated.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import type { FC } from '../../../lib/teact/teact'; -import React, { memo, useMemo, useRef } from '../../../lib/teact/teact'; - -import type { ApiStickerSet } from '../../../api/types'; - -import { STICKER_SIZE_PICKER_HEADER } from '../../../config'; -import { getFirstLetters } from '../../../util/textFormat'; - -import type { ObserveFn } from '../../../hooks/useIntersectionObserver'; -import { useIsIntersecting } from '../../../hooks/useIntersectionObserver'; -import useMedia from '../../../hooks/useMedia'; -import useMediaTransition from '../../../hooks/useMediaTransition'; - -import AnimatedSticker from '../../common/AnimatedSticker'; - -type OwnProps = { - size?: number; - stickerSet: ApiStickerSet; - observeIntersection: ObserveFn; -}; - -const StickerSetCoverAnimated: FC = ({ - size = STICKER_SIZE_PICKER_HEADER, - stickerSet, - observeIntersection, -}) => { - // eslint-disable-next-line no-null/no-null - const ref = useRef(null); - - const isIntersecting = useIsIntersecting(ref, observeIntersection); - - const mediaHash = `stickerSet${stickerSet.id}`; - const lottieData = useMedia(mediaHash, !isIntersecting); - const transitionClassNames = useMediaTransition(lottieData); - - const firstLetters = useMemo(() => { - if (lottieData) return undefined; - - return getFirstLetters(stickerSet.title, 2); - }, [lottieData, stickerSet.title]); - - return ( -
- {firstLetters} - {lottieData && ( - - )} -
- ); -}; - -export default memo(StickerSetCoverAnimated);