mirror of
https://github.com/bitwarden/android.git
synced 2026-08-25 17:09:55 -05:00
[PM-32810] feat: Add Bank Account item detail view (#6875)
This commit is contained in:
+439
@@ -0,0 +1,439 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.item
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.bitwarden.ui.platform.base.util.standardHorizontalMargin
|
||||
import com.bitwarden.ui.platform.base.util.toListItemCardStyle
|
||||
import com.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
|
||||
import com.bitwarden.ui.platform.components.field.BitwardenPasswordField
|
||||
import com.bitwarden.ui.platform.components.field.BitwardenTextField
|
||||
import com.bitwarden.ui.platform.components.header.BitwardenListHeaderText
|
||||
import com.bitwarden.ui.platform.components.icon.model.IconData
|
||||
import com.bitwarden.ui.platform.resource.BitwardenDrawable
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.component.itemHeader
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.component.vaultItemAttachments
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.component.vaultItemCustomFields
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.component.vaultItemHistory
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.component.vaultItemNotes
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultBankAccountItemTypeHandlers
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultCommonItemTypeHandlers
|
||||
import com.x8bit.bitwarden.ui.vault.util.longName
|
||||
|
||||
/**
|
||||
* Renders the [VaultItemScreen] content when viewing a bank account cipher.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun VaultItemBankAccountContent(
|
||||
commonState: VaultItemState.ViewState.Content.Common,
|
||||
bankAccountState: VaultItemState.ViewState.Content.ItemType.BankAccount,
|
||||
vaultCommonItemTypeHandlers: VaultCommonItemTypeHandlers,
|
||||
vaultBankAccountItemTypeHandlers: VaultBankAccountItemTypeHandlers,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var isExpanded by rememberSaveable { mutableStateOf(value = false) }
|
||||
LazyColumn(modifier = modifier.fillMaxWidth()) {
|
||||
item {
|
||||
Spacer(Modifier.height(height = 12.dp))
|
||||
}
|
||||
itemHeader(
|
||||
value = commonState.name,
|
||||
isFavorite = commonState.favorite,
|
||||
isArchived = commonState.archived,
|
||||
iconData = commonState.iconData,
|
||||
relatedLocations = commonState.relatedLocations,
|
||||
iconTestTag = "BankAccountItemNameIcon",
|
||||
textFieldTestTag = "BankAccountItemNameEntry",
|
||||
isExpanded = isExpanded,
|
||||
onExpandClick = { isExpanded = !isExpanded },
|
||||
applyIconBackground = commonState.iconData is IconData.Local,
|
||||
)
|
||||
item(key = "bankAccountDetailsHeader") {
|
||||
Spacer(modifier = Modifier.height(height = 16.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = BitwardenString.details),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.padding(horizontal = 16.dp)
|
||||
.animateItem(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(height = 8.dp))
|
||||
}
|
||||
|
||||
bankAccountState.bankName?.let { bankName ->
|
||||
item(key = "bankName") {
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = BitwardenString.bank_name),
|
||||
value = bankName,
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
textFieldTestTag = "BankAccountItemBankNameEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = bankName),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bankAccountState.nameOnAccount?.let { nameOnAccount ->
|
||||
item(key = "nameOnAccount") {
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = BitwardenString.name_on_account),
|
||||
value = nameOnAccount,
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
actions = {
|
||||
BitwardenStandardIconButton(
|
||||
vectorIconRes = BitwardenDrawable.ic_copy,
|
||||
contentDescription = stringResource(
|
||||
id = BitwardenString.copy_name_on_account,
|
||||
),
|
||||
onClick = vaultBankAccountItemTypeHandlers.onCopyNameOnAccountClick,
|
||||
modifier = Modifier.testTag(
|
||||
tag = "BankAccountCopyNameOnAccountButton",
|
||||
),
|
||||
)
|
||||
},
|
||||
textFieldTestTag = "BankAccountItemNameOnAccountEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = nameOnAccount),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bankAccountState.accountType?.let { accountType ->
|
||||
item(key = "accountType") {
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = BitwardenString.account_type),
|
||||
value = accountType.longName(),
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
textFieldTestTag = "BankAccountItemAccountTypeEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = accountType),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bankAccountState.accountNumber?.let { accountNumber ->
|
||||
item(key = "accountNumber") {
|
||||
var showAccountNumber by rememberSaveable { mutableStateOf(value = false) }
|
||||
BitwardenPasswordField(
|
||||
label = stringResource(id = BitwardenString.account_number),
|
||||
value = accountNumber,
|
||||
onValueChange = {},
|
||||
showPassword = showAccountNumber,
|
||||
showPasswordChange = { showAccountNumber = it },
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
actions = {
|
||||
BitwardenStandardIconButton(
|
||||
vectorIconRes = BitwardenDrawable.ic_copy,
|
||||
contentDescription = stringResource(
|
||||
id = BitwardenString.copy_account_number,
|
||||
),
|
||||
onClick = vaultBankAccountItemTypeHandlers.onCopyAccountNumberClick,
|
||||
modifier = Modifier.testTag(
|
||||
tag = "BankAccountCopyAccountNumberButton",
|
||||
),
|
||||
)
|
||||
},
|
||||
showPasswordTestTag = "ShowAccountNumberButton",
|
||||
passwordFieldTestTag = "BankAccountItemAccountNumberEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = accountNumber),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bankAccountState.routingNumber?.let { routingNumber ->
|
||||
item(key = "routingNumber") {
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = BitwardenString.routing_number),
|
||||
value = routingNumber,
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
actions = {
|
||||
BitwardenStandardIconButton(
|
||||
vectorIconRes = BitwardenDrawable.ic_copy,
|
||||
contentDescription = stringResource(
|
||||
id = BitwardenString.copy_routing_number,
|
||||
),
|
||||
onClick = vaultBankAccountItemTypeHandlers.onCopyRoutingNumberClick,
|
||||
modifier = Modifier.testTag(
|
||||
tag = "BankAccountCopyRoutingNumberButton",
|
||||
),
|
||||
)
|
||||
},
|
||||
textFieldTestTag = "BankAccountItemRoutingNumberEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = routingNumber),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bankAccountState.branchNumber?.let { branchNumber ->
|
||||
item(key = "branchNumber") {
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = BitwardenString.branch_number),
|
||||
value = branchNumber,
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
actions = {
|
||||
BitwardenStandardIconButton(
|
||||
vectorIconRes = BitwardenDrawable.ic_copy,
|
||||
contentDescription = stringResource(
|
||||
id = BitwardenString.copy_branch_number,
|
||||
),
|
||||
onClick = vaultBankAccountItemTypeHandlers.onCopyBranchNumberClick,
|
||||
modifier = Modifier.testTag(
|
||||
tag = "BankAccountCopyBranchNumberButton",
|
||||
),
|
||||
)
|
||||
},
|
||||
textFieldTestTag = "BankAccountItemBranchNumberEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = branchNumber),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bankAccountState.pin?.let { pin ->
|
||||
item(key = "pin") {
|
||||
var showPin by rememberSaveable { mutableStateOf(value = false) }
|
||||
BitwardenPasswordField(
|
||||
label = stringResource(id = BitwardenString.pin),
|
||||
value = pin,
|
||||
onValueChange = {},
|
||||
showPassword = showPin,
|
||||
showPasswordChange = { showPin = it },
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
actions = {
|
||||
BitwardenStandardIconButton(
|
||||
vectorIconRes = BitwardenDrawable.ic_copy,
|
||||
contentDescription = stringResource(
|
||||
id = BitwardenString.copy_pin,
|
||||
),
|
||||
onClick = vaultBankAccountItemTypeHandlers.onCopyPinClick,
|
||||
modifier = Modifier.testTag(tag = "BankAccountCopyPinButton"),
|
||||
)
|
||||
},
|
||||
showPasswordTestTag = "ShowPinButton",
|
||||
passwordFieldTestTag = "BankAccountItemPinEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = pin),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bankAccountState.swiftCode?.let { swiftCode ->
|
||||
item(key = "swiftCode") {
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = BitwardenString.swift_code),
|
||||
value = swiftCode,
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
actions = {
|
||||
BitwardenStandardIconButton(
|
||||
vectorIconRes = BitwardenDrawable.ic_copy,
|
||||
contentDescription = stringResource(
|
||||
id = BitwardenString.copy_swift_code,
|
||||
),
|
||||
onClick = vaultBankAccountItemTypeHandlers.onCopySwiftCodeClick,
|
||||
modifier = Modifier.testTag(
|
||||
tag = "BankAccountCopySwiftCodeButton",
|
||||
),
|
||||
)
|
||||
},
|
||||
textFieldTestTag = "BankAccountItemSwiftCodeEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = swiftCode),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bankAccountState.iban?.let { iban ->
|
||||
item(key = "iban") {
|
||||
var showIban by rememberSaveable { mutableStateOf(value = false) }
|
||||
BitwardenPasswordField(
|
||||
label = stringResource(id = BitwardenString.iban),
|
||||
value = iban,
|
||||
onValueChange = {},
|
||||
showPassword = showIban,
|
||||
showPasswordChange = { showIban = it },
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
actions = {
|
||||
BitwardenStandardIconButton(
|
||||
vectorIconRes = BitwardenDrawable.ic_copy,
|
||||
contentDescription = stringResource(
|
||||
id = BitwardenString.copy_iban,
|
||||
),
|
||||
onClick = vaultBankAccountItemTypeHandlers.onCopyIbanClick,
|
||||
modifier = Modifier.testTag(tag = "BankAccountCopyIbanButton"),
|
||||
)
|
||||
},
|
||||
showPasswordTestTag = "ShowIbanButton",
|
||||
passwordFieldTestTag = "BankAccountItemIbanEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = iban),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bankAccountState.bankContactPhone?.let { phone ->
|
||||
item(key = "bankContactPhone") {
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = BitwardenString.bank_contact_phone),
|
||||
value = phone,
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
actions = {
|
||||
BitwardenStandardIconButton(
|
||||
vectorIconRes = BitwardenDrawable.ic_copy,
|
||||
contentDescription = stringResource(
|
||||
id = BitwardenString.copy_bank_contact_phone,
|
||||
),
|
||||
onClick =
|
||||
vaultBankAccountItemTypeHandlers.onCopyBankContactPhoneClick,
|
||||
modifier = Modifier.testTag(
|
||||
tag = "BankAccountCopyBankContactPhoneButton",
|
||||
),
|
||||
)
|
||||
},
|
||||
textFieldTestTag = "BankAccountItemBankContactPhoneEntry",
|
||||
cardStyle = bankAccountState
|
||||
.propertyList
|
||||
.toListItemCardStyle(
|
||||
index = bankAccountState.propertyList.indexOf(element = phone),
|
||||
dividerPadding = 0.dp,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
vaultItemNotes(
|
||||
notes = commonState.notes,
|
||||
vaultCommonItemTypeHandlers = vaultCommonItemTypeHandlers,
|
||||
)
|
||||
|
||||
vaultItemCustomFields(
|
||||
customFields = commonState.customFields,
|
||||
vaultCommonItemTypeHandlers = vaultCommonItemTypeHandlers,
|
||||
)
|
||||
|
||||
vaultItemAttachments(
|
||||
attachments = commonState.attachments,
|
||||
vaultCommonItemTypeHandlers = vaultCommonItemTypeHandlers,
|
||||
)
|
||||
|
||||
vaultItemHistory(
|
||||
commonState = commonState,
|
||||
vaultCommonItemTypeHandlers = vaultCommonItemTypeHandlers,
|
||||
loginPasswordRevisionDate = null,
|
||||
)
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(88.dp))
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.x8bit.bitwarden.ui.vault.feature.addedit.VaultAddEditArgs
|
||||
import com.x8bit.bitwarden.ui.vault.feature.attachments.preview.PreviewAttachmentRoute
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultBankAccountItemTypeHandlers
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultCardItemTypeHandlers
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultCommonItemTypeHandlers
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultIdentityItemTypeHandlers
|
||||
@@ -284,6 +285,9 @@ fun VaultItemScreen(
|
||||
vaultIdentityItemTypeHandlers = remember(viewModel) {
|
||||
VaultIdentityItemTypeHandlers.create(viewModel = viewModel)
|
||||
},
|
||||
vaultBankAccountItemTypeHandlers = remember(viewModel) {
|
||||
VaultBankAccountItemTypeHandlers.create(viewModel = viewModel)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -368,6 +372,7 @@ private fun VaultItemContent(
|
||||
vaultCardItemTypeHandlers: VaultCardItemTypeHandlers,
|
||||
vaultSshKeyItemTypeHandlers: VaultSshKeyItemTypeHandlers,
|
||||
vaultIdentityItemTypeHandlers: VaultIdentityItemTypeHandlers,
|
||||
vaultBankAccountItemTypeHandlers: VaultBankAccountItemTypeHandlers,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when (viewState) {
|
||||
@@ -430,13 +435,23 @@ private fun VaultItemContent(
|
||||
)
|
||||
}
|
||||
|
||||
is VaultItemState.ViewState.Content.ItemType.BankAccount,
|
||||
is VaultItemState.ViewState.Content.ItemType.BankAccount -> {
|
||||
VaultItemBankAccountContent(
|
||||
commonState = viewState.common,
|
||||
bankAccountState = viewState.type,
|
||||
vaultCommonItemTypeHandlers = vaultCommonItemTypeHandlers,
|
||||
vaultBankAccountItemTypeHandlers = vaultBankAccountItemTypeHandlers,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
is VaultItemState.ViewState.Content.ItemType.DriversLicense,
|
||||
is VaultItemState.ViewState.Content.ItemType.Passport,
|
||||
-> {
|
||||
// TODO(PM-32810): Render dedicated content for new item types once the UI
|
||||
// ships in the phase-05-07 PR. Until then these are gated behind the
|
||||
// pm-32009-new-item-types feature flag and cannot be received.
|
||||
// TODO(PM-32810): Render dedicated content for the remaining new item types
|
||||
// once the UI ships in their respective Story slices. Until then these
|
||||
// branches are gated behind the pm-32009-new-item-types feature flag and
|
||||
// cannot be received.
|
||||
VaultItemSecureNoteContent(
|
||||
commonState = viewState.common,
|
||||
vaultCommonItemTypeHandlers = vaultCommonItemTypeHandlers,
|
||||
|
||||
+216
-3
@@ -46,6 +46,7 @@ import com.x8bit.bitwarden.ui.vault.feature.item.model.VaultItemStateData
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.util.toViewState
|
||||
import com.x8bit.bitwarden.ui.vault.feature.util.canAssignToCollections
|
||||
import com.x8bit.bitwarden.ui.vault.feature.util.hasDeletePermissionInAtLeastOneCollection
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultBankAccountType
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultCardBrand
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType
|
||||
@@ -238,6 +239,7 @@ class VaultItemViewModel @Inject constructor(
|
||||
is VaultItemAction.ItemType.Card -> handleCardTypeActions(action)
|
||||
is VaultItemAction.ItemType.SshKey -> handleSshKeyTypeActions(action)
|
||||
is VaultItemAction.ItemType.Identity -> handleIdentityTypeActions(action)
|
||||
is VaultItemAction.ItemType.BankAccount -> handleBankAccountTypeActions(action)
|
||||
is VaultItemAction.Common -> handleCommonActions(action)
|
||||
is VaultItemAction.Internal -> handleInternalAction(action)
|
||||
}
|
||||
@@ -1041,6 +1043,134 @@ class VaultItemViewModel @Inject constructor(
|
||||
|
||||
//endregion Identity Type Handlers
|
||||
|
||||
//region Bank Account Type Handlers
|
||||
|
||||
private fun handleBankAccountTypeActions(action: VaultItemAction.ItemType.BankAccount) {
|
||||
when (action) {
|
||||
VaultItemAction.ItemType.BankAccount.CopyNameOnAccountClick -> {
|
||||
handleCopyBankNameOnAccountClick()
|
||||
}
|
||||
|
||||
VaultItemAction.ItemType.BankAccount.CopyAccountNumberClick -> {
|
||||
handleCopyBankAccountNumberClick()
|
||||
}
|
||||
|
||||
VaultItemAction.ItemType.BankAccount.CopyRoutingNumberClick -> {
|
||||
handleCopyBankRoutingNumberClick()
|
||||
}
|
||||
|
||||
VaultItemAction.ItemType.BankAccount.CopyBranchNumberClick -> {
|
||||
handleCopyBankBranchNumberClick()
|
||||
}
|
||||
|
||||
VaultItemAction.ItemType.BankAccount.CopyPinClick -> {
|
||||
handleCopyBankPinClick()
|
||||
}
|
||||
|
||||
VaultItemAction.ItemType.BankAccount.CopySwiftCodeClick -> {
|
||||
handleCopyBankSwiftCodeClick()
|
||||
}
|
||||
|
||||
VaultItemAction.ItemType.BankAccount.CopyIbanClick -> {
|
||||
handleCopyBankIbanClick()
|
||||
}
|
||||
|
||||
VaultItemAction.ItemType.BankAccount.CopyBankContactPhoneClick -> {
|
||||
handleCopyBankContactPhoneClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyBankNameOnAccountClick() {
|
||||
onBankAccountContent { _, bankAccount ->
|
||||
bankAccount.nameOnAccount?.let { nameOnAccount ->
|
||||
clipboardManager.setText(
|
||||
text = nameOnAccount,
|
||||
toastDescriptorOverride = BitwardenString.name_on_account.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyBankAccountNumberClick() {
|
||||
onBankAccountContent { _, bankAccount ->
|
||||
bankAccount.accountNumber?.let { accountNumber ->
|
||||
clipboardManager.setText(
|
||||
text = accountNumber,
|
||||
toastDescriptorOverride = BitwardenString.account_number.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyBankRoutingNumberClick() {
|
||||
onBankAccountContent { _, bankAccount ->
|
||||
bankAccount.routingNumber?.let { routingNumber ->
|
||||
clipboardManager.setText(
|
||||
text = routingNumber,
|
||||
toastDescriptorOverride = BitwardenString.routing_number.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyBankBranchNumberClick() {
|
||||
onBankAccountContent { _, bankAccount ->
|
||||
bankAccount.branchNumber?.let { branchNumber ->
|
||||
clipboardManager.setText(
|
||||
text = branchNumber,
|
||||
toastDescriptorOverride = BitwardenString.branch_number.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyBankPinClick() {
|
||||
onBankAccountContent { _, bankAccount ->
|
||||
bankAccount.pin?.let { pin ->
|
||||
clipboardManager.setText(
|
||||
text = pin,
|
||||
toastDescriptorOverride = BitwardenString.pin.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyBankSwiftCodeClick() {
|
||||
onBankAccountContent { _, bankAccount ->
|
||||
bankAccount.swiftCode?.let { swiftCode ->
|
||||
clipboardManager.setText(
|
||||
text = swiftCode,
|
||||
toastDescriptorOverride = BitwardenString.swift_code.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyBankIbanClick() {
|
||||
onBankAccountContent { _, bankAccount ->
|
||||
bankAccount.iban?.let { iban ->
|
||||
clipboardManager.setText(
|
||||
text = iban,
|
||||
toastDescriptorOverride = BitwardenString.iban.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyBankContactPhoneClick() {
|
||||
onBankAccountContent { _, bankAccount ->
|
||||
bankAccount.bankContactPhone?.let { bankContactPhone ->
|
||||
clipboardManager.setText(
|
||||
text = bankContactPhone,
|
||||
toastDescriptorOverride = BitwardenString.bank_contact_phone.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//endregion Bank Account Type Handlers
|
||||
|
||||
//region Internal Type Handlers
|
||||
|
||||
private fun handleInternalAction(action: VaultItemAction.Internal) {
|
||||
@@ -1423,6 +1553,21 @@ class VaultItemViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun onBankAccountContent(
|
||||
crossinline block: (
|
||||
VaultItemState.ViewState.Content,
|
||||
VaultItemState.ViewState.Content.ItemType.BankAccount,
|
||||
) -> Unit,
|
||||
) {
|
||||
state.viewState.asContentOrNull()
|
||||
?.let { content ->
|
||||
(content.type as? VaultItemState.ViewState.Content.ItemType.BankAccount)
|
||||
?.let { bankAccountContent ->
|
||||
block(content, bankAccountContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1472,7 +1617,11 @@ data class VaultItemState(
|
||||
* Whether the fab is visible.
|
||||
*/
|
||||
val isFabVisible: Boolean
|
||||
get() = viewState is ViewState.Content && !isCipherDeleted && isCipherEditable
|
||||
get() = viewState is ViewState.Content &&
|
||||
!isCipherDeleted &&
|
||||
isCipherEditable &&
|
||||
// TODO: [PM-32810] Re-enable once Bank Account add/edit is wired.
|
||||
viewState.asContentOrNull()?.type !is ViewState.Content.ItemType.BankAccount
|
||||
|
||||
/**
|
||||
* Whether the cipher is in a collection.
|
||||
@@ -1879,7 +2028,7 @@ data class VaultItemState(
|
||||
data class BankAccount(
|
||||
val bankName: String?,
|
||||
val nameOnAccount: String?,
|
||||
val accountType: String?,
|
||||
val accountType: VaultBankAccountType?,
|
||||
val accountNumber: String?,
|
||||
val routingNumber: String?,
|
||||
val branchNumber: String?,
|
||||
@@ -1887,7 +2036,25 @@ data class VaultItemState(
|
||||
val swiftCode: String?,
|
||||
val iban: String?,
|
||||
val bankContactPhone: String?,
|
||||
) : ItemType()
|
||||
) : ItemType() {
|
||||
|
||||
/**
|
||||
* An ordered list of Bank Account specific elements.
|
||||
*/
|
||||
val propertyList: ImmutableList<Any>
|
||||
get() = persistentListOfNotNull(
|
||||
bankName,
|
||||
nameOnAccount,
|
||||
accountType,
|
||||
accountNumber,
|
||||
routingNumber,
|
||||
branchNumber,
|
||||
pin,
|
||||
swiftCode,
|
||||
iban,
|
||||
bankContactPhone,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the `DriversLicense` item type.
|
||||
@@ -2385,6 +2552,52 @@ sealed class VaultItemAction {
|
||||
*/
|
||||
data object CopyAddressClick : Identity()
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents actions specific to the Bank Account type.
|
||||
*/
|
||||
sealed class BankAccount : ItemType() {
|
||||
|
||||
/**
|
||||
* The user has clicked the copy button for the name on account.
|
||||
*/
|
||||
data object CopyNameOnAccountClick : BankAccount()
|
||||
|
||||
/**
|
||||
* The user has clicked the copy button for the account number.
|
||||
*/
|
||||
data object CopyAccountNumberClick : BankAccount()
|
||||
|
||||
/**
|
||||
* The user has clicked the copy button for the routing number.
|
||||
*/
|
||||
data object CopyRoutingNumberClick : BankAccount()
|
||||
|
||||
/**
|
||||
* The user has clicked the copy button for the branch number.
|
||||
*/
|
||||
data object CopyBranchNumberClick : BankAccount()
|
||||
|
||||
/**
|
||||
* The user has clicked the copy button for the PIN.
|
||||
*/
|
||||
data object CopyPinClick : BankAccount()
|
||||
|
||||
/**
|
||||
* The user has clicked the copy button for the SWIFT code.
|
||||
*/
|
||||
data object CopySwiftCodeClick : BankAccount()
|
||||
|
||||
/**
|
||||
* The user has clicked the copy button for the IBAN.
|
||||
*/
|
||||
data object CopyIbanClick : BankAccount()
|
||||
|
||||
/**
|
||||
* The user has clicked the copy button for the bank contact phone.
|
||||
*/
|
||||
data object CopyBankContactPhoneClick : BankAccount()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.item.handlers
|
||||
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.VaultItemAction
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.VaultItemViewModel
|
||||
|
||||
/**
|
||||
* A collection of handler functions for managing actions within the context of viewing bank
|
||||
* account items in a vault.
|
||||
*/
|
||||
data class VaultBankAccountItemTypeHandlers(
|
||||
val onCopyNameOnAccountClick: () -> Unit,
|
||||
val onCopyAccountNumberClick: () -> Unit,
|
||||
val onCopyRoutingNumberClick: () -> Unit,
|
||||
val onCopyBranchNumberClick: () -> Unit,
|
||||
val onCopyPinClick: () -> Unit,
|
||||
val onCopySwiftCodeClick: () -> Unit,
|
||||
val onCopyIbanClick: () -> Unit,
|
||||
val onCopyBankContactPhoneClick: () -> Unit,
|
||||
) {
|
||||
@Suppress("UndocumentedPublicClass")
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Creates the [VaultBankAccountItemTypeHandlers] using the [viewModel] to send desired
|
||||
* actions.
|
||||
*/
|
||||
fun create(viewModel: VaultItemViewModel): VaultBankAccountItemTypeHandlers =
|
||||
VaultBankAccountItemTypeHandlers(
|
||||
onCopyNameOnAccountClick = {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyNameOnAccountClick,
|
||||
)
|
||||
},
|
||||
onCopyAccountNumberClick = {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyAccountNumberClick,
|
||||
)
|
||||
},
|
||||
onCopyRoutingNumberClick = {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyRoutingNumberClick,
|
||||
)
|
||||
},
|
||||
onCopyBranchNumberClick = {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBranchNumberClick,
|
||||
)
|
||||
},
|
||||
onCopyPinClick = {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyPinClick,
|
||||
)
|
||||
},
|
||||
onCopySwiftCodeClick = {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopySwiftCodeClick,
|
||||
)
|
||||
},
|
||||
onCopyIbanClick = {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyIbanClick,
|
||||
)
|
||||
},
|
||||
onCopyBankContactPhoneClick = {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBankContactPhoneClick,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -24,6 +24,7 @@ import com.x8bit.bitwarden.ui.vault.feature.item.VaultItemState
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.model.TotpCodeItemData
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.model.VaultItemLocation
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.toLoginIconData
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultBankAccountType
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultCardBrand
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType
|
||||
import com.x8bit.bitwarden.ui.vault.model.findVaultCardBrandWithNameOrNull
|
||||
@@ -218,7 +219,7 @@ fun CipherView.toViewState(
|
||||
VaultItemState.ViewState.Content.ItemType.BankAccount(
|
||||
bankName = bankAccount?.bankName,
|
||||
nameOnAccount = bankAccount?.nameOnAccount,
|
||||
accountType = bankAccount?.accountType,
|
||||
accountType = bankAccount?.accountType?.let(VaultBankAccountType::parse),
|
||||
accountNumber = bankAccount?.accountNumber,
|
||||
routingNumber = bankAccount?.routingNumber,
|
||||
branchNumber = bankAccount?.branchNumber,
|
||||
@@ -344,7 +345,7 @@ private val CipherType.iconRes: Int
|
||||
CipherType.IDENTITY -> BitwardenDrawable.ic_id_card
|
||||
CipherType.SSH_KEY -> BitwardenDrawable.ic_ssh_key
|
||||
CipherType.LOGIN -> BitwardenDrawable.ic_globe
|
||||
CipherType.BANK_ACCOUNT -> BitwardenDrawable.ic_note
|
||||
CipherType.BANK_ACCOUNT -> BitwardenDrawable.ic_payment_card
|
||||
CipherType.DRIVERS_LICENSE -> BitwardenDrawable.ic_note
|
||||
CipherType.PASSPORT -> BitwardenDrawable.ic_note
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.x8bit.bitwarden.ui.vault.util
|
||||
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.x8bit.bitwarden.ui.vault.feature.addedit.util.SELECT_TEXT
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultBankAccountType
|
||||
|
||||
/**
|
||||
* Helper that exposes the display name [Text] for a [VaultBankAccountType].
|
||||
*/
|
||||
val VaultBankAccountType.longName: Text
|
||||
get() = when (this) {
|
||||
VaultBankAccountType.SELECT -> SELECT_TEXT
|
||||
VaultBankAccountType.CHECKING -> BitwardenString.checking.asText()
|
||||
VaultBankAccountType.SAVINGS -> BitwardenString.savings.asText()
|
||||
VaultBankAccountType.CERTIFICATE_OF_DEPOSIT -> {
|
||||
BitwardenString.certificate_of_deposit.asText()
|
||||
}
|
||||
|
||||
VaultBankAccountType.LINE_OF_CREDIT -> BitwardenString.line_of_credit.asText()
|
||||
VaultBankAccountType.INVESTMENT_BROKERAGE -> {
|
||||
BitwardenString.investment_brokerage.asText()
|
||||
}
|
||||
|
||||
VaultBankAccountType.MONEY_MARKET -> BitwardenString.money_market.asText()
|
||||
VaultBankAccountType.OTHER -> BitwardenString.other.asText()
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import com.x8bit.bitwarden.ui.vault.feature.attachments.preview.PreviewAttachmen
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.model.TotpCodeItemData
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.model.VaultItemLocation
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultAddEditType
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultBankAccountType
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultCardBrand
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType
|
||||
@@ -3252,6 +3253,267 @@ class VaultItemScreenTest : BitwardenComposeTest() {
|
||||
}
|
||||
|
||||
//endregion ssh key
|
||||
|
||||
//region bank account
|
||||
|
||||
@Test
|
||||
fun `in bank account state, all fields should be displayed when populated`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
|
||||
composeTestRule.onNodeWithTextAfterScroll("the bank name").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTextAfterScroll("the name on account").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTextAfterScroll("Checking").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTextAfterScroll("Account number").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTextAfterScroll("the routing number").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTextAfterScroll("the branch number").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTextAfterScroll("PIN").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTextAfterScroll("the swift code").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTextAfterScroll("the iban").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTextAfterScroll("the bank contact phone").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, on copy account number click should send CopyAccountNumberClick`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule
|
||||
.onNodeWithContentDescriptionAfterScroll("Copy account number")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopyAccountNumberClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, on copy routing number click should send CopyRoutingNumberClick`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule
|
||||
.onNodeWithContentDescriptionAfterScroll("Copy routing number")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopyRoutingNumberClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, on copy swift code click should send CopySwiftCodeClick`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule
|
||||
.onNodeWithContentDescriptionAfterScroll("Copy SWIFT code")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopySwiftCodeClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, on copy iban click should send CopyIbanClick`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule
|
||||
.onNodeWithContentDescriptionAfterScroll("Copy IBAN")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopyIbanClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, bankName should be displayed according to state`() {
|
||||
val bankName = "the bank name"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(bankName).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(bankName = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(bankName)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, nameOnAccount should be displayed according to state`() {
|
||||
val nameOnAccount = "the name on account"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(nameOnAccount).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(nameOnAccount = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(nameOnAccount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, accountType should be displayed according to state`() {
|
||||
val accountTypeText = "Checking"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(accountTypeText).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(accountType = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(accountTypeText)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, accountNumber should be displayed according to state`() {
|
||||
val accountNumberLabel = "Account number"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(accountNumberLabel).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(accountNumber = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(accountNumberLabel)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, routingNumber should be displayed according to state`() {
|
||||
val routingNumber = "the routing number"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(routingNumber).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(routingNumber = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(routingNumber)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, branchNumber should be displayed according to state`() {
|
||||
val branchNumber = "the branch number"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(branchNumber).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(branchNumber = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(branchNumber)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, pin should be displayed according to state`() {
|
||||
val pinLabel = "PIN"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(pinLabel).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(pin = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(pinLabel)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, swiftCode should be displayed according to state`() {
|
||||
val swiftCode = "the swift code"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(swiftCode).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(swiftCode = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(swiftCode)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, iban should be displayed according to state`() {
|
||||
val iban = "the iban"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(iban).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(iban = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(iban)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, bankContactPhone should be displayed according to state`() {
|
||||
val bankContactPhone = "the bank contact phone"
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule.onNodeWithTextAfterScroll(bankContactPhone).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateBankAccountType(currentState) { copy(bankContactPhone = null) }
|
||||
}
|
||||
|
||||
composeTestRule.assertScrollableNodeDoesNotExist(bankContactPhone)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `in bank account state, on copy name on account click should send CopyNameOnAccountClick`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule
|
||||
.onNodeWithContentDescriptionAfterScroll("Copy name on account")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyNameOnAccountClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, on copy branch number click should send CopyBranchNumberClick`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule
|
||||
.onNodeWithContentDescriptionAfterScroll("Copy branch number")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBranchNumberClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, on copy pin click should send CopyPinClick`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule
|
||||
.onNodeWithContentDescriptionAfterScroll("Copy PIN")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopyPinClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `in bank account state, on copy bank contact phone click should send CopyBankContactPhoneClick`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
composeTestRule
|
||||
.onNodeWithContentDescriptionAfterScroll("Copy bank contact phone")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBankContactPhoneClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in bank account state, edit fab should not be displayed`() {
|
||||
mutableStateFlow.update { it.copy(viewState = DEFAULT_BANK_ACCOUNT_VIEW_STATE) }
|
||||
|
||||
composeTestRule.onNodeWithContentDescription("Edit item").assertDoesNotExist()
|
||||
}
|
||||
|
||||
//endregion bank account
|
||||
}
|
||||
|
||||
//region Helper functions
|
||||
@@ -3325,6 +3587,29 @@ private fun updateCardType(
|
||||
return currentState.copy(viewState = updatedType)
|
||||
}
|
||||
|
||||
private fun updateBankAccountType(
|
||||
currentState: VaultItemState,
|
||||
transform: VaultItemState.ViewState.Content.ItemType.BankAccount.() ->
|
||||
VaultItemState.ViewState.Content.ItemType.BankAccount,
|
||||
): VaultItemState {
|
||||
val updatedType = when (val viewState = currentState.viewState) {
|
||||
is VaultItemState.ViewState.Content -> {
|
||||
when (val type = viewState.type) {
|
||||
is VaultItemState.ViewState.Content.ItemType.BankAccount -> {
|
||||
viewState.copy(
|
||||
type = type.transform(),
|
||||
)
|
||||
}
|
||||
|
||||
else -> viewState
|
||||
}
|
||||
}
|
||||
|
||||
else -> viewState
|
||||
}
|
||||
return currentState.copy(viewState = updatedType)
|
||||
}
|
||||
|
||||
private fun updateCommonContent(
|
||||
currentState: VaultItemState,
|
||||
transform: VaultItemState.ViewState.Content.Common.()
|
||||
@@ -3468,6 +3753,20 @@ private val DEFAULT_SSH_KEY: VaultItemState.ViewState.Content.ItemType.SshKey =
|
||||
showPrivateKey = false,
|
||||
)
|
||||
|
||||
private val DEFAULT_BANK_ACCOUNT: VaultItemState.ViewState.Content.ItemType.BankAccount =
|
||||
VaultItemState.ViewState.Content.ItemType.BankAccount(
|
||||
bankName = "the bank name",
|
||||
nameOnAccount = "the name on account",
|
||||
accountType = VaultBankAccountType.CHECKING,
|
||||
accountNumber = "the account number",
|
||||
routingNumber = "the routing number",
|
||||
branchNumber = "the branch number",
|
||||
pin = "the pin",
|
||||
swiftCode = "the swift code",
|
||||
iban = "the iban",
|
||||
bankContactPhone = "the bank contact phone",
|
||||
)
|
||||
|
||||
private val EMPTY_COMMON: VaultItemState.ViewState.Content.Common =
|
||||
VaultItemState.ViewState.Content.Common(
|
||||
name = "cipher",
|
||||
@@ -3599,6 +3898,12 @@ private val DEFAULT_SSH_KEY_VIEW_STATE: VaultItemState.ViewState.Content =
|
||||
type = DEFAULT_SSH_KEY,
|
||||
)
|
||||
|
||||
private val DEFAULT_BANK_ACCOUNT_VIEW_STATE: VaultItemState.ViewState.Content =
|
||||
VaultItemState.ViewState.Content(
|
||||
common = DEFAULT_COMMON.copy(iconData = IconData.Local(BitwardenDrawable.ic_globe)),
|
||||
type = DEFAULT_BANK_ACCOUNT,
|
||||
)
|
||||
|
||||
private val EMPTY_VIEW_STATES = listOf(
|
||||
EMPTY_LOGIN_VIEW_STATE,
|
||||
EMPTY_IDENTITY_VIEW_STATE,
|
||||
|
||||
+337
@@ -54,6 +54,7 @@ import com.x8bit.bitwarden.ui.vault.feature.item.util.createCommonContent
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.util.createLoginContent
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.util.toViewState
|
||||
import com.x8bit.bitwarden.ui.vault.feature.verificationcode.util.createVerificationCodeItem
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultBankAccountType
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultCardBrand
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType
|
||||
@@ -2602,6 +2603,321 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class BankAccountActions {
|
||||
private lateinit var viewModel: VaultItemViewModel
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel = createViewModel(
|
||||
state = DEFAULT_STATE.copy(viewState = BANK_ACCOUNT_VIEW_STATE),
|
||||
)
|
||||
every {
|
||||
mockCipherView.toViewState(
|
||||
previousState = null,
|
||||
isPremiumUser = true,
|
||||
totpCodeItemData = null,
|
||||
canDelete = true,
|
||||
canRestore = false,
|
||||
canAssignToCollections = true,
|
||||
canEdit = true,
|
||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||
isIconLoadingDisabled = false,
|
||||
relatedLocations = persistentListOf(),
|
||||
hasOrganizations = true,
|
||||
)
|
||||
} returns BANK_ACCOUNT_VIEW_STATE
|
||||
mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView)
|
||||
mutableAuthCodeItemFlow.value = DataState.Loaded(data = null)
|
||||
mutableCollectionsStateFlow.value = DataState.Loaded(emptyList())
|
||||
mutableFoldersStateFlow.value = DataState.Loaded(emptyList())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyAccountNumberClick should copy account number to clipboard`() = runTest {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyAccountNumberClick,
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(
|
||||
text = "12345678",
|
||||
toastDescriptorOverride = BitwardenString.account_number.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyRoutingNumberClick should copy routing number to clipboard`() = runTest {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyRoutingNumberClick,
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(
|
||||
text = "021000021",
|
||||
toastDescriptorOverride = BitwardenString.routing_number.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopySwiftCodeClick should copy SWIFT code to clipboard`() = runTest {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopySwiftCodeClick)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(
|
||||
text = "BOFAUS3N",
|
||||
toastDescriptorOverride = BitwardenString.swift_code.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyIbanClick should copy IBAN to clipboard`() = runTest {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopyIbanClick)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(
|
||||
text = "GB29NWBK60161331926819",
|
||||
toastDescriptorOverride = BitwardenString.iban.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyNameOnAccountClick should copy name on account to clipboard`() = runTest {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyNameOnAccountClick,
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(
|
||||
text = "John Doe",
|
||||
toastDescriptorOverride = BitwardenString.name_on_account.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyBranchNumberClick should copy branch number to clipboard`() = runTest {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBranchNumberClick,
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(
|
||||
text = "001",
|
||||
toastDescriptorOverride = BitwardenString.branch_number.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyPinClick should copy pin to clipboard`() = runTest {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopyPinClick)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(
|
||||
text = "4242",
|
||||
toastDescriptorOverride = BitwardenString.pin.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyBankContactPhoneClick should copy bank contact phone to clipboard`() =
|
||||
runTest {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBankContactPhoneClick,
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(
|
||||
text = "555-0100",
|
||||
toastDescriptorOverride = BitwardenString.bank_contact_phone.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on CopyAccountNumberClick with null account number should not copy to clipboard`() =
|
||||
runTest {
|
||||
val emptyState = BANK_ACCOUNT_VIEW_STATE.copy(
|
||||
type = DEFAULT_BANK_ACCOUNT_TYPE.copy(accountNumber = null),
|
||||
)
|
||||
viewModel = createViewModelWithBankAccountState(emptyState)
|
||||
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyAccountNumberClick,
|
||||
)
|
||||
|
||||
verify(exactly = 0) {
|
||||
clipboardManager.setText(
|
||||
text = any<String>(),
|
||||
toastDescriptorOverride = any<Text>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on CopyRoutingNumberClick with null routing number should not copy to clipboard`() =
|
||||
runTest {
|
||||
val emptyState = BANK_ACCOUNT_VIEW_STATE.copy(
|
||||
type = DEFAULT_BANK_ACCOUNT_TYPE.copy(routingNumber = null),
|
||||
)
|
||||
viewModel = createViewModelWithBankAccountState(emptyState)
|
||||
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyRoutingNumberClick,
|
||||
)
|
||||
|
||||
verify(exactly = 0) {
|
||||
clipboardManager.setText(
|
||||
text = any<String>(),
|
||||
toastDescriptorOverride = any<Text>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopySwiftCodeClick with null swift code should not copy to clipboard`() = runTest {
|
||||
val emptyState = BANK_ACCOUNT_VIEW_STATE.copy(
|
||||
type = DEFAULT_BANK_ACCOUNT_TYPE.copy(swiftCode = null),
|
||||
)
|
||||
viewModel = createViewModelWithBankAccountState(emptyState)
|
||||
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopySwiftCodeClick)
|
||||
|
||||
verify(exactly = 0) {
|
||||
clipboardManager.setText(
|
||||
text = any<String>(),
|
||||
toastDescriptorOverride = any<Text>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyIbanClick with null iban should not copy to clipboard`() = runTest {
|
||||
val emptyState = BANK_ACCOUNT_VIEW_STATE.copy(
|
||||
type = DEFAULT_BANK_ACCOUNT_TYPE.copy(iban = null),
|
||||
)
|
||||
viewModel = createViewModelWithBankAccountState(emptyState)
|
||||
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopyIbanClick)
|
||||
|
||||
verify(exactly = 0) {
|
||||
clipboardManager.setText(
|
||||
text = any<String>(),
|
||||
toastDescriptorOverride = any<Text>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on CopyNameOnAccountClick with null name on account should not copy to clipboard`() =
|
||||
runTest {
|
||||
val emptyState = BANK_ACCOUNT_VIEW_STATE.copy(
|
||||
type = DEFAULT_BANK_ACCOUNT_TYPE.copy(nameOnAccount = null),
|
||||
)
|
||||
viewModel = createViewModelWithBankAccountState(emptyState)
|
||||
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyNameOnAccountClick,
|
||||
)
|
||||
|
||||
verify(exactly = 0) {
|
||||
clipboardManager.setText(
|
||||
text = any<String>(),
|
||||
toastDescriptorOverride = any<Text>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on CopyBranchNumberClick with null branch number should not copy to clipboard`() =
|
||||
runTest {
|
||||
val emptyState = BANK_ACCOUNT_VIEW_STATE.copy(
|
||||
type = DEFAULT_BANK_ACCOUNT_TYPE.copy(branchNumber = null),
|
||||
)
|
||||
viewModel = createViewModelWithBankAccountState(emptyState)
|
||||
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBranchNumberClick,
|
||||
)
|
||||
|
||||
verify(exactly = 0) {
|
||||
clipboardManager.setText(
|
||||
text = any<String>(),
|
||||
toastDescriptorOverride = any<Text>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyPinClick with null pin should not copy to clipboard`() = runTest {
|
||||
val emptyState = BANK_ACCOUNT_VIEW_STATE.copy(
|
||||
type = DEFAULT_BANK_ACCOUNT_TYPE.copy(pin = null),
|
||||
)
|
||||
viewModel = createViewModelWithBankAccountState(emptyState)
|
||||
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.BankAccount.CopyPinClick)
|
||||
|
||||
verify(exactly = 0) {
|
||||
clipboardManager.setText(
|
||||
text = any<String>(),
|
||||
toastDescriptorOverride = any<Text>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on CopyBankContactPhoneClick with null bank contact phone should not copy to clipboard`() =
|
||||
runTest {
|
||||
val emptyState = BANK_ACCOUNT_VIEW_STATE.copy(
|
||||
type = DEFAULT_BANK_ACCOUNT_TYPE.copy(bankContactPhone = null),
|
||||
)
|
||||
viewModel = createViewModelWithBankAccountState(emptyState)
|
||||
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBankContactPhoneClick,
|
||||
)
|
||||
|
||||
verify(exactly = 0) {
|
||||
clipboardManager.setText(
|
||||
text = any<String>(),
|
||||
toastDescriptorOverride = any<Text>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createViewModelWithBankAccountState(
|
||||
viewState: VaultItemState.ViewState.Content,
|
||||
): VaultItemViewModel {
|
||||
// Override toViewState to return the requested null-field state.
|
||||
every {
|
||||
mockCipherView.toViewState(
|
||||
previousState = any(),
|
||||
isPremiumUser = true,
|
||||
totpCodeItemData = null,
|
||||
canDelete = true,
|
||||
canRestore = false,
|
||||
canAssignToCollections = true,
|
||||
canEdit = true,
|
||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||
isIconLoadingDisabled = false,
|
||||
relatedLocations = persistentListOf(),
|
||||
hasOrganizations = true,
|
||||
)
|
||||
} returns viewState
|
||||
val newViewModel = createViewModel(
|
||||
state = DEFAULT_STATE.copy(viewState = viewState),
|
||||
)
|
||||
mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView)
|
||||
mutableAuthCodeItemFlow.value = DataState.Loaded(data = null)
|
||||
mutableCollectionsStateFlow.value = DataState.Loaded(emptyList())
|
||||
mutableFoldersStateFlow.value = DataState.Loaded(emptyList())
|
||||
return newViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class VaultItemFlow {
|
||||
@BeforeEach
|
||||
@@ -3220,5 +3536,26 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
||||
common = DEFAULT_COMMON,
|
||||
type = DEFAULT_IDENTITY_TYPE,
|
||||
)
|
||||
|
||||
private val DEFAULT_BANK_ACCOUNT_TYPE:
|
||||
VaultItemState.ViewState.Content.ItemType.BankAccount =
|
||||
VaultItemState.ViewState.Content.ItemType.BankAccount(
|
||||
bankName = "First National",
|
||||
nameOnAccount = "John Doe",
|
||||
accountType = VaultBankAccountType.CHECKING,
|
||||
accountNumber = "12345678",
|
||||
routingNumber = "021000021",
|
||||
branchNumber = "001",
|
||||
pin = "4242",
|
||||
swiftCode = "BOFAUS3N",
|
||||
iban = "GB29NWBK60161331926819",
|
||||
bankContactPhone = "555-0100",
|
||||
)
|
||||
|
||||
private val BANK_ACCOUNT_VIEW_STATE: VaultItemState.ViewState.Content =
|
||||
VaultItemState.ViewState.Content(
|
||||
common = DEFAULT_COMMON,
|
||||
type = DEFAULT_BANK_ACCOUNT_TYPE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.item.handlers
|
||||
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.VaultItemAction
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.VaultItemViewModel
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class VaultBankAccountItemTypeHandlersTest {
|
||||
|
||||
private val viewModel = mockk<VaultItemViewModel> {
|
||||
every { trySendAction(any()) } returns Unit
|
||||
}
|
||||
private val handlers = VaultBankAccountItemTypeHandlers.create(viewModel = viewModel)
|
||||
|
||||
@Test
|
||||
fun `onCopyNameOnAccountClick should send CopyNameOnAccountClick action`() {
|
||||
handlers.onCopyNameOnAccountClick()
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyNameOnAccountClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onCopyAccountNumberClick should send CopyAccountNumberClick action`() {
|
||||
handlers.onCopyAccountNumberClick()
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyAccountNumberClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onCopyRoutingNumberClick should send CopyRoutingNumberClick action`() {
|
||||
handlers.onCopyRoutingNumberClick()
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyRoutingNumberClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onCopyBranchNumberClick should send CopyBranchNumberClick action`() {
|
||||
handlers.onCopyBranchNumberClick()
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBranchNumberClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onCopyPinClick should send CopyPinClick action`() {
|
||||
handlers.onCopyPinClick()
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyPinClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onCopySwiftCodeClick should send CopySwiftCodeClick action`() {
|
||||
handlers.onCopySwiftCodeClick()
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopySwiftCodeClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onCopyIbanClick should send CopyIbanClick action`() {
|
||||
handlers.onCopyIbanClick()
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyIbanClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onCopyBankContactPhoneClick should send CopyBankContactPhoneClick action`() {
|
||||
handlers.onCopyBankContactPhoneClick()
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
VaultItemAction.ItemType.BankAccount.CopyBankContactPhoneClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -458,6 +458,7 @@ class CipherViewExtensionsTest {
|
||||
CipherType.CARD to BitwardenDrawable.ic_payment_card,
|
||||
CipherType.SECURE_NOTE to BitwardenDrawable.ic_note,
|
||||
CipherType.SSH_KEY to BitwardenDrawable.ic_ssh_key,
|
||||
CipherType.BANK_ACCOUNT to BitwardenDrawable.ic_payment_card,
|
||||
)
|
||||
.forEach {
|
||||
val cipherView = createCipherView(type = it.key, isEmpty = false)
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.x8bit.bitwarden.ui.vault.util
|
||||
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.x8bit.bitwarden.ui.vault.feature.addedit.util.SELECT_TEXT
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultBankAccountType
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class VaultBankAccountTypeExtensionsTest {
|
||||
|
||||
@Test
|
||||
fun `longName should return the correct value for each VaultBankAccountType`() {
|
||||
mapOf(
|
||||
VaultBankAccountType.SELECT to SELECT_TEXT,
|
||||
VaultBankAccountType.CHECKING to BitwardenString.checking.asText(),
|
||||
VaultBankAccountType.SAVINGS to BitwardenString.savings.asText(),
|
||||
VaultBankAccountType.CERTIFICATE_OF_DEPOSIT to
|
||||
BitwardenString.certificate_of_deposit.asText(),
|
||||
VaultBankAccountType.LINE_OF_CREDIT to BitwardenString.line_of_credit.asText(),
|
||||
VaultBankAccountType.INVESTMENT_BROKERAGE to
|
||||
BitwardenString.investment_brokerage.asText(),
|
||||
VaultBankAccountType.MONEY_MARKET to BitwardenString.money_market.asText(),
|
||||
VaultBankAccountType.OTHER to BitwardenString.other.asText(),
|
||||
)
|
||||
.forEach { (type, label) ->
|
||||
assertEquals(label, type.longName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1319,15 +1319,19 @@ Do you want to switch to this account?</string>
|
||||
<string name="name_on_account">Name on account</string>
|
||||
<string name="account_type">Account type</string>
|
||||
<string name="account_number">Account number</string>
|
||||
<string name="routing_number">Routing/transit number</string>
|
||||
<string name="branch_number">Branch/institution number</string>
|
||||
<string name="routing_number">Routing number</string>
|
||||
<string name="branch_number">Branch number</string>
|
||||
<string name="swift_code">SWIFT code</string>
|
||||
<string name="iban">IBAN</string>
|
||||
<string name="bank_contact_phone">Bank contact phone</string>
|
||||
<string name="copy_name_on_account">Copy name on account</string>
|
||||
<string name="copy_account_number">Copy account number</string>
|
||||
<string name="copy_routing_number">Copy routing number</string>
|
||||
<string name="copy_branch_number">Copy branch number</string>
|
||||
<string name="copy_pin">Copy PIN</string>
|
||||
<string name="copy_swift_code">Copy SWIFT code</string>
|
||||
<string name="copy_iban">Copy IBAN</string>
|
||||
<string name="copy_bank_contact_phone">Copy bank contact phone</string>
|
||||
<string name="checking">Checking</string>
|
||||
<string name="savings">Savings</string>
|
||||
<string name="certificate_of_deposit">Certificate of deposit</string>
|
||||
@@ -1345,4 +1349,5 @@ Do you want to switch to this account?</string>
|
||||
<string name="issuing_authority">Issuing authority/office</string>
|
||||
<string name="issue_date">Issue date</string>
|
||||
<string name="expiration_date">Expiration date</string>
|
||||
<string name="details">Details</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user