Fix currency and added user weighting
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user