Always Learner
Always Learner

Reputation: 3016

How to display a second Toast correctly in Jetpack Compose?

I need to display a message each time an operation of adding/deleting an item in/from Firebase is complete. These are the functions in the interface:

suspend fun addItem(item: Item): Response<Unit>
suspend fun deleteItem(item: Item): Response<Unit>

These are the implementations:

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

override suspend fun deleteItem(item: Item) = try {
    itemsRef.document(item.id).delete().await()
    Response.Success(Unit)
} catch (ex: Exception) {
    Response.Failure(ex)
}

In the ViewModel I call the addItem and reset the state of the operations like this:

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

    private val _deleteItemResponse = MutableStateFlow<Response<String>?>(null)
    val deleteItemResponse: StateFlow<Response<String>?> = _deleteItemResponse.asStateFlow()

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

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

    fun resetAddItemState() = _addItemResponse.value?.let {
        _addItemResponse.value = null
    }

    fun resetDeleteItemState() = _deleteItemResponse.value?.let {
        _deleteItemResponse.value = null
    }
}

And inside the UI I use:

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

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

When I add an item, the first toast is displayed. If I delete an item and wait for the second toast to disappear, the second toast is displayed correctly. However, if I add an item and delete it right away without waiting for the first toast to disappear, the second toast is not displayed. How to solve this issue?

Upvotes: 1

Views: 82

Answers (2)

Tejas Soni
Tejas Soni

Reputation: 593

You can use a single Toast instance and update its message. This ensures that the Toast is displayed correctly without overlapping.

Here is the updated code:

class ItemActivity : AppCompatActivity() {
    private lateinit var viewModel: ItemViewModel
    private var toast: Toast? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_item)

        viewModel = ViewModelProvider(this).get(ItemViewModel::class.java)

        viewModel.addItemResponse.observe(this) { response ->
            handleResponse(response, "Added")
        }

        viewModel.deleteItemResponse.observe(this) { response ->
            handleResponse(response, "Deleted")
        }
    }

    private fun handleResponse(response: Response<String>?, message: String) {
        when (response) {
            is Response.Loading -> {
                // Show loading indicator if needed
            }
            is Response.Success -> {
                showToast(message)
                viewModel.resetAddItemState()
                viewModel.resetDeleteItemState()
            }
            is Response.Failure -> {
                showToast("Failed: ${response.ex.message}")
            }
        }
    }

    private fun showToast(message: String) {
        toast?.cancel()
        toast = Toast.makeText(this, message, Toast.LENGTH_LONG)
        toast?.show()
    }
}

Upvotes: 0

try to use applicationContext

Toast.makeText(applicationContext,"Message",Toast.LENGTH_SHORT).show()

Hope it will work.

Upvotes: 0

Related Questions