mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
fix(app): skip forwarded messages when editing with arrow up (#3234)
This commit is contained in:
@@ -1,170 +0,0 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import * as MessageCommands from '@app/features/messaging/commands/MessageCommands';
|
||||
import type {Message} from '@app/features/messaging/models/MessagingMessage';
|
||||
import MessageEdit from '@app/features/messaging/state/MessageEdit';
|
||||
import MessageFocus from '@app/features/messaging/state/MessageFocus';
|
||||
import {insertTextAtCursor} from '@app/features/messaging/utils/TextInputEditUtils';
|
||||
import {ComponentBus} from '@app/features/platform/utils/ComponentBus';
|
||||
import {canFocusTextarea, safeFocus} from '@app/features/platform/utils/InputFocusManager';
|
||||
import {isTextInputKeyEvent} from '@app/features/platform/utils/IsTextInputKeyEvent';
|
||||
import QuickSwitcher from '@app/features/search/state/QuickSwitcher';
|
||||
import ContextMenu from '@app/features/ui/state/ContextMenu';
|
||||
import KeyboardMode from '@app/features/ui/state/KeyboardMode';
|
||||
import MobileLayout from '@app/features/ui/state/MobileLayout';
|
||||
import {useCallback, useEffect} from 'react';
|
||||
|
||||
interface UseTextareaKeyboardOptions {
|
||||
channelId: string;
|
||||
isFocused: boolean;
|
||||
textareaRef: React.RefObject<HTMLTextAreaElement | null>;
|
||||
value: string;
|
||||
setValue: React.Dispatch<React.SetStateAction<string>>;
|
||||
handleTextChange: (newValue: string, previousValue: string) => void;
|
||||
previousValueRef: React.RefObject<string>;
|
||||
clearSegments: () => void;
|
||||
replyingMessage: {
|
||||
messageId: string;
|
||||
mentioning: boolean;
|
||||
} | null;
|
||||
editingMessage: Message | null;
|
||||
getLastEditableMessage: () => Message | null;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
type ArrowUpEditShortcutEvent = Pick<
|
||||
React.KeyboardEvent | KeyboardEvent,
|
||||
'key' | 'altKey' | 'ctrlKey' | 'metaKey' | 'shiftKey' | 'defaultPrevented'
|
||||
>;
|
||||
|
||||
export const shouldStartLastMessageEditFromArrowUp = (event: ArrowUpEditShortcutEvent, value: string): boolean => {
|
||||
if (event.defaultPrevented) return false;
|
||||
if (event.key !== 'ArrowUp') return false;
|
||||
if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return false;
|
||||
return value.length === 0;
|
||||
};
|
||||
export const useTextareaKeyboard = ({
|
||||
channelId,
|
||||
isFocused,
|
||||
textareaRef,
|
||||
value,
|
||||
setValue,
|
||||
handleTextChange,
|
||||
previousValueRef,
|
||||
clearSegments,
|
||||
replyingMessage,
|
||||
editingMessage,
|
||||
getLastEditableMessage,
|
||||
enabled,
|
||||
}: UseTextareaKeyboardOptions) => {
|
||||
const mobileLayout = MobileLayout;
|
||||
const editingMessageId = MessageEdit.getEditingMessageId(channelId);
|
||||
useEffect(() => {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
const textarea = textareaRef.current;
|
||||
if (!canFocusTextarea(textarea || undefined)) {
|
||||
return;
|
||||
}
|
||||
if (isFocused) {
|
||||
return;
|
||||
}
|
||||
if (QuickSwitcher.getIsOpen()) {
|
||||
return;
|
||||
}
|
||||
if (ContextMenu.contextMenu) {
|
||||
return;
|
||||
}
|
||||
if (KeyboardMode.keyboardModeEnabled && MessageFocus.focusedMessageId) {
|
||||
return;
|
||||
}
|
||||
if (!isTextInputKeyEvent(event)) {
|
||||
return;
|
||||
}
|
||||
if (!textarea) {
|
||||
return;
|
||||
}
|
||||
if (event.key === 'Dead') {
|
||||
safeFocus(textarea, true);
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
safeFocus(textarea, true);
|
||||
const inserted = insertTextAtCursor(textarea, event.key);
|
||||
if (!inserted) {
|
||||
setValue((prev) => {
|
||||
const newValue = prev + event.key;
|
||||
handleTextChange(newValue, previousValueRef.current ?? '');
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [
|
||||
editingMessageId,
|
||||
isFocused,
|
||||
mobileLayout.enabled,
|
||||
handleTextChange,
|
||||
previousValueRef,
|
||||
textareaRef,
|
||||
setValue,
|
||||
enabled,
|
||||
]);
|
||||
useEffect(() => {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
const isEditingInline = MessageEdit.getEditingMessageId(channelId) != null;
|
||||
if (isEditingInline) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
MessageCommands.stopEdit(channelId);
|
||||
return;
|
||||
}
|
||||
if (editingMessage && mobileLayout.enabled) {
|
||||
event.preventDefault();
|
||||
MessageCommands.stopEditMobile(channelId);
|
||||
setValue('');
|
||||
clearSegments();
|
||||
} else if (replyingMessage) {
|
||||
event.preventDefault();
|
||||
MessageCommands.stopReply(channelId);
|
||||
} else {
|
||||
event.preventDefault();
|
||||
ComponentBus.dispatch('ESCAPE_PRESSED');
|
||||
}
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [channelId, replyingMessage, editingMessage, mobileLayout.enabled, clearSegments, setValue, enabled]);
|
||||
const handleArrowUp = useCallback(
|
||||
(event: React.KeyboardEvent) => {
|
||||
if (!shouldStartLastMessageEditFromArrowUp(event, value)) {
|
||||
return;
|
||||
}
|
||||
if (KeyboardMode.keyboardModeEnabled) {
|
||||
event.preventDefault();
|
||||
ComponentBus.dispatch('FOCUS_BOTTOMMOST_MESSAGE', {channelId});
|
||||
return;
|
||||
}
|
||||
const message = getLastEditableMessage();
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
MessageCommands.startEdit(channelId, message.id, message.content);
|
||||
},
|
||||
[channelId, value, getLastEditableMessage],
|
||||
);
|
||||
return {handleArrowUp};
|
||||
};
|
||||
@@ -232,7 +232,12 @@ class Messages {
|
||||
|
||||
getLastEditableMessage(channelId: string): Message | undefined {
|
||||
return this.getMessages(channelId).searchFromNewest((message) => {
|
||||
return message.isCurrentUserAuthor() && message.state === MessageStates.SENT && message.isUserMessage();
|
||||
return (
|
||||
message.isCurrentUserAuthor() &&
|
||||
message.state === MessageStates.SENT &&
|
||||
message.isUserMessage() &&
|
||||
!message.messageSnapshots
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user