androidkotlinmvvmandroid-jetpack-compose

How to display a Toast in Jetpack Compose when an addition operation is complete?


I need to display a message only when the operation of adding an item in Firebase is complete. This is the function in the interface:

suspend fun addItem(item: Item): Response<String>

This is the implementation:

override suspend fun addItem(item: Item) = try {
    val itemId = itemsRef.add(item).await().id
    Response.Success(itemId)
} catch (ex: Exception) {
    Response.Failure(ex)
}

In the ViewModel I call the addItem like this:

class ItemViewModel @Inject constructor(
    private val repo: ItemRepository
): ViewModel() {
    private val _addItemResponse = MutableStateFlow<Response<String>>(Response.Success(""))
    val addItemResponse: StateFlow<Response<String>> = _addItemResponse.asStateFlow()

    fun addItem(item: Item) = viewModelScope.launch {
        _addItemResponse.value = Response.Loading
        _addItemResponse.value = repo.addItem(item)
    }
}

And inside the UI I use:

when(val addItemResponse = viewModel.addItemResponse.collectAsStateWithLifecycle().value) {
    is Response.Loading -> CircularProgressIndicator()
    is Response.Success -> Toast.makeText(context, addItemResponse.itemId, Toast.LENGTH_LONG).show()
    is Response.Failure -> Text(addItemResponse.ex)
}

The problem is that each time I start the app I get an empty Toast. If I add an item, I get a Toast message with the item ID, which is correct. But how to show the Toast message only when I get Succes, meaning when the data is added to Firebase?


Solution

  • Tactically, your problem lies here:

    private val _addItemResponse = MutableStateFlow<Response<String>>(Response.Success(""))
    

    You are modeling your response as state, and your default state is "we succeeded". That seems unlikely to be the case, as you have not done the work yet.

    Instead, you need a state with (at least) four options:

    Your initial state needs to be WeHaveNotDoneTheThingYet, and in that branch of your UI you do nothing.

    In addition, once you have displayed your Toast, you need to move the state from Success back to WeHaveNotDoneTheThingYet. Otherwise, you will show the Toast again on a recomposition.