X-Git-Url: https://git.ktnx.net/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fnet%2Fktnx%2Fmobileledger%2Fui%2Factivity%2FMainActivity.java;h=9cb68cb85a49d146a37e538bfa0fc5cb171edfe5;hb=acb9f133463139427f8a295cad1fdb391b03acda;hp=9082695fc4973d0adabd0ac38272ec83c381240d;hpb=2d85826653a8ba3e619afc83c5c91216a7fdb0b6;p=mobile-ledger.git 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 index 9082695f..9cb68cb8 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java @@ -18,7 +18,6 @@ package net.ktnx.mobileledger.ui.activity; import android.content.Intent; -import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; @@ -27,6 +26,7 @@ import android.graphics.Color; import android.graphics.drawable.Icon; import android.os.Build; import android.os.Bundle; +import android.text.format.DateUtils; import android.util.Log; import android.view.View; import android.view.animation.AnimationUtils; @@ -36,16 +36,17 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.Toolbar; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; +import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.adapter.FragmentStateAdapter; +import androidx.viewpager2.widget.ViewPager2; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; @@ -69,6 +70,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.Objects; /* * TODO: reports @@ -78,12 +80,11 @@ public class MainActivity extends ProfileThemedActivity { public static final String STATE_CURRENT_PAGE = "current_page"; public static final String BUNDLE_SAVED_STATE = "bundle_savedState"; public static final String STATE_ACC_FILTER = "account_filter"; - private static final String PREF_THEME_ID = "themeId"; DrawerLayout drawer; private View profileListHeadMore, profileListHeadCancel, profileListHeadAddProfile; private View bTransactionListCancelDownload; private SectionsPagerAdapter mSectionsPagerAdapter; - private ViewPager mViewPager; + private ViewPager2 mViewPager; private FloatingActionButton fab; private ProfilesRecyclerViewAdapter mProfileListAdapter; private int mCurrentPage; @@ -91,7 +92,7 @@ public class MainActivity extends ProfileThemedActivity { private Toolbar mToolbar; private DrawerLayout.SimpleDrawerListener drawerListener; private ActionBarDrawerToggle barDrawerToggle; - private ViewPager.SimpleOnPageChangeListener pageChangeListener; + private ViewPager2.OnPageChangeCallback pageChangeCallback; private MobileLedgerProfile profile; private MainModel mainModel; @Override @@ -124,19 +125,15 @@ public class MainActivity extends ProfileThemedActivity { drawer.removeDrawerListener(barDrawerToggle); barDrawerToggle = null; if (mViewPager != null) - mViewPager.removeOnPageChangeListener(pageChangeListener); - pageChangeListener = null; + mViewPager.unregisterOnPageChangeCallback(pageChangeCallback); + pageChangeCallback = null; super.onDestroy(); } @Override protected void setupProfileColors() { - SharedPreferences prefs = getPreferences(MODE_PRIVATE); - int profileColor = prefs.getInt(PREF_THEME_ID, -2); - if (profileColor == -2) - profileColor = Data.retrieveCurrentThemeIdFromDb(); + final int profileColor = Data.retrieveCurrentThemeIdFromDb(); Colors.setupTheme(this, profileColor); Colors.profileThemeId = profileColor; - storeThemeIdInPrefs(profileColor); } @Override protected void onResume() { @@ -160,7 +157,7 @@ public class MainActivity extends ProfileThemedActivity { profileListHeadAddProfile = findViewById(R.id.nav_new_profile_button); drawer = findViewById(R.id.drawer_layout); bTransactionListCancelDownload = findViewById(R.id.transaction_list_cancel_download); - mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); + mSectionsPagerAdapter = new SectionsPagerAdapter(this); mViewPager = findViewById(R.id.root_frame); Bundle extra = getIntent().getBundleExtra(BUNDLE_SAVED_STATE); @@ -200,8 +197,8 @@ public class MainActivity extends ProfileThemedActivity { mViewPager.setAdapter(mSectionsPagerAdapter); - if (pageChangeListener == null) { - pageChangeListener = new ViewPager.SimpleOnPageChangeListener() { + if (pageChangeCallback == null) { + pageChangeCallback = new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { mCurrentPage = position; @@ -220,7 +217,7 @@ public class MainActivity extends ProfileThemedActivity { super.onPageSelected(position); } }; - mViewPager.addOnPageChangeListener(pageChangeListener); + mViewPager.registerOnPageChangeCallback(pageChangeCallback); } mCurrentPage = 0; @@ -241,6 +238,9 @@ public class MainActivity extends ProfileThemedActivity { findViewById(R.id.nav_new_profile_button).setOnClickListener( v -> startEditProfileActivity(null)); + findViewById(R.id.transaction_list_cancel_download).setOnClickListener( + this::onStopTransactionRefreshClick); + RecyclerView root = findViewById(R.id.nav_profile_list); if (root == null) throw new RuntimeException("Can't get hold on the transaction value view"); @@ -331,6 +331,10 @@ public class MainActivity extends ProfileThemedActivity { .show(); mainModel.clearUpdateError(); }); + Data.locale.observe(this, l -> refreshLastUpdateInfo()); + Data.lastUpdateDate.observe(this, date -> refreshLastUpdateInfo()); + Data.lastUpdateTransactionCount.observe(this, date -> refreshLastUpdateInfo()); + Data.lastUpdateAccountCount.observe(this, date -> refreshLastUpdateInfo()); } private void scheduleDataRetrievalIfStale(long lastUpdate) { long now = new Date().getTime(); @@ -433,6 +437,7 @@ public class MainActivity extends ProfileThemedActivity { mProfileListAdapter.notifyDataSetChanged(); + mainModel.clearAccounts(); mainModel.clearTransactions(); if (haveProfile) { @@ -457,22 +462,15 @@ public class MainActivity extends ProfileThemedActivity { updateLastUpdateTextFromDB(); } private void profileThemeChanged() { - storeThemeIdInPrefs(profile.getThemeHue()); - // un-hook all observed LiveData Data.removeProfileObservers(this); Data.profiles.removeObservers(this); - Data.lastUpdateLiveData.removeObservers(this); + Data.lastUpdateTransactionCount.removeObservers(this); + Data.lastUpdateAccountCount.removeObservers(this); + Data.lastUpdateDate.removeObservers(this); recreate(); } - private void storeThemeIdInPrefs(int themeId) { - // store the new theme id in the preferences - SharedPreferences prefs = getPreferences(MODE_PRIVATE); - SharedPreferences.Editor e = prefs.edit(); - e.putInt(PREF_THEME_ID, themeId); - e.apply(); - } public void startEditProfileActivity(MobileLedgerProfile profile) { Intent intent = new Intent(this, ProfileDetailActivity.class); Bundle args = new Bundle(); @@ -554,26 +552,40 @@ public class MainActivity extends ProfileThemedActivity { Logger.debug("transactions", String.format(Locale.ENGLISH, "Last update = %d", lastUpdate)); if (lastUpdate == 0) { - Data.lastUpdateLiveData.postValue(null); + Data.lastUpdateDate.postValue(null); } else { - Data.lastUpdateLiveData.postValue(new Date(lastUpdate)); + Data.lastUpdateDate.postValue(new Date(lastUpdate)); } - // this is unfortunate, but it appears we need a two-stage rocket to make - // a value reach a recycler view item holder. first stage is a regular - // LiveData that can be observed by an activity (this). - // the second stage forwards the changes, in the UI thread, to the - // observable value, observed by the view holders. - // view holders can't observe the LiveData because they don't have - // access to lifecycle owners. oh, also the value is updated by a thread - // so it must be tunnelled by an activity for it to reach the view - // holders in the UI thread - Data.lastUpdateLiveData.observe(this, date -> runOnUiThread( - () -> Data.lastUpdate.set((date == null) ? 0 : date.getTime()))); scheduleDataRetrievalIfStale(lastUpdate); } + private void refreshLastUpdateInfo() { + final int formatFlags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR | + DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_NUMERIC_DATE; + String templateForTransactions = + getResources().getString(R.string.transaction_count_summary); + String templateForAccounts = getResources().getString(R.string.account_count_summary); + Integer accountCount = Data.lastUpdateAccountCount.getValue(); + Integer transactionCount = Data.lastUpdateTransactionCount.getValue(); + Date lastUpdate = Data.lastUpdateDate.getValue(); + if (lastUpdate == null) { + Data.lastTransactionsUpdateText.set("----"); + Data.lastAccountsUpdateText.set("----"); + } + else { + Data.lastTransactionsUpdateText.set( + String.format(Objects.requireNonNull(Data.locale.getValue()), + templateForTransactions, + transactionCount == null ? 0 : transactionCount, + DateUtils.formatDateTime(this, lastUpdate.getTime(), formatFlags))); + Data.lastAccountsUpdateText.set( + String.format(Objects.requireNonNull(Data.locale.getValue()), + templateForAccounts, accountCount == null ? 0 : accountCount, + DateUtils.formatDateTime(this, lastUpdate.getTime(), formatFlags))); + } + } public void onStopTransactionRefreshClick(View view) { Logger.debug("interactive", "Cancelling transactions refresh"); mainModel.stopTransactionsRetrieval(); @@ -609,9 +621,19 @@ public class MainActivity extends ProfileThemedActivity { mainModel.transactionRetrievalDone(); - if (progress.getError() != null) { - Snackbar.make(mViewPager, progress.getError(), Snackbar.LENGTH_LONG) - .show(); + String error = progress.getError(); + if (error != null) { + if (error.equals(RetrieveTransactionsTask.Result.ERR_JSON_PARSER_ERROR)) + error = getResources().getString(R.string.err_json_parser_error); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(error); + builder.setPositiveButton(R.string.btn_profile_options, (dialog, which) -> { + Logger.debug("error", "will start profile editor"); + startEditProfileActivity(profile); + }); + builder.create() + .show(); return; } @@ -659,15 +681,14 @@ public class MainActivity extends ProfileThemedActivity { fab.hide(); } - public static class SectionsPagerAdapter extends FragmentPagerAdapter { + public static class SectionsPagerAdapter extends FragmentStateAdapter { - SectionsPagerAdapter(FragmentManager fm) { - super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + public SectionsPagerAdapter(@NonNull FragmentActivity fragmentActivity) { + super(fragmentActivity); } - @NotNull @Override - public Fragment getItem(int position) { + public Fragment createFragment(int position) { Logger.debug("main", String.format(Locale.ENGLISH, "Switching to fragment %d", position)); switch (position) { @@ -683,7 +704,7 @@ public class MainActivity extends ProfileThemedActivity { } @Override - public int getCount() { + public int getItemCount() { return 2; } }