From a1f5cf187a6bc2731aa1ed057d3d11fccc5de2c4 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Thu, 14 May 2020 13:50:12 +0300 Subject: [PATCH] posting-level flag for amount validity; drop custom amount text filter the custom text filter in amount inputs seems to break with some Samsung keyboards. with a flag that is honoured by the code that checks for transaction submittability it is better, and allows for a nice warning icon on invalid input --- .../model/LedgerTransactionAccount.java | 9 +++++ .../ui/activity/NewTransactionItemHolder.java | 36 +++++++++---------- .../activity/NewTransactionItemsAdapter.java | 7 +++- .../ui/activity/NewTransactionModel.java | 13 +++++++ .../ic_error_outline_black_24dp.xml | 23 ++++++++++++ .../main/res/layout/new_transaction_row.xml | 2 +- 6 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 app/src/main/res/drawable-anydpi-v21/ic_error_outline_black_24dp.xml diff --git a/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransactionAccount.java b/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransactionAccount.java index c97b7e4a..1791cfbc 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransactionAccount.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransactionAccount.java @@ -30,11 +30,13 @@ public class LedgerTransactionAccount { private boolean amountSet = false; private String currency; private String comment; + private boolean amountValid = true; public LedgerTransactionAccount(String accountName, float amount, String currency, String comment) { this.setAccountName(accountName); this.amount = amount; this.amountSet = true; + this.amountValid = true; this.currency = Misc.emptyIsNull(currency); this.comment = Misc.emptyIsNull(comment); } @@ -51,6 +53,7 @@ public class LedgerTransactionAccount { setComment(origin.getComment()); if (origin.isAmountSet()) setAmount(origin.getAmount()); + amountValid = origin.amountValid; currency = origin.getCurrency(); } public String getComment() { @@ -78,13 +81,19 @@ public class LedgerTransactionAccount { public void setAmount(float account_amount) { this.amount = account_amount; this.amountSet = true; + this.amountValid = true; } public void resetAmount() { this.amountSet = false; + this.amountValid = true; + } + public void invalidateAmount() { + this.amountValid = false; } public boolean isAmountSet() { return amountSet; } + public boolean isAmountValid() { return amountValid; } public String getCurrency() { return currency; } 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 3e6cab36..a3dd711d 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 @@ -92,6 +92,7 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder private Observer currencyObserver; private Observer showCurrencyObserver; private Observer commentObserver; + private Observer amountValidityObserver; private boolean inUpdate = false; private boolean syncingData = false; private View commentButton; @@ -126,10 +127,10 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder }); transactionCommentLayout.findViewById(R.id.comment_button) - .setOnClickListener(v -> { - tvTransactionComment.setVisibility(View.VISIBLE); - tvTransactionComment.requestFocus(); - }); + .setOnClickListener(v -> { + tvTransactionComment.setVisibility(View.VISIBLE); + tvTransactionComment.requestFocus(); + }); mProfile = Data.profile.getValue(); if (mProfile == null) @@ -224,19 +225,6 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - // only one decimal separator is allowed - // plus and minus are allowed only at the beginning - String allowed = "0123456789"; - String val = s.toString(); - Logger.debug("input", val); - if (val.isEmpty() || (tvAmount.getSelectionStart() == 0)) - allowed += "-"; - if (!val.contains(decimalSeparator) && !val.contains(decimalDot)) - allowed += decimalSeparator + decimalDot; - - tvAmount.setKeyListener(DigitsKeyListener.getInstance(allowed)); - } if (syncData()) adapter.checkTransactionSubmittable(); @@ -445,6 +433,12 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder transactionCommentLayout.setVisibility(show ? View.VISIBLE : View.GONE); }; + + amountValidityObserver = valid -> { + tvAmount.setCompoundDrawablesRelativeWithIntrinsicBounds( + valid ? 0 : R.drawable.ic_error_outline_black_24dp, 0, 0, 0); + tvAmount.setMinEms(valid ? 4 : 5); + }; } private void commentFocusChanged(View layout, TextView textView, boolean hasFocus) { int textColor; @@ -574,18 +568,20 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder if (amount.isEmpty()) { account.resetAmount(); -// account.setCurrency(null); + item.validateAmount(); } else { try { amount = amount.replace(decimalSeparator, decimalDot); account.setAmount(Float.parseFloat(amount)); + item.validateAmount(); } catch (NumberFormatException e) { Logger.debug("new-trans", String.format( "assuming amount is not set due to number format exception. " + "input was '%s'", amount)); - account.resetAmount(); + account.invalidateAmount(); + item.invalidateAmount(); } final String curr = String.valueOf(tvCurrency.getText()); if (curr.equals(tvCurrency.getContext() @@ -641,6 +637,7 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder this.item.getModel().showCurrency.removeObserver(showCurrencyObserver); this.item.stopObservingComment(commentObserver); this.item.getModel().showComments.removeObserver(showCommentsObserver); + this.item.stopObservingAmountValidity(amountValidityObserver); this.item = null; } @@ -708,6 +705,7 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder item.observeComment(activity, commentObserver); item.getModel() .observeAccountCount(activity, accountCountObserver); + item.observeAmountValidity(activity, amountValidityObserver); break; } } 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 5caa38a5..c684b79f 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 @@ -473,7 +473,12 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter comment = new MutableLiveData<>(null); private MutableLiveData currency = new MutableLiveData<>(null); + private MutableLiveData amountValid = new MutableLiveData<>(true); private boolean amountHintIsSet = false; Item(NewTransactionModel model) { this.model = model; @@ -489,5 +490,17 @@ public class NewTransactionModel extends ViewModel { boolean isAmountHintSet() { return amountHintIsSet; } + void validateAmount() { + amountValid.setValue(true); + } + void invalidateAmount() { + amountValid.setValue(false); + } + void observeAmountValidity(NewTransactionActivity activity, Observer observer) { + amountValid.observe(activity, observer); + } + void stopObservingAmountValidity(Observer observer) { + amountValid.removeObserver(observer); + } } } diff --git a/app/src/main/res/drawable-anydpi-v21/ic_error_outline_black_24dp.xml b/app/src/main/res/drawable-anydpi-v21/ic_error_outline_black_24dp.xml new file mode 100644 index 00000000..76054bd5 --- /dev/null +++ b/app/src/main/res/drawable-anydpi-v21/ic_error_outline_black_24dp.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/app/src/main/res/layout/new_transaction_row.xml b/app/src/main/res/layout/new_transaction_row.xml index ca1889ee..ab1668cb 100644 --- a/app/src/main/res/layout/new_transaction_row.xml +++ b/app/src/main/res/layout/new_transaction_row.xml @@ -173,7 +173,7 @@ android:hint="@string/zero_amount" android:imeOptions="actionNext" android:inputType="numberSigned|numberDecimal|number" - android:minWidth="80sp" + android:minEms="4" android:selectAllOnFocus="true" android:textAlignment="viewEnd" app:layout_constraintBottom_toBottomOf="parent" -- 2.39.2