-
Notifications
You must be signed in to change notification settings - Fork 664
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add formatted content description for Expiration Date text field (#10185
- Loading branch information
1 parent
51dbaa9
commit fc31cc9
Showing
20 changed files
with
294 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
...rc/main/java/com/stripe/android/ui/core/elements/ExpiryDateContentDescriptionFormatter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package com.stripe.android.ui.core.elements | ||
|
||
import androidx.annotation.RestrictTo | ||
import androidx.appcompat.app.AppCompatDelegate | ||
import com.stripe.android.core.strings.ResolvableString | ||
import com.stripe.android.core.strings.resolvableString | ||
import com.stripe.android.uicore.R | ||
import java.text.ParseException | ||
import java.text.SimpleDateFormat | ||
import java.util.Locale | ||
|
||
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) | ||
fun formatExpirationDateForAccessibility(input: String): ResolvableString { | ||
if (input.isEmpty()) { | ||
return resolvableString(R.string.stripe_expiration_date_empty_content_description) | ||
} | ||
|
||
// Check if input is valid integer | ||
if (input.toIntOrNull() == null) return input.resolvableString | ||
|
||
val canOnlyBeSingleDigitMonth = input.isNotBlank() && !(input[0] == '0' || input[0] == '1') | ||
val canOnlyBeJanuary = input.length > 1 && input.take(2).toInt() > 12 | ||
val isSingleDigitMonth = canOnlyBeSingleDigitMonth || canOnlyBeJanuary | ||
|
||
val lastIndexOfMonth = if (isSingleDigitMonth) 0 else 1 | ||
val month = input.take(lastIndexOfMonth + 1).toIntOrNull() | ||
val year = input.slice(lastIndexOfMonth + 1..input.lastIndex).toIntOrNull() | ||
|
||
try { | ||
if (month != null) { | ||
val locale = AppCompatDelegate.getApplicationLocales()[0] ?: Locale.getDefault() | ||
val monthName = SimpleDateFormat("MM", locale).parse("$month")?.let { | ||
SimpleDateFormat("MMMM", locale).format(it) | ||
} | ||
|
||
return when (year) { | ||
null -> return resolvableString( | ||
R.string.stripe_expiration_date_month_complete_content_description, | ||
monthName | ||
) | ||
in 0..9 -> resolvableString( | ||
R.string.stripe_expiration_date_year_incomplete_content_description, | ||
monthName | ||
) | ||
else -> resolvableString( | ||
R.string.stripe_expiration_date_content_description, | ||
monthName, | ||
2000 + year | ||
) | ||
} | ||
} | ||
|
||
return input.resolvableString | ||
} catch (e: ParseException) { | ||
// ParseException should never be thrown so we can ignore but we want to prevent crash in the case it is thrown. | ||
return input.resolvableString | ||
} | ||
} |
111 changes: 111 additions & 0 deletions
111
...-core/src/test/java/com/stripe/android/utils/ExpiryDateContentDescriptionFormatterTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package com.stripe.android.utils | ||
|
||
import androidx.appcompat.app.AppCompatDelegate | ||
import androidx.core.os.LocaleListCompat | ||
import com.google.common.truth.Truth.assertThat | ||
import com.stripe.android.core.strings.resolvableString | ||
import com.stripe.android.ui.core.elements.formatExpirationDateForAccessibility | ||
import com.stripe.android.uicore.R | ||
import org.junit.Test | ||
|
||
class ExpiryDateContentDescriptionFormatterTest { | ||
|
||
@Test | ||
fun `formats correctly for empty input`() { | ||
val result = formatExpirationDateForAccessibility("") | ||
val expected = resolvableString(R.string.stripe_expiration_date_empty_content_description) | ||
|
||
assertThat(result).isEqualTo(expected) | ||
} | ||
|
||
@Test | ||
fun `formats correctly for month only`() { | ||
val result = formatExpirationDateForAccessibility("4") | ||
val expected = resolvableString( | ||
R.string.stripe_expiration_date_month_complete_content_description, | ||
"April" | ||
) | ||
|
||
assertThat(result).isEqualTo(expected) | ||
} | ||
|
||
@Test | ||
fun `formats correctly for month and incomplete year`() { | ||
val result = formatExpirationDateForAccessibility("55") | ||
val expected = resolvableString( | ||
R.string.stripe_expiration_date_year_incomplete_content_description, | ||
"May" | ||
) | ||
|
||
assertThat(result).isEqualTo(expected) | ||
} | ||
|
||
@Test | ||
fun `formats correctly for month and year`() { | ||
val result = formatExpirationDateForAccessibility("555") | ||
val expected = resolvableString( | ||
R.string.stripe_expiration_date_content_description, | ||
"May", | ||
2055 | ||
) | ||
|
||
assertThat(result).isEqualTo(expected) | ||
} | ||
|
||
@Test | ||
fun `formats correctly for double digit month`() { | ||
val result = formatExpirationDateForAccessibility("1255") | ||
val expected = resolvableString( | ||
R.string.stripe_expiration_date_content_description, | ||
"December", | ||
2055 | ||
) | ||
|
||
assertThat(result).isEqualTo(expected) | ||
} | ||
|
||
@Test | ||
fun `formats correctly for single digit month with leading 0`() { | ||
val result = formatExpirationDateForAccessibility("0155") | ||
val expected = resolvableString( | ||
R.string.stripe_expiration_date_content_description, | ||
"January", | ||
2055 | ||
) | ||
|
||
assertThat(result).isEqualTo(expected) | ||
} | ||
|
||
@Test | ||
fun `formats first two numbers as month if less than 13`() { | ||
val result = formatExpirationDateForAccessibility("126") | ||
val expected = resolvableString( | ||
R.string.stripe_expiration_date_year_incomplete_content_description, | ||
"December" | ||
) | ||
|
||
assertThat(result).isEqualTo(expected) | ||
} | ||
|
||
@Test | ||
fun `formats month correctly based on locale`() { | ||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags("FR")) | ||
val result = formatExpirationDateForAccessibility("126") | ||
val expected = resolvableString( | ||
R.string.stripe_expiration_date_year_incomplete_content_description, | ||
"décembre" | ||
) | ||
|
||
assertThat(result).isEqualTo(expected) | ||
// Clear FR locale | ||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.getEmptyLocaleList()) | ||
} | ||
|
||
@Test | ||
fun `returns input as resolvable string if input is not numeric`() { | ||
val result = formatExpirationDateForAccessibility("test") | ||
val expected = "test".resolvableString | ||
|
||
assertThat(result).isEqualTo(expected) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.