diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/SendMsgView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/SendMsgView.kt index c7cb491322..ebe9e6e83d 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/SendMsgView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/SendMsgView.kt @@ -1,12 +1,15 @@ package chat.simplex.app.views.chat +import android.annotation.SuppressLint +import android.content.Context import android.content.res.Configuration +import android.text.InputType +import android.view.ViewGroup +import android.view.inputmethod.* +import android.widget.EditText import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.BasicTextField -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check @@ -14,27 +17,25 @@ import androidx.compose.material.icons.outlined.ArrowUpward import androidx.compose.runtime.* import androidx.compose.ui.* import androidx.compose.ui.draw.clip -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.graphics.* +import androidx.compose.ui.platform.* import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp -import androidx.core.text.BidiFormatter +import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.view.inputmethod.EditorInfoCompat +import androidx.core.view.inputmethod.InputConnectionCompat +import androidx.core.widget.doOnTextChanged import chat.simplex.app.R +import chat.simplex.app.SimplexApp import chat.simplex.app.model.ChatItem import chat.simplex.app.ui.theme.HighOrLowlight import chat.simplex.app.ui.theme.SimpleXTheme +import chat.simplex.app.views.helpers.SharedContent import kotlinx.coroutines.delay -import kotlin.math.min -@OptIn(ExperimentalComposeUiApi::class) @Composable fun SendMsgView( composeState: MutableState, @@ -43,82 +44,114 @@ fun SendMsgView( textStyle: MutableState ) { val cs = composeState.value - val focusRequester = remember { FocusRequester() } - val keyboard = LocalSoftwareKeyboardController.current + var showKeyboard by remember { mutableStateOf(false) } LaunchedEffect(cs.contextItem) { - if (cs.contextItem !is ComposeContextItem.QuotedItem) return@LaunchedEffect - // In replying state - focusRequester.requestFocus() - delay(50) - keyboard?.show() + when (cs.contextItem) { + is ComposeContextItem.QuotedItem -> { + delay(100) + showKeyboard = true + } + is ComposeContextItem.EditingItem -> { + // Keyboard will not show up if we try to show it too fast + delay(300) + showKeyboard = true + } + } } - val isRtl = remember(cs.message) { BidiFormatter.getInstance().isRtl(cs.message.subSequence(0, min(50, cs.message.length))) } - BasicTextField( - value = cs.message, - onValueChange = onMessageChange, - textStyle = textStyle.value, - maxLines = 16, - keyboardOptions = KeyboardOptions.Default.copy( - capitalization = KeyboardCapitalization.Sentences, - autoCorrect = true - ), - modifier = Modifier.padding(vertical = 8.dp).focusRequester(focusRequester), - cursorBrush = SolidColor(HighOrLowlight), - decorationBox = { innerTextField -> - Surface( - shape = RoundedCornerShape(18.dp), - border = BorderStroke(1.dp, MaterialTheme.colors.secondary) - ) { - Row( - Modifier.background(MaterialTheme.colors.background), - verticalAlignment = Alignment.Bottom - ) { - CompositionLocalProvider( - LocalLayoutDirection provides if (isRtl) LayoutDirection.Rtl else LocalLayoutDirection.current + val textColor = MaterialTheme.colors.onBackground + val tintColor = MaterialTheme.colors.secondary + val paddingStart = with(LocalDensity.current) { 12.dp.roundToPx() } + val paddingTop = with(LocalDensity.current) { 7.dp.roundToPx() } + val paddingEnd = with(LocalDensity.current) { 45.dp.roundToPx() } + val paddingBottom = with(LocalDensity.current) { 7.dp.roundToPx() } + + Column(Modifier.padding(vertical = 8.dp)) { + Box { + AndroidView(modifier = Modifier, factory = { + val editText = @SuppressLint("AppCompatCustomView") object: EditText(it) { + override fun setOnReceiveContentListener( + mimeTypes: Array?, + listener: android.view.OnReceiveContentListener? ) { - Box( - Modifier - .weight(1f) - .padding(horizontal = 12.dp) - .padding(top = 5.dp) - .padding(bottom = 7.dp) - ) { - innerTextField() - } + super.setOnReceiveContentListener(mimeTypes, listener) } - val icon = if (cs.editing) Icons.Filled.Check else Icons.Outlined.ArrowUpward - val color = if (cs.sendEnabled()) MaterialTheme.colors.primary else HighOrLowlight - if (cs.inProgress - && (cs.preview is ComposePreview.ImagePreview || cs.preview is ComposePreview.FilePreview) - ) { - CircularProgressIndicator( - Modifier - .size(36.dp) - .padding(4.dp), - color = HighOrLowlight, - strokeWidth = 3.dp - ) - } else { - Icon( - icon, - stringResource(R.string.icon_descr_send_message), - tint = Color.White, - modifier = Modifier - .size(36.dp) - .padding(4.dp) - .clip(CircleShape) - .background(color) - .clickable { - if (cs.sendEnabled()) { - sendMessage() - } + override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection { + val connection = super.onCreateInputConnection(editorInfo) + EditorInfoCompat.setContentMimeTypes(editorInfo, arrayOf("image/*")) + val onCommit = InputConnectionCompat.OnCommitContentListener { inputContentInfo, _, _ -> + try { + inputContentInfo.requestPermission() + } catch (e: Exception) { + return@OnCommitContentListener false } - ) + SimplexApp.context.chatModel.sharedContent.value = SharedContent.Images(listOf(inputContentInfo.contentUri)) + true + } + return InputConnectionCompat.createWrapper(connection, editorInfo, onCommit) } } + editText.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + editText.maxLines = 16 + editText.inputType = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or editText.inputType + editText.setTextColor(textColor.toArgb()) + editText.textSize = textStyle.value.fontSize.value + val drawable = it.getDrawable(R.drawable.send_msg_view_background)!! + DrawableCompat.setTint(drawable, tintColor.toArgb()) + editText.background = drawable + editText.setPadding(paddingStart, paddingTop, paddingEnd, paddingBottom) + editText.setText(cs.message) + editText.textCursorDrawable?.let { DrawableCompat.setTint(it, HighOrLowlight.toArgb()) } + editText.doOnTextChanged { text, _, _, _ -> onMessageChange(text.toString()) } + editText + }) { + it.setTextColor(textColor.toArgb()) + it.textSize = textStyle.value.fontSize.value + DrawableCompat.setTint(it.background, tintColor.toArgb()) + if (cs.message != it.text.toString()) { + it.setText(cs.message) + // Set cursor to the end of the text + it.setSelection(it.text.length) + } + if (showKeyboard) { + it.requestFocus() + val imm: InputMethodManager = SimplexApp.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput(it, InputMethodManager.SHOW_IMPLICIT) + showKeyboard = false + } + } + Box(Modifier.align(Alignment.BottomEnd)) { + val icon = if (cs.editing) Icons.Filled.Check else Icons.Outlined.ArrowUpward + val color = if (cs.sendEnabled()) MaterialTheme.colors.primary else HighOrLowlight + if (cs.inProgress + && (cs.preview is ComposePreview.ImagePreview || cs.preview is ComposePreview.FilePreview) + ) { + CircularProgressIndicator( + Modifier + .size(36.dp) + .padding(4.dp), + color = HighOrLowlight, + strokeWidth = 3.dp + ) + } else { + Icon( + icon, + stringResource(R.string.icon_descr_send_message), + tint = Color.White, + modifier = Modifier + .size(36.dp) + .padding(4.dp) + .clip(CircleShape) + .background(color) + .clickable { + if (cs.sendEnabled()) { + sendMessage() + } + } + ) + } } } - ) + } } @Preview(showBackground = true) diff --git a/apps/android/app/src/main/res/drawable/send_msg_view_background.xml b/apps/android/app/src/main/res/drawable/send_msg_view_background.xml new file mode 100644 index 0000000000..be98ce5da5 --- /dev/null +++ b/apps/android/app/src/main/res/drawable/send_msg_view_background.xml @@ -0,0 +1,12 @@ + + + + + + + + + +