--- /dev/null
+/*
+ * Copyright © 2021 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your opinion), any later version.
+ *
+ * MoLe 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 MoLe. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package net.ktnx.mobileledger.dao;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
+import androidx.room.ColumnInfo;
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.Query;
+import androidx.room.Update;
+
+import net.ktnx.mobileledger.db.Transaction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Dao
+public abstract class TransactionDAO extends BaseDAO<Transaction> {
+ static public List<String> unbox(List<DescriptionContainer> list) {
+ ArrayList<String> result = new ArrayList<>(list.size());
+ for (DescriptionContainer item : list) {
+ result.add(item.description);
+ }
+
+ return result;
+ }
+ @Insert
+ public abstract void insertSync(Transaction item);
+
+ @Update
+ public abstract void updateSync(Transaction item);
+
+ @Delete
+ public abstract void deleteSync(Transaction item);
+
+ @Query("SELECT * FROM transactions")
+ public abstract LiveData<List<Transaction>> getAll();
+
+ // not useful for now
+// @Transaction
+// @Query("SELECT * FROM patterns")
+// List<PatternWithAccounts> getPatternsWithAccounts();
+ @Query("SELECT * FROM transactions WHERE profile = :profileUUID AND id = :id")
+ public abstract LiveData<Transaction> getById(@NonNull String profileUUID, long id);
+
+ @Query("SELECT DISTINCT description, CASE WHEN description_upper LIKE :term||'%%' THEN 1 " +
+ " WHEN description_upper LIKE '%%:'||:term||'%%' THEN 2 " +
+ " WHEN description_upper LIKE '%% '||:term||'%%' THEN 3 " +
+ " ELSE 9 END AS ordering " + "FROM description_history " +
+ "WHERE description_upper LIKE '%%'||:term||'%%' " +
+ "ORDER BY ordering, description_upper, rowid ")
+ public abstract List<DescriptionContainer> lookupDescriptionSync(@NonNull String term);
+
+ static public class DescriptionContainer {
+ @ColumnInfo
+ public String description;
+ @ColumnInfo
+ public int ordering;
+ }
+}
import net.ktnx.mobileledger.dao.CurrencyDAO;
import net.ktnx.mobileledger.dao.TemplateAccountDAO;
import net.ktnx.mobileledger.dao.TemplateHeaderDAO;
+import net.ktnx.mobileledger.dao.TransactionDAO;
import java.io.BufferedReader;
import java.io.IOException;
public abstract CurrencyDAO getCurrencyDAO();
public abstract AccountDAO getAccountDAO();
+
+ public abstract TransactionDAO getTransactionDAO();
}
--- /dev/null
+/*
+ * Copyright © 2021 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your opinion), any later version.
+ *
+ * MoLe 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 MoLe. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package net.ktnx.mobileledger.db;
+
+import android.content.Context;
+import android.widget.ArrayAdapter;
+import android.widget.Filter;
+
+import androidx.annotation.NonNull;
+
+import net.ktnx.mobileledger.dao.TransactionDAO;
+import net.ktnx.mobileledger.utils.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TransactionDescriptionAutocompleteAdapter extends ArrayAdapter<String> {
+ private final TransactionFilter filter = new TransactionFilter();
+ private final TransactionDAO dao = DB.get()
+ .getTransactionDAO();
+ public TransactionDescriptionAutocompleteAdapter(Context context) {
+ super(context, android.R.layout.simple_dropdown_item_1line, new ArrayList<>());
+ }
+ @NonNull
+ @Override
+ public Filter getFilter() {
+ return filter;
+ }
+ class TransactionFilter extends Filter {
+ @Override
+ protected FilterResults performFiltering(CharSequence constraint) {
+ FilterResults results = new FilterResults();
+ if (constraint == null) {
+ results.count = 0;
+ return results;
+ }
+
+ Logger.debug("acc", String.format("Looking for account '%s'", constraint));
+ final List<String> matches = TransactionDAO.unbox(dao.lookupDescriptionSync(
+ String.valueOf(constraint)
+ .toUpperCase()));
+ results.values = matches;
+ results.count = matches.size();
+
+ return results;
+ }
+ @Override
+ @SuppressWarnings("unchecked")
+ protected void publishResults(CharSequence constraint, FilterResults results) {
+ if (results.values == null) {
+ notifyDataSetInvalidated();
+ }
+ else {
+ setNotifyOnChange(false);
+ clear();
+ addAll((List<String>) results.values);
+ notifyDataSetChanged();
+ }
+ }
+ }
+}
import android.text.TextWatcher;
import android.view.View;
import android.widget.EditText;
-import android.widget.SimpleCursorAdapter;
+import android.widget.ListAdapter;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import net.ktnx.mobileledger.R;
import net.ktnx.mobileledger.databinding.NewTransactionHeaderRowBinding;
+import net.ktnx.mobileledger.db.TransactionDescriptionAutocompleteAdapter;
import net.ktnx.mobileledger.model.Data;
import net.ktnx.mobileledger.ui.DatePickerFragment;
import net.ktnx.mobileledger.utils.Logger;
-import net.ktnx.mobileledger.utils.MLDB;
import net.ktnx.mobileledger.utils.Misc;
import net.ktnx.mobileledger.utils.SimpleDate;
NewTransactionActivity activity = (NewTransactionActivity) b.getRoot()
.getContext();
- MLDB.hookAutocompletionAdapter(activity, b.newTransactionDescription,
- MLDB.DESCRIPTION_HISTORY_TABLE, "description", false, activity, mProfile);
+ b.newTransactionDescription.setAdapter(
+ new TransactionDescriptionAutocompleteAdapter(activity));
+ b.newTransactionDescription.setOnItemClickListener(
+ (parent, view, position, id) -> activity.descriptionSelected(
+ parent.getItemAtPosition(position)
+ .toString()));
decimalSeparator = "";
Data.locale.observe(activity, locale -> decimalSeparator = String.valueOf(
b.newTransactionDate.setText(head.getFormattedDate());
// avoid triggering completion pop-up
- SimpleCursorAdapter a =
- (SimpleCursorAdapter) b.newTransactionDescription.getAdapter();
+ ListAdapter a = b.newTransactionDescription.getAdapter();
try {
b.newTransactionDescription.setAdapter(null);
b.newTransactionDescription.setText(head.getDescription());
}
finally {
- b.newTransactionDescription.setAdapter(a);
+ b.newTransactionDescription.setAdapter(
+ (TransactionDescriptionAutocompleteAdapter) a);
}
b.transactionComment.setText(head.getComment());
/*
- * Copyright © 2020 Damyan Ivanov.
+ * Copyright © 2021 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
package net.ktnx.mobileledger.ui.transaction_list;
-import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import net.ktnx.mobileledger.R;
import net.ktnx.mobileledger.async.TransactionDateFinder;
+import net.ktnx.mobileledger.db.AccountAutocompleteAdapter;
import net.ktnx.mobileledger.model.Data;
import net.ktnx.mobileledger.model.MobileLedgerProfile;
import net.ktnx.mobileledger.ui.DatePickerFragment;
import net.ktnx.mobileledger.utils.Colors;
import net.ktnx.mobileledger.utils.Globals;
import net.ktnx.mobileledger.utils.Logger;
-import net.ktnx.mobileledger.utils.MLDB;
import net.ktnx.mobileledger.utils.SimpleDate;
import org.jetbrains.annotations.NotNull;
vAccountFilter = view.findViewById(R.id.transaction_list_account_name_filter);
accNameFilter = view.findViewById(R.id.transaction_filter_account_name);
- MLDB.hookAutocompletionAdapter(mainActivity, accNameFilter, "accounts", "name");
+ MobileLedgerProfile profile = Data.getProfile();
+ accNameFilter.setAdapter(new AccountAutocompleteAdapter(mainActivity, profile));
accNameFilter.setOnItemClickListener((parent, v, position, id) -> {
// debug("tmp", "direct onItemClick");
- Cursor c = (Cursor) parent.getItemAtPosition(position);
model.getAccountFilter()
- .setValue(c.getString(1));
+ .setValue(parent.getItemAtPosition(position)
+ .toString());
Globals.hideSoftKeyboard(mainActivity);
});
model.getUpdatingFlag()
.observe(getViewLifecycleOwner(), (flag) -> refreshLayout.setRefreshing(flag));
- MobileLedgerProfile profile = Data.getProfile();
model.getDisplayedTransactions()
.observe(getViewLifecycleOwner(), list -> modelAdapter.setTransactions(list));
view.findViewById(R.id.clearAccountNameFilter)
.setOnClickListener(v -> {
- model.getAccountFilter()
- .setValue(null);
- vAccountFilter.setVisibility(View.GONE);
- menuTransactionListFilter.setVisible(true);
- Globals.hideSoftKeyboard(mainActivity);
- });
+ model.getAccountFilter()
+ .setValue(null);
+ vAccountFilter.setVisibility(View.GONE);
+ menuTransactionListFilter.setVisible(true);
+ Globals.hideSoftKeyboard(mainActivity);
+ });
model.foundTransactionItemIndex.observe(getViewLifecycleOwner(), pos -> {
Logger.debug("go-to-date", String.format(Locale.US, "Found pos %d", pos));
package net.ktnx.mobileledger.utils;
-import android.annotation.TargetApi;
-import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
-import android.os.Build;
-import android.widget.AutoCompleteTextView;
-import android.widget.FilterQueryProvider;
-import android.widget.SimpleCursorAdapter;
import androidx.annotation.NonNull;
import net.ktnx.mobileledger.App;
import net.ktnx.mobileledger.async.DbOpQueue;
-import net.ktnx.mobileledger.async.DescriptionSelectedCallback;
-import net.ktnx.mobileledger.model.Data;
-import net.ktnx.mobileledger.model.MobileLedgerProfile;
import org.jetbrains.annotations.NonNls;
static public void setLongOption(String name, long value) {
setOption(name, String.valueOf(value));
}
- @TargetApi(Build.VERSION_CODES.N)
- public static void hookAutocompletionAdapter(final Context context,
- final AutoCompleteTextView view,
- final String table, final String field) {
- hookAutocompletionAdapter(context, view, table, field, true, null, null);
- }
- @TargetApi(Build.VERSION_CODES.N)
- public static void hookAutocompletionAdapter(final Context context,
- final AutoCompleteTextView view,
- final String table, final String field,
- final boolean profileSpecific,
- final DescriptionSelectedCallback callback,
- final MobileLedgerProfile profile) {
- String[] from = {field};
- int[] to = {android.R.id.text1};
- SimpleCursorAdapter adapter =
- new SimpleCursorAdapter(context, android.R.layout.simple_dropdown_item_1line, null,
- from, to, 0);
- adapter.setStringConversionColumn(1);
-
- FilterQueryProvider provider = constraint -> {
- if (constraint == null)
- return null;
-
- String str = constraint.toString()
- .toUpperCase();
- debug("autocompletion", "Looking for " + str);
-
- String sql;
- String[] params;
- if (profileSpecific) {
- MobileLedgerProfile p = (profile == null) ? Data.getProfile() : profile;
- sql = String.format(
- "SELECT rowid as _id, %s, CASE WHEN %s_upper LIKE ?||'%%' THEN 1 " +
- "WHEN %s_upper LIKE '%%:'||?||'%%' then 2 " +
- "WHEN %s_upper LIKE '%% '||?||'%%' THEN 3 " + "ELSE 9 END " + "FROM %s " +
- "WHERE profile=? AND %s_upper LIKE '%%'||?||'%%' " +
- "ORDER BY 3, %s_upper, 1;", field, field, field, field, table, field,
- field);
- params = new String[]{str, str, str, p.getUuid(), str};
- }
- else {
- sql = String.format(
- "SELECT rowid as _id, %s, CASE WHEN %s_upper LIKE ?||'%%' THEN 1 " +
- "WHEN %s_upper LIKE '%%:'||?||'%%' THEN 2 " +
- "WHEN %s_upper LIKE '%% '||?||'%%' THEN 3 " + "ELSE 9 END " + "FROM %s " +
- "WHERE %s_upper LIKE '%%'||?||'%%' " + "ORDER BY 3, %s_upper, 1;", field,
- field, field, field, table, field, field);
- params = new String[]{str, str, str, str};
- }
- debug("autocompletion", sql);
- SQLiteDatabase db = App.getDatabase();
-
- return db.rawQuery(sql, params);
- };
-
- adapter.setFilterQueryProvider(provider);
-
- view.setAdapter(adapter);
-
- if (callback != null)
- view.setOnItemClickListener(
- (parent, itemView, position, id) -> callback.descriptionSelected(
- String.valueOf(view.getText())));
- }
public static void queryInBackground(@NonNull String statement, String[] params,
@NonNull final CallbackHelper callbackHelper) {
/* All callbacks are called in the new (asynchronous) thread! */