private SimpleDate earliestDate, latestDate;
private SimpleDate lastDate = SimpleDate.today();
private boolean done;
+ private int transactionCount = 0;
public TransactionAccumulator(MainModel model) {
this.model = model;
}
list.add(new TransactionListItem(transaction));
lastDate = date;
+ transactionCount++;
}
public void done() {
done = true;
- model.setDisplayedTransactions(list);
+ model.setDisplayedTransactions(list, transactionCount);
model.setFirstTransactionDate(earliestDate);
model.setLastTransactionDate(latestDate);
}
public static final MutableLiveData<Boolean> currencyGap = new MutableLiveData<>(true);
public static final MutableLiveData<Locale> locale = new MutableLiveData<>();
public static final MutableLiveData<Boolean> drawerOpen = new MutableLiveData<>(false);
- public static final MutableLiveData<Date> lastUpdateLiveData = new MutableLiveData<>(null);
- public static final ObservableValue<Long> lastUpdate = new ObservableValue<>();
+ public static final MutableLiveData<Date> lastUpdateDate = new MutableLiveData<>(null);
+ public static final MutableLiveData<Integer> lastUpdateTransactionCount =
+ new MutableLiveData<>(0);
+ public static final ObservableValue<String> lastUpdateText = new ObservableValue<>();
private static final MutableLiveData<MobileLedgerProfile> profile =
new InertMutableLiveData<>();
private static final AtomicInteger backgroundTaskCount = new AtomicInteger(0);
return merged;
}
- private void setLastUpdateStamp() {
+ private void setLastUpdateStamp(long transactionCount) {
debug("db", "Updating transaction value stamp");
Date now = new Date();
profile.setLongOption(MLDB.OPT_LAST_SCRAPE, now.getTime());
- Data.lastUpdateLiveData.postValue(now);
+ Data.lastUpdateDate.postValue(now);
}
public void scheduleTransactionListReload() {
UpdateTransactionsTask task = new UpdateTransactionsTask();
public LiveData<List<TransactionListItem>> getDisplayedTransactions() {
return displayedTransactions;
}
- public void setDisplayedTransactions(List<TransactionListItem> list) {
+ public void setDisplayedTransactions(List<TransactionListItem> list, int transactionCount) {
displayedTransactions.postValue(list);
+ Data.lastUpdateTransactionCount.postValue(transactionCount);
}
public SimpleDate getFirstTransactionDate() {
return firstTransactionDate;
List<LedgerAccount> accounts, List<LedgerTransaction> transactions) {
profile.storeAccountAndTransactionListAsync(accounts, transactions);
- setLastUpdateStamp();
+ setLastUpdateStamp(transactions.size());
mergeAccountListFromWeb(accounts);
updateDisplayedAccounts();
import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
break;
case HEADER:
- setLastUpdateText(Data.lastUpdate.get());
+ setLastUpdateText(Data.lastUpdateText.get());
break;
default:
throw new IllegalStateException("Unexpected value: " + newType);
}
}
- void setLastUpdateText(long lastUpdate) {
- final int formatFlags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR |
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_NUMERIC_DATE;
- tvLastUpdate.setText((lastUpdate == 0) ? "----" : DateUtils.formatDateTime(
- tvLastUpdate.getContext(), lastUpdate, formatFlags));
+ void setLastUpdateText(String text) {
+ tvLastUpdate.setText(text);
}
private void initLastUpdateObserver() {
if (lastUpdateObserver != null)
return;
- lastUpdateObserver = (o, arg) -> setLastUpdateText(Data.lastUpdate.get());
+ lastUpdateObserver = (o, arg) -> setLastUpdateText(Data.lastUpdateText.get());
- Data.lastUpdate.addObserver(lastUpdateObserver);
+ Data.lastUpdateText.addObserver(lastUpdateObserver);
}
private void dropLastUpdateObserver() {
if (lastUpdateObserver == null)
return;
- Data.lastUpdate.deleteObserver(lastUpdateObserver);
+ Data.lastUpdateText.deleteObserver(lastUpdateObserver);
lastUpdateObserver = null;
}
private void setType(AccountListItem.Type newType) {
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle;
+import android.text.format.DateUtils;
import android.util.Log;
import android.view.View;
import android.view.animation.AnimationUtils;
import java.util.Date;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
/*
* TODO: reports
.show();
mainModel.clearUpdateError();
});
+ Data.locale.observe(this, l -> refreshLastUpdateInfo());
+ Data.lastUpdateDate.observe(this, date -> refreshLastUpdateInfo());
+ Data.lastUpdateTransactionCount.observe(this, date -> refreshLastUpdateInfo());
}
private void scheduleDataRetrievalIfStale(long lastUpdate) {
long now = new Date().getTime();
// un-hook all observed LiveData
Data.removeProfileObservers(this);
Data.profiles.removeObservers(this);
- Data.lastUpdateLiveData.removeObservers(this);
+ Data.lastUpdateTransactionCount.removeObservers(this);
+ Data.lastUpdateDate.removeObservers(this);
recreate();
}
Logger.debug("transactions", String.format(Locale.ENGLISH, "Last update = %d", lastUpdate));
if (lastUpdate == 0) {
- Data.lastUpdateLiveData.postValue(null);
+ Data.lastUpdateDate.postValue(null);
}
else {
- Data.lastUpdateLiveData.postValue(new Date(lastUpdate));
+ Data.lastUpdateDate.postValue(new Date(lastUpdate));
}
- // this is unfortunate, but it appears we need a two-stage rocket to make
- // a value reach a recycler view item holder. first stage is a regular
- // LiveData that can be observed by an activity (this).
- // the second stage forwards the changes, in the UI thread, to the
- // observable value, observed by the view holders.
- // view holders can't observe the LiveData because they don't have
- // access to lifecycle owners. oh, also the value is updated by a thread
- // so it must be tunnelled by an activity for it to reach the view
- // holders in the UI thread
- Data.lastUpdateLiveData.observe(this, date -> runOnUiThread(
- () -> Data.lastUpdate.set((date == null) ? 0 : date.getTime())));
scheduleDataRetrievalIfStale(lastUpdate);
}
+ private void refreshLastUpdateInfo() {
+ final int formatFlags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR |
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_NUMERIC_DATE;
+ String template = getResources().getString(R.string.transaction_count_summary);
+ Integer transactionCount = Data.lastUpdateTransactionCount.getValue();
+ Date lastUpdate = Data.lastUpdateDate.getValue();
+ Data.lastUpdateText.set((lastUpdate == null) ? "----" : String.format(
+ Objects.requireNonNull(Data.locale.getValue()), template,
+ (transactionCount == null) ? 0 : transactionCount,
+ DateUtils.formatDateTime(this, lastUpdate.getTime(), formatFlags)));
+ }
public void onStopTransactionRefreshClick(View view) {
Logger.debug("interactive", "Cancelling transactions refresh");
mainModel.stopTransactionsRetrieval();
}
break;
case HEADER:
- holder.setLastUpdateText(Data.lastUpdate.get());
+ holder.setLastUpdateText(Data.lastUpdateText.get());
break;
default:
package net.ktnx.mobileledger.ui.transaction_list;
-import android.text.format.DateUtils;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
if (lastUpdateObserver != null)
return;
- lastUpdateObserver = (o, arg) -> setLastUpdateText(Data.lastUpdate.get());
+ lastUpdateObserver = (o, arg) -> setLastUpdateText(Data.lastUpdateText.get());
- Data.lastUpdate.addObserver(lastUpdateObserver);
+ Data.lastUpdateText.addObserver(lastUpdateObserver);
}
- void setLastUpdateText(long lastUpdate) {
- final int formatFlags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR |
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_NUMERIC_DATE;
- tvLastUpdate.setText((lastUpdate == 0) ? "----"
- : DateUtils.formatDateTime(tvLastUpdate.getContext(),
- lastUpdate, formatFlags));
+ void setLastUpdateText(String text) {
+ tvLastUpdate.setText(text);
}
private void dropLastUpdateObserver() {
if (lastUpdateObserver == null)
return;
- Data.lastUpdate.deleteObserver(lastUpdateObserver);
+ Data.lastUpdateText.deleteObserver(lastUpdateObserver);
lastUpdateObserver = null;
}
void setType(TransactionListItem.Type newType) {
android:layout_height="wrap_content"
android:paddingTop="4dp"
>
- <TextView
- android:id="@+id/last_update_label"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:text="@string/transactions_last_update_label"
- android:textAppearance="@android:style/TextAppearance.Material.Small"
- app:layout_constraintEnd_toStartOf="@id/last_update_text"
- app:layout_constraintTop_toTopOf="parent"
- />
<TextView
android:id="@+id/last_update_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/activity_horizontal_margin"
+ android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
android:layout_weight="1"
- android:text="\?"
+ android:gravity="center"
+ android:text="1 123 transactions as of 29.02.2020 13:37"
android:textAppearance="@android:style/TextAppearance.Material.Small"
app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText"
/>
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ 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
<string name="navigation_drawer_open">Отваряне на страничния панел</string>
<string name="navigation_drawer_close">Затваряне на страничния панел</string>
<string name="nav_header_desc">Заглавна част на страничния панел</string>
+ <string name="transaction_count_summary">%,d движения към %s</string>
</resources>
<string name="go_to_date_menu_title">Go to date</string>
<string name="splash_icon_description">Main app icon</string>
<string name="sub_accounts_expand_collapse_trigger_description">Sub-accounts expand/collapse trigger</string>
+ <string name="transaction_count_summary">%,d transactions as of %s</string>
</resources>