package com.boardgamegeek.ui.dialog; import android.graphics.Color; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.DialogFragment; import android.text.TextUtils; import android.util.DisplayMetrics; import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.TextView; import com.boardgamegeek.R; import com.boardgamegeek.util.ColorUtils; import com.boardgamegeek.util.PreferencesUtils; import com.boardgamegeek.util.StringUtils; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.OnLongClick; import butterknife.Unbinder; public class NumberPadDialogFragment extends DialogFragment { private static final String KEY_TITLE = "TITLE"; private static final String KEY_OUTPUT = "OUTPUT"; private static final String KEY_COLOR = "COLOR"; private static final int MAX_LENGTH = 10; private Unbinder unbinder; @BindView(R.id.title) TextView titleView; @BindView(R.id.output) TextView outputView; @BindView(R.id.num_delete) View deleteView; private OnClickListener clickListener; private double minValue = 0.0; private double maxValue = Double.MAX_VALUE; private int maxMantissa = MAX_LENGTH; public interface OnClickListener { void onDoneClick(String output); } public static NumberPadDialogFragment newInstance(String title, String output) { return newInstance(title, output, null); } public static NumberPadDialogFragment newInstance(String title, String output, String colorDescription) { final NumberPadDialogFragment fragment = new NumberPadDialogFragment(); Bundle args = new Bundle(); args.putString(KEY_TITLE, title); if (StringUtils.isNumeric(output)) { args.putString(KEY_OUTPUT, output); } int c = ColorUtils.parseColor(colorDescription); if (c != Color.TRANSPARENT) { args.putInt(KEY_COLOR, c); } fragment.setArguments(args); return fragment; } public void setOnDoneClickListener(OnClickListener listener) { clickListener = listener; } public void setMinValue(double value) { minValue = value; } public void setMaxValue(double value) { maxValue = value; } public void setMaxMantissa(int value) { maxMantissa = value; } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setStyle(DialogFragment.STYLE_NO_TITLE, 0); } @Override public void onResume() { super.onResume(); Window window = getDialog().getWindow(); if (window != null) { DisplayMetrics dm = getResources().getDisplayMetrics(); int width = Math.min( getActivity().getResources().getDimensionPixelSize(R.dimen.dialog_width), dm.widthPixels * 3 / 4); int height = window.getAttributes().height; window.setLayout(width, height); } } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.dialog_number_pad, container, false); unbinder = ButterKnife.bind(this, view); Bundle args = getArguments(); if (args != null) { if (args.containsKey(KEY_TITLE)) { titleView.setText(args.getString(KEY_TITLE)); } if (args.containsKey(KEY_OUTPUT)) { outputView.setText(args.getString(KEY_OUTPUT)); enableDelete(); } if (args.containsKey(KEY_COLOR)) { int color = args.getInt(KEY_COLOR); titleView.setBackgroundColor(color); if (color != ColorUtils.TRANSPARENT && ColorUtils.isColorDark(color)) { titleView.setTextColor(Color.WHITE); } else { titleView.setTextColor(Color.BLACK); } } } return view; } @Override public void onDestroyView() { super.onDestroyView(); if (unbinder != null) unbinder.unbind(); } @OnClick({ R.id.num_0, R.id.num_1, R.id.num_2, R.id.num_3, R.id.num_4, R.id.num_5, R.id.num_6, R.id.num_7, R.id.num_8, R.id.num_9, R.id.num_decimal }) void onNumPadClick(TextView textView) { String output = outputView.getText().toString() + textView.getText(); if (isWithinLength(output) && isWithinRange(output)) { maybeBuzz(textView); outputView.setText(output); enableDelete(); } } @OnClick(R.id.num_done) void onDoneClick() { if (clickListener != null) { clickListener.onDoneClick(outputView.getText().toString()); } dismiss(); } @OnClick(R.id.num_delete) void onDeleteClick(View view) { final CharSequence text = outputView.getText(); if (text.length() > 0) { String output = text.subSequence(0, text.length() - 1).toString(); if (isWithinLength(output) && isWithinRange(output)) { maybeBuzz(view); outputView.setText(output); enableDelete(); } } } private void maybeBuzz(View v) { if (PreferencesUtils.getHapticFeedback(getContext())) { v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); } } @SuppressWarnings("SameReturnValue") @OnLongClick(R.id.num_delete) boolean onDeleteLongClick() { outputView.setText(""); enableDelete(); return true; } private boolean isWithinLength(String text) { return TextUtils.isEmpty(text) || text.length() <= MAX_LENGTH && getMantissaLength(text) <= maxMantissa; } private int getMantissaLength(String text) { if (!text.contains(".")) { return 0; } String[] parts = text.split("\\."); if (parts.length > 1) { return parts[1].length(); } return 0; } private boolean isWithinRange(String text) { if (TextUtils.isEmpty(text) || ".".equals(text)) { return true; } if (hasTwoDecimalPoints(text)) { return false; } double value = parseDouble(text); return value >= minValue && value <= maxValue; } private boolean hasTwoDecimalPoints(String text) { if (text == null) return false; int decimalIndex = text.indexOf('.'); return decimalIndex >= 0 && text.indexOf('.', decimalIndex + 1) >= 0; } private double parseDouble(String text) { if (TextUtils.isEmpty(text) || ".".equals(text) || "-".equals(text)) { return 0.0; } if (text.endsWith(".")) { return Double.parseDouble(text + "0"); } if (text.startsWith(".")) { return Double.parseDouble("0" + text); } return Double.parseDouble(text); } private void enableDelete() { deleteView.setEnabled(outputView.length() > 0); } }