cochrane343.journal.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for cochrane343.journal.MainActivity.java

Source

/*
 * The MIT License (MIT)
 * 
 * Copyright (c) 2014 by cochrane343
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package cochrane343.journal;

import android.app.AlertDialog;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Toast;
import cochrane343.journal.contentprovider.JournalContract.Expense;
import cochrane343.journal.dialogs.ExpenseDialogFragment;
import cochrane343.journal.dialogs.ExpenseDialogListener;

/**
 * @author cochrane343
 */
public class MainActivity extends ActionBarActivity implements ExpenseEditListener, ExpenseDialogListener {

    private static final String BUNDLE_KEY_MONTHLY_PAGER_ADAPTER_STATE = "monthlyPagerAdapterState";
    private static final String FRAGMENT_TAG_EXPENSE_DIALOG = "expenseDialog";

    /**
     * The view pager used to swipe through months
     */
    private ViewPager viewPager;
    private MonthlyExpensesPagerAdapter monthlyExpensesPagerAdapter;

    /* - - - - - Activity Lifecycle - - - - - - - - - - */

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main_activity);

        monthlyExpensesPagerAdapter = new MonthlyExpensesPagerAdapter(getSupportFragmentManager());

        viewPager = (ViewPager) findViewById(R.id.main_activity_view_pager);
        viewPager.setAdapter(monthlyExpensesPagerAdapter);

        if (savedInstanceState != null) {
            final Parcelable monthlyPagerAdapterState = savedInstanceState
                    .getParcelable(BUNDLE_KEY_MONTHLY_PAGER_ADAPTER_STATE);
            monthlyExpensesPagerAdapter.restoreState(monthlyPagerAdapterState, getClassLoader());
        } else {
            viewPager.setCurrentItem(DateTimeHelper.getMonthsSinceEpoch());
        }
    }

    /**
     * Inflates the menu of this activity and adds action items to the action bar.
     */
    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        final MenuInflater inflater = getMenuInflater();

        inflater.inflate(R.menu.activity_main_actions, menu);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public void onSaveInstanceState(final Bundle savedInstanceState) {
        savedInstanceState.putParcelable(BUNDLE_KEY_MONTHLY_PAGER_ADAPTER_STATE,
                monthlyExpensesPagerAdapter.saveState());

        super.onSaveInstanceState(savedInstanceState);
    }

    /* - - - - - Expense Edit Listener - - - - - - - - - - */

    @Override
    public void onAddExpense(final String description, final long costInCents, final long category) {
        final int selectedMonth = viewPager.getCurrentItem();
        final boolean selectedMonthIsCurrentMonth = selectedMonth == DateTimeHelper.getMonthsSinceEpoch();

        if (selectedMonthIsCurrentMonth) {
            addExpenseToCurrentMonth(description, costInCents, category);
        } else {
            if (shouldShowPastExpenseWarning()) {
                // TODO Consider refactoring into separate method
                final LayoutInflater inflater = LayoutInflater.from(this);
                final View warningLayout = inflater.inflate(R.layout.past_expense_warning, null);
                final CheckBox doNotAskAgainCheckbox = (CheckBox) warningLayout
                        .findViewById(R.id.do_not_show_again);

                final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setView(warningLayout).setTitle(R.string.label_past_expense)
                        .setMessage(R.string.label_past_expense_message)
                        .setPositiveButton(R.string.label_yes_add_to_past, new DialogInterface.OnClickListener() {
                            public void onClick(final DialogInterface dialog, final int which) {
                                if (doNotAskAgainCheckbox.isChecked()) {
                                    setShowPastExpenseWarning(false);
                                }
                                addExpenseToEndOfSelectedMonth(description, costInCents, category);
                            }
                        })
                        .setNegativeButton(R.string.label_no_add_to_current, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                if (doNotAskAgainCheckbox.isChecked()) {
                                    setShowPastExpenseWarning(false);
                                }
                                addExpenseToCurrentMonth(description, costInCents, category);
                            }
                        }).show();
            } else {
                addExpenseToEndOfSelectedMonth(description, costInCents, category);
            }
        }
    }

    /**
     * Adds a new expense with a current timestamp.
     * Used to add expenses to the ongoing month.
     * @since 0.11.0
     */
    private void addExpenseToCurrentMonth(final String description, final long costInCents, final long category) {
        final long currentTimestamp = DateTimeHelper.getNow().getMillis();

        addExpense(description, costInCents, category, currentTimestamp);
    }

    /**
     * Adds a new expense with the end of the currently selected month as timestamp.
     * Used to add expenses to past months.
     * @since 0.11.0
     */
    private void addExpenseToEndOfSelectedMonth(final String description, final long costInCents,
            final long category) {
        final int selectedMonth = viewPager.getCurrentItem();
        final long endOfSelectedMonthTimestamp = DateTimeHelper.getEndOfMonth(selectedMonth).getMillis();

        addExpense(description, costInCents, category, endOfSelectedMonthTimestamp);
    }

    /**
     * @since 0.11.0
     */
    private void addExpense(final String description, final long costInCents, final long category,
            final long timestamp) {
        final ContentValues newExpense = getContentValues(description, costInCents, category);

        newExpense.put(Expense._TIMESTAMP, timestamp);

        getContentResolver().insert(Expense.EXPENSES_URI, newExpense);

        Toast.makeText(this, R.string.toast_added_expense, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpdateExpense(final long expenseId, final String description, final long costInCents,
            final long category) {
        final ContentValues newExpense = getContentValues(description, costInCents, category);

        final Uri uri = ContentUris.withAppendedId(Expense.EXPENSES_URI, expenseId);

        getContentResolver().update(uri, newExpense, null, null);

        Toast.makeText(this, R.string.toast_updated_expense, Toast.LENGTH_SHORT).show();
    }

    private ContentValues getContentValues(final String description, final long costInCents, final long category) {
        final ContentValues newExpense = new ContentValues();

        newExpense.put(Expense._DESCRIPTION, description);
        newExpense.put(Expense._COST, costInCents);
        newExpense.put(Expense._CATEGORY, category);

        return newExpense;
    }

    @Override
    public void onDeleteExpense(final long expenseId) {
        final Uri uri = ContentUris.withAppendedId(Expense.EXPENSES_URI, expenseId);
        getContentResolver().delete(uri, null, null);
    }

    /* - - - - - User Interface Callbacks - - - - - - - - - - */

    /**
     * Handles presses on the action bar items.
     */
    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_add_expense:
            showExpenseDialogForCreate();
            return true;
        case R.id.action_settings:
            startActivity(new Intent(getApplicationContext(), SettingsActivity.class));
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    /**
     * Callback method invoked when the activity has detected the user's press of the
     * back key. Forwards the event to the currently displayed {@link MonthlyExpensesFragment}.
     * Propagates the event further if the fragment does not consume it.
     * Used to allow the user to navigate from single category display back to the
     * category overview.
     */
    @Override
    public void onBackPressed() {
        final MonthlyExpensesFragment currentFragment = (MonthlyExpensesFragment) monthlyExpensesPagerAdapter
                .instantiateItem(viewPager, viewPager.getCurrentItem());
        final boolean backPressConsumed = currentFragment.onBackPressed();

        if (!backPressConsumed) {
            super.onBackPressed();
        }
        ;
    }

    /* - - - - - Expense Dialog - - - - - - - - - - */

    @Override
    public void showExpenseDialogForCreate() {
        final FragmentManager fragmentManager = getSupportFragmentManager();

        final ExpenseDialogFragment expenseDialog = ExpenseDialogFragment.newInstanceForCreate();

        expenseDialog.show(fragmentManager, FRAGMENT_TAG_EXPENSE_DIALOG);
    }

    @Override
    public void showExpenseDialogForEdit(final long expenseId) {
        final FragmentManager fragmentManager = getSupportFragmentManager();

        final ExpenseDialogFragment expenseDialog = ExpenseDialogFragment.newInstanceForEdit(expenseId);

        expenseDialog.show(fragmentManager, FRAGMENT_TAG_EXPENSE_DIALOG);
    }

    /* - - - - - Settings - - - - - - - - - - */

    /**
     * Changes the setting for showing a warning when adding an expense to a past month.
     * @param shouldShowPastExpenseWarning true to enable the warning or false to disable it
     * @since 0.11.0
     */
    private void setShowPastExpenseWarning(final boolean shouldShowPastExpenseWarning) {
        final SharedPreferences defaultPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        final SharedPreferences.Editor editor = defaultPreferences.edit();

        final String preferenceKey = getString(R.string.preference_key_show_past_expense_warning);

        editor.putBoolean(preferenceKey, shouldShowPastExpenseWarning);

        editor.commit();
    }

    /**
     * @return true if showing a warning when adding an expense to a past month is enabled -
     * false if the warning is disabled
     * @since 0.11.0
     */
    private boolean shouldShowPastExpenseWarning() {
        final SharedPreferences defaultPreferences = PreferenceManager.getDefaultSharedPreferences(this);

        final String preferenceKey = getString(R.string.preference_key_show_past_expense_warning);

        final String preferenceDefaultString = getString(R.string.preference_default_show_past_expense_warning);
        final boolean preferenceDefault = Boolean.parseBoolean(preferenceDefaultString);

        return defaultPreferences.getBoolean(preferenceKey, preferenceDefault);
    }

}