diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt index d3300f6032..ad07a71fd8 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt @@ -265,7 +265,7 @@ private fun VaultScreenScaffold( }, floatingActionButton = { AnimatedVisibility( - visible = !accountMenuVisible, + visible = state.viewState.hasFab && !accountMenuVisible, enter = scaleIn(), exit = scaleOut(), ) { diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt index 8464f5c04b..86d280625b 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt @@ -304,17 +304,27 @@ data class VaultState( @Parcelize sealed class ViewState : Parcelable { + /** + * Determines whether or not the Floating Action Button (FAB) should be shown for the + * given state. + */ + abstract val hasFab: Boolean + /** * Loading state for the [VaultScreen], signifying that the content is being processed. */ @Parcelize - data object Loading : ViewState() + data object Loading : ViewState() { + override val hasFab: Boolean get() = false + } /** * Represents a state where the [VaultScreen] has no items to display. */ @Parcelize - data object NoItems : ViewState() + data object NoItems : ViewState() { + override val hasFab: Boolean get() = true + } /** * Represents a state where the [VaultScreen] is unable to display data due to an error @@ -323,7 +333,9 @@ data class VaultState( @Parcelize data class Error( val message: Text, - ) : ViewState() + ) : ViewState() { + override val hasFab: Boolean get() = false + } /** * Content state for the [VaultScreen] showing the actual content or items. @@ -349,7 +361,9 @@ data class VaultState( val noFolderItems: List, val collectionItems: List, val trashItemsCount: Int, - ) : ViewState() + ) : ViewState() { + override val hasFab: Boolean get() = true + } /** * Represents a folder item with a name and item count. diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt index ff25bf0911..9e7dace9aa 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt @@ -283,6 +283,25 @@ class VaultScreenTest : BaseComposeTest() { verify { viewModel.trySendAction(VaultAction.ExitConfirmationClick) } } + @Test + fun `floating action button should be shown or hidden according to the state`() { + val fabDescription = "Add item" + + mutableStateFlow.update { it.copy(viewState = VaultState.ViewState.Loading) } + composeTestRule.onNodeWithContentDescription(fabDescription).assertDoesNotExist() + + mutableStateFlow.update { + it.copy(viewState = VaultState.ViewState.Error("Error".asText())) + } + composeTestRule.onNodeWithContentDescription(fabDescription).assertDoesNotExist() + + mutableStateFlow.update { it.copy(viewState = VaultState.ViewState.NoItems) } + composeTestRule.onNodeWithContentDescription(fabDescription).assertIsDisplayed() + + mutableStateFlow.update { it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE) } + composeTestRule.onNodeWithContentDescription(fabDescription).assertIsDisplayed() + } + @Test fun `error dialog should be shown or hidden according to the state`() { val errorTitle = "Error title"