net.cactii.mathdoku.ui.ArchiveFragmentActivity.java Source code

Java tutorial

Introduction

Here is the source code for net.cactii.mathdoku.ui.ArchiveFragmentActivity.java

Source

/*
 * Copyright 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.cactii.mathdoku.ui;

import net.cactii.mathdoku.R;
import net.cactii.mathdoku.painter.PagerTabStripPainter;
import net.cactii.mathdoku.painter.Painter;
import net.cactii.mathdoku.storage.database.GridDatabaseAdapter;
import net.cactii.mathdoku.storage.database.GridDatabaseAdapter.SizeFilter;
import net.cactii.mathdoku.storage.database.GridDatabaseAdapter.StatusFilter;
import net.cactii.mathdoku.util.FeedbackEmail;
import net.cactii.mathdoku.util.SharedPuzzle;
import android.app.ActionBar;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v4.app.TaskStackBuilder;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;

public class ArchiveFragmentActivity extends AppFragmentActivity {

    public static final String BUNDLE_KEY_SOLVING_ATTEMPT_ID = "solvingAttemptId";

    /**
     * The {@link android.support.v4.view.PagerAdapter} that will provide
     * fragments representing each object in a collection. We use a
     * {@link android.support.v4.app.FragmentStatePagerAdapter} derivative,
     * which will destroy and re-create fragments as needed, saving and
     * restoring their state in the process. This is important to conserve
     * memory and is a best practice when allowing navigation between objects in
     * a potentially large collection.
     */
    ArchiveFragmentStatePagerAdapter mArchiveFragmentStatePagerAdapter;

    /**
     * The {@link android.support.v4.view.ViewPager} that will display the
     * object collection.
     */
    ViewPager mViewPager;
    ActionBar mActionBar;

    // Should filters be shown?
    private boolean mShowStatusFilter;
    private boolean mShowSizeFilter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.archive_activity_fragment);

        // Create an adapter that when requested, will return a fragment
        // representing an object in the collection.
        // ViewPager and its adapters use support library fragments, so we must
        // use getSupportFragmentManager.
        mArchiveFragmentStatePagerAdapter = new ArchiveFragmentStatePagerAdapter(getSupportFragmentManager(), this);

        // Get preferences for displaying the filter.
        mShowStatusFilter = mMathDokuPreferences.isArchiveStatusFilterVisible();
        mShowSizeFilter = mMathDokuPreferences.isArchiveSizeFilterVisible();
        mArchiveFragmentStatePagerAdapter
                .setStatusFilter(mMathDokuPreferences.getArchiveStatusFilterLastValueUsed());
        mArchiveFragmentStatePagerAdapter.setSizeFilter(mMathDokuPreferences.getArchiveSizeFilterLastValueUsed());

        mActionBar = getActionBar();
        if (mActionBar != null) {
            mActionBar.setDisplayHomeAsUpEnabled(true);
            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
            mActionBar.setTitle(getResources().getString(R.string.archive_action_bar_title));
            mActionBar.setDisplayShowCustomEnabled(true);

            mActionBar.setCustomView(R.layout.archive_action_bar_custom);

            setStatusSpinner();
            setSizeSpinner();
        }

        // Set up the ViewPager, attaching the adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mArchiveFragmentStatePagerAdapter);

        // Set up the pager tab strip
        final PagerTabStrip pagerTabStrip = (PagerTabStrip) findViewById(R.id.pager_tab_strip);
        pagerTabStrip.setDrawFullUnderline(false);

        // This pager contains a maximum of 3 visible items. The selected tab
        // will always be displayed in the middle. Hide the tab indicator by
        // setting color identical to background color.
        PagerTabStripPainter pagerTabStripPainter = Painter.getInstance().getPagerTabStripPainter();
        pagerTabStrip.setTabIndicatorColor(pagerTabStripPainter.getBackgroundColor());
        pagerTabStrip.setBackgroundColor(pagerTabStripPainter.getBackgroundColor());
        pagerTabStrip.setTextColor(pagerTabStripPainter.getTextColor());
        pagerTabStrip.setTextSize(TypedValue.COMPLEX_UNIT_SP,
                getResources().getDimension(net.cactii.mathdoku.R.dimen.text_size_default)
                        / getResources().getDisplayMetrics().density);
        pagerTabStrip.setGravity(Gravity.BOTTOM);

        // Non primary items are semi transparent.
        pagerTabStrip.setNonPrimaryAlpha(0.75f);

        // In case a solving attempt has been specified in the bundle, this
        // solving attempt will be showed as selected grid as long as it does
        // meet the selection criteria of the filters.
        Intent intent = getIntent();
        if (intent != null) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                int solvingAttemptId = bundle.getInt(BUNDLE_KEY_SOLVING_ATTEMPT_ID);
                if (solvingAttemptId >= 0
                        && mArchiveFragmentStatePagerAdapter.getPositionOfGridId(solvingAttemptId) >= 0) {
                    mMathDokuPreferences.setArchiveGridIdLastShowed(solvingAttemptId);
                }
            }
        }
    }

    @Override
    protected void onResumeFragments() {
        // Check for changes in visibility of status spinner. Reset the filters
        // for which the visibility changes.
        boolean showStatusFilterNew = mMathDokuPreferences.isArchiveStatusFilterVisible();
        boolean setSpinners = false;
        if (mShowStatusFilter != showStatusFilterNew) {
            mShowStatusFilter = showStatusFilterNew;
            mArchiveFragmentStatePagerAdapter.setStatusFilter(StatusFilter.ALL);
            setSpinners = true;
        }
        boolean showSizeFilterNew = mMathDokuPreferences.isArchiveSizeFilterVisible();
        if (mShowSizeFilter != showSizeFilterNew) {
            mShowSizeFilter = showSizeFilterNew;
            mArchiveFragmentStatePagerAdapter.setSizeFilter(SizeFilter.ALL);
            setSpinners = true;
        }

        // After all filters have been set to possible new values, the spinners
        // can set.
        if (setSpinners) {
            setStatusSpinner();
            setSizeSpinner();
        }

        // Select the same grid which was selected before. If not possible,
        // the last page will be shown.
        selectGridId(mMathDokuPreferences.getArchiveGridIdLastShowed());

        super.onResumeFragments();
    }

    @Override
    protected void onPause() {
        // Save preferences
        mMathDokuPreferences
                .setArchiveStatusFilterLastValueUsed(mArchiveFragmentStatePagerAdapter.getStatusFilter());
        mMathDokuPreferences.setArchiveSizeFilterLastValueUsed(mArchiveFragmentStatePagerAdapter.getSizeFilter());
        mMathDokuPreferences.setArchiveGridIdLastShowed(getCurrentSelectedGridId());

        super.onPause();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.archive_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            // This is called when the Home (Up) button is pressed in the action
            // bar. Create a simple intent that starts the hierarchical parent
            // activity and use NavUtils in the Support Package to ensure proper
            // handling of Up.
            Intent upIntent = new Intent(this, PuzzleFragmentActivity.class);
            if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                // This activity is not part of the application's task, so
                // create a new task with a synthesized back stack.
                // If there are ancestor activities, they should be added here.
                TaskStackBuilder.create(this).addNextIntent(upIntent).startActivities();
                finish();
            } else {
                // This activity is part of the application's task, so simply
                // navigate up to the hierarchical parent activity.
                NavUtils.navigateUpTo(this, upIntent);
            }
            return true;
        case R.id.action_share:
            new SharedPuzzle(this).addStatisticsChartsAsAttachments(this.getWindow().getDecorView())
                    .share(getSolvingAttemptIdForCurrentSelectedGrid());
            return true;
        case R.id.action_settings:
            startActivity(new Intent(this, ArchivePreferenceActivity.class));
            return true;
        case R.id.action_send_feedback:
            new FeedbackEmail(this).show();
            return true;
        case R.id.action_help:
            openHelpDialog();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * Initializes/refreshes the status spinner.
     * 
     * Returns: True in case the status spinner should be shown. False
     * otherwise.
     */
    protected void setStatusSpinner() {
        Spinner spinner = (Spinner) mActionBar.getCustomView().findViewById(R.id.spinner_status);
        if (!mShowStatusFilter || mArchiveFragmentStatePagerAdapter.getCount() == 0) {
            spinner.setVisibility(View.GONE);
            return;
        }

        // Determine which statuses are actually used for the currently
        // selected size filter.
        GridDatabaseAdapter gridDatabaseAdapter = new GridDatabaseAdapter();
        final StatusFilter[] usedStatuses = gridDatabaseAdapter
                .getUsedStatuses(mArchiveFragmentStatePagerAdapter.getSizeFilter());

        // Load the list of descriptions for statuses actually used into the
        // array adapter.
        String[] usedStatusesDescription = new String[usedStatuses.length];
        for (int i = 0; i < usedStatuses.length; i++) {
            usedStatusesDescription[i] = getResources()
                    .getStringArray(R.array.archive_status_filter)[usedStatuses[i].ordinal()];
        }
        ArrayAdapter<String> adapterStatus = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
                usedStatusesDescription);
        adapterStatus.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        // Build the spinner
        spinner.setAdapter(adapterStatus);

        // Restore selected status
        StatusFilter selectedStatusFilter = mArchiveFragmentStatePagerAdapter.getStatusFilter();
        for (int i = 0; i < usedStatuses.length; i++) {
            if (usedStatuses[i] == selectedStatusFilter) {
                spinner.setSelection(i);
                break;
            }
        }

        // Hide spinner if only two choices are available. As one of those
        // choices is always "ALL" the choices will result in an identical
        // selection.
        spinner.setVisibility((usedStatuses.length <= 2 ? View.GONE : View.VISIBLE));

        spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                // Get the selected status
                StatusFilter statusFilter = usedStatuses[(int) id];

                // Check if value for status spinner has changed.
                if (statusFilter != mArchiveFragmentStatePagerAdapter.getStatusFilter()) {
                    // Remember currently displayed grid id.
                    int gridId = getCurrentSelectedGridId();

                    // Refresh pager adapter with new status.
                    mArchiveFragmentStatePagerAdapter.setStatusFilter(statusFilter);

                    // Refresh the size spinner as the content of the spinners
                    // are related.
                    setSizeSpinner();

                    // If possible select the grid id which was selected before
                    // changing the spinner(s). Otherwise select last page.
                    selectGridId(gridId);
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
                // Do nothing
            }
        });
    }

    /**
     * Initializes/refreshes the sizes spinner.
     * 
     * Returns: True in case the sizes spinner should be shown. False otherwise.
     */
    protected void setSizeSpinner() {
        Spinner spinner = (Spinner) mActionBar.getCustomView().findViewById(R.id.spinner_size);
        if (!mShowSizeFilter || mArchiveFragmentStatePagerAdapter.getCount() == 0) {
            spinner.setVisibility(View.GONE);
            return;
        }

        // Determine which sizes are actually used for the currently
        // selected status filter.
        GridDatabaseAdapter gridDatabaseAdapter = new GridDatabaseAdapter();
        final SizeFilter[] usedSizes = gridDatabaseAdapter
                .getUsedSizes(mArchiveFragmentStatePagerAdapter.getStatusFilter());

        // Load the list of descriptions for sizes actually used into the
        // array adapter.
        String[] usedSizesDescription = new String[usedSizes.length];
        for (int i = 0; i < usedSizes.length; i++) {
            usedSizesDescription[i] = getResources().getStringArray(R.array.archive_size_filter)[usedSizes[i]
                    .ordinal()];
        }
        ArrayAdapter<String> adapterStatus = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
                usedSizesDescription);
        adapterStatus.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        // Build the spinner
        spinner.setAdapter(adapterStatus);

        // Restore selected size
        SizeFilter selectedSizeFilter = mArchiveFragmentStatePagerAdapter.getSizeFilter();
        for (int i = 0; i < usedSizes.length; i++) {
            if (usedSizes[i] == selectedSizeFilter) {
                spinner.setSelection(i);
                break;
            }
        }

        // Hide spinner if only two choices are available. As one of those
        // choices is always "ALL" the choices will result in an identical
        // selection.
        spinner.setVisibility((usedSizes.length <= 2 ? View.GONE : View.VISIBLE));

        spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                // Remember currently displayed grid id.
                int gridId = getCurrentSelectedGridId();

                // Get the selected status
                SizeFilter sizeFilter = usedSizes[(int) id];

                // Check if value for status spinner has changed.
                if (sizeFilter != mArchiveFragmentStatePagerAdapter.getSizeFilter()) {
                    // Refresh pager adapter with new status.
                    mArchiveFragmentStatePagerAdapter.setSizeFilter(sizeFilter);

                    // Refresh the status spinner as the content of the spinners
                    // are related.
                    setStatusSpinner();

                    // If possible select the grid id which was selected before
                    // changing the spinner(s). Otherwise select last page.
                    selectGridId(gridId);
                }

            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
                // Do nothing
            }
        });
    }

    /**
     * Displays the help dialog for the archive activity.
     */
    private void openHelpDialog() {
        // Get view and put relevant information into the view.
        LayoutInflater li = LayoutInflater.from(this);
        View view = li.inflate(R.layout.archive_help_dialog, null);

        new AlertDialog.Builder(this)
                .setTitle(getResources().getString(R.string.action_archive) + " "
                        + getResources().getString(R.string.action_help))
                .setIcon(R.drawable.icon).setView(view)
                .setNegativeButton(R.string.dialog_general_button_close, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int whichButton) {
                    }
                }).show();
    }

    /**
     * Get the grid id which is currently displayed in the archive.
     * 
     * @return The grid id which is currently displayed in the archive.
     */
    private int getCurrentSelectedGridId() {
        if (mArchiveFragmentStatePagerAdapter != null && mViewPager != null) {
            return mArchiveFragmentStatePagerAdapter.getGridId(mViewPager.getCurrentItem());
        } else {
            return -1;
        }
    }

    /**
     * Get the solving attempt id of the grid which is currently displayed in
     * the archive.
     * 
     * @return The solving attempt id of the grid which is currently displayed
     *         in the archive.
     */
    private int getSolvingAttemptIdForCurrentSelectedGrid() {
        if (mArchiveFragmentStatePagerAdapter != null && mViewPager != null) {
            return mArchiveFragmentStatePagerAdapter.getSolvingAttemptId(mViewPager.getCurrentItem());
        } else {
            return -1;
        }
    }

    /**
     * Select the page with the given grid id. In case the specified grid id was
     * not found, the last page is selected.
     * 
     * @param gridId
     *            The grid id for which the corresponding page in the archive
     *            has to be selected.
     * @return True in case the grid id has been found and is selected. False
     *         otherwise.
     */
    private boolean selectGridId(int gridId) {
        // Get the position of the grid in the adapter.
        int position = mArchiveFragmentStatePagerAdapter.getPositionOfGridId(gridId);

        // In case the grid id is found in the adapter it is selected.
        if (position >= 0) {
            mViewPager.setCurrentItem(position);
            return true;
        } else {
            // Show last page
            mViewPager.setCurrentItem(mArchiveFragmentStatePagerAdapter.getCount() - 1);
            return false;
        }
    }

    /**
     * Reload the game currently displayed in the archive.
     * 
     * @param view
     */
    public void onClickReloadGame(View view) {
        Intent intent = new Intent();
        intent.putExtra(BUNDLE_KEY_SOLVING_ATTEMPT_ID, getSolvingAttemptIdForCurrentSelectedGrid());
        setResult(RESULT_OK, intent);

        // Finish the archive activity
        finish();
    }

    public int getViewPagerCurrentPosition() {
        return (mViewPager == null ? -1 : mViewPager.getCurrentItem());
    }
}