Reaction Picker: Show current reactions (#4822)

This commit is contained in:
Alexander Zinchuk 2024-08-06 20:06:37 +02:00
parent eddce446de
commit a03db12474
3 changed files with 61 additions and 30 deletions

View File

@ -38,7 +38,7 @@ export type OwnProps = {
};
interface StateProps {
withCustomReactions?: boolean;
shouldUseFullPicker?: boolean;
message?: ApiMessage;
story?: ApiStory | ApiStorySkipped;
isCurrentUserPremium?: boolean;
@ -61,7 +61,7 @@ const ReactionPicker: FC<OwnProps & StateProps> = ({
position,
isTranslucent,
isCurrentUserPremium,
withCustomReactions,
shouldUseFullPicker,
sendAsMessage,
chatId,
isForEffects,
@ -91,10 +91,10 @@ const ReactionPicker: FC<OwnProps & StateProps> = ({
}
return {
x: storedPosition.x + (withCustomReactions ? FULL_PICKER_SHIFT_DELTA.x : LIMITED_PICKER_SHIFT_DELTA.x),
y: storedPosition.y + (withCustomReactions ? FULL_PICKER_SHIFT_DELTA.y : LIMITED_PICKER_SHIFT_DELTA.y),
x: storedPosition.x + (shouldUseFullPicker ? FULL_PICKER_SHIFT_DELTA.x : LIMITED_PICKER_SHIFT_DELTA.x),
y: storedPosition.y + (shouldUseFullPicker ? FULL_PICKER_SHIFT_DELTA.y : LIMITED_PICKER_SHIFT_DELTA.y),
};
}, [renderedStoryId, storedPosition, withCustomReactions]);
}, [renderedStoryId, storedPosition, shouldUseFullPicker]);
const getMenuElement = useLastCallback(() => menuRef.current);
const getLayout = useLastCallback(() => ({
@ -208,7 +208,7 @@ const ReactionPicker: FC<OwnProps & StateProps> = ({
className={buildClassName(styles.menu, 'ReactionPicker')}
bubbleClassName={buildClassName(
styles.menuContent,
!withCustomReactions && !renderedStoryId && styles.onlyReactions,
!shouldUseFullPicker && !renderedStoryId && styles.onlyReactions,
renderedStoryId && styles.storyMenu,
)}
withPortal
@ -225,7 +225,7 @@ const ReactionPicker: FC<OwnProps & StateProps> = ({
<StickerPicker
className=""
isHidden={!isOpen}
loadAndPlay={Boolean(isOpen && withCustomReactions)}
loadAndPlay={Boolean(isOpen && shouldUseFullPicker)}
idPrefix="message-effect"
canSendStickers={false}
noContextMenus={false}
@ -239,21 +239,22 @@ const ReactionPicker: FC<OwnProps & StateProps> = ({
<CustomEmojiPicker
chatId={renderedChatId}
idPrefix="message-emoji-set-"
isHidden={!isOpen || !(withCustomReactions || renderedStoryId)}
loadAndPlay={Boolean(isOpen && withCustomReactions)}
isHidden={!isOpen || !(shouldUseFullPicker || renderedStoryId)}
loadAndPlay={Boolean(isOpen && shouldUseFullPicker)}
isReactionPicker
className={!withCustomReactions && !renderedStoryId ? styles.hidden : undefined}
className={!shouldUseFullPicker && !renderedStoryId ? styles.hidden : undefined}
selectedReactionIds={selectedReactionIds}
isTranslucent={isTranslucent}
onCustomEmojiSelect={renderedStoryId ? handleStoryReactionSelect : handleToggleCustomReaction}
onReactionSelect={renderedStoryId ? handleStoryReactionSelect : handleToggleReaction}
/>
{!withCustomReactions && Boolean(renderedChatId) && (
{!shouldUseFullPicker && Boolean(renderedChatId) && (
<ReactionPickerLimited
chatId={renderedChatId}
loadAndPlay={isOpen}
onReactionSelect={renderedStoryId ? handleStoryReactionSelect : handleToggleReaction}
selectedReactionIds={selectedReactionIds}
message={message}
/>
)}
</>
@ -276,16 +277,20 @@ export default memo(withGlobal<OwnProps>((global): StateProps => {
const message = chatId && messageId ? selectChatMessage(global, chatId, messageId) : undefined;
const isPrivateChat = isUserId(chatId || storyPeerId || '');
const areSomeReactionsAllowed = chatFullInfo?.enabledReactions?.type === 'some';
const areCustomReactionsAllowed = chatFullInfo?.enabledReactions?.type === 'all'
&& chatFullInfo?.enabledReactions?.areCustomAllowed;
const { maxUniqueReactions } = global.appConfig || {};
const areAllReactionsAllowed = chatFullInfo?.enabledReactions?.type === 'all'
&& chatFullInfo?.enabledReactions?.areCustomAllowed;
const currentReactions = message?.reactions?.results;
const shouldUseCurrentReactions = Boolean(maxUniqueReactions && currentReactions
&& currentReactions.length >= maxUniqueReactions);
return {
message,
story,
position,
withCustomReactions: chat?.isForbidden || areSomeReactionsAllowed
? false
: areCustomReactionsAllowed || isPrivateChat,
shouldUseFullPicker: (chat?.isForbidden || areSomeReactionsAllowed || shouldUseCurrentReactions) ? false
: (areAllReactionsAllowed || isPrivateChat),
isTranslucent: selectIsContextMenuTranslucent(global),
isCurrentUserPremium: selectIsCurrentUserPremium(global),
sendAsMessage,

View File

@ -1,10 +1,18 @@
import type { FC } from '../../../../lib/teact/teact';
import React, { memo, useMemo, useRef } from '../../../../lib/teact/teact';
import React, {
memo,
useMemo, useRef,
} from '../../../../lib/teact/teact';
import { withGlobal } from '../../../../global';
import type { ApiAvailableReaction, ApiChatReactions, ApiReaction } from '../../../../api/types';
import type {
ApiAvailableReaction, ApiChatReactions, ApiMessage,
ApiReaction,
} from '../../../../api/types';
import { getReactionKey, sortReactions } from '../../../../global/helpers';
import {
getReactionKey, sortReactions,
} from '../../../../global/helpers';
import { selectChatFullInfo } from '../../../../global/selectors';
import buildClassName from '../../../../util/buildClassName';
import { REM } from '../../../common/helpers/mediaDimensions';
@ -21,6 +29,7 @@ type OwnProps = {
loadAndPlay: boolean;
onReactionSelect?: (reaction: ApiReaction) => void;
selectedReactionIds?: string[];
message?: ApiMessage;
};
type StateProps = {
@ -29,6 +38,7 @@ type StateProps = {
topReactions: ApiReaction[];
canAnimate?: boolean;
isSavedMessages?: boolean;
reactionsLimit?: number;
isCurrentUserPremium?: boolean;
};
@ -47,6 +57,8 @@ const ReactionPickerLimited: FC<OwnProps & StateProps> = ({
topReactions,
selectedReactionIds,
onReactionSelect,
message,
reactionsLimit,
}) => {
// eslint-disable-next-line no-null/no-null
const sharedCanvasRef = useRef<HTMLCanvasElement>(null);
@ -55,7 +67,15 @@ const ReactionPickerLimited: FC<OwnProps & StateProps> = ({
const { width: windowWidth } = useWindowSize();
const { isTouchScreen } = useAppLayout();
const currentReactions = message?.reactions?.results;
const shouldUseCurrentReactions = reactionsLimit && currentReactions
&& currentReactions.length >= reactionsLimit;
const allAvailableReactions = useMemo(() => {
if (shouldUseCurrentReactions) {
return currentReactions.map(({ reaction }) => reaction);
}
if (!enabledReactions) {
return [];
}
@ -65,7 +85,7 @@ const ReactionPickerLimited: FC<OwnProps & StateProps> = ({
}
return sortReactions(enabledReactions.allowed, topReactions);
}, [availableReactions, enabledReactions, topReactions]);
}, [availableReactions, enabledReactions, topReactions, shouldUseCurrentReactions, currentReactions]);
const pickerHeight = useMemo(() => {
const pickerWidth = Math.min(MODAL_MAX_WIDTH_REM * REM, windowWidth);
@ -112,12 +132,15 @@ const ReactionPickerLimited: FC<OwnProps & StateProps> = ({
export default memo(withGlobal<OwnProps>(
(global, { chatId }): StateProps => {
const { availableReactions, topReactions } = global.reactions;
const { maxUniqueReactions } = global.appConfig || {};
const { enabledReactions } = selectChatFullInfo(global, chatId) || {};
return {
enabledReactions,
availableReactions,
topReactions,
reactionsLimit: maxUniqueReactions,
};
},
)(ReactionPickerLimited));

View File

@ -75,10 +75,17 @@ const ReactionSelector: FC<OwnProps> = ({
const areReactionsLocked = isInSavedMessages && !isCurrentUserPremium && !isInStoryViewer;
const shouldUseCurrentReactions = Boolean(maxUniqueReactions
&& currentReactions && currentReactions.length >= maxUniqueReactions);
const availableReactions = useMemo(() => {
const reactions = isForEffects ? effectReactions : isInSavedMessages ? defaultTagReactions
: (enabledReactions?.type === 'some' ? enabledReactions.allowed
: allAvailableReactions?.map((reaction) => reaction.reaction));
const reactions = (() => {
if (shouldUseCurrentReactions) return currentReactions?.map((reaction) => reaction.reaction);
if (isForEffects) return effectReactions;
if (isInSavedMessages) return defaultTagReactions;
if (enabledReactions?.type === 'some') return enabledReactions.allowed;
return allAvailableReactions?.map((reaction) => reaction.reaction);
})();
const filteredReactions = reactions?.map((reaction) => {
const isCustomReaction = 'documentId' in reaction;
const availableReaction = allAvailableReactions?.find((r) => isSameReaction(r.reaction, reaction));
@ -87,12 +94,8 @@ const ReactionSelector: FC<OwnProps> = ({
if ((!isCustomReaction && !availableReaction) || availableReaction?.isInactive) return undefined;
if (!isPrivate && (!enabledReactions || !canSendReaction(reaction, enabledReactions))) {
return undefined;
}
if (maxUniqueReactions && currentReactions && currentReactions.length >= maxUniqueReactions
&& !currentReactions.some(({ reaction: currentReaction }) => isSameReaction(reaction, currentReaction))) {
if (!isPrivate && !shouldUseCurrentReactions
&& (!enabledReactions || !canSendReaction(reaction, enabledReactions))) {
return undefined;
}
@ -102,7 +105,7 @@ const ReactionSelector: FC<OwnProps> = ({
return sortReactions(filteredReactions, topReactions);
}, [
allAvailableReactions, currentReactions, defaultTagReactions, enabledReactions, isInSavedMessages, isPrivate,
maxUniqueReactions, topReactions, isForEffects, effectReactions,
topReactions, isForEffects, effectReactions, shouldUseCurrentReactions,
]);
const reactionsToRender = useMemo(() => {