import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
+import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import androidx.annotation.ColorInt;
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;
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;
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);
DecimalFormatSymbols.getInstance(locale)
.getMonetaryDecimalSeparator()));
- decimalDot = ".";
-
final TextWatcher tw = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
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");
}
};
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.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(),
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 {
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();
+
+ // having account name is important
+ if (TextUtils.isEmpty(acc.getAccountName()) !=
+ TextUtils.isEmpty(b.accountRowAccName.getText()))
+ significantChange = true;
+
acc.setAccountName(String.valueOf(b.accountRowAccName.getText()));
acc.setComment(String.valueOf(b.comment.getText()));
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);
if (item instanceof NewTransactionModel.TransactionHead) {
NewTransactionModel.TransactionHead head = item.toTransactionHead();
b.newTransactionDate.setText(head.getFormattedDate());
- b.newTransactionDescription.setText(head.getDescription());
+
+ // avoid triggering completion pop-up
+ SimpleCursorAdapter a =
+ (SimpleCursorAdapter) b.newTransactionDescription.getAdapter();
+ try {
+ b.newTransactionDescription.setAdapter(null);
+ b.newTransactionDescription.setText(head.getDescription());
+ }
+ finally {
+ b.newTransactionDescription.setAdapter(a);
+ }
b.transactionComment.setText(head.getComment());
//styleComment(b.transactionComment, head.getComment());
else if (item instanceof NewTransactionModel.TransactionAccount) {
NewTransactionModel.TransactionAccount acc = item.toTransactionAccount();
- b.accountRowAccName.setText(acc.getAccountName());
+ // 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 amountHint = acc.getAmountHint();
if (amountHint == null) {
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);
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;