From 53c1e0adfd08bd4a6f36bf3fa7b6e52d968c927d Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sun, 16 Dec 2018 13:12:53 +0000 Subject: [PATCH 01/16] debug-- --- .../net/ktnx/mobileledger/async/RetrieveTransactionsTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index 93132545..b0d423fd 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -117,7 +117,7 @@ public class RetrieveTransactionsTask extends if (isCancelled()) break; if (!line.isEmpty() && (line.charAt(0) == ' ')) continue; Matcher m; - L(String.format("State is %d", state)); + //L(String.format("State is %d", state)); switch (state) { case ParserState.EXPECTING_JOURNAL: if (line.equals("

General Journal

")) { -- 2.39.2 From f8f86b6145e025b787650f7342675622227f9b24 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sun, 16 Dec 2018 16:39:06 +0000 Subject: [PATCH 02/16] color the swipe progress spinner in the accounts summary activity too --- app/src/main/java/net/ktnx/mobileledger/AccountSummary.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java b/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java index 58cdad09..5ad2a57d 100644 --- a/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java +++ b/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java @@ -134,7 +134,9 @@ public class AccountSummary extends AppCompatActivity { if (dy > 0) ((FloatingActionButton) findViewById(R.id.btn_add_transaction)).hide(); } }); - ((SwipeRefreshLayout) findViewById(R.id.account_swiper)).setOnRefreshListener(() -> { + SwipeRefreshLayout swiper = findViewById(R.id.account_swiper); + swiper.setColorSchemeResources(R.color.colorPrimary, R.color.colorAccent); + swiper.setOnRefreshListener(() -> { Log.d("ui", "refreshing accounts via swipe"); update_accounts(true); }); -- 2.39.2 From 6c58c1072c9af6ea0d0f52baeae7f95ba7f7ee2f Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sun, 16 Dec 2018 17:07:44 +0000 Subject: [PATCH 03/16] move DB stuff into a static class downside is that we need to pass a context around --- .../net/ktnx/mobileledger/AccountSummary.java | 15 +- .../mobileledger/AccountSummaryViewModel.java | 16 +- .../mobileledger/NewTransactionActivity.java | 14 +- .../mobileledger/TransactionListActivity.java | 12 +- .../mobileledger/TransactionListAdapter.java | 7 +- .../async/RetrieveAccountsTask.java | 5 +- .../async/RetrieveTransactionsTask.java | 5 +- .../TransactionListViewModel.java | 11 +- .../{MobileLedgerDatabase.java => MLDB.java} | 157 ++++++++++-------- 9 files changed, 120 insertions(+), 122 deletions(-) rename app/src/main/java/net/ktnx/mobileledger/utils/{MobileLedgerDatabase.java => MLDB.java} (60%) diff --git a/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java b/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java index 5ad2a57d..2c9589e3 100644 --- a/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java +++ b/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java @@ -43,7 +43,7 @@ import android.widget.LinearLayout; import net.ktnx.mobileledger.async.RetrieveAccountsTask; import net.ktnx.mobileledger.model.LedgerAccount; -import net.ktnx.mobileledger.utils.MobileLedgerDatabase; +import net.ktnx.mobileledger.utils.MLDB; import java.lang.ref.WeakReference; import java.util.Date; @@ -58,7 +58,6 @@ public class AccountSummary extends AppCompatActivity { private static boolean account_list_needs_update = true; MenuItem mShowHiddenAccounts; SharedPreferences.OnSharedPreferenceChangeListener sBindPreferenceSummaryToValueListener; - private MobileLedgerDatabase dbh; private AccountSummaryViewModel model; private AccountSummaryAdapter modelAdapter; private Menu optMenu; @@ -74,8 +73,6 @@ public class AccountSummary extends AppCompatActivity { Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); - dbh = new MobileLedgerDatabase(this); - drawer = findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); @@ -92,7 +89,7 @@ public class AccountSummary extends AppCompatActivity { } model = ViewModelProviders.of(this).get(AccountSummaryViewModel.class); - List accounts = model.getAccounts(); + List accounts = model.getAccounts(getApplicationContext()); modelAdapter = new AccountSummaryAdapter(accounts); RecyclerView root = findViewById(R.id.account_root); @@ -250,7 +247,7 @@ public class AccountSummary extends AppCompatActivity { } private void prepare_db() { - account_list_last_updated = dbh.get_option_value("last_refresh", (long) 0); + account_list_last_updated = MLDB.get_option_value(this, "last_refresh", (long) 0); } private void update_accounts(boolean force) { @@ -277,12 +274,12 @@ public class AccountSummary extends AppCompatActivity { Snackbar.make(drawer, err_text, Snackbar.LENGTH_LONG ).show(); } else { - dbh.set_option_value("last_refresh", new Date().getTime() ); + MLDB.set_option_value(this, "last_refresh", new Date().getTime()); update_account_table(); } } private void update_account_table() { - model.reloadAccounts(); + model.reloadAccounts(getApplicationContext()); modelAdapter.notifyDataSetChanged(); } void stopSelection() { @@ -301,7 +298,7 @@ public class AccountSummary extends AppCompatActivity { stopSelection(); } public void onConfirmAccSelection(MenuItem item) { - model.commitSelections(); + model.commitSelections(getApplicationContext()); stopSelection(); } } diff --git a/app/src/main/java/net/ktnx/mobileledger/AccountSummaryViewModel.java b/app/src/main/java/net/ktnx/mobileledger/AccountSummaryViewModel.java index f01907b3..f9b5d74f 100644 --- a/app/src/main/java/net/ktnx/mobileledger/AccountSummaryViewModel.java +++ b/app/src/main/java/net/ktnx/mobileledger/AccountSummaryViewModel.java @@ -37,7 +37,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import net.ktnx.mobileledger.model.LedgerAccount; -import net.ktnx.mobileledger.utils.MobileLedgerDatabase; +import net.ktnx.mobileledger.utils.MLDB; import java.util.ArrayList; import java.util.List; @@ -45,24 +45,22 @@ import java.util.List; import static net.ktnx.mobileledger.SettingsActivity.PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS; class AccountSummaryViewModel extends AndroidViewModel { - private MobileLedgerDatabase dbh; private List accounts; public AccountSummaryViewModel(@NonNull Application application) { super(application); - dbh = new MobileLedgerDatabase(application); } - List getAccounts() { + List getAccounts(Context context) { if (accounts == null) { accounts = new ArrayList<>(); - reloadAccounts(); + reloadAccounts(context); } return accounts; } - void reloadAccounts() { + void reloadAccounts(Context context) { accounts.clear(); boolean showingOnlyStarred = PreferenceManager.getDefaultSharedPreferences(getApplication()) @@ -71,7 +69,7 @@ class AccountSummaryViewModel extends AndroidViewModel { if (showingOnlyStarred) sql += " WHERE hidden = 0"; sql += " ORDER BY name"; - try (SQLiteDatabase db = dbh.getReadableDatabase()) { + try (SQLiteDatabase db = MLDB.getReadableDatabase(context)) { try (Cursor cursor = db .rawQuery(sql,null)) { @@ -91,8 +89,8 @@ class AccountSummaryViewModel extends AndroidViewModel { } } } - void commitSelections() { - try(SQLiteDatabase db = dbh.getWritableDatabase()) { + void commitSelections(Context context) { + try(SQLiteDatabase db = MLDB.getWritableDatabase(context)) { db.beginTransaction(); try { for (LedgerAccount acc : accounts) { diff --git a/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java b/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java index 4950a1ef..38289020 100644 --- a/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java @@ -56,7 +56,7 @@ import net.ktnx.mobileledger.async.TaskCallback; import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.model.LedgerTransactionItem; import net.ktnx.mobileledger.ui.DatePickerFragment; -import net.ktnx.mobileledger.utils.MobileLedgerDatabase; +import net.ktnx.mobileledger.utils.MLDB; import java.util.Date; import java.util.Objects; @@ -80,7 +80,6 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal private AutoCompleteTextView text_descr; private static SaveTransactionTask saver; private MenuItem mSave; - private MobileLedgerDatabase dbh; @Override protected void onCreate(Bundle savedInstanceState) { @@ -89,8 +88,6 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); - dbh = new MobileLedgerDatabase(this); - text_date = findViewById(R.id.new_transaction_date); text_date.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override @@ -100,8 +97,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal } }); text_descr = findViewById(R.id.new_transaction_description); - hook_autocompletion_adapter(text_descr, MobileLedgerDatabase - .DESCRIPTION_HISTORY_TABLE, "description"); + hook_autocompletion_adapter(text_descr, MLDB.DESCRIPTION_HISTORY_TABLE, "description"); hook_text_change_listener(text_descr); progress = findViewById(R.id.save_transaction_progress); @@ -113,7 +109,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal AutoCompleteTextView acc_name_view = (AutoCompleteTextView) row.getChildAt(0); TextView amount_view = (TextView) row.getChildAt(1); hook_swipe_listener(row); - hook_autocompletion_adapter(acc_name_view, MobileLedgerDatabase.ACCOUNTS_TABLE, "name"); + hook_autocompletion_adapter(acc_name_view, MLDB.ACCOUNTS_TABLE, "name"); hook_text_change_listener(acc_name_view); hook_text_change_listener(amount_view); // Log.d("swipe", "hooked to row "+i); @@ -270,7 +266,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal String[] col_names = {FontsContract.Columns._ID, field}; MatrixCursor c = new MatrixCursor(col_names); - try (SQLiteDatabase db = dbh.getReadableDatabase()) { + try (SQLiteDatabase db = MLDB.getReadableDatabase(getApplicationContext())) { try (Cursor matches = db.rawQuery(String.format( "SELECT %s as a, case when %s_upper LIKE ?||'%%' then 1 " @@ -358,7 +354,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal if (focus) acc.requestFocus(); hook_swipe_listener(row); - hook_autocompletion_adapter(acc, MobileLedgerDatabase.ACCOUNTS_TABLE, "name"); + hook_autocompletion_adapter(acc, MLDB.ACCOUNTS_TABLE, "name"); hook_text_change_listener(acc); hook_text_change_listener(amt); } diff --git a/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java b/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java index 1073909d..715af08a 100644 --- a/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java @@ -35,7 +35,7 @@ import android.widget.TextView; import net.ktnx.mobileledger.async.RetrieveTransactionsTask; import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.ui.transaction_list.TransactionListViewModel; -import net.ktnx.mobileledger.utils.MobileLedgerDatabase; +import net.ktnx.mobileledger.utils.MLDB; import java.lang.ref.WeakReference; import java.time.ZoneId; @@ -60,8 +60,6 @@ public class TransactionListActivity extends AppCompatActivity { setupActionBar(); - MobileLedgerDatabase dbh = new MobileLedgerDatabase(this); - swiper = findViewById(R.id.transaction_swipe); if (swiper == null) throw new RuntimeException("Can't get hold on the swipe layout"); root = findViewById(R.id.transaction_root); @@ -71,7 +69,7 @@ public class TransactionListActivity extends AppCompatActivity { throw new RuntimeException("Can't get hold on the transaction list progress bar"); tvLastUpdate = findViewById(R.id.transactions_last_update); { - long last_update = dbh.get_option_value("transaction_list_last_update", 0L); + long last_update = MLDB.get_option_value(this, "transaction_list_last_update", 0L); Log.d("transactions", String.format("Last update = %d", last_update)); if (last_update == 0) tvLastUpdate.setText("never"); else { @@ -86,7 +84,7 @@ public class TransactionListActivity extends AppCompatActivity { } } model = ViewModelProviders.of(this).get(TransactionListViewModel.class); - List transactions = model.getTransactions(dbh); + List transactions = model.getTransactions(getApplicationContext()); modelAdapter = new TransactionListAdapter(transactions); RecyclerView root = findViewById(R.id.transaction_root); @@ -157,9 +155,9 @@ public class TransactionListActivity extends AppCompatActivity { progressBar.setVisibility(View.GONE); swiper.setRefreshing(false); if (success) { - MobileLedgerDatabase dbh = new MobileLedgerDatabase(this); Date now = new Date(); - dbh.set_option_value("transaction_list_last_update", now.getTime()); + MLDB.set_option_value(getApplicationContext(), "transaction_list_last_update", + now.getTime()); updateLastUpdateText(now); modelAdapter.notifyDataSetChanged(); } diff --git a/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java b/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java index b82e84ca..d0b2e943 100644 --- a/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java +++ b/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java @@ -33,7 +33,7 @@ import android.widget.TextView; import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.model.LedgerTransactionItem; -import net.ktnx.mobileledger.utils.MobileLedgerDatabase; +import net.ktnx.mobileledger.utils.MLDB; import java.util.Iterator; import java.util.List; @@ -50,9 +50,8 @@ class TransactionListAdapter LedgerTransaction tr = transactions.get(position); Context ctx = holder.row.getContext(); Resources rm = ctx.getResources(); - try (MobileLedgerDatabase dbh = new MobileLedgerDatabase(ctx)) { - try (SQLiteDatabase db = dbh.getReadableDatabase()) { - tr.loadData(db); + try (SQLiteDatabase db = MLDB.getReadableDatabase(ctx.getApplicationContext())) { + tr.loadData(db); holder.tvDescription .setText(String.format("%s\n%s", tr.getDescription(), tr.getDate())); diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java index 8117a198..3d96d327 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java @@ -24,7 +24,7 @@ import android.util.Log; import net.ktnx.mobileledger.AccountSummary; import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.model.LedgerAccount; -import net.ktnx.mobileledger.utils.MobileLedgerDatabase; +import net.ktnx.mobileledger.utils.MLDB; import net.ktnx.mobileledger.utils.NetworkUtil; import java.io.BufferedReader; @@ -58,8 +58,7 @@ public class RetrieveAccountsTask extends android.os.AsyncTask transactions; - public List getTransactions(MobileLedgerDatabase dbh) { + public List getTransactions(Context context) { if (transactions == null) { transactions = new ArrayList<>(); - reloadTransactions(dbh); + reloadTransactions(context); } return transactions; } - private void reloadTransactions(MobileLedgerDatabase dbh) { + private void reloadTransactions(Context context) { transactions.clear(); String sql = "SELECT id FROM transactions ORDER BY date desc, id desc"; - try (SQLiteDatabase db = dbh.getReadableDatabase()) { + try (SQLiteDatabase db = MLDB.getReadableDatabase(context)) { try (Cursor cursor = db.rawQuery(sql, null)) { while (cursor.moveToNext()) { transactions.add(new LedgerTransaction(cursor.getInt(0))); diff --git a/app/src/main/java/net/ktnx/mobileledger/utils/MobileLedgerDatabase.java b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java similarity index 60% rename from app/src/main/java/net/ktnx/mobileledger/utils/MobileLedgerDatabase.java rename to app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java index 7efc0ae8..5fd4e0e6 100644 --- a/app/src/main/java/net/ktnx/mobileledger/utils/MobileLedgerDatabase.java +++ b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java @@ -31,89 +31,56 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.Locale; -public class MobileLedgerDatabase extends SQLiteOpenHelper implements AutoCloseable { - public static final String DB_NAME = "mobile-ledger.db"; +import static net.ktnx.mobileledger.utils.MLDB.DatabaseMode.READ; +import static net.ktnx.mobileledger.utils.MLDB.DatabaseMode.WRITE; + +public final class MLDB { + public enum DatabaseMode { READ, WRITE }; public static final String ACCOUNTS_TABLE = "accounts"; public static final String DESCRIPTION_HISTORY_TABLE = "description_history"; - public static final int LATEST_REVISION = 8; - - private final Context mContext; - - public - MobileLedgerDatabase(Context context) { - super(context, DB_NAME, null, LATEST_REVISION); - Log.d("db", "creating helper instance"); - mContext = context; - } - - @Override - public - void onCreate(SQLiteDatabase db) { - Log.d("db", "onCreate called"); - onUpgrade(db, -1, LATEST_REVISION); - } - - @Override - public - void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Log.d("db", "onUpgrade called"); - for(int i = oldVersion+1; i <= newVersion; i++) applyRevision(db, i); - } - - private void applyRevision(SQLiteDatabase db, int - rev_no) { - final Resources rm = mContext.getResources(); - String rev_file = String.format(Locale.US, "sql_%d", rev_no); + private static MobileLedgerDatabase helperForReading, helperForWriting; - int res_id = rm.getIdentifier(rev_file, "raw", mContext.getPackageName()); - if (res_id == 0) - throw new SQLException(String.format(Locale.US, "No resource for revision %d", rev_no)); - db.beginTransaction(); - try (InputStream res = rm.openRawResource(res_id)) { - Log.d("db", "Applying revision " + String.valueOf(rev_no)); - InputStreamReader isr = new InputStreamReader(res); - BufferedReader reader = new BufferedReader(isr); - - String line; - while ((line = reader.readLine()) != null) { - db.execSQL(line); - } - - db.setTransactionSuccessful(); + public static synchronized SQLiteDatabase getDatabase(Context context, DatabaseMode mode) { + if (mode == READ) { + if (helperForReading == null) helperForReading = new MobileLedgerDatabase(context); + return helperForReading.getReadableDatabase(); } - catch (IOException e) { - Log.e("db", String.format("Error opening raw resource for revision %d", rev_no)); - e.printStackTrace(); - } - finally { - db.endTransaction(); + else { + if (helperForWriting == null) helperForWriting = new MobileLedgerDatabase(context); + return helperForWriting.getWritableDatabase(); } } - public int get_option_value(String name, int default_value) { - String s = get_option_value(name, String.valueOf(default_value)); + public static SQLiteDatabase getReadableDatabase(Context context) { + return getDatabase(context, READ); + } + public static SQLiteDatabase getWritableDatabase(Context context) { + return getDatabase(context, WRITE); + } + static public int get_option_value(Context context, String name, int default_value) { + String s = get_option_value(context, name, String.valueOf(default_value)); try { return Integer.parseInt(s); } catch (Exception e) { - Log.d("db", "returning default int value of "+name, e); + Log.d("db", "returning default int value of " + name, e); return default_value; } } - public long get_option_value(String name, long default_value) { - String s = get_option_value(name, String.valueOf(default_value)); + static public long get_option_value(Context context, String name, long default_value) { + String s = get_option_value(context, name, String.valueOf(default_value)); try { return Long.parseLong(s); } catch (Exception e) { - Log.d("db", "returning default long value of "+name, e); + Log.d("db", "returning default long value of " + name, e); return default_value; } } - public String get_option_value(String name, String default_value) { - Log.d("db", "about to fetch option "+name); - try(SQLiteDatabase db = getReadableDatabase()) { + static public String get_option_value(Context context, String name, String default_value) { + Log.d("db", "about to fetch option " + name); + try (SQLiteDatabase db = getReadableDatabase(context)) { try (Cursor cursor = db .rawQuery("select value from options where name=?", new String[]{name})) { @@ -134,25 +101,69 @@ public class MobileLedgerDatabase extends SQLiteOpenHelper implements AutoClosea } } - public void set_option_value(String name, String value) { - Log.d("db", "setting option "+name+"="+value); - try(SQLiteDatabase db = getWritableDatabase()) { + static public void set_option_value(Context context, String name, String value) { + Log.d("db", "setting option " + name + "=" + value); + try (SQLiteDatabase db = getWritableDatabase(context)) { db.execSQL("insert or replace into options(name, value) values(?, ?);", new String[]{name, value}); } } - public void set_option_value(String name, long value) { - set_option_value(name, String.valueOf(value)); + static public void set_option_value(Context context, String name, long value) { + set_option_value(context, name, String.valueOf(value)); } - public static long get_option_value(Context context, String name, long default_value) { - try(MobileLedgerDatabase db = new MobileLedgerDatabase(context)) { - return db.get_option_value(name, default_value); - } +} + +class MobileLedgerDatabase extends SQLiteOpenHelper implements AutoCloseable { + public static final String DB_NAME = "mobile-ledger.db"; + public static final int LATEST_REVISION = 8; + + private final Context mContext; + + public MobileLedgerDatabase(Context context) { + super(context, DB_NAME, null, LATEST_REVISION); + Log.d("db", "creating helper instance"); + mContext = context; + } + + @Override + public void onCreate(SQLiteDatabase db) { + Log.d("db", "onCreate called"); + onUpgrade(db, -1, LATEST_REVISION); } - public static void set_option_value(Context context, String name, String value) { - try(MobileLedgerDatabase db = new MobileLedgerDatabase(context)) { - db.set_option_value(name, value); + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.d("db", "onUpgrade called"); + for (int i = oldVersion + 1; i <= newVersion; i++) applyRevision(db, i); + } + + private void applyRevision(SQLiteDatabase db, int rev_no) { + final Resources rm = mContext.getResources(); + String rev_file = String.format(Locale.US, "sql_%d", rev_no); + + int res_id = rm.getIdentifier(rev_file, "raw", mContext.getPackageName()); + if (res_id == 0) throw new SQLException( + String.format(Locale.US, "No resource for revision %d", rev_no)); + db.beginTransaction(); + try (InputStream res = rm.openRawResource(res_id)) { + Log.d("db", "Applying revision " + String.valueOf(rev_no)); + InputStreamReader isr = new InputStreamReader(res); + BufferedReader reader = new BufferedReader(isr); + + String line; + while ((line = reader.readLine()) != null) { + db.execSQL(line); + } + + db.setTransactionSuccessful(); + } + catch (IOException e) { + Log.e("db", String.format("Error opening raw resource for revision %d", rev_no)); + e.printStackTrace(); + } + finally { + db.endTransaction(); } } } -- 2.39.2 From 70c486fbea2d6606f68d35fceedc90680fd13f7f Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sun, 16 Dec 2018 17:09:57 +0000 Subject: [PATCH 04/16] reformat/rewrap --- .../net/ktnx/mobileledger/AccountSummary.java | 79 +++---- .../mobileledger/NewTransactionActivity.java | 91 ++++---- .../mobileledger/TransactionListAdapter.java | 55 +++-- .../async/RetrieveAccountsTask.java | 198 +++++++++--------- .../async/RetrieveTransactionsTask.java | 187 +++++++++-------- 5 files changed, 308 insertions(+), 302 deletions(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java b/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java index 2c9589e3..3a59003d 100644 --- a/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java +++ b/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java @@ -52,10 +52,9 @@ import java.util.List; import static net.ktnx.mobileledger.SettingsActivity.PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS; public class AccountSummary extends AppCompatActivity { - DrawerLayout drawer; - private static long account_list_last_updated; private static boolean account_list_needs_update = true; + DrawerLayout drawer; MenuItem mShowHiddenAccounts; SharedPreferences.OnSharedPreferenceChangeListener sBindPreferenceSummaryToValueListener; private AccountSummaryViewModel model; @@ -74,17 +73,20 @@ public class AccountSummary extends AppCompatActivity { setSupportActionBar(toolbar); drawer = findViewById(R.id.drawer_layout); - ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( - this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); + ActionBarDrawerToggle toggle = + new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, + R.string.navigation_drawer_close); drawer.addDrawerListener(toggle); toggle.syncState(); android.widget.TextView ver = drawer.findViewById(R.id.drawer_version_text); try { - PackageInfo pi = getApplicationContext().getPackageManager().getPackageInfo(getPackageName(), 0); + PackageInfo pi = + getApplicationContext().getPackageManager().getPackageInfo(getPackageName(), 0); ver.setText(pi.versionName); - } catch (Exception e) { + } + catch (Exception e) { e.printStackTrace(); } @@ -99,30 +101,33 @@ public class AccountSummary extends AppCompatActivity { llm.setOrientation(LinearLayoutManager.VERTICAL); root.setLayoutManager(llm); - root.addOnItemTouchListener(new RecyclerItemListener(this, root, new RecyclerItemListener.RecyclerTouchListener() { - @Override - public void onClickItem(View v, int position) { - Log.d("list", String.format("item %d clicked", position)); - if (modelAdapter.isSelectionActive()) { - modelAdapter.selectItem(position); - } - } - - @Override - public void onLongClickItem(View v, int position) { - Log.d("list", String.format("item %d long-clicked", position)); - modelAdapter.startSelection(); - if (optMenu != null) { - optMenu.findItem(R.id.menu_acc_summary_cancel_selection).setVisible(true); - optMenu.findItem(R.id.menu_acc_summary_confirm_selection).setVisible(true); - optMenu.findItem(R.id.menu_acc_summary_only_starred).setVisible(false); - } - { - FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.btn_add_transaction); - if (fab != null) fab.hide(); - } - } - })); + root.addOnItemTouchListener(new RecyclerItemListener(this, root, + new RecyclerItemListener.RecyclerTouchListener() { + @Override + public void onClickItem(View v, int position) { + Log.d("list", String.format("item %d clicked", position)); + if (modelAdapter.isSelectionActive()) { + modelAdapter.selectItem(position); + } + } + + @Override + public void onLongClickItem(View v, int position) { + Log.d("list", String.format("item %d long-clicked", position)); + modelAdapter.startSelection(); + if (optMenu != null) { + optMenu.findItem(R.id.menu_acc_summary_cancel_selection) + .setVisible(true); + optMenu.findItem(R.id.menu_acc_summary_confirm_selection) + .setVisible(true); + optMenu.findItem(R.id.menu_acc_summary_only_starred).setVisible(false); + } + { + FloatingActionButton fab = findViewById(R.id.btn_add_transaction); + if (fab != null) fab.hide(); + } + } + })); root.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -190,7 +195,8 @@ public class AccountSummary extends AppCompatActivity { DrawerLayout drawer = findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); - } else { + } + else { super.onBackPressed(); } } @@ -233,8 +239,7 @@ public class AccountSummary extends AppCompatActivity { update_accounts(true); } - public - void onShowOnlyStarredClicked(MenuItem mi) { + public void onShowOnlyStarredClicked(MenuItem mi) { SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); boolean flag = pref.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false); @@ -252,8 +257,10 @@ public class AccountSummary extends AppCompatActivity { private void update_accounts(boolean force) { long now = new Date().getTime(); - if ((now > (account_list_last_updated + (24 * 3600*1000))) || force) { - Log.d("db", "accounts last updated at " + account_list_last_updated+" and now is " + now+". re-fetching"); + if ((now > (account_list_last_updated + (24 * 3600 * 1000))) || force) { + Log.d("db", + "accounts last updated at " + account_list_last_updated + " and now is " + now + + ". re-fetching"); update_accounts(); } } @@ -271,7 +278,7 @@ public class AccountSummary extends AppCompatActivity { if (error != 0) { String err_text = getResources().getString(error); Log.d("visual", String.format("showing snackbar: %s", err_text)); - Snackbar.make(drawer, err_text, Snackbar.LENGTH_LONG ).show(); + Snackbar.make(drawer, err_text, Snackbar.LENGTH_LONG).show(); } else { MLDB.set_option_value(this, "last_refresh", new Date().getTime()); diff --git a/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java b/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java index 38289020..22b518a0 100644 --- a/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java @@ -74,11 +74,11 @@ import java.util.Objects; * */ public class NewTransactionActivity extends AppCompatActivity implements TaskCallback { + private static SaveTransactionTask saver; private TableLayout table; private ProgressBar progress; private TextView text_date; private AutoCompleteTextView text_descr; - private static SaveTransactionTask saver; private MenuItem mSave; @Override @@ -91,8 +91,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal text_date = findViewById(R.id.new_transaction_date); text_date.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override - public - void onFocusChange(View v, boolean hasFocus) { + public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) pickTransactionDate(v); } }); @@ -117,8 +116,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal } @Override - protected - void onStart() { + protected void onStart() { super.onStart(); if (text_descr.getText().toString().isEmpty()) text_descr.requestFocus(); } @@ -152,14 +150,13 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal LedgerTransaction tr = new LedgerTransaction(date, text_descr.getText().toString()); TableLayout table = findViewById(R.id.new_transaction_accounts_table); - for ( int i = 0; i < table.getChildCount(); i++ ) { + for (int i = 0; i < table.getChildCount(); i++) { TableRow row = (TableRow) table.getChildAt(i); String acc = ((TextView) row.getChildAt(0)).getText().toString(); String amt = ((TextView) row.getChildAt(1)).getText().toString(); LedgerTransactionItem item = - amt.length() > 0 - ? new LedgerTransactionItem( acc, Float.parseFloat(amt)) - : new LedgerTransactionItem( acc ); + amt.length() > 0 ? new LedgerTransactionItem(acc, Float.parseFloat(amt)) + : new LedgerTransactionItem(acc); tr.add_item(item); } @@ -211,11 +208,11 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal // Toast.makeText(NewTransactionActivity.this, "LEFT", Toast.LENGTH_LONG).show(); } else { - Snackbar.make(table, R.string.msg_at_least_two_accounts_are_required, Snackbar.LENGTH_LONG) - .setAction("Action", null).show(); + Snackbar.make(table, R.string.msg_at_least_two_accounts_are_required, + Snackbar.LENGTH_LONG).setAction("Action", null).show(); } } -// @Override + // @Override // public boolean performClick(View view, MotionEvent m) { // return true; // } @@ -247,7 +244,8 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal } @TargetApi(Build.VERSION_CODES.N) - private void hook_autocompletion_adapter(final AutoCompleteTextView view, final String table, final String field) { + private void hook_autocompletion_adapter(final AutoCompleteTextView view, final String table, + final String field) { String[] from = {field}; int[] to = {android.R.id.text1}; SimpleCursorAdapter adapter = @@ -257,8 +255,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal FilterQueryProvider provider = new FilterQueryProvider() { @Override - public - Cursor runQuery(CharSequence constraint) { + public Cursor runQuery(CharSequence constraint) { if (constraint == null) return null; String str = constraint.toString().toUpperCase(); @@ -269,11 +266,11 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal try (SQLiteDatabase db = MLDB.getReadableDatabase(getApplicationContext())) { try (Cursor matches = db.rawQuery(String.format( - "SELECT %s as a, 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 2, 1;", field, field, field, field, table, field), + "SELECT %s as a, 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 2, 1;", + field, field, field, field, table, field), new String[]{str, str, str, str})) { int i = 0; @@ -313,16 +310,18 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal } public int dp2px(float dp) { - return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics())); + return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, + getResources().getDisplayMetrics())); } private void do_add_account_row(boolean focus) { final AutoCompleteTextView acc = new AutoCompleteTextView(this); - acc.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT, 9f)); + acc.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, + TableRow.LayoutParams.WRAP_CONTENT, 9f)); acc.setHint(R.string.new_transaction_account_hint); acc.setWidth(0); - acc.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_ENTER_ACTION - | EditorInfo.IME_FLAG_NAVIGATE_NEXT); + acc.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_ENTER_ACTION | + EditorInfo.IME_FLAG_NAVIGATE_NEXT); acc.setSingleLine(true); final EditText amt = new EditText(this); @@ -330,7 +329,8 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal TableRow.LayoutParams.MATCH_PARENT, 1f)); amt.setHint(R.string.new_transaction_amount_hint); amt.setWidth(0); - amt.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED | InputType.TYPE_NUMBER_FLAG_DECIMAL ); + amt.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED | + InputType.TYPE_NUMBER_FLAG_DECIMAL); amt.setMinWidth(dp2px(40)); amt.setTextAlignment(EditText.TEXT_ALIGNMENT_VIEW_END); amt.setImeOptions(EditorInfo.IME_ACTION_DONE); @@ -345,7 +345,8 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal acc.setNextFocusRightId(amt.getId()); final TableRow row = new TableRow(this); - row.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.MATCH_PARENT)); + row.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, + TableRow.LayoutParams.MATCH_PARENT)); row.setGravity(Gravity.BOTTOM); row.addView(acc); row.addView(amt); @@ -363,8 +364,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal do_add_account_row(true); } - public - void resetTransactionFromMenu(MenuItem item) { + public void resetTransactionFromMenu(MenuItem item) { reset_form(); } @@ -372,8 +372,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal save_transaction(); } - private - boolean is_zero(float f) { + private boolean is_zero(float f) { return (f < 0.005) && (f > -0.005); } @@ -435,22 +434,21 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal } } - if ((empty_rows == 0) && ((table.getChildCount() == accounts) || (table.getChildCount() - == amounts))) + if ((empty_rows == 0) && + ((table.getChildCount() == accounts) || (table.getChildCount() == amounts))) { do_add_account_row(false); } - Log.d("submittable", String.format("accounts=%d, accounts_with_values=%s, " - + "amounts_with_accounts=%d, amounts=%d, running_total=%1.2f, " - + "single_empty_with_acc=%s", accounts, accounts_with_values, - amounts_with_accounts, amounts, running_total, + Log.d("submittable", String.format("accounts=%d, accounts_with_values=%s, " + + "amounts_with_accounts=%d, amounts=%d, running_total=%1.2f, " + + "single_empty_with_acc=%s", accounts, + accounts_with_values, amounts_with_accounts, amounts, running_total, (single_empty_amount && single_empty_amount_has_account) ? "true" : "false")); - if (have_description && (accounts >= 2) && (accounts_with_values >= (accounts - 1)) && ( - amounts_with_accounts == amounts) && ( - single_empty_amount && single_empty_amount_has_account || is_zero( - running_total))) + if (have_description && (accounts >= 2) && (accounts_with_values >= (accounts - 1)) && + (amounts_with_accounts == amounts) && + (single_empty_amount && single_empty_amount_has_account || is_zero(running_total))) { if (mSave != null) mSave.setVisible(true); } @@ -472,8 +470,7 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal } @Override - public - void done(String error) { + public void done(String error) { progress.setVisibility(View.INVISIBLE); Log.d("visuals", "hiding progress"); @@ -491,15 +488,15 @@ public class NewTransactionActivity extends AppCompatActivity implements TaskCal text_descr.requestFocus(); - while(table.getChildCount() > 2) { + while (table.getChildCount() > 2) { table.removeViewAt(2); } - for( int i = 0; i < 2; i++ ) { + for (int i = 0; i < 2; i++) { TableRow tr = (TableRow) table.getChildAt(i); - if ( tr == null) break; + if (tr == null) break; - ((TextView)tr.getChildAt(0)).setText(""); - ((TextView)tr.getChildAt(1)).setText(""); + ((TextView) tr.getChildAt(0)).setText(""); + ((TextView) tr.getChildAt(1)).setText(""); } } } diff --git a/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java b/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java index d0b2e943..263aa96e 100644 --- a/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java +++ b/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java @@ -53,37 +53,34 @@ class TransactionListAdapter try (SQLiteDatabase db = MLDB.getReadableDatabase(ctx.getApplicationContext())) { tr.loadData(db); - holder.tvDescription - .setText(String.format("%s\n%s", tr.getDescription(), tr.getDate())); - TableLayout tbl = holder.row.findViewById(R.id.transaction_row_acc_amounts); - tbl.removeAllViews(); - for (Iterator it = tr.getItemsIterator(); it.hasNext(); ) { - LedgerTransactionItem acc = it.next(); - TableRow row = new TableRow(holder.row.getContext()); - TextView child = new TextView(ctx); - child.setText(acc.getShortAccountName()); - row.addView(child); - child = new TextView(ctx); - child.setText(acc.toString()); - row.addView(child); - tbl.addView(row); - } - - if (position % 2 == 0) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) holder.row - .setBackgroundColor( - rm.getColor(R.color.table_row_even_bg, ctx.getTheme())); - else holder.row.setBackgroundColor(rm.getColor(R.color.table_row_even_bg)); - } - else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) holder.row - .setBackgroundColor( - rm.getColor(R.color.drawer_background, ctx.getTheme())); - else holder.row.setBackgroundColor(rm.getColor(R.color.drawer_background)); - } + holder.tvDescription + .setText(String.format("%s\n%s", tr.getDescription(), tr.getDate())); + TableLayout tbl = holder.row.findViewById(R.id.transaction_row_acc_amounts); + tbl.removeAllViews(); + for (Iterator it = tr.getItemsIterator(); it.hasNext(); ) { + LedgerTransactionItem acc = it.next(); + TableRow row = new TableRow(holder.row.getContext()); + TextView child = new TextView(ctx); + child.setText(acc.getShortAccountName()); + row.addView(child); + child = new TextView(ctx); + child.setText(acc.toString()); + row.addView(child); + tbl.addView(row); + } - holder.row.setTag(R.id.POS, position); + if (position % 2 == 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) holder.row + .setBackgroundColor(rm.getColor(R.color.table_row_even_bg, ctx.getTheme())); + else holder.row.setBackgroundColor(rm.getColor(R.color.table_row_even_bg)); } + else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) holder.row + .setBackgroundColor(rm.getColor(R.color.drawer_background, ctx.getTheme())); + else holder.row.setBackgroundColor(rm.getColor(R.color.drawer_background)); + } + + holder.row.setTag(R.id.POS, position); } } diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java index 3d96d327..a342ca4d 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java @@ -41,9 +41,8 @@ import java.util.regex.Pattern; public class RetrieveAccountsTask extends android.os.AsyncTask { int error; - - private SharedPreferences pref; WeakReference mContext; + private SharedPreferences pref; public RetrieveAccountsTask(WeakReference context) { mContext = context; @@ -56,110 +55,116 @@ public class RetrieveAccountsTask extends android.os.AsyncTask\\s*([-+]?[\\d.,]+)(?:\\s+(\\S+))?"); + Pattern tr_re = Pattern.compile(""); + Pattern descriptions_line_re = + Pattern.compile("\\bdescriptionsSuggester\\s*=\\s*new\\b"); + Pattern description_items_re = + Pattern.compile("\"value\":\"([^\"]+)\""); + int count = 0; + while ((line = buf.readLine()) != null) { + Matcher m = account_name_re.matcher(line); + if (m.find()) { + String acct_encoded = m.group(1); + String acct_name = URLDecoder.decode(acct_encoded, "UTF-8"); + acct_name = acct_name.replace("\"", ""); + Log.d("account-parser", acct_name); + + addAccount(db, acct_name); + publishProgress(++count); + + last_account_name = acct_name; + + continue; + } - Matcher tr_m = tr_re.matcher(line); - if (tr_m.find()) { - Log.d("account-parser", " - another account expected"); - last_account_name = null; - continue; - } + Matcher tr_m = tr_re.matcher(line); + if (tr_m.find()) { + Log.d("account-parser", " - another account expected"); + last_account_name = null; + continue; + } - if (last_account_name != null) { - m = value_re.matcher(line); - boolean match_found = false; - while (m.find()) { - match_found = true; - String value = m.group(1); - String currency = m.group(2); - if (currency == null) currency = ""; - value = value.replace(',', '.'); - Log.d("db", "curr=" + currency + ", value=" + value); - db.execSQL( - "insert or replace into account_values(account, currency, value, keep) values(?, ?, ?, 1);", - new Object[]{last_account_name, currency, Float.valueOf(value) - }); - } - - if (match_found) continue; + if (last_account_name != null) { + m = value_re.matcher(line); + boolean match_found = false; + while (m.find()) { + match_found = true; + String value = m.group(1); + String currency = m.group(2); + if (currency == null) currency = ""; + value = value.replace(',', '.'); + Log.d("db", "curr=" + currency + ", value=" + value); + db.execSQL( + "insert or replace into account_values(account, currency, value, keep) values(?, ?, ?, 1);", + new Object[]{last_account_name, currency, + Float.valueOf(value) + }); } - m = descriptions_line_re.matcher(line); - if (m.find()) { - db.execSQL("update description_history set keep=0;"); - m = description_items_re.matcher(line); - while (m.find()) { - String description = m.group(1); - if (description.isEmpty()) continue; - - Log.d("db", String.format("Stored description: %s", - description)); - db.execSQL("insert or replace into description_history" - + "(description, description_upper, keep) " + "values(?, ?, 1);", - new Object[]{description, description.toUpperCase() - }); - } - } + if (match_found) continue; } - db.execSQL("delete from account_values where keep=0;"); - db.execSQL("delete from accounts where keep=0;"); -// db.execSQL("delete from description_history where keep=0;"); - db.setTransactionSuccessful(); - } - finally { - db.endTransaction(); + m = descriptions_line_re.matcher(line); + if (m.find()) { + db.execSQL("update description_history set keep=0;"); + m = description_items_re.matcher(line); + while (m.find()) { + String description = m.group(1); + if (description.isEmpty()) continue; + + Log.d("db", String.format("Stored description: %s", + description)); + db.execSQL("insert or replace into description_history" + + "(description, description_upper, keep) " + + "values(?, ?, 1);", + new Object[]{description, description.toUpperCase() + }); + } + } } + db.execSQL("delete from account_values where keep=0;"); + db.execSQL("delete from accounts where keep=0;"); +// db.execSQL("delete from description_history where keep=0;"); + db.setTransactionSuccessful(); + } + finally { + db.endTransaction(); } + } } } - } catch (MalformedURLException e) { + } + catch (MalformedURLException e) { error = R.string.err_bad_backend_url; e.printStackTrace(); } @@ -182,11 +187,10 @@ public class RetrieveAccountsTask extends android.os.AsyncTaskGeneral Journal")) { - state = ParserState.EXPECTING_TRANSACTION; - L("→ expecting transaction"); - } - break; - case ParserState.EXPECTING_TRANSACTION: - m = transactionStartPattern.matcher(line); - if (m.find()) { - transactionId = Integer.valueOf(m.group(1)); - state = ParserState.EXPECTING_TRANSACTION_DESCRIPTION; - L(String.format("found transaction %d → expecting " + - "description", transactionId)); - progress.setProgress(++transactionCount); - if (progress.getTotal() == Progress.INDETERMINATE) - progress.setTotal(transactionId); - publishProgress(progress); - } - m = endPattern.matcher(line); - if (m.find()) { - L("--- transaction list complete ---"); - success = true; - break LINES; - } - break; - case ParserState.EXPECTING_TRANSACTION_DESCRIPTION: - m = transactionDescriptionPattern.matcher(line); - if (m.find()) { - if (transactionId == 0) - throw new TransactionParserException( - "Transaction Id is 0 while expecting " + - "description"); + int transactionCount = 0; + int transactionId = 0; + LedgerTransaction transaction = null; + LINES: + while ((line = buf.readLine()) != null) { + if (isCancelled()) break; + Matcher m; + //L(String.format("State is %d", state)); + switch (state) { + case ParserState.EXPECTING_JOURNAL: + if (!line.isEmpty() && (line.charAt(0) == ' ')) continue; + if (line.equals("

General Journal

")) { + state = ParserState.EXPECTING_TRANSACTION; + L("→ expecting transaction"); + } + break; + case ParserState.EXPECTING_TRANSACTION: + if (!line.isEmpty() && (line.charAt(0) == ' ')) continue; + m = transactionStartPattern.matcher(line); + if (m.find()) { + transactionId = Integer.valueOf(m.group(1)); + state = ParserState.EXPECTING_TRANSACTION_DESCRIPTION; + L(String.format( + "found transaction %d → expecting " + "description", + transactionId)); + progress.setProgress(++transactionCount); + if (progress.getTotal() == Progress.INDETERMINATE) + progress.setTotal(transactionId); + publishProgress(progress); + } + m = endPattern.matcher(line); + if (m.find()) { + L("--- transaction list complete ---"); + success = true; + break LINES; + } + break; + case ParserState.EXPECTING_TRANSACTION_DESCRIPTION: + if (!line.isEmpty() && (line.charAt(0) == ' ')) continue; + m = transactionDescriptionPattern.matcher(line); + if (m.find()) { + if (transactionId == 0) + throw new TransactionParserException( + "Transaction Id is 0 while expecting " + + "description"); - transaction = - new LedgerTransaction(transactionId, m.group(1), - m.group(2)); - state = ParserState.EXPECTING_TRANSACTION_DETAILS; - L(String.format("transaction %d created for %s (%s) →" + - " expecting details", transactionId, - m.group(1), m.group(2))); - } - break; - case ParserState.EXPECTING_TRANSACTION_DETAILS: - if (line.isEmpty()) { - // transaction data collected - transaction.insertInto(db); + transaction = + new LedgerTransaction(transactionId, m.group(1), + m.group(2)); + state = ParserState.EXPECTING_TRANSACTION_DETAILS; + L(String.format("transaction %d created for %s (%s) →" + + " expecting details", transactionId, + m.group(1), m.group(2))); + } + break; + case ParserState.EXPECTING_TRANSACTION_DETAILS: + if (line.isEmpty()) { + // transaction data collected + transaction.insertInto(db); - state = ParserState.EXPECTING_TRANSACTION; - L(String.format("transaction %s saved → expecting " + - "transaction", transaction.getId())); + state = ParserState.EXPECTING_TRANSACTION; + L(String.format( + "transaction %s saved → expecting " + "transaction", + transaction.getId())); // sounds like a good idea, but transaction-1 may not be the first one chronologically // for example, when you add the initial seeding transaction after entering some others @@ -176,33 +180,30 @@ public class RetrieveTransactionsTask extends // "parser"); // break LINES; // } + } + else { + m = transactionDetailsPattern.matcher(line); + if (m.find()) { + String acc_name = m.group(1); + String amount = m.group(2); + amount = amount.replace(',', '.'); + transaction.add_item(new LedgerTransactionItem(acc_name, + Float.valueOf(amount))); + L(String.format("%s = %s", acc_name, amount)); } - else { - m = transactionDetailsPattern.matcher(line); - if (m.find()) { - String acc_name = m.group(1); - String amount = m.group(2); - amount = amount.replace(',', '.'); - transaction.add_item( - new LedgerTransactionItem(acc_name, - Float.valueOf(amount))); - L(String.format("%s = %s", acc_name, amount)); - } - else throw new IllegalStateException(String.format( - "Can't parse transaction details")); - } - break; - default: - throw new RuntimeException( - String.format("Unknown " + "parser state %d", - state)); - } + else throw new IllegalStateException( + String.format("Can't parse transaction details")); + } + break; + default: + throw new RuntimeException( + String.format("Unknown " + "parser state %d", state)); } - if (!isCancelled()) db.setTransactionSuccessful(); - } - finally { - db.endTransaction(); } + if (!isCancelled()) db.setTransactionSuccessful(); + } + finally { + db.endTransaction(); } } } -- 2.39.2 From 9244cf0f5edae3491bd5d117f065f8a3d2831e72 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sun, 16 Dec 2018 17:16:37 +0000 Subject: [PATCH 05/16] open SQLite db with write-ahead logging enabled this allows writers not to block readers --- app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java index 5fd4e0e6..9d8950a6 100644 --- a/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java +++ b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java @@ -35,7 +35,8 @@ import static net.ktnx.mobileledger.utils.MLDB.DatabaseMode.READ; import static net.ktnx.mobileledger.utils.MLDB.DatabaseMode.WRITE; public final class MLDB { - public enum DatabaseMode { READ, WRITE }; + public enum DatabaseMode {READ, WRITE} + public static final String ACCOUNTS_TABLE = "accounts"; public static final String DESCRIPTION_HISTORY_TABLE = "description_history"; private static MobileLedgerDatabase helperForReading, helperForWriting; @@ -124,6 +125,7 @@ class MobileLedgerDatabase extends SQLiteOpenHelper implements AutoCloseable { super(context, DB_NAME, null, LATEST_REVISION); Log.d("db", "creating helper instance"); mContext = context; + super.setWriteAheadLoggingEnabled(true); } @Override -- 2.39.2 From b78adb39561c840d31f537d5516040352671a805 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sun, 16 Dec 2018 18:01:34 +0000 Subject: [PATCH 06/16] drop shadow below the info about list freshness --- .../mobileledger/TransactionListAdapter.java | 5 ++-- app/src/main/res/drawable/drop_shadow.xml | 24 +++++++++++++++++++ .../res/layout/transaction_list_fragment.xml | 7 ++++++ app/src/main/res/values/colors.xml | 1 + 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/drawable/drop_shadow.xml diff --git a/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java b/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java index 263aa96e..267b759e 100644 --- a/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java +++ b/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java @@ -76,8 +76,9 @@ class TransactionListAdapter } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) holder.row - .setBackgroundColor(rm.getColor(R.color.drawer_background, ctx.getTheme())); - else holder.row.setBackgroundColor(rm.getColor(R.color.drawer_background)); + .setBackgroundColor(rm.getColor(R.color.table_row_odd_bg, ctx + .getTheme())); + else holder.row.setBackgroundColor(rm.getColor(R.color.table_row_odd_bg)); } holder.row.setTag(R.id.POS, position); diff --git a/app/src/main/res/drawable/drop_shadow.xml b/app/src/main/res/drawable/drop_shadow.xml new file mode 100644 index 00000000..01f3b027 --- /dev/null +++ b/app/src/main/res/drawable/drop_shadow.xml @@ -0,0 +1,24 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/transaction_list_fragment.xml b/app/src/main/res/layout/transaction_list_fragment.xml index bc9ad599..19bb72fa 100644 --- a/app/src/main/res/layout/transaction_list_fragment.xml +++ b/app/src/main/res/layout/transaction_list_fragment.xml @@ -50,6 +50,13 @@ android:text="TextView" /> + + #4db6ac #289d29b1 #ffffffff + #28fae0ff -- 2.39.2 From 1857937cbdb55199cb9391a7b42766d6dcba80c8 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Wed, 19 Dec 2018 20:22:41 +0000 Subject: [PATCH 07/16] refresh transaction list upon database update from the backend --- .../java/net/ktnx/mobileledger/TransactionListActivity.java | 2 +- .../ktnx/mobileledger/async/RetrieveTransactionsTask.java | 5 +++-- .../ui/transaction_list/TransactionListViewModel.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java b/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java index 715af08a..39323f7b 100644 --- a/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java @@ -47,7 +47,7 @@ public class TransactionListActivity extends AppCompatActivity { private SwipeRefreshLayout swiper; private RecyclerView root; private ProgressBar progressBar; - private TransactionListViewModel model; + public TransactionListViewModel model; private TextView tvLastUpdate; private TransactionListAdapter modelAdapter; @Override diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index 63b30b5c..e63f30d2 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -18,7 +18,6 @@ package net.ktnx.mobileledger.async; import android.annotation.SuppressLint; -import android.content.Context; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; @@ -92,7 +91,7 @@ public class RetrieveTransactionsTask extends NetworkUtil.prepare_connection(params[0].getBackendPref(), "journal"); http.setAllowUserInteraction(false); publishProgress(progress); - Context ctx = contextRef.get(); + TransactionListActivity ctx = contextRef.get(); if (ctx == null) return null; try (SQLiteDatabase db = MLDB.getWritableDatabase(ctx)) { try (InputStream resp = http.getInputStream()) { @@ -207,6 +206,8 @@ public class RetrieveTransactionsTask extends } } } + + if (success && !isCancelled()) ctx.model.reloadTransactions(ctx); } catch (MalformedURLException e) { error = R.string.err_bad_backend_url; diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListViewModel.java b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListViewModel.java index 0ce37f2c..53fb742f 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListViewModel.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListViewModel.java @@ -40,7 +40,7 @@ public class TransactionListViewModel extends ViewModel { return transactions; } - private void reloadTransactions(Context context) { + public void reloadTransactions(Context context) { transactions.clear(); String sql = "SELECT id FROM transactions ORDER BY date desc, id desc"; -- 2.39.2 From be05b80855f5e1f7d9d69426ed2a6ddfdd6d5a60 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Wed, 19 Dec 2018 20:23:53 +0000 Subject: [PATCH 08/16] transactions may come in random order from the backend --- .../net/ktnx/mobileledger/async/RetrieveTransactionsTask.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index e63f30d2..23f75c9c 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -133,7 +133,8 @@ public class RetrieveTransactionsTask extends "found transaction %d → expecting " + "description", transactionId)); progress.setProgress(++transactionCount); - if (progress.getTotal() == Progress.INDETERMINATE) + if ((progress.getTotal() == Progress.INDETERMINATE) || + (progress.getTotal() < transactionId)) progress.setTotal(transactionId); publishProgress(progress); } -- 2.39.2 From a686c3293dd0dbbe49db7fc0f287c451d6b2ecd8 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Wed, 19 Dec 2018 20:48:48 +0000 Subject: [PATCH 09/16] transactions.id -> integer --- .../mobileledger/model/LedgerTransaction.java | 23 ++++++++----------- .../net/ktnx/mobileledger/utils/MLDB.java | 2 +- app/src/main/res/raw/sql_9.sql | 9 ++++++++ 3 files changed, 20 insertions(+), 14 deletions(-) create mode 100644 app/src/main/res/raw/sql_9.sql diff --git a/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java b/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java index fab4ff3e..c4127ab8 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java @@ -41,13 +41,13 @@ public class LedgerTransaction { return Float.compare(o1.getAmount(), o2.getAmount()); } }; - private String id; + private Integer id; private String date; private String description; private ArrayList items; private String dataHash; private boolean dataLoaded; - public LedgerTransaction(String id, String date, String description) { + public LedgerTransaction(Integer id, String date, String description) { this.id = id; this.date = date; this.description = description; @@ -55,9 +55,6 @@ public class LedgerTransaction { this.dataHash = null; dataLoaded = false; } - public LedgerTransaction(int id, String date, String description) { - this(String.valueOf(id), date, description); - } public LedgerTransaction(String date, String description) { this(null, date, description); } @@ -96,13 +93,13 @@ public class LedgerTransaction { } }; } - public String getId() { + public int getId() { return id; } public void insertInto(SQLiteDatabase db) { fillDataHash(); db.execSQL("INSERT INTO transactions(id, date, description, data_hash) values(?,?,?,?)", - new String[]{id, date, description}); + new Object[]{id, date, description, dataHash}); for (LedgerTransactionItem item : items) { db.execSQL("INSERT INTO transaction_accounts(transaction_id, account_name, amount, " + @@ -137,20 +134,20 @@ public class LedgerTransaction { public void loadData(SQLiteDatabase db) { if (dataLoaded) return; - try (Cursor cTr = db.rawQuery("SELECT date, description from transactions WHERE " + - "id=?",new String[]{id})) { + try (Cursor cTr = db.rawQuery("SELECT date, description from transactions WHERE id=?", + new String[]{String.valueOf(id)})) + { if (cTr.moveToFirst()) { date = cTr.getString(0); description = cTr.getString(1); try (Cursor cAcc = db.rawQuery("SELECT account_name, amount, currency FROM " + "transaction_accounts WHERE transaction_id = ?", - new String[]{id})) + new String[]{String.valueOf(id)})) { while (cAcc.moveToNext()) { - add_item( - new LedgerTransactionItem(cAcc.getString(0), cAcc.getFloat(1), - cAcc.getString(2))); + add_item(new LedgerTransactionItem(cAcc.getString(0), cAcc.getFloat(1), + cAcc.getString(2))); } dataLoaded = true; diff --git a/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java index 9d8950a6..2773dc9f 100644 --- a/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java +++ b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java @@ -117,7 +117,7 @@ public final class MLDB { class MobileLedgerDatabase extends SQLiteOpenHelper implements AutoCloseable { public static final String DB_NAME = "mobile-ledger.db"; - public static final int LATEST_REVISION = 8; + public static final int LATEST_REVISION = 9; private final Context mContext; diff --git a/app/src/main/res/raw/sql_9.sql b/app/src/main/res/raw/sql_9.sql new file mode 100644 index 00000000..936cec67 --- /dev/null +++ b/app/src/main/res/raw/sql_9.sql @@ -0,0 +1,9 @@ +alter table transactions add keep boolean default 1 not null; +update transactions set keep = 1; +create table transactions_new(id integer, date varchar, description varchar, data_hash varchar, keep boolean); +insert into transactions_new(id, date, description, data_hash, keep) select cast(id as integer), date, description, data_hash, keep from transactions; +drop table transactions; +create table transactions(id integer primary key, date varchar, description varchar, data_hash varchar, keep boolean); +create unique index un_transactions_data_hash on transactions(data_hash); +insert into transactions(id, date, description, data_hash, keep) select id, date, description, data_hash, keep from transactions_new; +drop table transactions_new; \ No newline at end of file -- 2.39.2 From 483bc7255c2d181093d154b26430f081308cd81f Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Wed, 19 Dec 2018 20:49:11 +0000 Subject: [PATCH 10/16] progressive update of transaction list in DB, stop after 100 matches in the hope that no one will edit transactions older than 100 entries --- .../async/RetrieveTransactionsTask.java | 44 +++++++++++++++---- .../mobileledger/model/LedgerTransaction.java | 12 +++++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index 23f75c9c..451b164e 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -21,7 +21,6 @@ import android.annotation.SuppressLint; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; -import android.util.Log; import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.TransactionListActivity; @@ -58,7 +57,7 @@ public class RetrieveTransactionsTask extends this.contextRef = contextRef; } private static final void L(String msg) { - Log.d("transaction-parser", msg); +// Log.d("transaction-parser", msg); } @Override protected void onProgressUpdate(Progress... values) { @@ -85,6 +84,7 @@ public class RetrieveTransactionsTask extends @Override protected Void doInBackground(Params... params) { Progress progress = new Progress(); + int maxTransactionId = Progress.INDETERMINATE; success = false; try { HttpURLConnection http = @@ -99,16 +99,16 @@ public class RetrieveTransactionsTask extends String.format("HTTP error %d", http.getResponseCode())); db.beginTransaction(); try { - db.execSQL("DELETE FROM transactions;"); - db.execSQL("DELETE FROM transaction_accounts"); + db.execSQL("UPDATE transactions set keep=0"); int state = ParserState.EXPECTING_JOURNAL; String line; BufferedReader buf = new BufferedReader(new InputStreamReader(resp, "UTF-8")); - int transactionCount = 0; + int processedTransactionCount = 0; int transactionId = 0; + int matchedTransactionsCount = 0; LedgerTransaction transaction = null; LINES: while ((line = buf.readLine()) != null) { @@ -132,7 +132,9 @@ public class RetrieveTransactionsTask extends L(String.format( "found transaction %d → expecting " + "description", transactionId)); - progress.setProgress(++transactionCount); + progress.setProgress(++processedTransactionCount); + if (maxTransactionId < transactionId) + maxTransactionId = transactionId; if ((progress.getTotal() == Progress.INDETERMINATE) || (progress.getTotal() < transactionId)) progress.setTotal(transactionId); @@ -166,7 +168,30 @@ public class RetrieveTransactionsTask extends case ParserState.EXPECTING_TRANSACTION_DETAILS: if (line.isEmpty()) { // transaction data collected - transaction.insertInto(db); + if (transaction.existsInDb(db)) { + db.execSQL("UPDATE transactions SET keep = 1 WHERE id" + + "=?", new Integer[]{transaction.getId()}); + matchedTransactionsCount++; + + if (matchedTransactionsCount == 100) { + db.execSQL("UPDATE transactions SET keep=1 WHERE " + + "id < ?", + new Integer[]{transaction.getId()}); + progress.setTotal(progress.getProgress()); + publishProgress(progress); + break LINES; + } + } + else { + db.execSQL("DELETE from transactions WHERE id=?", + new Integer[]{transaction.getId()}); + db.execSQL("DELETE from transaction_accounts WHERE " + + "transaction_id=?", + new Integer[]{transaction.getId()}); + transaction.insertInto(db); + matchedTransactionsCount = 0; + progress.setTotal(maxTransactionId); + } state = ParserState.EXPECTING_TRANSACTION; L(String.format( @@ -200,7 +225,10 @@ public class RetrieveTransactionsTask extends String.format("Unknown " + "parser state %d", state)); } } - if (!isCancelled()) db.setTransactionSuccessful(); + if (!isCancelled()) { + db.execSQL("DELETE FROM transactions WHERE keep = 0"); + db.setTransactionSuccessful(); + } } finally { db.endTransaction(); diff --git a/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java b/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java index c4127ab8..adb45fb9 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java @@ -19,6 +19,7 @@ package net.ktnx.mobileledger.model; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.util.Log; import net.ktnx.mobileledger.utils.Digest; @@ -131,6 +132,17 @@ public class LedgerTransaction { String.format("Unable to get instance of %s digest", DIGEST_TYPE), e); } } + public boolean existsInDb(SQLiteDatabase db) { + fillDataHash(); + try (Cursor c = db + .rawQuery("SELECT 1 from transactions where data_hash = ?", new String[]{dataHash})) + { + boolean result = c.moveToFirst(); + Log.d("transactions", String.format("Transaction %d (%s) %s", id, dataHash, + result ? "already present" : "not present")); + return result; + } + } public void loadData(SQLiteDatabase db) { if (dataLoaded) return; -- 2.39.2 From 6fc42b662846642af06163456f05ec4154d6b2ad Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Thu, 20 Dec 2018 17:51:10 +0000 Subject: [PATCH 11/16] add version suffix for the debug build --- app/build.gradle | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index e7f61276..01a301f7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,3 +1,20 @@ +/* + * Copyright © 2018 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 . + */ + apply plugin: 'com.android.application' android { @@ -15,6 +32,9 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + versionNameSuffix '-debug' + } } sourceSets { main { assets.srcDirs = ['src/main/assets', 'src/main/assets/'] } } buildToolsVersion '28.0.3' @@ -25,7 +45,7 @@ android { } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:support-v4:28.0.0' implementation 'com.android.support:design:28.0.0' -- 2.39.2 From 8cd58ae381b9c50d07cb20217f1e3823fae3906d Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Thu, 20 Dec 2018 17:51:51 +0000 Subject: [PATCH 12/16] drop unused stuff related to partial transaction list parsing --- .../async/RetrieveTransactionsTask.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index 451b164e..afdef7df 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -257,33 +257,14 @@ public class RetrieveTransactionsTask extends } public static class Params { - static final int DEFAULT_LIMIT = 100; private SharedPreferences backendPref; - private String accountsRoot; - private int limit; public Params(SharedPreferences backendPref) { this.backendPref = backendPref; - this.accountsRoot = null; - this.limit = DEFAULT_LIMIT; - } - Params(SharedPreferences backendPref, String accountsRoot) { - this(backendPref, accountsRoot, DEFAULT_LIMIT); - } - Params(SharedPreferences backendPref, String accountsRoot, int limit) { - this.backendPref = backendPref; - this.accountsRoot = accountsRoot; - this.limit = limit; - } - String getAccountsRoot() { - return accountsRoot; } SharedPreferences getBackendPref() { return backendPref; } - int getLimit() { - return limit; - } } public class Progress { -- 2.39.2 From 7a263c51479d328b120147f748ba617795e46f57 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Thu, 20 Dec 2018 17:52:10 +0000 Subject: [PATCH 13/16] whitespace --- .../net/ktnx/mobileledger/async/RetrieveTransactionsTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index afdef7df..a3b9b62f 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -222,7 +222,7 @@ public class RetrieveTransactionsTask extends break; default: throw new RuntimeException( - String.format("Unknown " + "parser state %d", state)); + String.format("Unknown parser state %d", state)); } } if (!isCancelled()) { -- 2.39.2 From b4b2b3c53bc6dc2611654eda59447325be482f66 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Thu, 20 Dec 2018 17:52:20 +0000 Subject: [PATCH 14/16] information about transaction id when having trouble parsing details --- .../net/ktnx/mobileledger/async/RetrieveTransactionsTask.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index a3b9b62f..f3b4bea6 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -217,7 +217,8 @@ public class RetrieveTransactionsTask extends L(String.format("%s = %s", acc_name, amount)); } else throw new IllegalStateException( - String.format("Can't parse transaction details")); + String.format("Can't parse transaction %d details", + transactionId)); } break; default: -- 2.39.2 From a3a4e4ed15e027a882cb473f1c18477ed0f210d7 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Thu, 20 Dec 2018 17:59:24 +0000 Subject: [PATCH 15/16] a constant for the transaction list stamp option --- app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java index 2773dc9f..96cc2020 100644 --- a/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java +++ b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java @@ -39,6 +39,7 @@ public final class MLDB { public static final String ACCOUNTS_TABLE = "accounts"; public static final String DESCRIPTION_HISTORY_TABLE = "description_history"; + public static final String OPT_TRANSACTION_LIST_STAMP = "transaction_list_last_update"; private static MobileLedgerDatabase helperForReading, helperForWriting; public static synchronized SQLiteDatabase getDatabase(Context context, DatabaseMode mode) { -- 2.39.2 From 83ab10f246f2475f03dd1240f681ba5aaa84bb46 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Thu, 20 Dec 2018 17:59:51 +0000 Subject: [PATCH 16/16] more straight-forward updating of the text representing the transaction list update stamp --- .../mobileledger/TransactionListActivity.java | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java b/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java index 39323f7b..5577d501 100644 --- a/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java @@ -68,21 +68,7 @@ public class TransactionListActivity extends AppCompatActivity { if (progressBar == null) throw new RuntimeException("Can't get hold on the transaction list progress bar"); tvLastUpdate = findViewById(R.id.transactions_last_update); - { - long last_update = MLDB.get_option_value(this, "transaction_list_last_update", 0L); - Log.d("transactions", String.format("Last update = %d", last_update)); - if (last_update == 0) tvLastUpdate.setText("never"); - else { - Date date = new Date(last_update); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - tvLastUpdate.setText(date.toInstant().atZone(ZoneId.systemDefault()) - .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); - } - else { - tvLastUpdate.setText(date.toLocaleString()); - } - } - } + updateLastUpdateText(); model = ViewModelProviders.of(this).get(TransactionListViewModel.class); List transactions = model.getTransactions(getApplicationContext()); modelAdapter = new TransactionListAdapter(transactions); @@ -154,20 +140,26 @@ public class TransactionListActivity extends AppCompatActivity { public void onRetrieveDone(boolean success) { progressBar.setVisibility(View.GONE); swiper.setRefreshing(false); + updateLastUpdateText(); if (success) { - Date now = new Date(); - MLDB.set_option_value(getApplicationContext(), "transaction_list_last_update", - now.getTime()); - updateLastUpdateText(now); modelAdapter.notifyDataSetChanged(); } } - private void updateLastUpdateText(Date now) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - tvLastUpdate.setText(now.toInstant().atZone(ZoneId.systemDefault()).toString()); - } - else { - tvLastUpdate.setText(now.toLocaleString()); + private void updateLastUpdateText() { + { + long last_update = MLDB.get_option_value(this, MLDB.OPT_TRANSACTION_LIST_STAMP, 0L); + Log.d("transactions", String.format("Last update = %d", last_update)); + if (last_update == 0) tvLastUpdate.setText("never"); + else { + Date date = new Date(last_update); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + tvLastUpdate.setText(date.toInstant().atZone(ZoneId.systemDefault()) + .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + } + else { + tvLastUpdate.setText(date.toLocaleString()); + } + } } } } -- 2.39.2