From 8115d48e4d3287aea81473ed124d04f8903da1d4 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sat, 18 Apr 2020 15:50:04 +0300 Subject: [PATCH] move high-level login out of the new transaction model to the adapter --- .../ui/activity/NewTransactionItemHolder.java | 6 +- .../activity/NewTransactionItemsAdapter.java | 330 ++++++++++++++++- .../ui/activity/NewTransactionModel.java | 339 +----------------- 3 files changed, 336 insertions(+), 339 deletions(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionItemHolder.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionItemHolder.java index 89c88731..3b6f2ecb 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionItemHolder.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionItemHolder.java @@ -185,7 +185,7 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder syncData(); Logger.debug("textWatcher", "syncData() returned, checking if transaction is submittable"); - adapter.model.checkTransactionSubmittable(adapter); + adapter.checkTransactionSubmittable(); Logger.debug("textWatcher", "done"); } }; @@ -215,7 +215,7 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder } if (syncData()) - adapter.model.checkTransactionSubmittable(adapter); + adapter.checkTransactionSubmittable(); } }; tvDescription.addTextChangedListener(tw); @@ -347,7 +347,7 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder currencyObserver = currency -> { setCurrency(currency); - adapter.model.checkTransactionSubmittable(adapter); + adapter.checkTransactionSubmittable(); }; currencyGapObserver = hasGap -> { diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionItemsAdapter.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionItemsAdapter.java index ef5947af..67a90ae1 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionItemsAdapter.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionItemsAdapter.java @@ -17,26 +17,34 @@ package net.ktnx.mobileledger.ui.activity; +import android.annotation.SuppressLint; import android.database.Cursor; import android.view.LayoutInflater; import android.view.ViewGroup; import android.widget.LinearLayout; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView; import net.ktnx.mobileledger.App; +import net.ktnx.mobileledger.BuildConfig; import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.async.DescriptionSelectedCallback; +import net.ktnx.mobileledger.model.Currency; import net.ktnx.mobileledger.model.Data; import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.model.LedgerTransactionAccount; import net.ktnx.mobileledger.model.MobileLedgerProfile; import net.ktnx.mobileledger.utils.Logger; +import net.ktnx.mobileledger.utils.Misc; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Locale; +import java.util.Set; import static net.ktnx.mobileledger.utils.Logger.debug; @@ -46,6 +54,7 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter 0) + return; + + int accounts = 0; + final BalanceForCurrency balance = new BalanceForCurrency(); + final String descriptionText = model.getDescription(); + boolean submittable = true; + final ItemsForCurrency itemsForCurrency = new ItemsForCurrency(); + final ItemsForCurrency itemsWithEmptyAmountForCurrency = + new ItemsForCurrency(); + final ItemsForCurrency itemsWithAccountAndEmptyAmountForCurrency = + new ItemsForCurrency(); + final ItemsForCurrency itemsWithEmptyAccountForCurrency = + new ItemsForCurrency(); + final ItemsForCurrency itemsWithAmountForCurrency = + new ItemsForCurrency(); + final ItemsForCurrency itemsWithAccountForCurrency = + new ItemsForCurrency(); + final ItemsForCurrency emptyRowsForCurrency = + new ItemsForCurrency(); + final List emptyRows = new ArrayList<>(); + + try { + if ((descriptionText == null) || descriptionText.trim() + .isEmpty()) + { + Logger.debug("submittable", "Transaction not submittable: missing description"); + submittable = false; + } + + for (int i = 0; i < model.items.size(); i++) { + NewTransactionModel.Item item = model.items.get(i); + + LedgerTransactionAccount acc = item.getAccount(); + String acc_name = acc.getAccountName() + .trim(); + String currName = acc.getCurrency(); + + itemsForCurrency.add(currName, item); + + if (acc_name.isEmpty()) { + itemsWithEmptyAccountForCurrency.add(currName, item); + + if (acc.isAmountSet()) { + // 2) each amount has account name + Logger.debug("submittable", String.format( + "Transaction not submittable: row %d has no account name, but" + + " has" + " amount %1.2f", i + 1, acc.getAmount())); + submittable = false; + } + else { + emptyRowsForCurrency.add(currName, item); + } + } + else { + accounts++; + itemsWithAccountForCurrency.add(currName, item); + } + + if (acc.isAmountSet()) { + itemsWithAmountForCurrency.add(currName, item); + balance.add(currName, acc.getAmount()); + } + else { + itemsWithEmptyAmountForCurrency.add(currName, item); + + if (!acc_name.isEmpty()) + itemsWithAccountAndEmptyAmountForCurrency.add(currName, item); + } + } + + // 1) has at least two account names + if (accounts < 2) { + if (accounts == 0) + Logger.debug("submittable", + "Transaction not submittable: no account " + "names"); + else if (accounts == 1) + Logger.debug("submittable", + "Transaction not submittable: only one account name"); + else + Logger.debug("submittable", + String.format("Transaction not submittable: only %d account names", + accounts)); + submittable = false; + } + + // 3) for each commodity: + // 3a) amount must balance to 0, or + // 3b) there must be exactly one empty amount (with account) + for (String balCurrency : itemsForCurrency.currencies()) { + float currencyBalance = balance.get(balCurrency); + if (Misc.isZero(currencyBalance)) { + // remove hints from all amount inputs in that currency + for (NewTransactionModel.Item item : model.items) { + if (Currency.equal(item.getCurrency(), balCurrency)) + item.setAmountHint(null); + } + } + else { + List list = + itemsWithAccountAndEmptyAmountForCurrency.getList(balCurrency); + int balanceReceiversCount = list.size(); + if (balanceReceiversCount != 1) { + if (BuildConfig.DEBUG) { + if (balanceReceiversCount == 0) + Logger.debug("submittable", String.format( + "Transaction not submittable [%s]: non-zero balance " + + "with no empty amounts with accounts", balCurrency)); + else + Logger.debug("submittable", String.format( + "Transaction not submittable [%s]: non-zero balance " + + "with multiple empty amounts with accounts", balCurrency)); + } + submittable = false; + } + + List emptyAmountList = + itemsWithEmptyAmountForCurrency.getList(balCurrency); + + // suggest off-balance amount to a row and remove hints on other rows + NewTransactionModel.Item receiver = null; + if (!list.isEmpty()) + receiver = list.get(0); + else if (!emptyAmountList.isEmpty()) + receiver = emptyAmountList.get(0); + + for (NewTransactionModel.Item item : model.items) { + if (!Currency.equal(item.getCurrency(), balCurrency)) + continue; + + if (item.equals(receiver)) { + if (BuildConfig.DEBUG) + Logger.debug("submittable", + String.format("Setting amount hint to %1.2f [%s]", + -currencyBalance, balCurrency)); + item.setAmountHint(String.format("%1.2f", -currencyBalance)); + } + else { + if (BuildConfig.DEBUG) + Logger.debug("submittable", + String.format("Resetting hint of '%s' [%s]", + (item.getAccount() == null) ? "" : item.getAccount() + .getAccountName(), + balCurrency)); + item.setAmountHint(null); + } + } + } + } + + // 5) a row with an empty account name or empty amount is guaranteed to exist for + // each commodity + for (String balCurrency : balance.currencies()) { + int currEmptyRows = itemsWithEmptyAccountForCurrency.size(balCurrency); + int currRows = itemsForCurrency.size(balCurrency); + int currAccounts = itemsWithAccountForCurrency.size(balCurrency); + int currAmounts = itemsWithAmountForCurrency.size(balCurrency); + if ((currEmptyRows == 0) && + ((currRows == currAccounts) || (currRows == currAmounts))) + { + // perhaps there already is an unused empty row for another currency that + // is not used? +// boolean foundIt = false; +// for (Item item : emptyRows) { +// Currency itemCurrency = item.getCurrency(); +// String itemCurrencyName = +// (itemCurrency == null) ? "" : itemCurrency.getName(); +// if (Misc.isZero(balance.get(itemCurrencyName))) { +// item.setCurrency(Currency.loadByName(balCurrency)); +// item.setAmountHint( +// String.format("%1.2f", -balance.get(balCurrency))); +// foundIt = true; +// break; +// } +// } +// +// if (!foundIt) + addRow(balCurrency); + } + } + + // drop extra empty rows, not needed + for (String currName : emptyRowsForCurrency.currencies()) { + List emptyItems = emptyRowsForCurrency.getList(currName); + while ((model.items.size() > 2) && (emptyItems.size() > 1)) { + NewTransactionModel.Item item = emptyItems.get(1); + emptyItems.remove(1); + model.removeRow(item, this); + } + + // unused currency, remove last item (which is also an empty one) + if ((model.items.size() > 2) && (emptyItems.size() == 1)) { + List currItems = itemsForCurrency.getList(currName); + + if (currItems.size() == 1) { + NewTransactionModel.Item item = emptyItems.get(0); + model.removeRow(item, this); + } + } + } + + // 6) at least two rows need to be present in the ledger + while (model.items.size() < 2) + addRow(); + + + debug("submittable", submittable ? "YES" : "NO"); + model.isSubmittable.setValue(submittable); + + if (BuildConfig.DEBUG) { + debug("submittable", "== Dump of all items"); + for (int i = 0; i < model.items.size(); i++) { + NewTransactionModel.Item item = model.items.get(i); + LedgerTransactionAccount acc = item.getAccount(); + debug("submittable", String.format("Item %2d: [%4.2f(%s) %s] %s ; %s", i, + acc.isAmountSet() ? acc.getAmount() : 0, + item.isAmountHintSet() ? item.getAmountHint() : "ø", acc.getCurrency(), + acc.getAccountName(), acc.getComment())); + } + } + } + catch (NumberFormatException e) { + debug("submittable", "NO (because of NumberFormatException)"); + model.isSubmittable.setValue(false); + } + catch (Exception e) { + e.printStackTrace(); + debug("submittable", "NO (because of an Exception)"); + model.isSubmittable.setValue(false); + } + } + private class BalanceForCurrency { + private HashMap hashMap = new HashMap<>(); + float get(String currencyName) { + Float f = hashMap.get(currencyName); + if (f == null) { + f = 0f; + hashMap.put(currencyName, f); + } + return f; + } + void add(String currencyName, float amount) { + hashMap.put(currencyName, get(currencyName) + amount); + } + Set currencies() { + return hashMap.keySet(); + } + boolean containsCurrency(String currencyName) { + return hashMap.containsKey(currencyName); + } + } + + private class ItemsForCurrency { + private HashMap> hashMap = new HashMap<>(); + @NonNull + List getList(@Nullable String currencyName) { + List list = hashMap.get(currencyName); + if (list == null) { + list = new ArrayList<>(); + hashMap.put(currencyName, list); + } + return list; + } + void add(@Nullable String currencyName, @NonNull NewTransactionModel.Item item) { + getList(currencyName).add(item); + } + int size(@Nullable String currencyName) { + return this.getList(currencyName) + .size(); + } + Set currencies() { + return hashMap.keySet(); + } + } } diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionModel.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionModel.java index 34d3a849..ed283b21 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionModel.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionModel.java @@ -17,23 +17,17 @@ package net.ktnx.mobileledger.ui.activity; -import android.annotation.SuppressLint; - import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModel; -import net.ktnx.mobileledger.BuildConfig; import net.ktnx.mobileledger.model.Currency; import net.ktnx.mobileledger.model.Data; import net.ktnx.mobileledger.model.LedgerTransactionAccount; import net.ktnx.mobileledger.model.MobileLedgerProfile; -import net.ktnx.mobileledger.utils.Logger; -import net.ktnx.mobileledger.utils.Misc; import org.jetbrains.annotations.NotNull; @@ -42,52 +36,31 @@ import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; import java.util.Locale; -import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static net.ktnx.mobileledger.utils.Logger.debug; - public class NewTransactionModel extends ViewModel { private static final Pattern reYMD = Pattern.compile("^\\s*(\\d+)\\d*/\\s*(\\d+)\\s*/\\s*(\\d+)\\s*$"); private static final Pattern reMD = Pattern.compile("^\\s*(\\d+)\\s*/\\s*(\\d+)\\s*$"); private static final Pattern reD = Pattern.compile("\\s*(\\d+)\\s*$"); final MutableLiveData showCurrency = new MutableLiveData<>(false); + final ArrayList items = new ArrayList<>(); + final MutableLiveData isSubmittable = new MutableLiveData<>(false); private final Item header = new Item(this, null, ""); private final Item trailer = new Item(this); - private final ArrayList items = new ArrayList<>(); - private final MutableLiveData isSubmittable = new MutableLiveData<>(false); private final MutableLiveData focusedItem = new MutableLiveData<>(0); private final MutableLiveData accountCount = new MutableLiveData<>(0); private final MutableLiveData simulateSave = new MutableLiveData<>(false); - /* - Slots contain lists of items, all using the same currency, including the possible - item with no account/amount that is used to help balancing the transaction - - There is one slot per currency - */ - private final HashMap> slots = new HashMap<>(); - private int checkHoldCounter = 0; private boolean observingDataProfile; private Observer profileObserver = profile -> showCurrency.postValue(profile.getShowCommodityByDefault()); - public void observeDataProfile(LifecycleOwner activity) { + void observeDataProfile(LifecycleOwner activity) { if (!observingDataProfile) Data.profile.observe(activity, profileObserver); observingDataProfile = true; } - void holdSubmittableChecks() { - checkHoldCounter++; - } - void releaseSubmittableChecks() { - if (checkHoldCounter == 0) - throw new RuntimeException("Asymmetrical call to releaseSubmittableChecks"); - checkHoldCounter--; - } boolean getSimulateSave() { return simulateSave.getValue(); } @@ -171,248 +144,7 @@ public class NewTransactionModel extends ViewModel { return trailer; } - /* - A transaction is submittable if: - 0) has description - 1) has at least two account names - 2) each row with amount has account name - 3) for each commodity: - 3a) amounts must balance to 0, or - 3b) there must be exactly one empty amount (with account) - 4) empty accounts with empty amounts are ignored - Side effects: - 5) a row with an empty account name or empty amount is guaranteed to exist for each commodity - 6) at least two rows need to be present in the ledger - - */ - @SuppressLint("DefaultLocale") - void checkTransactionSubmittable(NewTransactionItemsAdapter adapter) { - if (checkHoldCounter > 0) - return; - - int accounts = 0; - final BalanceForCurrency balance = new BalanceForCurrency(); - final String descriptionText = getDescription(); - boolean submittable = true; - final ItemsForCurrency itemsForCurrency = new ItemsForCurrency(); - final ItemsForCurrency itemsWithEmptyAmountForCurrency = new ItemsForCurrency(); - final ItemsForCurrency itemsWithAccountAndEmptyAmountForCurrency = new ItemsForCurrency(); - final ItemsForCurrency itemsWithEmptyAccountForCurrency = new ItemsForCurrency(); - final ItemsForCurrency itemsWithAmountForCurrency = new ItemsForCurrency(); - final ItemsForCurrency itemsWithAccountForCurrency = new ItemsForCurrency(); - final ItemsForCurrency emptyRowsForCurrency = new ItemsForCurrency(); - final List emptyRows = new ArrayList<>(); - - try { - if ((descriptionText == null) || descriptionText.trim() - .isEmpty()) - { - Logger.debug("submittable", "Transaction not submittable: missing description"); - submittable = false; - } - - for (int i = 0; i < this.items.size(); i++) { - Item item = this.items.get(i); - - LedgerTransactionAccount acc = item.getAccount(); - String acc_name = acc.getAccountName() - .trim(); - String currName = acc.getCurrency(); - - itemsForCurrency.add(currName, item); - - if (acc_name.isEmpty()) { - itemsWithEmptyAccountForCurrency.add(currName, item); - - if (acc.isAmountSet()) { - // 2) each amount has account name - Logger.debug("submittable", String.format( - "Transaction not submittable: row %d has no account name, but" + - " has" + " amount %1.2f", i + 1, acc.getAmount())); - submittable = false; - } - else { - emptyRowsForCurrency.add(currName, item); - } - } - else { - accounts++; - itemsWithAccountForCurrency.add(currName, item); - } - - if (acc.isAmountSet()) { - itemsWithAmountForCurrency.add(currName, item); - balance.add(currName, acc.getAmount()); - } - else { - itemsWithEmptyAmountForCurrency.add(currName, item); - - if (!acc_name.isEmpty()) - itemsWithAccountAndEmptyAmountForCurrency.add(currName, item); - } - } - - // 1) has at least two account names - if (accounts < 2) { - if (accounts == 0) - Logger.debug("submittable", - "Transaction not submittable: no account " + "names"); - else if (accounts == 1) - Logger.debug("submittable", - "Transaction not submittable: only one account name"); - else - Logger.debug("submittable", - String.format("Transaction not submittable: only %d account names", - accounts)); - submittable = false; - } - - // 3) for each commodity: - // 3a) amount must balance to 0, or - // 3b) there must be exactly one empty amount (with account) - for (String balCurrency : itemsForCurrency.currencies()) { - float currencyBalance = balance.get(balCurrency); - if (Misc.isZero(currencyBalance)) { - // remove hints from all amount inputs in that currency - for (Item item : items) { - if (Currency.equal(item.getCurrency(), balCurrency)) - item.setAmountHint(null); - } - } - else { - List list = - itemsWithAccountAndEmptyAmountForCurrency.getList(balCurrency); - int balanceReceiversCount = list.size(); - if (balanceReceiversCount != 1) { - if (BuildConfig.DEBUG) { - if (balanceReceiversCount == 0) - Logger.debug("submittable", String.format( - "Transaction not submittable [%s]: non-zero balance " + - "with no empty amounts with accounts", balCurrency)); - else - Logger.debug("submittable", String.format( - "Transaction not submittable [%s]: non-zero balance " + - "with multiple empty amounts with accounts", balCurrency)); - } - submittable = false; - } - - List emptyAmountList = - itemsWithEmptyAmountForCurrency.getList(balCurrency); - - // suggest off-balance amount to a row and remove hints on other rows - Item receiver = null; - if (!list.isEmpty()) - receiver = list.get(0); - else if (!emptyAmountList.isEmpty()) - receiver = emptyAmountList.get(0); - - for (Item item : items) { - if (!Currency.equal(item.getCurrency(), balCurrency)) - continue; - - if (item.equals(receiver)) { - if (BuildConfig.DEBUG) - Logger.debug("submittable", - String.format("Setting amount hint to %1.2f [%s]", - -currencyBalance, balCurrency)); - item.setAmountHint(String.format("%1.2f", -currencyBalance)); - } - else { - if (BuildConfig.DEBUG) - Logger.debug("submittable", - String.format("Resetting hint of '%s' [%s]", - (item.getAccount() == null) ? "" : item.getAccount() - .getAccountName(), - balCurrency)); - item.setAmountHint(null); - } - } - } - } - - // 5) a row with an empty account name or empty amount is guaranteed to exist for - // each commodity - for (String balCurrency : balance.currencies()) { - int currEmptyRows = itemsWithEmptyAccountForCurrency.size(balCurrency); - int currRows = itemsForCurrency.size(balCurrency); - int currAccounts = itemsWithAccountForCurrency.size(balCurrency); - int currAmounts = itemsWithAmountForCurrency.size(balCurrency); - if ((currEmptyRows == 0) && - ((currRows == currAccounts) || (currRows == currAmounts))) - { - // perhaps there already is an unused empty row for another currency that - // is not used? -// boolean foundIt = false; -// for (Item item : emptyRows) { -// Currency itemCurrency = item.getCurrency(); -// String itemCurrencyName = -// (itemCurrency == null) ? "" : itemCurrency.getName(); -// if (Misc.isZero(balance.get(itemCurrencyName))) { -// item.setCurrency(Currency.loadByName(balCurrency)); -// item.setAmountHint( -// String.format("%1.2f", -balance.get(balCurrency))); -// foundIt = true; -// break; -// } -// } -// -// if (!foundIt) - adapter.addRow(balCurrency); - } - } - - // drop extra empty rows, not needed - for (String currName : emptyRowsForCurrency.currencies()) { - List emptyItems = emptyRowsForCurrency.getList(currName); - while ((this.items.size() > 2) && (emptyItems.size() > 1)) { - Item item = emptyItems.get(1); - emptyItems.remove(1); - removeRow(item, adapter); - } - - // unused currency, remove last item (which is also an empty one) - if ((items.size() > 2) && (emptyItems.size() == 1)) { - List currItems = itemsForCurrency.getList(currName); - - if (currItems.size() == 1) { - Item item = emptyItems.get(0); - removeRow(item, adapter); - } - } - } - - // 6) at least two rows need to be present in the ledger - while (this.items.size() < 2) - adapter.addRow(); - - - debug("submittable", submittable ? "YES" : "NO"); - isSubmittable.setValue(submittable); - - if (BuildConfig.DEBUG) { - debug("submittable", "== Dump of all items"); - for (int i = 0; i < items.size(); i++) { - Item item = items.get(i); - LedgerTransactionAccount acc = item.getAccount(); - debug("submittable", String.format("Item %2d: [%4.2f(%s) %s] %s ; %s", i, - acc.isAmountSet() ? acc.getAmount() : 0, - item.isAmountHintSet() ? item.getAmountHint() : "ø", acc.getCurrency(), - acc.getAccountName(), acc.getComment())); - } - } - } - catch (NumberFormatException e) { - debug("submittable", "NO (because of NumberFormatException)"); - isSubmittable.setValue(false); - } - catch (Exception e) { - e.printStackTrace(); - debug("submittable", "NO (because of an Exception)"); - isSubmittable.setValue(false); - } - } - private void removeRow(Item item, NewTransactionItemsAdapter adapter) { + void removeRow(Item item, NewTransactionItemsAdapter adapter) { int pos = items.indexOf(item); items.remove(pos); if (adapter != null) { @@ -459,76 +191,15 @@ public class NewTransactionModel extends ViewModel { void toggleCurrencyVisible() { showCurrency.setValue(!showCurrency.getValue()); } - public void setItemCurrency(Item item, Currency newCurrency, - NewTransactionItemsAdapter adapter) { - Currency oldCurrency = item.getCurrency(); - if (!Currency.equal(newCurrency, oldCurrency)) { - holdSubmittableChecks(); - try { - item.setCurrency(newCurrency); -// for (Item i : items) { -// if (Currency.equal(i.getCurrency(), oldCurrency)) -// i.setCurrency(newCurrency); -// } - } - finally { - releaseSubmittableChecks(); - } - - checkTransactionSubmittable(adapter); - } - } enum ItemType {generalData, transactionRow, bottomFiller} enum FocusedElement {Account, Comment, Amount} - private class ItemsForCurrency { - private HashMap> hashMap = new HashMap<>(); - @NonNull - List getList(@Nullable String currencyName) { - List list = hashMap.get(currencyName); - if (list == null) { - list = new ArrayList<>(); - hashMap.put(currencyName, list); - } - return list; - } - void add(@Nullable String currencyName, @NonNull Item item) { - getList(currencyName).add(item); - } - int size(@Nullable String currencyName) { - return this.getList(currencyName) - .size(); - } - Set currencies() { - return hashMap.keySet(); - } - } //========================================================================================== - private class BalanceForCurrency { - private HashMap hashMap = new HashMap<>(); - float get(String currencyName) { - Float f = hashMap.get(currencyName); - if (f == null) { - f = 0f; - hashMap.put(currencyName, f); - } - return f; - } - void add(String currencyName, float amount) { - hashMap.put(currencyName, get(currencyName) + amount); - } - Set currencies() { - return hashMap.keySet(); - } - boolean containsCurrency(String currencyName) { - return hashMap.containsKey(currencyName); - } - } - class Item { + static class Item { private ItemType type; private MutableLiveData date = new MutableLiveData<>(); private MutableLiveData description = new MutableLiveData<>(); -- 2.39.2