From b82614e5fa3bd45d6241fe332c6e0144a272d88d Mon Sep 17 00:00:00 2001 From: David Perez Date: Mon, 21 Oct 2024 14:48:54 -0500 Subject: [PATCH] PM-13847: Totp click on search should go directly to edit screen (#4123) --- .../feature/search/SearchViewModel.kt | 23 ++++++++++++++----- .../feature/search/SearchScreenTest.kt | 2 ++ .../feature/search/SearchViewModelTest.kt | 17 ++++++++++++-- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt index f73e18e6b..7eea1b728 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt @@ -17,6 +17,7 @@ import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardMan import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent import com.x8bit.bitwarden.data.platform.manager.util.toAutofillSelectionDataOrNull +import com.x8bit.bitwarden.data.platform.manager.util.toTotpDataOrNull import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.platform.repository.model.DataState @@ -46,6 +47,7 @@ import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterData import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType import com.x8bit.bitwarden.ui.vault.feature.vault.util.toFilteredList import com.x8bit.bitwarden.ui.vault.feature.vault.util.toVaultFilterData +import com.x8bit.bitwarden.ui.vault.model.TotpData import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -82,9 +84,7 @@ class SearchViewModel @Inject constructor( ?: run { val searchType = SearchArgs(savedStateHandle).type val userState = requireNotNull(authRepo.userStateFlow.value) - val autofillSelectionData = specialCircumstanceManager - .specialCircumstance - ?.toAutofillSelectionDataOrNull() + val specialCircumstance = specialCircumstanceManager.specialCircumstance SearchState( searchTerm = "", @@ -102,7 +102,8 @@ class SearchViewModel @Inject constructor( baseWebSendUrl = environmentRepo.environment.environmentUrlData.baseWebSendUrl, baseIconUrl = environmentRepo.environment.environmentUrlData.baseIconUrl, isIconLoadingDisabled = settingsRepo.isIconLoadingDisabled, - autofillSelectionData = autofillSelectionData, + autofillSelectionData = specialCircumstance?.toAutofillSelectionDataOrNull(), + totpData = specialCircumstance?.toTotpDataOrNull(), hasMasterPassword = userState.activeAccount.hasMasterPassword, isPremium = userState.activeAccount.isPremium, ) @@ -151,7 +152,11 @@ class SearchViewModel @Inject constructor( private fun handleItemClick(action: SearchAction.ItemClick) { val event = when (state.searchType) { is SearchTypeData.Vault -> { - SearchEvent.NavigateToViewCipher(cipherId = action.itemId) + if (state.isTotp) { + SearchEvent.NavigateToEditCipher(cipherId = action.itemId) + } else { + SearchEvent.NavigateToViewCipher(cipherId = action.itemId) + } } is SearchTypeData.Sends -> { @@ -718,7 +723,8 @@ data class SearchState( val baseIconUrl: String, val isIconLoadingDisabled: Boolean, // Internal - val autofillSelectionData: AutofillSelectionData? = null, + val autofillSelectionData: AutofillSelectionData?, + val totpData: TotpData?, val hasMasterPassword: Boolean, val isPremium: Boolean, ) : Parcelable { @@ -729,6 +735,11 @@ data class SearchState( val isAutofill: Boolean get() = autofillSelectionData != null + /** + * Whether or not this represents a listing screen for totp. + */ + val isTotp: Boolean get() = totpData != null + /** * Represents the specific view states for the search screen. */ diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreenTest.kt index ab96dc131..ae1c15485 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreenTest.kt @@ -890,6 +890,8 @@ private val DEFAULT_STATE: SearchState = SearchState( baseIconUrl = "www.test.com", isIconLoadingDisabled = false, hasMasterPassword = true, + totpData = null, + autofillSelectionData = null, isPremium = true, ) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt index a66fed09b..df3f0f45a 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt @@ -9,7 +9,6 @@ import com.bitwarden.vault.LoginUriView import com.x8bit.bitwarden.R import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus import com.x8bit.bitwarden.data.auth.repository.AuthRepository -import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState import com.x8bit.bitwarden.data.auth.repository.model.UserState import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilitySelectionManager @@ -23,6 +22,7 @@ import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager +import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository @@ -193,7 +193,7 @@ class SearchViewModelTest : BaseViewModelTest() { } @Test - fun `ItemClick for vault item should emit NavigateToViewCipher`() = runTest { + fun `ItemClick for vault item without totp should emit NavigateToViewCipher`() = runTest { val viewModel = createViewModel() viewModel.eventFlow.test { viewModel.trySendAction(SearchAction.ItemClick(itemId = "mock")) @@ -201,6 +201,17 @@ class SearchViewModelTest : BaseViewModelTest() { } } + @Test + fun `ItemClick for vault item with totp should emit NavigateToEditCipher`() = runTest { + specialCircumstanceManager.specialCircumstance = + SpecialCircumstance.AddTotpLoginItem(mockk()) + val viewModel = createViewModel() + viewModel.eventFlow.test { + viewModel.trySendAction(SearchAction.ItemClick(itemId = "mock")) + assertEquals(SearchEvent.NavigateToEditCipher(cipherId = "mock"), awaitItem()) + } + } + @Test fun `ItemClick for send item should emit NavigateToEditSend`() = runTest { val viewModel = createViewModel(DEFAULT_STATE.copy(searchType = SearchTypeData.Sends.All)) @@ -1515,6 +1526,8 @@ private val DEFAULT_STATE: SearchState = SearchState( baseIconUrl = "https://vault.bitwarden.com/icons", isIconLoadingDisabled = false, hasMasterPassword = true, + totpData = null, + autofillSelectionData = null, isPremium = true, )