diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditItemContent.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditItemContent.kt index 3ad7288b8e..257dc527e4 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditItemContent.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditItemContent.kt @@ -22,7 +22,6 @@ import com.x8bit.bitwarden.ui.platform.components.button.BitwardenTextSelectionB import com.x8bit.bitwarden.ui.platform.components.card.BitwardenActionCard import com.x8bit.bitwarden.ui.platform.components.card.BitwardenInfoCalloutCard import com.x8bit.bitwarden.ui.platform.components.coachmark.CoachMarkScope -import com.x8bit.bitwarden.ui.platform.components.dropdown.BitwardenMultiSelectButton import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextField import com.x8bit.bitwarden.ui.platform.components.header.BitwardenListHeaderText import com.x8bit.bitwarden.ui.platform.components.model.CardStyle @@ -33,7 +32,6 @@ import com.x8bit.bitwarden.ui.vault.feature.addedit.handlers.VaultAddEditCommonH import com.x8bit.bitwarden.ui.vault.feature.addedit.handlers.VaultAddEditIdentityTypeHandlers import com.x8bit.bitwarden.ui.vault.feature.addedit.handlers.VaultAddEditLoginTypeHandlers import com.x8bit.bitwarden.ui.vault.feature.addedit.handlers.VaultAddEditSshKeyTypeHandlers -import kotlinx.collections.immutable.toImmutableList /** * The top level content UI state for the [VaultAddEditScreen]. @@ -169,15 +167,10 @@ fun CoachMarkScope.VaultAddEditContent( if (isAddItemMode && state.common.hasOrganizations) { val collections = state.common.selectedOwner?.collections.orEmpty() item { - BitwardenMultiSelectButton( + BitwardenTextSelectionButton( label = stringResource(id = R.string.owner), - options = state.common.availableOwners.map { it.name }.toImmutableList(), selectedOption = state.common.selectedOwner?.name, - onOptionSelected = { selectedOwnerName -> - commonTypeHandlers.onOwnerSelected( - state.common.availableOwners.first { it.name == selectedOwnerName }, - ) - }, + onClick = commonTypeHandlers.onPresentOwnerOptions, cardStyle = if (collections.isNotEmpty()) { CardStyle.Middle() } else { diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreen.kt index 991e379816..7549f0c79c 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreen.kt @@ -44,6 +44,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect import com.x8bit.bitwarden.ui.platform.base.util.Text import com.x8bit.bitwarden.ui.platform.base.util.cardStyle import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin +import com.x8bit.bitwarden.ui.platform.base.util.toListItemCardStyle import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar import com.x8bit.bitwarden.ui.platform.components.appbar.NavigationIcon import com.x8bit.bitwarden.ui.platform.components.appbar.action.BitwardenOverflowActionItem @@ -420,10 +421,11 @@ fun VaultAddEditScreen( .imePadding() .fillMaxSize(), ) - FolderSelectionBottomSheet( - state = viewState.common, + + BottomSheetViews( + bottomSheetState = state.bottomSheetState, + viewState = viewState.common, handlers = commonTypeHandlers, - showBottomSheet = state.shouldShowFolderSelectionBottomSheet, ) } @@ -549,12 +551,39 @@ private fun VaultAddEditItemDialogs( } } +@Composable +private fun BottomSheetViews( + bottomSheetState: VaultAddEditState.BottomSheetState?, + viewState: VaultAddEditState.ViewState.Content.Common, + handlers: VaultAddEditCommonHandlers, + modifier: Modifier = Modifier, +) { + when (bottomSheetState) { + is VaultAddEditState.BottomSheetState.FolderSelection -> { + FolderSelectionBottomSheet( + state = viewState, + handlers = handlers, + modifier = modifier, + ) + } + + is VaultAddEditState.BottomSheetState.OwnerSelection -> { + OwnerSelectionBottomSheet( + state = viewState, + handlers = handlers, + modifier = modifier, + ) + } + + null -> Unit + } +} + @OptIn(ExperimentalMaterial3Api::class) @Composable private fun FolderSelectionBottomSheet( state: VaultAddEditState.ViewState.Content.Common, handlers: VaultAddEditCommonHandlers, - showBottomSheet: Boolean, modifier: Modifier = Modifier, ) { var selectedOptionState by rememberSaveable { @@ -562,12 +591,12 @@ private fun FolderSelectionBottomSheet( } BitwardenModalBottomSheet( sheetTitle = stringResource(R.string.folders), - onDismiss = handlers.onDismissFolderSelectionSheet, + onDismiss = handlers.onDismissBottomSheet, topBarActions = { animatedOnDismiss -> BitwardenTextButton( label = stringResource(R.string.save), onClick = { - handlers.onDismissFolderSelectionSheet() + handlers.onDismissBottomSheet() state .availableFolders .firstOrNull { @@ -584,7 +613,6 @@ private fun FolderSelectionBottomSheet( isEnabled = selectedOptionState.isNotBlank(), ) }, - showBottomSheet = showBottomSheet, sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), modifier = modifier.statusBarsPadding(), ) { @@ -698,3 +726,98 @@ private fun FolderSelectionBottomSheetContent( } } } + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun OwnerSelectionBottomSheet( + state: VaultAddEditState.ViewState.Content.Common, + handlers: VaultAddEditCommonHandlers, + modifier: Modifier = Modifier, +) { + + var selectedOptionState by rememberSaveable { + mutableStateOf(state.selectedOwner?.name.orEmpty()) + } + BitwardenModalBottomSheet( + sheetTitle = stringResource(R.string.owner), + onDismiss = handlers.onDismissBottomSheet, + topBarActions = { animatedOnDismiss -> + BitwardenTextButton( + label = stringResource(R.string.save), + onClick = { + handlers.onDismissBottomSheet() + state + .availableOwners + .firstOrNull { + it.name == selectedOptionState + } + ?.run { + handlers.onOwnerSelected(this.id) + } + animatedOnDismiss() + }, + isEnabled = selectedOptionState.isNotBlank(), + ) + }, + sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + modifier = modifier.statusBarsPadding(), + ) { + OwnerSelectionBottomSheetContent( + options = state.availableOwners.map { it.name }.toImmutableList(), + selectedOption = selectedOptionState, + onOptionSelected = { + selectedOptionState = it + }, + ) + } +} + +@Composable +private fun OwnerSelectionBottomSheetContent( + options: ImmutableList, + selectedOption: String, + onOptionSelected: (String) -> Unit, + modifier: Modifier = Modifier, +) { + LazyColumn( + modifier = modifier + .standardHorizontalMargin(), + ) { + item { + Spacer(modifier = Modifier.height(12.dp)) + } + itemsIndexed(options) { index, option -> + Row( + modifier = Modifier + .fillMaxWidth() + .cardStyle( + cardStyle = options.toListItemCardStyle(index = index), + onClick = { + onOptionSelected(option) + }, + ), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = option, + color = BitwardenTheme.colorScheme.text.primary, + style = BitwardenTheme.typography.bodyLarge, + modifier = Modifier.padding(horizontal = 16.dp), + ) + BitwardenRadioButton( + isSelected = selectedOption == option, + onClick = { + onOptionSelected(option) + }, + ) + } + } + item { + Spacer(modifier = Modifier.height(16.dp)) + } + item { + Spacer(modifier = Modifier.navigationBarsPadding()) + } + } +} diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index f54a0da82c..60604d204f 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -179,13 +179,13 @@ class VaultAddEditViewModel @Inject constructor( is VaultAddEditType.CloneItem -> VaultAddEditState.ViewState.Loading }, dialog = dialogState, + bottomSheetState = null, totpData = totpData, // Set special conditions for autofill and fido2 save shouldShowCloseButton = autofillSaveItem == null && fido2AttestationOptions == null, shouldExitOnSave = shouldExitOnSave, shouldShowCoachMarkTour = false, shouldClearSpecialCircumstance = autofillSelectionData == null, - shouldShowFolderSelectionBottomSheet = false, ) }, ) { @@ -352,9 +352,6 @@ class VaultAddEditViewModel @Inject constructor( } is VaultAddEditAction.Common.FolderChange -> handleFolderTextInputChange(action) - VaultAddEditAction.Common.DismissFolderSelectionBottomSheet -> { - handleDismissFolderSelectionBottomSheet() - } VaultAddEditAction.Common.SelectOrAddFolderForItem -> { handleSelectOrAddFolderForItem() @@ -363,6 +360,14 @@ class VaultAddEditViewModel @Inject constructor( is VaultAddEditAction.Common.AddNewFolder -> { handleAddNewFolder(action) } + + VaultAddEditAction.Common.SelectOwnerForItem -> { + handleSelectOwnerForItem() + } + + VaultAddEditAction.Common.DismissBottomSheet -> { + handleDismissBottomSheet() + } } } @@ -722,15 +727,27 @@ class VaultAddEditViewModel @Inject constructor( showFido2ErrorDialog() } - private fun handleDismissFolderSelectionBottomSheet() { + private fun handleSelectOrAddFolderForItem() { mutableStateFlow.update { - it.copy(shouldShowFolderSelectionBottomSheet = false) + it.copy( + bottomSheetState = VaultAddEditState.BottomSheetState.FolderSelection, + ) } } - private fun handleSelectOrAddFolderForItem() { + private fun handleSelectOwnerForItem() { mutableStateFlow.update { - it.copy(shouldShowFolderSelectionBottomSheet = true) + it.copy( + bottomSheetState = VaultAddEditState.BottomSheetState.OwnerSelection, + ) + } + } + + private fun handleDismissBottomSheet() { + mutableStateFlow.update { + it.copy( + bottomSheetState = null, + ) } } @@ -882,7 +899,7 @@ class VaultAddEditViewModel @Inject constructor( action: VaultAddEditAction.Common.OwnershipChange, ) { updateCommonContent { commonContent -> - commonContent.copy(selectedOwnerId = action.ownership.id) + commonContent.copy(selectedOwnerId = action.ownerId) } } @@ -2035,7 +2052,7 @@ data class VaultAddEditState( val cipherType: VaultItemCipherType, val viewState: ViewState, val dialog: DialogState?, - val shouldShowFolderSelectionBottomSheet: Boolean, + val bottomSheetState: BottomSheetState?, val shouldShowCloseButton: Boolean = true, // Internal val shouldExitOnSave: Boolean = false, @@ -2489,6 +2506,23 @@ data class VaultAddEditState( val collections: List, ) : Parcelable + /** + * Displays a bottom sheet. + */ + sealed class BottomSheetState : Parcelable { + /** + * Displays a folder selection bottom sheet. + */ + @Parcelize + data object FolderSelection : BottomSheetState() + + /** + * Displays a owner selection bottom sheet. + */ + @Parcelize + data object OwnerSelection : BottomSheetState() + } + /** * Displays a dialog. */ @@ -2755,11 +2789,11 @@ sealed class VaultAddEditAction { data class NotesTextChange(val notes: String) : Common() /** - * Fired when the ownership text input is changed. + * Fired when the owner text input is changed. * - * @property ownership The new ownership text. + * @property ownerId The new owner id. */ - data class OwnershipChange(val ownership: VaultAddEditState.Owner) : Common() + data class OwnershipChange(val ownerId: String?) : Common() /** * Represents the action to add a new custom field. @@ -2881,9 +2915,14 @@ sealed class VaultAddEditAction { data object SelectOrAddFolderForItem : Common() /** - * The user has dismissed the folder selection bottom sheet. + * The user has clicked on owner selection card for the item. */ - data object DismissFolderSelectionBottomSheet : Common() + data object SelectOwnerForItem : Common() + + /** + * The user has dismissed the current bottom sheet. + */ + data object DismissBottomSheet : Common() /** * The user has selected to add a new folder to associate with the item. diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/handlers/VaultAddEditCommonHandlers.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/handlers/VaultAddEditCommonHandlers.kt index e1793c32ac..f50b87bf71 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/handlers/VaultAddEditCommonHandlers.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/handlers/VaultAddEditCommonHandlers.kt @@ -17,12 +17,18 @@ import com.x8bit.bitwarden.ui.vault.model.VaultCollection * @property onToggleMasterPasswordReprompt Handles the action when the master password * reprompt toggle is changed. * @property onNotesTextChange Handles the action when the notes text is changed. - * @property onOwnerSelected Handles the action when a owner is selected. + * @property onPresentOwnerOptions Handles showing the list of ownership options. + * @property onOwnerSelected Handles the action when a owner is select. * @property onTooltipClick Handles the action when the tooltip button is clicked. * @property onAddNewCustomFieldClick Handles the action when the add new custom field * button is clicked. * @property onCustomFieldValueChange Handles the action when the field's value changes. * @property onCollectionSelect Handles the action when a collection is selected. + * @property onHiddenFieldVisibilityChange Handles the action when the hidden field visibility + * @property onSelectOrAddFolderForItem Handles the action when a folder is selected. + * @property onChangeToExistingFolder Handles the action when the folder is changed. + * @property onOnAddFolder Handles the action when a new folder is added. + * @property onDismissBottomSheet Handles when the current bottom sheet is dismissed. */ @Suppress("LongParameterList") data class VaultAddEditCommonHandlers( @@ -30,7 +36,8 @@ data class VaultAddEditCommonHandlers( val onToggleFavorite: (Boolean) -> Unit, val onToggleMasterPasswordReprompt: (Boolean) -> Unit, val onNotesTextChange: (String) -> Unit, - val onOwnerSelected: (VaultAddEditState.Owner) -> Unit, + val onPresentOwnerOptions: () -> Unit, + val onOwnerSelected: (String?) -> Unit, val onTooltipClick: () -> Unit, val onAddNewCustomFieldClick: (CustomFieldType, String) -> Unit, val onCustomFieldValueChange: (VaultAddEditState.Custom) -> Unit, @@ -38,9 +45,9 @@ data class VaultAddEditCommonHandlers( val onCollectionSelect: (VaultCollection) -> Unit, val onHiddenFieldVisibilityChange: (Boolean) -> Unit, val onSelectOrAddFolderForItem: () -> Unit, - val onDismissFolderSelectionSheet: () -> Unit, val onChangeToExistingFolder: (String?) -> Unit, val onOnAddFolder: (String) -> Unit, + val onDismissBottomSheet: () -> Unit, ) { @Suppress("UndocumentedPublicClass") companion object { @@ -62,6 +69,11 @@ data class VaultAddEditCommonHandlers( VaultAddEditAction.Common.SelectOrAddFolderForItem, ) }, + onPresentOwnerOptions = { + viewModel.trySendAction( + VaultAddEditAction.Common.SelectOwnerForItem, + ) + }, onToggleFavorite = { isFavorite -> viewModel.trySendAction( VaultAddEditAction.Common.ToggleFavorite(isFavorite), @@ -79,9 +91,11 @@ data class VaultAddEditCommonHandlers( VaultAddEditAction.Common.NotesTextChange(newNotes), ) }, - onOwnerSelected = { newOwnership -> + onOwnerSelected = { viewModel.trySendAction( - VaultAddEditAction.Common.OwnershipChange(newOwnership), + VaultAddEditAction.Common.OwnershipChange( + ownerId = it, + ), ) }, onTooltipClick = { @@ -124,11 +138,6 @@ data class VaultAddEditCommonHandlers( VaultAddEditAction.Common.HiddenFieldVisibilityChange(isVisible = it), ) }, - onDismissFolderSelectionSheet = { - viewModel.trySendAction( - VaultAddEditAction.Common.DismissFolderSelectionBottomSheet, - ) - }, onChangeToExistingFolder = { viewModel.trySendAction( VaultAddEditAction.Common.FolderChange( @@ -143,6 +152,11 @@ data class VaultAddEditCommonHandlers( ), ) }, + onDismissBottomSheet = { + viewModel.trySendAction( + VaultAddEditAction.Common.DismissBottomSheet, + ) + }, ) } } diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt index 514d8aefb2..ec735a73af 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt @@ -2326,7 +2326,7 @@ class VaultAddEditScreenTest : BaseComposeTest() { } @Test - fun `clicking a Ownership option should send OwnershipChange action`() { + fun `clicking a Ownership option should send SelectOwnerForItem action`() { updateStateWithOwners() // Opens the menu @@ -2336,26 +2336,82 @@ class VaultAddEditScreenTest : BaseComposeTest() { ) .performClick() - // Choose the option from the menu - composeTestRule - .onAllNodesWithText(text = "mockOwnerName-2") - .onLast() - .performScrollTo() - .performClick() - verify { viewModel.trySendAction( - VaultAddEditAction.Common.OwnershipChange( - VaultAddEditState.Owner( - id = "mockOwnerId-2", - name = "mockOwnerName-2", - collections = DEFAULT_COLLECTIONS, - ), - ), + VaultAddEditAction.Common.SelectOwnerForItem, ) } } + @Test + fun `should show owner selection bottom sheet when state updates to OwnerSelection`() { + mutableStateFlow.update { + it.copy(bottomSheetState = VaultAddEditState.BottomSheetState.OwnerSelection) + } + + composeTestRule + .onNodeWithText("Owner") + .assertIsDisplayed() + } + + @Test + fun `DismissOwnerSelectionBottomSheet action sent when bottom sheet close button click`() { + mutableStateFlow.update { + it.copy(bottomSheetState = VaultAddEditState.BottomSheetState.OwnerSelection) + } + + composeTestRule + .onNodeWithText("Owner") + .assertIsDisplayed() + + composeTestRule + .onAllNodesWithContentDescription("Close") + .filterToOne(hasAnySibling(hasText("Owner"))) + .assertIsDisplayed() + .performSemanticsAction(SemanticsActions.OnClick) + + dispatcher.advanceTimeByAndRunCurrent(1000L) + + verify { + viewModel.trySendAction(VaultAddEditAction.Common.DismissBottomSheet) + } + } + + @Test + fun `Selecting option and clicking save on owner sheet sends OwnershipChange action`() { + val ownerId = "1234" + val ownerName = "name" + mutableStateFlow.update { currentState -> + updateCommonContent(currentState) { + copy( + availableOwners = + listOf( + VaultAddEditState.Owner( + id = ownerId, + name = ownerName, + collections = DEFAULT_COLLECTIONS, + ), + ), + ) + } + .copy(bottomSheetState = VaultAddEditState.BottomSheetState.OwnerSelection) + } + + composeTestRule + .onNodeWithText(ownerName) + .performSemanticsAction(SemanticsActions.OnClick) + + composeTestRule + .onAllNodesWithText("Save") + .filterToOne(hasAnySibling(hasText("Owner"))) + .assertIsDisplayed() + .performSemanticsAction(SemanticsActions.OnClick) + + verify { + viewModel.trySendAction(VaultAddEditAction.Common.OwnershipChange(ownerId = ownerId)) + } + } + @Test fun `the Ownership control should display the text provided by the state`() { updateStateWithOwners() @@ -2504,9 +2560,9 @@ class VaultAddEditScreenTest : BaseComposeTest() { } @Test - fun `should show folder selection bottom sheet when state updates to true`() { + fun `should show folder selection bottom sheet when state updates to FolderSelection`() { mutableStateFlow.update { - it.copy(shouldShowFolderSelectionBottomSheet = true) + it.copy(bottomSheetState = VaultAddEditState.BottomSheetState.FolderSelection) } composeTestRule @@ -2521,7 +2577,7 @@ class VaultAddEditScreenTest : BaseComposeTest() { @Test fun `DismissFolderSelectionBottomSheet action sent when bottom sheet close button click`() { mutableStateFlow.update { - it.copy(shouldShowFolderSelectionBottomSheet = true) + it.copy(bottomSheetState = VaultAddEditState.BottomSheetState.FolderSelection) } composeTestRule @@ -2537,7 +2593,7 @@ class VaultAddEditScreenTest : BaseComposeTest() { dispatcher.advanceTimeByAndRunCurrent(1000L) verify { - viewModel.trySendAction(VaultAddEditAction.Common.DismissFolderSelectionBottomSheet) + viewModel.trySendAction(VaultAddEditAction.Common.DismissBottomSheet) } } @@ -2545,7 +2601,7 @@ class VaultAddEditScreenTest : BaseComposeTest() { @Test fun `Clicking add folder button in bottom sheet hides add button and replaced with TextField`() { mutableStateFlow.update { - it.copy(shouldShowFolderSelectionBottomSheet = true) + it.copy(bottomSheetState = VaultAddEditState.BottomSheetState.FolderSelection) } composeTestRule @@ -2567,7 +2623,7 @@ class VaultAddEditScreenTest : BaseComposeTest() { @Test fun `Editing the add folder text and clicking save send AddFolder action`() { mutableStateFlow.update { - it.copy(shouldShowFolderSelectionBottomSheet = true) + it.copy(bottomSheetState = VaultAddEditState.BottomSheetState.FolderSelection) } val newFolderName = "newFolderName" @@ -2614,7 +2670,7 @@ class VaultAddEditScreenTest : BaseComposeTest() { ), ) } - .copy(shouldShowFolderSelectionBottomSheet = true) + .copy(bottomSheetState = VaultAddEditState.BottomSheetState.FolderSelection) } composeTestRule @@ -2790,39 +2846,6 @@ class VaultAddEditScreenTest : BaseComposeTest() { .assertTextContains("NewNote") } - @Test - fun `Ownership option should send OwnershipChange action`() { - mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES - - updateStateWithOwners() - - // Opens the menu - composeTestRule - .onNodeWithContentDescriptionAfterScroll( - label = "placeholder@email.com. Owner", - ) - .performClick() - - // Choose the option from the menu - composeTestRule - .onAllNodesWithText(text = "mockOwnerName-2") - .onLast() - .performScrollTo() - .performClick() - - verify { - viewModel.trySendAction( - VaultAddEditAction.Common.OwnershipChange( - VaultAddEditState.Owner( - id = "mockOwnerId-2", - name = "mockOwnerName-2", - collections = DEFAULT_COLLECTIONS, - ), - ), - ) - } - } - @Suppress("MaxLineLength") @Test fun `in ItemType_SecureNotes the Ownership control should display the text provided by the state`() { @@ -4002,9 +4025,9 @@ class VaultAddEditScreenTest : BaseComposeTest() { isIndividualVaultDisabled = false, ), dialog = VaultAddEditState.DialogState.Generic(message = "test".asText()), + bottomSheetState = null, vaultAddEditType = VaultAddEditType.AddItem, shouldShowCoachMarkTour = false, - shouldShowFolderSelectionBottomSheet = false, ) private val DEFAULT_STATE_LOGIN = VaultAddEditState( @@ -4016,8 +4039,8 @@ class VaultAddEditScreenTest : BaseComposeTest() { isIndividualVaultDisabled = false, ), dialog = null, + bottomSheetState = null, shouldShowCoachMarkTour = false, - shouldShowFolderSelectionBottomSheet = false, ) private val DEFAULT_STATE_IDENTITY = VaultAddEditState( @@ -4029,8 +4052,8 @@ class VaultAddEditScreenTest : BaseComposeTest() { isIndividualVaultDisabled = false, ), dialog = null, + bottomSheetState = null, shouldShowCoachMarkTour = false, - shouldShowFolderSelectionBottomSheet = false, ) private val DEFAULT_STATE_CARD = VaultAddEditState( @@ -4042,8 +4065,8 @@ class VaultAddEditScreenTest : BaseComposeTest() { isIndividualVaultDisabled = false, ), dialog = null, + bottomSheetState = null, shouldShowCoachMarkTour = false, - shouldShowFolderSelectionBottomSheet = false, ) private val DEFAULT_STATE_SECURE_NOTES_CUSTOM_FIELDS = VaultAddEditState( @@ -4063,10 +4086,10 @@ class VaultAddEditScreenTest : BaseComposeTest() { isIndividualVaultDisabled = false, ), dialog = null, + bottomSheetState = null, vaultAddEditType = VaultAddEditType.AddItem, cipherType = VaultItemCipherType.SECURE_NOTE, shouldShowCoachMarkTour = false, - shouldShowFolderSelectionBottomSheet = false, ) private val DEFAULT_STATE_SECURE_NOTES = VaultAddEditState( @@ -4078,8 +4101,8 @@ class VaultAddEditScreenTest : BaseComposeTest() { isIndividualVaultDisabled = false, ), dialog = null, + bottomSheetState = null, shouldShowCoachMarkTour = false, - shouldShowFolderSelectionBottomSheet = false, ) private val DEFAULT_STATE_SSH_KEYS = VaultAddEditState( @@ -4091,8 +4114,8 @@ class VaultAddEditScreenTest : BaseComposeTest() { isIndividualVaultDisabled = false, ), dialog = null, + bottomSheetState = null, shouldShowCoachMarkTour = false, - shouldShowFolderSelectionBottomSheet = false, ) private val ALTERED_COLLECTIONS = listOf( diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt index 8983300972..04b6ba3f02 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt @@ -207,11 +207,11 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { type = VaultAddEditState.ViewState.Content.ItemType.Login(), ), dialog = null, + bottomSheetState = null, totpData = null, shouldShowCloseButton = true, shouldExitOnSave = false, shouldShowCoachMarkTour = false, - shouldShowFolderSelectionBottomSheet = false, ) val viewModel = createAddVaultItemViewModel( savedStateHandle = createSavedStateHandleWithState( @@ -296,8 +296,8 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { type = VaultAddEditState.ViewState.Content.ItemType.Login(), ), dialog = null, + bottomSheetState = null, shouldShowCoachMarkTour = false, - shouldShowFolderSelectionBottomSheet = false, ), viewModel.stateFlow.value, ) @@ -3217,7 +3217,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { viewModel.trySendAction(action) val expectedState = vaultAddItemInitialState.copy( - shouldShowFolderSelectionBottomSheet = true, + bottomSheetState = VaultAddEditState.BottomSheetState.FolderSelection, ) assertEquals(expectedState, viewModel.stateFlow.value) @@ -3226,18 +3226,18 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { @Test fun `DismissFolderSelectionBottomSheet should update state to hide bottom sheet`() = runTest { - val action = VaultAddEditAction.Common.DismissFolderSelectionBottomSheet + val action = VaultAddEditAction.Common.DismissBottomSheet viewModel.trySendAction(VaultAddEditAction.Common.SelectOrAddFolderForItem) assertEquals( vaultAddItemInitialState.copy( - shouldShowFolderSelectionBottomSheet = true, + bottomSheetState = VaultAddEditState.BottomSheetState.FolderSelection, ), viewModel.stateFlow.value, ) val expectedState = vaultAddItemInitialState.copy( - shouldShowFolderSelectionBottomSheet = false, + bottomSheetState = null, ) viewModel.trySendAction(action) assertEquals( @@ -3406,13 +3406,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { @Test fun `OwnershipChange should update ownership`() = runTest { - val action = VaultAddEditAction.Common.OwnershipChange( - ownership = VaultAddEditState.Owner( - id = "mockId-1", - name = "a@b.com", - collections = emptyList(), - ), - ) + val action = VaultAddEditAction.Common.OwnershipChange("mockId-1") viewModel.trySendAction(action) @@ -3428,6 +3422,42 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { assertEquals(expectedState, viewModel.stateFlow.value) } + @Test + fun `SelectOwnerForItem should update state to show bottom sheet`() = runTest { + val action = VaultAddEditAction.Common.SelectOwnerForItem + + viewModel.trySendAction(action) + + val expectedState = vaultAddItemInitialState.copy( + bottomSheetState = VaultAddEditState.BottomSheetState.OwnerSelection, + ) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `DismissOwnerSelectionBottomSheet should update state to hide bottom sheet`() = + runTest { + val action = VaultAddEditAction.Common.DismissBottomSheet + + viewModel.trySendAction(VaultAddEditAction.Common.SelectOwnerForItem) + + assertEquals( + vaultAddItemInitialState.copy( + bottomSheetState = VaultAddEditState.BottomSheetState.OwnerSelection, + ), + viewModel.stateFlow.value, + ) + val expectedState = vaultAddItemInitialState.copy( + bottomSheetState = null, + ) + viewModel.trySendAction(action) + assertEquals( + expectedState, + viewModel.stateFlow.value, + ) + } + @Suppress("MaxLineLength") @Test fun `AddNewCustomFieldClick should allow a user to add a custom boolean field in Secure notes item`() = @@ -4437,6 +4467,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { shouldExitOnSave: Boolean = false, typeContentViewState: VaultAddEditState.ViewState.Content.ItemType = createLoginTypeContentViewState(), dialogState: VaultAddEditState.DialogState? = null, + bottomSheetState: VaultAddEditState.BottomSheetState? = null, totpData: TotpData? = null, shouldClearSpecialCircumstance: Boolean = true, ): VaultAddEditState = @@ -4449,11 +4480,11 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { type = typeContentViewState, ), dialog = dialogState, + bottomSheetState = bottomSheetState, shouldExitOnSave = shouldExitOnSave, totpData = totpData, shouldShowCoachMarkTour = false, shouldClearSpecialCircumstance = shouldClearSpecialCircumstance, - shouldShowFolderSelectionBottomSheet = false, ) @Suppress("LongParameterList") @@ -4643,19 +4674,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { ) private fun ownershipChangeAction(): VaultAddEditAction.Common.OwnershipChange = - VaultAddEditAction.Common.OwnershipChange( - ownership = VaultAddEditState.Owner( - id = "organizationId", - name = "organizationName", - collections = listOf( - VaultCollection( - id = "mockId-1", - name = "mockName-1", - isSelected = false, - ), - ), - ), - ) + VaultAddEditAction.Common.OwnershipChange("organizationId") private fun collectionSelectAction(): VaultAddEditAction.Common.CollectionSelect = VaultAddEditAction.Common.CollectionSelect( diff --git a/authenticator/build.gradle.kts b/authenticator/build.gradle.kts index 607803943b..80ea5f71d5 100644 --- a/authenticator/build.gradle.kts +++ b/authenticator/build.gradle.kts @@ -311,6 +311,12 @@ tasks { getByName("sonar") { dependsOn("check") } + withType().configureEach { + jvmTarget = libs.versions.jvmTarget.get() + } + withType().configureEach { + jvmTarget = libs.versions.jvmTarget.get() + } } private fun renameFile(path: String, newName: String) {