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;
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;
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;
class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItemHolder>
implements DescriptionSelectedCallback {
- NewTransactionModel model;
+ private NewTransactionModel model;
private MobileLedgerProfile mProfile;
private ItemTouchHelper touchHelper;
private RecyclerView recyclerView;
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));
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()
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.date 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 date 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;
// 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
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);
}
+ 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++;
}
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());
}
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);
}
}
- private class ItemsForCurrency {
+ private static class ItemsForCurrency {
private HashMap<String, List<NewTransactionModel.Item>> hashMap = new HashMap<>();
@NonNull
List<NewTransactionModel.Item> getList(@Nullable String currencyName) {