From 7f0f858033a6c1852cc015bdc196dd1ccda059eb Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Fri, 10 Oct 2025 11:34:53 +0300 Subject: [PATCH] Simplified implementation of new chat text --- .../kotlin/com/tutpro/baresip/ChatScreen.kt | 35 ++++++++++--------- .../kotlin/com/tutpro/baresip/ViewModel.kt | 29 +++++++-------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/ChatScreen.kt b/app/src/main/kotlin/com/tutpro/baresip/ChatScreen.kt index 591021a1..4660c30b 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ChatScreen.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ChatScreen.kt @@ -48,11 +48,11 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -124,8 +124,6 @@ private fun ChatScreen( val aor = account.aor var chatMessages by remember(aor, peerUri) { mutableStateOf>(emptyList()) } - val allDrafts by viewModel.aorPeerMessage.collectAsState() - val currentDraft = allDrafts.getOrDefault(AorPeer(aor, peerUri), TextFieldValue("")) DisposableEffect(lifecycleOwner) { val observer = LifecycleEventObserver { _, event -> @@ -190,12 +188,9 @@ private fun ChatScreen( bottomBar = { NewMessage( ctx = ctx, + viewModel, account = account, peerUri = peerUri, - newMessage = currentDraft, - onNewMessageChange = { newTextFieldValue -> - viewModel.updateAorPeerMessage(aor, peerUri, newTextFieldValue) - }, addMessage = addMessage ) }, @@ -481,16 +476,19 @@ private fun Messages( @Composable private fun NewMessage( ctx: Context, + viewModel: ViewModel, account: Account, peerUri: String, - newMessage: TextFieldValue, - onNewMessageChange: (TextFieldValue) -> Unit, addMessage: (message: Message) -> Unit ) { val aor = account.aor val ua = UserAgent.ofAor(aor)!! + val newMessage = rememberSaveable(stateSaver = TextFieldValue.Saver) { + mutableStateOf(TextFieldValue(viewModel.getAorPeerMessage(aor, peerUri))) + } + var textFieldLoaded by remember { mutableStateOf(false) } val focusRequester = remember { FocusRequester() } @@ -512,10 +510,11 @@ private fun NewMessage( ) { val keyboardController = LocalSoftwareKeyboardController.current OutlinedTextField( - value = newMessage, + value = newMessage.value, placeholder = { Text(stringResource(R.string.new_message)) }, - onValueChange = { newValue -> - onNewMessageChange(newValue) + onValueChange = { + newMessage.value = it + viewModel.updateAorPeerMessage(aor, peerUri, it.text) }, modifier = Modifier .weight(1f) @@ -528,12 +527,13 @@ private fun NewMessage( }, singleLine = false, trailingIcon = { - if (newMessage.text.isNotEmpty()) { + if (newMessage.value.text.isNotEmpty()) { Icon( Icons.Outlined.Clear, contentDescription = "Clear", modifier = Modifier.clickable { - onNewMessageChange(TextFieldValue("")) + newMessage.value = TextFieldValue("") + viewModel.updateAorPeerMessage(aor, peerUri, "") } ) } }, @@ -546,7 +546,7 @@ private fun NewMessage( ) ) LaunchedEffect(Unit) { - if (newMessage.text.isNotEmpty()) + if (newMessage.value.text.isNotEmpty()) focusRequester.requestFocus() } Image( @@ -556,7 +556,7 @@ private fun NewMessage( modifier = Modifier .size(36.dp) .clickable { - val msgText = newMessage.text + val msgText = newMessage.value.text if (msgText.isNotEmpty()) { keyboardController?.hide() val time = System.currentTimeMillis() @@ -595,7 +595,8 @@ private fun NewMessage( msg.direction = MESSAGE_UP_FAIL msg.responseReason = ctx.getString(R.string.message_failed) } else { - onNewMessageChange(TextFieldValue("")) + newMessage.value = TextFieldValue("") + viewModel.updateAorPeerMessage(aor, peerUri, "") keyboardController?.hide() } } diff --git a/app/src/main/kotlin/com/tutpro/baresip/ViewModel.kt b/app/src/main/kotlin/com/tutpro/baresip/ViewModel.kt index 7ae457a5..cde58761 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ViewModel.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ViewModel.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import androidx.compose.runtime.State -import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.runtime.mutableIntStateOf import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow @@ -31,32 +31,33 @@ class ViewModel(application: Application) : AndroidViewModel(application) { _selectedAor.value = newValue } - private val _aorPeerMessage = MutableStateFlow(mutableMapOf()) - val aorPeerMessage: StateFlow> = _aorPeerMessage.asStateFlow() + private val _aorPeerMessage = MutableStateFlow(mutableMapOf()) - fun updateAorPeerMessage(aor: String, peerUri: String, value: TextFieldValue) { + fun updateAorPeerMessage(aor: String, peerUri: String, message: String) { val key = AorPeer(aor, peerUri) - val newMap = _aorPeerMessage.value.toMutableMap() - - if (value.text.isEmpty()) - newMap.remove(key) + if (message == "") + _aorPeerMessage.value.remove(key) else - newMap[key] = value - _aorPeerMessage.value = newMap + _aorPeerMessage.value[key] = message } - private val _showKeyboard = mutableStateOf(0) + fun getAorPeerMessage(aor: String, peerUri: String): String { + val key = AorPeer(aor, peerUri) + return _aorPeerMessage.value.getOrDefault(key, "") + } + + private val _showKeyboard = mutableIntStateOf(0) val showKeyboard: State = _showKeyboard fun requestShowKeyboard() { - _showKeyboard.value++ + _showKeyboard.intValue++ } - private val _hideKeyboard = mutableStateOf(0) + private val _hideKeyboard = mutableIntStateOf(0) val hideKeyboard: State = _hideKeyboard fun requestHideKeyboard() { - _hideKeyboard.value++ + _hideKeyboard.intValue++ } private val _speakerIcon = MutableStateFlow(R.drawable.speaker_off)