// Copyright 2015 The Project Buendia Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy // of the License at: http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software distrib- // uted under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES // OR CONDITIONS OF ANY KIND, either express or implied. See the License for // specific language governing permissions and limitations under the License. package org.projectbuendia.client.ui.dialogs; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager.LayoutParams; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import org.joda.time.DateTime; import org.joda.time.Days; import org.joda.time.LocalDate; import org.projectbuendia.client.R; import org.projectbuendia.client.events.actions.OrderDeleteRequestedEvent; import org.projectbuendia.client.events.actions.OrderSaveRequestedEvent; import org.projectbuendia.client.models.Order; import org.projectbuendia.client.utils.Utils; import butterknife.ButterKnife; import butterknife.InjectView; import de.greenrobot.event.EventBus; /** A {@link DialogFragment} for adding a new user. */ public class OrderDialogFragment extends DialogFragment { @InjectView(R.id.order_medication) EditText mMedication; @InjectView(R.id.order_dosage) EditText mDosage; @InjectView(R.id.order_frequency) EditText mFrequency; @InjectView(R.id.order_give_for_days) EditText mGiveForDays; @InjectView(R.id.order_give_for_days_label) TextView mGiveForDaysLabel; @InjectView(R.id.order_duration_label) TextView mDurationLabel; @InjectView(R.id.order_delete) Button mDelete; private LayoutInflater mInflater; /** Creates a new instance and registers the given UI, if specified. */ public static OrderDialogFragment newInstance(String patientUuid, Order order) { Bundle args = new Bundle(); args.putString("patientUuid", patientUuid); args.putBoolean("new", order == null); // This time is used as the current time for any calculations in this dialog. // Use this value throughout instead of calling now(). This is necessary to maintain UI // consistency (e.g. if the dialog is opened before midnight and submitted after midnight). args.putLong("now_millis", DateTime.now().getMillis()); if (order != null) { args.putString("uuid", order.uuid); args.putString("instructions", order.instructions); args.putLong("start_millis", order.start.getMillis()); if (order.stop != null) { args.putLong("stop_millis", order.stop.getMillis()); } } OrderDialogFragment fragment = new OrderDialogFragment(); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mInflater = LayoutInflater.from(getActivity()); } @Override public void onResume() { super.onResume(); // Replace the existing button listener so we can control whether the dialog is dismissed. final AlertDialog dialog = (AlertDialog) getDialog(); dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { onSubmit(dialog); } } ); } private void populateFields(Bundle args) { String instructions = args.getString("instructions"); mMedication.setText(Order.getMedication(instructions)); mDosage.setText(Order.getDosage(instructions)); mFrequency.setText(Order.getFrequency(instructions)); DateTime now = Utils.getDateTime(args, "now_millis"); Long stopMillis = Utils.getLong(args, "stop_millis"); if (stopMillis != null) { LocalDate lastDay = new DateTime(stopMillis).toLocalDate(); int days = Days.daysBetween(now.toLocalDate(), lastDay).getDays(); if (days >= 0) { mGiveForDays.setText("" + (days + 1)); // 1 day means stop after today } } updateLabels(); } public void onSubmit(Dialog dialog) { String uuid = getArguments().getString("uuid"); String patientUuid = getArguments().getString("patientUuid"); String medication = mMedication.getText().toString().trim(); String dosage = mDosage.getText().toString().trim(); String frequency = mFrequency.getText().toString().trim(); String instructions = Order.getInstructions(medication, dosage, frequency); String durationStr = mGiveForDays.getText().toString().trim(); Integer durationDays = durationStr.isEmpty() ? null : Integer.valueOf(durationStr); boolean valid = true; if (medication.isEmpty()) { setError(mMedication, R.string.enter_medication); valid = false; } if (durationDays != null && durationDays == 0) { setError(mGiveForDays, R.string.order_give_for_days_cannot_be_zero); valid = false; } Utils.logUserAction("order_submitted", "valid", "" + valid, "uuid", uuid, "medication", medication, "dosage", dosage, "frequency", frequency, "instructions", instructions, "durationDays", "" + durationDays); if (!valid) { return; } dialog.dismiss(); DateTime now = Utils.getDateTime(getArguments(), "now_millis"); DateTime start = Utils.getDateTime(getArguments(), "start_millis"); start = Utils.valueOrDefault(start, now); if (durationDays != null) { // Adjust durationDays to account for a start date in the past. Entering "2" // always means two more days, stopping after tomorrow, regardless of start date. LocalDate firstDay = start.toLocalDate(); LocalDate lastDay = now.toLocalDate().plusDays(durationDays - 1); durationDays = Days.daysBetween(firstDay, lastDay).getDays() + 1; } // Post an event that triggers the PatientChartController to save the order. EventBus.getDefault().post(new OrderSaveRequestedEvent( uuid, patientUuid, instructions, start, durationDays)); } public void onDelete(Dialog dialog, final String orderUuid) { dialog.dismiss(); new AlertDialog.Builder(getActivity()) .setMessage(R.string.confirm_order_delete) .setTitle(R.string.title_confirmation) .setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int i) { EventBus.getDefault().post(new OrderDeleteRequestedEvent(orderUuid)); } }) .setNegativeButton(R.string.cancel, null) .create().show(); } private void setError(EditText field, int resourceId) { field.setError(getResources().getString(resourceId)); field.invalidate(); field.requestFocus(); } @Override public @NonNull Dialog onCreateDialog(Bundle savedInstanceState) { View fragment = mInflater.inflate(R.layout.order_dialog_fragment, null); ButterKnife.inject(this, fragment); mGiveForDays.addTextChangedListener(new DurationDaysWatcher()); Bundle args = getArguments(); boolean newOrder = args.getBoolean("new"); String title = getString(newOrder ? R.string.title_new_order : R.string.title_edit_order); final String orderUuid = args.getString("uuid"); populateFields(args); final Dialog dialog = new AlertDialog.Builder(getActivity()) .setCancelable(false) // Disable auto-cancel. .setTitle(title) // The positive button uses dialog, so we have to set it below, after dialog is assigned. .setNegativeButton(R.string.cancel, null) .setView(fragment) .create(); ((AlertDialog) dialog).setButton(Dialog.BUTTON_POSITIVE, getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { onSubmit(dialog); } }); mDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { onDelete(dialog, orderUuid); } }); // Hide or show the "Stop" and "Delete" buttons appropriately. Long stopMillis = Utils.getLong(args, "stop_millis"); Long nowMillis = Utils.getLong(args, "now_millis"); Utils.showIf(mDelete, !newOrder); // Open the keyboard, ready to type into the medication field. dialog.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); mMedication.requestFocus(); return dialog; } /** Updates the various labels in the form that react to changes in input fields. */ void updateLabels() { DateTime now = Utils.getDateTime(getArguments(), "now_millis"); String text = mGiveForDays.getText().toString().trim(); int days = text.isEmpty() ? 0 : Integer.parseInt(text); LocalDate lastDay = now.toLocalDate().plusDays(days - 1); mGiveForDaysLabel.setText( days == 0 ? R.string.order_give_for_days : days == 1 ? R.string.order_give_for_day : R.string.order_give_for_days); mDurationLabel.setText(getResources().getString( days == 0 ? R.string.order_duration_unspecified : days == 1 ? R.string.order_duration_stop_after_today : days == 2 ? R.string.order_duration_stop_after_tomorrow : R.string.order_duration_stop_after_date ).replace("%s", Utils.toShortString(lastDay))); } class DurationDaysWatcher implements TextWatcher { @Override public void beforeTextChanged(CharSequence c, int x, int y, int z) { } @Override public void onTextChanged(CharSequence c, int x, int y, int z) { } @Override public void afterTextChanged(Editable editable) { updateLabels(); } } }