package ca.josephroque.bowlingcompanion.dialog; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.DialogFragment; import android.text.InputFilter; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.EditText; import android.widget.TextView; import ca.josephroque.bowlingcompanion.Constants; import ca.josephroque.bowlingcompanion.R; import ca.josephroque.bowlingcompanion.wrapper.LeagueEvent; /** * Created by Joseph Roque on 15-03-16. Provides dialog and callback interface {@link * ca.josephroque.bowlingcompanion.dialog.NameLeagueEventDialog.NameLeagueEventDialogListener} for the user to enter the * name of a new league or event to track the statistics of. */ public class NameLeagueEventDialog extends DialogFragment { /** Identifies output from this class in Logcat. */ @SuppressWarnings("unused") private static final String TAG = "NewLeagueEventDialog"; /** * Argument to indicate if the dialog should provide an input for the number of games, or just to edit the * instance. */ private static final String ARG_EDITING = "arg_editing"; /** Argument to indicate the league / event name being changed. */ private static final String ARG_LEAGUE_EVENT = "arg_league_event"; /** Instance of listener which contains methods that are executed upon user interaction. */ private NameLeagueEventDialogListener mDialogListener; /** If true, a new event is being added, a league otherwise. */ private boolean mIsEventMode; /** If true, a league or event is being changed. */ private boolean mEditing; /** The league / event being edited. Null if a new league / event is being created. */ private LeagueEvent mLeagueEvent; @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext()); final View dialogView = View.inflate(getContext(), R.layout.dialog_new_league_event, null); CharSequence leagueEventName = ""; CharSequence leagueEventNumberOfGames = ""; CharSequence leagueBaseAverage = ""; CharSequence leagueCurrentGames = ""; if (savedInstanceState != null) { // Loads member variables from bundle mIsEventMode = savedInstanceState.getBoolean(Constants.EXTRA_EVENT_MODE); mEditing = savedInstanceState.getBoolean(ARG_EDITING); leagueEventName = savedInstanceState.getCharSequence(Constants.EXTRA_NAME_LEAGUE); if (!mIsEventMode) { leagueBaseAverage = savedInstanceState.getCharSequence(Constants.EXTRA_BASE_AVERAGE); leagueCurrentGames = savedInstanceState.getCharSequence(Constants.EXTRA_BASE_GAMES); } if (!mEditing) leagueEventNumberOfGames = savedInstanceState.getCharSequence(Constants.EXTRA_NUMBER_OF_GAMES); else mLeagueEvent = savedInstanceState.getParcelable(ARG_LEAGUE_EVENT); } else { Bundle arguments = getArguments(); mIsEventMode = arguments.getBoolean(Constants.EXTRA_EVENT_MODE); mEditing = arguments.getBoolean(ARG_EDITING); if (mEditing) { mLeagueEvent = arguments.getParcelable(ARG_LEAGUE_EVENT); if (mLeagueEvent != null) { leagueEventName = mLeagueEvent.getLeagueEventName(); if (mLeagueEvent.getBaseAverage() >= 0) leagueBaseAverage = Short.toString(mLeagueEvent.getBaseAverage()); if (mLeagueEvent.getBaseGames() > 0) leagueCurrentGames = Integer.toString(mLeagueEvent.getBaseGames()); } } } final EditText editTextName = (EditText) dialogView.findViewById(R.id.et_league_event_name); editTextName.setHint( ((mIsEventMode) ? "Event" : "League") + " (max " + Constants.NAME_MAX_LENGTH + " characters)"); editTextName.setFilters(new InputFilter[]{new InputFilter.LengthFilter(Constants.NAME_MAX_LENGTH)}); editTextName.setText(leagueEventName); final EditText editTextBaseAverage = (EditText) dialogView.findViewById(R.id.et_league_base_avg); final EditText editTextCurrentGames = (EditText) dialogView.findViewById(R.id.et_league_base_games); final TextView textViewBaseAverage = (TextView) dialogView.findViewById(R.id.tv_base_avg); if (mIsEventMode) { textViewBaseAverage.setVisibility(View.GONE); editTextCurrentGames.setVisibility(View.GONE); editTextBaseAverage.setVisibility(View.GONE); } else { editTextBaseAverage.setHint("Current Average"); editTextBaseAverage.setText(leagueBaseAverage); editTextCurrentGames.setHint("Games so far (max 100,000)"); editTextCurrentGames.setText(leagueCurrentGames); } final EditText editTextNumberOfGames = (EditText) dialogView.findViewById(R.id.et_league_event_games); final int positiveButtonText; if (mEditing) { editTextNumberOfGames.setVisibility(View.GONE); positiveButtonText = R.string.dialog_change; } else { editTextNumberOfGames.setHint("# of games (1-" + ((mIsEventMode) ? Constants.MAX_NUMBER_EVENT_GAMES : Constants.MAX_NUMBER_LEAGUE_GAMES) + ")"); editTextNumberOfGames.setText(leagueEventNumberOfGames); positiveButtonText = R.string.dialog_add; } DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { if (mEditing) { updateLeagueEvent(editTextName.getText().toString().trim(), editTextBaseAverage.getText().toString().trim(), editTextCurrentGames.getText().toString().trim()); } else { addNewLeagueEvent(editTextName.getText().toString().trim(), editTextNumberOfGames.getText().toString().trim(), editTextBaseAverage.getText().toString().trim(), editTextCurrentGames.getText().toString().trim()); } } dialog.dismiss(); } }; dialogBuilder.setView(dialogView) .setPositiveButton(positiveButtonText, onClickListener) .setNegativeButton(R.string.dialog_cancel, onClickListener); AlertDialog dialog = dialogBuilder.create(); Window dialogWindow = dialog.getWindow(); if (dialogWindow != null) { dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); } return dialog; } @Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); // Saves member variables to bundle outState.putBoolean(Constants.EXTRA_EVENT_MODE, mIsEventMode); outState.putBoolean(ARG_EDITING, mEditing); outState.putCharSequence(Constants.EXTRA_NAME_LEAGUE, ((EditText) getDialog().findViewById(R.id.et_league_event_name)).getText()); if (!mIsEventMode) { outState.putCharSequence(Constants.EXTRA_BASE_AVERAGE, ((EditText) getDialog().findViewById(R.id.et_league_base_avg)).getText()); outState.putCharSequence(Constants.EXTRA_BASE_GAMES, ((EditText) getDialog().findViewById(R.id.et_league_base_games)).getText()); } if (!mEditing) outState.putCharSequence(Constants.EXTRA_NUMBER_OF_GAMES, ((EditText) getDialog().findViewById(R.id.et_league_event_games)).getText()); else outState.putParcelable(ARG_LEAGUE_EVENT, mLeagueEvent); } /** * Checks if the user input is valid, and changes the name and base average of the league / event if so. * * @param leagueName new name for league / event * @param strBaseAverage new base average for the league / event * @param strBaseGames new base number of games for determining the average */ private void updateLeagueEvent(String leagueName, String strBaseAverage, String strBaseGames) { short baseAverage; int baseGames; if (strBaseAverage.length() > 0) { try { baseAverage = Short.parseShort(strBaseAverage); } catch (NumberFormatException ex) { baseAverage = -1; } if (baseAverage > -1 && strBaseGames.length() > 0) { try { baseGames = Integer.parseInt(strBaseGames); } catch (NumberFormatException ex) { baseGames = 0; } } else { baseGames = 0; } } else { baseAverage = -1; baseGames = 0; } if (baseAverage >= 0 && baseGames == 0) baseGames = 1; if (leagueName.length() > 0 && baseAverage >= -1 && baseAverage <= Constants.GAME_MAX_SCORE && baseGames >= 0 && baseGames <= Constants.MAXIMUM_BASE_GAMES) mDialogListener.onUpdateLeagueEvent(mLeagueEvent, leagueName, baseAverage, baseGames); } /** * Checks if the user input is valid, and creates a new league / event if so. * * @param newLeagueName name for new league / event * @param strNumberOfGames number of games for new league / event * @param strBaseAverage base average of the league * @param strBaseGames base number of games for determining the average */ private void addNewLeagueEvent(String newLeagueName, String strNumberOfGames, String strBaseAverage, String strBaseGames) { if (newLeagueName.length() > 0 && strNumberOfGames.length() > 0) { byte numberOfGames; try { numberOfGames = Byte.parseByte(strNumberOfGames); } catch (NumberFormatException ex) { numberOfGames = -1; } short baseAverage; int baseGames; if (strBaseAverage.length() > 0) { try { baseAverage = Short.parseShort(strBaseAverage); } catch (NumberFormatException ex) { baseAverage = -1; } if (baseAverage > -1 && strBaseGames.length() > 0) { try { baseGames = Integer.parseInt(strBaseGames); } catch (NumberFormatException ex) { baseGames = 0; } } else { baseGames = 1; } } else { baseAverage = -1; baseGames = 0; } if (baseAverage >= 0 && baseGames == 0) baseGames = 1; mDialogListener.onAddNewLeagueEvent(mIsEventMode, newLeagueName, numberOfGames, baseAverage, baseGames); } } /** * Provides a method to the activity which created this object to handle user interaction with the dialog. */ public interface NameLeagueEventDialogListener { /** * Executed when user opts to add a new league or event. * * @param isEvent if true, a new event was added. If false, a new league was added * @param name name of the new league or event * @param numberOfGames number of games in the new league or event * @param baseAverage base average for the game * @param baseGames base number of games for determining the average */ void onAddNewLeagueEvent(boolean isEvent, String name, byte numberOfGames, short baseAverage, int baseGames); /** * Executed when user opts to change the name or base average of a league or event. * * @param leagueEvent league or event name that is being changed * @param name new name * @param baseAverage new base average for the game * @param baseGames base number of games for determining the average */ void onUpdateLeagueEvent(LeagueEvent leagueEvent, String name, short baseAverage, int baseGames); } /** * Creates a new instance of this DialogFragment and sets the listener to the parameter passed through this method. * * @param listener a listener for on click events * @param newEvent indicates if a new event or league is being created. Ignored if {@code editing} is {@code true} * @param editing if {@code true}, then an event or league is being changed * @param leagueEvent league / event to change. Can be null if {@code editing} is false * @return a new instance of NameLeagueEventDialog */ public static NameLeagueEventDialog newInstance(NameLeagueEventDialogListener listener, boolean newEvent, boolean editing, @Nullable LeagueEvent leagueEvent) { NameLeagueEventDialog dialog = new NameLeagueEventDialog(); dialog.mDialogListener = listener; Bundle args = new Bundle(); args.putBoolean(Constants.EXTRA_EVENT_MODE, newEvent); args.putBoolean(ARG_EDITING, editing); if (editing) { if (leagueEvent == null) throw new IllegalArgumentException("Must provide a league / event to change."); else args.putParcelable(ARG_LEAGUE_EVENT, leagueEvent); } dialog.setArguments(args); return dialog; } }