Java tutorial
/** * * This is OpenTraining, an Android application for planning your your fitness training. * Copyright (C) 2012-2013 Christian Skubich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package de.damdi.fitness.activity.start_training; import java.text.DateFormat; import java.util.ArrayList; import java.util.List; import de.damdi.fitness.basic.FSet; import de.damdi.fitness.basic.FitnessExercise; import de.damdi.fitness.basic.TrainingEntry; import de.damdi.fitness.basic.FSet.SetParameter; import de.damdi.fitness.R; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ListAdapter; import android.widget.Spinner; import android.widget.TextView; /** * Dialog Fragment that adds or edits an {@link TrainingEntry}/ of an * {@link FitnessExercise}. * */ public class DialogFragmentAddEntry extends DialogFragment { /** Tag for logging */ public static final String TAG = "DialogFragmentAddEntry"; /** ID for argument ({@link FitnessExercise}) */ public static String ARG_ID_EXERCISE = "fex"; /** ID for optional argument ({@link FSet}) */ public static String ARG_ID_FSET = "fset"; /** ID for argument (position of the FSet in the list) */ public static String ARG_ID_FSET_POSITION = "fset_position"; /** ID for optional argument ({@link TrainingEntry}) */ public static String ARG_ID_TRAINING_ENTRY = "trainingentry"; /** Currently displayed {@link FitnessExercise}. */ private FitnessExercise mFex; /** Currently edited {@link TrainingEntry} */ private TrainingEntry mTrainingEntry; /** Currently edited {@link FSet} */ private FSet mFSet; /** The position of {@link #mFSet} in {@link #mTrainingEntry} */ private int mFSetPosition; private Spinner spinner_duration; private Spinner spinner_duration_unit; private Spinner spinner_repetitions; private Spinner spinner_weight; private CheckBox checkbox_duration; private CheckBox checkbox_weight; private CheckBox checkbox_repetitions; enum EntryAction { CREATING_ENTRY, EDITING_ENTRY; } private EntryAction mState; public interface Callbacks { /** * Callback for when an item has been changed. */ public void onEntryEdited(FitnessExercise fitnessExercise); } /** * Create a new instance of DialogFragmentAddEntry. * * @param fEx * The {@link FitnessExercise} that should be edited * @param set * Optional parameter, the {@link FSet} that should be edited. If * this is null a new FSet will be added to the * {@link TrainingEntry} * @param setPosition * The position of FSet in the TrainingEntry. Will only be used, if the set is edited * @param trainingEntry * Optional parameter, the {@link TrainingEntry} that should be * edited. If this is null the latest TrainingEntry will be * chosen. * * @return The DialogFragment */ static DialogFragmentAddEntry newInstance(FitnessExercise fEx, FSet set, int setPosition, TrainingEntry trainingEntry) { DialogFragmentAddEntry f = new DialogFragmentAddEntry(); Bundle args = new Bundle(); args.putSerializable(ARG_ID_EXERCISE, fEx); args.putSerializable(ARG_ID_FSET, set); args.putInt(ARG_ID_FSET_POSITION, setPosition); args.putSerializable(ARG_ID_TRAINING_ENTRY, trainingEntry); f.setArguments(args); return f; } /** @see #newInstance(FitnessExercise, FSet, TrainingEntry) */ static DialogFragmentAddEntry newInstance(FitnessExercise fEx, FSet set, int setPosition) { return newInstance(fEx, set, setPosition, null); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mFex = (FitnessExercise) getArguments().getSerializable(ARG_ID_EXERCISE); mFSet = (FSet) getArguments().getSerializable(ARG_ID_FSET); mFSetPosition = getArguments().getInt(ARG_ID_FSET_POSITION); mTrainingEntry = (TrainingEntry) getArguments().getSerializable(ARG_ID_TRAINING_ENTRY); // select latest TrainingEntry if argument was null if (mTrainingEntry == null) { List<TrainingEntry> entryList = mFex.getTrainingEntryList(); TrainingEntry latestEntry = entryList.get(entryList.size() - 1); mTrainingEntry = latestEntry; mState = EntryAction.CREATING_ENTRY; } if (mFSet == null) { Log.v(TAG, "Argument for mFSet was null."); mState = EntryAction.CREATING_ENTRY; } else { Log.v(TAG, "Argument for mFSet was: " + mTrainingEntry.toDebugString()); mState = EntryAction.EDITING_ENTRY; } } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { LayoutInflater inflater = LayoutInflater.from(getActivity()); final View v = inflater.inflate(R.layout.fragment_dialog_add_entry, null); spinner_duration = (Spinner) v.findViewById(R.id.spinner_duration); spinner_duration_unit = (Spinner) v.findViewById(R.id.spinner_time_unit); spinner_repetitions = (Spinner) v.findViewById(R.id.spinner_repetitions); spinner_weight = (Spinner) v.findViewById(R.id.spinner_weight); checkbox_duration = (CheckBox) v.findViewById(R.id.checkbox_duration); checkbox_weight = (CheckBox) v.findViewById(R.id.checkbox_weight); checkbox_repetitions = (CheckBox) v.findViewById(R.id.checkbox_repetitions); fillSpinners(); setSpinners(); // show different text, if an entry is edited(not created) TextView tw = (TextView) v.findViewById(R.id.textview_entryaction); if (mState == EntryAction.EDITING_ENTRY) { tw.setText(getActivity().getString(R.string.edit_entry)); } else { tw.setText(getActivity().getString(R.string.add_entry)); } return new AlertDialog.Builder(getActivity()) .setTitle(DateFormat.getInstance().format(mTrainingEntry.getDate())).setView(v).setCancelable(true) .setPositiveButton(getString(R.string.save_entry), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { List<SetParameter> setParameters = new ArrayList<SetParameter>(); if (checkbox_duration.isChecked()) { SetParameter.Duration duration = new SetParameter.Duration(getDurationValue()); setParameters.add(duration); } if (checkbox_weight.isChecked()) { SetParameter.Weight weight = new SetParameter.Weight(getWeightValue()); setParameters.add(weight); } if (checkbox_repetitions.isChecked()) { SetParameter.Repetition repetition = new SetParameter.Repetition(getRepetitionValue()); setParameters.add(repetition); } // if no SetParameter has been chosen, the FSet // must not be created or even has to be deleted if (setParameters.isEmpty()) { if (mFSet != null) { // delete existing FSet boolean success = mTrainingEntry.getFSetList().remove(mFSet); if (!success) Log.e(TAG, "Could not delete FSet:\n " + mFSet.toString() + "\n in TrainingEntry:\n " + mTrainingEntry.toDebugString()); } else { // do nothing dialog.dismiss(); return; } } else { // if SetParameters have been chosen, either the old // FSet has to be updated or a new FSet has to be // added if (mFSet == null) { // add new FSet mFSet = new FSet(setParameters.toArray(new SetParameter[setParameters.size()])); mTrainingEntry.add(mFSet); } else { // replace old FSet mFSet = new FSet(setParameters.toArray(new SetParameter[setParameters.size()])); mTrainingEntry.getFSetList().set(mFSetPosition, mFSet); } mTrainingEntry.setHasBeenDone(mFSet, false); } FExDetailFragment fragment = (FExDetailFragment) getFragmentManager() .findFragmentById(R.id.exercise_detail_container); fragment.onEntryEdited(mFex); dialog.dismiss(); } }).setNegativeButton(getString(R.string.discard_entry), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }).create(); } private int getDurationValue() { int val = Integer.parseInt((String) spinner_duration.getSelectedItem()); switch (spinner_duration_unit.getSelectedItemPosition()) { case 0: // seconds break; case 2: // hours val = 60 * val; // no break! case 1: // minutes val = 60 * val; break; default: Log.e(TAG, "Unknown choice."); } return val; } private void setDurationValue(int value) { spinner_duration_unit.setSelection(0); if (value > 3600) { value = value / 3600; spinner_duration_unit.setSelection(2); } if (value > 60) { value = value / 60; spinner_duration_unit.setSelection(1); } spinner_duration.setSelection(value - 1); } private int getWeightValue() { String str = ((String) spinner_weight.getSelectedItem()); str = str.substring(0, str.length() - 3); str = str.replaceAll(",", "."); float floatingNumber = Float.parseFloat(str); floatingNumber *= 1000; // convert kg to g int val = (int) floatingNumber; return val; } private void setWeightValue(int value) { // this is not a very elegant solution but it should work ListAdapter adapter = (ListAdapter) spinner_weight.getAdapter(); for (int i = 0; i < adapter.getCount() - 1; i++) { String str = ((String) spinner_weight.getItemAtPosition(i)); str = str.substring(0, str.length() - 3); str = str.replaceAll(",", "."); float floatingNumber = Float.parseFloat(str); floatingNumber *= 1000; // convert kg to g int val = (int) floatingNumber; if (val == value) { spinner_weight.setSelection(i); return; } } Log.e(TAG, "Could not set weight value: " + value); } private int getRepetitionValue() { return (Integer) spinner_repetitions.getSelectedItemPosition() + 1; } private void setRepetitionValue(int value) { spinner_repetitions.setSelection(value - 1); } /** * Fills the spinners with entries, e.g. with "1 kg"(weight_spinner) or just * numbers. */ private void fillSpinners() { List<String> durationList = new ArrayList<String>(); for (Integer i = 1; i <= 120; i++) { durationList.add(i.toString()); } ArrayAdapter<String> durationAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_item, durationList); durationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner_duration.setAdapter(durationAdapter); List<String> repetitionList = new ArrayList<String>(); for (int i = 1; i <= 120; i++) { repetitionList.add(i + " x"); } ArrayAdapter<String> repetitionAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_item, repetitionList); repetitionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner_repetitions.setAdapter(repetitionAdapter); List<String> weightList = new ArrayList<String>(); for (int i = 250; i <= 1000; i += 250) { weightList.add(i / 1000 + "," + i % 1000 + " kg"); } for (int i = 1500; i <= 5000; i += 500) { weightList.add(i / 1000 + "," + i % 1000 + " kg"); } for (int i = 6000; i <= 200000; i += 1000) { weightList.add(i / 1000 + "," + i % 1000 + " kg"); } for (int i = 205000; i <= 400000; i += 5000) { weightList.add(i / 1000 + "," + i % 1000 + " kg"); } for (int i = 410000; i <= 500000; i += 10000) { weightList.add(i / 1000 + "," + i % 1000 + " kg"); } ArrayAdapter<String> weightAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_item, weightList); weightAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner_weight.setAdapter(weightAdapter); checkbox_duration.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton button, boolean val) { spinner_duration.setEnabled(val); spinner_duration_unit.setEnabled(val); } }); checkbox_weight.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton button, boolean val) { spinner_weight.setEnabled(val); } }); checkbox_repetitions.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton button, boolean val) { spinner_repetitions.setEnabled(val); } }); checkbox_duration.setChecked(true); checkbox_weight.setChecked(true); checkbox_repetitions.setChecked(true); } /** * If mFSet is not null it's settings will be loaded. Otherwise the last * used settings will be loaded. */ private void setSpinners() { FSet setToSet = mFSet; // only load last settings if no argument for mFSet has been passed(that // means mFSet is null) if (setToSet == null) { Log.v(TAG, "Trying to find old TrainingEntry for loading spinner settings."); List<TrainingEntry> entryList = mFex.getTrainingEntryList(); TrainingEntry previousEntry; for (int i = entryList.size() - 1; (i >= 0) && (setToSet == null); i--) { previousEntry = entryList.get(i); List<FSet> fsetList = previousEntry.getFSetList(); if (!fsetList.isEmpty()) { setToSet = fsetList.get(fsetList.size() - 1); } } } if (setToSet == null) { Log.w(TAG, "Did not find any old TrainingEntry for loading spinner settings."); return; } checkbox_duration.setChecked(false); checkbox_weight.setChecked(false); checkbox_repetitions.setChecked(false); for (SetParameter param : setToSet.getSetParameters()) { int value = param.getValue(); if (param instanceof SetParameter.Duration) { checkbox_duration.setChecked(true); setDurationValue(value); } if (param instanceof SetParameter.Repetition) { checkbox_repetitions.setChecked(true); setRepetitionValue(value); } if (param instanceof SetParameter.Weight) { checkbox_weight.setChecked(true); setWeightValue(value); } } } }