From: Damyan Ivanov Date: Sat, 12 Jan 2019 12:43:46 +0000 (+0000) Subject: replace dates in transaction list items with delimiters between items in different... X-Git-Tag: v0.3~52 X-Git-Url: https://git.ktnx.net/?p=mobile-ledger.git;a=commitdiff_plain;h=e12bae55fb75c0c30055dd34ded195e75feb3844;hp=90706eb1669fb560578f49565939ad28059d12fe replace dates in transaction list items with delimiters between items in different dates --- diff --git a/app/src/main/java/net/ktnx/mobileledger/MobileLedgerApplication.java b/app/src/main/java/net/ktnx/mobileledger/MobileLedgerApplication.java index 7f0dfeb6..804575b4 100644 --- a/app/src/main/java/net/ktnx/mobileledger/MobileLedgerApplication.java +++ b/app/src/main/java/net/ktnx/mobileledger/MobileLedgerApplication.java @@ -36,15 +36,19 @@ public class MobileLedgerApplication extends Application { public void onCreate() { super.onCreate(); updateColorValues(); + updateMonthNames(); MLDB.init(this); SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(this); Data.optShowOnlyStarred.set(p.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false)); - SharedPreferences.OnSharedPreferenceChangeListener handler = (preference, value) -> { - Data.optShowOnlyStarred - .set(preference.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false)); - }; + SharedPreferences.OnSharedPreferenceChangeListener handler = + (preference, value) -> Data.optShowOnlyStarred + .set(preference.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false)); p.registerOnSharedPreferenceChangeListener(handler); } + private void updateMonthNames() { + Resources rm = getResources(); + Globals.monthNames = rm.getStringArray(R.array.month_names); + } @Override public void onTerminate() { MLDB.done(); @@ -54,6 +58,7 @@ public class MobileLedgerApplication extends Application { public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); updateColorValues(); + updateMonthNames(); } private void updateColorValues() { Resources rm = getResources(); diff --git a/app/src/main/java/net/ktnx/mobileledger/async/SaveTransactionTask.java b/app/src/main/java/net/ktnx/mobileledger/async/SaveTransactionTask.java index fb520d4f..fae87bc3 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/SaveTransactionTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/SaveTransactionTask.java @@ -23,6 +23,7 @@ import android.util.Log; import net.ktnx.mobileledger.model.Data; import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.model.LedgerTransactionAccount; +import net.ktnx.mobileledger.utils.Globals; import net.ktnx.mobileledger.utils.NetworkUtil; import net.ktnx.mobileledger.utils.UrlEncodedFormData; @@ -42,11 +43,11 @@ import static java.lang.Thread.sleep; public class SaveTransactionTask extends AsyncTask { private final TaskCallback taskCallback; + protected String error; private String token; private String session; private String backendUrl; private LedgerTransaction ltr; - protected String error; public SaveTransactionTask(TaskCallback callback) { taskCallback = callback; @@ -65,7 +66,7 @@ public class SaveTransactionTask extends AsyncTask> { - protected List doInBackground(String[] filterAccName) { +public class UpdateTransactionsTask extends AsyncTask> { + protected List doInBackground(String[] filterAccName) { Data.backgroundTaskCount.incrementAndGet(); String profile_uuid = Data.profile.get().getUuid(); try { - ArrayList newList = new ArrayList<>(); + ArrayList newList = new ArrayList<>(); String sql; String[] params; if (filterAccName[0] == null) { - sql = "SELECT id FROM transactions WHERE profile=? ORDER BY date desc, id desc"; + sql = "SELECT id, date FROM transactions WHERE profile=? ORDER BY date desc, id " + + "desc"; params = new String[]{profile_uuid}; } else { - sql = "SELECT distinct tr.id from transactions tr JOIN transaction_accounts ta " + + sql = "SELECT distinct tr.id, tr.date from transactions tr JOIN " + + "transaction_accounts ta " + "ON ta.transaction_id=tr.id AND ta.profile=tr.profile WHERE tr.profile=? " + "and ta.account_name LIKE ?||'%' AND ta" + ".amount <> 0 ORDER BY tr.date desc, tr.id desc"; @@ -54,13 +59,27 @@ public class UpdateTransactionsTask extends AsyncTask accounts; private String dataHash; private boolean dataLoaded; - public LedgerTransaction(Integer id, String date, String description) { + public LedgerTransaction(Integer id, String dateString, String description) { + this(id, Globals.parseLedgerDate(dateString), description); + } + public LedgerTransaction(Integer id, Date date, String description) { this.profile = Data.profile.get().getUuid(); this.id = id; this.date = date; @@ -57,11 +62,11 @@ public class LedgerTransaction { this.dataHash = null; dataLoaded = false; } - public LedgerTransaction(String date, String description) { + public LedgerTransaction(Date date, String description) { this(null, date, description); } public LedgerTransaction(int id) { - this(id, null, null); + this(id, (Date) null, null); } public ArrayList getAccounts() { return accounts; @@ -70,10 +75,10 @@ public class LedgerTransaction { accounts.add(item); dataHash = null; } - public String getDate() { + public Date getDate() { return date; } - public void setDate(String date) { + public void setDate(Date date) { this.date = date; dataHash = null; } @@ -131,7 +136,8 @@ public class LedgerTransaction { new String[]{profile, String.valueOf(id)})) { if (cTr.moveToFirst()) { - date = cTr.getString(0); + String dateString = cTr.getString(0); + date = Globals.parseLedgerDate(dateString); description = cTr.getString(1); try (Cursor cAcc = db.rawQuery("SELECT account_name, amount, currency FROM " + diff --git a/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java b/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java index 8514e71d..70c12ab9 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java @@ -21,6 +21,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; +import net.ktnx.mobileledger.utils.Globals; import net.ktnx.mobileledger.utils.MLDB; import java.util.ArrayList; @@ -209,7 +210,8 @@ public final class MobileLedgerProfile { db.execSQL("INSERT INTO transactions(profile, id, date, description, data_hash, keep) " + "values(?,?,?,?,?,1)", - new Object[]{uuid, tr.getId(), tr.getDate(), tr.getDescription(), tr.getDataHash() + new Object[]{uuid, tr.getId(), Globals.formatLedgerDate(tr.getDate()), + tr.getDescription(), tr.getDataHash() }); for (LedgerTransactionAccount item : tr.getAccounts()) { diff --git a/app/src/main/java/net/ktnx/mobileledger/model/TransactionList.java b/app/src/main/java/net/ktnx/mobileledger/model/TransactionList.java index c01c2aac..548303aa 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/TransactionList.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/TransactionList.java @@ -21,5 +21,5 @@ import net.ktnx.mobileledger.utils.ObservableValue; import java.util.List; -public class TransactionList extends ObservableValue> { +public class TransactionList extends ObservableValue> { } diff --git a/app/src/main/java/net/ktnx/mobileledger/model/TransactionListItem.java b/app/src/main/java/net/ktnx/mobileledger/model/TransactionListItem.java new file mode 100644 index 00000000..ee1810a9 --- /dev/null +++ b/app/src/main/java/net/ktnx/mobileledger/model/TransactionListItem.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2019 Damyan Ivanov. + * This file is part of Mobile-Ledger. + * Mobile-Ledger is free software: you can distribute it and/or modify it + * under the term of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your opinion), any later version. + * + * Mobile-Ledger is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License terms for details. + * + * You should have received a copy of the GNU General Public License + * along with Mobile-Ledger. If not, see . + */ + +package net.ktnx.mobileledger.model; + +import java.util.Date; + +public class TransactionListItem { + private Type type; + private Date date; + private boolean monthShown; + private LedgerTransaction transaction; + public TransactionListItem(Date date, boolean monthShown) { + this.type = Type.DELIMITER; + this.date = date; + this.monthShown = monthShown; + } + public TransactionListItem(LedgerTransaction transaction) { + this.type = Type.TRANSACTION; + this.transaction = transaction; + } + public Type getType() { + return type; + } + public Date getDate() { + return date; + } + public boolean isMonthShown() { + return monthShown; + } + public LedgerTransaction getTransaction() { + return transaction; + } + public enum Type {TRANSACTION, DELIMITER} +} diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionActivity.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionActivity.java index 0856bb54..a08f88c1 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionActivity.java @@ -49,6 +49,7 @@ import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.model.LedgerTransactionAccount; import net.ktnx.mobileledger.ui.DatePickerFragment; import net.ktnx.mobileledger.ui.OnSwipeTouchListener; +import net.ktnx.mobileledger.utils.Globals; import net.ktnx.mobileledger.utils.MLDB; import java.util.Date; @@ -135,8 +136,10 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal saver = new SaveTransactionTask(this); - String date = tvDate.getText().toString(); - if (date.isEmpty()) date = String.valueOf(new Date().getDate()); + String dateString = tvDate.getText().toString(); + Date date; + if (dateString.isEmpty()) date = new Date(); + else date = Globals.parseLedgerDate(dateString); LedgerTransaction tr = new LedgerTransaction(date, tvDescription.getText().toString()); TableLayout table = findViewById(R.id.new_transaction_accounts_table); diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListAdapter.java b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListAdapter.java index 7004dd7d..febca019 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListAdapter.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListAdapter.java @@ -34,26 +34,57 @@ import android.widget.TextView; import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.model.LedgerTransactionAccount; +import net.ktnx.mobileledger.model.TransactionListItem; import net.ktnx.mobileledger.utils.Globals; import net.ktnx.mobileledger.utils.MLDB; +import java.text.DateFormat; +import java.util.Date; + import static net.ktnx.mobileledger.utils.DimensionUtils.dp2px; public class TransactionListAdapter extends RecyclerView.Adapter { private String boldAccountName; public void onBindViewHolder(@NonNull TransactionRowHolder holder, int position) { - LedgerTransaction tr = TransactionListViewModel.getTransaction(position); - // in a race when transaction value is reduced, but the model hasn't been notified yet - // the view will disappear when the notifications reaches the model, so by simply omitting - // the out-of-range get() call nothing bad happens - just a to-be-deleted view remains - // a bit longer - if (tr == null) return; + TransactionListItem item = TransactionListViewModel.getTransactionListItem(position); + + if (item.getType() == TransactionListItem.Type.TRANSACTION) { + holder.vTransaction.setVisibility(View.VISIBLE); + holder.vDelimiter.setVisibility(View.GONE); + LedgerTransaction tr = item.getTransaction(); + // in a race when transaction value is reduced, but the model hasn't been notified yet + // the view will disappear when the notifications reaches the model, so by simply omitting + // the out-of-range get() call nothing bad happens - just a to-be-deleted view remains + // a bit longer + if (tr == null) return; + + LedgerTransaction previous = null; + TransactionListItem previousItem = null; + if (position > 0) + previousItem = TransactionListViewModel.getTransactionListItem(position - 1); // Log.d("transactions", String.format("Filling position %d with %d accounts", position, // tr.getAccounts().size())); - TransactionLoader loader = new TransactionLoader(); - loader.execute(new TransactionLoaderParams(tr, holder, position, boldAccountName)); + TransactionLoader loader = new TransactionLoader(); + loader.execute( + new TransactionLoaderParams(tr, previous, holder, position, boldAccountName)); + + // WORKAROUND what seems to be a bug in CardHolder somewhere + // when a view that was previously holding a delimiter is re-purposed + // occasionally it stays too short (not high enough) + holder.vTransaction.measure(View.MeasureSpec + .makeMeasureSpec(holder.itemView.getWidth(), View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); + } + else { + Date date = item.getDate(); + holder.vTransaction.setVisibility(View.GONE); + holder.vDelimiter.setVisibility(View.VISIBLE); + holder.tvDelimiterDate.setText(DateFormat.getDateInstance().format(date)); + holder.tvDelimiterMonth + .setText(item.isMonthShown() ? Globals.monthNames[date.getMonth()] : ""); + } } @NonNull @@ -83,11 +114,18 @@ public class TransactionListAdapter extends RecyclerView.Adapter> task = new UTT(); + AsyncTask> task = new UTT(); task.execute(filter); } - public static LedgerTransaction getTransaction(int position) { - List transactions = Data.transactions.get(); + public static TransactionListItem getTransactionListItem(int position) { + List transactions = Data.transactions.get(); if (position >= transactions.size()) return null; return transactions.get(position); } public static int getTransactionCount() { - List transactions = Data.transactions.get(); + List transactions = Data.transactions.get(); if (transactions == null) return 0; return transactions.size(); } private static class UTT extends UpdateTransactionsTask { @Override - protected void onPostExecute(List list) { + protected void onPostExecute(List list) { super.onPostExecute(list); if (list != null) Data.transactions.set(list); } diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionLoaderStep.java b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionLoaderStep.java index e5243584..6b9bd402 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionLoaderStep.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionLoaderStep.java @@ -29,12 +29,14 @@ class TransactionLoaderStep { private LedgerTransactionAccount account; private int accountPosition; private String boldAccountName; + private boolean showDate; public TransactionLoaderStep(TransactionRowHolder holder, int position, - LedgerTransaction transaction) { + LedgerTransaction transaction, boolean showDate) { this.step = TransactionListAdapter.LoaderStep.HEAD; this.holder = holder; this.transaction = transaction; this.position = position; + this.showDate = showDate; } public TransactionLoaderStep(TransactionRowHolder holder, LedgerTransactionAccount account, int accountPosition, String boldAccountName) { @@ -74,4 +76,7 @@ class TransactionLoaderStep { public LedgerTransactionAccount getAccount() { return account; } + public boolean isDateShown() { + return showDate; + } } diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionRowHolder.java b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionRowHolder.java index 5e975969..f23311a0 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionRowHolder.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionRowHolder.java @@ -19,6 +19,7 @@ package net.ktnx.mobileledger.ui.transaction_list; import android.support.annotation.NonNull; import android.support.constraint.ConstraintLayout; +import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.LinearLayout; @@ -27,14 +28,20 @@ import android.widget.TextView; import net.ktnx.mobileledger.R; class TransactionRowHolder extends RecyclerView.ViewHolder { - TextView tvDescription, tvDate; + TextView tvDescription; LinearLayout tableAccounts; ConstraintLayout row; + ConstraintLayout vDelimiter; + CardView vTransaction; + TextView tvDelimiterMonth, tvDelimiterDate; public TransactionRowHolder(@NonNull View itemView) { super(itemView); this.row = itemView.findViewById(R.id.transaction_row); this.tvDescription = itemView.findViewById(R.id.transaction_row_description); - this.tvDate = itemView.findViewById(R.id.transaction_row_date); this.tableAccounts = itemView.findViewById(R.id.transaction_row_acc_amounts); + this.vDelimiter = itemView.findViewById(R.id.transaction_delimiter); + this.vTransaction = itemView.findViewById(R.id.transaction_card_view); + this.tvDelimiterDate = itemView.findViewById(R.id.transaction_delimiter_date); + this.tvDelimiterMonth = itemView.findViewById(R.id.transaction_delimiter_month); } } diff --git a/app/src/main/java/net/ktnx/mobileledger/utils/Globals.java b/app/src/main/java/net/ktnx/mobileledger/utils/Globals.java index 4cf2b755..30dec945 100644 --- a/app/src/main/java/net/ktnx/mobileledger/utils/Globals.java +++ b/app/src/main/java/net/ktnx/mobileledger/utils/Globals.java @@ -23,6 +23,11 @@ import android.support.annotation.ColorInt; import android.view.View; import android.view.inputmethod.InputMethodManager; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + public final class Globals { @ColorInt public static int tableRowEvenBG; @@ -30,6 +35,7 @@ public final class Globals { public static int tableRowOddBG; @ColorInt public static int primaryDark, defaultTextColor; + public static String[] monthNames; public static void hideSoftKeyboard(Activity act) { // hide the keyboard View v = act.getCurrentFocus(); @@ -39,5 +45,16 @@ public final class Globals { imm.hideSoftInputFromWindow(v.getWindowToken(), 0); } } - + private static SimpleDateFormat ledgerDateFormatter = new SimpleDateFormat("y/M/d", Locale.US); + public static Date parseLedgerDate(String dateString) { + try { + return ledgerDateFormatter.parse(dateString); + } + catch (ParseException e) { + throw new RuntimeException(String.format("Error parsing date '%s'", dateString), e); + } + } + public static String formatLedgerDate(Date date) { + return ledgerDateFormatter.format(date); + } } \ No newline at end of file diff --git a/app/src/main/res/layout/transaction_list_row.xml b/app/src/main/res/layout/transaction_list_row.xml index f2ed7572..775dc79f 100644 --- a/app/src/main/res/layout/transaction_list_row.xml +++ b/app/src/main/res/layout/transaction_list_row.xml @@ -1,7 +1,7 @@ - + android:layout_height="wrap_content"> - - - + android:layout_margin="8dp" + android:visibility="gone" + app:cardCornerRadius="16dp" + app:cardElevation="4dp" + app:cardUseCompatPadding="false" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_goneMarginBottom="8dp"> - - - - - - - - + android:padding="8dp"> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent"> - + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/transaction_row_head" /> - + + + android:gravity="center_vertical" + android:orientation="horizontal" + android:paddingStart="8dp" + android:paddingEnd="0dp"> - + + + + + + android:gravity="center_vertical" + android:orientation="horizontal" + android:paddingStart="8dp" + android:paddingEnd="0dp"> + + + + + - + + + + + + + + + + + - + \ No newline at end of file diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index b9ad9e7c..805c12b3 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -66,4 +66,19 @@ Нов профил Изтриване на профила Изтриване + + Януари + Февруари + Март + Април + Май + Юни + Юли + Август + Септември + Октомври + Ноември + Декември + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c0546694..2390373d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -108,4 +108,18 @@ New profile Delete profile Delete + + January + February + Match + April + May + June + July + August + September + October + November + December +