From 0bbdc409d82da31324c031f36607510f17d992e6 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Mon, 31 Dec 2018 05:31:57 +0000 Subject: [PATCH] major refactor, make account summary and transaction list fragments, part of the "Main" activity --- app/src/main/AndroidManifest.xml | 27 +- .../mobileledger/TransactionListActivity.java | 245 ------------------ .../async/RetrieveAccountsTask.java | 10 +- .../async/RetrieveTransactionsTask.java | 23 +- .../{ => ui}/OnSwipeTouchListener.java | 4 +- .../{ => ui}/RecyclerItemListener.java | 6 +- .../AccountSummaryFragment.java} | 245 ++++++------------ .../AccountSummaryViewModel.java | 10 +- .../AppCompatPreferenceActivity.java | 2 +- .../ui/activity/MainActivity.java | 196 ++++++++++++++ .../activity}/NewTransactionActivity.java | 4 +- .../{ => ui/activity}/SettingsActivity.java | 6 +- .../TransactionListAdapter.java | 6 +- .../TransactionListFragment.java | 207 ++++++++++++++- .../TransactionListViewModel.java | 10 +- .../net/ktnx/mobileledger/utils/Globals.java | 13 + .../res/layout/account_summary_fragment.xml | 52 ++++ .../res/layout/activity_new_transaction.xml | 2 +- .../res/layout/app_bar_account_summary.xml | 13 +- .../res/layout/content_account_summary.xml | 2 +- .../res/layout/content_new_transaction.xml | 2 +- app/src/main/res/layout/drawer.xml | 1 + .../res/layout/transaction_list_activity.xml | 2 +- .../res/layout/transaction_list_fragment.xml | 7 +- app/src/main/res/menu/account_summary.xml | 11 +- app/src/main/res/menu/transaction_list.xml | 6 +- app/src/main/res/xml/pref_headers.xml | 8 +- 27 files changed, 630 insertions(+), 490 deletions(-) delete mode 100644 app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java rename app/src/main/java/net/ktnx/mobileledger/{ => ui}/OnSwipeTouchListener.java (97%) rename app/src/main/java/net/ktnx/mobileledger/{ => ui}/RecyclerItemListener.java (94%) rename app/src/main/java/net/ktnx/mobileledger/{AccountSummary.java => ui/account_summary/AccountSummaryFragment.java} (57%) rename app/src/main/java/net/ktnx/mobileledger/{ => ui/account_summary}/AccountSummaryViewModel.java (96%) rename app/src/main/java/net/ktnx/mobileledger/{ => ui/activity}/AppCompatPreferenceActivity.java (98%) create mode 100644 app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java rename app/src/main/java/net/ktnx/mobileledger/{ => ui/activity}/NewTransactionActivity.java (99%) rename app/src/main/java/net/ktnx/mobileledger/{ => ui/activity}/SettingsActivity.java (99%) rename app/src/main/java/net/ktnx/mobileledger/{ => ui/transaction_list}/TransactionListAdapter.java (98%) create mode 100644 app/src/main/res/layout/account_summary_fragment.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1cd74d14..5ab5cdc6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -31,7 +31,7 @@ android:name="net.ktnx.mobileledger.MobileLedgerApplication" android:theme="@style/AppTheme"> @@ -40,34 +40,21 @@ + android:parentActivityName=".ui.activity.MainActivity"> + android:value="net.ktnx.mobileledger.ui.activity.MainActivity" /> - - - - - - - + android:value="net.ktnx.mobileledger.ui.activity.MainActivity" /> diff --git a/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java b/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java deleted file mode 100644 index ac992cdf..00000000 --- a/app/src/main/java/net/ktnx/mobileledger/TransactionListActivity.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * 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 . - */ - -package net.ktnx.mobileledger; - -import android.arch.lifecycle.ViewModelProviders; -import android.database.MatrixCursor; -import android.os.Build; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.inputmethod.InputMethodManager; -import android.widget.AdapterView; -import android.widget.AutoCompleteTextView; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; - -import net.ktnx.mobileledger.async.RetrieveTransactionsTask; -import net.ktnx.mobileledger.ui.transaction_list.TransactionListViewModel; -import net.ktnx.mobileledger.utils.MLDB; - -import java.lang.ref.WeakReference; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.Date; - -public class TransactionListActivity extends AppCompatActivity { - public TransactionListViewModel model; - private View bTransactionListCancelDownload; - private MenuItem menuTransactionListFilter; - private View vAccountFilter; - private SwipeRefreshLayout swiper; - private RecyclerView root; - private ProgressBar progressBar; - private LinearLayout progressLayout; - private TextView tvLastUpdate; - private TransactionListAdapter modelAdapter; - private RetrieveTransactionsTask retrieveTransactionsTask; - private AutoCompleteTextView accNameFilter; - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.transaction_list_activity); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - - setupActionBar(); - - 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); - if (root == null) throw new RuntimeException("Can't get hold on the transaction list view"); - progressBar = findViewById(R.id.transaction_list_progress_bar); - if (progressBar == null) - throw new RuntimeException("Can't get hold on the transaction list progress bar"); - progressLayout = findViewById(R.id.transaction_progress_layout); - if (progressLayout == null) throw new RuntimeException( - "Can't get hold on the transaction list progress bar layout"); - tvLastUpdate = findViewById(R.id.transactions_last_update); - updateLastUpdateText(); - model = ViewModelProviders.of(this).get(TransactionListViewModel.class); - modelAdapter = new TransactionListAdapter(model); - - RecyclerView root = findViewById(R.id.transaction_root); - root.setAdapter(modelAdapter); - - LinearLayoutManager llm = new LinearLayoutManager(this); - - llm.setOrientation(LinearLayoutManager.VERTICAL); - root.setLayoutManager(llm); - - swiper.setOnRefreshListener(() -> { - Log.d("ui", "refreshing transactions via swipe"); - update_transactions(); - }); - - swiper.setColorSchemeResources(R.color.colorPrimary, R.color.colorAccent); - - vAccountFilter = findViewById(R.id.transaction_list_account_name_filter); - accNameFilter = findViewById(R.id.transaction_filter_account_name); - bTransactionListCancelDownload = findViewById(R.id.transaction_list_cancel_download); - - MLDB.hook_autocompletion_adapter(this, accNameFilter, "accounts", "name"); - TransactionListActivity me = this; - accNameFilter.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Log.d("tmp", "direct onItemClick"); - model.reloadTransactions(me); - MatrixCursor mc = (MatrixCursor) parent.getItemAtPosition(position); - modelAdapter.setBoldAccountName(mc.getString(1)); - modelAdapter.notifyDataSetChanged(); - me.hideSoftKeyboard(); - } - }); - - 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) { - update_transactions(); - } - else { - model.reloadTransactions(this); - } - } - private void setupActionBar() { - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - // Show the Up button in the action bar. - actionBar.setDisplayHomeAsUpEnabled(true); - } - } - @Override - public void finish() { - super.finish(); - Log.d("visuals", "finishing"); - overridePendingTransition(R.anim.dummy, R.anim.slide_out_right); - } - private void update_transactions() { - retrieveTransactionsTask = new RetrieveTransactionsTask(new WeakReference<>(this)); - - RetrieveTransactionsTask.Params params = new RetrieveTransactionsTask.Params( - PreferenceManager.getDefaultSharedPreferences(this)); - - retrieveTransactionsTask.execute(params); - bTransactionListCancelDownload.setEnabled(true); - } - - public void onRetrieveStart() { - progressBar.setIndeterminate(true); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) progressBar.setProgress(0, false); - else progressBar.setProgress(0); - progressLayout.setVisibility(View.VISIBLE); - } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.transaction_list, menu); - menuTransactionListFilter = menu.findItem(R.id.menu_transaction_list_filter); - if ((menuTransactionListFilter == null)) throw new AssertionError(); - - return true; - } - public void onRetrieveProgress(RetrieveTransactionsTask.Progress progress) { - if ((progress.getTotal() == RetrieveTransactionsTask.Progress.INDETERMINATE) || - (progress.getTotal() == 0)) - { - progressBar.setIndeterminate(true); - } - else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - progressBar.setMin(0); - } - progressBar.setMax(progress.getTotal()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - progressBar.setProgress(progress.getProgress(), true); - } - else progressBar.setProgress(progress.getProgress()); - progressBar.setIndeterminate(false); - } - } - - public void onRetrieveDone(boolean success) { - progressLayout.setVisibility(View.GONE); - swiper.setRefreshing(false); - updateLastUpdateText(); - if (success) { - Log.d("transactions", "calling notifyDataSetChanged()"); - modelAdapter.notifyDataSetChanged(); - } - } - 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(getString(R.string.transaction_last_update_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()); - } - } - } - } - public void onClearAccountNameClick(View view) { - vAccountFilter.setVisibility(View.GONE); - menuTransactionListFilter.setVisible(true); - accNameFilter.setText(null); - model.reloadTransactions(this); - modelAdapter.resetBoldAccountName(); - modelAdapter.notifyDataSetChanged(); - hideSoftKeyboard(); - } - private void hideSoftKeyboard() { - // hide the keyboard - View v = getCurrentFocus(); - if (v != null) { - InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(v.getWindowToken(), 0); - } - } - public void onShowFilterClick(MenuItem menuItem) { - vAccountFilter.setVisibility(View.VISIBLE); - menuTransactionListFilter.setVisible(false); - accNameFilter.requestFocus(); - InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); - imm.showSoftInput(accNameFilter, 0); - } - public void onStopTransactionRefreshClick(View view) { - Log.d("interactive", "Cancelling transactions refresh"); - if (retrieveTransactionsTask != null) retrieveTransactionsTask.cancel(false); - bTransactionListCancelDownload.setEnabled(false); - } -} 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 a342ca4d..59362fad 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveAccountsTask.java @@ -21,7 +21,7 @@ import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.util.Log; -import net.ktnx.mobileledger.AccountSummary; +import net.ktnx.mobileledger.ui.account_summary.AccountSummaryFragment; import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.model.LedgerAccount; import net.ktnx.mobileledger.utils.MLDB; @@ -41,10 +41,10 @@ import java.util.regex.Pattern; public class RetrieveAccountsTask extends android.os.AsyncTask { int error; - WeakReference mContext; + WeakReference mContext; private SharedPreferences pref; - public RetrieveAccountsTask(WeakReference context) { + public RetrieveAccountsTask(WeakReference context) { mContext = context; error = 0; } @@ -57,7 +57,7 @@ public class RetrieveAccountsTask extends android.os.AsyncTask contextRef; + protected WeakReference contextRef; protected int error; private boolean success; - public RetrieveTransactionsTask(WeakReference contextRef) { + public RetrieveTransactionsTask(WeakReference contextRef) { this.contextRef = contextRef; } private static final void L(String msg) { @@ -64,28 +64,28 @@ public class RetrieveTransactionsTask extends @Override protected void onProgressUpdate(Progress... values) { super.onProgressUpdate(values); - TransactionListActivity context = getContext(); + TransactionListFragment context = getContext(); if (context == null) return; context.onRetrieveProgress(values[0]); } @Override protected void onPreExecute() { super.onPreExecute(); - TransactionListActivity context = getContext(); + TransactionListFragment context = getContext(); if (context == null) return; context.onRetrieveStart(); } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); - TransactionListActivity context = getContext(); + TransactionListFragment context = getContext(); if (context == null) return; context.onRetrieveDone(success); } @Override protected void onCancelled() { super.onCancelled(); - TransactionListActivity context = getContext(); + TransactionListFragment context = getContext(); if (context == null) return; context.onRetrieveDone(false); } @@ -100,9 +100,9 @@ public class RetrieveTransactionsTask extends NetworkUtil.prepare_connection(params[0].getBackendPref(), "journal"); http.setAllowUserInteraction(false); publishProgress(progress); - TransactionListActivity ctx = contextRef.get(); + TransactionListFragment ctx = getContext(); if (ctx == null) return null; - try (SQLiteDatabase db = MLDB.getWritableDatabase(ctx)) { + try (SQLiteDatabase db = MLDB.getWritableDatabase(ctx.getActivity())) { try (InputStream resp = http.getInputStream()) { if (http.getResponseCode() != 200) throw new IOException( String.format("HTTP error %d", http.getResponseCode())); @@ -251,7 +251,8 @@ public class RetrieveTransactionsTask extends if (success && !isCancelled()) { Log.d("db", "Updating transaction list stamp"); - MLDB.set_option_value(ctx, MLDB.OPT_TRANSACTION_LIST_STAMP, new Date().getTime()); + MLDB.set_option_value(ctx.getActivity(), MLDB.OPT_TRANSACTION_LIST_STAMP, + new Date().getTime()); ctx.model.reloadTransactions(ctx); } } @@ -269,7 +270,7 @@ public class RetrieveTransactionsTask extends } return null; } - TransactionListActivity getContext() { + TransactionListFragment getContext() { return contextRef.get(); } diff --git a/app/src/main/java/net/ktnx/mobileledger/OnSwipeTouchListener.java b/app/src/main/java/net/ktnx/mobileledger/ui/OnSwipeTouchListener.java similarity index 97% rename from app/src/main/java/net/ktnx/mobileledger/OnSwipeTouchListener.java rename to app/src/main/java/net/ktnx/mobileledger/ui/OnSwipeTouchListener.java index 3257b2c4..ecc00959 100644 --- a/app/src/main/java/net/ktnx/mobileledger/OnSwipeTouchListener.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/OnSwipeTouchListener.java @@ -15,7 +15,7 @@ * along with Mobile-Ledger. If not, see . */ -package net.ktnx.mobileledger; +package net.ktnx.mobileledger.ui; import android.content.Context; import android.util.Log; @@ -27,7 +27,7 @@ import android.view.View; public abstract class OnSwipeTouchListener implements View.OnTouchListener { public final GestureDetector gestureDetector; - OnSwipeTouchListener(Context ctx) { + protected OnSwipeTouchListener(Context ctx) { gestureDetector = new GestureDetector(ctx, new GestureListener() ); } diff --git a/app/src/main/java/net/ktnx/mobileledger/RecyclerItemListener.java b/app/src/main/java/net/ktnx/mobileledger/ui/RecyclerItemListener.java similarity index 94% rename from app/src/main/java/net/ktnx/mobileledger/RecyclerItemListener.java rename to app/src/main/java/net/ktnx/mobileledger/ui/RecyclerItemListener.java index b95f4f77..64427c2e 100644 --- a/app/src/main/java/net/ktnx/mobileledger/RecyclerItemListener.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/RecyclerItemListener.java @@ -15,7 +15,7 @@ * along with Mobile-Ledger. If not, see . */ -package net.ktnx.mobileledger; +package net.ktnx.mobileledger.ui; import android.content.Context; import android.support.annotation.NonNull; @@ -25,11 +25,11 @@ import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; -class RecyclerItemListener implements OnItemTouchListener { +public class RecyclerItemListener implements OnItemTouchListener { private RecyclerTouchListener listener; private GestureDetector gd; - interface RecyclerTouchListener { + public interface RecyclerTouchListener { void onClickItem(View v, int position); void onLongClickItem(View v, int position); } diff --git a/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryFragment.java similarity index 57% rename from app/src/main/java/net/ktnx/mobileledger/AccountSummary.java rename to app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryFragment.java index 3a59003d..b0b67327 100644 --- a/app/src/main/java/net/ktnx/mobileledger/AccountSummary.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryFragment.java @@ -15,93 +15,87 @@ * along with Mobile-Ledger. If not, see . */ -package net.ktnx.mobileledger; +package net.ktnx.mobileledger.ui.account_summary; import android.arch.lifecycle.ViewModelProviders; -import android.content.Intent; +import android.content.Context; import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; +import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.ActionBarDrawerToggle; -import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; import android.util.Log; +import android.view.LayoutInflater; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.LinearLayout; +import android.view.ViewGroup; +import net.ktnx.mobileledger.R; +import net.ktnx.mobileledger.ui.RecyclerItemListener; import net.ktnx.mobileledger.async.RetrieveAccountsTask; import net.ktnx.mobileledger.model.LedgerAccount; +import net.ktnx.mobileledger.ui.activity.MainActivity; import net.ktnx.mobileledger.utils.MLDB; import java.lang.ref.WeakReference; import java.util.Date; import java.util.List; -import static net.ktnx.mobileledger.SettingsActivity.PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS; +import static net.ktnx.mobileledger.ui.activity.SettingsActivity.PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS; + +public class AccountSummaryFragment extends Fragment { -public class AccountSummary extends AppCompatActivity { 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; private AccountSummaryAdapter modelAdapter; private Menu optMenu; - - public static void preferences_changed() { - account_list_needs_update = true; - } - + private MainActivity mActivity; + private FloatingActionButton fab; + private SwipeRefreshLayout swiper; @Override - protected void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_account_summary); - Toolbar toolbar = findViewById(R.id.toolbar); - 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); - drawer.addDrawerListener(toggle); - toggle.syncState(); - - android.widget.TextView ver = drawer.findViewById(R.id.drawer_version_text); + setHasOptionsMenu(true); + } + public void onAttach(Context context) { + super.onAttach(context); + mActivity = (MainActivity) context; + } + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.account_summary_fragment, container, false); + } - try { - PackageInfo pi = - getApplicationContext().getPackageManager().getPackageInfo(getPackageName(), 0); - ver.setText(pi.versionName); - } - catch (Exception e) { - e.printStackTrace(); - } + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); model = ViewModelProviders.of(this).get(AccountSummaryViewModel.class); - List accounts = model.getAccounts(getApplicationContext()); + List accounts = model.getAccounts(this.getContext()); modelAdapter = new AccountSummaryAdapter(accounts); - RecyclerView root = findViewById(R.id.account_root); + RecyclerView root = mActivity.findViewById(R.id.account_root); root.setAdapter(modelAdapter); - LinearLayoutManager llm = new LinearLayoutManager(this); + LinearLayoutManager llm = new LinearLayoutManager(mActivity); llm.setOrientation(LinearLayoutManager.VERTICAL); root.setLayoutManager(llm); - root.addOnItemTouchListener(new RecyclerItemListener(this, root, + fab = mActivity.findViewById(R.id.btn_add_transaction); + + root.addOnItemTouchListener(new RecyclerItemListener(mActivity, root, new RecyclerItemListener.RecyclerTouchListener() { @Override public void onClickItem(View v, int position) { @@ -123,7 +117,6 @@ public class AccountSummary extends AppCompatActivity { optMenu.findItem(R.id.menu_acc_summary_only_starred).setVisible(false); } { - FloatingActionButton fab = findViewById(R.id.btn_add_transaction); if (fab != null) fab.hide(); } } @@ -132,11 +125,13 @@ public class AccountSummary extends AppCompatActivity { root.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - if (dy < 0) ((FloatingActionButton) findViewById(R.id.btn_add_transaction)).show(); - if (dy > 0) ((FloatingActionButton) findViewById(R.id.btn_add_transaction)).hide(); + if (fab != null) { + if (dy < 0) fab.show(); + if (dy > 0) fab.hide(); + } } }); - SwipeRefreshLayout swiper = findViewById(R.id.account_swiper); + swiper = mActivity.findViewById(R.id.account_swiper); swiper.setColorSchemeResources(R.color.colorPrimary, R.color.colorAccent); swiper.setOnRefreshListener(() -> { Log.d("ui", "refreshing accounts via swipe"); @@ -145,114 +140,10 @@ public class AccountSummary extends AppCompatActivity { prepare_db(); // update_account_table(); update_accounts(false); - } - - @Override - protected void onStart() { - super.onStart(); - LinearLayout grp = drawer.findViewById(R.id.nav_actions); - for (int i = 0; i < grp.getChildCount(); i++) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - grp.getChildAt(i).setBackgroundColor( - getResources().getColor(R.color.drawer_background, getTheme())); - } - else { - grp.getChildAt(i) - .setBackgroundColor(getResources().getColor(R.color.drawer_background)); - } - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - drawer.findViewById(R.id.nav_account_summary).setBackgroundColor( - getResources().getColor(R.color.table_row_even_bg, getTheme())); - } - else { - drawer.findViewById(R.id.nav_account_summary) - .setBackgroundColor(getResources().getColor(R.color.table_row_even_bg)); - } - } - - public void fab_new_transaction_clicked(View view) { - Intent intent = new Intent(this, NewTransactionActivity.class); - startActivity(intent); - overridePendingTransition(R.anim.slide_in_right, R.anim.dummy); - } - - public void nav_exit_clicked(View view) { - Log.w("app", "exiting"); - finish(); - } - - public void nav_settings_clicked(View view) { - Intent intent = new Intent(this, SettingsActivity.class); - startActivity(intent); - } - public void onLatestTransactionsClicked(View view) { - Intent intent = new Intent(this, TransactionListActivity.class); - startActivity(intent); - } - @Override - public void onBackPressed() { - DrawerLayout drawer = findViewById(R.id.drawer_layout); - if (drawer.isDrawerOpen(GravityCompat.START)) { - drawer.closeDrawer(GravityCompat.START); - } - else { - super.onBackPressed(); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.account_summary, menu); - optMenu = menu; - - mShowHiddenAccounts = menu.findItem(R.id.menu_acc_summary_only_starred); - if (mShowHiddenAccounts == null) throw new AssertionError(); - - sBindPreferenceSummaryToValueListener = (preference, value) -> mShowHiddenAccounts - .setChecked(preference.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false)); - SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); - pref.registerOnSharedPreferenceChangeListener(sBindPreferenceSummaryToValueListener); - - mShowHiddenAccounts.setChecked(pref.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false)); - - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. -// int id = item.getItemId(); - - //noinspection SimplifiableIfStatement - //if (id == R.id.action_settings) { - // return true; - // } - return super.onOptionsItemSelected(item); } - - public void onRefreshAccountSummaryClicked(MenuItem mi) { - update_accounts(true); - } - - public void onShowOnlyStarredClicked(MenuItem mi) { - SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); - boolean flag = pref.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false); - - SharedPreferences.Editor editor = pref.edit(); - editor.putBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, !flag); - Log.d("pref", "Setting show only starred accounts pref to " + (flag ? "false" : "true")); - editor.apply(); - - update_account_table(); - } - private void prepare_db() { - account_list_last_updated = MLDB.get_option_value(this, "last_refresh", (long) 0); + account_list_last_updated = MLDB.get_option_value(mActivity, "last_refresh", (long) 0); } private void update_accounts(boolean force) { @@ -268,27 +159,44 @@ public class AccountSummary extends AppCompatActivity { private void update_accounts() { RetrieveAccountsTask task = new RetrieveAccountsTask(new WeakReference<>(this)); - task.setPref(PreferenceManager.getDefaultSharedPreferences(this)); + task.setPref(PreferenceManager.getDefaultSharedPreferences(mActivity)); task.execute(); } public void onAccountRefreshDone(int error) { - SwipeRefreshLayout srl = findViewById(R.id.account_swiper); - srl.setRefreshing(false); + swiper.setRefreshing(false); 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(swiper, err_text, Snackbar.LENGTH_LONG).show(); } else { - MLDB.set_option_value(this, "last_refresh", new Date().getTime()); + MLDB.set_option_value(mActivity, "last_refresh", new Date().getTime()); update_account_table(); } } private void update_account_table() { - model.reloadAccounts(getApplicationContext()); + if (this.getContext() == null) return; + + model.reloadAccounts(this.getContext()); modelAdapter.notifyDataSetChanged(); } + public void onRefreshAccountSummaryClicked(MenuItem mi) { + update_accounts(true); + } + + public void onShowOnlyStarredClicked(MenuItem mi) { + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(mActivity); + boolean flag = pref.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false); + + SharedPreferences.Editor editor = pref.edit(); + editor.putBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, !flag); + Log.d("pref", "Setting show only starred accounts pref to " + (flag ? "false" : "true")); + editor.apply(); + + update_account_table(); + } + void stopSelection() { modelAdapter.stopSelection(); if (optMenu != null) { @@ -297,7 +205,6 @@ public class AccountSummary extends AppCompatActivity { optMenu.findItem(R.id.menu_acc_summary_only_starred).setVisible(true); } { - FloatingActionButton fab = findViewById(R.id.btn_add_transaction); if (fab != null) fab.show(); } } @@ -305,7 +212,25 @@ public class AccountSummary extends AppCompatActivity { stopSelection(); } public void onConfirmAccSelection(MenuItem item) { - model.commitSelections(getApplicationContext()); + model.commitSelections(mActivity); stopSelection(); } + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + // Inflate the menu; this adds items to the action bar if it is present. + inflater.inflate(R.menu.account_summary, menu); + optMenu = menu; + + mShowHiddenAccounts = menu.findItem(R.id.menu_acc_summary_only_starred); + if (mShowHiddenAccounts == null) throw new AssertionError(); + + sBindPreferenceSummaryToValueListener = (preference, value) -> mShowHiddenAccounts + .setChecked(preference.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false)); + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(mActivity); + pref.registerOnSharedPreferenceChangeListener(sBindPreferenceSummaryToValueListener); + + mShowHiddenAccounts.setChecked(pref.getBoolean(PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS, false)); + + Log.d("menu", "MainActivity: onCreateOptionsMenu called"); + } } diff --git a/app/src/main/java/net/ktnx/mobileledger/AccountSummaryViewModel.java b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryViewModel.java similarity index 96% rename from app/src/main/java/net/ktnx/mobileledger/AccountSummaryViewModel.java rename to app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryViewModel.java index f9b5d74f..942a5685 100644 --- a/app/src/main/java/net/ktnx/mobileledger/AccountSummaryViewModel.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryViewModel.java @@ -15,7 +15,7 @@ * along with Mobile-Ledger. If not, see . */ -package net.ktnx.mobileledger; +package net.ktnx.mobileledger.ui.account_summary; import android.app.Application; import android.arch.lifecycle.AndroidViewModel; @@ -36,13 +36,14 @@ import android.widget.CheckBox; import android.widget.LinearLayout; import android.widget.TextView; +import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.model.LedgerAccount; import net.ktnx.mobileledger.utils.MLDB; import java.util.ArrayList; import java.util.List; -import static net.ktnx.mobileledger.SettingsActivity.PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS; +import static net.ktnx.mobileledger.ui.activity.SettingsActivity.PREF_KEY_SHOW_ONLY_STARRED_ACCOUNTS; class AccountSummaryViewModel extends AndroidViewModel { private List accounts; @@ -107,7 +108,8 @@ class AccountSummaryViewModel extends AndroidViewModel { } } -class AccountSummaryAdapter extends RecyclerView.Adapter { +class AccountSummaryAdapter extends RecyclerView.Adapter { private List accounts; private boolean selectionActive; @@ -123,7 +125,7 @@ class AccountSummaryAdapter extends RecyclerView.Adapter. */ -package net.ktnx.mobileledger; +package net.ktnx.mobileledger.ui.activity; import android.content.res.Configuration; import android.os.Bundle; diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java new file mode 100644 index 00000000..e66cf045 --- /dev/null +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java @@ -0,0 +1,196 @@ +/* + * 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 . + */ + +package net.ktnx.mobileledger.ui.activity; + +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.ContextMenu; +import android.view.MenuItem; +import android.view.View; +import android.widget.LinearLayout; + +import net.ktnx.mobileledger.ui.account_summary.AccountSummaryFragment; +import net.ktnx.mobileledger.R; +import net.ktnx.mobileledger.ui.transaction_list.TransactionListFragment; + +public class MainActivity extends AppCompatActivity { + DrawerLayout drawer; + private AccountSummaryFragment accountSummaryFragment; + private TransactionListFragment transactionListFragment; + private Fragment currentFragment = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_account_summary); + Toolbar toolbar = findViewById(R.id.toolbar); + 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); + drawer.addDrawerListener(toggle); + toggle.syncState(); + + android.widget.TextView ver = drawer.findViewById(R.id.drawer_version_text); + + try { + PackageInfo pi = + getApplicationContext().getPackageManager().getPackageInfo(getPackageName(), 0); + ver.setText(pi.versionName); + } + catch (Exception e) { + e.printStackTrace(); + } + + onAccountSummaryClicked(null); + } + + @Override + protected void onStart() { + super.onStart(); + LinearLayout grp = drawer.findViewById(R.id.nav_actions); + for (int i = 0; i < grp.getChildCount(); i++) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + grp.getChildAt(i).setBackgroundColor( + getResources().getColor(R.color.drawer_background, getTheme())); + } + else { + grp.getChildAt(i) + .setBackgroundColor(getResources().getColor(R.color.drawer_background)); + } + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + drawer.findViewById(R.id.nav_account_summary).setBackgroundColor( + getResources().getColor(R.color.table_row_even_bg, getTheme())); + } + else { + drawer.findViewById(R.id.nav_account_summary) + .setBackgroundColor(getResources().getColor(R.color.table_row_even_bg)); + } + } + + public void fab_new_transaction_clicked(View view) { + Intent intent = new Intent(this, NewTransactionActivity.class); + startActivity(intent); + overridePendingTransition(R.anim.slide_in_right, R.anim.dummy); + } + + public void nav_exit_clicked(View view) { + Log.w("app", "exiting"); + finish(); + } + + public void nav_settings_clicked(View view) { + Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + } + private void markDrawerItemCurrent(int id) { + View item = drawer.findViewById(id); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + item.setBackgroundColor(getResources().getColor(R.color.table_row_even_bg, getTheme())); + } + else { + item.setBackgroundColor(getResources().getColor(R.color.table_row_even_bg)); + } + + LinearLayout actions = drawer.findViewById(R.id.nav_actions); + for (int i = 0; i < actions.getChildCount(); i++) { + View view = actions.getChildAt(i); + if (view.getId() != id) { + view.setBackgroundColor(getResources().getColor(android.R.color.transparent)); + } + } + } + public void onOptionsMenuClicked(MenuItem menuItem) { + ContextMenu.ContextMenuInfo info = menuItem.getMenuInfo(); + switch (menuItem.getItemId()) { + case R.id.menu_acc_summary_cancel_selection: + if (accountSummaryFragment != null) + accountSummaryFragment.onCancelAccSelection(menuItem); + break; + case R.id.menu_acc_summary_confirm_selection: + if (accountSummaryFragment != null) + accountSummaryFragment.onConfirmAccSelection(menuItem); + break; + case R.id.menu_acc_summary_only_starred: + if (accountSummaryFragment != null) + accountSummaryFragment.onShowOnlyStarredClicked(menuItem); + break; + case R.id.menu_transaction_list_filter: + if (transactionListFragment != null) + transactionListFragment.onShowFilterClick(menuItem); + break; + default: + Log.e("menu", String.format("Menu item %d not handled", menuItem.getItemId())); + } + } + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.clearAccountNameFilter: + if (transactionListFragment != null) + transactionListFragment.onClearAccountNameClick(view); + break; + default: + Log.e("click", String.format("View %d click not handled", view.getId())); + } + } + public void onAccountSummaryClicked(View view) { + markDrawerItemCurrent(R.id.nav_account_summary); + drawer.closeDrawers(); + + FragmentManager fm = getSupportFragmentManager(); + FragmentTransaction ft = fm.beginTransaction(); + currentFragment = accountSummaryFragment = new AccountSummaryFragment(); + ft.replace(R.id.root_frame, accountSummaryFragment); + ft.commit(); + } + public void onLatestTransactionsClicked(View view) { + markDrawerItemCurrent(R.id.nav_latest_transactions); + drawer.closeDrawers(); + + FragmentManager fm = getSupportFragmentManager(); + FragmentTransaction ft = fm.beginTransaction(); + currentFragment = transactionListFragment = new TransactionListFragment(); + ft.replace(R.id.root_frame, transactionListFragment); + ft.commit(); + } + @Override + public void onBackPressed() { + DrawerLayout drawer = findViewById(R.id.drawer_layout); + if (drawer.isDrawerOpen(GravityCompat.START)) { + drawer.closeDrawer(GravityCompat.START); + } + else { + super.onBackPressed(); + } + } + +} diff --git a/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionActivity.java similarity index 99% rename from app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java rename to app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionActivity.java index e7d6ca4b..43c10b27 100644 --- a/app/src/main/java/net/ktnx/mobileledger/NewTransactionActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionActivity.java @@ -15,7 +15,7 @@ * along with Mobile-Ledger. If not, see . */ -package net.ktnx.mobileledger; +package net.ktnx.mobileledger.ui.activity; import android.annotation.SuppressLint; import android.os.Bundle; @@ -43,6 +43,8 @@ import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; +import net.ktnx.mobileledger.ui.OnSwipeTouchListener; +import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.async.SaveTransactionTask; import net.ktnx.mobileledger.async.TaskCallback; import net.ktnx.mobileledger.model.LedgerTransaction; diff --git a/app/src/main/java/net/ktnx/mobileledger/SettingsActivity.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/SettingsActivity.java similarity index 99% rename from app/src/main/java/net/ktnx/mobileledger/SettingsActivity.java rename to app/src/main/java/net/ktnx/mobileledger/ui/activity/SettingsActivity.java index 07e0c61b..8f6ff2fb 100644 --- a/app/src/main/java/net/ktnx/mobileledger/SettingsActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/SettingsActivity.java @@ -15,7 +15,7 @@ * along with Mobile-Ledger. If not, see . */ -package net.ktnx.mobileledger; +package net.ktnx.mobileledger.ui.activity; import android.annotation.TargetApi; import android.content.Context; @@ -37,6 +37,8 @@ import android.support.v7.app.ActionBar; import android.text.TextUtils; import android.view.MenuItem; +import net.ktnx.mobileledger.R; + import java.util.List; /** @@ -60,8 +62,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity { private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = (preference, value) -> { String stringValue = value.toString(); - AccountSummary.preferences_changed(); - if (preference instanceof ListPreference) { // For list preferences, look up the correct display value in // the preference's 'entries' list. diff --git a/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListAdapter.java similarity index 98% rename from app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java rename to app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListAdapter.java index 41c3cdd5..7983aa5b 100644 --- a/app/src/main/java/net/ktnx/mobileledger/TransactionListAdapter.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListAdapter.java @@ -15,7 +15,7 @@ * along with Mobile-Ledger. If not, see . */ -package net.ktnx.mobileledger; +package net.ktnx.mobileledger.ui.transaction_list; import android.content.Context; import android.database.sqlite.SQLiteDatabase; @@ -32,15 +32,15 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; +import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.model.LedgerTransactionAccount; -import net.ktnx.mobileledger.ui.transaction_list.TransactionListViewModel; import net.ktnx.mobileledger.utils.Globals; import net.ktnx.mobileledger.utils.MLDB; import static net.ktnx.mobileledger.utils.DimensionUtils.dp2px; -class TransactionListAdapter +public class TransactionListAdapter extends RecyclerView.Adapter { TransactionListViewModel model; private String boldAccountName; diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListFragment.java b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListFragment.java index 97d2fe80..72e07b27 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListFragment.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListFragment.java @@ -18,22 +18,67 @@ package net.ktnx.mobileledger.ui.transaction_list; import android.arch.lifecycle.ViewModelProviders; +import android.content.Context; +import android.database.MatrixCursor; +import android.os.Build; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView; +import android.widget.AutoCompleteTextView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; +import net.ktnx.mobileledger.ui.activity.MainActivity; import net.ktnx.mobileledger.R; +import net.ktnx.mobileledger.async.RetrieveTransactionsTask; +import net.ktnx.mobileledger.utils.Globals; +import net.ktnx.mobileledger.utils.MLDB; -public class TransactionListFragment extends Fragment { +import java.lang.ref.WeakReference; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +import static android.content.Context.INPUT_METHOD_SERVICE; - private TransactionListViewModel mViewModel; - public static TransactionListFragment newInstance() { - return new TransactionListFragment(); +public class TransactionListFragment extends Fragment { + public TransactionListViewModel model; + private MainActivity mActivity; + private View bTransactionListCancelDownload; + private MenuItem menuTransactionListFilter; + private View vAccountFilter; + private SwipeRefreshLayout swiper; + private RecyclerView root; + private ProgressBar progressBar; + private LinearLayout progressLayout; + private TextView tvLastUpdate; + private TransactionListAdapter modelAdapter; + private RetrieveTransactionsTask retrieveTransactionsTask; + private AutoCompleteTextView accNameFilter; + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + @Override + public void onAttach(Context context) { + super.onAttach(context); + mActivity = (MainActivity) context; } @Nullable @Override @@ -46,8 +91,158 @@ public class TransactionListFragment extends Fragment { public void onActivityCreated(@Nullable Bundle savedInstanceState) { Log.d("flow", "TransactionListFragment.onActivityCreated called"); super.onActivityCreated(savedInstanceState); - mViewModel = ViewModelProviders.of(this).get(TransactionListViewModel.class); - // TODO: Use the ViewModel + + swiper = mActivity.findViewById(R.id.transaction_swipe); + if (swiper == null) throw new RuntimeException("Can't get hold on the swipe layout"); + root = mActivity.findViewById(R.id.transaction_root); + if (root == null) throw new RuntimeException("Can't get hold on the transaction list view"); + progressBar = mActivity.findViewById(R.id.transaction_list_progress_bar); + if (progressBar == null) + throw new RuntimeException("Can't get hold on the transaction list progress bar"); + progressLayout = mActivity.findViewById(R.id.transaction_progress_layout); + if (progressLayout == null) throw new RuntimeException( + "Can't get hold on the transaction list progress bar layout"); + tvLastUpdate = mActivity.findViewById(R.id.transactions_last_update); + updateLastUpdateText(); + model = ViewModelProviders.of(this).get(TransactionListViewModel.class); + modelAdapter = new TransactionListAdapter(model); + + RecyclerView root = mActivity.findViewById(R.id.transaction_root); + root.setAdapter(modelAdapter); + + LinearLayoutManager llm = new LinearLayoutManager(mActivity); + + llm.setOrientation(LinearLayoutManager.VERTICAL); + root.setLayoutManager(llm); + + swiper.setOnRefreshListener(() -> { + Log.d("ui", "refreshing transactions via swipe"); + update_transactions(); + }); + + swiper.setColorSchemeResources(R.color.colorPrimary, R.color.colorAccent); + + vAccountFilter = mActivity.findViewById(R.id.transaction_list_account_name_filter); + accNameFilter = mActivity.findViewById(R.id.transaction_filter_account_name); + bTransactionListCancelDownload = + mActivity.findViewById(R.id.transaction_list_cancel_download); + + TransactionListFragment me = this; + MLDB.hook_autocompletion_adapter(mActivity, accNameFilter, "accounts", "name"); + accNameFilter.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Log.d("tmp", "direct onItemClick"); + model.reloadTransactions(me); + MatrixCursor mc = (MatrixCursor) parent.getItemAtPosition(position); + modelAdapter.setBoldAccountName(mc.getString(1)); + modelAdapter.notifyDataSetChanged(); + Globals.hideSoftKeyboard(mActivity); + } + }); + + updateLastUpdateText(); + long last_update = MLDB.get_option_value(mActivity, MLDB.OPT_TRANSACTION_LIST_STAMP, 0L); + Log.d("transactions", String.format("Last update = %d", last_update)); + if (last_update == 0) { + update_transactions(); + } + else { + model.reloadTransactions(this); + } + } + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.transaction_list, menu); + + menuTransactionListFilter = menu.findItem(R.id.menu_transaction_list_filter); + if ((menuTransactionListFilter == null)) throw new AssertionError(); + + super.onCreateOptionsMenu(menu, inflater); + } + private void update_transactions() { + retrieveTransactionsTask = new RetrieveTransactionsTask(new WeakReference<>(this)); + + RetrieveTransactionsTask.Params params = new RetrieveTransactionsTask.Params( + PreferenceManager.getDefaultSharedPreferences(mActivity)); + + retrieveTransactionsTask.execute(params); + bTransactionListCancelDownload.setEnabled(true); + } + public void onRetrieveStart() { + progressBar.setIndeterminate(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) progressBar.setProgress(0, false); + else progressBar.setProgress(0); + progressLayout.setVisibility(View.VISIBLE); + } + public void onRetrieveProgress(RetrieveTransactionsTask.Progress progress) { + if ((progress.getTotal() == RetrieveTransactionsTask.Progress.INDETERMINATE) || + (progress.getTotal() == 0)) + { + progressBar.setIndeterminate(true); + } + else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + progressBar.setMin(0); + } + progressBar.setMax(progress.getTotal()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + progressBar.setProgress(progress.getProgress(), true); + } + else progressBar.setProgress(progress.getProgress()); + progressBar.setIndeterminate(false); + } } + public void onRetrieveDone(boolean success) { + progressLayout.setVisibility(View.GONE); + swiper.setRefreshing(false); + updateLastUpdateText(); + if (success) { + Log.d("transactions", "calling notifyDataSetChanged()"); + modelAdapter.notifyDataSetChanged(); + } + } + private void updateLastUpdateText() { + { + long last_update = + MLDB.get_option_value(mActivity, MLDB.OPT_TRANSACTION_LIST_STAMP, 0L); + Log.d("transactions", String.format("Last update = %d", last_update)); + if (last_update == 0) { + tvLastUpdate.setText(getString(R.string.transaction_last_update_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()); + } + } + } + } + public void onClearAccountNameClick(View view) { + vAccountFilter.setVisibility(View.GONE); + menuTransactionListFilter.setVisible(true); + accNameFilter.setText(null); + model.reloadTransactions(this); + modelAdapter.resetBoldAccountName(); + modelAdapter.notifyDataSetChanged(); + Globals.hideSoftKeyboard(mActivity); + } + public void onShowFilterClick(MenuItem menuItem) { + vAccountFilter.setVisibility(View.VISIBLE); + menuTransactionListFilter.setVisible(false); + accNameFilter.requestFocus(); + InputMethodManager imm = + (InputMethodManager) mActivity.getSystemService(INPUT_METHOD_SERVICE); + imm.showSoftInput(accNameFilter, 0); + } + public void onStopTransactionRefreshClick(View view) { + Log.d("interactive", "Cancelling transactions refresh"); + if (retrieveTransactionsTask != null) retrieveTransactionsTask.cancel(false); + bTransactionListCancelDownload.setEnabled(false); + } } 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 1680236b..ec339fcf 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 @@ -17,8 +17,8 @@ package net.ktnx.mobileledger.ui.transaction_list; +import android.app.Activity; import android.arch.lifecycle.ViewModel; -import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; @@ -26,7 +26,6 @@ import android.view.View; import android.widget.AutoCompleteTextView; import net.ktnx.mobileledger.R; -import net.ktnx.mobileledger.TransactionListActivity; import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.utils.MLDB; @@ -36,10 +35,11 @@ public class TransactionListViewModel extends ViewModel { private ArrayList transactions; - public void reloadTransactions(Context context) { + public void reloadTransactions(TransactionListFragment context) { ArrayList newList = new ArrayList<>(); - TransactionListActivity act = (TransactionListActivity) context; + Activity act = context.getActivity(); + boolean hasFilter = act.findViewById(R.id.transaction_list_account_name_filter).getVisibility() == View.VISIBLE; @@ -64,7 +64,7 @@ public class TransactionListViewModel extends ViewModel { } Log.d("tmp", sql); - try (SQLiteDatabase db = MLDB.getReadableDatabase(context)) { + try (SQLiteDatabase db = MLDB.getReadableDatabase(act)) { try (Cursor cursor = db.rawQuery(sql, params)) { while (cursor.moveToNext()) { newList.add(new LedgerTransaction(cursor.getInt(0))); diff --git a/app/src/main/java/net/ktnx/mobileledger/utils/Globals.java b/app/src/main/java/net/ktnx/mobileledger/utils/Globals.java index b7fffadf..e32a4321 100644 --- a/app/src/main/java/net/ktnx/mobileledger/utils/Globals.java +++ b/app/src/main/java/net/ktnx/mobileledger/utils/Globals.java @@ -17,7 +17,11 @@ package net.ktnx.mobileledger.utils; +import android.app.Activity; +import android.content.Context; import android.support.annotation.ColorInt; +import android.view.View; +import android.view.inputmethod.InputMethodManager; public final class Globals { @ColorInt @@ -26,5 +30,14 @@ public final class Globals { public static int table_row_odd_bg; @ColorInt public static int primaryDark, defaultTextColor; + public static void hideSoftKeyboard(Activity act) { + // hide the keyboard + View v = act.getCurrentFocus(); + if (v != null) { + InputMethodManager imm = + (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(v.getWindowToken(), 0); + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/account_summary_fragment.xml b/app/src/main/res/layout/account_summary_fragment.xml new file mode 100644 index 00000000..72d800c7 --- /dev/null +++ b/app/src/main/res/layout/account_summary_fragment.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_new_transaction.xml b/app/src/main/res/layout/activity_new_transaction.xml index c03c5988..b36b0a03 100644 --- a/app/src/main/res/layout/activity_new_transaction.xml +++ b/app/src/main/res/layout/activity_new_transaction.xml @@ -21,7 +21,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".NewTransactionActivity"> + tools:context=".ui.activity.NewTransactionActivity"> - + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:context="net.ktnx.mobileledger.ui.activity.MainActivity"> \ No newline at end of file diff --git a/app/src/main/res/menu/transaction_list.xml b/app/src/main/res/menu/transaction_list.xml index 00433377..80232e4a 100644 --- a/app/src/main/res/menu/transaction_list.xml +++ b/app/src/main/res/menu/transaction_list.xml @@ -17,12 +17,14 @@ --> + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools"> \ No newline at end of file diff --git a/app/src/main/res/xml/pref_headers.xml b/app/src/main/res/xml/pref_headers.xml index 8054ff3b..de84c0a6 100644 --- a/app/src/main/res/xml/pref_headers.xml +++ b/app/src/main/res/xml/pref_headers.xml @@ -20,21 +20,21 @@
-- 2.39.2