From 99c50a3fc87eecb5fad593bed6c3b6add660667a Mon Sep 17 00:00:00 2001 From: Shannon Draeker <125921730+shannon-livefront@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:26:34 -0600 Subject: [PATCH] PM-9443: Update empty search state (#3409) --- .../itemlisting/VaultItemListingEmpty.kt | 1 + .../itemlisting/VaultItemListingViewModel.kt | 1 + .../util/VaultItemListingDataExtensions.kt | 10 +++++++ .../ui/vault/feature/vault/VaultNoItems.kt | 17 ++++++++++- .../itemlisting/VaultItemListingScreenTest.kt | 14 +++++++-- .../VaultItemListingViewModelTest.kt | 8 +++++ .../VaultItemListingDataExtensionsTest.kt | 30 +++++++++++++++++++ 7 files changed, 78 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingEmpty.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingEmpty.kt index 59315982c2..0c8d7035cb 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingEmpty.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingEmpty.kt @@ -30,6 +30,7 @@ fun VaultItemListingEmpty( VaultNoItems( policyDisablesSend = policyDisablesSend, message = state.message(), + buttonText = state.buttonText(), modifier = modifier, addItemClickAction = addItemClickAction, ) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index a46c4ca80e..1fc448563e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -1044,6 +1044,7 @@ data class VaultItemListingState( data class NoItems( val message: Text, val shouldShowAddButton: Boolean, + val buttonText: Text, ) : ViewState() { override val isPullToRefreshEnabled: Boolean get() = true } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt index fcf5690bac..5d30cb86f8 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt @@ -161,6 +161,10 @@ fun VaultData.toViewState( ?.uri ?.toHostOrPathOrNull() ?.let { R.string.no_items_for_uri.asText(it) } + ?: fido2CreationData + ?.origin + ?.toHostOrPathOrNull() + ?.let { R.string.no_items_for_uri.asText(it) } ?: run { when (itemListingType) { is VaultItemListingState.ItemListingType.Vault.Folder -> { @@ -189,6 +193,11 @@ fun VaultData.toViewState( VaultItemListingState.ViewState.NoItems( message = message, shouldShowAddButton = shouldShowAddButton, + buttonText = if (fido2CreationData != null) { + R.string.save_passkey_as_new_login.asText() + } else { + R.string.add_an_item.asText() + }, ) } } @@ -213,6 +222,7 @@ fun List.toViewState( VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultNoItems.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultNoItems.kt index 98902e3c03..e6992b1b02 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultNoItems.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultNoItems.kt @@ -6,10 +6,12 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -20,6 +22,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.x8bit.bitwarden.R import com.x8bit.bitwarden.ui.platform.components.text.BitwardenPolicyWarningText +import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter /** * No items view for the [VaultScreen]. @@ -30,6 +33,7 @@ fun VaultNoItems( policyDisablesSend: Boolean, modifier: Modifier = Modifier, message: String = stringResource(id = R.string.no_items), + buttonText: String = stringResource(id = R.string.add_an_item), ) { Column( modifier = modifier.verticalScroll(rememberScrollState()), @@ -46,6 +50,17 @@ fun VaultNoItems( Spacer(modifier = Modifier.weight(1F)) + Icon( + painter = rememberVectorPainter(id = R.drawable.ic_search), + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .size(74.dp) + .padding(horizontal = 16.dp), + ) + + Spacer(modifier = Modifier.height(24.dp)) + Text( textAlign = TextAlign.Center, modifier = Modifier @@ -68,7 +83,7 @@ fun VaultNoItems( ), ) { Text( - text = stringResource(id = R.string.add_an_item), + text = buttonText, style = MaterialTheme.typography.labelLarge, ) } diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt index 1655f3178e..5e726eee0d 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt @@ -352,6 +352,7 @@ class VaultItemListingScreenTest : BaseComposeTest() { viewState = VaultItemListingState.ViewState.NoItems( message = "There are no Sends in your account.".asText(), shouldShowAddButton = true, + buttonText = "Add an Item".asText(), ), ) } @@ -381,12 +382,13 @@ class VaultItemListingScreenTest : BaseComposeTest() { } @Test - fun `add an item button click should send AddItemClick action`() { + fun `Add an Item button click should send AddItemClick action`() { mutableStateFlow.update { it.copy( viewState = VaultItemListingState.ViewState.NoItems( message = "There are no items in your vault.".asText(), shouldShowAddButton = true, + buttonText = "Add an Item".asText(), ), ) } @@ -487,6 +489,7 @@ class VaultItemListingScreenTest : BaseComposeTest() { viewState = VaultItemListingState.ViewState.NoItems( message = "There are no items in your vault.".asText(), shouldShowAddButton = true, + buttonText = "Add an Item".asText(), ), ) } @@ -509,6 +512,7 @@ class VaultItemListingScreenTest : BaseComposeTest() { viewState = VaultItemListingState.ViewState.NoItems( message = "There are no items in your vault.".asText(), shouldShowAddButton = true, + buttonText = "Add an Item".asText(), ), ) } @@ -525,7 +529,7 @@ class VaultItemListingScreenTest : BaseComposeTest() { } @Test - fun `Add an item button should be displayed according to state`() { + fun `Add an Item button should be displayed according to state`() { mutableStateFlow.update { DEFAULT_STATE } composeTestRule .onNodeWithText(text = "Add an Item") @@ -536,6 +540,7 @@ class VaultItemListingScreenTest : BaseComposeTest() { viewState = VaultItemListingState.ViewState.NoItems( message = "There are no items in your vault.".asText(), shouldShowAddButton = true, + buttonText = "Add an Item".asText(), ), ) } @@ -549,6 +554,7 @@ class VaultItemListingScreenTest : BaseComposeTest() { viewState = VaultItemListingState.ViewState.NoItems( message = "There are no items in your vault.".asText(), shouldShowAddButton = false, + buttonText = "Add an Item".asText(), ), ) } @@ -564,12 +570,16 @@ class VaultItemListingScreenTest : BaseComposeTest() { viewState = VaultItemListingState.ViewState.NoItems( message = "There are no items in your vault.".asText(), shouldShowAddButton = true, + buttonText = "Save passkey as new login".asText(), ), ) } composeTestRule .onNodeWithText(text = "There are no items in your vault.") .assertIsDisplayed() + composeTestRule + .onNodeWithText(text = "Save passkey as new login") + .assertIsDisplayed() } @Test diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt index b3958c46d9..9dd1c21c12 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt @@ -1067,6 +1067,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewState = VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), ), viewModel.stateFlow.value, @@ -1095,6 +1096,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewState = VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), ), viewModel.stateFlow.value, @@ -1164,6 +1166,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewState = VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), ), viewModel.stateFlow.value, @@ -1190,6 +1193,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewState = VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), ), viewModel.stateFlow.value, @@ -1277,6 +1281,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewState = VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), ), viewModel.stateFlow.value, @@ -1306,6 +1311,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewState = VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), ), viewModel.stateFlow.value, @@ -1391,6 +1397,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewState = VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), ), viewModel.stateFlow.value, @@ -1419,6 +1426,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewState = VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), ), viewModel.stateFlow.value, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensionsTest.kt index 890cf3219a..183f651f3a 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensionsTest.kt @@ -1,5 +1,6 @@ package com.x8bit.bitwarden.ui.vault.feature.itemlisting.util +import android.content.pm.SigningInfo import android.net.Uri import com.bitwarden.send.SendType import com.bitwarden.vault.CipherRepromptType @@ -7,6 +8,7 @@ import com.bitwarden.vault.CipherType import com.bitwarden.vault.CipherView import com.bitwarden.vault.FolderView import com.x8bit.bitwarden.R +import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData import com.x8bit.bitwarden.data.platform.repository.model.Environment import com.x8bit.bitwarden.data.platform.repository.util.baseIconUrl @@ -513,6 +515,7 @@ class VaultItemListingDataExtensionsTest { VaultItemListingState.ViewState.NoItems( message = R.string.no_items_trash.asText(), shouldShowAddButton = false, + buttonText = R.string.add_an_item.asText(), ), vaultData.toViewState( vaultFilterType = VaultFilterType.AllVaults, @@ -530,6 +533,7 @@ class VaultItemListingDataExtensionsTest { VaultItemListingState.ViewState.NoItems( message = R.string.no_items_folder.asText(), shouldShowAddButton = false, + buttonText = R.string.add_an_item.asText(), ), vaultData.toViewState( vaultFilterType = VaultFilterType.AllVaults, @@ -549,6 +553,7 @@ class VaultItemListingDataExtensionsTest { VaultItemListingState.ViewState.NoItems( message = R.string.no_items.asText(), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), vaultData.toViewState( vaultFilterType = VaultFilterType.AllVaults, @@ -566,6 +571,7 @@ class VaultItemListingDataExtensionsTest { VaultItemListingState.ViewState.NoItems( message = R.string.no_items_for_uri.asText("www.test.com"), shouldShowAddButton = true, + buttonText = R.string.add_an_item.asText(), ), vaultData.toViewState( vaultFilterType = VaultFilterType.AllVaults, @@ -580,6 +586,30 @@ class VaultItemListingDataExtensionsTest { hasMasterPassword = true, ), ) + + // Autofill passkey + assertEquals( + VaultItemListingState.ViewState.NoItems( + message = R.string.no_items_for_uri.asText("www.test.com"), + shouldShowAddButton = true, + buttonText = R.string.save_passkey_as_new_login.asText(), + ), + vaultData.toViewState( + vaultFilterType = VaultFilterType.AllVaults, + itemListingType = VaultItemListingState.ItemListingType.Vault.Login, + isIconLoadingDisabled = false, + baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, + autofillSelectionData = null, + fido2CreationData = Fido2CredentialRequest( + userId = "", + requestJson = "", + packageName = "", + signingInfo = SigningInfo(), + origin = "https://www.test.com", + ), + hasMasterPassword = true, + ), + ) } @Test