mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-10-31 16:22:49 +00:00
Merge pull request #7353 from hayaksi1/fix/860-enter-sends-message
Send a message with Enter on a physical keyboard, Shift+Enter for a new line
This commit is contained in:
+3
-2
@@ -161,6 +161,8 @@ fun TextComposer(
|
||||
} else {
|
||||
stringResource(id = R.string.rich_text_editor_composer_placeholder)
|
||||
}
|
||||
val canSendTextMessage = markdown.isNotBlank() || composerMode is MessageComposerMode.Attachment
|
||||
|
||||
val textInput: @Composable () -> Unit = when (state) {
|
||||
is TextEditorState.Rich -> {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
@@ -219,14 +221,13 @@ fun TextComposer(
|
||||
onReceiveSuggestion = onReceiveSuggestion,
|
||||
richTextEditorStyle = style,
|
||||
onSelectRichContent = onSelectRichContent,
|
||||
onSendMessage = { if (canSendTextMessage) onSendMessage() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val canSendTextMessage = markdown.isNotBlank() || composerMode is MessageComposerMode.Attachment
|
||||
|
||||
val textFormattingOptions: @Composable (() -> Unit)? = (state as? TextEditorState.Rich)?.let {
|
||||
@Composable { TextFormatting(state = it.richTextEditorState) }
|
||||
}
|
||||
|
||||
+21
@@ -9,6 +9,8 @@
|
||||
package io.element.android.libraries.textcomposer.components.markdown
|
||||
|
||||
import android.content.Context
|
||||
import android.view.KeyCharacterMap
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
|
||||
@@ -17,8 +19,27 @@ internal class MarkdownEditText(
|
||||
) : AppCompatEditText(context) {
|
||||
var onSelectionChangeListener: ((Int, Int) -> Unit)? = null
|
||||
|
||||
var onEnterKeyListener: (() -> Boolean)? = null
|
||||
|
||||
private var isModifyingText = false
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
if (event.keyCode == KeyEvent.KEYCODE_ENTER &&
|
||||
!event.isShiftPressed &&
|
||||
event.deviceId != KeyCharacterMap.VIRTUAL_KEYBOARD
|
||||
) {
|
||||
val listener = onEnterKeyListener
|
||||
if (listener != null) {
|
||||
return when (event.action) {
|
||||
KeyEvent.ACTION_UP -> true
|
||||
KeyEvent.ACTION_DOWN -> if (event.repeatCount == 0) listener() else true
|
||||
else -> super.dispatchKeyEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
fun updateEditableText(charSequence: CharSequence) {
|
||||
isModifyingText = true
|
||||
editableText.clear()
|
||||
|
||||
+7
@@ -54,6 +54,7 @@ fun MarkdownTextInput(
|
||||
onReceiveSuggestion: (Suggestion?) -> Unit,
|
||||
richTextEditorStyle: RichTextEditorStyle,
|
||||
onSelectRichContent: ((Uri) -> Unit)?,
|
||||
onSendMessage: (() -> Unit)? = null,
|
||||
) {
|
||||
// Copied from io.element.android.wysiwyg.internal.utils.UriContentListener
|
||||
class ReceiveUriContentListener(
|
||||
@@ -132,6 +133,12 @@ fun MarkdownTextInput(
|
||||
update = { editText ->
|
||||
editText.contentDescription = placeholder
|
||||
editText.applyStyleInCompose(richTextEditorStyle)
|
||||
editText.onEnterKeyListener = onSendMessage?.let { send ->
|
||||
{
|
||||
send()
|
||||
true
|
||||
}
|
||||
}
|
||||
val text = state.text.value()
|
||||
mentionSpanUpdater.updateMentionSpans(text)
|
||||
if (state.text.needsDisplaying()) {
|
||||
|
||||
+67
@@ -10,6 +10,8 @@
|
||||
|
||||
package io.element.android.libraries.textcomposer.impl.components.markdown
|
||||
|
||||
import android.view.KeyCharacterMap
|
||||
import android.view.KeyEvent
|
||||
import android.widget.EditText
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||
@@ -32,12 +34,51 @@ import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState
|
||||
import io.element.android.libraries.textcomposer.model.Suggestion
|
||||
import io.element.android.libraries.textcomposer.model.SuggestionType
|
||||
import io.element.android.libraries.textcomposer.model.aMarkdownTextEditorState
|
||||
import io.element.android.tests.testutils.EnsureCalledOnce
|
||||
import io.element.android.tests.testutils.EnsureCalledOnceWithParam
|
||||
import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||
import org.junit.Test
|
||||
|
||||
class MarkdownTextInputTest : RobolectricTest() {
|
||||
@Test
|
||||
fun `pressing enter on a physical keyboard sends the message`() = runAndroidComposeUiTest {
|
||||
val state = aMarkdownTextEditorState(initialText = "Hello", initialFocus = true)
|
||||
val onSendMessage = EnsureCalledOnce()
|
||||
setMarkdownTextInput(state = state, onSendMessage = onSendMessage)
|
||||
val editor = activity!!.findEditor()
|
||||
editor.pressEnter()
|
||||
awaitIdle()
|
||||
onSendMessage.assertSuccess()
|
||||
assertThat(editor.editableText.toString()).isEqualTo("Hello")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pressing shift enter on a physical keyboard inserts a new line`() = runAndroidComposeUiTest {
|
||||
val state = aMarkdownTextEditorState(initialText = "Hello", initialFocus = true)
|
||||
var sendCount = 0
|
||||
setMarkdownTextInput(state = state, onSendMessage = { sendCount++ })
|
||||
val editor = activity!!.findEditor()
|
||||
editor.setSelection(editor.editableText.length)
|
||||
editor.pressEnter(metaState = KeyEvent.META_SHIFT_ON)
|
||||
awaitIdle()
|
||||
assertThat(sendCount).isEqualTo(0)
|
||||
assertThat(editor.editableText.toString()).isEqualTo("Hello\n")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pressing enter on the soft keyboard does not send the message`() = runAndroidComposeUiTest {
|
||||
val state = aMarkdownTextEditorState(initialText = "Hello", initialFocus = true)
|
||||
var sendCount = 0
|
||||
setMarkdownTextInput(state = state, onSendMessage = { sendCount++ })
|
||||
val editor = activity!!.findEditor()
|
||||
editor.setSelection(editor.editableText.length)
|
||||
editor.pressEnter(deviceId = KeyCharacterMap.VIRTUAL_KEYBOARD)
|
||||
awaitIdle()
|
||||
assertThat(sendCount).isEqualTo(0)
|
||||
assertThat(editor.editableText.toString()).isEqualTo("Hello\n")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when user types onTyping is triggered with value 'true'`() = runAndroidComposeUiTest {
|
||||
val state = aMarkdownTextEditorState(initialFocus = true)
|
||||
@@ -150,6 +191,7 @@ class MarkdownTextInputTest : RobolectricTest() {
|
||||
state: MarkdownTextEditorState = aMarkdownTextEditorState(),
|
||||
onTyping: (Boolean) -> Unit = {},
|
||||
onSuggestionReceived: (Suggestion?) -> Unit = {},
|
||||
onSendMessage: (() -> Unit)? = null,
|
||||
) {
|
||||
setContent {
|
||||
val style = ElementRichTextEditorStyle.composerStyle(hasFocus = state.hasFocus)
|
||||
@@ -161,6 +203,27 @@ class MarkdownTextInputTest : RobolectricTest() {
|
||||
onReceiveSuggestion = onSuggestionReceived,
|
||||
richTextEditorStyle = style,
|
||||
onSelectRichContent = null,
|
||||
onSendMessage = onSendMessage,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun EditText.pressEnter(
|
||||
metaState: Int = 0,
|
||||
deviceId: Int = PHYSICAL_KEYBOARD_DEVICE_ID,
|
||||
) {
|
||||
listOf(KeyEvent.ACTION_DOWN, KeyEvent.ACTION_UP).forEach { action ->
|
||||
dispatchKeyEvent(
|
||||
KeyEvent(
|
||||
0L,
|
||||
0L,
|
||||
action,
|
||||
KeyEvent.KEYCODE_ENTER,
|
||||
0,
|
||||
metaState,
|
||||
deviceId,
|
||||
0,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -168,4 +231,8 @@ class MarkdownTextInputTest : RobolectricTest() {
|
||||
private fun ComponentActivity.findEditor(): EditText {
|
||||
return window.decorView.findViewWithTag(TestTags.plainTextEditor.value)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PHYSICAL_KEYBOARD_DEVICE_ID = 1
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user