]> git.ktnx.net Git - mobile-ledger.git/blob - app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java
nice side-swipe switch between account summary and transaction list
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / ui / activity / MainActivity.java
1 /*
2  * Copyright © 2019 Damyan Ivanov.
3  * This file is part of Mobile-Ledger.
4  * Mobile-Ledger is free software: you can distribute it and/or modify it
5  * under the term of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your opinion), any later version.
8  *
9  * Mobile-Ledger is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License terms for details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with Mobile-Ledger. If not, see <https://www.gnu.org/licenses/>.
16  */
17
18 package net.ktnx.mobileledger.ui.activity;
19
20 import android.content.Intent;
21 import android.content.pm.PackageInfo;
22 import android.os.Build;
23 import android.os.Bundle;
24 import android.preference.PreferenceManager;
25 import android.support.annotation.ColorInt;
26 import android.support.v4.app.Fragment;
27 import android.support.v4.app.FragmentManager;
28 import android.support.v4.app.FragmentPagerAdapter;
29 import android.support.v4.view.GravityCompat;
30 import android.support.v4.view.ViewPager;
31 import android.support.v4.widget.DrawerLayout;
32 import android.support.v7.app.ActionBarDrawerToggle;
33 import android.support.v7.app.AppCompatActivity;
34 import android.support.v7.widget.Toolbar;
35 import android.util.Log;
36 import android.view.ContextMenu;
37 import android.view.MenuItem;
38 import android.view.View;
39 import android.widget.LinearLayout;
40 import android.widget.ProgressBar;
41 import android.widget.TextView;
42
43 import net.ktnx.mobileledger.R;
44 import net.ktnx.mobileledger.async.RetrieveTransactionsTask;
45 import net.ktnx.mobileledger.model.Data;
46 import net.ktnx.mobileledger.model.LedgerAccount;
47 import net.ktnx.mobileledger.ui.MobileLedgerListFragment;
48 import net.ktnx.mobileledger.ui.account_summary.AccountSummaryFragment;
49 import net.ktnx.mobileledger.ui.transaction_list.TransactionListFragment;
50 import net.ktnx.mobileledger.utils.MLDB;
51
52 import java.lang.ref.WeakReference;
53 import java.time.ZoneId;
54 import java.time.format.DateTimeFormatter;
55 import java.util.Date;
56 import java.util.Observable;
57 import java.util.Observer;
58
59 public class MainActivity extends AppCompatActivity {
60     public MobileLedgerListFragment currentFragment = null;
61     DrawerLayout drawer;
62     private AccountSummaryFragment accountSummaryFragment;
63     private TransactionListFragment transactionListFragment;
64     private FragmentManager fragmentManager;
65     private TextView tvLastUpdate;
66     private RetrieveTransactionsTask retrieveTransactionsTask;
67     private View bTransactionListCancelDownload;
68     private ProgressBar progressBar;
69     private LinearLayout progressLayout;
70     private SectionsPagerAdapter mSectionsPagerAdapter;
71     private ViewPager mViewPager;
72
73     @Override
74     protected void onStart() {
75         super.onStart();
76
77         Data.lastUpdateDate.set(null);
78         updateLastUpdateTextFromDB();
79         Date lastUpdate = Data.lastUpdateDate.get();
80
81         long now = new Date().getTime();
82         if ((lastUpdate == null) || (now > (lastUpdate.getTime() + (24 * 3600 * 1000)))) {
83             if (lastUpdate == null) Log.d("db::", "WEB data never fetched. scheduling a fetch");
84             else Log.d("db",
85                     String.format("WEB data last fetched at %1.3f and now is %1.3f. re-fetching",
86                             lastUpdate.getTime() / 1000f, now / 1000f));
87
88             scheduleTransactionListRetrieval();
89         }
90     }
91     @Override
92     protected void onCreate(Bundle savedInstanceState) {
93         super.onCreate(savedInstanceState);
94         setContentView(R.layout.activity_main);
95         Toolbar toolbar = findViewById(R.id.toolbar);
96         setSupportActionBar(toolbar);
97
98         drawer = findViewById(R.id.drawer_layout);
99         ActionBarDrawerToggle toggle =
100                 new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open,
101                         R.string.navigation_drawer_close);
102         drawer.addDrawerListener(toggle);
103         toggle.syncState();
104
105         android.widget.TextView ver = drawer.findViewById(R.id.drawer_version_text);
106
107         try {
108             PackageInfo pi =
109                     getApplicationContext().getPackageManager().getPackageInfo(getPackageName(), 0);
110             ver.setText(pi.versionName);
111         }
112         catch (Exception e) {
113             e.printStackTrace();
114         }
115
116         tvLastUpdate = findViewById(R.id.transactions_last_update);
117
118         bTransactionListCancelDownload = findViewById(R.id.transaction_list_cancel_download);
119         progressBar = findViewById(R.id.transaction_list_progress_bar);
120         if (progressBar == null)
121             throw new RuntimeException("Can't get hold on the transaction value progress bar");
122         progressLayout = findViewById(R.id.transaction_progress_layout);
123         if (progressLayout == null) throw new RuntimeException(
124                 "Can't get hold on the transaction value progress bar layout");
125
126         fragmentManager = getSupportFragmentManager();
127         mSectionsPagerAdapter = new SectionsPagerAdapter(fragmentManager);
128
129         mViewPager = findViewById(R.id.root_frame);
130         mViewPager.setAdapter(mSectionsPagerAdapter);
131         mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener(){
132             @Override
133             public void onPageSelected(int position) {
134                 switch (position) {
135                     case 0:
136                         markDrawerItemCurrent(R.id.nav_account_summary);
137                         break;
138                     case 1:
139                         markDrawerItemCurrent(R.id.nav_latest_transactions);
140                         break;
141                     default:
142                         Log.e("MainActivity", String.format("Unexpected page index %d", position));
143                 }
144
145                 super.onPageSelected(position);
146             }
147         });
148
149         Data.lastUpdateDate.addObserver(new Observer() {
150             @Override
151             public void update(Observable o, Object arg) {
152                 Log.d("main", "lastUpdateDate changed");
153                 runOnUiThread(() -> {
154                     Date date = Data.lastUpdateDate.get();
155                     if (date == null) {
156                         tvLastUpdate.setText(R.string.transaction_last_update_never);
157                     }
158                     else {
159                         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
160                             tvLastUpdate.setText(date.toInstant().atZone(ZoneId.systemDefault())
161                                     .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
162                         }
163                         else {
164                             tvLastUpdate.setText(date.toLocaleString());
165                         }
166                     }
167                 });
168             }
169         });
170
171         Data.ledgerTitle.addObserver(new Observer() {
172             @Override
173             public void update(Observable o, Object arg) {
174                 runOnUiThread(() -> {
175                     String title = Data.ledgerTitle.get();
176                     if (title == null) toolbar.setSubtitle("");
177                     else toolbar.setSubtitle(title);
178                 });
179             }
180         });
181     }
182     public void fab_new_transaction_clicked(View view) {
183         Intent intent = new Intent(this, NewTransactionActivity.class);
184         startActivity(intent);
185         overridePendingTransition(R.anim.slide_in_right, R.anim.dummy);
186     }
187
188     public void nav_exit_clicked(View view) {
189         Log.w("app", "exiting");
190         finish();
191     }
192
193     public void nav_settings_clicked(View view) {
194         Intent intent = new Intent(this, SettingsActivity.class);
195         startActivity(intent);
196     }
197     public void markDrawerItemCurrent(int id) {
198         TextView item = drawer.findViewById(id);
199         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
200             item.setBackgroundColor(getResources().getColor(R.color.table_row_even_bg, getTheme()));
201         }
202         else {
203             item.setBackgroundColor(getResources().getColor(R.color.table_row_even_bg));
204         }
205
206         setTitle(item.getText());
207
208         @ColorInt int transparent = getResources().getColor(android.R.color.transparent);
209
210         LinearLayout actions = drawer.findViewById(R.id.nav_actions);
211         for (int i = 0; i < actions.getChildCount(); i++) {
212             View view = actions.getChildAt(i);
213             if (view.getId() != id) {
214                 view.setBackgroundColor(transparent);
215             }
216         }
217     }
218     public void onOptionsMenuClicked(MenuItem menuItem) {
219         ContextMenu.ContextMenuInfo info = menuItem.getMenuInfo();
220         switch (menuItem.getItemId()) {
221             case R.id.menu_acc_summary_cancel_selection:
222                 if (accountSummaryFragment != null)
223                     accountSummaryFragment.onCancelAccSelection(menuItem);
224                 break;
225             case R.id.menu_acc_summary_confirm_selection:
226                 if (accountSummaryFragment != null)
227                     accountSummaryFragment.onConfirmAccSelection(menuItem);
228                 break;
229             case R.id.menu_acc_summary_only_starred:
230                 if (accountSummaryFragment != null)
231                     accountSummaryFragment.onShowOnlyStarredClicked(menuItem);
232                 break;
233             case R.id.menu_transaction_list_filter:
234                 if (transactionListFragment != null)
235                     transactionListFragment.onShowFilterClick(menuItem);
236                 break;
237             default:
238                 Log.e("menu", String.format("Menu item %d not handled", menuItem.getItemId()));
239         }
240     }
241     public void onViewClicked(View view) {
242         switch (view.getId()) {
243             case R.id.clearAccountNameFilter:
244                 if (transactionListFragment != null)
245                     transactionListFragment.onClearAccountNameClick(view);
246                 break;
247             default:
248                 Log.e("click", String.format("View %d click not handled", view.getId()));
249         }
250     }
251     public void onAccountSummaryClicked(View view) {
252         drawer.closeDrawers();
253
254         showAccountSummaryFragment();
255     }
256     private void showAccountSummaryFragment() {
257         mViewPager.setCurrentItem(0, true);
258 //        FragmentTransaction ft = fragmentManager.beginTransaction();
259 //        accountSummaryFragment = new AccountSummaryFragment();
260 //        ft.replace(R.id.root_frame, accountSummaryFragment);
261 //        ft.commit();
262 //        currentFragment = accountSummaryFragment;
263     }
264     public void onLatestTransactionsClicked(View view) {
265         drawer.closeDrawers();
266
267         showTransactionsFragment(null);
268     }
269     private void resetFragmentBackStack() {
270 //        fragmentManager.popBackStack(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
271     }
272     private void showTransactionsFragment(LedgerAccount account) {
273         mViewPager.setCurrentItem(1, true);
274 //        FragmentTransaction ft = fragmentManager.beginTransaction();
275 //        if (transactionListFragment == null) {
276 //            Log.d("flow", "MainActivity creating TransactionListFragment");
277 //            transactionListFragment = new TransactionListFragment();
278 //        }
279 //        Bundle bundle = new Bundle();
280 //        if (account != null) {
281 //            bundle.putString(TransactionListFragment.BUNDLE_KEY_FILTER_ACCOUNT_NAME,
282 //                    account.getName());
283 //        }
284 //        transactionListFragment.setArguments(bundle);
285 //        ft.replace(R.id.root_frame, transactionListFragment);
286 //        if (account != null)
287 //            ft.addToBackStack(getResources().getString(R.string.title_activity_transaction_list));
288 //        ft.commit();
289 //
290 //        currentFragment = transactionListFragment;
291     }
292     public void showAccountTransactions(LedgerAccount account) {
293         showTransactionsFragment(account);
294     }
295     @Override
296     public void onBackPressed() {
297         DrawerLayout drawer = findViewById(R.id.drawer_layout);
298         if (drawer.isDrawerOpen(GravityCompat.START)) {
299             drawer.closeDrawer(GravityCompat.START);
300         }
301         else {
302             Log.d("fragments",
303                     String.format("manager stack: %d", fragmentManager.getBackStackEntryCount()));
304
305             super.onBackPressed();
306         }
307     }
308     public void updateLastUpdateTextFromDB() {
309         {
310             long last_update = MLDB.get_option_value(MLDB.OPT_TRANSACTION_LIST_STAMP, 0L);
311
312             Log.d("transactions", String.format("Last update = %d", last_update));
313             if (last_update == 0) {
314                 Data.lastUpdateDate.set(null);
315             }
316             else {
317                 Data.lastUpdateDate.set(new Date(last_update));
318             }
319         }
320     }
321     public void scheduleTransactionListRetrieval() {
322         retrieveTransactionsTask = new RetrieveTransactionsTask(new WeakReference<>(this));
323
324         RetrieveTransactionsTask.Params params = new RetrieveTransactionsTask.Params(
325                 PreferenceManager.getDefaultSharedPreferences(this));
326
327         retrieveTransactionsTask.execute(params);
328         bTransactionListCancelDownload.setEnabled(true);
329     }
330     public void onStopTransactionRefreshClick(View view) {
331         Log.d("interactive", "Cancelling transactions refresh");
332         if (retrieveTransactionsTask != null) retrieveTransactionsTask.cancel(false);
333         bTransactionListCancelDownload.setEnabled(false);
334     }
335     public void onRetrieveDone(boolean success) {
336         progressLayout.setVisibility(View.GONE);
337         updateLastUpdateTextFromDB();
338     }
339     public void onRetrieveStart() {
340         progressBar.setIndeterminate(true);
341         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) progressBar.setProgress(0, false);
342         else progressBar.setProgress(0);
343         progressLayout.setVisibility(View.VISIBLE);
344     }
345     public void onRetrieveProgress(RetrieveTransactionsTask.Progress progress) {
346         if ((progress.getTotal() == RetrieveTransactionsTask.Progress.INDETERMINATE) ||
347             (progress.getTotal() == 0))
348         {
349             progressBar.setIndeterminate(true);
350         }
351         else {
352             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
353                 progressBar.setMin(0);
354             }
355             progressBar.setMax(progress.getTotal());
356             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
357                 progressBar.setProgress(progress.getProgress(), true);
358             }
359             else progressBar.setProgress(progress.getProgress());
360             progressBar.setIndeterminate(false);
361         }
362     }
363     public class SectionsPagerAdapter extends FragmentPagerAdapter {
364
365         public SectionsPagerAdapter(FragmentManager fm) {
366             super(fm);
367         }
368
369         @Override
370         public Fragment getItem(int position) {
371             Log.d("main", String.format("Switching to gragment %d", position));
372             switch (position) {
373                 case 0:
374                     return new AccountSummaryFragment();
375                 case 1:
376                     return new TransactionListFragment();
377                 default:
378                     throw new IllegalStateException(
379                             String.format("Unexpected fragment index: " + "%d", position));
380             }
381         }
382
383         @Override
384         public int getCount() {
385             return 2;
386         }
387     }
388
389 }