diff --git a/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillActivity.kt b/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillActivity.kt index 33b253a..20f0727 100644 --- a/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillActivity.kt +++ b/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillActivity.kt @@ -333,7 +333,7 @@ class EditBillActivity : AppCompatActivity() { viewModel.owersSelection[id] == true && viewModel.parseAmountFromUi(amountStr) > 0 }.mapValues { val uiAmount = viewModel.parseAmountFromUi(it.value) - SupportUtil.round2(uiAmount / viewModel.selectedCurrencyRate) + SupportUtil.round2(uiAmount * viewModel.selectedCurrencyRate) } } else { // PERCENT val totalAmount = viewModel.amountAsDouble @@ -342,7 +342,7 @@ class EditBillActivity : AppCompatActivity() { }.mapValues { val percent = viewModel.parseAmountFromUi(it.value) val uiAmount = SupportUtil.round2(totalAmount * percent / 100.0) - SupportUtil.round2(uiAmount / viewModel.selectedCurrencyRate) + SupportUtil.round2(uiAmount * viewModel.selectedCurrencyRate) } } diff --git a/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillScreen.kt b/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillScreen.kt index c1e32cd..aab3583 100644 --- a/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillScreen.kt +++ b/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillScreen.kt @@ -450,7 +450,10 @@ fun OwerSelectionSection( size = 32.dp ) Spacer(modifier = Modifier.width(8.dp)) - Text(member.name, modifier = Modifier.weight(1f)) + val weightSuffix = if (viewModel.hasDifferentWeights && member.weight != 1.0) { + " (x${member.weight.toString().removeSuffix(".0")})" + } else "" + Text("${member.name}$weightSuffix", modifier = Modifier.weight(1f)) if (isSelected || viewModel.splitMode != SplitMode.EVEN) { val focusManager = LocalFocusManager.current @@ -671,19 +674,115 @@ fun BillAdditionalDetailsSection( } @SuppressLint("ViewModelConstructorInComposable") -@Preview(showBackground = true) +@Preview(showBackground = true, name = "Standard Split") @Composable fun EditBillScreenPreview() { MaterialTheme { EditBillScreen( viewModel = EditBillViewModel().apply { what = "Pizza" - amount = "12.50" + amount = "12.00" mainCurrencyName = "EUR" members = listOf( DBMember(1, 0, 0, "Alice", true, 1.0, 0, null, null, null, null, null), DBMember(2, 0, 0, "Bob", true, 1.0, 0, null, null, null, null, null) ) + owersSelection[1] = true + owersSelection[2] = true + updateSplits() + }, + categories = emptyList(), + paymentModes = emptyList(), + onSave = {}, + onBack = {}, + onDateClick = {}, + onTimeClick = {}, + onScan = {} + ) + } +} + +@SuppressLint("ViewModelConstructorInComposable") +@Preview(showBackground = true, name = "Weighted Split") +@Composable +fun EditBillScreenWeightedPreview() { + MaterialTheme { + EditBillScreen( + viewModel = EditBillViewModel().apply { + what = "Weighted Pizza" + amount = "60.00" + mainCurrencyName = "EUR" + members = listOf( + DBMember(1, 0, 0, "Alice", true, 2.0, 0, null, null, null, null, null), + DBMember(2, 0, 0, "Bob", true, 1.0, 0, null, null, null, null, null), + DBMember(3, 0, 0, "Charlie", true, 1.0, 0, null, null, null, null, null) + ) + owersSelection[1] = true + owersSelection[2] = true + owersSelection[3] = true + updateSplits() + }, + categories = emptyList(), + paymentModes = emptyList(), + onSave = {}, + onBack = {}, + onDateClick = {}, + onTimeClick = {}, + onScan = {} + ) + } +} + +@SuppressLint("ViewModelConstructorInComposable") +@Preview(showBackground = true, name = "Custom Split (#)") +@Composable +fun EditBillScreenCustomPreview() { + MaterialTheme { + EditBillScreen( + viewModel = EditBillViewModel().apply { + what = "Custom Split Pizza" + amount = "60.00" + mainCurrencyName = "EUR" + members = listOf( + DBMember(1, 0, 0, "Alice", true, 1.0, 0, null, null, null, null, null), + DBMember(2, 0, 0, "Bob", true, 1.0, 0, null, null, null, null, null) + ) + splitMode = SplitMode.CUSTOM + owersSelection[1] = true + owersSelection[2] = true + owersCustomSplit[1] = "40.00" + owersCustomSplit[2] = "20.00" + }, + categories = emptyList(), + paymentModes = emptyList(), + onSave = {}, + onBack = {}, + onDateClick = {}, + onTimeClick = {}, + onScan = {} + ) + } +} + +@SuppressLint("ViewModelConstructorInComposable") +@Preview(showBackground = true, name = "Percent Split (%)") +@Composable +fun EditBillScreenPercentPreview() { + MaterialTheme { + EditBillScreen( + viewModel = EditBillViewModel().apply { + what = "Percent Split Pizza" + amount = "100.00" + mainCurrencyName = "EUR" + members = listOf( + DBMember(1, 0, 0, "Alice", true, 1.0, 0, null, null, null, null, null), + DBMember(2, 0, 0, "Bob", true, 1.0, 0, null, null, null, null, null) + ) + splitMode = SplitMode.PERCENT + owersSelection[1] = true + owersSelection[2] = true + owersPercentSplit[1] = "70" + owersPercentSplit[2] = "30" }, categories = emptyList(), paymentModes = emptyList(), diff --git a/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillViewModel.kt b/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillViewModel.kt index 6d8ba58..2fca26c 100644 --- a/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillViewModel.kt +++ b/app/src/main/java/net/helcel/cowspent/android/bill_edit/EditBillViewModel.kt @@ -61,18 +61,18 @@ class EditBillViewModel : ViewModel() { val amountAsDouble: Double get() = parseAmountFromUi(amount) - fun getEvenSplit(): Double { - val selectedOwersCount = owersSelection.count { it.value } - return if (selectedOwersCount > 0) SupportUtil.round2(amountAsDouble / selectedOwersCount) else 0.0 - } + val hasDifferentWeights: Boolean + get() = members.isNotEmpty() && members.any { it.weight != members[0].weight } fun updateSplits() { if (splitMode == SplitMode.EVEN) { - val even = getEvenSplit() - val evenStr = if (even == 0.0) "" else SupportUtil.round2(even).toString() + val selectedMembers = members.filter { owersSelection[it.id] == true } + val totalWeight = selectedMembers.sumOf { it.weight } + val uiAmount = amountAsDouble members.forEach { m -> if (owersSelection[m.id] == true) { - owersCustomSplit[m.id] = evenStr + val share = if (totalWeight > 0) (uiAmount * m.weight) / totalWeight else 0.0 + owersCustomSplit[m.id] = if (share == 0.0) "" else SupportUtil.round2(share).toString() } else { owersCustomSplit.remove(m.id) } @@ -180,7 +180,7 @@ class EditBillViewModel : ViewModel() { } fun getFinalAmount(): Double { - return SupportUtil.round2(amountAsDouble / selectedCurrencyRate) + return SupportUtil.round2(amountAsDouble * selectedCurrencyRate) } fun getFinalComment(): String { @@ -252,10 +252,9 @@ class EditBillViewModel : ViewModel() { if (selected) { // If we have metadata, the custom splits from DB are also converted. // We should show them as "Original" if possible? - // Actually, if we use metadata, we should probably store original splits too, - // but for now let's just reverse the rate for display. + // Reverse calculation for display: UI Part = DB Part / Rate val dbPart = customSplits[member.id]!! - val uiPart = if (selectedCurrencyRate != 1.0) dbPart * selectedCurrencyRate else dbPart + val uiPart = if (selectedCurrencyRate != 0.0) dbPart / selectedCurrencyRate else dbPart owersCustomSplit[member.id] = SupportUtil.round2(uiPart).toString() } } @@ -263,18 +262,18 @@ class EditBillViewModel : ViewModel() { // Even split logic splitMode = SplitMode.EVEN val billOwerIds = bill.billOwersIds - val selectedCount = billOwerIds.size + val selectedMembers = members.filter { billOwerIds.contains(it.id) } + val totalWeight = selectedMembers.sumOf { it.weight } // Use UI amount for even split calculation val uiAmount = amountAsDouble - val evenSplit = if (selectedCount > 0) uiAmount / selectedCount else 0.0 - val evenSplitStr = if (evenSplit == 0.0) "" else SupportUtil.round2(evenSplit).toString() for (member in members) { val selected = billOwerIds.contains(member.id) owersSelection[member.id] = selected if (selected) { - owersCustomSplit[member.id] = evenSplitStr + val share = if (totalWeight > 0) (uiAmount * member.weight) / totalWeight else 0.0 + owersCustomSplit[member.id] = if (share == 0.0) "" else SupportUtil.round2(share).toString() } } } diff --git a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesActivity.kt b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesActivity.kt index 437e7b4..ad30126 100644 --- a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesActivity.kt +++ b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesActivity.kt @@ -114,7 +114,8 @@ class ManageCurrenciesActivity : AppCompatActivity() { } private fun addOrUpdateCurrency() { - val exchangeRate = try { viewModel.newCurrencyRate.toDouble() } catch (_: Exception) { 0.0 } + val uiRate = try { viewModel.newCurrencyRate.toDouble() } catch (_: Exception) { 0.0 } + val exchangeRate = if (uiRate != 0.0) 1.0 / uiRate else 0.0 val currencyName = viewModel.newCurrencyName val editingId = viewModel.editingCurrencyId @@ -142,7 +143,8 @@ class ManageCurrenciesActivity : AppCompatActivity() { private fun startEditing(currency: DBCurrency) { viewModel.editingCurrencyId = currency.id viewModel.newCurrencyName = currency.name ?: "" - viewModel.newCurrencyRate = currency.exchangeRate.toString() + val uiRate = if (currency.exchangeRate != 0.0) 1.0 / currency.exchangeRate else 0.0 + viewModel.newCurrencyRate = uiRate.toString() } private fun cancelEditing() { diff --git a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesScreen.kt b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesScreen.kt index 030477a..9124992 100644 --- a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesScreen.kt +++ b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesScreen.kt @@ -304,7 +304,7 @@ fun CurrencyRow( modifier = Modifier.padding(horizontal = 8.dp) ) Text( - text = formatAmount(currency.exchangeRate), + text = formatAmount(if (currency.exchangeRate != 0.0) 1.0 / currency.exchangeRate else 0.0), style = MaterialTheme.typography.body1, fontWeight = FontWeight.ExtraBold, color = if (isEditing) MaterialTheme.colors.secondary else MaterialTheme.colors.onSurface