Formula Input & rounding & more

This commit is contained in:
2026-09-02 00:43:39 +02:00
parent 42f67dfbe4
commit 72ba99f4b6
3 changed files with 34 additions and 26 deletions
@@ -329,20 +329,18 @@ class EditBillActivity : AppCompatActivity() {
if (splitMode != SplitMode.EVEN) { if (splitMode != SplitMode.EVEN) {
val splits: Map<Long, Double> = if (splitMode == SplitMode.CUSTOM) { val splits: Map<Long, Double> = if (splitMode == SplitMode.CUSTOM) {
viewModel.owersCustomSplit.filter { (id, amountStr) -> viewModel.owersCustomSplit.filter { (id, amountStr) ->
viewModel.owersSelection[id] == true && (amountStr.replace(',', '.').toDoubleOrNull() viewModel.owersSelection[id] == true && viewModel.parseAmountFromUi(amountStr) > 0
?: 0.0) > 0
}.mapValues { }.mapValues {
val uiAmount = it.value.replace(',', '.').toDoubleOrNull() ?: 0.0 val uiAmount = viewModel.parseAmountFromUi(it.value)
SupportUtil.round2(uiAmount / viewModel.selectedCurrencyRate) SupportUtil.round2(uiAmount / viewModel.selectedCurrencyRate)
} }
} else { // PERCENT } else { // PERCENT
val totalAmount = viewModel.amountAsDouble val totalAmount = viewModel.amountAsDouble
viewModel.owersPercentSplit.filter { (id, percentStr) -> viewModel.owersPercentSplit.filter { (id, percentStr) ->
viewModel.owersSelection[id] == true && (percentStr.replace(',', '.').toDoubleOrNull() viewModel.owersSelection[id] == true && viewModel.parseAmountFromUi(percentStr) > 0
?: 0.0) > 0
}.mapValues { }.mapValues {
val percent = it.value.replace(',', '.').toDoubleOrNull() ?: 0.0 val percent = viewModel.parseAmountFromUi(it.value)
val uiAmount = totalAmount * percent / 100.0 val uiAmount = SupportUtil.round2(totalAmount * percent / 100.0)
SupportUtil.round2(uiAmount / viewModel.selectedCurrencyRate) SupportUtil.round2(uiAmount / viewModel.selectedCurrencyRate)
} }
} }
@@ -193,8 +193,9 @@ fun BillBasicInfoSection(
OutlinedTextField( OutlinedTextField(
value = viewModel.amount, value = viewModel.amount,
onValueChange = { onValueChange = { nv->
viewModel.amount = it val filteredValue = nv.filter { it in "0123456789.+-*/" }
viewModel.amount = filteredValue
viewModel.updateSplits() viewModel.updateSplits()
}, },
enabled = canEdit, enabled = canEdit,
@@ -233,7 +234,7 @@ fun BillBasicInfoSection(
Icon(Icons.Default.SwapHoriz, contentDescription = "Change Currency") Icon(Icons.Default.SwapHoriz, contentDescription = "Change Currency")
} }
}, },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
@@ -442,13 +443,14 @@ fun OwerSelectionSection(
BasicTextField( BasicTextField(
value = value, value = value,
onValueChange = { onValueChange = { nv ->
val filteredValue = nv.filter { it in "0123456789.+-*/" }
if (viewModel.splitMode == SplitMode.PERCENT) { if (viewModel.splitMode == SplitMode.PERCENT) {
viewModel.owersPercentSplit[member.id] = it viewModel.owersPercentSplit[member.id] = filteredValue
} else { } else {
viewModel.owersCustomSplit[member.id] = it viewModel.owersCustomSplit[member.id] = filteredValue
} }
viewModel.owersSelection[member.id] = (it != "") viewModel.owersSelection[member.id] = (filteredValue != "")
}, },
modifier = Modifier modifier = Modifier
.width(80.dp) .width(80.dp)
@@ -44,18 +44,26 @@ class EditBillViewModel : ViewModel() {
var dialogState by mutableStateOf<DialogState?>(null) var dialogState by mutableStateOf<DialogState?>(null)
val amountAsDouble: Double fun parseAmountFromUi(input: String): Double {
get() { if (input.isBlank()) return 0.0
return parseAmount(amount) ?: try { val sanitized = input.replace(',', '.')
evalMath(amount.replace(',', '.')) // If it contains any math operator, try evalMath first
} catch (_: Exception) { if (sanitized.any { it in "+-*/" }) {
0.0 try {
} val result = evalMath(sanitized)
if (result != 0.0) return SupportUtil.round2(result)
} catch (_: Exception) {}
} }
val parsed = parseAmount(input) ?: 0.0
return SupportUtil.round2(parsed)
}
val amountAsDouble: Double
get() = parseAmountFromUi(amount)
fun getEvenSplit(): Double { fun getEvenSplit(): Double {
val selectedOwersCount = owersSelection.count { it.value } val selectedOwersCount = owersSelection.count { it.value }
return if (selectedOwersCount > 0) amountAsDouble / selectedOwersCount else 0.0 return if (selectedOwersCount > 0) SupportUtil.round2(amountAsDouble / selectedOwersCount) else 0.0
} }
fun updateSplits() { fun updateSplits() {
@@ -109,13 +117,13 @@ class EditBillViewModel : ViewModel() {
return if (splitMode == SplitMode.PERCENT) { return if (splitMode == SplitMode.PERCENT) {
val customTotal = owersPercentSplit.entries val customTotal = owersPercentSplit.entries
.filter { owersSelection[it.key] == true } .filter { owersSelection[it.key] == true }
.sumOf { it.value.replace(',', '.').toDoubleOrNull() ?: 0.0 } .sumOf { parseAmountFromUi(it.value) }
100.0 - customTotal SupportUtil.round2(100.0 - customTotal)
} else { } else {
val customTotal = owersCustomSplit.entries val customTotal = owersCustomSplit.entries
.filter { owersSelection[it.key] == true } .filter { owersSelection[it.key] == true }
.sumOf { it.value.replace(',', '.').toDoubleOrNull() ?: 0.0 } .sumOf { parseAmountFromUi(it.value) }
amountAsDouble - customTotal SupportUtil.round2(amountAsDouble - customTotal)
} }
} }