X-Git-Url: https://git.ktnx.net/?p=mobile-ledger.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fnet%2Fktnx%2Fmobileledger%2Fui%2Fnew_transaction%2FNewTransactionModel.java;h=d8f387b72696983f1fe9f87d0ae12e0a5b4d1be8;hp=b3e9eeb3c8b6b26d5a7be7b0aaa911fdb9cb9f92;hb=dd7e3b83b17546504605f93b3a462d1a1be3b382;hpb=9b4d7761927317f74b68ca22e53b7d60bbabf2e3 diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionModel.java b/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionModel.java index b3e9eeb3..d8f387b7 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionModel.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionModel.java @@ -1,5 +1,5 @@ /* - * Copyright © 2021 Damyan Ivanov. + * Copyright © 2022 Damyan Ivanov. * This file is part of MoLe. * MoLe is free software: you can distribute it and/or modify it * under the term of the GNU General Public License as published by @@ -18,6 +18,7 @@ package net.ktnx.mobileledger.ui.new_transaction; import android.annotation.SuppressLint; +import android.os.Build; import android.text.TextUtils; import androidx.annotation.NonNull; @@ -74,13 +75,14 @@ public class NewTransactionModel extends ViewModel { private final AtomicInteger busyCounter = new AtomicInteger(0); private final MutableLiveData busyFlag = new InertMutableLiveData<>(false); private final Observer profileObserver = profile -> { - showCurrency.postValue(profile.getShowCommodityByDefault()); - showComments.postValue(profile.getShowCommentsByDefault()); + if (profile != null) { + showCurrency.postValue(profile.getShowCommodityByDefault()); + showComments.postValue(profile.getShowCommentsByDefault()); + } }; private final MutableLiveData focusInfo = new MutableLiveData<>(); private boolean observingDataProfile; public NewTransactionModel() { - reset(); } public LiveData getShowCurrency() { return showCurrency; @@ -162,7 +164,7 @@ public class NewTransactionModel extends ViewModel { return copy; } private List shallowCopyList() { - return new ArrayList<>(items.getValue()); + return new ArrayList<>(Objects.requireNonNull(items.getValue())); } LiveData getShowComments() { return showComments; @@ -369,7 +371,7 @@ public class NewTransactionModel extends ViewModel { noteFocusChanged(fi.position - 1, fi.element); setItems(newList); } - void noteFocusChanged(int position, FocusedElement element) { + void noteFocusChanged(int position, @Nullable FocusedElement element) { FocusInfo present = focusInfo.getValue(); if (present == null || present.position != position || present.element != element) focusInfo.setValue(new FocusInfo(position, element)); @@ -442,14 +444,14 @@ public class NewTransactionModel extends ViewModel { LedgerTransaction tr = head.asLedgerTransaction(); tr.setComment(head.getComment()); - LedgerTransactionAccount emptyAmountAccount = null; - float emptyAmountAccountBalance = 0; + HashMap> emptyAmountAccounts = new HashMap<>(); + HashMap emptyAmountAccountBalance = new HashMap<>(); for (int i = 1; i < list.size(); i++) { TransactionAccount item = list.get(i) .toTransactionAccount(); + String currency = item.getCurrency(); LedgerTransactionAccount acc = new LedgerTransactionAccount(item.getAccountName() - .trim(), - item.getCurrency()); + .trim(), currency); if (acc.getAccountName() .isEmpty()) continue; @@ -458,17 +460,52 @@ public class NewTransactionModel extends ViewModel { if (item.isAmountSet()) { acc.setAmount(item.getAmount()); - emptyAmountAccountBalance += item.getAmount(); + Float emptyCurrBalance = emptyAmountAccountBalance.get(currency); + if (emptyCurrBalance == null) { + emptyAmountAccountBalance.put(currency, item.getAmount()); + } + else { + emptyAmountAccountBalance.put(currency, emptyCurrBalance + item.getAmount()); + } } else { - emptyAmountAccount = acc; + List emptyCurrAccounts = + emptyAmountAccounts.get(currency); + if (emptyCurrAccounts == null) + emptyAmountAccounts.put(currency, emptyCurrAccounts = new ArrayList<>()); + emptyCurrAccounts.add(acc); } tr.addAccount(acc); } - if (emptyAmountAccount != null) - emptyAmountAccount.setAmount(-emptyAmountAccountBalance); + if (emptyAmountAccounts.size() > 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + emptyAmountAccounts.forEach((currency, accounts) -> { + if (accounts.size() != 1) + throw new RuntimeException(String.format(Locale.US, + "Should not happen: approved transaction has %d accounts for " + + "currency %s", accounts.size(), currency)); + accounts.get(0) + .setAmount(-Objects.requireNonNull( + emptyAmountAccountBalance.get(currency))); + }); + } + else { + for (String currency : emptyAmountAccounts.keySet()) { + List accounts = + Objects.requireNonNull(emptyAmountAccounts.get(currency)); + + if (accounts.size() != 1) + throw new RuntimeException(String.format(Locale.US, + "Should not happen: approved transaction has %d accounts for " + + "currency %s", accounts.size(), currency)); + accounts.get(0) + .setAmount(-Objects.requireNonNull( + emptyAmountAccountBalance.get(currency))); + } + } + } return tr; } @@ -495,10 +532,11 @@ public class NewTransactionModel extends ViewModel { int singleNegativeIndex = -1; int singlePositiveIndex = -1; int negativeCount = 0; + boolean hasCurrency = false; for (int i = 0; i < accounts.size(); i++) { LedgerTransactionAccount acc = accounts.get(i); - TransactionAccount item = - new TransactionAccount(acc.getAccountName(), acc.getCurrency()); + TransactionAccount item = new TransactionAccount(acc.getAccountName(), + Misc.nullIsEmpty(acc.getCurrency())); newList.add(item); item.setAccountName(acc.getAccountName()); @@ -524,6 +562,10 @@ public class NewTransactionModel extends ViewModel { } else item.resetAmount(); + + if (item.getCurrency() + .length() > 0) + hasCurrency = true; } if (BuildConfig.DEBUG) dumpItemList("Loaded previous transaction", newList); @@ -537,9 +579,12 @@ public class NewTransactionModel extends ViewModel { moveItemLast(newList, singlePositiveIndex); } + final boolean foundTransactionHasCurrency = hasCurrency; Misc.onMainThread(() -> { setItems(newList); noteFocusChanged(1, FocusedElement.Amount); + if (foundTransactionHasCurrency) + showCurrency.setValue(true); }); } /** @@ -626,15 +671,14 @@ public class NewTransactionModel extends ViewModel { itemsWithAccountForCurrency.add(currName, item); } - if (item.isAmountSet()) { + if (item.isAmountSet() && item.isAmountValid()) { itemsWithAmountForCurrency.add(currName, item); balance.add(currName, item.getAmount()); } else { if (!item.isAmountValid()) { Logger.debug("submittable", - String.format("Not submittable: row %d has an invalid amount", - i + 1)); + String.format("Not submittable: row %d has an invalid amount", i)); submittable = false; hasInvalidAmount = true; } @@ -725,13 +769,13 @@ public class NewTransactionModel extends ViewModel { continue; if (item == receiver) { - final String hint = String.format("%1.2f", -currencyBalance); + final String hint = Data.formatNumber(-currencyBalance); if (!acc.isAmountHintSet() || !Misc.equalStrings(acc.getAmountHint(), hint)) { Logger.debug("submittable", - String.format("Setting amount hint of {%s} to %s [%s]", - acc.toString(), hint, balCurrency)); + String.format("Setting amount hint of {%s} to %s [%s]", acc, + hint, balCurrency)); acc.setAmountHint(hint); listChanged = true; } @@ -772,7 +816,7 @@ public class NewTransactionModel extends ViewModel { // if (Misc.isZero(balance.get(itemCurrencyName))) { // item.setCurrency(Currency.loadByName(balCurrency)); // item.setAmountHint( -// String.format("%1.2f", -balance.get(balCurrency))); +// Data.formatNumber(-balance.get(balCurrency))); // foundIt = true; // break; // } @@ -782,7 +826,7 @@ public class NewTransactionModel extends ViewModel { final TransactionAccount newAcc = new TransactionAccount("", balCurrency); final float bal = balance.get(balCurrency); if (!Misc.isZero(bal) && currAmounts == currRows) - newAcc.setAmountHint(String.format("%4.2f", -bal)); + newAcc.setAmountHint(Data.formatNumber(-bal)); Logger.debug("submittable", String.format("Adding new item with %s for currency %s", newAcc.getAmountHint(), balCurrency)); @@ -896,7 +940,7 @@ public class NewTransactionModel extends ViewModel { public static class FocusInfo { int position; FocusedElement element; - public FocusInfo(int position, FocusedElement element) { + public FocusInfo(int position, @Nullable FocusedElement element) { this.position = position; this.element = element; } @@ -1026,7 +1070,7 @@ public class NewTransactionModel extends ViewModel { b.append(String.format(" '%s'", description)); if (date != null) - b.append(String.format("@%s", date.toString())); + b.append(String.format("@%s", date)); if (!TextUtils.isEmpty(comment)) b.append(String.format(" /%s/", comment)); @@ -1067,10 +1111,13 @@ public class NewTransactionModel extends ViewModel { private String accountName; private String amountHint; private String comment; + @NotNull private String currency = ""; private float amount; private boolean amountSet; private boolean amountValid = true; + @NotNull + private String amountText = ""; private FocusedElement focusedElement = FocusedElement.Account; private boolean amountHintIsSet = false; private boolean isLast = false; @@ -1082,6 +1129,7 @@ public class NewTransactionModel extends ViewModel { amountSet = origin.amountSet; amountHint = origin.amountHint; amountHintIsSet = origin.amountHintIsSet; + amountText = origin.amountText; comment = origin.comment; currency = origin.currency; amountValid = origin.amountValid; @@ -1089,11 +1137,6 @@ public class NewTransactionModel extends ViewModel { isLast = origin.isLast; accountNameCursorPosition = origin.accountNameCursorPosition; } - public TransactionAccount(LedgerTransactionAccount account) { - super(); - currency = account.getCurrency(); - amount = account.getAmount(); - } public TransactionAccount(String accountName) { super(); this.accountName = accountName; @@ -1103,6 +1146,46 @@ public class NewTransactionModel extends ViewModel { this.accountName = accountName; this.currency = currency; } + public @NotNull String getAmountText() { + return amountText; + } + public void setAmountText(@NotNull String amountText) { + this.amountText = amountText; + } + public boolean setAndCheckAmountText(@NotNull String amountText) { + String amtText = amountText.trim(); + this.amountText = amtText; + + boolean significantChange = false; + + if (amtText.isEmpty()) { + if (amountSet) { + significantChange = true; + } + resetAmount(); + } + else { + try { + amtText = amtText.replace(Data.getDecimalSeparator(), Data.decimalDot); + final float parsedAmount = Float.parseFloat(amtText); + if (!amountSet || !amountValid || !Misc.equalFloats(parsedAmount, amount)) + significantChange = true; + amount = parsedAmount; + amountSet = true; + amountValid = true; + } + catch (NumberFormatException e) { + Logger.debug("new-trans", String.format( + "assuming amount is not set due to number format exception. " + + "input was '%s'", amtText)); + if (amountValid) // it was valid and now it's not + significantChange = true; + amountValid = false; + } + } + + return significantChange; + } public boolean isLast() { return isLast; } @@ -1123,9 +1206,13 @@ public class NewTransactionModel extends ViewModel { public void setAmount(float amount) { this.amount = amount; amountSet = true; + amountValid = true; + amountText = Data.formatNumber(amount); } public void resetAmount() { amountSet = false; + amountValid = true; + amountText = ""; } @Override public ItemType getType() { @@ -1175,6 +1262,7 @@ public class NewTransactionModel extends ViewModel { } @SuppressLint("DefaultLocale") @Override + @NotNull public String toString() { StringBuilder b = new StringBuilder(); b.append(String.format("id:%d/%s", id, Integer.toHexString(hashCode()))); @@ -1182,9 +1270,13 @@ public class NewTransactionModel extends ViewModel { b.append(String.format(" acc'%s'", accountName)); if (amountSet) - b.append(String.format(" %4.2f", amount)); + b.append(amountText) + .append(" [") + .append(amountValid ? "valid" : "invalid") + .append("] ") + .append(String.format(Locale.ROOT, " {raw %4.2f}", amount)); else if (amountHintIsSet) - b.append(String.format(" (%s)", amountHint)); + b.append(String.format(" (hint %s)", amountHint)); if (!TextUtils.isEmpty(currency)) b.append(" ") @@ -1204,7 +1296,9 @@ public class NewTransactionModel extends ViewModel { boolean equal = Misc.equalStrings(accountName, other.accountName); equal = equal && Misc.equalStrings(comment, other.comment) && - (amountSet ? other.amountSet && amount == other.amount : !other.amountSet); + (amountSet ? other.amountSet && amountValid == other.amountValid && + Misc.equalStrings(amountText, other.amountText) + : !other.amountSet); // compare amount hint only if there is no amount if (!amountSet) @@ -1214,8 +1308,7 @@ public class NewTransactionModel extends ViewModel { equal = equal && Misc.equalStrings(currency, other.currency) && isLast == other.isLast; Logger.debug("new-trans", - String.format("Comparing {%s} and {%s}: %s", this.toString(), other.toString(), - equal)); + String.format("Comparing {%s} and {%s}: %s", this, other, equal)); return equal; } public int getAccountNameCursorPosition() {