]> git.ktnx.net Git - mobile-ledger.git/blob - app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java
whitespace
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / ui / activity / MainActivity.java
1 /*
2  * Copyright © 2021 Damyan Ivanov.
3  * This file is part of MoLe.
4  * MoLe 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  * MoLe 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 MoLe. 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.content.pm.ShortcutInfo;
23 import android.content.pm.ShortcutManager;
24 import android.content.res.ColorStateList;
25 import android.graphics.Color;
26 import android.graphics.drawable.Icon;
27 import android.os.Build;
28 import android.os.Bundle;
29 import android.text.format.DateUtils;
30 import android.util.Log;
31 import android.view.View;
32 import android.view.animation.AnimationUtils;
33 import android.widget.TextView;
34
35 import androidx.annotation.NonNull;
36 import androidx.appcompat.app.ActionBarDrawerToggle;
37 import androidx.appcompat.app.AlertDialog;
38 import androidx.core.view.GravityCompat;
39 import androidx.drawerlayout.widget.DrawerLayout;
40 import androidx.fragment.app.Fragment;
41 import androidx.fragment.app.FragmentActivity;
42 import androidx.lifecycle.ViewModelProvider;
43 import androidx.recyclerview.widget.LinearLayoutManager;
44 import androidx.recyclerview.widget.RecyclerView;
45 import androidx.viewpager2.adapter.FragmentStateAdapter;
46 import androidx.viewpager2.widget.ViewPager2;
47
48 import com.google.android.material.snackbar.Snackbar;
49
50 import net.ktnx.mobileledger.R;
51 import net.ktnx.mobileledger.async.RetrieveTransactionsTask;
52 import net.ktnx.mobileledger.databinding.ActivityMainBinding;
53 import net.ktnx.mobileledger.model.Data;
54 import net.ktnx.mobileledger.model.MobileLedgerProfile;
55 import net.ktnx.mobileledger.ui.MainModel;
56 import net.ktnx.mobileledger.ui.account_summary.AccountSummaryFragment;
57 import net.ktnx.mobileledger.ui.new_transaction.NewTransactionActivity;
58 import net.ktnx.mobileledger.ui.profiles.ProfilesRecyclerViewAdapter;
59 import net.ktnx.mobileledger.ui.templates.TemplatesActivity;
60 import net.ktnx.mobileledger.ui.transaction_list.TransactionListFragment;
61 import net.ktnx.mobileledger.utils.Colors;
62 import net.ktnx.mobileledger.utils.Logger;
63 import net.ktnx.mobileledger.utils.MLDB;
64
65 import org.jetbrains.annotations.NotNull;
66
67 import java.util.ArrayList;
68 import java.util.Date;
69 import java.util.List;
70 import java.util.Locale;
71 import java.util.Objects;
72
73 /*
74  * TODO: reports
75  *  */
76
77 public class MainActivity extends ProfileThemedActivity {
78     public static final String STATE_CURRENT_PAGE = "current_page";
79     public static final String BUNDLE_SAVED_STATE = "bundle_savedState";
80     public static final String STATE_ACC_FILTER = "account_filter";
81     private SectionsPagerAdapter mSectionsPagerAdapter;
82     private ProfilesRecyclerViewAdapter mProfileListAdapter;
83     private int mCurrentPage;
84     private boolean mBackMeansToAccountList = false;
85     private DrawerLayout.SimpleDrawerListener drawerListener;
86     private ActionBarDrawerToggle barDrawerToggle;
87     private ViewPager2.OnPageChangeCallback pageChangeCallback;
88     private MobileLedgerProfile profile;
89     private MainModel mainModel;
90     private ActivityMainBinding b;
91     @Override
92     protected void onStart() {
93         super.onStart();
94
95         Logger.debug("MainActivity", "onStart()");
96
97         b.mainPager.setCurrentItem(mCurrentPage, false);
98     }
99     @Override
100     protected void onSaveInstanceState(@NotNull Bundle outState) {
101         super.onSaveInstanceState(outState);
102         outState.putInt(STATE_CURRENT_PAGE, b.mainPager.getCurrentItem());
103         if (mainModel.getAccountFilter()
104                      .getValue() != null)
105             outState.putString(STATE_ACC_FILTER, mainModel.getAccountFilter()
106                                                           .getValue());
107     }
108     @Override
109     protected void onDestroy() {
110         mSectionsPagerAdapter = null;
111         b.navProfileList.setAdapter(null);
112         b.drawerLayout.removeDrawerListener(drawerListener);
113         drawerListener = null;
114         b.drawerLayout.removeDrawerListener(barDrawerToggle);
115         barDrawerToggle = null;
116         b.mainPager.unregisterOnPageChangeCallback(pageChangeCallback);
117         pageChangeCallback = null;
118         super.onDestroy();
119     }
120     @Override
121     protected void onResume() {
122         super.onResume();
123         fabShouldShow();
124     }
125     @Override
126     protected void onCreate(Bundle savedInstanceState) {
127         Logger.debug("MainActivity", "onCreate()/entry");
128         super.onCreate(savedInstanceState);
129         Logger.debug("MainActivity", "onCreate()/after super");
130         b = ActivityMainBinding.inflate(getLayoutInflater());
131         setContentView(b.getRoot());
132
133         mainModel = new ViewModelProvider(this).get(MainModel.class);
134
135         mSectionsPagerAdapter = new SectionsPagerAdapter(this);
136
137         Bundle extra = getIntent().getBundleExtra(BUNDLE_SAVED_STATE);
138         if (extra != null && savedInstanceState == null)
139             savedInstanceState = extra;
140
141
142         setSupportActionBar(b.toolbar);
143
144         Data.observeProfile(this, this::onProfileChanged);
145
146         Data.profiles.observe(this, this::onProfileListChanged);
147         Data.backgroundTaskProgress.observe(this, this::onRetrieveProgress);
148         Data.backgroundTasksRunning.observe(this, this::onRetrieveRunningChanged);
149
150         if (barDrawerToggle == null) {
151             barDrawerToggle = new ActionBarDrawerToggle(this, b.drawerLayout, b.toolbar,
152                     R.string.navigation_drawer_open, R.string.navigation_drawer_close);
153             b.drawerLayout.addDrawerListener(barDrawerToggle);
154         }
155         barDrawerToggle.syncState();
156
157         try {
158             PackageInfo pi = getApplicationContext().getPackageManager()
159                                                     .getPackageInfo(getPackageName(), 0);
160             ((TextView) b.navUpper.findViewById(R.id.drawer_version_text)).setText(pi.versionName);
161             ((TextView) b.noProfilesLayout.findViewById(R.id.drawer_version_text)).setText(
162                     pi.versionName);
163         }
164         catch (Exception e) {
165             e.printStackTrace();
166         }
167
168         markDrawerItemCurrent(R.id.nav_account_summary);
169
170         b.mainPager.setAdapter(mSectionsPagerAdapter);
171
172         if (pageChangeCallback == null) {
173             pageChangeCallback = new ViewPager2.OnPageChangeCallback() {
174                 @Override
175                 public void onPageSelected(int position) {
176                     mCurrentPage = position;
177                     switch (position) {
178                         case 0:
179                             markDrawerItemCurrent(R.id.nav_account_summary);
180                             break;
181                         case 1:
182                             markDrawerItemCurrent(R.id.nav_latest_transactions);
183                             break;
184                         default:
185                             Log.e("MainActivity",
186                                     String.format("Unexpected page index %d", position));
187                     }
188
189                     super.onPageSelected(position);
190                 }
191             };
192             b.mainPager.registerOnPageChangeCallback(pageChangeCallback);
193         }
194
195         mCurrentPage = 0;
196         if (savedInstanceState != null) {
197             int currentPage = savedInstanceState.getInt(STATE_CURRENT_PAGE, -1);
198             if (currentPage != -1) {
199                 mCurrentPage = currentPage;
200             }
201             mainModel.getAccountFilter()
202                      .setValue(savedInstanceState.getString(STATE_ACC_FILTER, null));
203         }
204
205         b.btnNoProfilesAdd.setOnClickListener(
206                 v -> MobileLedgerProfile.startEditProfileActivity(this, null));
207
208         b.btnAddTransaction.setOnClickListener(this::fabNewTransactionClicked);
209
210         b.navNewProfileButton.setOnClickListener(
211                 v -> MobileLedgerProfile.startEditProfileActivity(this, null));
212
213         b.transactionListCancelDownload.setOnClickListener(this::onStopTransactionRefreshClick);
214
215         if (mProfileListAdapter == null)
216             mProfileListAdapter = new ProfilesRecyclerViewAdapter();
217         b.navProfileList.setAdapter(mProfileListAdapter);
218
219         mProfileListAdapter.editingProfiles.observe(this, newValue -> {
220             if (newValue) {
221                 b.navProfilesStartEdit.setVisibility(View.GONE);
222                 b.navProfilesCancelEdit.setVisibility(View.VISIBLE);
223                 b.navNewProfileButton.setVisibility(View.VISIBLE);
224                 if (b.drawerLayout.isDrawerOpen(GravityCompat.START)) {
225                     b.navProfilesStartEdit.startAnimation(
226                             AnimationUtils.loadAnimation(MainActivity.this, R.anim.fade_out));
227                     b.navProfilesCancelEdit.startAnimation(
228                             AnimationUtils.loadAnimation(MainActivity.this, R.anim.fade_in));
229                     b.navNewProfileButton.startAnimation(
230                             AnimationUtils.loadAnimation(MainActivity.this, R.anim.fade_in));
231                 }
232             }
233             else {
234                 b.navProfilesCancelEdit.setVisibility(View.GONE);
235                 b.navProfilesStartEdit.setVisibility(View.VISIBLE);
236                 b.navNewProfileButton.setVisibility(View.GONE);
237                 if (b.drawerLayout.isDrawerOpen(GravityCompat.START)) {
238                     b.navProfilesCancelEdit.startAnimation(
239                             AnimationUtils.loadAnimation(MainActivity.this, R.anim.fade_out));
240                     b.navProfilesStartEdit.startAnimation(
241                             AnimationUtils.loadAnimation(MainActivity.this, R.anim.fade_in));
242                     b.navNewProfileButton.startAnimation(
243                             AnimationUtils.loadAnimation(MainActivity.this, R.anim.fade_out));
244                 }
245             }
246
247             mProfileListAdapter.notifyDataSetChanged();
248         });
249
250         LinearLayoutManager llm = new LinearLayoutManager(this);
251
252         llm.setOrientation(RecyclerView.VERTICAL);
253         b.navProfileList.setLayoutManager(llm);
254
255         b.navProfilesStartEdit.setOnClickListener((v) -> mProfileListAdapter.flipEditingProfiles());
256         b.navProfilesCancelEdit.setOnClickListener(
257                 (v) -> mProfileListAdapter.flipEditingProfiles());
258         b.navProfileListHeadButtons.setOnClickListener(
259                 (v) -> mProfileListAdapter.flipEditingProfiles());
260         if (drawerListener == null) {
261             drawerListener = new DrawerLayout.SimpleDrawerListener() {
262                 @Override
263                 public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
264                     if (slideOffset > 0.2)
265                         fabHide();
266                 }
267                 @Override
268                 public void onDrawerClosed(View drawerView) {
269                     super.onDrawerClosed(drawerView);
270                     mProfileListAdapter.setAnimationsEnabled(false);
271                     mProfileListAdapter.editingProfiles.setValue(false);
272                     Data.drawerOpen.setValue(false);
273                     fabShouldShow();
274                 }
275                 @Override
276                 public void onDrawerOpened(View drawerView) {
277                     super.onDrawerOpened(drawerView);
278                     mProfileListAdapter.setAnimationsEnabled(true);
279                     Data.drawerOpen.setValue(true);
280                     fabHide();
281                 }
282             };
283             b.drawerLayout.addDrawerListener(drawerListener);
284         }
285
286         Data.drawerOpen.observe(this, open -> {
287             if (open)
288                 b.drawerLayout.open();
289             else
290                 b.drawerLayout.close();
291         });
292
293         mainModel.getUpdateError()
294                  .observe(this, (error) -> {
295                      if (error == null)
296                          return;
297
298                      Snackbar.make(b.mainPager, error, Snackbar.LENGTH_INDEFINITE)
299                              .show();
300                      mainModel.clearUpdateError();
301                  });
302         Data.locale.observe(this, l -> refreshLastUpdateInfo());
303         Data.lastUpdateDate.observe(this, date -> refreshLastUpdateInfo());
304         Data.lastUpdateTransactionCount.observe(this, date -> refreshLastUpdateInfo());
305         Data.lastUpdateAccountCount.observe(this, date -> refreshLastUpdateInfo());
306         b.navAccountSummary.setOnClickListener(this::onAccountSummaryClicked);
307         b.navLatestTransactions.setOnClickListener(this::onLatestTransactionsClicked);
308         b.navPatterns.setOnClickListener(this::onPatternsClick);
309     }
310     private void onPatternsClick(View view) {
311         Intent intent = new Intent(this, TemplatesActivity.class);
312         startActivity(intent);
313     }
314     private void scheduleDataRetrievalIfStale(long lastUpdate) {
315         long now = new Date().getTime();
316         if ((lastUpdate == 0) || (now > (lastUpdate + (24 * 3600 * 1000)))) {
317             if (lastUpdate == 0)
318                 Logger.debug("db::", "WEB data never fetched. scheduling a fetch");
319             else
320                 Logger.debug("db", String.format(Locale.ENGLISH,
321                         "WEB data last fetched at %1.3f and now is %1.3f. re-fetching",
322                         lastUpdate / 1000f, now / 1000f));
323
324             mainModel.scheduleTransactionListRetrieval();
325         }
326     }
327     private void createShortcuts(List<MobileLedgerProfile> list) {
328         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1)
329             return;
330
331         ShortcutManager sm = getSystemService(ShortcutManager.class);
332         List<ShortcutInfo> shortcuts = new ArrayList<>();
333         int i = 0;
334         for (MobileLedgerProfile p : list) {
335             if (shortcuts.size() >= sm.getMaxShortcutCountPerActivity())
336                 break;
337
338             if (!p.isPostingPermitted())
339                 continue;
340
341             final ShortcutInfo.Builder builder =
342                     new ShortcutInfo.Builder(this, "new_transaction_" + p.getUuid());
343             ShortcutInfo si = builder.setShortLabel(p.getName())
344                                      .setIcon(Icon.createWithResource(this,
345                                              R.drawable.thick_plus_icon))
346                                      .setIntent(new Intent(Intent.ACTION_VIEW, null, this,
347                                              NewTransactionActivity.class).putExtra("profile_uuid",
348                                              p.getUuid()))
349                                      .setRank(i)
350                                      .build();
351             shortcuts.add(si);
352             i++;
353         }
354         sm.setDynamicShortcuts(shortcuts);
355     }
356     private void onProfileListChanged(List<MobileLedgerProfile> newList) {
357         if ((newList == null) || newList.isEmpty()) {
358             b.noProfilesLayout.setVisibility(View.VISIBLE);
359             b.mainAppLayout.setVisibility(View.GONE);
360             return;
361         }
362
363         b.mainAppLayout.setVisibility(View.VISIBLE);
364         b.noProfilesLayout.setVisibility(View.GONE);
365
366         b.navProfileList.setMinimumHeight(
367                 (int) (getResources().getDimension(R.dimen.thumb_row_height) * newList.size()));
368
369         Logger.debug("profiles", "profile list changed");
370         mProfileListAdapter.notifyDataSetChanged();
371
372         createShortcuts(newList);
373     }
374     /**
375      * called when the current profile has changed
376      */
377     private void onProfileChanged(MobileLedgerProfile profile) {
378         if (this.profile == null) {
379             if (profile == null)
380                 return;
381         }
382         else {
383             if (this.profile.equals(profile))
384                 return;
385         }
386
387         boolean haveProfile = profile != null;
388
389         if (haveProfile)
390             setTitle(profile.getName());
391         else
392             setTitle(R.string.app_name);
393
394         mainModel.setProfile(profile);
395
396         this.profile = profile;
397
398         int newProfileTheme = haveProfile ? profile.getThemeHue() : -1;
399         if (newProfileTheme != Colors.profileThemeId) {
400             Logger.debug("profiles",
401                     String.format(Locale.ENGLISH, "profile theme %d → %d", Colors.profileThemeId,
402                             newProfileTheme));
403             Colors.profileThemeId = newProfileTheme;
404             profileThemeChanged();
405             // profileThemeChanged would restart the activity, so no need to reload the
406             // data sets below
407             return;
408         }
409
410         b.noProfilesLayout.setVisibility(haveProfile ? View.GONE : View.VISIBLE);
411         b.pagerLayout.setVisibility(haveProfile ? View.VISIBLE : View.VISIBLE);
412
413         mProfileListAdapter.notifyDataSetChanged();
414
415         mainModel.clearAccounts();
416         mainModel.clearTransactions();
417
418         if (haveProfile) {
419             mainModel.scheduleAccountListReload();
420             Logger.debug("transactions", "requesting list reload");
421             mainModel.scheduleTransactionListReload();
422
423             if (profile.isPostingPermitted()) {
424                 b.toolbar.setSubtitle(null);
425                 b.btnAddTransaction.show();
426             }
427             else {
428                 b.toolbar.setSubtitle(R.string.profile_subtitle_read_only);
429                 b.btnAddTransaction.hide();
430             }
431         }
432         else {
433             b.toolbar.setSubtitle(null);
434             b.btnAddTransaction.hide();
435         }
436
437         updateLastUpdateTextFromDB();
438     }
439     private void profileThemeChanged() {
440         // un-hook all observed LiveData
441         Data.removeProfileObservers(this);
442         Data.profiles.removeObservers(this);
443         Data.lastUpdateTransactionCount.removeObservers(this);
444         Data.lastUpdateAccountCount.removeObservers(this);
445         Data.lastUpdateDate.removeObservers(this);
446
447         recreate();
448     }
449     public void fabNewTransactionClicked(View view) {
450         Intent intent = new Intent(this, NewTransactionActivity.class);
451         startActivity(intent);
452         overridePendingTransition(R.anim.slide_in_up, R.anim.dummy);
453     }
454     public void markDrawerItemCurrent(int id) {
455         TextView item = b.drawerLayout.findViewById(id);
456         item.setBackgroundColor(Colors.tableRowDarkBG);
457
458         for (int i = 0; i < b.navActions.getChildCount(); i++) {
459             View view = b.navActions.getChildAt(i);
460             if (view.getId() != id) {
461                 view.setBackgroundColor(Color.TRANSPARENT);
462             }
463         }
464     }
465     public void onAccountSummaryClicked(View view) {
466         b.drawerLayout.closeDrawers();
467
468         showAccountSummaryFragment();
469     }
470     private void showAccountSummaryFragment() {
471         b.mainPager.setCurrentItem(0, true);
472         mainModel.getAccountFilter()
473                  .setValue(null);
474     }
475     public void onLatestTransactionsClicked(View view) {
476         b.drawerLayout.closeDrawers();
477
478         showTransactionsFragment(null);
479     }
480     public void showTransactionsFragment(String accName) {
481         mainModel.getAccountFilter()
482                  .setValue(accName);
483         b.mainPager.setCurrentItem(1, true);
484     }
485     public void showAccountTransactions(String accountName) {
486         mBackMeansToAccountList = true;
487         showTransactionsFragment(accountName);
488     }
489     @Override
490     public void onBackPressed() {
491         if (b.drawerLayout.isDrawerOpen(GravityCompat.START)) {
492             b.drawerLayout.closeDrawer(GravityCompat.START);
493         }
494         else {
495             if (mBackMeansToAccountList && (b.mainPager.getCurrentItem() == 1)) {
496                 mainModel.getAccountFilter()
497                          .setValue(null);
498                 showAccountSummaryFragment();
499                 mBackMeansToAccountList = false;
500             }
501             else {
502                 Logger.debug("fragments", String.format(Locale.ENGLISH, "manager stack: %d",
503                         getSupportFragmentManager().getBackStackEntryCount()));
504
505                 super.onBackPressed();
506             }
507         }
508     }
509     public void updateLastUpdateTextFromDB() {
510         if (profile == null)
511             return;
512
513         long lastUpdate = profile.getLongOption(MLDB.OPT_LAST_SCRAPE, 0L);
514
515         Logger.debug("transactions", String.format(Locale.ENGLISH, "Last update = %d", lastUpdate));
516         if (lastUpdate == 0) {
517             Data.lastUpdateDate.postValue(null);
518         }
519         else {
520             Data.lastUpdateDate.postValue(new Date(lastUpdate));
521         }
522
523         scheduleDataRetrievalIfStale(lastUpdate);
524
525     }
526     private void refreshLastUpdateInfo() {
527         final int formatFlags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR |
528                                 DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_NUMERIC_DATE;
529         String templateForTransactions =
530                 getResources().getString(R.string.transaction_count_summary);
531         String templateForAccounts = getResources().getString(R.string.account_count_summary);
532         Integer accountCount = Data.lastUpdateAccountCount.getValue();
533         Integer transactionCount = Data.lastUpdateTransactionCount.getValue();
534         Date lastUpdate = Data.lastUpdateDate.getValue();
535         if (lastUpdate == null) {
536             Data.lastTransactionsUpdateText.set("----");
537             Data.lastAccountsUpdateText.set("----");
538         }
539         else {
540             Data.lastTransactionsUpdateText.set(
541                     String.format(Objects.requireNonNull(Data.locale.getValue()),
542                             templateForTransactions,
543                             transactionCount == null ? 0 : transactionCount,
544                             DateUtils.formatDateTime(this, lastUpdate.getTime(), formatFlags)));
545             Data.lastAccountsUpdateText.set(
546                     String.format(Objects.requireNonNull(Data.locale.getValue()),
547                             templateForAccounts, accountCount == null ? 0 : accountCount,
548                             DateUtils.formatDateTime(this, lastUpdate.getTime(), formatFlags)));
549         }
550     }
551     public void onStopTransactionRefreshClick(View view) {
552         Logger.debug("interactive", "Cancelling transactions refresh");
553         mainModel.stopTransactionsRetrieval();
554         b.transactionListCancelDownload.setEnabled(false);
555     }
556     public void onRetrieveRunningChanged(Boolean running) {
557         if (running) {
558             b.transactionListCancelDownload.setEnabled(true);
559             ColorStateList csl = Colors.getColorStateList();
560             b.transactionListProgressBar.setIndeterminateTintList(csl);
561             b.transactionListProgressBar.setProgressTintList(csl);
562             b.transactionListProgressBar.setIndeterminate(true);
563             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
564                 b.transactionListProgressBar.setProgress(0, false);
565             }
566             else {
567                 b.transactionListProgressBar.setProgress(0);
568             }
569             b.transactionProgressLayout.setVisibility(View.VISIBLE);
570         }
571         else {
572             b.transactionProgressLayout.setVisibility(View.GONE);
573         }
574     }
575     public void onRetrieveProgress(RetrieveTransactionsTask.Progress progress) {
576         if (progress.getState() == RetrieveTransactionsTask.ProgressState.FINISHED) {
577             Logger.debug("progress", "Done");
578             b.transactionProgressLayout.setVisibility(View.GONE);
579
580             mainModel.transactionRetrievalDone();
581
582             String error = progress.getError();
583             if (error != null) {
584                 if (error.equals(RetrieveTransactionsTask.Result.ERR_JSON_PARSER_ERROR))
585                     error = getResources().getString(R.string.err_json_parser_error);
586
587                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
588                 builder.setMessage(error);
589                 builder.setPositiveButton(R.string.btn_profile_options, (dialog, which) -> {
590                     Logger.debug("error", "will start profile editor");
591                     MobileLedgerProfile.startEditProfileActivity(this, profile);
592                 });
593                 builder.create()
594                        .show();
595                 return;
596             }
597
598             return;
599         }
600
601
602         b.transactionListCancelDownload.setEnabled(true);
603 //        ColorStateList csl = Colors.getColorStateList();
604 //        progressBar.setIndeterminateTintList(csl);
605 //        progressBar.setProgressTintList(csl);
606 //        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
607 //            progressBar.setProgress(0, false);
608 //        else
609 //            progressBar.setProgress(0);
610         b.transactionProgressLayout.setVisibility(View.VISIBLE);
611
612         if (progress.isIndeterminate() || (progress.getTotal() <= 0)) {
613             b.transactionListProgressBar.setIndeterminate(true);
614             Logger.debug("progress", "indeterminate");
615         }
616         else {
617             if (b.transactionListProgressBar.isIndeterminate()) {
618                 b.transactionListProgressBar.setIndeterminate(false);
619             }
620 //            Logger.debug("progress",
621 //                    String.format(Locale.US, "%d/%d", progress.getProgress(), progress.getTotal
622 //                    ()));
623             b.transactionListProgressBar.setMax(progress.getTotal());
624             // for some reason animation doesn't work - no progress is shown (stick at 0)
625             // on lineageOS 14.1 (Nougat, 7.1.2)
626             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
627                 b.transactionListProgressBar.setProgress(progress.getProgress(), false);
628             else
629                 b.transactionListProgressBar.setProgress(progress.getProgress());
630         }
631     }
632     public void fabShouldShow() {
633         if ((profile != null) && profile.isPostingPermitted() && !b.drawerLayout.isOpen())
634             b.btnAddTransaction.show();
635         else
636             fabHide();
637     }
638     public void fabHide() {
639         b.btnAddTransaction.hide();
640     }
641
642     public static class SectionsPagerAdapter extends FragmentStateAdapter {
643
644         public SectionsPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
645             super(fragmentActivity);
646         }
647         @NotNull
648         @Override
649         public Fragment createFragment(int position) {
650             Logger.debug("main",
651                     String.format(Locale.ENGLISH, "Switching to fragment %d", position));
652             switch (position) {
653                 case 0:
654 //                    debug("flow", "Creating account summary fragment");
655                     return new AccountSummaryFragment();
656                 case 1:
657                     return new TransactionListFragment();
658                 default:
659                     throw new IllegalStateException(
660                             String.format("Unexpected fragment index: " + "%d", position));
661             }
662         }
663
664         @Override
665         public int getItemCount() {
666             return 2;
667         }
668     }
669 }