]> git.ktnx.net Git - mobile-ledger.git/blob - app/src/main/java/net/ktnx/mobileledger/AccountSummary.java
migrate to a proper db helper class, sub-classed from SQLiteOpenHelper
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / AccountSummary.java
1 package net.ktnx.mobileledger;
2
3 import android.annotation.SuppressLint;
4 import android.content.Intent;
5 import android.content.SharedPreferences;
6 import android.content.pm.PackageInfo;
7 import android.content.res.Resources;
8 import android.database.Cursor;
9 import android.database.sqlite.SQLiteDatabase;
10 import android.graphics.Typeface;
11 import android.os.Build;
12 import android.os.Bundle;
13 import android.preference.PreferenceManager;
14 import android.support.design.widget.Snackbar;
15 import android.support.v4.view.GravityCompat;
16 import android.support.v4.widget.DrawerLayout;
17 import android.support.v7.app.ActionBarDrawerToggle;
18 import android.support.v7.app.AppCompatActivity;
19 import android.support.v7.widget.Toolbar;
20 import android.util.Log;
21 import android.util.TypedValue;
22 import android.view.ContextMenu;
23 import android.view.Gravity;
24 import android.view.Menu;
25 import android.view.MenuItem;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.widget.EditText;
29 import android.widget.LinearLayout;
30 import android.widget.ProgressBar;
31 import android.widget.TextView;
32
33 import java.util.Date;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36
37 import static android.view.View.GONE;
38
39 public class AccountSummary extends AppCompatActivity {
40     DrawerLayout drawer;
41
42     private static long account_list_last_updated;
43     private static boolean account_list_needs_update = true;
44     MenuItem mShowHiddenAccounts;
45     SharedPreferences.OnSharedPreferenceChangeListener sBindPreferenceSummaryToValueListener;
46     private AccountRowLayout clickedAccountRow;
47     private MobileLedgerDatabase dbh;
48
49     public static void preferences_changed() {
50         account_list_needs_update = true;
51     }
52     MenuItem mRefresh;
53
54     @Override
55     protected void onCreate(Bundle savedInstanceState) {
56         super.onCreate(savedInstanceState);
57         setContentView(R.layout.activity_account_summary);
58         Toolbar toolbar = findViewById(R.id.toolbar);
59         setSupportActionBar(toolbar);
60
61         dbh = new MobileLedgerDatabase(this);
62
63         drawer = findViewById(R.id.drawer_layout);
64         ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
65                 this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
66         drawer.addDrawerListener(toggle);
67         toggle.syncState();
68
69         android.widget.TextView ver = drawer.findViewById(R.id.drawer_version_text);
70
71         try {
72             PackageInfo pi = getApplicationContext().getPackageManager().getPackageInfo(getPackageName(), 0);
73             ver.setText(pi.versionName);
74         } catch (Exception e) {
75             e.printStackTrace();
76         }
77
78         prepare_db();
79         update_account_table();
80         update_accounts(false);
81     }
82
83     @Override
84     protected void onStart() {
85         super.onStart();
86         LinearLayout grp = drawer.findViewById(R.id.nav_actions);
87         for (int i = 0; i < grp.getChildCount(); i++) {
88             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
89                 grp.getChildAt(i).setBackgroundColor(
90                         getResources().getColor(R.color.drawer_background, getTheme()));
91             }
92             else {
93                 grp.getChildAt(i)
94                         .setBackgroundColor(getResources().getColor(R.color.drawer_background));
95             }
96         }
97         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
98             drawer.findViewById(R.id.nav_account_summary).setBackgroundColor(
99                     getResources().getColor(R.color.table_row_even_bg, getTheme()));
100         }
101         else {
102             drawer.findViewById(R.id.nav_account_summary)
103                     .setBackgroundColor(getResources().getColor(R.color.table_row_even_bg));
104         }
105     }
106
107     public void fab_new_transaction_clicked(View view) {
108         Intent intent = new Intent(this, NewTransactionActivity.class);
109         startActivity(intent);
110         overridePendingTransition(R.anim.slide_in_right, R.anim.dummy);
111     }
112
113     public void nav_exit_clicked(View view) {
114         Log.w("mobileledger", "exiting");
115         finish();
116     }
117
118     public void nav_settings_clicked(View view) {
119         Intent intent = new Intent(this, SettingsActivity.class);
120         startActivity(intent);
121     }
122
123     @Override
124     public void onBackPressed() {
125         DrawerLayout drawer = findViewById(R.id.drawer_layout);
126         if (drawer.isDrawerOpen(GravityCompat.START)) {
127             drawer.closeDrawer(GravityCompat.START);
128         } else {
129             super.onBackPressed();
130         }
131     }
132
133     @Override
134     public boolean onCreateOptionsMenu(Menu menu) {
135         // Inflate the menu; this adds items to the action bar if it is present.
136         getMenuInflater().inflate(R.menu.account_summary, menu);
137         mRefresh = menu.findItem(R.id.menu_acc_summary_refresh);
138         if (mRefresh == null) throw new AssertionError();
139
140         mShowHiddenAccounts = menu.findItem(R.id.menu_acc_summary_show_hidden);
141         if (mShowHiddenAccounts == null) throw new AssertionError();
142
143         sBindPreferenceSummaryToValueListener =
144                 new SharedPreferences.OnSharedPreferenceChangeListener() {
145                     @Override
146                     public
147                     void onSharedPreferenceChanged(SharedPreferences preference, String value) {
148                         mShowHiddenAccounts
149                                 .setChecked(preference.getBoolean("show_hidden_accounts", false));
150                     }
151                 };
152         SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
153         pref.registerOnSharedPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
154
155         mShowHiddenAccounts.setChecked(pref.getBoolean("show_hidden_accounts", false));
156
157         return true;
158     }
159
160     @Override
161     public boolean onOptionsItemSelected(MenuItem item) {
162         // Handle action bar item clicks here. The action bar will
163         // automatically handle clicks on the Home/Up button, so long
164         // as you specify a parent activity in AndroidManifest.xml.
165 //        int id = item.getItemId();
166
167         //noinspection SimplifiableIfStatement
168         //if (id == R.id.action_settings) {
169         //    return true;
170         // }
171
172         return super.onOptionsItemSelected(item);
173     }
174
175     public void onRefreshAccountSummaryClicked(MenuItem mi) {
176         update_accounts(true);
177     }
178
179     public
180     void onShowHiddenAccountsClicked(MenuItem mi) {
181         SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
182         boolean flag = pref.getBoolean("show_hidden_accounts", false);
183
184         SharedPreferences.Editor editor = pref.edit();
185         editor.putBoolean("show_hidden_accounts", !flag);
186         Log.d("pref", "Setting show_hidden_accounts to " + (flag ? "false" : "true"));
187         editor.apply();
188
189         update_account_table();
190     }
191
192     private void prepare_db() {
193         account_list_last_updated = dbh.get_option_value("last_refresh", (long) 0);
194     }
195
196     private void update_accounts(boolean force) {
197         long now = new Date().getTime();
198         if ((now > (account_list_last_updated + (24 * 3600*1000))) || force) {
199             Log.d("db", "accounts last updated at " + account_list_last_updated+" and now is " + now+". re-fetching");
200             update_accounts();
201         }
202     }
203
204     private void update_accounts() {
205         if (mRefresh != null) mRefresh.setVisible(false);
206         Resources rm = getResources();
207
208         ProgressBar pb = findViewById(R.id.progressBar);
209         pb.setVisibility(View.VISIBLE);
210         TextView pt = findViewById(R.id.textProgress);
211         pt.setVisibility(View.VISIBLE);
212         pb.setIndeterminate(true);
213
214         RetrieveAccountsTask task = new RetrieveAccountsTask() {
215             @Override
216             protected void onProgressUpdate(Integer... values) {
217                 if ( values[0] == 0 )
218                     pt.setText(R.string.progress_connecting);
219                 else
220                     pt.setText(String.format(getResources().getString(R.string.progress_N_accounts_loaded), values[0]));
221             }
222
223             @Override
224             protected void onPostExecute(Void result) {
225                 pb.setVisibility(GONE);
226                 pt.setVisibility(GONE);
227                 if (mRefresh != null) mRefresh.setVisible(true);
228                 if (this.error != 0) {
229                     String err_text = rm.getString(this.error);
230                     Log.d("visual", String.format("showing snackbar: %s", err_text));
231                     Snackbar.make(drawer, err_text, Snackbar.LENGTH_LONG ).show();
232                 }
233                 else {
234                     dbh.set_option_value("last_refresh", new Date().getTime() );
235                     update_account_table();
236                 }
237             }
238         };
239
240         task.setPref(PreferenceManager.getDefaultSharedPreferences(this));
241         task.execute();
242
243     }
244
245     public int dp2px(float dp) {
246         return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()));
247     }
248
249     Pattern higher_account = Pattern.compile("^[^:]+:");
250
251     private String strip_higher_accounts(String acc_name, int[] count) {
252         count[0] = 0;
253         while (true) {
254             Matcher m = higher_account.matcher(acc_name);
255             if (m.find()) {
256                 count[0]++;
257                 acc_name = m.replaceFirst("");
258             }
259             else break;
260         }
261
262         return acc_name;
263     }
264
265     public void hideAccountClicked(MenuItem item) {
266         try(SQLiteDatabase db = dbh.getWritableDatabase()) {
267             db.execSQL("update accounts set hidden=1 where name=?", new Object[]{clickedAccountRow.getAccountName()});
268         }
269         update_account_table();
270     }
271
272     @SuppressLint("DefaultLocale")
273     private void update_account_table() {
274         LinearLayout root = findViewById(R.id.account_root);
275         root.removeAllViewsInLayout();
276
277         View.OnCreateContextMenuListener ccml = new View.OnCreateContextMenuListener() {
278             @Override
279             public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
280                 clickedAccountRow = (AccountRowLayout) v;
281                 getMenuInflater().inflate(R.menu.account_summary_account_menu, menu);
282             }
283         };
284
285         int rowHeight =
286                 (int) (getTheme().obtainStyledAttributes(new int[]{android.R.attr.actionBarSize})
287                         .getDimensionPixelSize(0, dp2px(56)) * 0.75);
288
289         boolean showingHiddenAccounts = PreferenceManager.getDefaultSharedPreferences(this)
290                 .getBoolean("show_hidden_accounts", false);
291         Log.d("pref", "show_hidden_accounts is " + (showingHiddenAccounts ? "true" : "false"));
292
293         try(SQLiteDatabase db = dbh.getReadableDatabase()) {
294             try (Cursor cursor = db
295                     .rawQuery("SELECT name, hidden FROM accounts ORDER BY name;", null))
296             {
297                 boolean even = false;
298                 String skippingAccountName = null;
299                 while (cursor.moveToNext()) {
300                     String acc_name = cursor.getString(0);
301                     if (skippingAccountName != null) {
302                         if (acc_name.startsWith(skippingAccountName + ":")) continue;
303
304                         skippingAccountName = null;
305                     }
306
307                     boolean is_hidden = cursor.getInt(1) == 1;
308
309                     if (!showingHiddenAccounts && is_hidden) {
310                         skippingAccountName = acc_name;
311                         continue;
312                     }
313
314                     LinearLayout r = new AccountRowLayout(this, acc_name);
315                     r.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
316                             ViewGroup.LayoutParams.WRAP_CONTENT));
317                     r.setGravity(Gravity.CENTER_VERTICAL);
318                     r.setPadding(getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin), dp2px(3),
319                             getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin),
320                             dp2px(4));
321                     r.setMinimumHeight(rowHeight);
322
323                     if (even) {
324                         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
325                             r.setBackgroundColor(
326                                     getResources().getColor(R.color.table_row_even_bg, getTheme()));
327                         }
328                         else {
329                             r.setBackgroundColor(getResources().getColor(R.color.table_row_even_bg));
330                         }
331                     }
332                     even = !even;
333                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
334                         r.setContextClickable(true);
335                     }
336                     r.setOnCreateContextMenuListener(ccml);
337
338
339                     TextView acc_tv = new TextView(this, null, R.style.account_summary_account_name);
340                     acc_tv.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
341                             ViewGroup.LayoutParams.MATCH_PARENT, 5f));
342                     acc_tv.setGravity(Gravity.CENTER_VERTICAL);
343                     int[] indent_level = new int[]{0};
344                     String short_acc_name = strip_higher_accounts(acc_name, indent_level);
345                     acc_tv.setPadding(indent_level[0] * getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin) / 2, 0, 0,
346                             0);
347                     acc_tv.setText(short_acc_name);
348                     if (is_hidden) acc_tv.setTypeface(null, Typeface.ITALIC);
349                     r.addView(acc_tv);
350
351                     TextView amt_tv = new TextView(this, null, R.style.account_summary_amounts);
352                     amt_tv.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
353                             ViewGroup.LayoutParams.MATCH_PARENT, 1f));
354                     amt_tv.setTextAlignment(EditText.TEXT_ALIGNMENT_VIEW_END);
355                     amt_tv.setGravity(Gravity.CENTER_VERTICAL);
356 //                amt_tv.setGravity(Gravity.CENTER);
357                     amt_tv.setMinWidth(dp2px(60f));
358                     StringBuilder amt_text = new StringBuilder();
359                     try (Cursor cAmounts = db.rawQuery(
360                             "SELECT currency, value FROM account_values WHERE account = ?", new String[]{acc_name}))
361                     {
362                         while (cAmounts.moveToNext()) {
363                             String curr = cAmounts.getString(0);
364                             Float amt = cAmounts.getFloat(1);
365                             if (amt_text.length() != 0) amt_text.append('\n');
366                             amt_text.append(String.format("%s %,1.2f", curr, amt));
367                         }
368                     }
369                     amt_tv.setText(amt_text.toString());
370                     if (is_hidden) amt_tv.setTypeface(null, Typeface.ITALIC);
371
372                     r.addView(amt_tv);
373
374                     root.addView(r);
375                 }
376             }
377         }
378     }
379 }