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 -> {
CustomFieldLinkedField(
selectedOption = customField.vaultLinkedFieldType,
supportedLinkedTypes = supportedLinkedTypes,
onValueChanged = {
onCustomFieldValueChange(customField.copy(vaultLinkedFieldType = it))
},
modifier = modifier,
)
customField.vaultLinkedFieldType?.let { fieldType ->
CustomFieldLinkedField(
selectedOption = fieldType,
supportedLinkedTypes = supportedLinkedTypes,
onValueChanged = {
onCustomFieldValueChange(customField.copy(vaultLinkedFieldType = it))
},
modifier = modifier,
)
}
}
is VaultAddEditState.Custom.TextField -> {

View file

@ -339,14 +339,31 @@ fun LazyListScope.vaultAddEditIdentityItems(
items(commonState.customFieldData) { customItem ->
VaultAddEditCustomField(
customItem,
customField = customItem,
onCustomFieldValueChange = commonTypeHandlers.onCustomFieldValueChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
supportedLinkedTypes = persistentListOf(
VaultLinkedFieldType.PASSWORD,
VaultLinkedFieldType.USERNAME,
VaultLinkedFieldType.TITLE,
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() {
updateContent { currentContent ->
currentContent.copy(
common = currentContent.common.clearNonSharedData(),
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
)
}
@ -155,6 +156,7 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleSwitchToAddSecureNotesItem() {
updateContent { currentContent ->
currentContent.copy(
common = currentContent.common.clearNonSharedData(),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
)
}
@ -163,6 +165,7 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleSwitchToAddCardItem() {
updateContent { currentContent ->
currentContent.copy(
common = currentContent.common.clearNonSharedData(),
type = VaultAddEditState.ViewState.Content.ItemType.Card(),
)
}
@ -171,6 +174,7 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleSwitchToAddIdentityItem() {
updateContent { currentContent ->
currentContent.copy(
common = currentContent.common.clearNonSharedData(),
type = VaultAddEditState.ViewState.Content.ItemType.Identity(),
)
}
@ -230,13 +234,17 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleAddNewCustomFieldClick(
action: VaultAddEditAction.Common.AddNewCustomFieldClick,
) {
updateCommonContent { common ->
updateContent {
val newCustomData: VaultAddEditState.Custom =
action.customFieldType.toCustomField(action.name)
common.copy(customFieldData = common.customFieldData + newCustomData)
action.customFieldType.toCustomField(
name = action.name,
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
//region Identity Type Handlers
@Suppress("LongMethod")
private fun handleIdentityTypeActions(action: VaultAddEditAction.ItemType.IdentityType) {
when (action) {
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
}
@ -1185,7 +1201,7 @@ data class VaultAddEditState(
data class LinkedField(
override val itemId: String,
val name: String,
val vaultLinkedFieldType: VaultLinkedFieldType,
val vaultLinkedFieldType: VaultLinkedFieldType?,
) : Custom()
}

View file

@ -22,6 +22,7 @@ enum class CustomFieldType(val typeText: Text) {
*/
fun CustomFieldType.toCustomField(
name: String,
itemType: VaultAddEditState.ViewState.Content.ItemType,
): VaultAddEditState.Custom {
return when (this) {
CustomFieldType.BOOLEAN -> {
@ -36,7 +37,7 @@ fun CustomFieldType.toCustomField(
VaultAddEditState.Custom.LinkedField(
itemId = UUID.randomUUID().toString(),
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,
value = null,
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()),
BRAND(id = 304.toUInt(), label = R.string.brand.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 {

View file

@ -31,19 +31,72 @@ class CustomFieldTypeTests {
val type = CustomFieldType.BOOLEAN
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)
}
@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 type = CustomFieldType.LINKED
val expected =
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)
}
@ -54,7 +107,10 @@ class CustomFieldTypeTests {
val type = CustomFieldType.TEXT
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)
}
@ -65,7 +121,10 @@ class CustomFieldTypeTests {
val type = CustomFieldType.HIDDEN
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)
}