net.czlee.debatekeeper.PrepTimeBellsEditActivity.java Source code

Java tutorial

Introduction

Here is the source code for net.czlee.debatekeeper.PrepTimeBellsEditActivity.java

Source

/*
 * Copyright (C) 2013 Chuan-Zheng Lee
 *
 * This file is part of the Debatekeeper app, which is licensed under the
 * GNU General Public Licence version 3 (GPLv3).  You can redistribute
 * and/or modify it under the terms of the GPLv3, and you must not use
 * this file except in compliance with the GPLv3.
 *
 * This app is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public Licence for more details.
 *
 * You should have received a copy of the GNU General Public Licence
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package net.czlee.debatekeeper;

import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.text.Editable;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TimePicker;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Locale;

/**
 * This activity allows the user to edit the preparation time bells.
 *
 * The activity does all its editing through an instance of {@link PrepTimeBellsManager}.
 * The implementation for loading and saving the edits to the {@link SharedPreferences} is
 * left to the {@link PrepTimeBellsManager}.
 *
 * @author Chuan-Zheng Lee
 * @since  2013-02-02
 *
 */
public class PrepTimeBellsEditActivity extends FragmentActivity {

    private PrepTimeBellsManager mPtbm;

    private static final String DIALOG_TAG_ADD_BELL = "add";
    private static final String DIALOG_TAG_CLEAR_ALL_BELLS = "clr";
    private static final String DIALOG_TAG_EDIT_BELL = "edit";

    private static final String KEY_INDEX = "index";

    // These must match the strings in R.string.AddPrepTimeBellTypes (in prep_time_bells_edit.xml)
    private static final int ADD_PREP_TIME_BELL_TYPE_START = 0;
    private static final int ADD_PREP_TIME_BELL_TYPE_FINISH = 1;
    private static final int ADD_PREP_TIME_BELL_TYPE_PERCENTAGE = 2;

    //******************************************************************************************
    // Public classes
    //******************************************************************************************

