package com.pluscubed.plustimer.ui.solvedialog; import android.annotation.SuppressLint; import android.app.Dialog; import android.app.DialogFragment; import android.graphics.Color; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ImageView; import android.widget.Spinner; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; import com.couchbase.lite.CouchbaseLiteException; import com.pluscubed.plustimer.R; import com.pluscubed.plustimer.base.RecyclerViewUpdate; import com.pluscubed.plustimer.model.PuzzleType; import com.pluscubed.plustimer.model.Session; import com.pluscubed.plustimer.model.Solve; import com.pluscubed.plustimer.utils.PrefUtils; import com.pluscubed.plustimer.utils.ThemeUtils; import com.pluscubed.plustimer.utils.Utils; import net.gnehzr.tnoodle.scrambles.InvalidScrambleException; import java.io.IOException; import java.math.BigDecimal; import rx.android.schedulers.AndroidSchedulers; /** * Solve modify dialog */ public class SolveDialogFragment extends DialogFragment { private static final String ARG_DIALOG_INIT_PUZZLETYPE_ID = "com.pluscubed.plustimer.dialog.puzzleType"; private static final String ARG_DIALOG_INIT_SESSION_ID = "com.pluscubed.plustimer.dialog.sessionIndex"; private static final String ARG_DIALOG_INIT_SOLVE = "com.pluscubed.plustimer.dialog.solveIndex"; private static final String ARG_DIALOG_INIT_ADD_MODE = "com.pluscubed.plustimer.dialog.addMode"; private String mPuzzleTypeId; private String mSessionId; private boolean mAddMode; private EditText mScrambleEdit; private Solve mSolveCopy; private boolean mMillisecondsEnabled; private EditText mTimeEdit; private Solve mSolve; public static SolveDialogFragment newInstance(boolean addMode, String puzzleTypeId, String sessionId, Solve solve) { SolveDialogFragment d = new SolveDialogFragment(); Bundle args = new Bundle(); args.putString(ARG_DIALOG_INIT_SESSION_ID, sessionId); args.putParcelable(ARG_DIALOG_INIT_SOLVE, solve); args.putString(ARG_DIALOG_INIT_PUZZLETYPE_ID, puzzleTypeId); args.putBoolean(ARG_DIALOG_INIT_ADD_MODE, addMode); d.setArguments(args); return d; } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { //SOLVE SETUP mAddMode = getArguments().getBoolean(ARG_DIALOG_INIT_ADD_MODE); mPuzzleTypeId = getArguments().getString(ARG_DIALOG_INIT_PUZZLETYPE_ID); mSessionId = getArguments().getString(ARG_DIALOG_INIT_SESSION_ID); if (!mAddMode) { //Original solve contains the ID - new info will be copied back from mSolveCopy mSolve = getArguments().getParcelable(ARG_DIALOG_INIT_SOLVE); mSolveCopy = new Solve(mSolve); } else { mSolveCopy = new Solve(); } mMillisecondsEnabled = PrefUtils.isDisplayMillisecondsEnabled(getActivity()); boolean signEnabled = PrefUtils.isSignEnabled(getActivity()); String timeString = "0"; String scramble = ""; long timestamp = mSolveCopy.getTimestamp(); int penalty = Solve.PENALTY_NONE; if (!mAddMode) { timeString = mSolveCopy.getDescriptiveTimeString(mMillisecondsEnabled); scramble = Utils.getUiScramble(getActivity(), mSolveCopy.getScramble(), signEnabled, mPuzzleTypeId).toBlocking().value(); penalty = mSolveCopy.getPenalty(); } LayoutInflater inflater = getActivity().getLayoutInflater(); //VIEW INFLATION @SuppressLint("InflateParams") View v = inflater.inflate(R.layout.fragment_dialog_solve, null); //TIMESTAMP TEXTVIEW SETUP TextView timestampTextView = (TextView) v.findViewById(R.id.dialog_solve_timestamp_textview); timestampTextView.setText(Utils.dateTimeSecondsStringFromTimestamp(getActivity().getApplicationContext(), timestamp)); //PENALTY SPINNER SETUP Spinner penaltySpinner = (Spinner) v.findViewById(R.id.dialog_solve_modify_penalty_spinner); ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getActivity(), 0, getResources().getStringArray(R.array.penalty_array)) { @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getActivity().getLayoutInflater() .inflate(R.layout.spinner_item, parent, false); } TextView textView = (TextView) convertView.findViewById (android.R.id.text1); textView.setText(getItem(position)); if (PrefUtils.getTheme(getActivity()) != PrefUtils.Theme.DARK && PrefUtils.getTheme(getActivity()) != PrefUtils.Theme.BLACK) { ImageView triangle = (ImageView) convertView.findViewById(R.id .spinner_item_imageview); triangle.setColorFilter(Color.BLACK); } return convertView; } @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { View v = super.getDropDownView(position, convertView, parent); int textColor; if (PrefUtils.getTheme(getActivity()) == PrefUtils.Theme.DARK || PrefUtils.getTheme(getActivity()) == PrefUtils.Theme.BLACK) { textColor = R.color.list_dropdown_color_dark; } else { textColor = R.color.list_dropdown_color_light; } ((TextView) v.findViewById(android.R.id.text1)).setTextColor (getResources().getColorStateList(textColor)); return v; } }; adapter.setDropDownViewResource(R.layout.spinner_item_dropdown); penaltySpinner.setAdapter(adapter); penaltySpinner.setSelection(penalty); penaltySpinner.setOnItemSelectedListener(new AdapterView .OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int selectedPosition, long id) { try { mSolveCopy.setPenalty(null, selectedPosition); } catch (CouchbaseLiteException | IOException e) { e.printStackTrace(); } updateTitle(); } @Override public void onNothingSelected(AdapterView<?> parent) { } }); //TIME EDITTEXT SETUP mTimeEdit = (EditText) v.findViewById(R.id.dialog_solve_time_edittext); if (!mAddMode) { mTimeEdit.setText(Utils.timeStringSecondsFromNs(mSolveCopy.getRawTime(), mMillisecondsEnabled)); } mTimeEdit.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { while (true) { try { if (s.length() != 0) { BigDecimal timeEditTextDecimal = BigDecimal.valueOf(Double.parseDouble(s.toString())); mSolveCopy.setRawTime(null, timeEditTextDecimal.multiply(BigDecimal.valueOf(1000000000)).longValueExact()); updateTitle(); break; } else { getDialog().setTitle(Utils.timeStringFromNs(0, mMillisecondsEnabled)); mSolveCopy.setRawTime(null, 0); break; } } catch (NumberFormatException | ArithmeticException e) { s.delete(s.length() - 1, s.length()); } catch (CouchbaseLiteException | IOException e) { e.printStackTrace(); } } } }); //SCRAMBLE EDITTEXT SETUP mScrambleEdit = (EditText) v.findViewById(R.id.dialog_solve_scramble_edittext); mScrambleEdit.setText(scramble); mScrambleEdit.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { mScrambleEdit.setError(null); } }); //Return MaterialDialog.Builder builder = new MaterialDialog.Builder(getActivity()); builder.customView(v, true) .title(timeString) .theme(ThemeUtils.getDialogTheme(getActivity())) .autoDismiss(false) .positiveText(android.R.string.ok) .negativeText(android.R.string.cancel) .onPositive((dialog, which) -> onOkPressed()) .onNegative((dialog, which) -> onCancelPressed()); if (!mAddMode) { builder.neutralText(R.string.delete) .onNeutral((dialog, which) -> { onDeletePressed(); dialog.dismiss(); }); } return builder.build(); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (mAddMode) { getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams .SOFT_INPUT_STATE_VISIBLE); } return super.onCreateView(inflater, container, savedInstanceState); } private void onDeletePressed() { //TODO /*if (ErrorUtils.isSolveNonexistent(getActivity(), mPuzzleTypeId, mSessionId, mSolveId)) { return; }*/ PuzzleType.get(getActivity(), mPuzzleTypeId) .flatMap(puzzleType -> puzzleType.getSessionDeferred(getActivity(), mSessionId)) .flatMapObservable(session -> session.deleteSolveAsync(getActivity(), mSolve.getId()).toObservable()) .toCompletable() .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::dismiss); } private void onCancelPressed() { dismiss(); } private void onOkPressed() { if (mTimeEdit.getText().toString().equals("")) { mTimeEdit.setText("0"); } String scrambleText = Utils.signToWcaNotation(getActivity(), mScrambleEdit.getText().toString(), mPuzzleTypeId) .toBlocking().value(); if (!scrambleText.equals(mSolveCopy.getScramble())) { PuzzleType.get(getActivity(), mPuzzleTypeId) .map(puzzleType -> { try { return puzzleType.getPuzzle().getSolvedState().applyAlgorithm(scrambleText); } catch (InvalidScrambleException e) { return null; } }) .subscribe(state -> { if (state == null) { mScrambleEdit.setError(getString(R.string.invalid_scramble)); } }); } try { mSolveCopy.setScramble(null, scrambleText); } catch (CouchbaseLiteException | IOException ignore) { //won't happen on disconnected solve } if (!mAddMode) { mSolve.copy(mSolveCopy); mSolve.updateCb(getActivity()); Session.notifyListeners(mSessionId, mSolve, RecyclerViewUpdate.SINGLE_CHANGE); dismiss(); } else { PuzzleType.get(getActivity(), mPuzzleTypeId) .flatMap(puzzleType -> puzzleType.getSessionDeferred(getActivity(), mSessionId)) .subscribe(session -> { try { session.addDisconnectedSolve(getActivity(), mSolveCopy); } catch (CouchbaseLiteException | IOException e) { e.printStackTrace(); } }); dismiss(); } } void updateTitle() { if (getDialog() != null) { getDialog().setTitle(mSolveCopy.getDescriptiveTimeString(mMillisecondsEnabled)); } } }