Prevent entering oversized custom donation amounts.

Fixes #14750
Resolves #14854

Co-authored-by: Greyson Parrelli <greyson@signal.org>
This commit is contained in:
abgolor
2026-08-19 19:05:48 -04:00
committed by Cody Henthorne
co-authored by Greyson Parrelli
parent 5139ea0840
commit ff217b061f
2 changed files with 53 additions and 0 deletions
@@ -226,6 +226,10 @@ data class Boost(
@VisibleForTesting
class MoneyFilter(val currency: Currency, private val text: AppCompatEditText? = null, private val onCustomAmountChanged: (String) -> Unit = {}) : DigitsKeyListener(false, true), TextWatcher {
companion object {
private const val MAX_INTEGRAL_DIGITS = 10
}
val separator = DecimalFormatSymbols.getInstance().decimalSeparator
val separatorCount = min(1, currency.defaultFractionDigits)
val symbol: String = currency.getSymbol(Locale.getDefault())
@@ -257,6 +261,12 @@ data class Boost(
val result = dest.subSequence(0, dstart).toString() + source.toString() + dest.subSequence(dend, dest.length)
val resultWithoutCurrencyPrefix = BidiUtil.stripBidiIndicator(result.removePrefix(symbol).removeSuffix(symbol).trim())
val integralDigitCount = resultWithoutCurrencyPrefix.substringBefore(separator).count { it.isDigit() }
if (integralDigitCount > MAX_INTEGRAL_DIGITS) {
return dest.subSequence(dstart, dend)
}
if (resultWithoutCurrencyPrefix.length == 1 && !resultWithoutCurrencyPrefix.isDigitsOnly() && resultWithoutCurrencyPrefix != separator.toString()) {
return dest.subSequence(dstart, dend)
}
@@ -247,4 +247,47 @@ class BoostTest__MoneyFilter {
assertEquals("0.0", result)
}
@Test
fun `Given USD, when I enter ten integral digits, then I expect successful filter`() {
val testSubject = Boost.MoneyFilter(usd)
val editable = SpannableStringBuilder("1234567890.12")
val dest = SpannableStringBuilder()
val filterResult = testSubject.filter(editable, 0, editable.length, dest, 0, 0)
assertNull(filterResult)
}
@Test
fun `Given USD, when I enter eleven integral digits, then I expect unsuccessful filter`() {
val testSubject = Boost.MoneyFilter(usd)
val editable = SpannableStringBuilder("12345678901")
val dest = SpannableStringBuilder()
val filterResult = testSubject.filter(editable, 0, editable.length, dest, 0, 0)
assertNotNull(filterResult)
}
@Test
fun `Given USD and ten integral digits, when I append a digit, then I expect the existing text to be retained`() {
val testSubject = Boost.MoneyFilter(usd)
val dest = SpannableStringBuilder("$1234567890")
val filterResult = testSubject.filter("1", 0, 1, dest, dest.length, dest.length)
assertEquals("", filterResult.toString())
}
@Test
fun `Given JPY, when I enter eleven integral digits, then I expect unsuccessful filter`() {
val testSubject = Boost.MoneyFilter(yen)
val editable = SpannableStringBuilder("12345678901")
val dest = SpannableStringBuilder()
val filterResult = testSubject.filter(editable, 0, editable.length, dest, 0, 0)
assertNotNull(filterResult)
}
}