Sticker: Fix looping behavior (#4279)

This commit is contained in:
Alexander Zinchuk 2024-02-23 14:06:16 +01:00
parent ae9d09c762
commit 95f98442fc
6 changed files with 41 additions and 29 deletions

View File

@ -78,7 +78,7 @@ const CustomEmoji: FC<OwnProps> = ({
const { customEmoji, canPlay } = useCustomEmoji(documentId);
const loopCountRef = useRef(0);
const [shouldLoop, setShouldLoop] = useState(true);
const [shouldPlay, setShouldPlay] = useState(true);
const hasCustomColor = customEmoji?.shouldUseTextColor;
const customColor = useDynamicColorListener(containerRef, !hasCustomColor);
@ -89,7 +89,7 @@ const CustomEmoji: FC<OwnProps> = ({
loopCountRef.current += 1;
if (loopCountRef.current >= loopLimit) {
setShouldLoop(false);
setShouldPlay(false);
e.currentTarget.currentTime = 0;
} else {
// Loop manually
@ -102,9 +102,8 @@ const CustomEmoji: FC<OwnProps> = ({
loopCountRef.current += 1;
// Sticker plays 1 more time after disabling loop
if (loopCountRef.current >= loopLimit - 1) {
setShouldLoop(false);
if (loopCountRef.current >= loopLimit) {
setShouldPlay(false);
}
});
@ -143,10 +142,10 @@ const CustomEmoji: FC<OwnProps> = ({
sticker={customEmoji}
isSmall={!isBig}
size={size}
noPlay={noPlay || !canPlay}
noPlay={noPlay || !(shouldPlay && canPlay)}
thumbClassName={styles.thumb}
fullMediaClassName={styles.media}
shouldLoop={shouldLoop}
shouldLoop
loopLimit={loopLimit}
shouldPreloadPreview={shouldPreloadPreview || noPlay || !canPlay}
forceOnHeavyAnimation={forceOnHeavyAnimation}

View File

@ -180,12 +180,12 @@ const StickerView: FC<OwnProps> = ({
/>
) : isVideo ? (
<OptimizedVideo
canPlay={shouldPlay && shouldLoop}
canPlay={shouldPlay}
className={buildClassName(styles.media, fullMediaClassName, fullMediaClassNames, 'sticker-media')}
src={fullMediaData}
playsInline
muted
loop={!loopLimit}
loop={shouldLoop && !loopLimit}
isPriority={forceAlways}
disablePictureInPicture
onReady={markPlayerReady}

View File

@ -35,6 +35,7 @@ type OwnProps = {
withEffectOnly?: boolean;
shouldPause?: boolean;
shouldLoop?: boolean;
loopLimit?: number;
observeIntersection?: ObserveFn;
};
@ -64,6 +65,7 @@ const ReactionAnimatedEmoji = ({
withEffectOnly,
shouldPause,
shouldLoop,
loopLimit,
observeIntersection,
}: OwnProps & StateProps) => {
const { stopActiveReaction } = getActions();
@ -164,6 +166,7 @@ const ReactionAnimatedEmoji = ({
className={styles.customEmoji}
size={size}
noPlay={shouldPause}
loopLimit={loopLimit}
forceAlways
observeIntersectionForPlaying={observeIntersection}
/>

View File

@ -1,11 +1,12 @@
import type { FC } from '../../lib/teact/teact';
import React, { memo, useEffect, useRef } from '../../lib/teact/teact';
import React, {
memo, useEffect, useMemo, useRef,
} from '../../lib/teact/teact';
import { getActions, withGlobal } from '../../global';
import type { ApiSticker, ApiUpdateConnectionStateType } from '../../api/types';
import type { MessageList } from '../../global/types';
import { getPeerIdDividend } from '../../global/helpers';
import { selectChat, selectChatLastMessage, selectCurrentMessageList } from '../../global/selectors';
import useLang from '../../hooks/useLang';
@ -20,14 +21,14 @@ type OwnProps = {
};
type StateProps = {
sticker?: ApiSticker;
stickers?: ApiSticker[];
lastUnreadMessageId?: number;
connectionState?: ApiUpdateConnectionStateType;
currentMessageList?: MessageList;
};
const ContactGreeting: FC<OwnProps & StateProps> = ({
sticker,
stickers,
connectionState,
lastUnreadMessageId,
currentMessageList,
@ -43,13 +44,20 @@ const ContactGreeting: FC<OwnProps & StateProps> = ({
// eslint-disable-next-line no-null/no-null
const containerRef = useRef<HTMLDivElement>(null);
const sticker = useMemo(() => {
if (!stickers?.length) return undefined;
const randomIndex = Math.floor(Math.random() * stickers.length);
return stickers[randomIndex];
}, [stickers]);
useEffect(() => {
if (sticker || connectionState !== 'connectionStateReady') {
if (stickers?.length || connectionState !== 'connectionStateReady') {
return;
}
loadGreetingStickers();
}, [connectionState, loadGreetingStickers, sticker]);
}, [connectionState, loadGreetingStickers, stickers]);
useEffect(() => {
if (connectionState === 'connectionStateReady' && lastUnreadMessageId) {
@ -94,8 +102,6 @@ const ContactGreeting: FC<OwnProps & StateProps> = ({
export default memo(withGlobal<OwnProps>(
(global, { userId }): StateProps => {
const { stickers } = global.stickers.greeting;
const dividend = getPeerIdDividend(userId) + getPeerIdDividend(global.currentUserId!);
const sticker = stickers?.length ? stickers[dividend % stickers.length] : undefined;
const chat = selectChat(global, userId);
if (!chat) {
return {};
@ -104,7 +110,7 @@ export default memo(withGlobal<OwnProps>(
const lastMessage = selectChatLastMessage(global, chat.id);
return {
sticker,
stickers,
lastUnreadMessageId: lastMessage && lastMessage.id !== chat.lastReadInboxMessageId
? lastMessage.id
: undefined,

View File

@ -607,7 +607,7 @@ const MessageList: FC<OwnProps & StateProps> = ({
) : isBot && !hasMessages ? (
<MessageListBotInfo chatId={chatId} />
) : shouldRenderGreeting ? (
<ContactGreeting userId={chatId} />
<ContactGreeting key={chatId} userId={chatId} />
) : messageIds && (!messageGroups || isGroupChatJustCreated || isEmptyTopic) ? (
<NoMessages
chatId={chatId}

View File

@ -26,6 +26,7 @@ import styles from './ReactionButton.module.scss';
const REACTION_SIZE = 1.25 * REM;
const TITLE_MAX_LENGTH = 15;
const LOOP_LIMIT = 1;
const SavedTagButton: FC<{
reaction: ApiReaction;
@ -134,6 +135,7 @@ const SavedTagButton: FC<{
className={styles.animatedEmoji}
containerId={containerId}
reaction={reaction}
loopLimit={LOOP_LIMIT}
size={REACTION_SIZE}
observeIntersection={observeIntersection}
/>
@ -151,16 +153,18 @@ const SavedTagButton: FC<{
>
<path className={styles.tailFill} d="m 0,30 c 3.1855,0 6.1803,-1.5176 8.0641,-4.0864 l 5.835,-7.9568 c 1.2906,-1.7599 1.2906,-4.1537 0,-5.9136 L 8.0641,4.08636 C 6.1803,1.51761 3.1855,0 0,0" />
</svg>
<PromptDialog
isOpen={isRenamePromptOpen}
maxLength={TITLE_MAX_LENGTH}
title={lang(tag?.title ? 'SavedTagRenameTag' : 'SavedTagLabelTag')}
subtitle={lang('SavedTagLabelTagText')}
placeholder={lang('SavedTagLabelPlaceholder')}
initialValue={tag?.title}
onClose={closeRenamePrompt}
onSubmit={handleRenameTag}
/>
{withContextMenu && (
<PromptDialog
isOpen={isRenamePromptOpen}
maxLength={TITLE_MAX_LENGTH}
title={lang(tag?.title ? 'SavedTagRenameTag' : 'SavedTagLabelTag')}
subtitle={lang('SavedTagLabelTagText')}
placeholder={lang('SavedTagLabelPlaceholder')}
initialValue={tag?.title}
onClose={closeRenamePrompt}
onSubmit={handleRenameTag}
/>
)}
{withContextMenu && contextMenuPosition && (
<Menu
ref={menuRef}