How can I properly handle number in text component in jetpack compose (with MVVM pattern)
Please note that the price can be null or have a value (maybe 0 btw)
I have a poor implementation for now, I changed the keyboard like this :
OutlinedTextField(
value = if (vm.viewState.collectAsState().value.price != null) vm.viewState.collectAsState().value.price.toString() else "",
onValueChange = { vm.onProductPriceChange(it) },
label = { Text(stringResource(id = R.string.price)) },
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.None,
autoCorrect = true,
keyboardType = KeyboardType.Number
),
)
and for onValueChange :
fun onProductPriceChange(it: Any) {
if (it.toString() == "") {
_viewState.value = _viewState.value.copy(price = null)
} else {
try
{
_viewState.value = _viewState.value.copy(price = it.toString().toDouble())
}
catch (e: NumberFormatException)
{ // dismiss the bad entries
}
}
}
there can be multiple bad output of the user for example write 22..0 (I dismissed them which is a workaround acceptable)
but there are bad behaviour, when you want to write 10, it will convert it to 10.0. it is not huge but it has backwards
when you delete number in the EditText, 10.0 will become 10.0 and then 100.0 and then 10.0 and finally 1.0. btw it is impossible to go back to the null value (for this case, I can consider 0.0 = no value)
I saw that VisualTransformation (https://medium.com/google-developer-experts/hands-on-jetpack-compose-visualtransformation-to-create-a-phone-number-formatter-99b0347fc4f6) could handle my case but the documentation seems complicated
class DoubleVisualTransformation : VisualTransformation {
override fun filter(str: AnnotatedString): TransformedText {
val strNullDouble = str.text.toBigDecimalOrNull()
var transformedString: String
if (str.text == "" || strNullDouble == null)
return TransformedText(AnnotatedString(""), OffsetMapping.Identity)
else if (strNullDouble.toDouble() % 1 == 0.0 && str.text.last() != '.')
transformedString = strNullDouble.toInt().toString()
else
transformedString = str.text
return TransformedText(
text = AnnotatedString(transformedString),
offsetMapping = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
return offset
}
override fun transformedToOriginal(offset: Int): Int {
return offset
}
}
)
}
}
how can I improve the behavior ?