]> git.ktnx.net Git - mobile-ledger.git/blobdiff - app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionItemsAdapter.java
two fallouts after transaction date reorganisation and 'go to date' feature
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / ui / activity / NewTransactionItemsAdapter.java
index d20f402f806aafefa9906ec0f61044c1196b76c2..80deaf27281315af7974e05f2c7def6fd9bb1cae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -18,6 +18,7 @@
 package net.ktnx.mobileledger.ui.activity;
 
 import android.annotation.SuppressLint;
+import android.app.Activity;
 import android.database.Cursor;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
@@ -28,7 +29,8 @@ import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.ItemTouchHelper;
 import androidx.recyclerview.widget.RecyclerView;
 
-import net.ktnx.mobileledger.App;
+import com.google.android.material.snackbar.Snackbar;
+
 import net.ktnx.mobileledger.BuildConfig;
 import net.ktnx.mobileledger.R;
 import net.ktnx.mobileledger.async.DescriptionSelectedCallback;
@@ -38,6 +40,7 @@ import net.ktnx.mobileledger.model.LedgerTransaction;
 import net.ktnx.mobileledger.model.LedgerTransactionAccount;
 import net.ktnx.mobileledger.model.MobileLedgerProfile;
 import net.ktnx.mobileledger.utils.Logger;
+import net.ktnx.mobileledger.utils.MLDB;
 import net.ktnx.mobileledger.utils.Misc;
 
 import java.util.ArrayList;
@@ -50,7 +53,7 @@ import static net.ktnx.mobileledger.utils.Logger.debug;
 
 class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItemHolder>
         implements DescriptionSelectedCallback {
-    NewTransactionModel model;
+    private NewTransactionModel model;
     private MobileLedgerProfile mProfile;
     private ItemTouchHelper touchHelper;
     private RecyclerView recyclerView;
@@ -124,10 +127,10 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItem
     public void setProfile(MobileLedgerProfile profile) {
         mProfile = profile;
     }
-    int addRow() {
+    private int addRow() {
         return addRow(null);
     }
-    int addRow(String commodity) {
+    private int addRow(String commodity) {
         final int newAccountCount = model.addAccount(new LedgerTransactionAccount("", commodity));
         Logger.debug("new-transaction",
                 String.format(Locale.US, "invoking notifyItemInserted(%d)", newAccountCount));
@@ -158,7 +161,7 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItem
     public int getItemCount() {
         return model.getAccountCount() + 2;
     }
-    boolean accountListIsEmpty() {
+    private boolean accountListIsEmpty() {
         for (int i = 0; i < model.getAccountCount(); i++) {
             LedgerTransactionAccount acc = model.getAccount(i);
             if (!acc.getAccountName()
@@ -190,52 +193,87 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItem
         String accFilter = mProfile.getPreferredAccountsFilter();
 
         ArrayList<String> params = new ArrayList<>();
-        StringBuilder sb = new StringBuilder(
-                "select t.profile, t.id from transactions t where t.description=?");
+        StringBuilder sb = new StringBuilder("select t.profile, t.id from transactions t");
+
+        if (!Misc.isEmptyOrNull(accFilter)) {
+            sb.append(" JOIN transaction_accounts ta")
+              .append(" ON ta.profile = t.profile")
+              .append(" AND ta.transaction_id = t.id");
+        }
+
+        sb.append(" WHERE t.description=?");
         params.add(description);
 
-        if (accFilter != null) {
-            sb.append(" AND EXISTS (")
-              .append("SELECT 1 FROM transaction_accounts ta ")
-              .append("WHERE ta.profile = t.profile")
-              .append(" AND ta.transaction_id = t.id")
-              .append(" AND UPPER(ta.account_name) LIKE '%'||?||'%')");
-            params.add(accFilter.toUpperCase());
+        if (!Misc.isEmptyOrNull(accFilter)) {
+            sb.append(" AND ta.account_name LIKE '%'||?||'%'");
+            params.add(accFilter);
         }
 
-        sb.append(" ORDER BY date desc limit 1");
+        sb.append(" ORDER BY t.year desc, t.month desc, t.day desc LIMIT 1");
 
         final String sql = sb.toString();
         debug("descr", sql);
         debug("descr", params.toString());
 
-        try (Cursor c = App.getDatabase()
-                           .rawQuery(sql, params.toArray(new String[]{})))
-        {
-            String profileUUID;
-            int transactionId;
+        Activity activity = (Activity) recyclerView.getContext();
+        // FIXME: handle exceptions?
+        MLDB.queryInBackground(sql, params.toArray(new String[]{}), new MLDB.CallbackHelper() {
+            @Override
+            public void onStart() {
+                model.incrementBusyCounter();
+            }
+            @Override
+            public void onDone() {
+                model.decrementBusyCounter();
+            }
+            @Override
+            public boolean onRow(@NonNull Cursor cursor) {
+                final String profileUUID = cursor.getString(0);
+                final int transactionId = cursor.getInt(1);
+                activity.runOnUiThread(() -> loadTransactionIntoModel(profileUUID, transactionId));
+                return false; // limit 1, by the way
+            }
+            @Override
+            public void onNoRows() {
+                if (Misc.isEmptyOrNull(accFilter))
+                    return;
 
-            if (!c.moveToNext()) {
-                sb = new StringBuilder("select t.profile, t.id from transactions t where t.description=?");
-                sb.append(" ORDER BY date desc LIMIT 1");
+                debug("descr", "Trying transaction search without preferred account filter");
 
-                final String broaderSql = sb.toString();
+                final String broaderSql =
+                        "select t.profile, t.id from transactions t where t.description=?" +
+                        " ORDER BY year desc, month desc, day desc LIMIT 1";
+                params.remove(1);
                 debug("descr", broaderSql);
-                debug("descr", params.toString());
-                try (Cursor c2 = App.getDatabase().rawQuery(broaderSql, new String[]{description})) {
-                    if (!c2.moveToNext()) return;
-
-                    profileUUID = c2.getString(0);
-                    transactionId = c2.getInt(1);
-                }
-            }
-            else {
-                profileUUID = c.getString(0);
-                transactionId = c.getInt(1);
+                debug("descr", description);
+
+                activity.runOnUiThread(() -> {
+                    Snackbar.make(recyclerView, R.string.ignoring_preferred_account,
+                            Snackbar.LENGTH_LONG)
+                            .show();
+                });
+
+                MLDB.queryInBackground(broaderSql, new String[]{description},
+                        new MLDB.CallbackHelper() {
+                            @Override
+                            public void onStart() {
+                                model.incrementBusyCounter();
+                            }
+                            @Override
+                            public boolean onRow(@NonNull Cursor cursor) {
+                                final String profileUUID = cursor.getString(0);
+                                final int transactionId = cursor.getInt(1);
+                                activity.runOnUiThread(
+                                        () -> loadTransactionIntoModel(profileUUID, transactionId));
+                                return false;
+                            }
+                            @Override
+                            public void onDone() {
+                                model.decrementBusyCounter();
+                            }
+                        });
             }
-
-            loadTransactionIntoModel(profileUUID, transactionId);
-        }
+        });
     }
     private void loadTransactionIntoModel(String profileUUID, int transactionId) {
         LedgerTransaction tr;
@@ -313,7 +351,7 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItem
             // TODO perhaps do only one notification about the whole range (notifyDatasetChanged)?
         }
     }
-    public void reset() {
+    void reset() {
         int presentItemCount = model.getAccountCount();
         model.reset();
         notifyItemChanged(0);       // header changed
@@ -321,20 +359,23 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItem
         if (presentItemCount > 2)
             notifyItemRangeRemoved(3, presentItemCount - 2); // all the rest are gone
     }
-    public void updateFocusedItem(int position) {
+    void updateFocusedItem(int position) {
         model.updateFocusedItem(position);
     }
-    public void noteFocusIsOnAccount(int position) {
+    void noteFocusIsOnAccount(int position) {
         model.noteFocusChanged(position, NewTransactionModel.FocusedElement.Account);
     }
-    public void noteFocusIsOnAmount(int position) {
+    void noteFocusIsOnAmount(int position) {
         model.noteFocusChanged(position, NewTransactionModel.FocusedElement.Amount);
     }
-    public void noteFocusIsOnComment(int position) {
+    void noteFocusIsOnComment(int position) {
         model.noteFocusChanged(position, NewTransactionModel.FocusedElement.Comment);
     }
-    public void toggleComment(int position) {
-        model.toggleComment(position);
+    void noteFocusIsOnTransactionComment(int position) {
+        model.noteFocusChanged(position, NewTransactionModel.FocusedElement.TransactionComment);
+    }
+    public void noteFocusIsOnDescription(int pos) {
+        model.noteFocusChanged(pos, NewTransactionModel.FocusedElement.Description);
     }
     private void holdSubmittableChecks() {
         checkHoldCounter++;
@@ -432,7 +473,12 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItem
                     itemsWithAccountForCurrency.add(currName, item);
                 }
 
-                if (acc.isAmountSet()) {
+                if (!acc.isAmountValid()) {
+                    Logger.debug("submittable",
+                            String.format("Not submittable: row %d has an invalid amount", i + 1));
+                    submittable = false;
+                }
+                else if (acc.isAmountSet()) {
                     itemsWithAmountForCurrency.add(currName, item);
                     balance.add(currName, acc.getAmount());
                 }
@@ -604,7 +650,8 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItem
             model.isSubmittable.setValue(false);
         }
     }
-    private class BalanceForCurrency {
+
+    private static class BalanceForCurrency {
         private HashMap<String, Float> hashMap = new HashMap<>();
         float get(String currencyName) {
             Float f = hashMap.get(currencyName);
@@ -625,7 +672,7 @@ class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItem
         }
     }
 
-    private class ItemsForCurrency {
+    private static class ItemsForCurrency {
         private HashMap<String, List<NewTransactionModel.Item>> hashMap = new HashMap<>();
         @NonNull
         List<NewTransactionModel.Item> getList(@Nullable String currencyName) {