From 8f2a41bc13dda5eca99706eeec4f9408a5954020 Mon Sep 17 00:00:00 2001 From: keejef Date: Wed, 20 Sep 2023 09:23:52 +1000 Subject: [PATCH] feat: Allow enter to break line in settings https://github.com/oxen-io/session-desktop/issues/1486 --- _locales/en/messages.json | 4 ++ .../composition/CompositionBox.tsx | 41 +++++++++++++++++- .../section/CategoryConversations.tsx | 42 +++++++++++++++++-- ts/data/settings-key.ts | 3 +- ts/types/LocalizerKeys.ts | 4 ++ 5 files changed, 87 insertions(+), 7 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 09a67aa7b..70a8e2a5c 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -410,6 +410,10 @@ "open": "Open", "audioMessageAutoplayTitle": "Autoplay Audio Messages", "audioMessageAutoplayDescription": "Autoplay consecutive audio messages.", + "enterKeySettingTitle": "Enter Key", + "enterKeySettingDescription": "Function of the enter key when typing in a conversation.", + "enterSendNewMessageDescription": "ENTER sends a message, SHIFT + ENTER starts a new line", + "enterNewLineDescription": "SHIFT + ENTER sends a message, ENTER starts a new line", "clickToTrustContact": "Click to download media", "trustThisContactDialogTitle": "Trust $name$?", "trustThisContactDialogDescription": "Are you sure you want to download media sent by $name$?", diff --git a/ts/components/conversation/composition/CompositionBox.tsx b/ts/components/conversation/composition/CompositionBox.tsx index c3669e78a..c1d2d05e4 100644 --- a/ts/components/conversation/composition/CompositionBox.tsx +++ b/ts/components/conversation/composition/CompositionBox.tsx @@ -832,8 +832,19 @@ class CompositionBoxInner extends React.Component { } private async onKeyDown(event: any) { - if (event.key === 'Enter' && !event.shiftKey && !event.nativeEvent.isComposing) { - // If shift, newline. If in IME composing mode, leave it to IME. Else send message. + const isEnter = event.key === 'Enter'; + const isShiftEnter = event.shiftKey && isEnter; + const isEnterNewLineSetting = (window.getSettingValue(SettingsKey.settingsEnterKeyFunction) as string) === 'enterNewLine'; + const isNotComposing = !event.nativeEvent.isComposing; + + if (isEnterNewLineSetting && isEnter && isNotComposing) { + event.preventDefault(); + if (isShiftEnter) { + await this.onSendMessage(); + } else { + this.insertNewLine(); + } + } else if (isEnter && !event.shiftKey && isNotComposing) { event.preventDefault(); await this.onSendMessage(); } else if (event.key === 'Escape' && this.state.showEmojiPanel) { @@ -845,6 +856,32 @@ class CompositionBoxInner extends React.Component { } } + private insertNewLine() { + const messageBox = this.textarea.current; + if (!messageBox) { + return; + } + + const { draft } = this.state; + const { selectedConversationKey } = this.props; + + if (!selectedConversationKey) { + return; // add this check to prevent undefined from being used + } + + const currentSelectionStart = Number(messageBox.selectionStart); + const realSelectionStart = getSelectionBasedOnMentions(draft, currentSelectionStart); + + const before = draft.slice(0, realSelectionStart); + const after = draft.slice(realSelectionStart); + + this.setState({ draft: `${before}\n${after}` }); + updateDraftForConversation({ + conversationKey: selectedConversationKey, + draft: `${before}\n${after}`, + }); + } + private async onKeyUp() { if (!this.props.selectedConversationKey) { throw new Error('selectedConversationKey is needed'); diff --git a/ts/components/settings/section/CategoryConversations.tsx b/ts/components/settings/section/CategoryConversations.tsx index 3830883ae..b0335af4d 100644 --- a/ts/components/settings/section/CategoryConversations.tsx +++ b/ts/components/settings/section/CategoryConversations.tsx @@ -6,10 +6,9 @@ import { SettingsKey } from '../../../data/settings-key'; import { ToastUtils } from '../../../session/utils'; import { toggleAudioAutoplay } from '../../../state/ducks/userConfig'; import { getAudioAutoplay } from '../../../state/selectors/userConfig'; - +import { SessionRadioGroup } from '../../basic/SessionRadioGroup'; import { BlockedContactsList } from '../BlockedList'; - -import { SessionToggleWithDescription } from '../SessionSettingListItem'; +import { SessionSettingsItemWrapper, SessionToggleWithDescription } from '../SessionSettingListItem'; async function toggleCommunitiesPruning() { try { @@ -81,13 +80,48 @@ const AudioMessageAutoPlaySetting = () => { ); }; +const EnterKeyFunctionSetting = () => { + const forceUpdate = useUpdate(); + + const initialSetting = window.getSettingValue(SettingsKey.settingsEnterKeyFunction) || true; + + const items = [ + { + label: window.i18n('enterSendNewMessageDescription'), + value: 'enterSend', + }, + { + label: window.i18n('enterNewLineDescription'), + value: 'enterNewLine', + }, + ]; + + return ( + + { + await window.setSettingValue(SettingsKey.settingsEnterKeyFunction, selectedRadioValue); + forceUpdate(); + }} + /> + + ); +}; + export const CategoryConversations = () => { return ( <> - + ); diff --git a/ts/data/settings-key.ts b/ts/data/settings-key.ts index 345e6b081..a34782706 100644 --- a/ts/data/settings-key.ts +++ b/ts/data/settings-key.ts @@ -1,7 +1,7 @@ const settingsReadReceipt = 'read-receipt-setting'; const settingsTypingIndicator = 'typing-indicators-setting'; const settingsAutoUpdate = 'auto-update'; - +const settingsEnterKeyFunction = 'enter-key-function-setting'; const settingsMenuBar = 'hide-menu-bar'; const settingsSpellCheck = 'spell-check'; const settingsLinkPreview = 'link-preview-setting'; @@ -24,6 +24,7 @@ export const SettingsKey = { settingsReadReceipt, settingsTypingIndicator, settingsAutoUpdate, + settingsEnterKeyFunction, settingsMenuBar, settingsSpellCheck, settingsLinkPreview, diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index ed5d4ad7f..f9cc384b1 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -169,9 +169,13 @@ export type LocalizerKeys = | 'endCall' | 'enterAnOpenGroupURL' | 'enterDisplayName' + | 'enterKeySettingDescription' + | 'enterKeySettingTitle' + | 'enterNewLineDescription' | 'enterNewPassword' | 'enterPassword' | 'enterRecoveryPhrase' + | 'enterSendNewMessageDescription' | 'enterSessionID' | 'enterSessionIDOfRecipient' | 'enterSessionIDOrONSName'