/*
* Calendula - An assistant for personal medication management.
* Copyright (C) 2016 CITIUS - USC
*
* Calendula is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software. If not, see <http://www.gnu.org/licenses/>.
*/
package es.usc.citius.servando.calendula.fragments;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.text.Html;
import android.text.Spanned;
import android.text.format.Time;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.NumberPicker;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.doomonafireball.betterpickers.numberpicker.NumberPickerBuilder;
import com.doomonafireball.betterpickers.numberpicker.NumberPickerDialogFragment;
import com.doomonafireball.betterpickers.radialtimepicker.RadialTimePickerDialog;
import com.doomonafireball.betterpickers.recurrencepicker.EventRecurrence;
import com.doomonafireball.betterpickers.recurrencepicker.RecurrencePickerDialog;
import com.google.ical.values.DateTimeValueImpl;
import com.google.ical.values.DateValue;
import com.google.ical.values.Frequency;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import es.usc.citius.servando.calendula.R;
import es.usc.citius.servando.calendula.activities.ScheduleCreationActivity;
import es.usc.citius.servando.calendula.database.DB;
import es.usc.citius.servando.calendula.fragments.dosePickers.DefaultDosePickerFragment;
import es.usc.citius.servando.calendula.fragments.dosePickers.DosePickerFragment;
import es.usc.citius.servando.calendula.fragments.dosePickers.LiquidDosePickerFragment;
import es.usc.citius.servando.calendula.fragments.dosePickers.PillDosePickerFragment;
import es.usc.citius.servando.calendula.persistence.Medicine;
import es.usc.citius.servando.calendula.persistence.Patient;
import es.usc.citius.servando.calendula.persistence.Presentation;
import es.usc.citius.servando.calendula.persistence.RepetitionRule;
import es.usc.citius.servando.calendula.persistence.Routine;
import es.usc.citius.servando.calendula.persistence.Schedule;
import es.usc.citius.servando.calendula.persistence.ScheduleItem;
import es.usc.citius.servando.calendula.persistence.ScheduleItemComparator;
import es.usc.citius.servando.calendula.util.ScheduleHelper;
/**
* Created by joseangel.pineiro on 12/11/13.
*/
public class ScheduleTimetableFragment extends Fragment
implements NumberPickerDialogFragment.NumberPickerDialogHandler,
RecurrencePickerDialog.OnRecurrenceSetListener, RadialTimePickerDialog.OnTimeSetListener {
public static final String TAG = ScheduleTimetableFragment.class.getName();
public static final int REF_DIALOG_HOURLY_INTERVAL = 1;
public static final int REF_DIALOG_ROUTINE_INTERVAL = 2;
public static final int REF_DIALOG_CYCLE_DAYS = 3;
public static final int REF_DIALOG_CYCLE_REST = 4;
final Frequency[] FREQ =
new Frequency[]{Frequency.DAILY, Frequency.WEEKLY, Frequency.MONTHLY};
LinearLayout timetableContainer;
int timesPerDay = 1;
int cycleDays = -1;
int cycleRest = -1;
Spinner scheduleSpinner;
Spinner repeatTypeSpinner;
Spinner freqSpinner;
ScheduleItemComparator scheduleItemComparator = new ScheduleItemComparator();
Button buttonScheduleStart;
Button buttonScheduleEnd;
Button intervalEditText;
Button hourlyIntervalEditText;
Button hourlyIntervalFrom;
Button hourlyIntervalRepeatDose;
Button periodValue;
Button periodRest;
ImageButton cycleSpinnerTrigger;
//RadioGroup scheduleTypeRadioGroup;
ImageButton clearStartButton;
ImageButton clearEndButton;
View daySelectionBox;
View customRepeatBox;
TextView ruleText;
Schedule schedule;
boolean ignoreNextEvent = true;
//View boxType;
View boxHourlyInterval;
View boxTimesByDay;
View boxTimetable;
View boxRepeat;
View boxPeriod;
View boxDuration;
View boxHelp;
TextView helpView;
ImageButton nextButton;
ScrollView scrollView;
private boolean isFirstScheduleSelection = true;
private int lastScheduleType = -1;
int color;
private Patient patient;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get schedule from state helper if any
schedule = ScheduleHelper.instance().getSchedule();
if (schedule == null) {
schedule = new Schedule();
ScheduleHelper.instance().setSchedule(schedule);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_schedule_timetable, container, false);
patient = DB.patients().getActive(getActivity());
color = patient.color();
scrollView = (ScrollView) rootView.findViewById(R.id.schedule_scroll);
timetableContainer =
(LinearLayout) rootView.findViewById(R.id.schedule_timetable_container);
boxHourlyInterval = rootView.findViewById(R.id.box_hourinterval);
boxTimesByDay = rootView.findViewById(R.id.box_schedule_times_by_day);
boxTimetable = rootView.findViewById(R.id.box_schedule_timetable);
boxRepeat = rootView.findViewById(R.id.box_schedule_repeat);
boxPeriod = rootView.findViewById(R.id.box_schedule_period);
boxDuration = rootView.findViewById(R.id.box_schedule_duration);
boxHelp = rootView.findViewById(R.id.box_schedule_help);
helpView = (TextView) rootView.findViewById(R.id.schedule_help_text);
nextButton = (ImageButton) rootView.findViewById(R.id.schedule_help_button);
hourlyIntervalEditText = (Button) rootView.findViewById(R.id.hourinterval_edit_text);
hourlyIntervalFrom = (Button) rootView.findViewById(R.id.hourinterval_from_text);
hourlyIntervalRepeatDose = (Button) rootView.findViewById(R.id.repeat_dose);
scheduleSpinner = (Spinner) rootView.findViewById(R.id.schedules_spinner);
buttonScheduleStart = (Button) rootView.findViewById(R.id.button_set_start);
buttonScheduleEnd = (Button) rootView.findViewById(R.id.button_set_end);
clearStartButton = (ImageButton) rootView.findViewById(R.id.button_clear_start);
clearEndButton = (ImageButton) rootView.findViewById(R.id.button_clear_end);
repeatTypeSpinner = (Spinner) rootView.findViewById(R.id.repeat_type_spinner);
periodValue = (Button) rootView.findViewById(R.id.period_value);
periodRest = (Button) rootView.findViewById(R.id.period_rest);
freqSpinner = (Spinner) rootView.findViewById(R.id.freq_spinner);
daySelectionBox = rootView.findViewById(R.id.day_selector_box);
customRepeatBox = rootView.findViewById(R.id.custom_repeat_box);
intervalEditText = (Button) rootView.findViewById(R.id.interval_edit_text);
ruleText = (TextView) rootView.findViewById(R.id.rule_text);
cycleSpinnerTrigger = (ImageButton) rootView.findViewById(R.id.cycles_spinner_trigger);
setupScheduleSpinner();
setupDaySelectionListeners(rootView);
setupHourlyRepetitionLinsteners();
setupStartEndDatePickers(rootView);
setupForCurrentSchedule(rootView);
setupCycleSpinner();
setupForCurrentSchedule(rootView);
updateColors(rootView);
return rootView;
}
private void updateColors(View rootView) {
int color = DB.patients().getActive(getActivity()).color();
((TextView)rootView.findViewById(R.id.textView3)).setTextColor(color);
((TextView)rootView.findViewById(R.id.textView2)).setTextColor(color);
(rootView.findViewById(R.id.imageView)).setBackgroundColor(color);
(rootView.findViewById(R.id.imageView1)).setBackgroundColor(color);
StateListDrawable sld = (StateListDrawable) rootView.findViewById(R.id.text_container).getBackground();
GradientDrawable shape = (GradientDrawable) sld.getCurrent();
shape.setColor(Color.parseColor("#ececec"));
hourlyIntervalEditText.setTextColor(color);
hourlyIntervalFrom.setTextColor(color);
hourlyIntervalRepeatDose.setTextColor(color);
buttonScheduleStart.setTextColor(color);
buttonScheduleEnd.setTextColor(color);
periodValue.setTextColor(color);
periodRest.setTextColor(color);
}
private void setupCycleSpinner() {
final String[] cycles = getResources().getStringArray(R.array.schedule_cycles);
cycleSpinnerTrigger.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
b.setTitle(R.string.schedule_type_common_periods);
b.setItems(cycles, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
String c = cycles[which];
String[] parts = c.replaceAll(" ", "").split("\\+");
periodValue.setText(parts[0]);
periodRest.setText(parts[1]);
schedule.setCycle(Integer.valueOf(parts[0]), Integer.valueOf(parts[1]));
}
});
b.show();
}
});
}
private void setupForCurrentSchedule(View rootView) {
if (schedule.getId() != null) {
setupForKnownSchedule(rootView);
} else {
setupForNewSchedule(rootView);
}
}
public void onTypeSelected() {
Log.d(TAG, "onTypeSelected");
if (getView() != null) {
Log.d(TAG, "getView() is not null");
setupForCurrentSchedule(getView());
}
}
private void updateHourlyIntervalBox() {
LocalTime t = schedule.startTime();
if (t == null) {
t = LocalTime.now().withMinuteOfHour(0);
schedule.setStartTime(t);
}
String time = new LocalTime(t.getHourOfDay(), t.getMinuteOfHour()).toString("kk:mm");
hourlyIntervalFrom.setText(getString(R.string.first_intake) + ": " + time);
if (schedule.rule().interval() < 1) {
schedule.rule().setInterval(8);
}
schedule.rule().setFrequency(Frequency.HOURLY);
hourlyIntervalEditText.setText(String.valueOf(schedule.rule().interval()));
hourlyIntervalRepeatDose.setText(schedule.displayDose());
}
private void setupForKnownSchedule(View rootView) {
int type = ScheduleHelper.instance().getScheduleType();
Log.d(TAG, "Setup for known schedule: " + type);
boxTimesByDay.setVisibility(View.GONE);
boxTimetable.setVisibility(View.GONE);
boxRepeat.setVisibility(View.GONE);
boxHourlyInterval.setVisibility(View.GONE);
boxHelp.setVisibility(View.GONE);
boxPeriod.setVisibility(View.GONE);
boxDuration.setVisibility(View.VISIBLE);
if (type == ScheduleTypeFragment.TYPE_ROUTINES) {
boxTimesByDay.setVisibility(View.VISIBLE);
boxTimetable.setVisibility(View.VISIBLE);
boxRepeat.setVisibility(View.VISIBLE);
timesPerDay = ScheduleHelper.instance().getTimesPerDay();
scheduleSpinner.setSelection(ScheduleHelper.instance().getSelectedScheduleIdx());
checkSelectedDays(rootView, schedule.days());
setupRepetitions(rootView);
updateRepeatTypeAndInterval(rootView);
} else if (type == ScheduleTypeFragment.TYPE_HOURLY) {
schedule.rule().setDays(Schedule.noWeekDays());
boxHourlyInterval.setVisibility(View.VISIBLE);
updateHourlyIntervalBox();
} else {
boxTimesByDay.setVisibility(View.VISIBLE);
boxTimetable.setVisibility(View.VISIBLE);
boxPeriod.setVisibility(View.VISIBLE);
updatePeriodSelector();
}
boxHelp.setVisibility(View.GONE);
}
private void setupForNewSchedule(View rootView) {
int type = ScheduleHelper.instance().getScheduleType();
Log.d(TAG, "Setup for new schedule: " + type);
boxTimesByDay.setVisibility(View.GONE);
boxTimetable.setVisibility(View.GONE);
boxRepeat.setVisibility(View.GONE);
boxDuration.setVisibility(View.GONE);
boxPeriod.setVisibility(View.GONE);
boxHourlyInterval.setVisibility(View.GONE);
boxHelp.setVisibility(View.VISIBLE);
if (type == ScheduleTypeFragment.TYPE_ROUTINES) {
boxTimesByDay.setVisibility(View.VISIBLE);
timesPerDay = ScheduleHelper.instance().getTimesPerDay();
scheduleSpinner.setSelection(ScheduleHelper.instance().getSelectedScheduleIdx());
checkSelectedDays(rootView, schedule.days());
setupRepetitions(rootView);
updateRepeatTypeAndInterval(rootView);
helpView.setText(getString(R.string.schedule_help_timesbyday));
} else if (type == ScheduleTypeFragment.TYPE_HOURLY) {
schedule.setType(Schedule.SCHEDULE_TYPE_HOURLY);
boxHourlyInterval.setVisibility(View.VISIBLE);
schedule.setDays(Schedule.noWeekDays());
updateHourlyIntervalBox();
helpView.setText(getString(R.string.schedule_help_hourly));
} else {
schedule.setType(Schedule.SCHEDULE_TYPE_CYCLE);
boxTimesByDay.setVisibility(View.VISIBLE);
timesPerDay = ScheduleHelper.instance().getTimesPerDay();
scheduleSpinner.setSelection(ScheduleHelper.instance().getSelectedScheduleIdx());
helpView.setText(getString(R.string.schedule_help_timesbyday));
updatePeriodSelector();
}
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showNext();
}
});
}
private void updatePeriodSelector() {
periodValue.setText(String.valueOf(schedule.getCycleDays()));
periodRest.setText(String.valueOf(schedule.getCycleRest()));
periodValue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NumberPickerBuilder npb =
new NumberPickerBuilder().setDecimalVisibility(NumberPicker.INVISIBLE)
.setMinNumber(1)
.setMaxNumber(100)
.setPlusMinusVisibility(NumberPicker.INVISIBLE)
.setFragmentManager(getChildFragmentManager())
.setTargetFragment(ScheduleTimetableFragment.this)
.setReference(REF_DIALOG_CYCLE_DAYS)
.setStyleResId(R.style.BetterPickersDialogFragment_Calendula);
npb.show();
}
});
periodRest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NumberPickerBuilder npb =
new NumberPickerBuilder().setDecimalVisibility(NumberPicker.INVISIBLE)
.setMinNumber(1)
.setMaxNumber(100)
.setPlusMinusVisibility(NumberPicker.INVISIBLE)
.setFragmentManager(getChildFragmentManager())
.setTargetFragment(ScheduleTimetableFragment.this)
.setReference(REF_DIALOG_CYCLE_REST)
.setStyleResId(R.style.BetterPickersDialogFragment_Calendula);
npb.show();
}
});
}
private void updateRepeatTypeAndInterval(View rootView) {
int repeatType = schedule.type();
setRepeatType(repeatType, rootView, true);
repeatTypeSpinner.setSelection(repeatType);
intervalEditText.setText(String.valueOf(schedule.rule().interval()));
}
private void showNext() {
int type = ScheduleHelper.instance().getScheduleType();
if (type == ScheduleTypeFragment.TYPE_ROUTINES) {
if (boxTimesByDay.getVisibility() != View.VISIBLE) {
helpView.setText(getString(R.string.schedule_help_timesbyday));
boxTimesByDay.setVisibility(View.VISIBLE);
boxHourlyInterval.setVisibility(View.INVISIBLE);
} else if (boxTimetable.getVisibility() != View.VISIBLE) {
helpView.setText(getString(R.string.schedule_help_timetable));
showBox(boxTimetable);
} else if (boxRepeat.getVisibility() != View.VISIBLE) {
helpView.setText(getString(R.string.schedule_help_repeat));
showBox(boxRepeat);
} else if (boxDuration.getVisibility() != View.VISIBLE) {
helpView.setText(getString(R.string.schedule_help_duration));
showBox(boxDuration);
nextButton.setVisibility(View.GONE);
}
} else if (type == ScheduleTypeFragment.TYPE_HOURLY) {
if (boxHourlyInterval.getVisibility() != View.VISIBLE) {
boxHourlyInterval.setVisibility(View.VISIBLE);
boxTimesByDay.setVisibility(View.INVISIBLE);
helpView.setText(getString(R.string.schedule_help_hourly));
} else if (boxDuration.getVisibility() != View.VISIBLE) {
helpView.setText(getString(R.string.schedule_help_duration));
showBox(boxDuration);
nextButton.setVisibility(View.GONE);
}
} else if (type == ScheduleTypeFragment.TYPE_PERIOD) {
if (boxTimesByDay.getVisibility() != View.VISIBLE) {
helpView.setText(getString(R.string.schedule_help_timesbyday));
boxTimesByDay.setVisibility(View.VISIBLE);
boxHourlyInterval.setVisibility(View.INVISIBLE);
} else if (boxTimetable.getVisibility() != View.VISIBLE) {
helpView.setText(getString(R.string.schedule_help_timetable));
showBox(boxTimetable);
} else if (boxPeriod.getVisibility() != View.VISIBLE) {
helpView.setText(getString(R.string.schedule_help_cycle));
showBox(boxPeriod);
} else if (boxDuration.getVisibility() != View.VISIBLE) {
helpView.setText(getString(R.string.schedule_help_duration));
showBox(boxDuration);
nextButton.setVisibility(View.GONE);
}
}
}
private void showBox(final View v) {
v.setVisibility(View.VISIBLE);
Animation a = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_scheule_box_slide_up);
scrollView.postDelayed(new Runnable() {
@Override
public void run() {
scrollView.smoothScrollBy(0, 1000); // ensure scroll bottom
}
}, 200);
a.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
v.startAnimation(a);
}
void setupHourlyRepetitionLinsteners() {
hourlyIntervalEditText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showHourlyPickerDIalog();
}
});
hourlyIntervalFrom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DateTime time = schedule.startTime().toDateTimeToday();
RadialTimePickerDialog timePickerDialog =
RadialTimePickerDialog.newInstance(ScheduleTimetableFragment.this,
time.getHourOfDay(), time.getMinuteOfHour(), true);
timePickerDialog.show(getChildFragmentManager(), "111");
}
});
hourlyIntervalRepeatDose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showHourlyDosePickerDialog();
}
});
}
private void setupRepetitions(final View rooView) {
ruleText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showRecurrencePickerDialog();
}
});
repeatTypeSpinner.setAdapter(
new ArrayAdapter<>(getActivity(), R.layout.support_simple_spinner_dropdown_item,
getResources().getStringArray(R.array.schedule_repeat_types)));
repeatTypeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
setRepeatType(position, rooView, !ignoreNextEvent);
ignoreNextEvent = false;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
freqSpinner.setAdapter(
new ArrayAdapter<>(getActivity(), R.layout.support_simple_spinner_dropdown_item,
getResources().getStringArray(R.array.schedule_repeat_frequency_units)));
freqSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
setFrequency(position, rooView);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
intervalEditText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showIntervalPickerDIalog();
}
});
}
void setupStartEndDatePickers(View rootView) {
if (schedule.start() == null) {
schedule.setStart(LocalDate.now());
}
final LocalDate scheduleStart = schedule.start();
buttonScheduleStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DatePickerDialog dpd =
new DatePickerDialog(getActivity(), new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
Log.d(TAG, year + " " + monthOfYear);
LocalDate d = new LocalDate(year, monthOfYear + 1, dayOfMonth);
setScheduleStart(d);
}
}, scheduleStart.getYear(), scheduleStart.getMonthOfYear() - 1,
scheduleStart.getDayOfMonth());
dpd.show();
}
});
buttonScheduleEnd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LocalDate scheduleEnd =
schedule.end() != null ? schedule.end() : scheduleStart.plusMonths(3);
DatePickerDialog dpd =
new DatePickerDialog(getActivity(), new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
LocalDate d = new LocalDate(year, monthOfYear + 1, dayOfMonth);
setScheduleEnd(d);
}
}, scheduleEnd.getYear(), scheduleEnd.getMonthOfYear() - 1,
scheduleEnd.getDayOfMonth());
dpd.show();
}
});
buttonScheduleEnd.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Do you want this schedule to continue indefinitely?")
.setCancelable(true)
.setPositiveButton(getString(R.string.dialog_yes_option),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
setScheduleEnd(null);
}
})
.setNegativeButton(getString(R.string.dialog_no_option),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
return true;
}
});
clearStartButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setScheduleStart(null);
}
});
clearEndButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setScheduleEnd(null);
}
});
setScheduleStart(schedule.start());
setScheduleEnd(schedule.end());
}
private void setFrequency(int freq, View rootView) {
if (ScheduleHelper.instance().getScheduleType() == ScheduleTypeFragment.TYPE_ROUTINES) {
Frequency frequency = FREQ[freq];
schedule.rule().setFrequency(frequency);
if (frequency == Frequency.WEEKLY) {
int dayCount = schedule.dayCount();
if (dayCount == 0 || dayCount == 7) {
checkToday(rootView);
}
daySelectionBox.setVisibility(View.VISIBLE);
} else {
schedule.rule().setDays(null);
daySelectionBox.setVisibility(View.GONE);
}
}
}
private void setRepeatType(int type, View v, boolean updateUi) {
if (ScheduleHelper.instance().getScheduleType() == ScheduleTypeFragment.TYPE_ROUTINES) {
schedule.setType(type);
if (updateUi) {
//resetRule();
if (type == Schedule.SCHEDULE_TYPE_EVERYDAY) {
daySelectionBox.setVisibility(View.VISIBLE);
customRepeatBox.setVisibility(View.GONE);
ruleText.setVisibility(View.GONE);
schedule.rule().setInterval(0);
schedule.rule().setFrequency(Frequency.DAILY);
checkAllDays(v);
} else if (type == Schedule.SCHEDULE_TYPE_SOMEDAYS) {
daySelectionBox.setVisibility(View.VISIBLE);
customRepeatBox.setVisibility(View.GONE);
ruleText.setVisibility(View.GONE);
// Interval
schedule.rule().setInterval(0);
// frequency
schedule.rule().setFrequency(Frequency.DAILY);
// byday
if (schedule.dayCount() == 7 || schedule.dayCount() == 0) {
checkToday(v);
} else {
checkSelectedDays(v, schedule.days());
}
} else if (type == Schedule.SCHEDULE_TYPE_INTERVAL) {
ruleText.setVisibility(View.GONE);
customRepeatBox.setVisibility(View.VISIBLE);
int interval = schedule.rule().interval();
if (interval < 2) {
interval = 2;
}
schedule.rule().setInterval(interval);
intervalEditText.setText(String.valueOf(schedule.rule().interval()));
Frequency f = schedule.rule().frequency();
if (f.equals(Frequency.WEEKLY)) {
freqSpinner.setSelection(1);
setFrequency(1, v);
} else if (f.equals(Frequency.MONTHLY)) {
freqSpinner.setSelection(2);
setFrequency(2, v);
} else {
freqSpinner.setSelection(0);
setFrequency(0, v);
}
}
}
}
}
private Spanned getCurrentSchedule() {
String text =
getString(R.string.schedule_custom_rule_text, schedule.toReadableString(getActivity()));
int count = schedule.rule().iCalRule().getCount();
if (count > 0) {
text += "<br><u>" + getString(R.string.schedules_stop_after, count) + "</u>";
}
return Html.fromHtml(text);
}
private void checkAllDays(View v) {
checkSelectedDays(v, Schedule.allWeekDays());
}
private void checkToday(View v) {
boolean[] days = Schedule.noWeekDays();
days[LocalDate.now().getDayOfWeek() - 1] = true;
checkSelectedDays(v, days);
}
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
}
private void setupScheduleSpinner() {
// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter<CharSequence> adapter =
ArrayAdapter.createFromResource(getActivity(), R.array.schedules_array,
R.layout.spinner_text_item);
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
// Apply the adapter to the spinner
scheduleSpinner.setAdapter(adapter);
scheduleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
String selected = (String) adapterView.getItemAtPosition(i);
onScheduleSelected(selected, i);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
void onScheduleSelected(String selection, int index) {
ScheduleHelper.instance().setSelectedScheduleIdx(index);
String schedules[] = getResources().getStringArray(R.array.schedules_array);
// obtain times per day from selected schedule
for (int i = 0; i < schedules.length; i++) {
if (schedules[i].equalsIgnoreCase(selection)) {
timesPerDay = i + 1;
ScheduleHelper.instance().setTimesPerDay(timesPerDay);
break;
}
}
addTimetableEntries(timesPerDay, DB.routines().findAllForActivePatient(getContext()));
}
void setupDaySelectionListeners(final View rootView) {
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
TextView text = ((TextView) view);
int index;
switch (text.getId()) {
case R.id.day_mo:
schedule.toggleSelectedDay(0);
index = 0;
break;
case R.id.day_tu:
schedule.toggleSelectedDay(1);
index = 1;
break;
case R.id.day_we:
schedule.toggleSelectedDay(2);
index = 2;
break;
case R.id.day_th:
index = 3;
schedule.toggleSelectedDay(3);
break;
case R.id.day_fr:
schedule.toggleSelectedDay(4);
index = 4;
break;
case R.id.day_sa:
schedule.toggleSelectedDay(5);
index = 5;
break;
case R.id.day_su:
schedule.toggleSelectedDay(6);
index = 6;
break;
default:
return;
}
boolean daySelected = schedule.days()[index];
StateListDrawable sld = (StateListDrawable) text.getBackground();
GradientDrawable shape = (GradientDrawable) sld.getCurrent();
shape.setColor(daySelected ? color : Color.WHITE);
text.setTypeface(null, daySelected ? Typeface.BOLD : Typeface.NORMAL);
text.setTextColor(daySelected ? Color.WHITE : Color.BLACK);
boolean allDaysSelected = schedule.allDaysSelected();
if (schedule.type() == Schedule.SCHEDULE_TYPE_EVERYDAY && !allDaysSelected) {
setRepeatType(Schedule.SCHEDULE_TYPE_SOMEDAYS, rootView, false);
ignoreNextEvent = true;
repeatTypeSpinner.setSelection(1);
} else if (schedule.type() == Schedule.SCHEDULE_TYPE_SOMEDAYS && allDaysSelected) {
repeatTypeSpinner.setSelection(0);
schedule.setType(Schedule.SCHEDULE_TYPE_EVERYDAY);
}
Log.d(TAG, "All days selected: " + allDaysSelected + ", repeatType: " + schedule.type());
}
};
rootView.findViewById(R.id.day_mo).setOnClickListener(listener);
rootView.findViewById(R.id.day_tu).setOnClickListener(listener);
rootView.findViewById(R.id.day_we).setOnClickListener(listener);
rootView.findViewById(R.id.day_th).setOnClickListener(listener);
rootView.findViewById(R.id.day_fr).setOnClickListener(listener);
rootView.findViewById(R.id.day_sa).setOnClickListener(listener);
rootView.findViewById(R.id.day_su).setOnClickListener(listener);
}
void showIntervalPickerDIalog() {
NumberPickerBuilder npb =
new NumberPickerBuilder().setDecimalVisibility(NumberPicker.INVISIBLE)
.setMinNumber(1)
.setMaxNumber(31)
.setPlusMinusVisibility(NumberPicker.INVISIBLE)
.setFragmentManager(getChildFragmentManager())
.setTargetFragment(this).setReference(REF_DIALOG_ROUTINE_INTERVAL)
.setStyleResId(R.style.BetterPickersDialogFragment_Calendula);
npb.show();
}
void showHourlyPickerDIalog() {
/*NumberPickerBuilder npb =
new NumberPickerBuilder().setDecimalVisibility(NumberPicker.INVISIBLE)
.setMinNumber(1)
.setMaxNumber(24)
.setPlusMinusVisibility(NumberPicker.INVISIBLE)
.setFragmentManager(getChildFragmentManager())
.setTargetFragment(this)
.setReference(REF_DIALOG_HOURLY_INTERVAL)
.setStyleResId(R.style.BetterPickersDialogFragment_Calendula);
npb.show();*/
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
b.setTitle(getString(R.string.dialog_interval_title));
final String[] types = {"2", "3", "4", "6", "8", "12"};
b.setItems(types, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
int result = Integer.valueOf(types[which]);
hourlyIntervalEditText.setText("" + result);
schedule.rule().setFrequency(Frequency.HOURLY);
schedule.rule().setInterval(result);
}
});
b.show();
}
void showRecurrencePickerDialog() {
RecurrencePickerDialog dialog = new RecurrencePickerDialog();
DateTime start = schedule.start() != null ? schedule.start().toDateTimeAtStartOfDay()
: DateTime.now().withTimeAtStartOfDay();
Bundle b = new Bundle();
b.putString(RecurrencePickerDialog.BUNDLE_RRULE,
schedule.rule().toIcal().replace("RRULE:", ""));
b.putLong(RecurrencePickerDialog.BUNDLE_START_TIME_MILLIS, DateTime.now().getMillis());
//b.putString(RecurrencePickerDialog.BUNDLE_TIME_ZONE, t.timezone);
dialog.setArguments(b);
dialog.setOnRecurrenceSetListener(this);
dialog.show(getChildFragmentManager(), "REC");
}
void addTimetableEntries(int timesPerDay, List<Routine> routines) {
Collections.sort(ScheduleHelper.instance().getScheduleItems(), scheduleItemComparator);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
String[] routineNames = getUpdatedRoutineNames();
timetableContainer.removeAllViews();
List<ScheduleItem> scheduleItems = new ArrayList<ScheduleItem>();
boolean enableDelete = timesPerDay > 1;
for (int i = 0; i < timesPerDay; i++) {
// try to get previous routine from state holder
ScheduleItem s;
if (i < ScheduleHelper.instance().getScheduleItems().size()) {
ScheduleItem toCopy = ScheduleHelper.instance().getScheduleItems().get(i);
s = new ScheduleItem(null, toCopy.routine(), toCopy.dose());
} else {
s = new ScheduleItem(null, (i < routines.size()) ? routines.get(i) : null, 1);
}
if (s != null) {
scheduleItems.add(s);
}
View view = buildTimetableEntry(s, routineNames, enableDelete);
timetableContainer.addView(view, params);
}
ScheduleHelper.instance().setScheduleItems(scheduleItems);
// for (ScheduleItem i : ScheduleCreationHelper.instance().getScheduleItems())
// Log.d(TAG, "addTimetableEntries (end): " + i.getId() + ", " + i.routine().name() + ", " + i.dose());
}
String[] getUpdatedRoutineNames() {
List<Routine> routines = DB.routines().findAllForActivePatient(getContext());
int j = 0;
String[] routineNames = new String[routines.size() + 1];
for (Routine r : routines) {
routineNames[j++] = r.name();
}
routineNames[routineNames.length - 1] = getString(R.string.create_new_routine);
return routineNames;
}
View buildTimetableEntry(ScheduleItem r, String[] routineNames, boolean enableDelete) {
LayoutInflater inflater = getActivity().getLayoutInflater();
final View entry = inflater.inflate(R.layout.schedule_timetable_entry, null);
updateEntryTime(r.routine(), entry);
setupScheduleEntrySpinners(entry, r, routineNames);
if (enableDelete) {
entry.findViewById(R.id.entry_remove).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ScheduleHelper.instance()
.getScheduleItems()
.remove(timetableContainer.indexOfChild(entry));
scheduleSpinner.setSelection(timesPerDay - 2);
}
});
} else {
entry.findViewById(R.id.entry_remove).setVisibility(View.INVISIBLE);
}
return entry;
}
void updateRoutineSelectionAdapter(final View entryView, Spinner routineSpinner,
String[] routineNames) {
ArrayAdapter<String> routineAdapter =
new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_item,
routineNames);
routineAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
routineSpinner.setAdapter(routineAdapter);
}
private void setupScheduleEntrySpinners(final View entryView, ScheduleItem scheduleItem,
String[] routineNames) {
final Spinner routineSpinner = (Spinner) entryView.findViewById(R.id.entry_routine_spinner);
final TextView doseTv = (TextView) entryView.findViewById(R.id.entry_dose_textview);
// final Spinner doseSpinner = (Spinner) entryView.findViewById(R.id.entry_dose_spinner);
doseTv.setTag(scheduleItem);
routineSpinner.setTag(scheduleItem);
// set up the routine selection adapter
updateRoutineSelectionAdapter(entryView, routineSpinner, routineNames);
if (scheduleItem != null && scheduleItem.routine() != null) {
String routineName = scheduleItem.routine().name();
int index = Arrays.asList(routineNames).indexOf(routineName);
routineSpinner.setSelection(index);
} else {
routineSpinner.setSelection(routineNames.length - 1);
}
doseTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDosePickerDialog((ScheduleItem) v.getTag(), (TextView) v);
}
});
// set up the dose selection adapter
// ArrayAdapter<String> doseAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_item, doses);
// doseAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
// doseSpinner.setAdapter(doseAdapter);
// select 1 pill by default
// doseSpinner.setSelection((int) scheduleItem.dose() - 1); // dose "1" is located at the index "0", and so on
doseTv.setText(scheduleItem.displayDose());
// setup listeners
routineSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
String selected = (String) adapterView.getItemAtPosition(i);
Routine r = DB.routines().findByPatientAndName(selected, patient);
ScheduleItem item = ((ScheduleItem) routineSpinner.getTag());
if (r != null) {
updateEntryTime(r, entryView);
} else {
updateEntryTime(null, entryView);
showAddNewRoutineDialog(entryView);
}
Log.d(TAG, "Updated routine to "
+ (r != null ? r.name() : "NULL")
+ " on item "
+ item.getId());
item.setRoutine(r);
logScheduleItems();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
routineSpinner.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
if (((String) routineSpinner.getSelectedItem()).equalsIgnoreCase(
getString(R.string.create_new_routine))) {
showAddNewRoutineDialog(entryView);
return true;
}
}
return false;
}
});
}
private void logScheduleItems() {
for (ScheduleItem si : ScheduleHelper.instance().getScheduleItems()) {
Log.d("TAG", (si.routine() != null ? si.routine().name() : "NONE")
+ ", "
+ si.dose()
+ " ****************************");
}
}
void updateEntryTime(Routine r, View entry) {
String hourText;
String minuteText;
if (r != null) {
hourText = (r.time().getHourOfDay() < 10 ? "0" + r.time().getHourOfDay()
: r.time().getHourOfDay()) + ":";
minuteText = (r.time().getMinuteOfHour() < 10 ? "0" + r.time().getMinuteOfHour()
: r.time().getMinuteOfHour()) + "";
} else {
hourText = "--:";
minuteText = "--";
}
TextView h =((TextView) entry.findViewById(R.id.hour_text));
TextView m = ((TextView) entry.findViewById(R.id.minute_text));
h.setText(hourText);
m.setText(minuteText);
h.setTextColor(color);
m.setTextColor(color);
}
void showAddNewRoutineDialog(final View entryView) {
FragmentManager fm = getActivity().getSupportFragmentManager();
final RoutineCreateOrEditFragment addRoutineFragment = new RoutineCreateOrEditFragment();
addRoutineFragment.setOnRoutineEditListener(
new RoutineCreateOrEditFragment.OnRoutineEditListener() {
@Override
public void onRoutineEdited(Routine r) {
// do nothing
}
@Override
public void onRoutineDeleted(Routine r) {
// do nothing
}
@Override
public void onRoutineCreated(final Routine r) {
Spinner rSpinner = (Spinner) entryView.findViewById(R.id.entry_routine_spinner);
String names[] = getUpdatedRoutineNames();
updateRoutineSelectionAdapter(entryView, rSpinner, names);
Log.d(TAG, "Routine name: " + r.name());
Log.d(TAG, "Routine time: " + r.time().toString("hh:mm"));
Log.d(TAG, "Names: " + Arrays.toString(names));
int selection = Arrays.asList(names).indexOf(r.name());
rSpinner.setSelection(selection);
updateEntryTime(r, entryView);
addRoutineFragment.dismiss();
}
});
addRoutineFragment.show(fm, "fragment_edit_name");
}
private DosePickerFragment getDosePickerFragment(Medicine med, ScheduleItem item, Schedule s) {
DosePickerFragment dpf = null;
Bundle arguments = new Bundle();
// if (med.presentation().equals(Presentation.SYRUP)) {
// dpf = new LiquidDosePickerFragment();
// }
if (med.presentation().equals(Presentation.DROPS)
|| med.presentation().equals(Presentation.PILLS)
|| med.presentation().equals(Presentation.CAPSULES)
|| med.presentation().equals(Presentation.EFFERVESCENT)){
dpf = new PillDosePickerFragment();
}else{
dpf = new DefaultDosePickerFragment();
arguments.putSerializable("presentation", med.presentation());
}
if(item != null){
arguments.putDouble("dose", item.dose());
}else if(s != null) {
arguments.putDouble("dose", s.dose());
}
dpf.setArguments(arguments);
return dpf;
}
void showDosePickerDialog(final ScheduleItem item, final TextView tv) {
Medicine med = ScheduleHelper.instance().getSelectedMed();
if(med == null){
((ScheduleCreationActivity)getActivity()).onDoseSelectedWithNoMed();
return;
}
final DosePickerFragment dpf = getDosePickerFragment(med,item,null);
if(dpf != null){
FragmentManager fm = getActivity().getSupportFragmentManager();
dpf.setOnDoseSelectedListener(
new LiquidDosePickerFragment.OnDoseSelectedListener() {
@Override
public void onDoseSelected(double dose) {
Log.d(TAG, "Set dose "
+ dose
+ " to item "
+ item.routine().name()
+ ", "
+ item.getId());
item.setDose((float) dose);
tv.setText(item.displayDose());
logScheduleItems();
}
});
dpf.show(fm, "fragment_select_dose");
}
}
void showHourlyDosePickerDialog() {
Medicine med = ScheduleHelper.instance().getSelectedMed();
if(med == null){
// TODO: get from resources and use snack.show()
Toast.makeText(getActivity(), "Por favor, selecciona un medicamento antes", Toast.LENGTH_LONG).show();
return;
}
final DosePickerFragment dpf = getDosePickerFragment(med,null,schedule);
if(dpf != null){
FragmentManager fm = getActivity().getSupportFragmentManager();
dpf.setOnDoseSelectedListener(
new LiquidDosePickerFragment.OnDoseSelectedListener() {
@Override
public void onDoseSelected(double dose) {
schedule.setDose((float) dose);
hourlyIntervalRepeatDose.setText(schedule.displayDose());
}
});
dpf.show(fm, "fragment_select_dose");
}else{
}
}
void checkSelectedDays(View rootView, boolean[] days) {
Log.d(TAG, "Checking selected days: " + Arrays.toString(days));
schedule.setDays(days);
TextView mo = ((TextView) rootView.findViewById(R.id.day_mo));
TextView tu = ((TextView) rootView.findViewById(R.id.day_tu));
TextView we = ((TextView) rootView.findViewById(R.id.day_we));
TextView th = ((TextView) rootView.findViewById(R.id.day_th));
TextView fr = ((TextView) rootView.findViewById(R.id.day_fr));
TextView sa = ((TextView) rootView.findViewById(R.id.day_sa));
TextView su = ((TextView) rootView.findViewById(R.id.day_su));
TextView [] daysTvs = new TextView[]{mo, tu, we, th, fr, sa, su};
for(int i = 0; i < daysTvs.length; i++){
boolean isSelected = days[i];
StateListDrawable sld = (StateListDrawable) daysTvs[i].getBackground();
GradientDrawable shape = (GradientDrawable) sld.getCurrent();
shape.setColor(isSelected ? color : Color.WHITE);
daysTvs[i].setTypeface(null, isSelected ? Typeface.BOLD : Typeface.NORMAL);
daysTvs[i].setTextColor(isSelected ? Color.WHITE : Color.BLACK);
}
}
@Override
public void onDialogNumberSet(int reference, int number, double decimal, boolean isNegative,
double fullNumber) {
if (reference == REF_DIALOG_ROUTINE_INTERVAL) {
intervalEditText.setText("" + number);
schedule.rule().setInterval(number);
} else if (reference == REF_DIALOG_HOURLY_INTERVAL) {
hourlyIntervalEditText.setText("" + number);
schedule.rule().setFrequency(Frequency.HOURLY);
schedule.rule().setInterval(number);
} else if (reference == REF_DIALOG_CYCLE_DAYS) {
periodValue.setText(String.valueOf(number));
cycleDays = number;
if (cycleRest > 0) {
schedule.setCycle(cycleDays, cycleRest);
}
} else if (reference == REF_DIALOG_CYCLE_REST) {
periodRest.setText(String.valueOf(number));
cycleRest = number;
if (cycleDays > 0) {
schedule.setCycle(cycleDays, cycleRest);
}
}
}
@Override
public void onTimeSet(RadialTimePickerDialog radialTimePickerDialog, int hour,
int minute) {
String time = new LocalTime(hour, minute).toString("kk:mm");
hourlyIntervalFrom.setText(getString(R.string.first_intake) + ": " + time);
schedule.setStartTime(new LocalTime(hour, minute));
}
@Override
public void onRecurrenceSet(String s) {
EventRecurrence event = new EventRecurrence();
LocalDate now = LocalDate.now();
Time startDate = new Time(Time.getCurrentTimezone());
startDate.set(now.getDayOfMonth(), now.getMonthOfYear(), now.getYear());
startDate.normalize(true);
event.parse(s);
event.setStartDate(startDate);
Log.d(TAG, "OnRecurrenceSet: " + event.startDate);
schedule.setRepetition(new RepetitionRule("RRULE:" + s));
setScheduleStart(schedule.start());
LocalDate end = schedule.end();
Log.d(TAG, "ICAL: " + schedule.rule().toIcal());
setScheduleEnd(end);
Log.d(TAG, "ICAL: " + schedule.rule().toIcal());
ruleText.setText(getCurrentSchedule());
}
void setScheduleStart(LocalDate start) {
schedule.setStart(start);
if (start == null) {
buttonScheduleStart.setText(getString(R.string.button_schedule_repeat_today));
clearStartButton.setVisibility(View.INVISIBLE);
} else {
buttonScheduleStart.setText(
start.toString(getString(R.string.schedule_limits_date_format)));
clearStartButton.setVisibility(View.VISIBLE);
}
}
void setScheduleEnd(LocalDate end) {
if (end == null) {
buttonScheduleEnd.setText(getString(R.string.never));
schedule.rule().iCalRule().setUntil(null);
clearEndButton.setVisibility(View.INVISIBLE);
} else {
DateValue v =
new DateTimeValueImpl(end.getYear(), end.getMonthOfYear(), end.getDayOfMonth(), 0,
0, 0);
schedule.rule().iCalRule().setUntil(v);
buttonScheduleEnd.setText(
end.toString(getString(R.string.schedule_limits_date_format)));
clearEndButton.setVisibility(View.VISIBLE);
}
}
}