Reputation: 1
Jetpack Compose. Problem with updating the state. Only the sender of the message is updated, but no one else is. I use MVI architecture
There are two functions in my viewModel for the chat screen, getMessages() triggers immediately when I open chat in launchedEffect with the Unit key, i.e. only once. The getMessages() then runs a coroutine where I update the state. Each user's screen is refreshed at that moment, messages are displayed. But when I send a message, an event is triggered that calls sendMessage() in the viewModel, there I update the state, I figured out that you can even update it that way, getMessages() in the coroutine runs again and updates the state. BUT, the problem is that only the sender of the message updates state, and other users don't, they either need to do something in the keyboard or restart the chat so that state is updated.
sendMessage() in ViewModel
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("SimpleDateFormat")
private fun sendMessage(text: String) {
val calendar: Calendar = Calendar.getInstance()
val currentDate = LocalDate.now()
val time = SimpleDateFormat("HH:mm")
val currentMonthName = currentDate.month.getDisplayName(
TextStyle.FULL, Locale.getDefault()
)
val message = MessageModel(
name = Firebase.auth.currentUser?.displayName.toString(),
text = text,
time = time.format(calendar.time),
isMine = false,
sender = Firebase.auth.currentUser?.uid.toString(),
date = currentDate.dayOfMonth.toString() + " " + currentMonthName,
isNewDate = false
)
viewModelScope.launch {
repository.addMessage(message)
_uiState.value.counter += 1
}
}
getMessages() in ViewModel
private fun getMessages() {
_uiState.update { currentState ->
currentState.copy(
isLoading = true
)
}
viewModelScope.launch {
var i = 0
repository.getMessages()
.map { messages ->
_messagesItemsSenders.add(messages.get(0).sender)
_messagesDates.add(messages.get(0).date)
_messagesPaddingMineAfterLastOther.add(messages.get(0).isMine)
// Check for new sender
if ((_messagesItemsSenders.size > 1) && (!messages.get(0).isMine) and
(_messagesItemsSenders[i] == _messagesItemsSenders[i-1])) {
messages.get(0).isMoreOne = true
}
// Check for new date
messages.get(0).isNewDate =
!((_messagesDates.size > 1) && (_messagesDates[i] == _messagesDates[i-1]))
// Set padding for first message that called "isMine"
messages.get(0).isPaddingMine = (_messagesPaddingMineAfterLastOther.size > 1) &&
(messages.get(0).isMine) and
(_messagesPaddingMineAfterLastOther[i]
!= _messagesPaddingMineAfterLastOther[i-1])
i += 1
ChatViewState(messages = messages, isLoading = false)
}
.collect() { newState ->
_uiState.value = newState
}
}
Upvotes: 0
Views: 241
Reputation: 317
Store the received messages in a mutableStateList, then reference the list whereever you want to display the messages. When the list is updated, (a new message has been received) the composeables which call the list will recompose.
Upvotes: 0