    public static class DialogAddOrEditBellFragment extends DialogFragment {

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);

        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            Dialog dialog = getAddOrEditBellDialog();
            return dialog;
        }

        private Dialog getAddOrEditBellDialog() {
            final PrepTimeBellsEditActivity activity = (PrepTimeBellsEditActivity) getActivity();

            AlertDialog.Builder builder = new AlertDialog.Builder(activity);

            View content = activity.getLayoutInflater().inflate(R.layout.add_prep_time_bell, null);

            // Take note of the form elements
            final Spinner typeSpinner = (Spinner) content.findViewById(R.id.addPrepTimeBellDialog_typeSpinner);
            final TimePicker timePicker = (TimePicker) content.findViewById(R.id.addPrepTimeBellDialog_timePicker);
            final EditText editText = (EditText) content.findViewById(R.id.addPrepTimeBellDialog_editText);

            // Format the form elements
            timePicker.setIs24HourView(true);
            ArrayAdapter<CharSequence> typesAdapter = ArrayAdapter.createFromResource(activity,
                    R.array.prepTimeBellsEditor_editBellDialog_types, android.R.layout.simple_spinner_item);
            typesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            typeSpinner.setAdapter(typesAdapter);

            typeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                    // Show either the EditText or TimePicker, whichever is appropriate
                    if (pos == ADD_PREP_TIME_BELL_TYPE_PERCENTAGE) { // This is "percentage through prep time"
                        editText.setVisibility(View.VISIBLE);
                        timePicker.setVisibility(View.GONE);
                    } else {
                        editText.setVisibility(View.GONE);
                        timePicker.setVisibility(View.VISIBLE);
                    }
                }

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

            String title, confirmButtonText;
            DialogInterface.OnClickListener confirmOnClickListener;

            // Prepare the dialog fields
            if (getTag() == DIALOG_TAG_ADD_BELL) {

                prepareAddBellDialogView(content);

                title = getString(R.string.prepTimeBellsEditor_addBellDialog_title);
                confirmButtonText = getString(R.string.prepTimeBellsEditor_addBellDialog_confirmButton);
                confirmOnClickListener = activity.getAddBellDialogOnClickListener();

            } else if (getTag() == DIALOG_TAG_EDIT_BELL) {

                prepareEditBellDialogView(content);
                int index = getArguments().getInt(KEY_INDEX);

                title = getString(R.string.prepTimeBellsEditor_editBellDialog_title,
                        activity.mPtbm.getBellDescription(index));
                confirmButtonText = getString(R.string.prepTimeBellsEditor_editBellDialog_confirmButton);
                confirmOnClickListener = activity.getEditBellDialogOnClickListener(index);

            } else {

                Log.e("DialogAddOrEditBellFrag", "Unrecognised tag: " + getTag());

                title = getString(R.string.prepTimeBellsEditor_addBellDialog_title);
                confirmButtonText = getString(R.string.prepTimeBellsEditor_addBellDialog_confirmButton);
                confirmOnClickListener = new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                };
            }

            // When the text field gains focus, select all
            builder.setTitle(title).setView(content).setCancelable(true)
                    .setPositiveButton(confirmButtonText, confirmOnClickListener)
                    .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();
                        }
                    });

            return builder.create();
        }

        private void prepareAddBellDialogView(View view) {
            final TimePicker timePicker = (TimePicker) view.findViewById(R.id.addPrepTimeBellDialog_timePicker);
            final EditText editText = (EditText) view.findViewById(R.id.addPrepTimeBellDialog_editText);

            // Defaults
            timePicker.setCurrentHour(5);
            timePicker.setCurrentMinute(0);
            editText.setText("50");

        }

        /**
         * @param view the {@link View} to be prepared
         */
        private void prepareEditBellDialogView(View view) {
            final Bundle args = getArguments();

            final Spinner typeSpinner = (Spinner) view.findViewById(R.id.addPrepTimeBellDialog_typeSpinner);
            final TimePicker timePicker = (TimePicker) view.findViewById(R.id.addPrepTimeBellDialog_timePicker);
            final EditText editText = (EditText) view.findViewById(R.id.addPrepTimeBellDialog_editText);

            // Defaults
            timePicker.setCurrentHour(5);
            timePicker.setCurrentMinute(0);
            editText.setText("50");

            // Populate the fields with the current values
            String type = args.getString(PrepTimeBellsManager.KEY_TYPE);
            if (type == PrepTimeBellsManager.VALUE_TYPE_START) {
                typeSpinner.setSelection(ADD_PREP_TIME_BELL_TYPE_START);
                long time = args.getLong(PrepTimeBellsManager.KEY_TIME);
                timePicker.setCurrentHour((int) (time / 60));
                timePicker.setCurrentMinute((int) (time % 60));
            } else if (type == PrepTimeBellsManager.VALUE_TYPE_FINISH) {
                typeSpinner.setSelection(ADD_PREP_TIME_BELL_TYPE_FINISH);
                long time = args.getLong(PrepTimeBellsManager.KEY_TIME);
                timePicker.setCurrentHour((int) (time / 60));
                timePicker.setCurrentMinute((int) (time % 60));
            } else if (type == PrepTimeBellsManager.VALUE_TYPE_PROPORTIONAL) {
                typeSpinner.setSelection(ADD_PREP_TIME_BELL_TYPE_PERCENTAGE);
                double proportion = args.getDouble(PrepTimeBellsManager.KEY_PROPORTION);
                editText.setText(String.valueOf(proportion * 100));
            }

        }

    }

    public static class DialogClearBellsFragment extends DialogFragment {

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {

            final PrepTimeBellsEditActivity activity = (PrepTimeBellsEditActivity) getActivity();
            AlertDialog.Builder builder = new AlertDialog.Builder(activity);

            builder.setTitle(R.string.prepTimeBellsEditor_clearAllDialog_title).setMessage("").setCancelable(true)
                    .setPositiveButton(R.string.prepTimeBellsEditor_clearAllDialog_confirmButton,
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    boolean spareFinish = activity.mPtbm.hasBellsOtherThanFinish();
                                    activity.mPtbm.deleteAllBells(spareFinish);
                                    activity.refreshBellsList();
                                }
                            })
                    .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();
                        }
                    });

            Dialog dialog = builder.create();

            int messageResId = (activity.mPtbm.hasFinishBell() && activity.mPtbm.hasBellsOtherThanFinish())
                    ? R.string.prepTimeBellsEditor_clearAllDialog_message_withFinishBell
                    : R.string.prepTimeBellsEditor_clearAllDialog_message_noFinishBell;
            AlertDialog alert = (AlertDialog) dialog;
            alert.setMessage(getString(messageResId));

            return alert;
        }

    }

    //******************************************************************************************
    // Private classes
    //******************************************************************************************

    private class AddButtonOnClickListener implements OnClickListener {
        @Override
        public void onClick(View v) {
            // Generate the "add bell" dialog
            DialogFragment fragment = new DialogAddOrEditBellFragment();
            fragment.show(getSupportFragmentManager(), DIALOG_TAG_ADD_BELL);
        }
    }

    private class ClearButtonOnClickListener implements OnClickListener {
        @Override
        public void onClick(View v) {
            // Generate the "are you sure?" dialog
            DialogFragment fragment = new DialogClearBellsFragment();
            fragment.show(getSupportFragmentManager(), DIALOG_TAG_CLEAR_ALL_BELLS);
        }
    }

    //******************************************************************************************
    // Public methods
    //******************************************************************************************
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
        String title = getString(R.string.prepTimeBellsEditor_contextMenu_header,
                mPtbm.getBellDescription(info.position));
        menu.setHeaderTitle(title);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.prep_time_bells_list_context, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home)
            finish();
        return super.onOptionsItemSelected(item);
    }

    //******************************************************************************************
    // Protected methods
    //******************************************************************************************

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_prep_time_bells_edit);

        // Open the preferences file and instantiate the PrepTimeBellsManager
        SharedPreferences prefs = getSharedPreferences(PrepTimeBellsManager.PREP_TIME_BELLS_PREFERENCES_NAME,
                MODE_PRIVATE);
        mPtbm = new PrepTimeBellsManager(this);
        mPtbm.loadFromPreferences(prefs);

        // Populate the list
        refreshBellsList();

        // Set the OnClickListeners
        ((Button) findViewById(R.id.prepTimeBellsEditor_addBellButton))
                .setOnClickListener(new AddButtonOnClickListener());
        ((Button) findViewById(R.id.prepTimeBellsEditor_clearAllButton))
                .setOnClickListener(new ClearButtonOnClickListener());

        // Register a context menu for the bells list items
        registerForContextMenu(findViewById(R.id.prepTimeBellsEditor_bellsList));

        // Register for the list to show a toast on non-long click
        ((ListView) findViewById(R.id.prepTimeBellsEditor_bellsList))
                .setOnItemClickListener(new OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
                        Toast.makeText(PrepTimeBellsEditActivity.this, R.string.prepTimeBellsEditor_contextMenu_tip,
                                Toast.LENGTH_SHORT).show();
                    }
                });

        // Set the action bar
        ActionBar bar = getActionBar();
        if (bar != null)
            bar.setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        switch (item.getItemId()) {
        case R.id.prepTimeBellsEditor_contextMenu_edit:
            Bundle args = mPtbm.getBellBundle(info.position);
            args.putInt(KEY_INDEX, info.position);
            DialogFragment fragment = new DialogAddOrEditBellFragment();
            fragment.setArguments(args);
            fragment.show(getSupportFragmentManager(), DIALOG_TAG_EDIT_BELL);
            return true;
        case R.id.prepTimeBellsEditor_contextMenu_delete:
            mPtbm.deleteBell(info.position);
            refreshBellsList();
            return true;
        default:
            return super.onContextItemSelected(item);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        SharedPreferences prefs = getSharedPreferences(PrepTimeBellsManager.PREP_TIME_BELLS_PREFERENCES_NAME,
                MODE_PRIVATE);
        mPtbm.saveToPreferences(prefs);
    }

    //******************************************************************************************
    // Private methods
    //******************************************************************************************

    @SuppressLint("DefaultLocale")
    private void refreshBellsList() {
        ArrayList<String> descriptions = mPtbm.getBellDescriptions();

        // Convert descriptions to sentence case
        ListIterator<String> descriptionsIterator = descriptions.listIterator();
        while (descriptionsIterator.hasNext()) {
            String description = descriptionsIterator.next();
            descriptionsIterator
                    .set(description.substring(0, 1).toUpperCase(Locale.getDefault()) + description.substring(1));
        }

        ListView view = (ListView) findViewById(R.id.prepTimeBellsEditor_bellsList);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
                descriptions);
        view.setAdapter(adapter);

        // Disable the "clear" button if there is nothing to clear
        ((Button) findViewById(R.id.prepTimeBellsEditor_clearAllButton)).setEnabled(mPtbm.hasBells());
    }

    private static Bundle createBellBundleFromAddOrEditDialog(final Dialog dialog) {
        final Spinner typeSpinner = (Spinner) dialog.findViewById(R.id.addPrepTimeBellDialog_typeSpinner);
        final TimePicker timePicker = (TimePicker) dialog.findViewById(R.id.addPrepTimeBellDialog_timePicker);
        final EditText editText = (EditText) dialog.findViewById(R.id.addPrepTimeBellDialog_editText);

        int typeSelected = typeSpinner.getSelectedItemPosition();
        Bundle bundle = new Bundle();
        switch (typeSelected) {
        case ADD_PREP_TIME_BELL_TYPE_START:
        case ADD_PREP_TIME_BELL_TYPE_FINISH:
            // We're using this in hours and minutes, not minutes and seconds
            int minutes = timePicker.getCurrentHour();
            int seconds = timePicker.getCurrentMinute();
            long time = minutes * 60 + seconds;
            if (typeSelected == ADD_PREP_TIME_BELL_TYPE_START)
                bundle.putString(PrepTimeBellsManager.KEY_TYPE, PrepTimeBellsManager.VALUE_TYPE_START);
            else
                bundle.putString(PrepTimeBellsManager.KEY_TYPE, PrepTimeBellsManager.VALUE_TYPE_FINISH);
            bundle.putLong(PrepTimeBellsManager.KEY_TIME, time);
            break;
        case ADD_PREP_TIME_BELL_TYPE_PERCENTAGE:
            Editable text = editText.getText();
            bundle.putString(PrepTimeBellsManager.KEY_TYPE, PrepTimeBellsManager.VALUE_TYPE_PROPORTIONAL);
            Double percentage = Double.parseDouble(text.toString());
            double value = percentage / 100;
            bundle.putDouble(PrepTimeBellsManager.KEY_PROPORTION, value);
            break;
        }

        return bundle;
    }

    private DialogInterface.OnClickListener getAddBellDialogOnClickListener() {
        return new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int which) {
                Dialog dialog = (Dialog) dialogInterface;
                Bundle newBundle = createBellBundleFromAddOrEditDialog(dialog);
                mPtbm.addFromBundle(newBundle);
                refreshBellsList();
            }
        };
    }

    private DialogInterface.OnClickListener getEditBellDialogOnClickListener(final int index) {
        return new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int which) {
                Dialog dialog = (Dialog) dialogInterface;
                Bundle newBundle = createBellBundleFromAddOrEditDialog(dialog);
                mPtbm.replaceFromBundle(index, newBundle);
                refreshBellsList();
            }
        };

    }

}