Composer Embedded Message: Fix closing animation (#6634)
This commit is contained in:
parent
c2eb1abd3c
commit
a662e58e78
@ -31,6 +31,7 @@ import { unique } from '../../../util/iteratees';
|
|||||||
|
|
||||||
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
||||||
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
||||||
|
import useFrozenProps from '../../../hooks/useFrozenProps';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
import useOldLang from '../../../hooks/useOldLang';
|
import useOldLang from '../../../hooks/useOldLang';
|
||||||
@ -81,33 +82,21 @@ type OwnProps = {
|
|||||||
|
|
||||||
const CLOSE_DURATION = 350;
|
const CLOSE_DURATION = 350;
|
||||||
|
|
||||||
const ComposerEmbeddedMessage = ({
|
const ComposerEmbeddedMessage = (props: OwnProps & StateProps) => {
|
||||||
replyInfo,
|
const {
|
||||||
suggestedPostInfo,
|
shouldAnimate,
|
||||||
editingId,
|
isReplyToDiscussion,
|
||||||
message,
|
isInChangingRecipientMode,
|
||||||
sender,
|
forwardMessageIds,
|
||||||
shouldAnimate,
|
fromChatId,
|
||||||
forwardedMessagesCount,
|
replyInfo,
|
||||||
noAuthors,
|
editingId,
|
||||||
noCaptions,
|
suggestedPostInfo,
|
||||||
forwardsHaveCaptions,
|
shouldForceShowEditing,
|
||||||
shouldForceShowEditing,
|
message,
|
||||||
isCurrentUserPremium,
|
forwardedMessagesCount,
|
||||||
isContextMenuDisabled,
|
} = props;
|
||||||
isReplyToDiscussion,
|
|
||||||
isInChangingRecipientMode,
|
|
||||||
shouldPreventComposerAnimation,
|
|
||||||
senderChat,
|
|
||||||
chatId,
|
|
||||||
currentUserId,
|
|
||||||
isSenderChannel,
|
|
||||||
forwardMessageIds,
|
|
||||||
fromChatId,
|
|
||||||
isMediaNsfw,
|
|
||||||
theme,
|
|
||||||
onClear,
|
|
||||||
}: OwnProps & StateProps) => {
|
|
||||||
const {
|
const {
|
||||||
resetDraftReplyInfo,
|
resetDraftReplyInfo,
|
||||||
resetDraftSuggestedPostInfo,
|
resetDraftSuggestedPostInfo,
|
||||||
@ -127,19 +116,16 @@ const ComposerEmbeddedMessage = ({
|
|||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
const isReplyToTopicStart = message?.content.action?.type === 'topicCreate';
|
const isReplyToTopicStart = message?.content.action?.type === 'topicCreate';
|
||||||
const isShowingReply = replyInfo && !shouldForceShowEditing;
|
|
||||||
const isReplyWithQuote = Boolean(replyInfo?.quoteText);
|
|
||||||
const isShowingSuggestedPost = Boolean(suggestedPostInfo) && !shouldForceShowEditing;
|
const isShowingSuggestedPost = Boolean(suggestedPostInfo) && !shouldForceShowEditing;
|
||||||
|
|
||||||
const isForwarding = Boolean(forwardedMessagesCount);
|
const isForwarding = Boolean(forwardedMessagesCount);
|
||||||
|
|
||||||
const selectSenderFromForwardedMessage = useLastCallback((forwardedMessage: ApiMessage) => {
|
const selectSenderFromForwardedMessage = useLastCallback((forwardedMessage: ApiMessage) => {
|
||||||
const global = getGlobal();
|
const global = getGlobal();
|
||||||
sender = selectForwardedSender(global, forwardedMessage);
|
let localSender = selectForwardedSender(global, forwardedMessage);
|
||||||
if (!sender) {
|
if (!localSender) {
|
||||||
sender = selectSender(global, forwardedMessage);
|
localSender = selectSender(global, forwardedMessage);
|
||||||
}
|
}
|
||||||
return sender;
|
return localSender;
|
||||||
});
|
});
|
||||||
|
|
||||||
const forwardSenders = useMemo(() => {
|
const forwardSenders = useMemo(() => {
|
||||||
@ -159,7 +145,7 @@ const ComposerEmbeddedMessage = ({
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
shouldRender, transitionClassNames,
|
shouldRender, transitionClassNames, isClosing,
|
||||||
} = useShowTransitionDeprecated(
|
} = useShowTransitionDeprecated(
|
||||||
isShown && !isReplyToTopicStart && !isReplyToDiscussion,
|
isShown && !isReplyToTopicStart && !isReplyToDiscussion,
|
||||||
undefined,
|
undefined,
|
||||||
@ -169,6 +155,35 @@ const ComposerEmbeddedMessage = ({
|
|||||||
CLOSE_DURATION,
|
CLOSE_DURATION,
|
||||||
!shouldAnimate,
|
!shouldAnimate,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
chatId,
|
||||||
|
currentUserId,
|
||||||
|
theme,
|
||||||
|
onClear,
|
||||||
|
isCurrentUserPremium,
|
||||||
|
isContextMenuDisabled,
|
||||||
|
shouldPreventComposerAnimation,
|
||||||
|
sender,
|
||||||
|
senderChat,
|
||||||
|
isMediaNsfw,
|
||||||
|
noAuthors,
|
||||||
|
noCaptions,
|
||||||
|
forwardsHaveCaptions,
|
||||||
|
forwardedMessagesCount: frozenForwardedMessagesCount,
|
||||||
|
message: frozenMessage,
|
||||||
|
shouldForceShowEditing: frozenShouldForceShowEditing,
|
||||||
|
suggestedPostInfo: frozenSuggestedPostInfo,
|
||||||
|
replyInfo: frozenReplyInfo,
|
||||||
|
editingId: frozenEditingId,
|
||||||
|
isSenderChannel,
|
||||||
|
} = useFrozenProps(props, isClosing);
|
||||||
|
|
||||||
|
const isForwardingRendering = Boolean(frozenForwardedMessagesCount);
|
||||||
|
const isShowingReplyRendering = Boolean(frozenReplyInfo) && !frozenShouldForceShowEditing;
|
||||||
|
const isReplyWithQuoteRendering = Boolean(frozenReplyInfo?.quoteText);
|
||||||
|
const isShowingSuggestedPostRendering = Boolean(frozenSuggestedPostInfo) && !frozenShouldForceShowEditing;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (shouldPreventComposerAnimation) {
|
if (shouldPreventComposerAnimation) {
|
||||||
setShouldPreventComposerAnimation({ shouldPreventComposerAnimation: false });
|
setShouldPreventComposerAnimation({ shouldPreventComposerAnimation: false });
|
||||||
@ -176,14 +191,14 @@ const ComposerEmbeddedMessage = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const clearEmbedded = useLastCallback(() => {
|
const clearEmbedded = useLastCallback(() => {
|
||||||
if (editingId) {
|
if (frozenEditingId) {
|
||||||
setEditingId({ messageId: undefined });
|
setEditingId({ messageId: undefined });
|
||||||
} else if (forwardedMessagesCount) {
|
} else if (frozenForwardedMessagesCount) {
|
||||||
exitForwardMode();
|
exitForwardMode();
|
||||||
} else if (isShowingSuggestedPost) {
|
} else if (isShowingSuggestedPostRendering) {
|
||||||
resetDraftSuggestedPostInfo();
|
resetDraftSuggestedPostInfo();
|
||||||
resetDraftReplyInfo();
|
resetDraftReplyInfo();
|
||||||
} else if (replyInfo && !shouldForceShowEditing) {
|
} else if (frozenReplyInfo && !frozenShouldForceShowEditing) {
|
||||||
resetDraftReplyInfo();
|
resetDraftReplyInfo();
|
||||||
}
|
}
|
||||||
onClear?.();
|
onClear?.();
|
||||||
@ -197,10 +212,10 @@ const ComposerEmbeddedMessage = ({
|
|||||||
} = useContextMenuHandlers(ref);
|
} = useContextMenuHandlers(ref);
|
||||||
|
|
||||||
const focusMessageFromDraft = () => {
|
const focusMessageFromDraft = () => {
|
||||||
focusMessage({ chatId: message!.chatId, messageId: message!.id, noForumTopicPanel: true });
|
focusMessage({ chatId: frozenMessage!.chatId, messageId: frozenMessage!.id, noForumTopicPanel: true });
|
||||||
};
|
};
|
||||||
const handleMessageClick = useLastCallback((e: React.MouseEvent): void => {
|
const handleMessageClick = useLastCallback((e: React.MouseEvent): void => {
|
||||||
if (suggestedPostInfo) {
|
if (frozenSuggestedPostInfo) {
|
||||||
openSuggestMessageModal({ chatId });
|
openSuggestMessageModal({ chatId });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -231,6 +246,13 @@ const ComposerEmbeddedMessage = ({
|
|||||||
});
|
});
|
||||||
const handleDoNotReplyClick = useLastCallback(buildAutoCloseMenuItemHandler(clearEmbedded));
|
const handleDoNotReplyClick = useLastCallback(buildAutoCloseMenuItemHandler(clearEmbedded));
|
||||||
|
|
||||||
|
const handleIconKeyDown = useLastCallback((e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
handleContextMenu(e as unknown as React.MouseEvent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const getTriggerElement = useLastCallback(() => ref.current);
|
const getTriggerElement = useLastCallback(() => ref.current);
|
||||||
const getRootElement = useLastCallback(() => ref.current!);
|
const getRootElement = useLastCallback(() => ref.current!);
|
||||||
const getMenuElement = useLastCallback(() => ref.current!.querySelector('.forward-context-menu .bubble'));
|
const getMenuElement = useLastCallback(() => ref.current!.querySelector('.forward-context-menu .bubble'));
|
||||||
@ -243,47 +265,47 @@ const ComposerEmbeddedMessage = ({
|
|||||||
}, [handleContextMenuClose, handleContextMenuHide, shouldRender]);
|
}, [handleContextMenuClose, handleContextMenuHide, shouldRender]);
|
||||||
|
|
||||||
const className = buildClassName('ComposerEmbeddedMessage', transitionClassNames);
|
const className = buildClassName('ComposerEmbeddedMessage', transitionClassNames);
|
||||||
const renderingSender = useCurrentOrPrev(sender, true);
|
|
||||||
|
|
||||||
const { className: peerColorClass, style: peerColorStyle } = usePeerColor({
|
const { className: peerColorClass, style: peerColorStyle } = usePeerColor({
|
||||||
peer: renderingSender,
|
peer: sender,
|
||||||
theme,
|
theme,
|
||||||
});
|
});
|
||||||
const innerClassName = buildClassName('ComposerEmbeddedMessage_inner', peerColorClass);
|
const innerClassName = buildClassName('ComposerEmbeddedMessage_inner', peerColorClass);
|
||||||
|
|
||||||
const leftIcon = useMemo(() => {
|
const leftIcon = useMemo(() => {
|
||||||
if (editingId) {
|
if (frozenEditingId) {
|
||||||
return 'edit';
|
return 'edit';
|
||||||
}
|
}
|
||||||
if (isShowingSuggestedPost) {
|
if (isShowingSuggestedPostRendering) {
|
||||||
return 'cash-circle';
|
return 'cash-circle';
|
||||||
}
|
}
|
||||||
if (isForwarding) {
|
if (isForwardingRendering) {
|
||||||
return 'forward';
|
return 'forward';
|
||||||
}
|
}
|
||||||
if (isShowingReply) {
|
if (isShowingReplyRendering) {
|
||||||
return 'reply';
|
return 'reply';
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}, [editingId, isForwarding, isShowingReply, isShowingSuggestedPost]);
|
}, [frozenEditingId, isForwardingRendering, isShowingReplyRendering, isShowingSuggestedPostRendering]);
|
||||||
|
|
||||||
const customText = forwardedMessagesCount && forwardedMessagesCount > 1
|
const customText = frozenForwardedMessagesCount && frozenForwardedMessagesCount > 1
|
||||||
? oldLang('ForwardedMessageCount', forwardedMessagesCount)
|
? oldLang('ForwardedMessageCount', frozenForwardedMessagesCount)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const strippedMessage = useMemo(() => {
|
const strippedMessage = useMemo(() => {
|
||||||
if (!message || !isForwarding || !message.content.text || !noAuthors || isCurrentUserPremium) return message;
|
if (!frozenMessage || !isForwardingRendering || !frozenMessage.content.text
|
||||||
|
|| !noAuthors || isCurrentUserPremium) return frozenMessage;
|
||||||
|
|
||||||
const strippedText = stripCustomEmoji(message.content.text);
|
const strippedText = stripCustomEmoji(frozenMessage.content.text);
|
||||||
return {
|
return {
|
||||||
...message,
|
...frozenMessage,
|
||||||
content: {
|
content: {
|
||||||
...message.content,
|
...frozenMessage.content,
|
||||||
text: strippedText,
|
text: strippedText,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}, [isCurrentUserPremium, isForwarding, message, noAuthors]);
|
}, [isCurrentUserPremium, isForwardingRendering, frozenMessage, noAuthors]);
|
||||||
|
|
||||||
const renderingLeftIcon = useCurrentOrPrev(leftIcon, true);
|
const renderingLeftIcon = useCurrentOrPrev(leftIcon, true);
|
||||||
|
|
||||||
@ -291,22 +313,29 @@ const ComposerEmbeddedMessage = ({
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canReplyInSenderChat = sender && !isSenderChannel && chatId !== sender.id && sender.id !== currentUserId;
|
const canReplyInSenderChat = sender && !isSenderChannel
|
||||||
|
&& chatId !== sender.id && sender.id !== currentUserId;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} ref={ref} onContextMenu={handleContextMenu}>
|
<div className={className} ref={ref} onContextMenu={handleContextMenu}>
|
||||||
<div className={innerClassName} style={peerColorStyle}>
|
<div className={innerClassName} style={peerColorStyle}>
|
||||||
<div className="embedded-left-icon" onClick={handleContextMenu}>
|
<div
|
||||||
|
className="embedded-left-icon"
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={handleContextMenu}
|
||||||
|
onKeyDown={handleIconKeyDown}
|
||||||
|
>
|
||||||
{renderingLeftIcon && <Icon name={renderingLeftIcon} />}
|
{renderingLeftIcon && <Icon name={renderingLeftIcon} />}
|
||||||
{Boolean(replyInfo?.quoteText) && (
|
{Boolean(frozenReplyInfo?.quoteText) && (
|
||||||
<Icon name="quote" className="quote-reply" />
|
<Icon name="quote" className="quote-reply" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<EmbeddedMessage
|
<EmbeddedMessage
|
||||||
isOpen={isShown}
|
isOpen={isShown}
|
||||||
className="inside-input"
|
className="inside-input"
|
||||||
replyInfo={replyInfo}
|
replyInfo={frozenReplyInfo}
|
||||||
suggestedPostInfo={suggestedPostInfo}
|
suggestedPostInfo={frozenSuggestedPostInfo}
|
||||||
isMediaNsfw={isMediaNsfw}
|
isMediaNsfw={isMediaNsfw}
|
||||||
isInComposer
|
isInComposer
|
||||||
message={strippedMessage}
|
message={strippedMessage}
|
||||||
@ -314,7 +343,7 @@ const ComposerEmbeddedMessage = ({
|
|||||||
composerForwardSenders={forwardSenders}
|
composerForwardSenders={forwardSenders}
|
||||||
customText={customText}
|
customText={customText}
|
||||||
noCaptions={noCaptions}
|
noCaptions={noCaptions}
|
||||||
title={(editingId && !isShowingReply) ? oldLang('EditMessage')
|
title={(frozenEditingId && !isShowingReplyRendering) ? oldLang('EditMessage')
|
||||||
: noAuthors ? oldLang('HiddenSendersNameDescription') : undefined}
|
: noAuthors ? oldLang('HiddenSendersNameDescription') : undefined}
|
||||||
onClick={handleMessageClick}
|
onClick={handleMessageClick}
|
||||||
senderChat={senderChat}
|
senderChat={senderChat}
|
||||||
@ -328,7 +357,7 @@ const ComposerEmbeddedMessage = ({
|
|||||||
onClick={handleClearClick}
|
onClick={handleClearClick}
|
||||||
iconName="close"
|
iconName="close"
|
||||||
/>
|
/>
|
||||||
{(isShowingReply || isForwarding) && !isContextMenuDisabled && (
|
{(isShowingReplyRendering || isForwardingRendering) && !isContextMenuDisabled && (
|
||||||
<Menu
|
<Menu
|
||||||
isOpen={isContextMenuOpen}
|
isOpen={isContextMenuOpen}
|
||||||
anchor={contextMenuAnchor}
|
anchor={contextMenuAnchor}
|
||||||
@ -339,7 +368,7 @@ const ComposerEmbeddedMessage = ({
|
|||||||
onClose={handleContextMenuClose}
|
onClose={handleContextMenuClose}
|
||||||
onCloseAnimationEnd={handleContextMenuHide}
|
onCloseAnimationEnd={handleContextMenuHide}
|
||||||
>
|
>
|
||||||
{isForwarding && (
|
{isForwardingRendering && (
|
||||||
<>
|
<>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={!noAuthors ? 'message-succeeded' : undefined}
|
icon={!noAuthors ? 'message-succeeded' : undefined}
|
||||||
@ -349,7 +378,7 @@ const ComposerEmbeddedMessage = ({
|
|||||||
noAuthors: false,
|
noAuthors: false,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{oldLang(forwardedMessagesCount > 1 ? 'ShowSenderNames' : 'ShowSendersName')}
|
{oldLang(frozenForwardedMessagesCount > 1 ? 'ShowSenderNames' : 'ShowSendersName')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={noAuthors ? 'message-succeeded' : undefined}
|
icon={noAuthors ? 'message-succeeded' : undefined}
|
||||||
@ -359,7 +388,7 @@ const ComposerEmbeddedMessage = ({
|
|||||||
noAuthors: true,
|
noAuthors: true,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{oldLang(forwardedMessagesCount > 1 ? 'HideSenderNames' : 'HideSendersName')}
|
{oldLang(frozenForwardedMessagesCount > 1 ? 'HideSenderNames' : 'HideSendersName')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{forwardsHaveCaptions && (
|
{forwardsHaveCaptions && (
|
||||||
<>
|
<>
|
||||||
@ -372,7 +401,8 @@ const ComposerEmbeddedMessage = ({
|
|||||||
noCaptions: false,
|
noCaptions: false,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{oldLang(forwardedMessagesCount > 1 ? 'Conversation.ForwardOptions.ShowCaption' : 'ShowCaption')}
|
{oldLang(frozenForwardedMessagesCount > 1
|
||||||
|
? 'Conversation.ForwardOptions.ShowCaption' : 'ShowCaption')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={noCaptions ? 'message-succeeded' : undefined}
|
icon={noCaptions ? 'message-succeeded' : undefined}
|
||||||
@ -382,7 +412,8 @@ const ComposerEmbeddedMessage = ({
|
|||||||
noCaptions: true,
|
noCaptions: true,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{oldLang(forwardedMessagesCount > 1 ? 'Conversation.ForwardOptions.HideCaption' : 'HideCaption')}
|
{oldLang(frozenForwardedMessagesCount > 1
|
||||||
|
? 'Conversation.ForwardOptions.HideCaption' : 'HideCaption')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -392,7 +423,7 @@ const ComposerEmbeddedMessage = ({
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{isShowingReply && (
|
{isShowingReplyRendering && (
|
||||||
<>
|
<>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon="show-message"
|
icon="show-message"
|
||||||
@ -400,7 +431,7 @@ const ComposerEmbeddedMessage = ({
|
|||||||
>
|
>
|
||||||
{oldLang('Message.Context.Goto')}
|
{oldLang('Message.Context.Goto')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{isReplyWithQuote && (
|
{isReplyWithQuoteRendering && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon="remove-quote"
|
icon="remove-quote"
|
||||||
onClick={handleRemoveQuoteClick}
|
onClick={handleRemoveQuoteClick}
|
||||||
|
|||||||
24
src/hooks/useFrozenProps.ts
Normal file
24
src/hooks/useFrozenProps.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { useRef } from '../lib/teact/teact';
|
||||||
|
|
||||||
|
export default function useFrozenProps<T extends Record<string, unknown>>(
|
||||||
|
props: T,
|
||||||
|
shouldFreeze: boolean,
|
||||||
|
alwaysFreshKeys?: readonly (keyof T)[],
|
||||||
|
): T {
|
||||||
|
const frozenRef = useRef<T>(props);
|
||||||
|
|
||||||
|
if (!shouldFreeze) {
|
||||||
|
frozenRef.current = props;
|
||||||
|
} else if (alwaysFreshKeys?.length) {
|
||||||
|
const updates: Partial<T> = {};
|
||||||
|
for (const key of alwaysFreshKeys) {
|
||||||
|
updates[key] = props[key];
|
||||||
|
}
|
||||||
|
frozenRef.current = {
|
||||||
|
...frozenRef.current,
|
||||||
|
...updates,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return frozenRef.current;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user