feat: cursor at end when editing and open keyboard
Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
5a6a25c113
commit
3652d01ea8
|
|
@ -29,6 +29,7 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -39,6 +40,7 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -51,8 +53,8 @@ import chat.revolt.api.schemas.ChannelType
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MessageField(
|
||||
messageContent: String,
|
||||
onMessageContentChange: (String) -> Unit,
|
||||
value: TextFieldValue,
|
||||
onValueChange: (TextFieldValue) -> Unit,
|
||||
onAddAttachment: () -> Unit,
|
||||
onSendMessage: () -> Unit,
|
||||
channelType: ChannelType,
|
||||
|
|
@ -73,16 +75,23 @@ fun MessageField(
|
|||
ChannelType.SavedMessages -> R.string.message_field_placeholder_notes
|
||||
}
|
||||
|
||||
val sendButtonVisible = (messageContent.isNotBlank() || forceSendButton) && !disabled
|
||||
val sendButtonVisible = (value.text.isNotBlank() || forceSendButton) && !disabled
|
||||
|
||||
LaunchedEffect(editMode) {
|
||||
if (editMode) {
|
||||
focusRequester.requestFocus()
|
||||
} else {
|
||||
focusRequester.freeFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp))
|
||||
) {
|
||||
|
||||
BasicTextField(
|
||||
value = messageContent,
|
||||
onValueChange = onMessageContentChange,
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
singleLine = false,
|
||||
enabled = !disabled,
|
||||
textStyle = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.onSurface),
|
||||
|
|
@ -97,21 +106,21 @@ fun MessageField(
|
|||
keyboardActions = KeyboardActions.Default,
|
||||
decorationBox = @Composable { innerTextField ->
|
||||
TextFieldDefaults.DecorationBox(
|
||||
value = messageContent,
|
||||
value = value.text,
|
||||
innerTextField = innerTextField,
|
||||
enabled = !disabled,
|
||||
singleLine = false,
|
||||
visualTransformation = VisualTransformation.None,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
placeholder = {
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = placeholderResource,
|
||||
channelName
|
||||
),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = placeholderResource,
|
||||
channelName
|
||||
),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
},
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
|
|
@ -127,28 +136,28 @@ fun MessageField(
|
|||
),
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
when {
|
||||
editMode -> Icons.Default.Close
|
||||
else -> Icons.Default.Add
|
||||
},
|
||||
tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f),
|
||||
contentDescription = stringResource(id = R.string.add_attachment_alt),
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.size(32.dp)
|
||||
.clickable {
|
||||
when {
|
||||
editMode -> cancelEdit()
|
||||
else -> {
|
||||
focusRequester.freeFocus() // hide keyboard because it's annoying
|
||||
onAddAttachment()
|
||||
}
|
||||
Icon(
|
||||
when {
|
||||
editMode -> Icons.Default.Close
|
||||
else -> Icons.Default.Add
|
||||
},
|
||||
tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f),
|
||||
contentDescription = stringResource(id = R.string.add_attachment_alt),
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.size(32.dp)
|
||||
.clickable {
|
||||
when {
|
||||
editMode -> cancelEdit()
|
||||
else -> {
|
||||
focusRequester.freeFocus() // hide keyboard because it's annoying
|
||||
onAddAttachment()
|
||||
}
|
||||
}
|
||||
.padding(4.dp)
|
||||
.testTag("add_attachment")
|
||||
)
|
||||
}
|
||||
.padding(4.dp)
|
||||
.testTag("add_attachment")
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
AnimatedVisibility(sendButtonVisible,
|
||||
|
|
@ -186,8 +195,8 @@ fun MessageField(
|
|||
@Composable
|
||||
fun MessageFieldPreview() {
|
||||
MessageField(
|
||||
messageContent = "Hello world!",
|
||||
onMessageContentChange = {},
|
||||
value = TextFieldValue("Hello world!"),
|
||||
onValueChange = {},
|
||||
onSendMessage = {},
|
||||
onAddAttachment = {},
|
||||
channelType = ChannelType.TextChannel,
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import androidx.compose.ui.graphics.toArgb
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
|
|
@ -173,6 +174,13 @@ fun ChannelScreen(
|
|||
label = "ScrollDownFABPadding"
|
||||
)
|
||||
|
||||
val fieldContent = remember(viewModel.pendingMessageContent, viewModel.textSelection) {
|
||||
TextFieldValue(
|
||||
viewModel.pendingMessageContent,
|
||||
viewModel.textSelection
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(channelId) {
|
||||
viewModel.fetchChannel(channelId)
|
||||
|
||||
|
|
@ -465,9 +473,10 @@ fun ChannelScreen(
|
|||
)
|
||||
} else {
|
||||
MessageField(
|
||||
messageContent = viewModel.pendingMessageContent,
|
||||
onMessageContentChange = {
|
||||
viewModel.pendingMessageContent = it
|
||||
value = fieldContent,
|
||||
onValueChange = {
|
||||
viewModel.pendingMessageContent = it.text
|
||||
viewModel.textSelection = it.selection
|
||||
},
|
||||
onSendMessage = viewModel::sendPendingMessage,
|
||||
onAddAttachment = {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import androidx.compose.runtime.mutableStateListOf
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import chat.revolt.R
|
||||
|
|
@ -64,6 +65,7 @@ class ChannelScreenViewModel : ViewModel() {
|
|||
var hasNoMoreMessages by mutableStateOf(false)
|
||||
|
||||
var pendingMessageContent by mutableStateOf("")
|
||||
var textSelection by mutableStateOf(TextRange(0))
|
||||
var pendingReplies = mutableStateListOf<SendMessageReply>()
|
||||
var pendingAttachments = mutableStateListOf<FileArgs>()
|
||||
|
||||
|
|
@ -394,6 +396,7 @@ class ChannelScreenViewModel : ViewModel() {
|
|||
msg.id == it.messageId
|
||||
} ?: return@onEach
|
||||
pendingMessageContent = message.content ?: ""
|
||||
textSelection = TextRange(message.content?.length ?: 0)
|
||||
}
|
||||
}
|
||||
}.catch {
|
||||
|
|
|
|||
Loading…
Reference in New Issue