Composer / Embedded Message: Fix edit and reply (#2372)

This commit is contained in:
Alexander Zinchuk 2023-01-28 02:16:13 +01:00
parent 8d4e447981
commit 55a9715bca
3 changed files with 69 additions and 28 deletions

View File

@ -54,6 +54,7 @@ import {
selectChatType,
selectRequestedDraftFiles,
selectTabState,
selectReplyingToId,
} from '../../../global/selectors';
import {
getAllowedAttachmentOptions,
@ -145,6 +146,7 @@ type StateProps =
isChatWithBot?: boolean;
isChatWithSelf?: boolean;
isChannel?: boolean;
replyingToId?: number;
isForCurrentMessageList: boolean;
isRightColumnShown?: boolean;
isSelectModeActive?: boolean;
@ -260,6 +262,7 @@ const Composer: FC<OwnProps & StateProps> = ({
sendAsChat,
sendAsId,
editingDraft,
replyingToId,
requestedDraftText,
requestedDraftFiles,
botMenuButton,
@ -394,12 +397,6 @@ const Composer: FC<OwnProps & StateProps> = ({
sendMessageAction({ type: 'typing' });
}, [editingMessage, html, sendMessageAction]);
const mainButtonState = editingMessage ? MainButtonState.Edit
: (!IS_VOICE_RECORDING_SUPPORTED || activeVoiceRecording || (html && !attachments.length) || isForwarding)
? (shouldSchedule ? MainButtonState.Schedule : MainButtonState.Send)
: MainButtonState.Record;
const canShowCustomSendMenu = !shouldSchedule;
const {
isMentionTooltipOpen, closeMentionTooltip, insertMention, mentionFilteredUsers,
} = useMentionTooltip(
@ -438,13 +435,6 @@ const Composer: FC<OwnProps & StateProps> = ({
chatBotCommands,
);
const {
isContextMenuOpen: isCustomSendMenuOpen,
handleContextMenu,
handleContextMenuClose,
handleContextMenuHide,
} = useContextMenuHandlers(mainButtonRef, !(mainButtonState === MainButtonState.Send && canShowCustomSendMenu));
const {
canSendStickers, canSendGifs, canAttachMedia, canAttachPolls, canAttachEmbedLinks,
} = useMemo(() => getAllowedAttachmentOptions(chat, isChatWithBot), [chat, isChatWithBot]);
@ -597,7 +587,7 @@ const Composer: FC<OwnProps & StateProps> = ({
customEmojiNotificationNumber.current = Number(!notificationNumber);
}, [currentUserId, lang, showNotification]);
const [handleEditComplete, handleEditCancel] = useEditing(
const [handleEditComplete, handleEditCancel, shouldForceShowEditing] = useEditing(
htmlRef,
setHtml,
editingMessage,
@ -608,7 +598,36 @@ const Composer: FC<OwnProps & StateProps> = ({
messageListType,
draft,
editingDraft,
replyingToId,
);
const mainButtonState = useMemo(() => {
if (editingMessage && shouldForceShowEditing) {
return MainButtonState.Edit;
}
if (IS_VOICE_RECORDING_SUPPORTED && !activeVoiceRecording && !(html && !attachments.length) && !isForwarding) {
return MainButtonState.Record;
}
if (shouldSchedule) {
return MainButtonState.Schedule;
}
return MainButtonState.Send;
}, [
activeVoiceRecording, attachments.length, editingMessage, html, isForwarding, shouldForceShowEditing,
shouldSchedule,
]);
const canShowCustomSendMenu = !shouldSchedule;
const {
isContextMenuOpen: isCustomSendMenuOpen,
handleContextMenu,
handleContextMenuClose,
handleContextMenuHide,
} = useContextMenuHandlers(mainButtonRef, !(mainButtonState === MainButtonState.Send && canShowCustomSendMenu));
useDraft(draft, chatId, threadId, htmlRef, setHtml, editingMessage, lastSyncTime);
useClipboardPaste(
isForCurrentMessageList,
@ -1264,7 +1283,10 @@ const Composer: FC<OwnProps & StateProps> = ({
/>
<div id="message-compose">
<div className="svg-appendix" ref={appendixRef} />
<ComposerEmbeddedMessage onClear={handleEmbeddedClear} />
<ComposerEmbeddedMessage
onClear={handleEmbeddedClear}
shouldForceShowEditing={Boolean(shouldForceShowEditing && editingMessage)}
/>
<WebPagePreview
chatId={chatId}
threadId={threadId}
@ -1529,11 +1551,14 @@ export default memo(withGlobal<OwnProps>(
? selectEditingScheduledDraft(global, chatId)
: selectEditingDraft(global, chatId, threadId);
const replyingToId = selectReplyingToId(global, chatId, threadId);
const tabState = selectTabState(global);
return {
editingMessage: selectEditingMessage(global, chatId, threadId, messageListType),
connectionState: global.connectionState,
replyingToId,
draft: selectDraft(global, chatId, threadId),
chat,
isChatWithBot,

View File

@ -54,6 +54,7 @@ type StateProps = {
type OwnProps = {
onClear?: () => void;
shouldForceShowEditing?: boolean;
};
const FORWARD_RENDERING_DELAY = 300;
@ -68,6 +69,7 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
noAuthors,
noCaptions,
forwardsHaveCaptions,
shouldForceShowEditing,
isCurrentUserPremium,
onClear,
}) => {
@ -99,7 +101,7 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
} = useShowTransition(canAnimate && isShown, undefined, !shouldAnimate, undefined, !shouldAnimate);
const clearEmbedded = useCallback(() => {
if (replyingToId) {
if (replyingToId && !shouldForceShowEditing) {
setReplyingToId({ messageId: undefined });
} else if (editingId) {
setEditingId({ messageId: undefined });
@ -107,7 +109,10 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
exitForwardMode();
}
onClear?.();
}, [replyingToId, editingId, forwardedMessagesCount, onClear, setReplyingToId, setEditingId, exitForwardMode]);
}, [
replyingToId, shouldForceShowEditing, editingId, forwardedMessagesCount, onClear, setReplyingToId, setEditingId,
exitForwardMode,
]);
useEffect(() => (isShown ? captureEscKeyListener(clearEmbedded) : undefined), [isShown, clearEmbedded]);
@ -146,7 +151,7 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
const className = buildClassName('ComposerEmbeddedMessage', transitionClassNames);
const leftIcon = useMemo(() => {
if (replyingToId) {
if (replyingToId && !shouldForceShowEditing) {
return 'icon-reply';
}
if (editingId) {
@ -157,7 +162,7 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
}
return undefined;
}, [editingId, isForwarding, replyingToId]);
}, [editingId, isForwarding, replyingToId, shouldForceShowEditing]);
const customText = forwardedMessagesCount && forwardedMessagesCount > 1
? lang('ForwardedMessageCount', forwardedMessagesCount)
@ -274,7 +279,7 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
};
export default memo(withGlobal<OwnProps>(
(global): StateProps => {
(global, { shouldForceShowEditing }): StateProps => {
const { chatId, threadId, type: messageListType } = selectCurrentMessageList(global) || {};
if (!chatId || !threadId || !messageListType) {
return {};
@ -295,7 +300,7 @@ export default memo(withGlobal<OwnProps>(
const forwardedMessages = forwardMessageIds?.map((id) => selectChatMessage(global, fromChatId!, id)!);
let message: ApiMessage | undefined;
if (replyingToId) {
if (replyingToId && !shouldForceShowEditing) {
message = selectChatMessage(global, chatId, replyingToId);
} else if (editingId) {
message = selectEditingMessage(global, chatId, threadId, messageListType);
@ -304,7 +309,7 @@ export default memo(withGlobal<OwnProps>(
}
let sender: ApiChat | ApiUser | undefined;
if (replyingToId && message) {
if (replyingToId && message && !shouldForceShowEditing) {
const { forwardInfo } = message;
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
if (forwardInfo && (forwardInfo.isChannelPost || isChatWithSelf)) {

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect } from '../../../../lib/teact/teact';
import { useCallback, useEffect, useState } from '../../../../lib/teact/teact';
import { getActions } from '../../../../global';
import type { ApiFormattedText, ApiMessage } from '../../../../api/types';
@ -25,19 +25,30 @@ const useEditing = (
type: MessageListType,
draft?: ApiFormattedText,
editingDraft?: ApiFormattedText,
) => {
replyingToId?: number,
): [VoidFunction, VoidFunction, boolean] => {
const { editMessage, setEditingDraft } = getActions();
const [shouldForceShowEditing, setShouldForceShowEditing] = useState<boolean>();
useEffectWithPrevDeps(([prevEditedMessage]) => {
useEffectWithPrevDeps(([prevEditedMessage, prevReplyingToId]) => {
if (!editedMessage) {
return;
}
if (prevEditedMessage?.id === editedMessage.id) {
if (replyingToId && prevReplyingToId !== replyingToId) {
setHtml('');
setShouldForceShowEditing(false);
return;
}
if (prevEditedMessage?.id === editedMessage.id && replyingToId === prevReplyingToId) {
return;
}
const text = !prevEditedMessage && editingDraft?.text.length ? editingDraft : editedMessage.content.text;
const html = getTextWithEntitiesAsHtml(text);
setHtml(html);
setShouldForceShowEditing(true);
// `fastRaf` would execute syncronously in this case
requestAnimationFrame(() => {
const messageInput = document.querySelector<HTMLDivElement>(EDITABLE_INPUT_CSS_SELECTOR);
@ -45,7 +56,7 @@ const useEditing = (
focusEditableElement(messageInput, true);
}
});
}, [editedMessage, setHtml] as const);
}, [editedMessage, replyingToId, setHtml] as const);
useEffect(() => {
if (!editedMessage) return undefined;
@ -111,7 +122,7 @@ const useEditing = (
useBackgroundMode(handleBlur);
useBeforeUnload(handleBlur);
return [handleEditComplete, handleEditCancel];
return [handleEditComplete, handleEditCancel, shouldForceShowEditing];
};
export default useEditing;