www sss
www sss

Reputation: 1

How can I update state for all users in my Jetpack Compose chat app when a message is sent?

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

Answers (1)

RandomLonelyDev
RandomLonelyDev

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

Related Questions