package com.aricneto.twistytimer.fragment; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.graphics.PorterDuff; import android.os.Bundle; import android.preference.PreferenceManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.aricneto.twistytimer.fragment.dialog.CategorySelectDialog; import com.aricneto.twistytimer.fragment.dialog.BottomSheetTrainerDialog; import com.aricneto.twistytimer.fragment.dialog.PuzzleSelectDialog; import com.aricneto.twistytimer.listener.DialogListenerMessage; import com.aricneto.twistytimer.puzzle.TrainerScrambler; import com.aricneto.twistytimer.utils.Prefs; import com.aricneto.twistytimer.utils.ThemeUtils; import com.google.android.material.tabs.TabLayout; import androidx.appcompat.content.res.AppCompatResources; import androidx.cardview.widget.CardView; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; import androidx.viewpager.widget.ViewPager; import android.util.Log; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.aricneto.twistify.R; import com.aricneto.twistytimer.TwistyTimer; import com.aricneto.twistytimer.activity.MainActivity; import com.aricneto.twistytimer.layout.LockedViewPager; import com.aricneto.twistytimer.listener.OnBackPressedInFragmentListener; import com.aricneto.twistytimer.stats.Statistics; import com.aricneto.twistytimer.stats.StatisticsCache; import com.aricneto.twistytimer.stats.StatisticsLoader; import com.aricneto.twistytimer.utils.PuzzleUtils; import com.aricneto.twistytimer.utils.Wrapper; import com.github.ksoichiro.android.observablescrollview.CacheFragmentStatePagerAdapter; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import static com.aricneto.twistytimer.fragment.TimerFragment.TIMER_MODE_TIMER; import static com.aricneto.twistytimer.fragment.TimerFragment.TIMER_MODE_TRAINER; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_CHANGED_CATEGORY; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_CHANGED_THEME; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_DELETE_SELECTED_TIMES; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_GENERATE_SCRAMBLE; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_HISTORY_TIMES_SHOWN; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_SCROLLED_PAGE; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_SELECTION_MODE_OFF; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_SELECTION_MODE_ON; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_SESSION_TIMES_SHOWN; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_TIMER_STARTED; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_TIMER_STOPPED; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_TIME_SELECTED; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_TIME_UNSELECTED; import static com.aricneto.twistytimer.utils.TTIntent.ACTION_TOOLBAR_RESTORED; import static com.aricneto.twistytimer.utils.TTIntent.CATEGORY_TIME_DATA_CHANGES; import static com.aricneto.twistytimer.utils.TTIntent.CATEGORY_UI_INTERACTIONS; import static com.aricneto.twistytimer.utils.TTIntent.TTFragmentBroadcastReceiver; import static com.aricneto.twistytimer.utils.TTIntent.broadcast; import static com.aricneto.twistytimer.utils.TTIntent.registerReceiver; import static com.aricneto.twistytimer.utils.TTIntent.unregisterReceiver; public class TimerFragmentMain extends BaseFragment implements OnBackPressedInFragmentListener, DialogListenerMessage { /** * Flag to enable debug logging for this class. */ private static final boolean DEBUG_ME = true; /** * A "tag" to identify this class in log messages. */ private static final String TAG = TimerFragmentMain.class.getSimpleName(); /** * The zero-based position of the timer fragment/tab/page. */ public static final int TIMER_PAGE = 0; /** * The zero-based position of the timer list fragment/tab/page. */ public static final int LIST_PAGE = 1; /** * The zero-based position of the timer graph fragment/tab/page. */ public static final int GRAPH_PAGE = 2; /** * The total number of pages. */ private static final int NUM_PAGES = 3; private static final String PUZZLE = "puzzle"; private static final String PUZZLE_SUBTYPE = "puzzle_type"; private static final String TIMER_MODE = "timer_mode"; private static final String TRAINER_SUBSET = "trainer_subset"; private static final String TAG_CATEGORY_DIALOG = "select_category_dialog"; private static final String TAG_PUZZLE_DIALOG = "puzzle_spinner_dialog_fragment"; private Unbinder mUnbinder; @BindView(R.id.root) RelativeLayout rootLayout; @BindView(R.id.toolbar) CardView mToolbar; @BindView(R.id.pager) LockedViewPager viewPager; @BindView(R.id.main_tabs) TabLayout tabLayout; @BindView(R.id.tab_view) View tabView; @BindView(R.id.puzzleSpinner)View puzzleSpinnerLayout; @BindView(R.id.nav_button_settings) View navButtonSettings; @BindView(R.id.nav_button_category) View navButtonCategory; @BindView(R.id.nav_button_history) ImageView navButtonHistory; @BindView(R.id.puzzleCategory) TextView puzzleCategoryText; @BindView(R.id.puzzleName) TextView puzzleNameText; ActionMode actionMode; private LinearLayout tabStrip; private NavigationAdapter viewPagerAdapter; // Stores the current puzzle being timed/shown private String currentPuzzle; private String currentPuzzleCategory; private TrainerScrambler.TrainerSubset currentPuzzleSubset; private String currentTimerMode; // Stores the current state of the list switch boolean history = false; int currentPage = TIMER_PAGE; private boolean pagerEnabled; private int selectCount = 0; private CategorySelectDialog categoryDialog; private View.OnClickListener clickListener = new View.OnClickListener() { @Override public void onClick(View view) { switch (view.getId()) { case R.id.nav_button_category: categoryDialog = CategorySelectDialog.newInstance(currentPuzzle, currentPuzzleCategory, currentTimerMode, currentPuzzleSubset); categoryDialog.setDialogListener(categoryDialogListener); categoryDialog.show(mFragmentManager, TAG_CATEGORY_DIALOG); break; case R.id.nav_button_history: history = !history; updateHistorySwitchItem(); broadcast(CATEGORY_TIME_DATA_CHANGES, history ? ACTION_HISTORY_TIMES_SHOWN : ACTION_SESSION_TIMES_SHOWN); break; case R.id.nav_button_settings: getMainActivity().openDrawer(); break; } } }; private DialogListenerMessage categoryDialogListener = new DialogListenerMessage() { @Override public void onUpdateDialog(String text) { currentPuzzleCategory = text; broadcast(CATEGORY_UI_INTERACTIONS, ACTION_CHANGED_CATEGORY); } }; private ActionMode.Callback actionModeCallback = new ActionMode.Callback() { // Called when the action mode is created; startActionMode() was called @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Inflate a menu resource providing context menu items MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.menu_list_callback, menu); return true; } // Called each time the action mode is shown. Always called after onCreateActionMode, but // may be called multiple times if the mode is invalidated. @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //getActivity().getWindow().setStatusBarColor(ThemeUtils.fetchAttrColor(mContext, R.attr.colorPrimaryDark)); //} return true; // Return false if nothing is done } // Called when the user selects a contextual menu item @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.delete: // Receiver will delete times and then broadcast "ACTION_TIMES_MODIFIED". broadcast(CATEGORY_UI_INTERACTIONS, ACTION_DELETE_SELECTED_TIMES); mode.finish(); return true; default: return false; } } // Called when the user exits the action mode @Override public void onDestroyActionMode(ActionMode mode) { } }; // Receives broadcasts about changes to the time user interface. private TTFragmentBroadcastReceiver mUIInteractionReceiver = new TTFragmentBroadcastReceiver(this, CATEGORY_UI_INTERACTIONS) { @Override public void onReceiveWhileAdded(Context context, Intent intent) { switch (intent.getAction()) { case ACTION_CHANGED_THEME: try { // If the theme has been changed, then the activity will need to be recreated. The // theme can only be applied properly during the inflation of the layouts, so it has // to go back to "Activity.updateLocale()" to do that. ((MainActivity) getActivity()).onRecreateRequired(); } catch (Exception e) {} break; case ACTION_TIMER_STARTED: getMainActivity().setDrawerLock(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); viewPager.setPagingEnabled(false); activateTabLayout(false); mToolbar.animate() .translationY(-mToolbar.getHeight()) .alpha(0) .setDuration(mAnimationDuration); tabView.animate() .translationY(tabView.getHeight()) .alpha(0) .setDuration(mAnimationDuration); break; case ACTION_TIMER_STOPPED: getMainActivity().setDrawerLock(DrawerLayout.LOCK_MODE_UNDEFINED); mToolbar.animate() .translationY(0) .alpha(1) .setDuration(mAnimationDuration); tabView.animate() .translationY(0) .alpha(1) .setDuration(mAnimationDuration) .withEndAction(() -> broadcast(CATEGORY_UI_INTERACTIONS, ACTION_TOOLBAR_RESTORED)); activateTabLayout(true); if (pagerEnabled) viewPager.setPagingEnabled(true); else viewPager.setPagingEnabled(false); break; case ACTION_SELECTION_MODE_ON: selectCount = 0; actionMode = mToolbar.startActionMode(actionModeCallback); break; case ACTION_SELECTION_MODE_OFF: selectCount = 0; if (actionMode != null) actionMode.finish(); break; case ACTION_TIME_SELECTED: selectCount += 1; actionMode.setTitle(getResources().getQuantityString(R.plurals.selected_list, selectCount, selectCount)); break; case ACTION_TIME_UNSELECTED: selectCount -= 1; actionMode.setTitle(getResources().getQuantityString(R.plurals.selected_list, selectCount, selectCount)); break; case ACTION_CHANGED_CATEGORY: viewPager.setAdapter(viewPagerAdapter); viewPager.setCurrentItem(currentPage); updatePuzzleSpinnerHeader(); handleStatisticsLoader(); if (currentTimerMode.equals(TIMER_MODE_TRAINER)) broadcast(CATEGORY_UI_INTERACTIONS, ACTION_GENERATE_SCRAMBLE); break; } } }; private Context mContext; private FragmentManager mFragmentManager; private int mAnimationDuration; @SuppressLint("StringFormatInvalid") private void updatePuzzleSpinnerHeader() { history = false; updateHistorySwitchItem(); puzzleCategoryText.setText(currentPuzzleCategory.toLowerCase()); if (currentTimerMode.equals(TIMER_MODE_TRAINER)) puzzleNameText.setText(getString(R.string.title_trainer, currentPuzzleSubset.name())); else puzzleNameText.setText(PuzzleUtils.getPuzzleNameFromType(currentPuzzle)); } public TimerFragmentMain() { // Required empty public constructor } public static TimerFragmentMain newInstance(String puzzle, String category, String mode, TrainerScrambler.TrainerSubset subset) { final TimerFragmentMain fragment = new TimerFragmentMain(); Bundle args = new Bundle(); args.putString(PUZZLE, puzzle); args.putString(PUZZLE_SUBTYPE, category); args.putString(TIMER_MODE, mode); args.putSerializable(TRAINER_SUBSET, subset); fragment.setArguments(args); if (DEBUG_ME) Log.d(TAG, "newInstance() -> " + fragment); return fragment; } @Override public void onSaveInstanceState(Bundle outState) { if (DEBUG_ME) Log.d(TAG, "onSaveInstanceState()"); super.onSaveInstanceState(outState); outState.putString("puzzle", currentPuzzle); outState.putString("subtype", currentPuzzleCategory); outState.putSerializable("subset", currentPuzzleSubset); outState.putString("mode", currentTimerMode); outState.putBoolean("history", history); } @Override public void onCreate(Bundle savedInstanceState) { if (DEBUG_ME) Log.d(TAG, "updateLocale(savedInstanceState=" + savedInstanceState + ")"); super.onCreate(savedInstanceState); mContext = getContext(); mFragmentManager = getFragmentManager(); // Retrieve arguments if (getArguments() != null) { currentPuzzle = getArguments().getString(PUZZLE); currentPuzzleCategory = getArguments().getString(PUZZLE_SUBTYPE); currentTimerMode = getArguments().getString(TIMER_MODE); currentPuzzleSubset = (TrainerScrambler.TrainerSubset) getArguments().getSerializable(TRAINER_SUBSET); } // Retrieve instance state if (savedInstanceState != null) { currentPuzzle = savedInstanceState.getString("puzzle"); currentPuzzleCategory = savedInstanceState.getString("subtype"); currentTimerMode = savedInstanceState.getString("mode", TimerFragment.TIMER_MODE_TIMER); currentPuzzleSubset = (TrainerScrambler.TrainerSubset) savedInstanceState.getSerializable("subset"); history = savedInstanceState.getBoolean("history"); // Set the dialog listeners again, in case the dialogs are open. categoryDialog = (CategorySelectDialog) mFragmentManager .findFragmentByTag(TAG_CATEGORY_DIALOG); if (categoryDialog != null) categoryDialog.setDialogListener(categoryDialogListener); PuzzleSelectDialog selectDialog = (PuzzleSelectDialog) mFragmentManager .findFragmentByTag(TAG_PUZZLE_DIALOG); if (selectDialog != null) selectDialog.setDialogListener(this); } mAnimationDuration = Prefs.getInt(R.string.pk_timer_animation_duration, mContext.getResources().getInteger(R.integer.defaultAnimationDuration)); } @Override public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (DEBUG_ME) Log.d(TAG, "onCreateView(savedInstanceState=" + savedInstanceState + ")"); View root = inflater.inflate(R.layout.fragment_timer_main, container, false); mUnbinder = ButterKnife.bind(this, root); return root; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // setup background gradient rootLayout.setBackground(ThemeUtils.fetchBackgroundGradient(mContext, ThemeUtils.getPreferredTheme())); navButtonCategory.setOnClickListener(clickListener); navButtonHistory.setOnClickListener(clickListener); navButtonSettings.setOnClickListener(clickListener); if (savedInstanceState == null) { // Remember last used puzzle currentPuzzle = Prefs.getString(R.string.pk_last_used_puzzle, PuzzleUtils.TYPE_333); updateCurrentCategory(); } pagerEnabled = PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean( getString(R.string.pk_tab_swiping_enabled), true); viewPager.setPagingEnabled(pagerEnabled); // Menu bar background if (Prefs.getBoolean(R.string.pk_menu_background, false)) { mToolbar.setCardBackgroundColor(Color.TRANSPARENT); mToolbar.setCardElevation(0); } viewPagerAdapter = new NavigationAdapter(getChildFragmentManager()); viewPager.setAdapter(viewPagerAdapter); viewPager.setOffscreenPageLimit(NUM_PAGES - 1); tabLayout.setupWithViewPager(viewPager); tabLayout.setSelectedTabIndicator(0); tabLayout.setTabIconTint(AppCompatResources.getColorStateList(mContext, R.color.tab_color)); tabStrip = ((LinearLayout) tabLayout.getChildAt(0)); tabLayout.getBackground().setColorFilter(ThemeUtils.fetchAttrColor(mContext, R.attr.colorTabBar), PorterDuff.Mode.SRC_IN); // Handle spinner AFTER reading from savedInstanceState, so we can correctly // fill the category field in the spinner handleHeaderSpinner(); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { setupPage(position); currentPage = position; } @Override public void onPageScrollStateChanged(int state) { broadcast(CATEGORY_UI_INTERACTIONS, ACTION_SCROLLED_PAGE); } }); // Register a receiver to update if something has changed registerReceiver(mUIInteractionReceiver); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); handleStatisticsLoader(); } private void handleStatisticsLoader() { // The "StatisticsLoader" is managed from this fragment, as it has the necessary access to // the puzzle type, subtype and history values. // // "restartLoader" ensures that any old loader with the wrong puzzle type/subtype will not // be reused. For now, those arguments are just passed via their respective fields to // "onCreateLoader". if (DEBUG_ME) Log.d(TAG, "Puzzle and subtype: " + currentPuzzle + " // " + currentPuzzleCategory); if (DEBUG_ME) Log.d(TAG, "onActivityCreated -> restartLoader: STATISTICS_LOADER_ID"); getLoaderManager().restartLoader(MainActivity.STATISTICS_LOADER_ID, null, new LoaderManager.LoaderCallbacks<Wrapper<Statistics>>() { @Override public Loader<Wrapper<Statistics>> onCreateLoader(int id, Bundle args) { if (DEBUG_ME) Log.d(TAG, "onCreateLoader: STATISTICS_LOADER_ID"); return new StatisticsLoader(mContext, Statistics.newAllTimeStatistics(), currentPuzzle, currentPuzzleCategory); } @Override public void onLoadFinished(Loader<Wrapper<Statistics>> loader, Wrapper<Statistics> data) { if (DEBUG_ME) Log.d(TAG, "onLoadFinished: STATISTICS_LOADER_ID"); // Other fragments can get the statistics from the cache when they are // created and can register themselves as observers of further updates. StatisticsCache.getInstance().updateAndNotify(data.content()); } @Override public void onLoaderReset(Loader<Wrapper<Statistics>> loader) { if (DEBUG_ME) Log.d(TAG, "onLoaderReset: STATISTICS_LOADER_ID"); // Clear the cache and notify all observers that the statistics are "null". StatisticsCache.getInstance().updateAndNotify(null); } }); } private void activateTabLayout(boolean b) { tabStrip.setEnabled(b); for (int i = 0; i < tabStrip.getChildCount(); i++) { tabStrip.getChildAt(i).setClickable(b); } } @Override public void onResume() { if (DEBUG_ME) Log.d(TAG, "onResume() : currentPage=" + currentPage); // Sets up the toolbar with the icons appropriate to the current page. mToolbar.post(() -> setupPage(currentPage)); super.onResume(); } /** * Passes on the "Back" button press event to subordinate fragments and indicates if any * fragment consumed the event. * * @return {@code true} if the "Back" button press was consumed and no further action should be * taken; or {@code false} if the "Back" button press was ignored and the caller should * propagate it to the next interested party. */ @Override public boolean onBackPressedInFragment() { if (DEBUG_ME) Log.d(TAG, "onBackPressedInFragment()"); return viewPagerAdapter != null && viewPagerAdapter.dispatchOnBackPressedInFragment(); } @Override public void onDetach() { if (DEBUG_ME) Log.d(TAG, "onDetach()"); super.onDetach(); unregisterReceiver(mUIInteractionReceiver); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } private void updateHistorySwitchItem() { if (history) { navButtonHistory.setImageResource(R.drawable.ic_history_on); navButtonHistory.animate() .rotation(-135) .setInterpolator(new AccelerateDecelerateInterpolator()) .setDuration(300) .start(); } else { navButtonHistory.setImageResource(R.drawable.ic_history_off); navButtonHistory.animate() .rotation(0) .setInterpolator(new AccelerateDecelerateInterpolator()) .setDuration(300) .start(); } } /** * Sets the page's toolbar buttons and other things * * @param pageNum */ private void setupPage(int pageNum) { if (DEBUG_ME) Log.d(TAG, "setupPage(pageNum=" + pageNum + ")"); if (actionMode != null) actionMode.finish(); if (mToolbar == null) { return; } switch (pageNum) { case TIMER_PAGE: if (navButtonHistory != null) { navButtonHistory.animate() .withStartAction(() -> navButtonHistory.setEnabled(false)) .alpha(0) .setDuration(200) .withEndAction(() -> { // navButtonHistory may already be destroyed by the time we get // to the end action, so we have to check if it still exists if (navButtonHistory != null) navButtonHistory.setVisibility(View.GONE); }) .start(); } break; case LIST_PAGE: case GRAPH_PAGE: if (navButtonHistory != null) { navButtonHistory.setVisibility(View.VISIBLE); navButtonHistory.animate() .withStartAction(() -> navButtonHistory.setEnabled(true)) .alpha(1) .setDuration(200) .start(); } break; } } /** * The app saves the last subtype used for each puzzle. This function is called to both update * the last subtype when it's changed, and to set the subtipe. */ private void updateCurrentCategory() { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(TwistyTimer.getAppContext()); SharedPreferences.Editor editor = sharedPreferences.edit(); final List<String> subtypeList = TwistyTimer.getDBHandler().getAllSubtypesFromType(currentPuzzle); if (subtypeList.size() == 0) { currentPuzzleCategory = "Normal"; editor.putString(getString(R.string.pk_last_used_category) + currentPuzzle, "Normal"); editor.apply(); } else { currentPuzzleCategory = sharedPreferences.getString(getString(R.string.pk_last_used_category) + currentPuzzle, "Normal"); } } private void handleHeaderSpinner() { // Setup action bar click listener puzzleSpinnerLayout.setOnClickListener(v -> { if (currentTimerMode.equals(TimerFragment.TIMER_MODE_TRAINER)) { BottomSheetTrainerDialog bottomSheetTrainerDialog = BottomSheetTrainerDialog.newInstance(currentPuzzleSubset, currentPuzzleCategory); bottomSheetTrainerDialog.show(mFragmentManager, "trainer_dialog_fragment"); } else { // Setup spinner dialog and adapter PuzzleSelectDialog puzzleSelectDialog = PuzzleSelectDialog.newInstance(); puzzleSelectDialog.setDialogListener(this); puzzleSelectDialog.show(mFragmentManager, TAG_PUZZLE_DIALOG); } }); updatePuzzleSpinnerHeader(); } // A new puzzle has been selected @Override public void onUpdateDialog(String text) { currentPuzzle = text; Prefs.edit().putString(R.string.pk_last_used_puzzle, currentPuzzle).apply(); updateCurrentCategory(); viewPager.setAdapter(viewPagerAdapter); viewPager.setCurrentItem(currentPage); PuzzleSelectDialog selectDialog = (PuzzleSelectDialog) mFragmentManager.findFragmentByTag(TAG_PUZZLE_DIALOG); if (selectDialog != null) selectDialog.dismiss(); //// update titles updatePuzzleSpinnerHeader(); handleStatisticsLoader(); } protected class NavigationAdapter extends CacheFragmentStatePagerAdapter { public NavigationAdapter(FragmentManager fm) { super(fm); } @Override protected Fragment createItem(int position) { if (DEBUG_ME) Log.d(TAG, "NavigationAdapter.createItem(" + position + ")"); switch (position) { case TIMER_PAGE: return TimerFragment.newInstance( currentPuzzle, currentPuzzleCategory, currentTimerMode, currentPuzzleSubset); case LIST_PAGE: return TimerListFragment.newInstance( currentPuzzle, currentPuzzleCategory, history); case GRAPH_PAGE: return TimerGraphFragment.newInstance( currentPuzzle, currentPuzzleCategory, history); } return TimerFragment.newInstance(PuzzleUtils.TYPE_333, "Normal", TIMER_MODE_TIMER, TrainerScrambler.TrainerSubset.OLL); } /** * Notifies each fragment (that is listening) that the "Back" button has been pressed. * Stops when the first fragment consumes the event. * * @return {@code true} if any fragment consumed the "Back" button press event; or {@code false} * if the event was not consumed by any fragment. */ public boolean dispatchOnBackPressedInFragment() { if (DEBUG_ME) Log.d(TAG, "NavigationAdapter.dispatchOnBackPressedInFragment()"); boolean isConsumed = false; for (int p = 0; p < NUM_PAGES && !isConsumed; p++) { final Fragment fragment = getItemAt(p); if (fragment instanceof OnBackPressedInFragmentListener) { // => not null isConsumed = ((OnBackPressedInFragmentListener) fragment) .onBackPressedInFragment(); } } return isConsumed; } @Override public int getCount() { return NUM_PAGES; } } }