From 2f6a36ce1ab98c11d09e300ddfe46395a58bc546 Mon Sep 17 00:00:00 2001 From: David Perez Date: Fri, 15 May 2026 14:03:42 -0500 Subject: [PATCH] bug: Update Passport and License date formats in VaultItemScreen (#6927) --- .../feature/item/util/CipherViewExtensions.kt | 33 +++++++++++++++---- .../datasource/sdk/model/CipherViewUtil.kt | 12 +++---- .../item/util/CipherViewExtensionsTest.kt | 14 ++++---- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensions.kt index e773ab5d27..e72cbbe54a 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensions.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensions.kt @@ -1,6 +1,7 @@ package com.x8bit.bitwarden.ui.vault.feature.item.util import androidx.annotation.DrawableRes +import com.bitwarden.core.data.util.toFormattedDateStyle import com.bitwarden.core.data.util.toFormattedDateTimeStyle import com.bitwarden.ui.platform.base.util.nullIfAllEqual import com.bitwarden.ui.platform.base.util.orNullIfBlank @@ -32,6 +33,8 @@ import com.x8bit.bitwarden.ui.vault.util.formatCardNumber import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import java.time.Clock +import java.time.LocalDate +import java.time.format.DateTimeParseException import java.time.format.FormatStyle import java.util.Locale @@ -236,12 +239,12 @@ fun CipherView.toViewState( middleName = driversLicense?.middleName, lastName = driversLicense?.lastName, licenseNumber = driversLicense?.licenseNumber, - dateOfBirth = driversLicense?.dateOfBirth, + dateOfBirth = driversLicense?.dateOfBirth?.toFormattedDate(clock = clock), issuingCountry = driversLicense?.issuingCountry, issuingState = driversLicense?.issuingState, issuingAuthority = driversLicense?.issuingAuthority, - issueDate = driversLicense?.issueDate, - expirationDate = driversLicense?.expirationDate, + issueDate = driversLicense?.issueDate?.toFormattedDate(clock = clock), + expirationDate = driversLicense?.expirationDate?.toFormattedDate(clock = clock), licenseClass = driversLicense?.licenseClass, ) } @@ -249,7 +252,7 @@ fun CipherView.toViewState( CipherType.PASSPORT -> VaultItemState.ViewState.Content.ItemType.Passport( givenName = passport?.givenName, surname = passport?.surname, - dateOfBirth = passport?.dateOfBirth, + dateOfBirth = passport?.dateOfBirth?.toFormattedDate(clock = clock), sex = passport?.sex, birthPlace = passport?.birthPlace, nationality = passport?.nationality, @@ -258,8 +261,8 @@ fun CipherView.toViewState( nationalIdentificationNumber = passport?.nationalIdentificationNumber, issuingCountry = passport?.issuingCountry, issuingAuthority = passport?.issuingAuthority, - issueDate = passport?.issueDate, - expirationDate = passport?.expirationDate, + issueDate = passport?.issueDate?.toFormattedDate(clock = clock), + expirationDate = passport?.expirationDate?.toFormattedDate(clock = clock), ) }, ) @@ -302,6 +305,24 @@ fun FieldView.toCustomField( ) } +/** + * Takes a string date that is formatted in the default ISO-8601 format (uuuu-MM-dd) and converts + * it to appropriate human-readable format. + */ +private fun String.toFormattedDate( + clock: Clock, +): String? { + val localDate = try { + LocalDate.parse(this) + } catch (_: DateTimeParseException) { + null + } + return localDate?.toFormattedDateStyle( + dateStyle = FormatStyle.LONG, + clock = clock, + ) +} + private fun LoginUriView.toUriData() = VaultItemState.ViewState.Content.ItemType.Login.UriData( uri = uri.orZeroWidthSpace(), diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt index a6a4a49145..43fff63267 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt @@ -271,13 +271,13 @@ fun createMockDriversLicenseView( firstName: String? = "mockFirstName-$number", middleName: String? = "mockMiddleName-$number", lastName: String? = "mockLastName-$number", - dateOfBirth: String? = "mockDateOfBirth-$number", + dateOfBirth: String? = "2006-05-11", licenseNumber: String? = "mockLicenseNumber-$number", issuingCountry: String? = "mockIssuingCountry-$number", issuingState: String? = "mockIssuingState-$number", issuingAuthority: String? = "mockIssuingAuthority-$number", - issueDate: String? = "mockIssueDate-$number", - expirationDate: String? = "mockExpirationDate-$number", + issueDate: String? = "2024-06-15", + expirationDate: String? = "2031-11-25", licenseClass: String? = "mockLicenseClass-$number", ): DriversLicenseView = DriversLicenseView( @@ -302,7 +302,7 @@ fun createMockPassportView( number: Int, surname: String? = "mockSurname-$number", givenName: String? = "mockGivenName-$number", - dateOfBirth: String? = "mockDateOfBirth-$number", + dateOfBirth: String? = "2006-05-11", birthPlace: String? = "mockBirthPlace-$number", sex: String? = "mockSex-$number", nationality: String? = "mockNationality-$number", @@ -310,8 +310,8 @@ fun createMockPassportView( passportType: String? = "mockPassportType-$number", issuingCountry: String? = "mockIssuingCountry-$number", issuingAuthority: String? = "mockIssuingAuthority-$number", - issueDate: String? = "mockIssueDate-$number", - expirationDate: String? = "mockExpirationDate-$number", + issueDate: String? = "2024-06-15", + expirationDate: String? = "2031-11-25", nationalIdentificationNumber: String? = "mockNationalIdentificationNumber-$number", ): PassportView = PassportView( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensionsTest.kt index f79a2f952f..3f7b2336fd 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensionsTest.kt @@ -452,7 +452,6 @@ class CipherViewExtensionsTest { ) } - @Suppress("MaxLineLength") @Test fun `toViewState should transform full CipherView into ViewState Drivers License Content`() { val cipherView = createCipherView(type = CipherType.DRIVERS_LICENSE, isEmpty = false) @@ -485,12 +484,12 @@ class CipherViewExtensionsTest { middleName = "mockMiddleName-1", lastName = "mockLastName-1", licenseNumber = "mockLicenseNumber-1", - dateOfBirth = "mockDateOfBirth-1", + dateOfBirth = "May 11, 2006", issuingCountry = "mockIssuingCountry-1", issuingState = "mockIssuingState-1", issuingAuthority = "mockIssuingAuthority-1", - issueDate = "mockIssueDate-1", - expirationDate = "mockExpirationDate-1", + issueDate = "June 15, 2024", + expirationDate = "November 25, 2031", licenseClass = "mockLicenseClass-1", ), ), @@ -498,7 +497,6 @@ class CipherViewExtensionsTest { ) } - @Suppress("MaxLineLength") @Test fun `toViewState should transform empty CipherView into ViewState Drivers License Content`() { val cipherView = createCipherView(type = CipherType.DRIVERS_LICENSE, isEmpty = true) @@ -573,7 +571,7 @@ class CipherViewExtensionsTest { type = VaultItemState.ViewState.Content.ItemType.Passport( givenName = "mockGivenName-1", surname = "mockSurname-1", - dateOfBirth = "mockDateOfBirth-1", + dateOfBirth = "May 11, 2006", sex = "mockSex-1", birthPlace = "mockBirthPlace-1", nationality = "mockNationality-1", @@ -582,8 +580,8 @@ class CipherViewExtensionsTest { nationalIdentificationNumber = "mockNationalIdentificationNumber-1", issuingCountry = "mockIssuingCountry-1", issuingAuthority = "mockIssuingAuthority-1", - issueDate = "mockIssueDate-1", - expirationDate = "mockExpirationDate-1", + issueDate = "June 15, 2024", + expirationDate = "November 25, 2031", ), ), viewState,