Add linked fields for identity (#536)

This commit is contained in:
Ramsey Smith 2024-01-08 13:23:22 -07:00 committed by Álison Fernandes
parent e318a316e7
commit 36d49a62a6
7 changed files with 149 additions and 25 deletions

View file

@ -61,14 +61,16 @@ fun VaultAddEditCustomField(
} }
is VaultAddEditState.Custom.LinkedField -> { is VaultAddEditState.Custom.LinkedField -> {
CustomFieldLinkedField( customField.vaultLinkedFieldType?.let { fieldType ->
selectedOption = customField.vaultLinkedFieldType, CustomFieldLinkedField(
supportedLinkedTypes = supportedLinkedTypes, selectedOption = fieldType,
onValueChanged = { supportedLinkedTypes = supportedLinkedTypes,
onCustomFieldValueChange(customField.copy(vaultLinkedFieldType = it)) onValueChanged = {
}, onCustomFieldValueChange(customField.copy(vaultLinkedFieldType = it))
modifier = modifier, },
) modifier = modifier,
)
}
} }
is VaultAddEditState.Custom.TextField -> { is VaultAddEditState.Custom.TextField -> {

View file

@ -339,14 +339,31 @@ fun LazyListScope.vaultAddEditIdentityItems(
items(commonState.customFieldData) { customItem -> items(commonState.customFieldData) { customItem ->
VaultAddEditCustomField( VaultAddEditCustomField(
customItem, customField = customItem,
onCustomFieldValueChange = commonTypeHandlers.onCustomFieldValueChange, onCustomFieldValueChange = commonTypeHandlers.onCustomFieldValueChange,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
supportedLinkedTypes = persistentListOf( supportedLinkedTypes = persistentListOf(
VaultLinkedFieldType.PASSWORD, VaultLinkedFieldType.TITLE,
VaultLinkedFieldType.USERNAME, VaultLinkedFieldType.MIDDLE_NAME,
VaultLinkedFieldType.ADDRESS_1,
VaultLinkedFieldType.ADDRESS_2,
VaultLinkedFieldType.ADDRESS_3,
VaultLinkedFieldType.CITY,
VaultLinkedFieldType.STATE,
VaultLinkedFieldType.POSTAL_CODE,
VaultLinkedFieldType.COUNTRY,
VaultLinkedFieldType.COMPANY,
VaultLinkedFieldType.EMAIL,
VaultLinkedFieldType.PHONE,
VaultLinkedFieldType.SSN,
VaultLinkedFieldType.IDENTITY_USERNAME,
VaultLinkedFieldType.PASSPORT_NUMBER,
VaultLinkedFieldType.LICENSE_NUMBER,
VaultLinkedFieldType.FIRST_NAME,
VaultLinkedFieldType.LAST_NAME,
VaultLinkedFieldType.FULL_NAME,
), ),
) )
} }

View file

@ -147,6 +147,7 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleSwitchToAddLoginItem() { private fun handleSwitchToAddLoginItem() {
updateContent { currentContent -> updateContent { currentContent ->
currentContent.copy( currentContent.copy(
common = currentContent.common.clearNonSharedData(),
type = VaultAddEditState.ViewState.Content.ItemType.Login(), type = VaultAddEditState.ViewState.Content.ItemType.Login(),
) )
} }
@ -155,6 +156,7 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleSwitchToAddSecureNotesItem() { private fun handleSwitchToAddSecureNotesItem() {
updateContent { currentContent -> updateContent { currentContent ->
currentContent.copy( currentContent.copy(
common = currentContent.common.clearNonSharedData(),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes, type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
) )
} }
@ -163,6 +165,7 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleSwitchToAddCardItem() { private fun handleSwitchToAddCardItem() {
updateContent { currentContent -> updateContent { currentContent ->
currentContent.copy( currentContent.copy(
common = currentContent.common.clearNonSharedData(),
type = VaultAddEditState.ViewState.Content.ItemType.Card(), type = VaultAddEditState.ViewState.Content.ItemType.Card(),
) )
} }
@ -171,6 +174,7 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleSwitchToAddIdentityItem() { private fun handleSwitchToAddIdentityItem() {
updateContent { currentContent -> updateContent { currentContent ->
currentContent.copy( currentContent.copy(
common = currentContent.common.clearNonSharedData(),
type = VaultAddEditState.ViewState.Content.ItemType.Identity(), type = VaultAddEditState.ViewState.Content.ItemType.Identity(),
) )
} }
@ -230,13 +234,17 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleAddNewCustomFieldClick( private fun handleAddNewCustomFieldClick(
action: VaultAddEditAction.Common.AddNewCustomFieldClick, action: VaultAddEditAction.Common.AddNewCustomFieldClick,
) { ) {
updateContent {
updateCommonContent { common ->
val newCustomData: VaultAddEditState.Custom = val newCustomData: VaultAddEditState.Custom =
action.customFieldType.toCustomField(action.name) action.customFieldType.toCustomField(
name = action.name,
common.copy(customFieldData = common.customFieldData + newCustomData) itemType = it.type,
)
it.copy(
common = it
.common
.copy(customFieldData = it.common.customFieldData + newCustomData),
)
} }
} }
@ -457,6 +465,7 @@ class VaultAddEditViewModel @Inject constructor(
//endregion Add Login Item Type Handlers //endregion Add Login Item Type Handlers
//region Identity Type Handlers //region Identity Type Handlers
@Suppress("LongMethod")
private fun handleIdentityTypeActions(action: VaultAddEditAction.ItemType.IdentityType) { private fun handleIdentityTypeActions(action: VaultAddEditAction.ItemType.IdentityType) {
when (action) { when (action) {
is VaultAddEditAction.ItemType.IdentityType.FirstNameTextChange -> { is VaultAddEditAction.ItemType.IdentityType.FirstNameTextChange -> {
@ -909,6 +918,13 @@ class VaultAddEditViewModel @Inject constructor(
} }
} }
private fun VaultAddEditState.ViewState.Content.Common.clearNonSharedData():
VaultAddEditState.ViewState.Content.Common =
copy(
customFieldData = customFieldData
.filterNot { it is VaultAddEditState.Custom.LinkedField },
)
//endregion Utility Functions //endregion Utility Functions
} }
@ -1185,7 +1201,7 @@ data class VaultAddEditState(
data class LinkedField( data class LinkedField(
override val itemId: String, override val itemId: String,
val name: String, val name: String,
val vaultLinkedFieldType: VaultLinkedFieldType, val vaultLinkedFieldType: VaultLinkedFieldType?,
) : Custom() ) : Custom()
} }

View file

@ -22,6 +22,7 @@ enum class CustomFieldType(val typeText: Text) {
*/ */
fun CustomFieldType.toCustomField( fun CustomFieldType.toCustomField(
name: String, name: String,
itemType: VaultAddEditState.ViewState.Content.ItemType,
): VaultAddEditState.Custom { ): VaultAddEditState.Custom {
return when (this) { return when (this) {
CustomFieldType.BOOLEAN -> { CustomFieldType.BOOLEAN -> {
@ -36,7 +37,7 @@ fun CustomFieldType.toCustomField(
VaultAddEditState.Custom.LinkedField( VaultAddEditState.Custom.LinkedField(
itemId = UUID.randomUUID().toString(), itemId = UUID.randomUUID().toString(),
name = name, name = name,
vaultLinkedFieldType = VaultLinkedFieldType.USERNAME, vaultLinkedFieldType = itemType.defaultLinkedFieldTypeOrNull,
) )
} }
@ -57,3 +58,12 @@ fun CustomFieldType.toCustomField(
} }
} }
} }
@Suppress("MaxLineLength")
private val VaultAddEditState.ViewState.Content.ItemType.defaultLinkedFieldTypeOrNull: VaultLinkedFieldType?
get() = when (this) {
is VaultAddEditState.ViewState.Content.ItemType.Card -> VaultLinkedFieldType.CARDHOLDER_NAME
is VaultAddEditState.ViewState.Content.ItemType.Identity -> VaultLinkedFieldType.TITLE
is VaultAddEditState.ViewState.Content.ItemType.Login -> VaultLinkedFieldType.USERNAME
is VaultAddEditState.ViewState.Content.ItemType.SecureNotes -> null
}

View file

@ -177,7 +177,7 @@ private fun VaultAddEditState.Custom.toFieldView(): FieldView =
name = item.name, name = item.name,
value = null, value = null,
type = FieldType.LINKED, type = FieldType.LINKED,
linkedId = item.vaultLinkedFieldType.id, linkedId = item.vaultLinkedFieldType?.id,
) )
} }

View file

@ -23,6 +23,26 @@ enum class VaultLinkedFieldType(
SECURITY_CODE(id = 303.toUInt(), label = R.string.security_code.asText()), SECURITY_CODE(id = 303.toUInt(), label = R.string.security_code.asText()),
BRAND(id = 304.toUInt(), label = R.string.brand.asText()), BRAND(id = 304.toUInt(), label = R.string.brand.asText()),
NUMBER(id = 305.toUInt(), label = R.string.number.asText()), NUMBER(id = 305.toUInt(), label = R.string.number.asText()),
TITLE(id = 400.toUInt(), label = R.string.title.asText()),
MIDDLE_NAME(id = 401.toUInt(), label = R.string.middle_name.asText()),
ADDRESS_1(id = 402.toUInt(), label = R.string.address1.asText()),
ADDRESS_2(id = 403.toUInt(), label = R.string.address2.asText()),
ADDRESS_3(id = 404.toUInt(), label = R.string.address3.asText()),
CITY(id = 405.toUInt(), label = R.string.city_town.asText()),
STATE(id = 406.toUInt(), label = R.string.state_province.asText()),
POSTAL_CODE(id = 407.toUInt(), label = R.string.zip_postal_code.asText()),
COUNTRY(id = 408.toUInt(), label = R.string.country.asText()),
COMPANY(id = 409.toUInt(), label = R.string.company.asText()),
EMAIL(id = 410.toUInt(), label = R.string.email.asText()),
PHONE(id = 411.toUInt(), label = R.string.phone.asText()),
SSN(id = 412.toUInt(), label = R.string.ssn.asText()),
IDENTITY_USERNAME(id = 413.toUInt(), label = R.string.username.asText()),
PASSPORT_NUMBER(id = 414.toUInt(), label = R.string.passport_number.asText()),
LICENSE_NUMBER(id = 415.toUInt(), label = R.string.license_number.asText()),
FIRST_NAME(id = 416.toUInt(), label = R.string.first_name.asText()),
LAST_NAME(id = 417.toUInt(), label = R.string.last_name.asText()),
FULL_NAME(id = 418.toUInt(), label = R.string.full_name.asText()),
; ;
companion object { companion object {

View file

@ -31,19 +31,72 @@ class CustomFieldTypeTests {
val type = CustomFieldType.BOOLEAN val type = CustomFieldType.BOOLEAN
val expected = VaultAddEditState.Custom.BooleanField(TEST_ID, "test", false) val expected = VaultAddEditState.Custom.BooleanField(TEST_ID, "test", false)
val actual = type.toCustomField(name) val actual = type.toCustomField(
name = name,
itemType = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
)
assertEquals(expected, actual) assertEquals(expected, actual)
} }
@Test @Test
fun `toCustomField should return a custom linked type when we pass in required linked type`() { fun `toCustomField should return a custom linked type when we pass in Login type`() {
val name = "test" val name = "test"
val type = CustomFieldType.LINKED val type = CustomFieldType.LINKED
val expected = val expected =
VaultAddEditState.Custom.LinkedField(TEST_ID, "test", VaultLinkedFieldType.USERNAME) VaultAddEditState.Custom.LinkedField(TEST_ID, "test", VaultLinkedFieldType.USERNAME)
val actual = type.toCustomField(name) val actual = type.toCustomField(
name = name,
itemType = VaultAddEditState.ViewState.Content.ItemType.Login(),
)
assertEquals(expected, actual)
}
@Test
fun `toCustomField should return a custom linked type when we pass in Identity type`() {
val name = "test"
val type = CustomFieldType.LINKED
val expected =
VaultAddEditState.Custom.LinkedField(TEST_ID, "test", VaultLinkedFieldType.TITLE)
val actual = type.toCustomField(
name = name,
itemType = VaultAddEditState.ViewState.Content.ItemType.Identity(),
)
assertEquals(expected, actual)
}
@Suppress("MaxLineLength")
@Test
fun `toCustomField should return a custom linked type when we pass in Card type`() {
val name = "test"
val type = CustomFieldType.LINKED
val expected =
VaultAddEditState.Custom.LinkedField(TEST_ID, "test", VaultLinkedFieldType.CARDHOLDER_NAME)
val actual = type.toCustomField(
name = name,
itemType = VaultAddEditState.ViewState.Content.ItemType.Card(),
)
assertEquals(expected, actual)
}
@Suppress("MaxLineLength")
@Test
fun `toCustomField should return a null custom linked type when we pass in Secure Note type`() {
val name = "test"
val type = CustomFieldType.LINKED
val expected =
VaultAddEditState.Custom.LinkedField(TEST_ID, "test", null)
val actual = type.toCustomField(
name = name,
itemType = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
)
assertEquals(expected, actual) assertEquals(expected, actual)
} }
@ -54,7 +107,10 @@ class CustomFieldTypeTests {
val type = CustomFieldType.TEXT val type = CustomFieldType.TEXT
val expected = VaultAddEditState.Custom.TextField(TEST_ID, "test", "") val expected = VaultAddEditState.Custom.TextField(TEST_ID, "test", "")
val actual = type.toCustomField(name) val actual = type.toCustomField(
name = name,
itemType = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
)
assertEquals(expected, actual) assertEquals(expected, actual)
} }
@ -65,7 +121,10 @@ class CustomFieldTypeTests {
val type = CustomFieldType.HIDDEN val type = CustomFieldType.HIDDEN
val expected = VaultAddEditState.Custom.HiddenField(TEST_ID, "test", "") val expected = VaultAddEditState.Custom.HiddenField(TEST_ID, "test", "")
val actual = type.toCustomField(name) val actual = type.toCustomField(
name = name,
itemType = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
)
assertEquals(expected, actual) assertEquals(expected, actual)
} }