mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
Add linked fields for identity (#536)
This commit is contained in:
parent
e318a316e7
commit
36d49a62a6
7 changed files with 149 additions and 25 deletions
|
@ -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 -> {
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue