package co.smartreceipts.android.fragments; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.res.Configuration; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.text.TextUtils; import android.text.format.DateFormat; import android.text.format.Time; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.EditText; import android.widget.Spinner; import java.math.BigDecimal; import java.sql.Date; import javax.inject.Inject; import co.smartreceipts.android.R; import co.smartreceipts.android.SmartReceiptsApplication; import co.smartreceipts.android.analytics.Analytics; import co.smartreceipts.android.analytics.events.Events; import co.smartreceipts.android.date.DateEditText; import co.smartreceipts.android.date.DateManager; import co.smartreceipts.android.model.Distance; import co.smartreceipts.android.model.Trip; import co.smartreceipts.android.model.factory.DistanceBuilderFactory; import co.smartreceipts.android.model.utils.ModelUtils; import co.smartreceipts.android.persistence.DatabaseHelper; import co.smartreceipts.android.persistence.PersistenceManager; import co.smartreceipts.android.persistence.database.controllers.impl.DistanceTableController; import co.smartreceipts.android.persistence.database.operations.DatabaseOperationMetadata; import co.smartreceipts.android.settings.UserPreferenceManager; import co.smartreceipts.android.settings.catalog.UserPreference; import dagger.android.support.AndroidSupportInjection; import wb.android.autocomplete.AutoCompleteAdapter; public class DistanceDialogFragment extends DialogFragment implements OnClickListener { public static final String TAG = DistanceDialogFragment.class.getSimpleName(); private static final String ARG_SUGGESTED_DATE = "arg_suggested_date"; @Inject PersistenceManager persistenceManager; @Inject DateManager dateManager; @Inject Analytics analytics; @Inject DistanceTableController distanceTableController; private EditText distance, rate, comment; private AutoCompleteTextView location; private DateEditText date; private Spinner currency; private Trip trip; private Distance updateableDistance; private AutoCompleteAdapter locationAutoCompleteAdapter; private Date suggestedDate; /** * Creates a new instance of a {@link DistanceDialogFragment}, which * can be used to enter a new distance item * * @param trip - the parent {@link Trip} * @return - a {@link DistanceDialogFragment} */ public static DistanceDialogFragment newInstance(final Trip trip) { return newInstance(trip, null, null); } /** * Creates a new instance of a {@link DistanceDialogFragment}, which * can be used to enter a new distance item * * @param trip - the parent {@link Trip} * @param suggestedDate - the suggested {@link Date} to display to the user when creating a new distance item * @return - a {@link DistanceDialogFragment} */ public static DistanceDialogFragment newInstance(final Trip trip, final Date suggestedDate) { return newInstance(trip, null, suggestedDate); } /** * Creates a new instance of a {@link DistanceDialogFragment}, which * can be used to update an existing distance item * * @param trip - the parent {@link Trip} * @param distance - the {@link Distance} object to update * @return - a {@link DistanceDialogFragment} */ public static DistanceDialogFragment newInstance(final Trip trip, final Distance distance) { return newInstance(trip, distance, null); } private static DistanceDialogFragment newInstance(final Trip trip, final Distance distance, final Date suggestedDate) { final DistanceDialogFragment dialog = new DistanceDialogFragment(); final Bundle args = new Bundle(); args.putParcelable(Trip.PARCEL_KEY, trip); if (distance != null) { args.putParcelable(Distance.PARCEL_KEY, distance); } if (suggestedDate != null) { args.putLong(ARG_SUGGESTED_DATE, suggestedDate.getTime() + 1); } dialog.setArguments(args); return dialog; } @Override public void onAttach(Context context) { AndroidSupportInjection.inject(this); super.onAttach(context); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final SmartReceiptsApplication app = ((SmartReceiptsApplication) getActivity().getApplication()); trip = getArguments().getParcelable(Trip.PARCEL_KEY); updateableDistance = getArguments().getParcelable(Distance.PARCEL_KEY); final Time now = new Time(); now.setToNow(); // Default to "now" if not suggested date was set suggestedDate = new Date(getArguments().getLong(ARG_SUGGESTED_DATE, now.toMillis(false))); } @SuppressLint("InflateParams") @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { final LayoutInflater inflater = LayoutInflater.from(getActivity()); final View rootView = inflater.inflate(R.layout.dialog_mileage, null); distance = (EditText) rootView.findViewById(R.id.dialog_mileage_distance); rate = (EditText) rootView.findViewById(R.id.dialog_mileage_rate); currency = (Spinner) rootView.findViewById(R.id.dialog_mileage_currency); location = (AutoCompleteTextView) rootView.findViewById(R.id.dialog_mileage_location); comment = (EditText) rootView.findViewById(R.id.dialog_mileage_comment); date = (DateEditText) rootView.findViewById(R.id.dialog_mileage_date); DatabaseHelper databaseHelper = persistenceManager.getDatabase(); UserPreferenceManager prefs = persistenceManager.getPreferenceManager(); final ArrayAdapter<CharSequence> currencies = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, databaseHelper.getCurrenciesList()); currencies.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); currency.setAdapter(currencies); date.setOnClickListener(dateManager.getDateEditTextListener()); date.setFocusable(false); date.setFocusableInTouchMode(false); final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setView(rootView); if (updateableDistance == null) { // New Distance builder.setTitle(getString(R.string.dialog_mileage_title_create)); builder.setPositiveButton(getString(R.string.dialog_mileage_positive_create), this); date.date = suggestedDate; date.setText(DateFormat.getDateFormat(getActivity()).format(date.date)); int idx = currencies.getPosition(trip.getPrice().getCurrencyCode()); if (idx > 0) { currency.setSelection(idx); } final float distanceRate = prefs.get(UserPreference.Distance.DefaultDistanceRate); if (distanceRate > 0) { rate.setText(ModelUtils.getDecimalFormattedValue(new BigDecimal(distanceRate), Distance.RATE_PRECISION)); } if (locationAutoCompleteAdapter == null) { locationAutoCompleteAdapter = AutoCompleteAdapter.getInstance(getActivity(), DatabaseHelper.TAG_DISTANCE_LOCATION, databaseHelper); } else { locationAutoCompleteAdapter.reset(); } location.setAdapter(locationAutoCompleteAdapter); distance.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus && getActivity() != null && getDialog() != null) { if (getActivity().getResources().getConfiguration().hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); } } } }); } else { // Update distance builder.setTitle(getString(R.string.dialog_mileage_title_update)); builder.setPositiveButton(getString(R.string.dialog_mileage_positive_update), this); builder.setNeutralButton(getString(R.string.dialog_mileage_neutral_delete), this); distance.setText(updateableDistance.getDecimalFormattedDistance()); rate.setText(updateableDistance.getDecimalFormattedRate()); location.setText(updateableDistance.getLocation()); comment.setText(updateableDistance.getComment()); date.setText(updateableDistance.getFormattedDate(getActivity(), prefs.get(UserPreference.General.DateSeparator))); date.date = updateableDistance.getDate(); int idx = currencies.getPosition(updateableDistance.getPrice().getCurrencyCode()); if (idx > 0) { currency.setSelection(idx); } } builder.setNegativeButton(android.R.string.cancel, this); final Dialog dialog = builder.create(); dateManager.setDateEditTextListenerDialogHolder(dialog); return dialog; } @Override public void onPause() { if (locationAutoCompleteAdapter != null) { locationAutoCompleteAdapter.onPause(); } super.onPause(); } @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { // Create/Edit final String currency = this.currency.getSelectedItem().toString(); final String location = this.location.getText().toString(); final String comment = this.comment.getText().toString(); final Date date = this.date.date; if (updateableDistance == null) { // We're inserting a new one final BigDecimal distance = getBigDecimalFromString(this.distance.getText().toString(), new BigDecimal(0)); final BigDecimal rate = getBigDecimalFromString(this.rate.getText().toString(), new BigDecimal(0)); final DistanceBuilderFactory builder = new DistanceBuilderFactory(); builder.setTrip(trip); builder.setLocation(location); builder.setDistance(distance); builder.setDate(date); builder.setRate(rate); builder.setCurrency(currency); builder.setComment(comment); analytics.record(Events.Distance.PersistNewDistance); distanceTableController.insert(builder.build(), new DatabaseOperationMetadata()); } else { // We're updating final BigDecimal distance = getBigDecimalFromString(this.distance.getText().toString(), updateableDistance.getDistance()); final BigDecimal rate = getBigDecimalFromString(this.rate.getText().toString(), updateableDistance.getRate()); final DistanceBuilderFactory builder = new DistanceBuilderFactory(updateableDistance); builder.setLocation(location); builder.setDistance(distance); builder.setDate(date); builder.setRate(rate); builder.setCurrency(currency); builder.setComment(comment); analytics.record(Events.Distance.PersistUpdateDistance); distanceTableController.update(updateableDistance, builder.build(), new DatabaseOperationMetadata()); } } else if (which == DialogInterface.BUTTON_NEUTRAL) { // Delete final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(getString(R.string.delete_item, updateableDistance.getLocation())); builder.setMessage(R.string.delete_sync_information); builder.setCancelable(true); builder.setPositiveButton(R.string.delete, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { distanceTableController.delete(updateableDistance, new DatabaseOperationMetadata()); dismiss(); } }); builder.setNegativeButton(android.R.string.cancel, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); } }); builder.show(); } dismiss(); } /** * @param number - a string containing a number * @param fallback - the {@link BigDecimal} to return if the string is NaN * @return a {@link BigDecimal} or the fallback param if not */ private BigDecimal getBigDecimalFromString(String number, BigDecimal fallback) { if (TextUtils.isEmpty(number)) { return fallback; } try { return new BigDecimal(number.replace(",", ".")); } catch (NumberFormatException e) { return fallback; } } }