mirror of
https://github.com/bitwarden/android.git
synced 2026-03-21 13:52:07 -05:00
PM-18570 Update Owner Selection Field to Bottom Sheet Selector (#4810)
This commit is contained in:
@@ -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<AddEditItemCoachMark>.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 {
|
||||
|
||||
@@ -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<String>,
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<VaultCollection>,
|
||||
) : 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.
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user