Skip to content
Snippets Groups Projects
Commit 7e1f7a76 authored by Mikolai Gütschow's avatar Mikolai Gütschow Committed by Sebastian
Browse files

add custom TextField that reacts on enter and shift-enter

parent dc028e2f
No related branches found
No related tags found
1 merge request!68Send messages on enter
Pipeline #8814 passed
package androidx.compose.material
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.shape.ZeroCornerSize
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.isAltPressed
import androidx.compose.ui.input.key.isCtrlPressed
import androidx.compose.ui.input.key.isMetaPressed
import androidx.compose.ui.input.key.isShiftPressed
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun TextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
onEnter: () -> Unit = {},
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = LocalTextStyle.current,
label: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
isError: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
singleLine: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape =
MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
colors: TextFieldColors = TextFieldDefaults.textFieldColors()
) {
var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = value)) }
val textFieldValue = textFieldValueState.copy(text = value)
val modifier = Modifier.onPreviewKeyEvent {
if (it.type == KeyEventType.KeyDown && it.key == Key.Enter) {
if (it.isShiftPressed) {
textFieldValueState = textFieldValue.insertOrReplaceBy("\n")
onValueChange(textFieldValueState.text)
} else if (!it.isModifierKeyPressed) {
onEnter()
}
return@onPreviewKeyEvent true
}
false
}.then(modifier)
TextField(
enabled = enabled,
readOnly = readOnly,
value = textFieldValue,
onValueChange = {
textFieldValueState = it
if (value != it.text) {
onValueChange(it.text)
}
},
modifier = modifier,
singleLine = singleLine,
textStyle = textStyle,
label = label,
placeholder = placeholder,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
isError = isError,
visualTransformation = visualTransformation,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { onEnter() }),
maxLines = maxLines,
interactionSource = interactionSource,
shape = shape,
colors = colors
)
}
val KeyEvent.isModifierKeyPressed: Boolean
get() = isShiftPressed || isAltPressed || isMetaPressed || isCtrlPressed
fun TextFieldValue.insertOrReplaceBy(replacement: CharSequence) = this.copy(
text = text.replaceRange(selection.min, selection.max, replacement),
selection = TextRange(selection.min + 1, selection.min + 1)
)
package org.briarproject.briar.desktop.conversation
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
......@@ -8,10 +7,11 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.AlertDialog
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TextFieldDefaults
......@@ -19,22 +19,32 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Send
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.briarproject.briar.desktop.theme.DarkColors
import org.briarproject.briar.desktop.ui.HorizontalDivider
import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
import org.briarproject.briar.desktop.utils.PreviewUtils.preview
@Preview
@Composable
fun PreviewConversationInput() {
MaterialTheme(colors = DarkColors) {
Surface {
ConversationInput("Lorem ipsum.", {}, {})
}
@OptIn(ExperimentalMaterialApi::class)
fun main() = preview {
val (text, updateText) = remember { mutableStateOf("Lorem ipsum.") }
var dialogVisible by remember { mutableStateOf(false) }
var sentText by remember { mutableStateOf("") }
ConversationInput(text, updateText) { dialogVisible = true; sentText = text; updateText("") }
if (dialogVisible) {
AlertDialog(
onDismissRequest = { dialogVisible = false },
buttons = {},
text = { Text(sentText) },
)
}
}
......@@ -45,6 +55,7 @@ fun ConversationInput(text: String, updateText: (String) -> Unit, onSend: () ->
TextField(
value = text,
onValueChange = updateText,
onEnter = onSend,
maxLines = 10,
textStyle = TextStyle(fontSize = 16.sp, lineHeight = 16.sp),
placeholder = { Text(i18n("conversation.message.new")) },
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment