/*
- * Copyright © 2019 Damyan Ivanov.
+ * Copyright © 2020 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
import net.ktnx.mobileledger.model.Data;
import net.ktnx.mobileledger.model.LedgerTransactionAccount;
import net.ktnx.mobileledger.model.MobileLedgerProfile;
+import net.ktnx.mobileledger.utils.Globals;
+import net.ktnx.mobileledger.utils.SimpleDate;
import org.jetbrains.annotations.NotNull;
+import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
-import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
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<Boolean> showCurrency = new MutableLiveData<>(false);
final ArrayList<Item> items = new ArrayList<>();
final MutableLiveData<Boolean> isSubmittable = new MutableLiveData<>(false);
- private final Item header = new Item(this, null, "");
+ final MutableLiveData<Boolean> showComments = new MutableLiveData<>(true);
+ private final Item header = new Item(this, "");
private final Item trailer = new Item(this);
private final MutableLiveData<Integer> focusedItem = new MutableLiveData<>(0);
private final MutableLiveData<Integer> accountCount = new MutableLiveData<>(0);
private final MutableLiveData<Boolean> simulateSave = new MutableLiveData<>(false);
- private boolean observingDataProfile;
- private Observer<MobileLedgerProfile> profileObserver =
- profile -> showCurrency.postValue(profile.getShowCommodityByDefault());
private final AtomicInteger busyCounter = new AtomicInteger(0);
private final MutableLiveData<Boolean> busyFlag = new MutableLiveData<>(false);
+ private final Observer<MobileLedgerProfile> profileObserver = profile -> {
+ showCurrency.postValue(profile.getShowCommodityByDefault());
+ showComments.postValue(profile.getShowCommentsByDefault());
+ };
+ private boolean observingDataProfile;
+ void observeShowComments(LifecycleOwner owner, Observer<? super Boolean> observer) {
+ showComments.observe(owner, observer);
+ }
void observeBusyFlag(@NonNull LifecycleOwner owner, Observer<? super Boolean> observer) {
busyFlag.observe(owner, observer);
}
void observeDataProfile(LifecycleOwner activity) {
if (!observingDataProfile)
- Data.profile.observe(activity, profileObserver);
+ Data.observeProfile(activity, profileObserver);
observingDataProfile = true;
}
boolean getSimulateSave() {
int getAccountCount() {
return items.size();
}
- public Date getDate() {
+ public SimpleDate getDate() {
return header.date.getValue();
}
public String getDescription() {
return header.description.getValue();
}
+ public String getComment() {
+ return header.comment.getValue();
+ }
LiveData<Boolean> isSubmittable() {
return this.isSubmittable;
}
void reset() {
header.date.setValue(null);
header.description.setValue(null);
+ header.comment.setValue(null);
items.clear();
items.add(new Item(this, new LedgerTransactionAccount("")));
items.add(new Item(this, new LedgerTransactionAccount("")));
}
void incrementBusyCounter() {
int newValue = busyCounter.incrementAndGet();
- if (newValue == 1) busyFlag.postValue(true);
+ if (newValue == 1)
+ busyFlag.postValue(true);
}
void decrementBusyCounter() {
int newValue = busyCounter.decrementAndGet();
- if (newValue == 0) busyFlag.postValue(false);
+ if (newValue == 0)
+ busyFlag.postValue(false);
}
public boolean getBusyFlag() {
return busyFlag.getValue();
}
+ public void toggleShowComments() {
+ showComments.setValue(!showComments.getValue());
+ }
enum ItemType {generalData, transactionRow, bottomFiller}
- enum FocusedElement {Account, Comment, Amount}
+ enum FocusedElement {Account, Comment, Amount, Description, TransactionComment}
//==========================================================================================
static class Item {
- private ItemType type;
- private MutableLiveData<Date> date = new MutableLiveData<>();
- private MutableLiveData<String> description = new MutableLiveData<>();
+ private final ItemType type;
+ private final MutableLiveData<SimpleDate> date = new MutableLiveData<>();
+ private final MutableLiveData<String> description = new MutableLiveData<>();
+ private final MutableLiveData<String> amountHint = new MutableLiveData<>(null);
+ private final NewTransactionModel model;
+ private final MutableLiveData<Boolean> editable = new MutableLiveData<>(true);
+ private final MutableLiveData<String> comment = new MutableLiveData<>(null);
+ private final MutableLiveData<Currency> currency = new MutableLiveData<>(null);
+ private final MutableLiveData<Boolean> amountValid = new MutableLiveData<>(true);
private LedgerTransactionAccount account;
- private MutableLiveData<String> amountHint = new MutableLiveData<>(null);
- private NewTransactionModel model;
- private MutableLiveData<Boolean> editable = new MutableLiveData<>(true);
private FocusedElement focusedElement = FocusedElement.Account;
- private MutableLiveData<String> comment = new MutableLiveData<>(null);
- private MutableLiveData<Currency> currency = new MutableLiveData<>(null);
private boolean amountHintIsSet = false;
Item(NewTransactionModel model) {
this.model = model;
type = ItemType.bottomFiller;
editable.setValue(false);
}
- Item(NewTransactionModel model, Date date, String description) {
+ Item(NewTransactionModel model, String description) {
this.model = model;
this.type = ItemType.generalData;
- this.date.setValue(date);
this.description.setValue(description);
this.editable.setValue(true);
}
return model;
}
void setEditable(boolean editable) {
- ensureType(ItemType.generalData, ItemType.transactionRow);
+ ensureTypeIsGeneralDataOrTransactionRow();
this.editable.setValue(editable);
}
- private void ensureType(ItemType type1, ItemType type2) {
- if ((type != type1) && (type != type2)) {
+ private void ensureTypeIsGeneralDataOrTransactionRow() {
+ if ((type != ItemType.generalData) && (type != ItemType.transactionRow)) {
throw new RuntimeException(
String.format("Actual type (%s) differs from wanted (%s or %s)", type,
- type1, type2));
+ ItemType.generalData, ItemType.transactionRow));
}
}
String getAmountHint() {
wantedType));
}
}
- public Date getDate() {
+ public SimpleDate getDate() {
ensureType(ItemType.generalData);
return date.getValue();
}
- public void setDate(Date date) {
+ public void setDate(SimpleDate date) {
ensureType(ItemType.generalData);
this.date.setValue(date);
}
- public void setDate(String text) {
+ public void setDate(String text) throws ParseException {
if ((text == null) || text.trim()
.isEmpty())
{
- setDate((Date) null);
+ setDate((SimpleDate) null);
return;
}
- int year, month, day;
- final Calendar c = GregorianCalendar.getInstance();
- Matcher m = reYMD.matcher(text);
- if (m.matches()) {
- year = Integer.parseInt(m.group(1));
- month = Integer.parseInt(m.group(2)) - 1; // month is 0-based
- day = Integer.parseInt(m.group(3));
- }
- else {
- year = c.get(Calendar.YEAR);
- m = reMD.matcher(text);
- if (m.matches()) {
- month = Integer.parseInt(m.group(1)) - 1;
- day = Integer.parseInt(m.group(2));
- }
- else {
- month = c.get(Calendar.MONTH);
- m = reD.matcher(text);
- if (m.matches()) {
- day = Integer.parseInt(m.group(1));
- }
- else {
- day = c.get(Calendar.DAY_OF_MONTH);
- }
- }
- }
-
- c.set(year, month, day);
-
- this.setDate(c.getTime());
+ SimpleDate date = Globals.parseLedgerDate(text);
+ this.setDate(date);
}
void observeDate(@NonNull @NotNull androidx.lifecycle.LifecycleOwner owner,
- @NonNull androidx.lifecycle.Observer<? super Date> observer) {
+ @NonNull androidx.lifecycle.Observer<? super SimpleDate> observer) {
this.date.observe(owner, observer);
}
- void stopObservingDate(@NonNull androidx.lifecycle.Observer<? super Date> observer) {
+ void stopObservingDate(@NonNull androidx.lifecycle.Observer<? super SimpleDate> observer) {
this.date.removeObserver(observer);
}
public String getDescription() {
@NonNull androidx.lifecycle.Observer<? super String> observer) {
this.description.removeObserver(observer);
}
+ public String getTransactionComment() {
+ ensureType(ItemType.generalData);
+ return comment.getValue();
+ }
+ public void setTransactionComment(String transactionComment) {
+ ensureType(ItemType.generalData);
+ this.comment.setValue(transactionComment);
+ }
+ void observeTransactionComment(@NonNull @NotNull LifecycleOwner owner,
+ @NonNull Observer<? super String> observer) {
+ ensureType(ItemType.generalData);
+ this.comment.observe(owner, observer);
+ }
+ void stopObservingTransactionComment(@NonNull Observer<? super String> observer) {
+ this.comment.removeObserver(observer);
+ }
public LedgerTransactionAccount getAccount() {
ensureType(ItemType.transactionRow);
return account;
String getFormattedDate() {
if (date == null)
return null;
- Date time = date.getValue();
- if (time == null)
+ SimpleDate d = date.getValue();
+ if (d == null)
return null;
- Calendar c = GregorianCalendar.getInstance();
- c.setTime(time);
Calendar today = GregorianCalendar.getInstance();
- final int myYear = c.get(Calendar.YEAR);
- final int myMonth = c.get(Calendar.MONTH);
- final int myDay = c.get(Calendar.DAY_OF_MONTH);
-
- if (today.get(Calendar.YEAR) != myYear) {
- return String.format(Locale.US, "%d/%02d/%02d", myYear, myMonth + 1, myDay);
+ if (today.get(Calendar.YEAR) != d.year) {
+ return String.format(Locale.US, "%d/%02d/%02d", d.year, d.month, d.day);
}
- if (today.get(Calendar.MONTH) != myMonth) {
- return String.format(Locale.US, "%d/%02d", myMonth + 1, myDay);
+ if (today.get(Calendar.MONTH) != d.month - 1) {
+ return String.format(Locale.US, "%d/%02d", d.month, d.day);
}
- return String.valueOf(myDay);
+ return String.valueOf(d.day);
}
void observeEditableFlag(NewTransactionActivity activity, Observer<Boolean> observer) {
editable.observe(activity, observer);
void stopObservingCurrency(Observer<Currency> observer) {
currency.removeObserver(observer);
}
- boolean isOfType(ItemType type) {
- return this.type == type;
+ boolean isBottomFiller() {
+ return this.type == ItemType.bottomFiller;
}
boolean isAmountHintSet() {
return amountHintIsSet;
}
+ void validateAmount() {
+ amountValid.setValue(true);
+ }
+ void invalidateAmount() {
+ amountValid.setValue(false);
+ }
+ void observeAmountValidity(NewTransactionActivity activity, Observer<Boolean> observer) {
+ amountValid.observe(activity, observer);
+ }
+ void stopObservingAmountValidity(Observer<Boolean> observer) {
+ amountValid.removeObserver(observer);
+ }
}
}