Skip to content

Instantly share code, notes, and snippets.

@damianpetla
Created October 14, 2023 09:28
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save damianpetla/1c504b03871245041e1a5a39dd89adc1 to your computer and use it in GitHub Desktop.
Save damianpetla/1c504b03871245041e1a5a39dd89adc1 to your computer and use it in GitHub Desktop.
Transforming EditText value into currency
import androidx.compose.ui.text.input.OffsetMapping
class CurrencyOffsetMapping(originalText: String, formattedText: String) : OffsetMapping {
private val originalLength: Int = originalText.length
private val indexes = findDigitIndexes(originalText, formattedText)
private fun findDigitIndexes(firstString: String, secondString: String): List<Int> {
val digitIndexes = mutableListOf<Int>()
var currentIndex = 0
for (digit in firstString) {
// Find the index of the digit in the second string
val index = secondString.indexOf(digit, currentIndex)
if (index != -1) {
digitIndexes.add(index)
currentIndex = index + 1
} else {
// If the digit is not found, return an empty list
return emptyList()
}
}
return digitIndexes
}
override fun originalToTransformed(offset: Int): Int {
if (offset >= originalLength) {
return indexes.last() + 1
}
return indexes[offset]
}
override fun transformedToOriginal(offset: Int): Int {
return indexes.indexOfFirst { it >= offset }.takeIf { it != -1 } ?: originalLength
}
}
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.input.OffsetMapping
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
import androidx.core.text.isDigitsOnly
import java.text.NumberFormat
import java.util.Currency
private class CurrencyVisualTransformation(
currencyCode: String
) : VisualTransformation {
private val numberFormatter = NumberFormat.getCurrencyInstance().apply {
currency = Currency.getInstance(currencyCode)
maximumFractionDigits = 0
}
override fun filter(text: AnnotatedString): TransformedText {
val originalText = text.text.trim()
if (originalText.isEmpty()) {
return TransformedText(text, OffsetMapping.Identity)
}
if (originalText.isDigitsOnly().not()) {
Log.w("TAG", "Prize visual transformation require using digits only but found [$originalText]")
return TransformedText(text, OffsetMapping.Identity)
}
val formattedText = numberFormatter.format(originalText.toInt())
return TransformedText(
AnnotatedString(formattedText),
CurrencyOffsetMapping(originalText, formattedText)
)
}
}
@Composable
fun rememberCurrencyVisualTransformation(currency: String): VisualTransformation {
val inspectionMode = LocalInspectionMode.current
return remember(currency) {
if (inspectionMode) {
VisualTransformation.None
} else {
CurrencyVisualTransformation(currency)
}
}
}
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.text.input.KeyboardType
private const val MAX_VALUE = 10000
@Composable
fun SampleUse() {
var value by remember { mutableStateOf("") }
val currencyVisualTransformation = rememberCurrencyVisualTransformation(currency = "USD")
TextField(
value = value,
onValueChange = { newValue ->
val trimmed = newValue.trimStart('0').trim { it.isDigit().not() }
if (trimmed.isEmpty() || trimmed.toInt() <= MAX_VALUE) {
value = trimmed
}
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
visualTransformation = currencyVisualTransformation
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment