Refactored VaultAddItem UI State (#417)

This commit is contained in:
Ramsey Smith 2023-12-19 11:08:15 -07:00 committed by Álison Fernandes
parent acdce7a07b
commit 772d6693a6
13 changed files with 1007 additions and 1855 deletions

View file

@ -20,11 +20,11 @@ import kotlinx.collections.immutable.toImmutableList
*/
@Composable
fun AddEditItemContent(
viewState: VaultAddItemState.ViewState.Content,
state: VaultAddItemState.ViewState.Content,
isAddItemMode: Boolean,
onTypeOptionClicked: (VaultAddItemState.ItemTypeOption) -> Unit,
commonTypeHandlers: VaultAddItemCommonTypeHandlers,
loginItemTypeHandlers: VaultAddLoginItemTypeHandlers,
secureNotesTypeHandlers: VaultAddSecureNotesItemTypeHandlers,
modifier: Modifier = Modifier,
) {
LazyColumn(
@ -42,35 +42,37 @@ fun AddEditItemContent(
item {
Spacer(modifier = Modifier.height(8.dp))
TypeOptionsItem(
content = viewState,
itemType = state.type,
onTypeOptionClicked = onTypeOptionClicked,
modifier = Modifier.padding(horizontal = 16.dp),
)
}
}
when (viewState) {
is VaultAddItemState.ViewState.Content.Login -> {
when (state.type) {
is VaultAddItemState.ViewState.Content.ItemType.Login -> {
addEditLoginItems(
state = viewState,
commonState = state.common,
loginState = state.type,
isAddItemMode = isAddItemMode,
commonActionHandler = commonTypeHandlers,
loginItemTypeHandlers = loginItemTypeHandlers,
)
}
is VaultAddItemState.ViewState.Content.Card -> {
is VaultAddItemState.ViewState.Content.ItemType.Card -> {
// TODO(BIT-507): Create UI for card-type item creation
}
is VaultAddItemState.ViewState.Content.Identity -> {
is VaultAddItemState.ViewState.Content.ItemType.Identity -> {
// TODO(BIT-667): Create UI for identity-type item creation
}
is VaultAddItemState.ViewState.Content.SecureNotes -> {
is VaultAddItemState.ViewState.Content.ItemType.SecureNotes -> {
addEditSecureNotesItems(
state = viewState,
commonState = state.common,
isAddItemMode = isAddItemMode,
secureNotesTypeHandlers = secureNotesTypeHandlers,
commonTypeHandlers = commonTypeHandlers,
)
}
}
@ -83,7 +85,7 @@ fun AddEditItemContent(
@Composable
private fun TypeOptionsItem(
content: VaultAddItemState.ViewState.Content,
itemType: VaultAddItemState.ViewState.Content.ItemType,
onTypeOptionClicked: (VaultAddItemState.ItemTypeOption) -> Unit,
modifier: Modifier,
) {
@ -93,7 +95,7 @@ private fun TypeOptionsItem(
BitwardenMultiSelectButton(
label = stringResource(id = R.string.type),
options = optionsWithStrings.values.toImmutableList(),
selectedOption = stringResource(id = content.displayStringResId),
selectedOption = stringResource(id = itemType.displayStringResId),
onOptionSelected = { selectedOption ->
val selectedOptionId = optionsWithStrings
.entries

View file

@ -34,16 +34,18 @@ import kotlinx.collections.immutable.toImmutableList
*/
@Suppress("LongMethod")
fun LazyListScope.addEditLoginItems(
state: VaultAddItemState.ViewState.Content.Login,
commonState: VaultAddItemState.ViewState.Content.Common,
loginState: VaultAddItemState.ViewState.Content.ItemType.Login,
isAddItemMode: Boolean,
commonActionHandler: VaultAddItemCommonTypeHandlers,
loginItemTypeHandlers: VaultAddLoginItemTypeHandlers,
) {
item {
Spacer(modifier = Modifier.height(8.dp))
BitwardenTextField(
label = stringResource(id = R.string.name),
value = state.name,
onValueChange = loginItemTypeHandlers.onNameTextChange,
value = commonState.name,
onValueChange = commonActionHandler.onNameTextChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -54,7 +56,7 @@ fun LazyListScope.addEditLoginItems(
Spacer(modifier = Modifier.height(8.dp))
BitwardenTextFieldWithActions(
label = stringResource(id = R.string.username),
value = state.username,
value = loginState.username,
onValueChange = loginItemTypeHandlers.onUsernameTextChange,
actions = {
BitwardenIconButtonWithResource(
@ -73,7 +75,7 @@ fun LazyListScope.addEditLoginItems(
Spacer(modifier = Modifier.height(8.dp))
BitwardenPasswordFieldWithActions(
label = stringResource(id = R.string.password),
value = state.password,
value = loginState.password,
onValueChange = loginItemTypeHandlers.onPasswordTextChange,
modifier = Modifier
.padding(horizontal = 16.dp),
@ -131,7 +133,7 @@ fun LazyListScope.addEditLoginItems(
Spacer(modifier = Modifier.height(8.dp))
BitwardenTextFieldWithActions(
label = stringResource(id = R.string.uri),
value = state.uri,
value = loginState.uri,
onValueChange = loginItemTypeHandlers.onUriTextChange,
actions = {
BitwardenIconButtonWithResource(
@ -171,9 +173,9 @@ fun LazyListScope.addEditLoginItems(
Spacer(modifier = Modifier.height(8.dp))
BitwardenMultiSelectButton(
label = stringResource(id = R.string.folder),
options = state.availableFolders.map { it.invoke() }.toImmutableList(),
selectedOption = state.folderName.invoke(),
onOptionSelected = loginItemTypeHandlers.onFolderTextChange,
options = commonState.availableFolders.map { it.invoke() }.toImmutableList(),
selectedOption = commonState.folderName.invoke(),
onOptionSelected = commonActionHandler.onFolderTextChange,
modifier = Modifier.padding(horizontal = 16.dp),
)
}
@ -184,8 +186,8 @@ fun LazyListScope.addEditLoginItems(
label = stringResource(
id = R.string.favorite,
),
isChecked = state.favorite,
onCheckedChange = loginItemTypeHandlers.onToggleFavorite,
isChecked = commonState.favorite,
onCheckedChange = commonActionHandler.onToggleFavorite,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -196,13 +198,13 @@ fun LazyListScope.addEditLoginItems(
Spacer(modifier = Modifier.height(16.dp))
BitwardenSwitchWithActions(
label = stringResource(id = R.string.password_prompt),
isChecked = state.masterPasswordReprompt,
onCheckedChange = loginItemTypeHandlers.onToggleMasterPasswordReprompt,
isChecked = commonState.masterPasswordReprompt,
onCheckedChange = commonActionHandler.onToggleMasterPasswordReprompt,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
actions = {
IconButton(onClick = loginItemTypeHandlers.onTooltipClick) {
IconButton(onClick = commonActionHandler.onTooltipClick) {
Icon(
painter = painterResource(id = R.drawable.ic_tooltip),
tint = MaterialTheme.colorScheme.onSurface,
@ -230,8 +232,8 @@ fun LazyListScope.addEditLoginItems(
BitwardenTextField(
singleLine = false,
label = stringResource(id = R.string.notes),
value = state.notes,
onValueChange = loginItemTypeHandlers.onNotesTextChange,
value = commonState.notes,
onValueChange = commonActionHandler.onNotesTextChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -248,10 +250,10 @@ fun LazyListScope.addEditLoginItems(
)
}
items(state.customFieldData) { customItem ->
items(commonState.customFieldData) { customItem ->
AddEditCustomField(
customItem,
onCustomFieldValueChange = loginItemTypeHandlers.onCustomFieldValueChange,
onCustomFieldValueChange = commonActionHandler.onCustomFieldValueChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -265,7 +267,7 @@ fun LazyListScope.addEditLoginItems(
item {
Spacer(modifier = Modifier.height(16.dp))
AddEditCustomFieldsButton(
onFinishNamingClick = loginItemTypeHandlers.onAddNewCustomFieldClick,
onFinishNamingClick = commonActionHandler.onAddNewCustomFieldClick,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -287,9 +289,9 @@ fun LazyListScope.addEditLoginItems(
Spacer(modifier = Modifier.height(8.dp))
BitwardenMultiSelectButton(
label = stringResource(id = R.string.who_owns_this_item),
options = state.availableOwners.toImmutableList(),
selectedOption = state.ownership,
onOptionSelected = loginItemTypeHandlers.onOwnershipTextChange,
options = commonState.availableOwners.toImmutableList(),
selectedOption = commonState.ownership,
onOptionSelected = commonActionHandler.onOwnershipTextChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),

View file

@ -28,16 +28,16 @@ import kotlinx.collections.immutable.toImmutableList
*/
@Suppress("LongMethod")
fun LazyListScope.addEditSecureNotesItems(
state: VaultAddItemState.ViewState.Content.SecureNotes,
commonState: VaultAddItemState.ViewState.Content.Common,
isAddItemMode: Boolean,
secureNotesTypeHandlers: VaultAddSecureNotesItemTypeHandlers,
commonTypeHandlers: VaultAddItemCommonTypeHandlers,
) {
item {
Spacer(modifier = Modifier.height(8.dp))
BitwardenTextField(
label = stringResource(id = R.string.name),
value = state.name,
onValueChange = secureNotesTypeHandlers.onNameTextChange,
value = commonState.name,
onValueChange = commonTypeHandlers.onNameTextChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -58,9 +58,9 @@ fun LazyListScope.addEditSecureNotesItems(
Spacer(modifier = Modifier.height(8.dp))
BitwardenMultiSelectButton(
label = stringResource(id = R.string.folder),
options = state.availableFolders.map { it.invoke() }.toImmutableList(),
selectedOption = state.folderName.invoke(),
onOptionSelected = secureNotesTypeHandlers.onFolderTextChange,
options = commonState.availableFolders.map { it.invoke() }.toImmutableList(),
selectedOption = commonState.folderName.invoke(),
onOptionSelected = commonTypeHandlers.onFolderTextChange,
modifier = Modifier
.padding(horizontal = 16.dp),
)
@ -70,8 +70,8 @@ fun LazyListScope.addEditSecureNotesItems(
Spacer(modifier = Modifier.height(16.dp))
BitwardenSwitch(
label = stringResource(id = R.string.favorite),
isChecked = state.favorite,
onCheckedChange = secureNotesTypeHandlers.onToggleFavorite,
isChecked = commonState.favorite,
onCheckedChange = commonTypeHandlers.onToggleFavorite,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -82,13 +82,13 @@ fun LazyListScope.addEditSecureNotesItems(
Spacer(modifier = Modifier.height(16.dp))
BitwardenSwitchWithActions(
label = stringResource(id = R.string.password_prompt),
isChecked = state.masterPasswordReprompt,
onCheckedChange = secureNotesTypeHandlers.onToggleMasterPasswordReprompt,
isChecked = commonState.masterPasswordReprompt,
onCheckedChange = commonTypeHandlers.onToggleMasterPasswordReprompt,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
actions = {
IconButton(onClick = secureNotesTypeHandlers.onTooltipClick) {
IconButton(onClick = commonTypeHandlers.onTooltipClick) {
Icon(
painter = painterResource(id = R.drawable.ic_tooltip),
tint = MaterialTheme.colorScheme.onSurface,
@ -116,8 +116,8 @@ fun LazyListScope.addEditSecureNotesItems(
BitwardenTextField(
singleLine = false,
label = stringResource(id = R.string.notes),
value = state.notes,
onValueChange = secureNotesTypeHandlers.onNotesTextChange,
value = commonState.notes,
onValueChange = commonTypeHandlers.onNotesTextChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -133,11 +133,10 @@ fun LazyListScope.addEditSecureNotesItems(
.padding(horizontal = 16.dp),
)
}
items(state.customFieldData) { customItem ->
items(commonState.customFieldData) { customItem ->
AddEditCustomField(
customItem,
onCustomFieldValueChange = secureNotesTypeHandlers.onCustomFieldValueChange,
onCustomFieldValueChange = commonTypeHandlers.onCustomFieldValueChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -147,7 +146,7 @@ fun LazyListScope.addEditSecureNotesItems(
item {
Spacer(modifier = Modifier.height(16.dp))
AddEditCustomFieldsButton(
onFinishNamingClick = secureNotesTypeHandlers.onAddNewCustomFieldClick,
onFinishNamingClick = commonTypeHandlers.onAddNewCustomFieldClick,
options = persistentListOf(
CustomFieldType.TEXT,
CustomFieldType.HIDDEN,
@ -174,9 +173,9 @@ fun LazyListScope.addEditSecureNotesItems(
Spacer(modifier = Modifier.height(8.dp))
BitwardenMultiSelectButton(
label = stringResource(id = R.string.who_owns_this_item),
options = state.availableOwners.toImmutableList(),
selectedOption = state.ownership,
onOptionSelected = secureNotesTypeHandlers.onOwnershipTextChange,
options = commonState.availableOwners.toImmutableList(),
selectedOption = commonState.ownership,
onOptionSelected = commonTypeHandlers.onOwnershipTextChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),

View file

@ -4,8 +4,8 @@ import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.vault.feature.additem.model.CustomFieldType
/**
* A collection of handler functions specifically tailored for managing actions
* within the context of adding secure note items to a vault.
* A collection of handler functions for managing actions common
* within the context of adding items to a vault.
*
* @property onNameTextChange Handles the action when the name text is changed.
* @property onFolderTextChange Handles the action when the folder text is changed.
@ -20,7 +20,7 @@ import com.x8bit.bitwarden.ui.vault.feature.additem.model.CustomFieldType
* @property onCustomFieldValueChange Handles the action when the field's value changes
*/
@Suppress("LongParameterList")
class VaultAddSecureNotesItemTypeHandlers(
class VaultAddItemCommonTypeHandlers(
val onNameTextChange: (String) -> Unit,
val onFolderTextChange: (String) -> Unit,
val onToggleFavorite: (Boolean) -> Unit,
@ -34,54 +34,54 @@ class VaultAddSecureNotesItemTypeHandlers(
companion object {
/**
* Creates an instance of [VaultAddSecureNotesItemTypeHandlers] by binding actions
* Creates an instance of [VaultAddItemCommonTypeHandlers] by binding actions
* to the provided [VaultAddItemViewModel].
*/
@Suppress("LongMethod")
fun create(viewModel: VaultAddItemViewModel): VaultAddSecureNotesItemTypeHandlers {
return VaultAddSecureNotesItemTypeHandlers(
fun create(viewModel: VaultAddItemViewModel): VaultAddItemCommonTypeHandlers {
return VaultAddItemCommonTypeHandlers(
onNameTextChange = { newName ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.NameTextChange(newName),
VaultAddItemAction.Common.NameTextChange(newName),
)
},
onFolderTextChange = { newFolder ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.FolderChange(
VaultAddItemAction.Common.FolderChange(
newFolder.asText(),
),
)
},
onToggleFavorite = { isFavorite ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.ToggleFavorite(isFavorite),
VaultAddItemAction.Common.ToggleFavorite(isFavorite),
)
},
onToggleMasterPasswordReprompt = { isMasterPasswordReprompt ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.ToggleMasterPasswordReprompt(
VaultAddItemAction.Common.ToggleMasterPasswordReprompt(
isMasterPasswordReprompt,
),
)
},
onNotesTextChange = { newNotes ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.NotesTextChange(newNotes),
VaultAddItemAction.Common.NotesTextChange(newNotes),
)
},
onOwnershipTextChange = { newOwnership ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.OwnershipChange(newOwnership),
VaultAddItemAction.Common.OwnershipChange(newOwnership),
)
},
onTooltipClick = {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.TooltipClick,
VaultAddItemAction.Common.TooltipClick,
)
},
onAddNewCustomFieldClick = { newCustomFieldType, name ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.AddNewCustomFieldClick(
VaultAddItemAction.Common.AddNewCustomFieldClick(
newCustomFieldType,
name,
),
@ -89,7 +89,7 @@ class VaultAddSecureNotesItemTypeHandlers(
},
onCustomFieldValueChange = { newValue ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.CustomFieldValueChange(
VaultAddItemAction.Common.CustomFieldValueChange(
newValue,
),
)

View file

@ -55,14 +55,14 @@ fun VaultAddItemScreen(
VaultAddLoginItemTypeHandlers.create(viewModel = viewModel)
}
val secureNotesTypeHandlers = remember(viewModel) {
VaultAddSecureNotesItemTypeHandlers.create(viewModel = viewModel)
val commonTypeHandlers = remember(viewModel) {
VaultAddItemCommonTypeHandlers.create(viewModel = viewModel)
}
VaultAddEditItemDialogs(
dialogState = state.dialog,
onDismissRequest = remember(viewModel) {
{ viewModel.trySendAction(VaultAddItemAction.DismissDialog) }
{ viewModel.trySendAction(VaultAddItemAction.Common.DismissDialog) }
},
)
@ -77,14 +77,14 @@ fun VaultAddItemScreen(
navigationIcon = painterResource(id = R.drawable.ic_close),
navigationIconContentDescription = stringResource(id = R.string.close),
onNavigationIconClick = remember(viewModel) {
{ viewModel.trySendAction(VaultAddItemAction.CloseClick) }
{ viewModel.trySendAction(VaultAddItemAction.Common.CloseClick) }
},
scrollBehavior = scrollBehavior,
actions = {
BitwardenTextButton(
label = stringResource(id = R.string.save),
onClick = remember(viewModel) {
{ viewModel.trySendAction(VaultAddItemAction.SaveClick) }
{ viewModel.trySendAction(VaultAddItemAction.Common.SaveClick) }
},
)
},
@ -94,13 +94,13 @@ fun VaultAddItemScreen(
when (val viewState = state.viewState) {
is VaultAddItemState.ViewState.Content -> {
AddEditItemContent(
viewState = viewState,
state = viewState,
isAddItemMode = state.isAddItemMode,
onTypeOptionClicked = remember(viewModel) {
{ viewModel.trySendAction(VaultAddItemAction.TypeOptionSelect(it)) }
{ viewModel.trySendAction(VaultAddItemAction.Common.TypeOptionSelect(it)) }
},
loginItemTypeHandlers = loginItemTypeHandlers,
secureNotesTypeHandlers = secureNotesTypeHandlers,
commonTypeHandlers = commonTypeHandlers,
modifier = Modifier
.imePadding()
.padding(innerPadding)

View file

@ -1,22 +1,13 @@
package com.x8bit.bitwarden.ui.vault.feature.additem
import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.vault.feature.additem.model.CustomFieldType
/**
* A collection of handler functions specifically tailored for managing actions
* within the context of adding login items to a vault.
*
* @property onNameTextChange Handles the action when the name text is changed.
* @property onUsernameTextChange Handles the action when the username text is changed.
* @property onPasswordTextChange Handles the action when the password text is changed.
* @property onUriTextChange Handles the action when the URI text is changed.
* @property onFolderTextChange Handles the action when the folder text is changed.
* @property onToggleFavorite Handles the action when the favorite toggle is changed.
* @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 onOwnershipTextChange Handles the action when the ownership text is changed.
* @property onOpenUsernameGeneratorClick Handles the action when the username generator
* button is clicked.
* @property onPasswordCheckerClick Handles the action when the password checker
@ -26,31 +17,18 @@ import com.x8bit.bitwarden.ui.vault.feature.additem.model.CustomFieldType
* @property onSetupTotpClick Handles the action when the setup TOTP button is clicked.
* @property onUriSettingsClick Handles the action when the URI settings button is clicked.
* @property onAddNewUriClick Handles the action when the add new URI button is clicked.
* @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
*/
@Suppress("LongParameterList")
class VaultAddLoginItemTypeHandlers(
val onNameTextChange: (String) -> Unit,
val onUsernameTextChange: (String) -> Unit,
val onPasswordTextChange: (String) -> Unit,
val onUriTextChange: (String) -> Unit,
val onFolderTextChange: (String) -> Unit,
val onToggleFavorite: (Boolean) -> Unit,
val onToggleMasterPasswordReprompt: (Boolean) -> Unit,
val onNotesTextChange: (String) -> Unit,
val onOwnershipTextChange: (String) -> Unit,
val onOpenUsernameGeneratorClick: () -> Unit,
val onPasswordCheckerClick: () -> Unit,
val onOpenPasswordGeneratorClick: () -> Unit,
val onSetupTotpClick: () -> Unit,
val onUriSettingsClick: () -> Unit,
val onAddNewUriClick: () -> Unit,
val onTooltipClick: () -> Unit,
val onAddNewCustomFieldClick: (CustomFieldType, String) -> Unit,
val onCustomFieldValueChange: (VaultAddItemState.Custom) -> Unit,
) {
companion object {
@ -64,11 +42,6 @@ class VaultAddLoginItemTypeHandlers(
@Suppress("LongMethod")
fun create(viewModel: VaultAddItemViewModel): VaultAddLoginItemTypeHandlers {
return VaultAddLoginItemTypeHandlers(
onNameTextChange = { newName ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.NameTextChange(newName),
)
},
onUsernameTextChange = { newUsername ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.UsernameTextChange(newUsername),
@ -84,33 +57,6 @@ class VaultAddLoginItemTypeHandlers(
VaultAddItemAction.ItemType.LoginType.UriTextChange(newUri),
)
},
onFolderTextChange = { newFolder ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.FolderChange(newFolder.asText()),
)
},
onToggleFavorite = { isFavorite ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.ToggleFavorite(isFavorite),
)
},
onToggleMasterPasswordReprompt = { isMasterPasswordReprompt ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.ToggleMasterPasswordReprompt(
isMasterPasswordReprompt,
),
)
},
onNotesTextChange = { newNotes ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.NotesTextChange(newNotes),
)
},
onOwnershipTextChange = { newOwnership ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.OwnershipChange(newOwnership),
)
},
onOpenUsernameGeneratorClick = {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.OpenUsernameGeneratorClick,
@ -135,24 +81,6 @@ class VaultAddLoginItemTypeHandlers(
onAddNewUriClick = {
viewModel.trySendAction(VaultAddItemAction.ItemType.LoginType.AddNewUriClick)
},
onTooltipClick = {
viewModel.trySendAction(VaultAddItemAction.ItemType.LoginType.TooltipClick)
},
onAddNewCustomFieldClick = { customFieldType, name ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.AddNewCustomFieldClick(
customFieldType = customFieldType,
name = name,
),
)
},
onCustomFieldValueChange = { customField ->
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.CustomFieldValueChange(
customField = customField,
),
)
},
)
}
}

View file

@ -15,55 +15,36 @@ import java.util.UUID
* Transforms [CipherView] into [VaultAddItemState.ViewState].
*/
fun CipherView.toViewState(): VaultAddItemState.ViewState =
when (type) {
CipherType.LOGIN -> {
val loginView = requireNotNull(this.login)
VaultAddItemState.ViewState.Content.Login(
originalCipher = this,
name = this.name,
username = loginView.username.orEmpty(),
password = loginView.password.orEmpty(),
uri = loginView.uris?.firstOrNull()?.uri.orEmpty(),
favorite = this.favorite,
masterPasswordReprompt = this.reprompt == CipherRepromptType.PASSWORD,
notes = this.notes.orEmpty(),
// TODO: Update these properties to pull folder from data layer (BIT-501)
folderName = this.folderId?.asText() ?: R.string.folder_none.asText(),
availableFolders = emptyList(),
// TODO: Update this property to pull owner from data layer (BIT-501)
ownership = "",
// TODO: Update this property to pull available owners from data layer (BIT-501)
availableOwners = emptyList(),
customFieldData = this.fields.orEmpty().map { it.toCustomField() },
)
}
VaultAddItemState.ViewState.Content(
type = when (type) {
CipherType.LOGIN -> {
VaultAddItemState.ViewState.Content.ItemType.Login(
username = login?.username.orEmpty(),
password = login?.password.orEmpty(),
uri = login?.uris?.firstOrNull()?.uri.orEmpty(),
)
}
CipherType.SECURE_NOTE -> {
VaultAddItemState.ViewState.Content.SecureNotes(
originalCipher = this,
name = this.name,
favorite = this.favorite,
masterPasswordReprompt = this.reprompt == CipherRepromptType.PASSWORD,
notes = this.notes.orEmpty(),
// TODO: Update these properties to pull folder from data layer (BIT-501)
folderName = this.folderId?.asText() ?: R.string.folder_none.asText(),
availableFolders = emptyList(),
// TODO: Update this property to pull owner from data layer (BIT-501)
ownership = "",
// TODO: Update this property to pull available owners from data layer (BIT-501)
availableOwners = emptyList(),
customFieldData = this.fields.orEmpty().map { it.toCustomField() },
)
}
CipherType.CARD -> VaultAddItemState.ViewState.Error(
message = "Not yet implemented.".asText(),
)
CipherType.IDENTITY -> VaultAddItemState.ViewState.Error(
message = "Not yet implemented.".asText(),
)
}
CipherType.SECURE_NOTE -> VaultAddItemState.ViewState.Content.ItemType.SecureNotes
CipherType.CARD -> VaultAddItemState.ViewState.Content.ItemType.Card
CipherType.IDENTITY -> VaultAddItemState.ViewState.Content.ItemType.Identity
},
common = VaultAddItemState.ViewState.Content.Common(
originalCipher = this,
name = this.name,
favorite = this.favorite,
masterPasswordReprompt = this.reprompt == CipherRepromptType.PASSWORD,
notes = this.notes.orEmpty(),
// TODO: Update these properties to pull folder from data layer (BIT-501)
folderName = this.folderId?.asText() ?: R.string.folder_none.asText(),
availableFolders = emptyList(),
// TODO: Update this property to pull owner from data layer (BIT-501)
ownership = "",
// TODO: Update this property to pull available owners from data layer (BIT-501)
availableOwners = emptyList(),
customFieldData = this.fields.orEmpty().map { it.toCustomField() },
),
)
private fun FieldView.toCustomField() =
when (this.type) {

View file

@ -100,53 +100,53 @@ fun VaultData.toViewState(): VaultState.ViewState =
}
/**
* Transforms a [VaultAddItemState.ViewState.Content] into [CipherView].
* Transforms a [VaultAddItemState.ViewState.ItemType] into [CipherView].
*/
fun VaultAddItemState.ViewState.Content.toCipherView(): CipherView =
CipherView(
// Pulled from original cipher when editing, otherwise uses defaults
id = this.originalCipher?.id,
collectionIds = this.originalCipher?.collectionIds.orEmpty(),
key = this.originalCipher?.key,
edit = this.originalCipher?.edit ?: true,
viewPassword = this.originalCipher?.viewPassword ?: true,
localData = this.originalCipher?.localData,
attachments = this.originalCipher?.attachments,
organizationUseTotp = this.originalCipher?.organizationUseTotp ?: false,
passwordHistory = this.originalCipher?.passwordHistory,
creationDate = this.originalCipher?.creationDate ?: Instant.now(),
deletedDate = this.originalCipher?.deletedDate,
revisionDate = this.originalCipher?.revisionDate ?: Instant.now(),
id = common.originalCipher?.id,
collectionIds = common.originalCipher?.collectionIds.orEmpty(),
key = common.originalCipher?.key,
edit = common.originalCipher?.edit ?: true,
viewPassword = common.originalCipher?.viewPassword ?: true,
localData = common.originalCipher?.localData,
attachments = common.originalCipher?.attachments,
organizationUseTotp = common.originalCipher?.organizationUseTotp ?: false,
passwordHistory = common.originalCipher?.passwordHistory,
creationDate = common.originalCipher?.creationDate ?: Instant.now(),
deletedDate = common.originalCipher?.deletedDate,
revisionDate = common.originalCipher?.revisionDate ?: Instant.now(),
// Type specific section
type = this.toCipherType(),
identity = this.toIdentityView(),
secureNote = this.toSecureNotesView(),
login = this.toLoginView(),
card = this.toCardView(),
type = type.toCipherType(),
identity = type.toIdentityView(),
secureNote = type.toSecureNotesView(),
login = type.toLoginView(common = common),
card = type.toCardView(),
// Fields we always grab from the UI
name = this.name,
notes = this.notes,
favorite = this.favorite,
name = common.name,
notes = common.notes,
favorite = common.favorite,
// TODO Use real folder ID (BIT-528)
folderId = this.originalCipher?.folderId,
folderId = common.originalCipher?.folderId,
// TODO Use real organization ID (BIT-780)
organizationId = this.originalCipher?.organizationId,
reprompt = this.toCipherRepromptType(),
fields = this.customFieldData.map { it.toFieldView() },
organizationId = common.originalCipher?.organizationId,
reprompt = common.toCipherRepromptType(),
fields = common.customFieldData.map { it.toFieldView() },
)
private fun VaultAddItemState.ViewState.Content.toCipherType(): CipherType =
private fun VaultAddItemState.ViewState.Content.ItemType.toCipherType(): CipherType =
when (this) {
is VaultAddItemState.ViewState.Content.Card -> CipherType.CARD
is VaultAddItemState.ViewState.Content.Identity -> CipherType.IDENTITY
is VaultAddItemState.ViewState.Content.Login -> CipherType.LOGIN
is VaultAddItemState.ViewState.Content.SecureNotes -> CipherType.SECURE_NOTE
is VaultAddItemState.ViewState.Content.ItemType.Card -> CipherType.CARD
is VaultAddItemState.ViewState.Content.ItemType.Identity -> CipherType.IDENTITY
is VaultAddItemState.ViewState.Content.ItemType.Login -> CipherType.LOGIN
is VaultAddItemState.ViewState.Content.ItemType.SecureNotes -> CipherType.SECURE_NOTE
}
private fun VaultAddItemState.ViewState.Content.toCardView(): CardView? =
(this as? VaultAddItemState.ViewState.Content.Card)?.let {
private fun VaultAddItemState.ViewState.Content.ItemType.toCardView(): CardView? =
(this as? VaultAddItemState.ViewState.Content.ItemType.Card)?.let {
// TODO Create real CardView from Content (BIT-668)
CardView(
cardholderName = null,
@ -158,8 +158,8 @@ private fun VaultAddItemState.ViewState.Content.toCardView(): CardView? =
)
}
private fun VaultAddItemState.ViewState.Content.toIdentityView(): IdentityView? =
(this as? VaultAddItemState.ViewState.Content.Identity)?.let {
private fun VaultAddItemState.ViewState.Content.ItemType.toIdentityView(): IdentityView? =
(this as? VaultAddItemState.ViewState.Content.ItemType.Identity)?.let {
// TODO Create real IdentityView from Content (BIT-508)
IdentityView(
title = null,
@ -183,12 +183,14 @@ private fun VaultAddItemState.ViewState.Content.toIdentityView(): IdentityView?
)
}
private fun VaultAddItemState.ViewState.Content.toLoginView(): LoginView? =
(this as? VaultAddItemState.ViewState.Content.Login)?.let {
private fun VaultAddItemState.ViewState.Content.ItemType.toLoginView(
common: VaultAddItemState.ViewState.Content.Common,
): LoginView? =
(this as? VaultAddItemState.ViewState.Content.ItemType.Login)?.let {
LoginView(
username = it.username,
password = it.password,
passwordRevisionDate = it.originalCipher?.login?.passwordRevisionDate,
passwordRevisionDate = common.originalCipher?.login?.passwordRevisionDate,
uris = listOf(
// TODO Implement URI list (BIT-1094)
LoginUriView(
@ -198,18 +200,18 @@ private fun VaultAddItemState.ViewState.Content.toLoginView(): LoginView? =
),
),
// TODO Implement TOTP (BIT-1066)
totp = it.originalCipher?.login?.totp,
autofillOnPageLoad = it.originalCipher?.login?.autofillOnPageLoad,
totp = common.originalCipher?.login?.totp,
autofillOnPageLoad = common.originalCipher?.login?.autofillOnPageLoad,
)
}
private fun VaultAddItemState.ViewState.Content.toSecureNotesView(): SecureNoteView? =
(this as? VaultAddItemState.ViewState.Content.SecureNotes)?.let {
private fun VaultAddItemState.ViewState.Content.ItemType.toSecureNotesView(): SecureNoteView? =
(this as? VaultAddItemState.ViewState.Content.ItemType.SecureNotes)?.let {
SecureNoteView(type = SecureNoteType.GENERIC)
}
private fun VaultAddItemState.ViewState.Content.toCipherRepromptType(): CipherRepromptType =
if (this.masterPasswordReprompt) {
private fun VaultAddItemState.ViewState.Content.Common.toCipherRepromptType(): CipherRepromptType =
if (masterPasswordReprompt) {
CipherRepromptType.PASSWORD
} else {
CipherRepromptType.NONE

View file

@ -31,7 +31,6 @@ import com.x8bit.bitwarden.ui.util.onNodeWithContentDescriptionAfterScroll
import com.x8bit.bitwarden.ui.util.onNodeWithTextAfterScroll
import com.x8bit.bitwarden.ui.vault.feature.additem.model.CustomFieldType
import com.x8bit.bitwarden.ui.vault.model.VaultAddEditType
import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
@ -79,7 +78,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.CloseClick,
VaultAddItemAction.Common.CloseClick,
)
}
}
@ -92,7 +91,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.SaveClick,
VaultAddItemAction.Common.SaveClick,
)
}
}
@ -108,7 +107,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.DismissDialog,
VaultAddItemAction.Common.DismissDialog,
)
}
}
@ -139,7 +138,12 @@ class VaultAddItemScreenTest : BaseComposeTest() {
composeTestRule.onNodeWithText(message).assertIsNotDisplayed()
mutableStateFlow.update {
it.copy(viewState = VaultAddItemState.ViewState.Content.Login())
it.copy(
viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(),
type = VaultAddItemState.ViewState.Content.ItemType.Login(),
),
)
}
composeTestRule.onNodeWithText(message).assertIsNotDisplayed()
@ -162,7 +166,12 @@ class VaultAddItemScreenTest : BaseComposeTest() {
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
mutableStateFlow.update {
it.copy(viewState = VaultAddItemState.ViewState.Content.Login())
it.copy(
viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(),
type = VaultAddItemState.ViewState.Content.ItemType.Login(),
),
)
}
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
}
@ -183,7 +192,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.TypeOptionSelect(VaultAddItemState.ItemTypeOption.LOGIN),
VaultAddItemAction.Common.TypeOptionSelect(VaultAddItemState.ItemTypeOption.LOGIN),
)
}
}
@ -194,41 +203,18 @@ class VaultAddItemScreenTest : BaseComposeTest() {
.onNodeWithContentDescriptionAfterScroll(label = "Type, Login")
.assertIsDisplayed()
mutableStateFlow.update { it.copy(viewState = VaultAddItemState.ViewState.Content.Card()) }
mutableStateFlow.update { it.copy(
viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(),
type = VaultAddItemState.ViewState.Content.ItemType.Card,
),
) }
composeTestRule
.onNodeWithContentDescriptionAfterScroll(label = "Type, Card")
.assertIsDisplayed()
}
@Test
fun `in ItemType_Login state changing Name text field should trigger NameTextChange`() {
composeTestRule
.onNodeWithTextAfterScroll(text = "Name")
.performTextInput(text = "TestName")
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.NameTextChange(name = "TestName"),
)
}
}
@Test
fun `in ItemType_Login the name control should display the text provided by the state`() {
composeTestRule
.onNodeWithTextAfterScroll(text = "Name")
.assertTextContains("")
mutableStateFlow.update { currentState ->
updateLoginType(currentState) { copy(name = "NewName") }
}
composeTestRule
.onNodeWithTextAfterScroll(text = "Name")
.assertTextContains("NewName")
}
@Test
fun `in ItemType_Login state changing Username text field should trigger UsernameTextChange`() {
composeTestRule
@ -399,191 +385,9 @@ class VaultAddItemScreenTest : BaseComposeTest() {
}
}
@Test
fun `in ItemType_Login state clicking a Folder Option should send FolderChange action`() {
// Opens the menu
composeTestRule
.onNodeWithContentDescriptionAfterScroll(label = "Folder, No Folder")
.performClick()
// Choose the option from the menu
composeTestRule
.onAllNodesWithText(text = "Folder 1")
.onLast()
.performScrollTo()
.performClick()
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.FolderChange("Folder 1".asText()),
)
}
}
@Test
fun `in ItemType_Login the folder control should display the text provided by the state`() {
composeTestRule
.onNodeWithContentDescriptionAfterScroll(label = "Folder, No Folder")
.assertIsDisplayed()
mutableStateFlow.update { currentState ->
updateLoginType(currentState) { copy(folderName = "Folder 2".asText()) }
}
composeTestRule
.onNodeWithContentDescriptionAfterScroll(label = "Folder, Folder 2")
.assertIsDisplayed()
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state, toggling the favorite toggle should send ToggleFavorite action`() {
composeTestRule
.onNodeWithTextAfterScroll("Favorite")
.performClick()
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.ToggleFavorite(
isFavorite = true,
),
)
}
}
@Test
fun `in ItemType_Login the favorite toggle should be enabled or disabled according to state`() {
composeTestRule
.onNodeWithTextAfterScroll("Favorite")
.assertIsOff()
mutableStateFlow.update { currentState ->
updateLoginType(currentState) { copy(favorite = true) }
}
composeTestRule
.onNodeWithTextAfterScroll("Favorite")
.assertIsOn()
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state, toggling the Master password re-prompt toggle should send ToggleMasterPasswordReprompt action`() {
composeTestRule
.onNodeWithTextAfterScroll("Master password re-prompt")
.performTouchInput {
click(position = Offset(x = 1f, y = center.y))
}
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.ToggleMasterPasswordReprompt(
isMasterPasswordReprompt = true,
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login the master password re-prompt toggle should be enabled or disabled according to state`() {
composeTestRule
.onNodeWithTextAfterScroll("Master password re-prompt")
.assertIsOff()
mutableStateFlow.update { currentState ->
updateLoginType(currentState) { copy(masterPasswordReprompt = true) }
}
composeTestRule
.onNodeWithTextAfterScroll("Master password re-prompt")
.assertIsOn()
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state, toggling the Master password re-prompt tooltip button should send TooltipClick action`() {
composeTestRule
.onNodeWithContentDescriptionAfterScroll(label = "Master password re-prompt help")
.performClick()
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.TooltipClick,
)
}
}
@Test
fun `in ItemType_Login state changing Notes text field should trigger NotesTextChange`() {
composeTestRule
.onAllNodesWithTextAfterScroll("Notes")
.filterToOne(hasSetTextAction())
.performTextInput("TestNotes")
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.NotesTextChange("TestNotes"),
)
}
}
@Test
fun `in ItemType_Login the Notes control should display the text provided by the state`() {
composeTestRule
.onAllNodesWithTextAfterScroll("Notes")
.filterToOne(hasSetTextAction())
.performTextInput("")
mutableStateFlow.update { currentState ->
updateLoginType(currentState) { copy(notes = "NewNote") }
}
composeTestRule
.onAllNodesWithTextAfterScroll("Notes")
.filterToOne(hasSetTextAction())
.assertTextContains("NewNote")
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state clicking New Custom Field button should allow creation of Text type`() {
mutableStateFlow.value = DEFAULT_STATE_LOGIN
composeTestRule
.onNodeWithTextAfterScroll(text = "New custom field")
.performClick()
composeTestRule
.onAllNodesWithText("Cancel")
.filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
composeTestRule
.onNodeWithText(text = "Text")
.performClick()
composeTestRule
.onNodeWithText("Name")
.performTextInput("TestText")
composeTestRule
.onNodeWithText("Ok")
.performClick()
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.AddNewCustomFieldClick(
customFieldType = CustomFieldType.TEXT,
name = "TestText",
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state clicking New Custom Field button should allow creation of Linked type`() {
fun `clicking New Custom Field button should allow creation of Linked type`() {
mutableStateFlow.value = DEFAULT_STATE_LOGIN
composeTestRule
@ -609,7 +413,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.AddNewCustomFieldClick(
VaultAddItemAction.Common.AddNewCustomFieldClick(
customFieldType = CustomFieldType.LINKED,
name = "TestLinked",
),
@ -617,134 +421,8 @@ class VaultAddItemScreenTest : BaseComposeTest() {
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state clicking New Custom Field button should allow creation of Boolean type`() {
mutableStateFlow.value = DEFAULT_STATE_LOGIN
composeTestRule
.onNodeWithTextAfterScroll(text = "New custom field")
.performClick()
composeTestRule
.onAllNodesWithText("Cancel")
.filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
composeTestRule
.onNodeWithText(text = "Boolean")
.performClick()
composeTestRule
.onNodeWithText("Name")
.performTextInput("TestBoolean")
composeTestRule
.onNodeWithText("Ok")
.performClick()
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.AddNewCustomFieldClick(
customFieldType = CustomFieldType.BOOLEAN,
name = "TestBoolean",
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state clicking New Custom Field button should allow creation of Hidden type`() {
mutableStateFlow.value = DEFAULT_STATE_LOGIN
composeTestRule
.onNodeWithTextAfterScroll(text = "New custom field")
.performClick()
composeTestRule
.onAllNodesWithText("Cancel")
.filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
composeTestRule
.onNodeWithText(text = "Hidden")
.performClick()
composeTestRule
.onNodeWithText("Name")
.performTextInput("TestHidden")
composeTestRule
.onNodeWithText("Ok")
.performClick()
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.AddNewCustomFieldClick(
customFieldType = CustomFieldType.HIDDEN,
name = "TestHidden",
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state clicking and changing the custom text field will send a CustomFieldValueChange event`() {
mutableStateFlow.value = DEFAULT_STATE_LOGIN_CUSTOM_FIELDS
composeTestRule
.onNodeWithTextAfterScroll("TestText")
.performTextClearance()
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.CustomFieldValueChange(
VaultAddItemState.Custom.TextField("Test ID", "TestText", ""),
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state clicking and changing the custom hidden field will send a CustomFieldValueChange event`() {
mutableStateFlow.value = DEFAULT_STATE_LOGIN_CUSTOM_FIELDS
composeTestRule
.onNodeWithTextAfterScroll("TestHidden")
.performTextClearance()
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.CustomFieldValueChange(
VaultAddItemState.Custom.HiddenField("Test ID", "TestHidden", ""),
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state clicking and changing the custom boolean field will send a CustomFieldValueChange event`() {
mutableStateFlow.value = DEFAULT_STATE_LOGIN_CUSTOM_FIELDS
composeTestRule
.onNodeWithTextAfterScroll("TestBoolean")
.performClick()
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.CustomFieldValueChange(
VaultAddItemState.Custom.BooleanField("Test ID", "TestBoolean", true),
),
)
}
}
@Test
fun `in ItemType_Login state clicking a Ownership option should send OwnershipChange action`() {
fun `clicking a Ownership option should send OwnershipChange action`() {
// Opens the menu
composeTestRule
.onNodeWithContentDescriptionAfterScroll(
@ -761,13 +439,13 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.LoginType.OwnershipChange("a@b.com"),
VaultAddItemAction.Common.OwnershipChange("a@b.com"),
)
}
}
@Test
fun `in ItemType_Login the Ownership control should display the text provided by the state`() {
fun `the Ownership control should display the text provided by the state`() {
composeTestRule
.onNodeWithContentDescriptionAfterScroll(
label = "Who owns this item?, placeholder@email.com",
@ -775,7 +453,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
.assertIsDisplayed()
mutableStateFlow.update { currentState ->
updateLoginType(currentState) { copy(ownership = "Owner 2") }
updateCommonContent(currentState) { copy(ownership = "Owner 2") }
}
composeTestRule
@ -784,7 +462,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
}
@Test
fun `in ItemType_SecureNotes state changing Name text field should trigger NameTextChange`() {
fun `changing Name text field should trigger NameTextChange`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -793,13 +471,13 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.NameTextChange(name = "TestName"),
VaultAddItemAction.Common.NameTextChange(name = "TestName"),
)
}
}
@Test
fun `in ItemType_SecureNotes the name control should display the text provided by the state`() {
fun `the name control should display the text provided by the state`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -807,7 +485,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
.assertTextContains("")
mutableStateFlow.update { currentState ->
updateSecureNotesType(currentState) { copy(name = "NewName") }
updateCommonContent(currentState) { copy(name = "NewName") }
}
composeTestRule
@ -816,7 +494,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
}
@Test
fun `in ItemType_SecureNotes state clicking a Folder Option should send FolderChange action`() {
fun `clicking a Folder Option should send FolderChange action`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
// Opens the menu
@ -833,14 +511,14 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.FolderChange("Folder 1".asText()),
VaultAddItemAction.Common.FolderChange("Folder 1".asText()),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes the folder control should display the text provided by the state`() {
fun `the folder control should display the text provided by the state`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -848,7 +526,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
.assertIsDisplayed()
mutableStateFlow.update { currentState ->
updateSecureNotesType(currentState) { copy(folderName = "Folder 2".asText()) }
updateCommonContent(currentState) { copy(folderName = "Folder 2".asText()) }
}
composeTestRule
@ -858,7 +536,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state, toggling the favorite toggle should send ToggleFavorite action`() {
fun `toggling the favorite toggle should send ToggleFavorite action`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -867,16 +545,15 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.ToggleFavorite(
VaultAddItemAction.Common.ToggleFavorite(
isFavorite = true,
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes the favorite toggle should be enabled or disabled according to state`() {
fun `the favorite toggle should be enabled or disabled according to state`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -884,7 +561,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
.assertIsOff()
mutableStateFlow.update { currentState ->
updateSecureNotesType(currentState) { copy(favorite = true) }
updateCommonContent(currentState) { copy(favorite = true) }
}
composeTestRule
@ -894,7 +571,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state, toggling the Master password re-prompt toggle should send ToggleMasterPasswordReprompt action`() {
fun `toggling the Master password re-prompt toggle should send ToggleMasterPasswordReprompt action`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -905,7 +582,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.ToggleMasterPasswordReprompt(
VaultAddItemAction.Common.ToggleMasterPasswordReprompt(
isMasterPasswordReprompt = true,
),
)
@ -914,7 +591,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes the master password re-prompt toggle should be enabled or disabled according to state`() {
fun `the master password re-prompt toggle should be enabled or disabled according to state`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -922,7 +599,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
.assertIsOff()
mutableStateFlow.update { currentState ->
updateSecureNotesType(currentState) { copy(masterPasswordReprompt = true) }
updateCommonContent(currentState) { copy(masterPasswordReprompt = true) }
}
composeTestRule
@ -930,9 +607,8 @@ class VaultAddItemScreenTest : BaseComposeTest() {
.assertIsOn()
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state, toggling the Master password re-prompt tooltip button should send TooltipClick action`() {
fun `toggling the Master password re-prompt tooltip button should send TooltipClick action`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -941,13 +617,13 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.TooltipClick,
VaultAddItemAction.Common.TooltipClick,
)
}
}
@Test
fun `in ItemType_SecureNotes state changing Notes text field should trigger NotesTextChange`() {
fun `changing Notes text field should trigger NotesTextChange`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -957,14 +633,13 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.NotesTextChange("TestNotes"),
VaultAddItemAction.Common.NotesTextChange("TestNotes"),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes the Notes control should display the text provided by the state`() {
fun `the Notes control should display the text provided by the state`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -973,7 +648,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
.assertTextContains("")
mutableStateFlow.update { currentState ->
updateSecureNotesType(currentState) { copy(notes = "NewNote") }
updateCommonContent(currentState) { copy(notes = "NewNote") }
}
composeTestRule
@ -984,7 +659,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state clicking a Ownership option should send OwnershipChange action`() {
fun `Ownership option should send OwnershipChange action`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
// Opens the menu
@ -1001,7 +676,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.OwnershipChange("a@b.com"),
VaultAddItemAction.Common.OwnershipChange("a@b.com"),
)
}
}
@ -1016,7 +691,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
.assertIsDisplayed()
mutableStateFlow.update { currentState ->
updateSecureNotesType(currentState) { copy(ownership = "Owner 2") }
updateCommonContent(currentState) { copy(ownership = "Owner 2") }
}
composeTestRule
@ -1026,7 +701,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state clicking New Custom Field button should allow creation of Text type`() {
fun `clicking New Custom Field button should allow creation of Text type`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -1052,7 +727,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.AddNewCustomFieldClick(
VaultAddItemAction.Common.AddNewCustomFieldClick(
customFieldType = CustomFieldType.TEXT,
name = "TestText",
),
@ -1062,7 +737,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state clicking New Custom Field button should not display linked type`() {
fun `clicking New Custom Field button should not display linked type`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -1081,7 +756,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state clicking New Custom Field button should allow creation of Boolean type`() {
fun `clicking New Custom Field button should allow creation of Boolean type`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -1107,7 +782,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.AddNewCustomFieldClick(
VaultAddItemAction.Common.AddNewCustomFieldClick(
customFieldType = CustomFieldType.BOOLEAN,
name = "TestBoolean",
),
@ -1115,9 +790,8 @@ class VaultAddItemScreenTest : BaseComposeTest() {
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state clicking New Custom Field button should allow creation of Hidden type`() {
fun `clicking New Custom Field button should allow creation of Hidden type`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES
composeTestRule
@ -1144,7 +818,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.AddNewCustomFieldClick(
VaultAddItemAction.Common.AddNewCustomFieldClick(
customFieldType = CustomFieldType.HIDDEN,
name = "TestHidden",
),
@ -1154,7 +828,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state clicking and changing the custom text field will send a CustomFieldValueChange event`() {
fun `clicking and changing the custom text field will send a CustomFieldValueChange event`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES_CUSTOM_FIELDS
composeTestRule
@ -1163,7 +837,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.CustomFieldValueChange(
VaultAddItemAction.Common.CustomFieldValueChange(
VaultAddItemState.Custom.TextField("Test ID", "TestText", ""),
),
)
@ -1172,7 +846,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state clicking and changing the custom hidden field will send a CustomFieldValueChange event`() {
fun `clicking and changing the custom hidden field will send a CustomFieldValueChange event`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES_CUSTOM_FIELDS
composeTestRule
@ -1181,7 +855,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.CustomFieldValueChange(
VaultAddItemAction.Common.CustomFieldValueChange(
VaultAddItemState.Custom.HiddenField("Test ID", "TestHidden", ""),
),
)
@ -1190,7 +864,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_SecureNotes state clicking and changing the custom boolean field will send a CustomFieldValueChange event`() {
fun `clicking and changing the custom boolean field will send a CustomFieldValueChange event`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES_CUSTOM_FIELDS
composeTestRule
@ -1199,7 +873,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddItemAction.ItemType.SecureNotesType.CustomFieldValueChange(
VaultAddItemAction.Common.CustomFieldValueChange(
VaultAddItemState.Custom.BooleanField("Test ID", "TestBoolean", true),
),
)
@ -1211,22 +885,34 @@ class VaultAddItemScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
private fun updateLoginType(
currentState: VaultAddItemState,
transform: VaultAddItemState.ViewState.Content.Login.() -> VaultAddItemState.ViewState.Content.Login,
transform: VaultAddItemState.ViewState.Content.ItemType.Login.() ->
VaultAddItemState.ViewState.Content.ItemType.Login,
): VaultAddItemState {
val updatedType = when (val viewState = currentState.viewState) {
is VaultAddItemState.ViewState.Content.Login -> viewState.transform()
is VaultAddItemState.ViewState.Content -> {
when (val type = viewState.type) {
is VaultAddItemState.ViewState.Content.ItemType.Login -> {
viewState.copy(
type = type.transform(),
)
}
else -> viewState
}
}
else -> viewState
}
return currentState.copy(viewState = updatedType)
}
@Suppress("MaxLineLength")
private fun updateSecureNotesType(
private fun updateCommonContent(
currentState: VaultAddItemState,
transform: VaultAddItemState.ViewState.Content.SecureNotes.() -> VaultAddItemState.ViewState.Content.SecureNotes,
transform: VaultAddItemState.ViewState.Content.Common.()
-> VaultAddItemState.ViewState.Content.Common,
): VaultAddItemState {
val updatedType = when (val viewState = currentState.viewState) {
is VaultAddItemState.ViewState.Content.SecureNotes -> viewState.transform()
is VaultAddItemState.ViewState.Content ->
viewState.copy(common = viewState.common.transform())
else -> viewState
}
return currentState.copy(viewState = updatedType)
@ -1235,42 +921,35 @@ class VaultAddItemScreenTest : BaseComposeTest() {
//endregion Helper functions
companion object {
private val DEFAULT_STATE_LOGIN_CUSTOM_FIELDS = VaultAddItemState(
viewState = VaultAddItemState.ViewState.Content.Login(
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField("Test ID", "TestBoolean", false),
VaultAddItemState.Custom.TextField("Test ID", "TestText", "TestTextVal"),
VaultAddItemState.Custom.HiddenField("Test ID", "TestHidden", "TestHiddenVal"),
VaultAddItemState.Custom.LinkedField(
"LinkedID",
"TestLinked",
VaultLinkedFieldType.USERNAME,
),
),
),
dialog = null,
vaultAddEditType = VaultAddEditType.AddItem,
)
private val DEFAULT_STATE_LOGIN_DIALOG = VaultAddItemState(
viewState = VaultAddItemState.ViewState.Content.Login(),
viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(),
type = VaultAddItemState.ViewState.Content.ItemType.Login(),
),
dialog = VaultAddItemState.DialogState.Error("test".asText()),
vaultAddEditType = VaultAddEditType.AddItem,
)
private val DEFAULT_STATE_LOGIN = VaultAddItemState(
vaultAddEditType = VaultAddEditType.AddItem,
viewState = VaultAddItemState.ViewState.Content.Login(),
viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(),
type = VaultAddItemState.ViewState.Content.ItemType.Login(),
),
dialog = null,
)
@Suppress("MaxLineLength")
private val DEFAULT_STATE_SECURE_NOTES_CUSTOM_FIELDS = VaultAddItemState(
viewState = VaultAddItemState.ViewState.Content.SecureNotes(
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField("Test ID", "TestBoolean", false),
VaultAddItemState.Custom.TextField("Test ID", "TestText", "TestTextVal"),
VaultAddItemState.Custom.HiddenField("Test ID", "TestHidden", "TestHiddenVal"),
viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField("Test ID", "TestBoolean", false),
VaultAddItemState.Custom.TextField("Test ID", "TestText", "TestTextVal"),
VaultAddItemState.Custom.HiddenField("Test ID", "TestHidden", "TestHiddenVal"),
),
),
type = VaultAddItemState.ViewState.Content.ItemType.SecureNotes,
),
dialog = null,
vaultAddEditType = VaultAddEditType.AddItem,
@ -1278,7 +957,10 @@ class VaultAddItemScreenTest : BaseComposeTest() {
private val DEFAULT_STATE_SECURE_NOTES = VaultAddItemState(
vaultAddEditType = VaultAddEditType.AddItem,
viewState = VaultAddItemState.ViewState.Content.SecureNotes(),
viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(),
type = VaultAddItemState.ViewState.Content.ItemType.SecureNotes,
),
dialog = null,
)
}

View file

@ -46,7 +46,30 @@ class CipherViewExtensionsTest {
val result = cipherView.toViewState()
assertEquals(
VaultAddItemState.ViewState.Error(message = "Not yet implemented.".asText()),
VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(
originalCipher = cipherView,
name = "cipher",
folderName = R.string.folder_none.asText(),
favorite = false,
masterPasswordReprompt = true,
notes = "Lots of notes",
ownership = "",
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField(TEST_ID, "TestBoolean", false),
VaultAddItemState.Custom.TextField(TEST_ID, "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField(TEST_ID, "TestHidden", "TestHidden"),
VaultAddItemState.Custom.LinkedField(
TEST_ID,
"TestLinked",
VaultLinkedFieldType.USERNAME,
),
),
availableFolders = emptyList(),
availableOwners = emptyList(),
),
type = VaultAddItemState.ViewState.Content.ItemType.Card,
),
result,
)
}
@ -58,7 +81,30 @@ class CipherViewExtensionsTest {
val result = cipherView.toViewState()
assertEquals(
VaultAddItemState.ViewState.Error(message = "Not yet implemented.".asText()),
VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(
originalCipher = cipherView,
name = "cipher",
folderName = R.string.folder_none.asText(),
favorite = false,
masterPasswordReprompt = true,
notes = "Lots of notes",
ownership = "",
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField(TEST_ID, "TestBoolean", false),
VaultAddItemState.Custom.TextField(TEST_ID, "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField(TEST_ID, "TestHidden", "TestHidden"),
VaultAddItemState.Custom.LinkedField(
TEST_ID,
"TestLinked",
VaultLinkedFieldType.USERNAME,
),
),
availableFolders = emptyList(),
availableOwners = emptyList(),
),
type = VaultAddItemState.ViewState.Content.ItemType.Identity,
),
result,
)
}
@ -70,29 +116,33 @@ class CipherViewExtensionsTest {
val result = cipherView.toViewState()
assertEquals(
VaultAddItemState.ViewState.Content.Login(
originalCipher = cipherView,
name = "cipher",
username = "username",
password = "password",
uri = "www.example.com",
folderName = R.string.folder_none.asText(),
favorite = false,
masterPasswordReprompt = true,
notes = "Lots of notes",
ownership = "",
availableFolders = emptyList(),
availableOwners = emptyList(),
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField(TEST_ID, "TestBoolean", false),
VaultAddItemState.Custom.TextField(TEST_ID, "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField(TEST_ID, "TestHidden", "TestHidden"),
VaultAddItemState.Custom.LinkedField(
TEST_ID,
"TestLinked",
VaultLinkedFieldType.USERNAME,
VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(
originalCipher = cipherView,
name = "cipher",
folderName = R.string.folder_none.asText(),
favorite = false,
masterPasswordReprompt = true,
notes = "Lots of notes",
ownership = "",
availableFolders = emptyList(),
availableOwners = emptyList(),
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField(TEST_ID, "TestBoolean", false),
VaultAddItemState.Custom.TextField(TEST_ID, "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField(TEST_ID, "TestHidden", "TestHidden"),
VaultAddItemState.Custom.LinkedField(
TEST_ID,
"TestLinked",
VaultLinkedFieldType.USERNAME,
),
),
),
type = VaultAddItemState.ViewState.Content.ItemType.Login(
username = "username",
password = "password",
uri = "www.example.com",
),
),
result,
)
@ -105,21 +155,24 @@ class CipherViewExtensionsTest {
val result = cipherView.toViewState()
assertEquals(
VaultAddItemState.ViewState.Content.SecureNotes(
originalCipher = cipherView,
name = "cipher",
folderName = R.string.folder_none.asText(),
favorite = false,
masterPasswordReprompt = true,
notes = "Lots of notes",
ownership = "",
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField(TEST_ID, "TestBoolean", false),
VaultAddItemState.Custom.TextField(TEST_ID, "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField(TEST_ID, "TestHidden", "TestHidden"),
VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(
originalCipher = cipherView,
name = "cipher",
folderName = R.string.folder_none.asText(),
favorite = false,
masterPasswordReprompt = true,
notes = "Lots of notes",
ownership = "",
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField(TEST_ID, "TestBoolean", false),
VaultAddItemState.Custom.TextField(TEST_ID, "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField(TEST_ID, "TestHidden", "TestHidden"),
),
availableFolders = emptyList(),
availableOwners = emptyList(),
),
availableFolders = emptyList(),
availableOwners = emptyList(),
type = VaultAddItemState.ViewState.Content.ItemType.SecureNotes,
),
result,
)

View file

@ -131,16 +131,20 @@ class VaultDataExtensionsTest {
fun `toCipherView should transform Login ItemType to CipherView`() {
mockkStatic(Instant::class)
every { Instant.now() } returns Instant.MIN
val loginItemType = VaultAddItemState.ViewState.Content.Login(
name = "mockName-1",
username = "mockUsername-1",
password = "mockPassword-1",
uri = "mockUri-1",
folderName = "mockFolder-1".asText(),
favorite = false,
masterPasswordReprompt = false,
notes = "mockNotes-1",
ownership = "mockOwnership-1",
val loginItemType = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(
name = "mockName-1",
folderName = "mockFolder-1".asText(),
favorite = false,
masterPasswordReprompt = false,
notes = "mockNotes-1",
ownership = "mockOwnership-1",
),
type = VaultAddItemState.ViewState.Content.ItemType.Login(
username = "mockUsername-1",
password = "mockPassword-1",
uri = "mockUri-1",
),
)
val result = loginItemType.toCipherView()
@ -191,30 +195,34 @@ class VaultDataExtensionsTest {
@Test
fun `toCipherView should transform Login ItemType to CipherView with original cipher`() {
val cipherView = DEFAULT_LOGIN_CIPHER_VIEW
val loginItemType = VaultAddItemState.ViewState.Content.Login(
originalCipher = cipherView,
name = "mockName-1",
username = "mockUsername-1",
password = "mockPassword-1",
uri = "mockUri-1",
folderName = "mockFolder-1".asText(),
favorite = true,
masterPasswordReprompt = false,
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField("testId", "TestBoolean", false),
VaultAddItemState.Custom.TextField("testId", "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField("testId", "TestHidden", "TestHidden"),
VaultAddItemState.Custom.LinkedField(
"testId",
"TestLinked",
VaultLinkedFieldType.USERNAME,
val viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(
originalCipher = cipherView,
name = "mockName-1",
folderName = "mockFolder-1".asText(),
favorite = true,
masterPasswordReprompt = false,
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField("testId", "TestBoolean", false),
VaultAddItemState.Custom.TextField("testId", "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField("testId", "TestHidden", "TestHidden"),
VaultAddItemState.Custom.LinkedField(
"testId",
"TestLinked",
VaultLinkedFieldType.USERNAME,
),
),
notes = "mockNotes-1",
ownership = "mockOwnership-1",
),
type = VaultAddItemState.ViewState.Content.ItemType.Login(
username = "mockUsername-1",
password = "mockPassword-1",
uri = "mockUri-1",
),
notes = "mockNotes-1",
ownership = "mockOwnership-1",
)
val result = loginItemType.toCipherView()
val result = viewState.toCipherView()
assertEquals(
@Suppress("MaxLineLength")
@ -278,21 +286,24 @@ class VaultDataExtensionsTest {
fun `toCipherView should transform SecureNotes ItemType to CipherView`() {
mockkStatic(Instant::class)
every { Instant.now() } returns Instant.MIN
val secureNotesItemType = VaultAddItemState.ViewState.Content.SecureNotes(
name = "mockName-1",
folderName = "mockFolder-1".asText(),
favorite = false,
masterPasswordReprompt = false,
notes = "mockNotes-1",
ownership = "mockOwnership-1",
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField("testId", "TestBoolean", false),
VaultAddItemState.Custom.TextField("testId", "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField("testId", "TestHidden", "TestHidden"),
val viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(
name = "mockName-1",
folderName = "mockFolder-1".asText(),
favorite = false,
masterPasswordReprompt = false,
notes = "mockNotes-1",
ownership = "mockOwnership-1",
customFieldData = listOf(
VaultAddItemState.Custom.BooleanField("testId", "TestBoolean", false),
VaultAddItemState.Custom.TextField("testId", "TestText", "TestText"),
VaultAddItemState.Custom.HiddenField("testId", "TestHidden", "TestHidden"),
),
),
type = VaultAddItemState.ViewState.Content.ItemType.SecureNotes,
)
val result = secureNotesItemType.toCipherView()
val result = viewState.toCipherView()
assertEquals(
CipherView(
@ -347,18 +358,21 @@ class VaultDataExtensionsTest {
@Test
fun `toCipherView should transform SecureNotes ItemType to CipherView with original cipher`() {
val cipherView = DEFAULT_SECURE_NOTES_CIPHER_VIEW
val secureNotesItemType = VaultAddItemState.ViewState.Content.SecureNotes(
originalCipher = cipherView,
name = "mockName-1",
folderName = "mockFolder-1".asText(),
favorite = false,
masterPasswordReprompt = true,
notes = "mockNotes-1",
ownership = "mockOwnership-1",
customFieldData = emptyList(),
val viewState = VaultAddItemState.ViewState.Content(
common = VaultAddItemState.ViewState.Content.Common(
originalCipher = cipherView,
name = "mockName-1",
folderName = "mockFolder-1".asText(),
favorite = false,
masterPasswordReprompt = true,
notes = "mockNotes-1",
ownership = "mockOwnership-1",
customFieldData = emptyList(),
),
type = VaultAddItemState.ViewState.Content.ItemType.SecureNotes,
)
val result = secureNotesItemType.toCipherView()
val result = viewState.toCipherView()
assertEquals(
cipherView.copy(