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%2FNewTransactionItemHolder.java;h=c6232d167f7e303af4d93be2222354918727cc36;hp=1725f91a64ae0c58ffc7ca5652db67007a7d1e3f;hb=a0508ea0def0c4c6400626f26517d8e69631ff15;hpb=80d43ee6b1f34f923dd78ea33847d4addf990fde diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionItemHolder.java b/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionItemHolder.java index 1725f91a..c6232d16 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionItemHolder.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionItemHolder.java @@ -56,7 +56,7 @@ import java.util.Objects; class NewTransactionItemHolder extends RecyclerView.ViewHolder implements DatePickerFragment.DatePickedListener, DescriptionSelectedCallback { - private final String decimalDot; + private final String decimalDot = "."; private final MobileLedgerProfile mProfile; private final NewTransactionRowBinding b; private final NewTransactionItemsAdapter mAdapter; @@ -90,7 +90,7 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder mProfile = Data.getProfile(); - View.OnFocusChangeListener focusMonitor = (v, hasFocus) -> { + @SuppressLint("DefaultLocale") View.OnFocusChangeListener focusMonitor = (v, hasFocus) -> { final int id = v.getId(); if (hasFocus) { boolean wasSyncing = syncingData; @@ -119,6 +119,19 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder syncingData = wasSyncing; } } + else { // lost focus + if (id == R.id.account_row_acc_amounts) { + try { + String input = String.valueOf(b.accountRowAccAmounts.getText()); + input = input.replace(decimalSeparator, decimalDot); + b.accountRowAccAmounts.setText( + String.format("%4.2f", Float.parseFloat(input))); + } + catch (NumberFormatException ex) { + // ignored + } + } + } if (id == R.id.comment) { commentFocusChanged(b.comment, hasFocus); @@ -147,8 +160,6 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder DecimalFormatSymbols.getInstance(locale) .getMonetaryDecimalSeparator())); - decimalDot = "."; - final TextWatcher tw = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -165,10 +176,11 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder return; Logger.debug("textWatcher", "calling syncData()"); - syncData(); - Logger.debug("textWatcher", - "syncData() returned, checking if transaction is submittable"); - adapter.model.checkTransactionSubmittable(null); + if (syncData()) { + Logger.debug("textWatcher", + "syncData() returned, checking if transaction is submittable"); + adapter.model.checkTransactionSubmittable(null); + } Logger.debug("textWatcher", "done"); } }; @@ -203,77 +215,7 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder commentFocusChanged(b.comment, false); adapter.model.getFocusInfo() - .observe(activity, focusInfo -> { - if (ignoreFocusChanges) { - Logger.debug("new-trans", "Ignoring focus change"); - return; - } - ignoreFocusChanges = true; - try { - if (((focusInfo == null) || (focusInfo.element == null) || - focusInfo.position != getAdapterPosition()) || - itemView.hasFocus()) - return; - - NewTransactionModel.Item item = getItem(); - if (item instanceof NewTransactionModel.TransactionHead) { - NewTransactionModel.TransactionHead head = - item.toTransactionHead(); - // bad idea - double pop-up, and not really necessary. - // the user can tap the input to get the calendar - //if (!tvDate.hasFocus()) tvDate.requestFocus(); - switch (focusInfo.element) { - case TransactionComment: - b.transactionComment.setVisibility(View.VISIBLE); - b.transactionComment.requestFocus(); - break; - case Description: - boolean focused = - b.newTransactionDescription.requestFocus(); -// tvDescription.dismissDropDown(); - if (focused) - Misc.showSoftKeyboard( - (NewTransactionActivity) b.getRoot() - .getContext()); - break; - } - } - else if (item instanceof NewTransactionModel.TransactionAccount) { - NewTransactionModel.TransactionAccount acc = - item.toTransactionAccount(); - switch (focusInfo.element) { - case Amount: - b.accountRowAccAmounts.requestFocus(); - break; - case Comment: - b.comment.setVisibility(View.VISIBLE); - b.comment.requestFocus(); - break; - case Account: - boolean focused = b.accountRowAccName.requestFocus(); -// b.accountRowAccName.dismissDropDown(); - if (focused) - Misc.showSoftKeyboard( - (NewTransactionActivity) b.getRoot() - .getContext()); - break; - } - } - } - finally { - ignoreFocusChanges = false; - } - }); - adapter.model.getAccountCount() - .observe(activity, count -> { - final int adapterPosition = getAdapterPosition(); - final int layoutPosition = getLayoutPosition(); - - if (adapterPosition == count) - b.accountRowAccAmounts.setImeOptions(EditorInfo.IME_ACTION_DONE); - else - b.accountRowAccAmounts.setImeOptions(EditorInfo.IME_ACTION_NEXT); - }); + .observe(activity, this::applyFocus); Data.currencyGap.observe(activity, hasGap -> updateCurrencyPositionAndPadding(Data.currencySymbolPosition.getValue(), @@ -329,6 +271,61 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder b.transactionCommentLayout.setVisibility(show ? View.VISIBLE : View.GONE); }); } + private void applyFocus(NewTransactionModel.FocusInfo focusInfo) { + if (ignoreFocusChanges) { + Logger.debug("new-trans", "Ignoring focus change"); + return; + } + ignoreFocusChanges = true; + try { + if (((focusInfo == null) || (focusInfo.element == null) || + focusInfo.position != getAdapterPosition())) + return; + + NewTransactionModel.Item item = getItem(); + if (item instanceof NewTransactionModel.TransactionHead) { + NewTransactionModel.TransactionHead head = item.toTransactionHead(); + // bad idea - double pop-up, and not really necessary. + // the user can tap the input to get the calendar + //if (!tvDate.hasFocus()) tvDate.requestFocus(); + switch (focusInfo.element) { + case TransactionComment: + b.transactionComment.setVisibility(View.VISIBLE); + b.transactionComment.requestFocus(); + break; + case Description: + boolean focused = b.newTransactionDescription.requestFocus(); +// tvDescription.dismissDropDown(); + if (focused) + Misc.showSoftKeyboard((NewTransactionActivity) b.getRoot() + .getContext()); + break; + } + } + else if (item instanceof NewTransactionModel.TransactionAccount) { + NewTransactionModel.TransactionAccount acc = item.toTransactionAccount(); + switch (focusInfo.element) { + case Amount: + b.accountRowAccAmounts.requestFocus(); + break; + case Comment: + b.comment.setVisibility(View.VISIBLE); + b.comment.requestFocus(); + break; + case Account: + boolean focused = b.accountRowAccName.requestFocus(); +// b.accountRowAccName.dismissDropDown(); + if (focused) + Misc.showSoftKeyboard((NewTransactionActivity) b.getRoot() + .getContext()); + break; + } + } + } + finally { + ignoreFocusChanges = false; + } + } public void checkAmountValid(String s) { boolean valid = true; try { @@ -486,17 +483,35 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder syncingData = true; + boolean significantChange = false; + try { if (item instanceof NewTransactionModel.TransactionHead) { NewTransactionModel.TransactionHead head = item.toTransactionHead(); head.setDate(String.valueOf(b.newTransactionDate.getText())); + + // transaction description is required + if (TextUtils.isEmpty(head.getDescription()) != + TextUtils.isEmpty(b.newTransactionDescription.getText())) + significantChange = true; + head.setDescription(String.valueOf(b.newTransactionDescription.getText())); head.setComment(String.valueOf(b.transactionComment.getText())); } else if (item instanceof NewTransactionModel.TransactionAccount) { NewTransactionModel.TransactionAccount acc = item.toTransactionAccount(); - acc.setAccountName(String.valueOf(b.accountRowAccName.getText())); + + // having account name is important + final Editable incomingAccountName = b.accountRowAccName.getText(); + if (TextUtils.isEmpty(acc.getAccountName()) != + TextUtils.isEmpty(incomingAccountName)) + significantChange = true; + + acc.setAccountName(String.valueOf(incomingAccountName)); + final int accNameSelEnd = b.accountRowAccName.getSelectionEnd(); + final int accNameSelStart = b.accountRowAccName.getSelectionStart(); + acc.setAccountNameCursorPosition(accNameSelEnd); acc.setComment(String.valueOf(b.comment.getText())); @@ -504,36 +519,48 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder amount = amount.trim(); if (amount.isEmpty()) { + if (acc.isAmountSet()) + significantChange = true; acc.resetAmount(); acc.setAmountValid(true); } else { try { amount = amount.replace(decimalSeparator, decimalDot); - acc.setAmount(Float.parseFloat(amount)); + final float parsedAmount = Float.parseFloat(amount); + if (!acc.isAmountSet() || !Misc.equalFloats(parsedAmount, acc.getAmount())) + significantChange = true; + acc.setAmount(parsedAmount); acc.setAmountValid(true); } catch (NumberFormatException e) { Logger.debug("new-trans", String.format( "assuming amount is not set due to number format exception. " + "input was '%s'", amount)); + if (acc.isAmountValid()) + significantChange = true; acc.setAmountValid(false); } final String curr = String.valueOf(b.currency.getText()); + final String currValue; if (curr.equals(b.currency.getContext() .getResources() .getString(R.string.currency_symbol)) || curr.isEmpty()) - acc.setCurrency(null); + currValue = null; else - acc.setCurrency(curr); + currValue = curr; + + if (!significantChange && !TextUtils.equals(acc.getCurrency(), currValue)) + significantChange = true; + acc.setCurrency(currValue); } } else { throw new RuntimeException("Should not happen"); } - return true; + return significantChange; } catch (ParseException e) { throw new RuntimeException("Should not happen", e); @@ -581,21 +608,31 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder b.ntrData.setVisibility(View.VISIBLE); b.ntrAccount.setVisibility(View.GONE); - b.ntrPadding.setVisibility(View.GONE); setEditable(true); } else if (item instanceof NewTransactionModel.TransactionAccount) { NewTransactionModel.TransactionAccount acc = item.toTransactionAccount(); - // avoid triggering completion pop-up - AccountAutocompleteAdapter a = - (AccountAutocompleteAdapter) b.accountRowAccName.getAdapter(); - try { - b.accountRowAccName.setAdapter(null); - b.accountRowAccName.setText(acc.getAccountName()); - } - finally { - b.accountRowAccName.setAdapter(a); + final String incomingAccountName = acc.getAccountName(); + final String presentAccountName = String.valueOf(b.accountRowAccName.getText()); + if (!TextUtils.equals(incomingAccountName, presentAccountName)) { + Logger.debug("bind", + String.format("Setting account name from '%s' to '%s' (| @ %d)", + presentAccountName, incomingAccountName, + acc.getAccountNameCursorPosition())); + // avoid triggering completion pop-up + AccountAutocompleteAdapter a = + (AccountAutocompleteAdapter) b.accountRowAccName.getAdapter(); + try { + b.accountRowAccName.setAdapter(null); + b.accountRowAccName.setText(incomingAccountName); + if (b.accountRowAccName.hasFocus()) + b.accountRowAccName.setSelection( + acc.getAccountNameCursorPosition()); + } + finally { + b.accountRowAccName.setAdapter(a); + } } final String amountHint = acc.getAmountHint(); @@ -606,6 +643,9 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder b.accountRowAccAmounts.setHint(amountHint); } + b.accountRowAccAmounts.setImeOptions( + acc.isLast() ? EditorInfo.IME_ACTION_DONE : EditorInfo.IME_ACTION_NEXT); + setCurrencyString(acc.getCurrency()); b.accountRowAccAmounts.setText( acc.isAmountSet() ? String.format("%4.2f", acc.getAmount()) : null); @@ -615,12 +655,15 @@ class NewTransactionItemHolder extends RecyclerView.ViewHolder b.ntrData.setVisibility(View.GONE); b.ntrAccount.setVisibility(View.VISIBLE); - b.ntrPadding.setVisibility(View.GONE); + setEditable(true); } else { throw new RuntimeException("Don't know how to handle " + item); } + + applyFocus(mAdapter.model.getFocusInfo() + .getValue()); } finally { syncingData = false;