package de.danoeh.antennapod.activity; import android.annotation.TargetApi; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.database.DataSetObserver; import android.os.Build; import android.os.Bundle; import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.google.android.material.snackbar.Snackbar; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.drawerlayout.widget.DrawerLayout; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.Toolbar; import android.util.Log; import android.util.TypedValue; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast; import com.bumptech.glide.Glide; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.Validate; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.NavListAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.event.MessageEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.Flavors; import de.danoeh.antennapod.core.util.IntentUtils; import de.danoeh.antennapod.core.util.StorageUtils; import de.danoeh.antennapod.dialog.RatingDialog; import de.danoeh.antennapod.dialog.RenameFeedDialog; import de.danoeh.antennapod.fragment.AddFeedFragment; import de.danoeh.antennapod.fragment.DownloadsFragment; import de.danoeh.antennapod.fragment.EpisodesFragment; import de.danoeh.antennapod.fragment.ExternalPlayerFragment; import de.danoeh.antennapod.fragment.FeedItemlistFragment; import de.danoeh.antennapod.fragment.PlaybackHistoryFragment; import de.danoeh.antennapod.fragment.QueueFragment; import de.danoeh.antennapod.fragment.SubscriptionFragment; import de.danoeh.antennapod.fragment.TransitionEffect; import de.danoeh.antennapod.menuhandler.NavDrawerActivity; import de.danoeh.antennapod.preferences.PreferenceUpgrader; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; /** * The activity that is shown when the user launches the app. */ public class MainActivity extends CastEnabledActivity implements NavDrawerActivity { private static final String TAG = "MainActivity"; private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE | EventDistributor.UNREAD_ITEMS_UPDATE; public static final String PREF_NAME = "MainActivityPrefs"; public static final String PREF_IS_FIRST_LAUNCH = "prefMainActivityIsFirstLaunch"; public static final String PREF_LAST_FRAGMENT_TAG = "prefMainActivityLastFragmentTag"; public static final String EXTRA_NAV_TYPE = "nav_type"; public static final String EXTRA_NAV_INDEX = "nav_index"; public static final String EXTRA_FRAGMENT_TAG = "fragment_tag"; public static final String EXTRA_FRAGMENT_ARGS = "fragment_args"; private static final String EXTRA_FEED_ID = "fragment_feed_id"; private static final String SAVE_BACKSTACK_COUNT = "backstackCount"; private static final String SAVE_TITLE = "title"; public static final String[] NAV_DRAWER_TAGS = { QueueFragment.TAG, EpisodesFragment.TAG, SubscriptionFragment.TAG, DownloadsFragment.TAG, PlaybackHistoryFragment.TAG, AddFeedFragment.TAG, NavListAdapter.SUBSCRIPTION_LIST_TAG }; private Toolbar toolbar; private ExternalPlayerFragment externalPlayerFragment; private DrawerLayout drawerLayout; private View navDrawer; private ListView navList; private NavListAdapter navAdapter; private int mPosition = -1; private ActionBarDrawerToggle drawerToggle; private CharSequence currentTitle; private ProgressDialog pd; private Disposable disposable; private long lastBackButtonPressTime = 0; @NonNull public static Intent getIntentToOpenFeed(@NonNull Context context, long feedId) { Intent intent = new Intent(context.getApplicationContext(), MainActivity.class); intent.putExtra(MainActivity.EXTRA_FEED_ID, feedId); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); return intent; } @Override public void onCreate(Bundle savedInstanceState) { setTheme(UserPreferences.getNoTitleTheme()); super.onCreate(savedInstanceState); StorageUtils.checkStorageAvailability(this); setContentView(R.layout.main); toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { findViewById(R.id.shadow).setVisibility(View.GONE); int elevation = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics()); getSupportActionBar().setElevation(elevation); } currentTitle = getTitle(); drawerLayout = findViewById(R.id.drawer_layout); navList = findViewById(R.id.nav_list); navDrawer = findViewById(R.id.nav_layout); drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close); if (savedInstanceState != null) { int backstackCount = savedInstanceState.getInt(SAVE_BACKSTACK_COUNT, 0); drawerToggle.setDrawerIndicatorEnabled(backstackCount == 0); } drawerLayout.setDrawerListener(drawerToggle); final FragmentManager fm = getSupportFragmentManager(); fm.addOnBackStackChangedListener(() -> drawerToggle.setDrawerIndicatorEnabled(fm.getBackStackEntryCount() == 0)); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); navAdapter = new NavListAdapter(itemAccess, this); navList.setAdapter(navAdapter); navList.setOnItemClickListener(navListClickListener); navList.setOnItemLongClickListener(newListLongClickListener); registerForContextMenu(navList); navAdapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { selectedNavListIndex = getSelectedNavListIndex(); } }); findViewById(R.id.nav_settings).setOnClickListener(v -> { drawerLayout.closeDrawer(navDrawer); startActivity(new Intent(MainActivity.this, PreferenceActivity.class)); }); FragmentTransaction transaction = fm.beginTransaction(); Fragment mainFragment = fm.findFragmentByTag("main"); if (mainFragment != null) { transaction.replace(R.id.main_view, mainFragment); } else { String lastFragment = getLastNavFragment(); if (ArrayUtils.contains(NAV_DRAWER_TAGS, lastFragment)) { loadFragment(lastFragment, null); } else { try { loadFeedFragmentById(Integer.parseInt(lastFragment), null); } catch (NumberFormatException e) { // it's not a number, this happens if we removed // a label from the NAV_DRAWER_TAGS // give them a nice default... loadFragment(QueueFragment.TAG, null); } } } externalPlayerFragment = new ExternalPlayerFragment(); transaction.replace(R.id.playerFragment, externalPlayerFragment, ExternalPlayerFragment.TAG); transaction.commit(); checkFirstLaunch(); PreferenceUpgrader.checkUpgrades(this); } private void saveLastNavFragment(String tag) { Log.d(TAG, "saveLastNavFragment(tag: " + tag +")"); SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE); SharedPreferences.Editor edit = prefs.edit(); if(tag != null) { edit.putString(PREF_LAST_FRAGMENT_TAG, tag); } else { edit.remove(PREF_LAST_FRAGMENT_TAG); } edit.apply(); } private String getLastNavFragment() { SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE); String lastFragment = prefs.getString(PREF_LAST_FRAGMENT_TAG, QueueFragment.TAG); Log.d(TAG, "getLastNavFragment() -> " + lastFragment); return lastFragment; } private void checkFirstLaunch() { SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE); if (prefs.getBoolean(PREF_IS_FIRST_LAUNCH, true)) { loadFragment(AddFeedFragment.TAG, null); new Handler().postDelayed(() -> drawerLayout.openDrawer(navDrawer), 1500); // for backward compatibility, we only change defaults for fresh installs UserPreferences.setUpdateInterval(12); SharedPreferences.Editor edit = prefs.edit(); edit.putBoolean(PREF_IS_FIRST_LAUNCH, false); edit.apply(); } } private void showDrawerPreferencesDialog() { final List hiddenDrawerItems = UserPreferences.getHiddenDrawerItems(); String[] navLabels = new String[NAV_DRAWER_TAGS.length]; final boolean[] checked = new boolean[NAV_DRAWER_TAGS.length]; for (int i = 0; i < NAV_DRAWER_TAGS.length; i++) { String tag = NAV_DRAWER_TAGS[i]; navLabels[i] = navAdapter.getLabel(tag); if (!hiddenDrawerItems.contains(tag)) { checked[i] = true; } } AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setTitle(R.string.drawer_preferences); builder.setMultiChoiceItems(navLabels, checked, (dialog, which, isChecked) -> { if (isChecked) { hiddenDrawerItems.remove(NAV_DRAWER_TAGS[which]); } else { hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]); } }); builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> UserPreferences.setHiddenDrawerItems(hiddenDrawerItems)); builder.setNegativeButton(R.string.cancel_label, null); builder.create().show(); } public boolean isDrawerOpen() { return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer); } public List getFeeds() { return (navDrawerData != null) ? navDrawerData.feeds : null; } private void loadFragment(int index, Bundle args) { Log.d(TAG, "loadFragment(index: " + index + ", args: " + args + ")"); if (index < navAdapter.getSubscriptionOffset()) { String tag = navAdapter.getTags().get(index); loadFragment(tag, args); } else { int pos = index - navAdapter.getSubscriptionOffset(); loadFeedFragmentByPosition(pos, args); } } public void loadFragment(String tag, Bundle args) { Log.d(TAG, "loadFragment(tag: " + tag + ", args: " + args + ")"); Fragment fragment = null; switch (tag) { case QueueFragment.TAG: fragment = new QueueFragment(); break; case EpisodesFragment.TAG: fragment = new EpisodesFragment(); break; case DownloadsFragment.TAG: fragment = new DownloadsFragment(); break; case PlaybackHistoryFragment.TAG: fragment = new PlaybackHistoryFragment(); break; case AddFeedFragment.TAG: fragment = new AddFeedFragment(); break; case SubscriptionFragment.TAG: SubscriptionFragment subscriptionFragment = new SubscriptionFragment(); fragment = subscriptionFragment; break; default: // default to the queue tag = QueueFragment.TAG; fragment = new QueueFragment(); args = null; break; } currentTitle = navAdapter.getLabel(tag); getSupportActionBar().setTitle(currentTitle); saveLastNavFragment(tag); if (args != null) { fragment.setArguments(args); } loadFragment(fragment); } private void loadFeedFragmentByPosition(int relPos, Bundle args) { if(relPos < 0) { return; } Feed feed = itemAccess.getItem(relPos); loadFeedFragmentById(feed.getId(), args); } public void loadFeedFragmentById(long feedId, Bundle args) { Fragment fragment = FeedItemlistFragment.newInstance(feedId); if(args != null) { fragment.setArguments(args); } saveLastNavFragment(String.valueOf(feedId)); currentTitle = ""; getSupportActionBar().setTitle(currentTitle); loadFragment(fragment); } private void loadFragment(Fragment fragment) { FragmentManager fragmentManager = getSupportFragmentManager(); // clear back stack for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) { fragmentManager.popBackStack(); } FragmentTransaction t = fragmentManager.beginTransaction(); t.replace(R.id.main_view, fragment, "main"); fragmentManager.popBackStack(); // TODO: we have to allow state loss here // since this function can get called from an AsyncTask which // could be finishing after our app has already committed state // and is about to get shutdown. What we *should* do is // not commit anything in an AsyncTask, but that's a bigger // change than we want now. t.commitAllowingStateLoss(); if (navAdapter != null) { navAdapter.notifyDataSetChanged(); } } public void loadChildFragment(Fragment fragment, TransitionEffect transition) { Validate.notNull(fragment); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); switch (transition) { case FADE: transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out); break; case FLIP: transaction.setCustomAnimations( R.anim.card_flip_left_in, R.anim.card_flip_left_out, R.anim.card_flip_right_in, R.anim.card_flip_right_out); break; } transaction .hide(getSupportFragmentManager().findFragmentByTag("main")) .add(R.id.main_view, fragment, "main") .addToBackStack(null) .commit(); } public void loadChildFragment(Fragment fragment) { loadChildFragment(fragment, TransitionEffect.NONE); } public void dismissChildFragment() { getSupportFragmentManager().popBackStack(); } private int getSelectedNavListIndex() { String currentFragment = getLastNavFragment(); if(currentFragment == null) { // should not happen, but better safe than sorry return -1; } int tagIndex = navAdapter.getTags().indexOf(currentFragment); if(tagIndex >= 0) { return tagIndex; } else if(ArrayUtils.contains(NAV_DRAWER_TAGS, currentFragment)) { // the fragment was just hidden return -1; } else { // last fragment was not a list, but a feed long feedId = Long.parseLong(currentFragment); if (navDrawerData != null) { List feeds = navDrawerData.feeds; for (int i = 0; i < feeds.size(); i++) { if (feeds.get(i).getId() == feedId) { return i + navAdapter.getSubscriptionOffset(); } } } return -1; } } private final AdapterView.OnItemClickListener navListClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { int viewType = parent.getAdapter().getItemViewType(position); if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER && position != selectedNavListIndex) { loadFragment(position, null); } drawerLayout.closeDrawer(navDrawer); } }; private final AdapterView.OnItemLongClickListener newListLongClickListener = new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { if(position < navAdapter.getTags().size()) { showDrawerPreferencesDialog(); return true; } else { mPosition = position; return false; } } }; @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); drawerToggle.syncState(); if (savedInstanceState != null) { currentTitle = savedInstanceState.getString(SAVE_TITLE); if (!drawerLayout.isDrawerOpen(navDrawer)) { getSupportActionBar().setTitle(currentTitle); } selectedNavListIndex = getSelectedNavListIndex(); } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); drawerToggle.onConfigurationChanged(newConfig); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(SAVE_TITLE, getSupportActionBar().getTitle().toString()); outState.putInt(SAVE_BACKSTACK_COUNT, getSupportFragmentManager().getBackStackEntryCount()); } @Override public void onStart() { super.onStart(); EventDistributor.getInstance().register(contentUpdate); EventBus.getDefault().register(this); RatingDialog.init(this); } @Override protected void onPause() { super.onPause(); } @Override protected void onResume() { super.onResume(); StorageUtils.checkStorageAvailability(this); Intent intent = getIntent(); if (intent.hasExtra(EXTRA_FEED_ID) || (navDrawerData != null && intent.hasExtra(EXTRA_NAV_TYPE) && (intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)))) { handleNavIntent(); } loadData(); RatingDialog.check(); } @Override protected void onStop() { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); EventBus.getDefault().unregister(this); if (disposable != null) { disposable.dispose(); } if(pd != null) { pd.dismiss(); } } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void onTrimMemory(int level) { super.onTrimMemory(level); Glide.get(this).trimMemory(level); } @Override public void onLowMemory() { super.onLowMemory(); Glide.get(this).clearMemory(); } @Override public boolean onCreateOptionsMenu(Menu menu) { boolean retVal = super.onCreateOptionsMenu(menu); if (Flavors.FLAVOR == Flavors.PLAY) { switch (getLastNavFragment()) { case QueueFragment.TAG: case EpisodesFragment.TAG: requestCastButton(MenuItem.SHOW_AS_ACTION_IF_ROOM); return retVal; case DownloadsFragment.TAG: case PlaybackHistoryFragment.TAG: case AddFeedFragment.TAG: case SubscriptionFragment.TAG: return retVal; default: requestCastButton(MenuItem.SHOW_AS_ACTION_NEVER); return retVal; } } else { return retVal; } } @Override public boolean onOptionsItemSelected(MenuItem item) { if (drawerToggle.onOptionsItemSelected(item)) { return true; } else if (item.getItemId() == android.R.id.home) { if (getSupportFragmentManager().getBackStackEntryCount() > 0) { dismissChildFragment(); } return true; } else { return super.onOptionsItemSelected(item); } } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); if(v.getId() != R.id.nav_list) { return; } AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo; int position = adapterInfo.position; if(position < navAdapter.getSubscriptionOffset()) { return; } MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.nav_feed_context, menu); Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset()); menu.setHeaderTitle(feed.getTitle()); // episodes are not loaded, so we cannot check if the podcast has new or unplayed ones! } @Override public boolean onContextItemSelected(MenuItem item) { final int position = mPosition; mPosition = -1; // reset if(position < 0) { return false; } Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset()); switch(item.getItemId()) { case R.id.remove_all_new_flags_item: ConfirmationDialog removeAllNewFlagsConfirmationDialog = new ConfirmationDialog(this, R.string.remove_all_new_flags_label, R.string.remove_all_new_flags_confirmation_msg) { @Override public void onConfirmButtonPressed(DialogInterface dialog) { dialog.dismiss(); DBWriter.removeFeedNewFlag(feed.getId()); } }; removeAllNewFlagsConfirmationDialog.createNewDialog().show(); return true; case R.id.mark_all_read_item: ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(this, R.string.mark_all_read_label, R.string.mark_all_read_confirmation_msg) { @Override public void onConfirmButtonPressed(DialogInterface dialog) { dialog.dismiss(); DBWriter.markFeedRead(feed.getId()); } }; markAllReadConfirmationDialog.createNewDialog().show(); return true; case R.id.rename_item: new RenameFeedDialog(this, feed).show(); return true; case R.id.remove_item: final FeedRemover remover = new FeedRemover(this, feed) { @Override protected void onPostExecute(Void result) { super.onPostExecute(result); if(getSelectedNavListIndex() == position) { loadFragment(EpisodesFragment.TAG, null); } } }; ConfirmationDialog conDialog = new ConfirmationDialog(this, R.string.remove_feed_label, getString(R.string.feed_delete_confirmation_msg, feed.getTitle())) { @Override public void onConfirmButtonPressed( DialogInterface dialog) { dialog.dismiss(); long mediaId = PlaybackPreferences.getCurrentlyPlayingFeedMediaId(); if (mediaId > 0 && FeedItemUtil.indexOfItemWithMediaId(feed.getItems(), mediaId) >= 0) { Log.d(TAG, "Currently playing episode is about to be deleted, skipping"); remover.skipOnCompletion = true; int playerStatus = PlaybackPreferences.getCurrentPlayerStatus(); if(playerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) { IntentUtils.sendLocalBroadcast(MainActivity.this, PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE); } } remover.executeAsync(); } }; conDialog.createNewDialog().show(); return true; default: return super.onContextItemSelected(item); } } @Override public void onBackPressed() { if (isDrawerOpen()) { drawerLayout.closeDrawer(navDrawer); } else if (getSupportFragmentManager().getBackStackEntryCount() != 0) { super.onBackPressed(); } else { switch (UserPreferences.getBackButtonBehavior()) { case OPEN_DRAWER: drawerLayout.openDrawer(navDrawer); break; case SHOW_PROMPT: new AlertDialog.Builder(this) .setMessage(R.string.close_prompt) .setPositiveButton(R.string.yes, (dialogInterface, i) -> MainActivity.super.onBackPressed()) .setNegativeButton(R.string.no, null) .setCancelable(false) .show(); break; case DOUBLE_TAP: if (lastBackButtonPressTime < System.currentTimeMillis() - 2000) { Toast.makeText(this, R.string.double_tap_toast, Toast.LENGTH_SHORT).show(); lastBackButtonPressTime = System.currentTimeMillis(); } else { super.onBackPressed(); } break; case GO_TO_PAGE: if (getLastNavFragment().equals(UserPreferences.getBackButtonGoToPage())) { super.onBackPressed(); } else { loadFragment(UserPreferences.getBackButtonGoToPage(), null); } break; default: super.onBackPressed(); } } } private DBReader.NavDrawerData navDrawerData; private int selectedNavListIndex = 0; private final NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() { @Override public int getCount() { if (navDrawerData != null) { return navDrawerData.feeds.size(); } else { return 0; } } @Override public Feed getItem(int position) { if (navDrawerData != null && 0 <= position && position < navDrawerData.feeds.size()) { return navDrawerData.feeds.get(position); } else { return null; } } @Override public int getSelectedItemIndex() { return selectedNavListIndex; } @Override public int getQueueSize() { return (navDrawerData != null) ? navDrawerData.queueSize : 0; } @Override public int getNumberOfNewItems() { return (navDrawerData != null) ? navDrawerData.numNewItems : 0; } @Override public int getNumberOfDownloadedItems() { return (navDrawerData != null) ? navDrawerData.numDownloadedItems : 0; } @Override public int getReclaimableItems() { return (navDrawerData != null) ? navDrawerData.reclaimableSpace : 0; } @Override public int getFeedCounter(long feedId) { return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0; } @Override public int getFeedCounterSum() { if(navDrawerData == null) { return 0; } int sum = 0; for(int counter : navDrawerData.feedCounters.values()) { sum += counter; } return sum; } }; private void loadData() { disposable = Observable.fromCallable(DBReader::getNavDrawerData) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { boolean handleIntent = (navDrawerData == null); navDrawerData = result; navAdapter.notifyDataSetChanged(); if (handleIntent) { handleNavIntent(); } }, error -> Log.e(TAG, Log.getStackTraceString(error))); } @Subscribe public void onEvent(QueueEvent event) { Log.d(TAG, "onEvent(" + event + ")"); // we are only interested in the number of queue items, not download status or position if(event.action == QueueEvent.Action.DELETED_MEDIA || event.action == QueueEvent.Action.SORTED || event.action == QueueEvent.Action.MOVED) { return; } loadData(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(MessageEvent event) { Log.d(TAG, "onEvent(" + event + ")"); View parentLayout = findViewById(R.id.drawer_layout); Snackbar snackbar = Snackbar.make(parentLayout, event.message, Snackbar.LENGTH_SHORT); if(event.action != null) { snackbar.setAction(getString(R.string.undo), v -> event.action.run()); } snackbar.show(); } private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((EVENTS & arg) != 0) { Log.d(TAG, "Received contentUpdate Intent."); loadData(); } } }; private void handleNavIntent() { Log.d(TAG, "handleNavIntent()"); Intent intent = getIntent(); if (intent.hasExtra(EXTRA_FEED_ID) || (intent.hasExtra(EXTRA_NAV_TYPE) && (intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)))) { int index = intent.getIntExtra(EXTRA_NAV_INDEX, -1); String tag = intent.getStringExtra(EXTRA_FRAGMENT_TAG); Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS); long feedId = intent.getLongExtra(EXTRA_FEED_ID, 0); if (index >= 0) { loadFragment(index, args); } else if (tag != null) { loadFragment(tag, args); } else if(feedId > 0) { loadFeedFragmentById(feedId, args); } } setIntent(new Intent(MainActivity.this, MainActivity.class)); // to avoid handling the intent twice when the configuration changes } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); } @VisibleForTesting public void updateNavDrawer() { navAdapter.notifyDataSetChanged(); } }