diff --git a/app/src/androidTest/java/org/isoron/uhabits/espresso/MainActivityActions.java b/app/src/androidTest/java/org/isoron/uhabits/espresso/MainActivityActions.java index c03e9c9db..2fdd59c19 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/espresso/MainActivityActions.java +++ b/app/src/androidTest/java/org/isoron/uhabits/espresso/MainActivityActions.java @@ -182,7 +182,7 @@ public class MainActivityActions try { - onView(allOf(withId(R.id.sFrequency), + onView(allOf(withId(R.id.spinner), withEffectiveVisibility(VISIBLE))).perform(click()); onData(allOf(instanceOf(String.class), startsWith("Custom"))) .inRoot(isPlatformPopup()) @@ -193,7 +193,7 @@ public class MainActivityActions // ignored } - onView(withId(R.id.tvFreqNum)).perform(replaceText(num)); - onView(withId(R.id.tvFreqDen)).perform(replaceText(den)); + onView(withId(R.id.numerator)).perform(replaceText(num)); + onView(withId(R.id.denominator)).perform(replaceText(den)); } } diff --git a/app/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.java b/app/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.java index 792e403f7..08b754df7 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.java +++ b/app/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.java @@ -26,6 +26,7 @@ import android.support.v7.app.AlertDialog; import android.support.v7.app.*; import org.isoron.uhabits.*; +import org.isoron.uhabits.models.*; import org.isoron.uhabits.utils.*; /** @@ -35,7 +36,6 @@ public class WeekdayPickerDialog extends AppCompatDialogFragment implements DialogInterface.OnMultiChoiceClickListener, DialogInterface.OnClickListener { - private boolean[] selectedDays; private OnWeekdaysPickedListener listener; @@ -49,7 +49,8 @@ public class WeekdayPickerDialog extends AppCompatDialogFragment implements @Override public void onClick(DialogInterface dialog, int which) { - if (listener != null) listener.onWeekdaysPicked(selectedDays); + if (listener != null) + listener.onWeekdaysSet(new WeekdayList(selectedDays)); } @Override @@ -73,13 +74,13 @@ public class WeekdayPickerDialog extends AppCompatDialogFragment implements this.listener = listener; } - public void setSelectedDays(boolean[] selectedDays) + public void setSelectedDays(WeekdayList days) { - this.selectedDays = selectedDays; + this.selectedDays = days.toArray(); } public interface OnWeekdaysPickedListener { - void onWeekdaysPicked(boolean[] selectedDays); + void onWeekdaysSet(WeekdayList days); } } diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BaseDialogHelper.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BaseDialogHelper.java deleted file mode 100644 index 4712c8961..000000000 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BaseDialogHelper.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2016 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker 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. - * - * Loop Habit Tracker 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 program. If not, see . - */ - -package org.isoron.uhabits.activities.habits.edit; - -import android.annotation.*; -import android.support.annotation.*; -import android.support.v4.app.*; -import android.view.*; -import android.widget.*; - -import org.isoron.uhabits.R; -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.utils.*; - -import butterknife.*; - -public class BaseDialogHelper -{ - private DialogFragment frag; - - @BindView(R.id.tvName) - TextView tvName; - - @BindView(R.id.tvDescription) - TextView tvDescription; - - @Nullable - @BindView(R.id.tvFreqNum) - TextView tvFreqNum; - - @Nullable - @BindView(R.id.tvFreqDen) - TextView tvFreqDen; - - @BindView(R.id.tvReminderTime) - TextView tvReminderTime; - - @BindView(R.id.tvReminderDays) - TextView tvReminderDays; - - @Nullable - @BindView(R.id.sFrequency) - Spinner sFrequency; - - @Nullable - @BindView(R.id.llCustomFrequency) - ViewGroup llCustomFrequency; - - @BindView(R.id.llReminderDays) - ViewGroup llReminderDays; - - public BaseDialogHelper(DialogFragment frag, View view) - { - this.frag = frag; - ButterKnife.bind(this, view); - } - - protected void populateForm(final Habit habit) - { - tvName.setText(habit.getName()); - tvDescription.setText(habit.getDescription()); - - populateColor(habit.getColor()); - populateFrequencyFields(habit); - populateReminderFields(habit); - } - - void parseFormIntoHabit(Habit habit) - { - habit.setName(tvName.getText().toString().trim()); - habit.setDescription(tvDescription.getText().toString().trim()); - - if (tvFreqDen != null && tvFreqNum != null) - { - String freqNum = tvFreqNum.getText().toString(); - String freqDen = tvFreqDen.getText().toString(); - if (!freqNum.isEmpty() && !freqDen.isEmpty()) - { - int numerator = Integer.parseInt(freqNum); - int denominator = Integer.parseInt(freqDen); - habit.setFrequency(new Frequency(numerator, denominator)); - } - } - } - - void populateColor(int paletteColor) - { - tvName.setTextColor( - ColorUtils.getColor(frag.getContext(), paletteColor)); - } - - @SuppressLint("SetTextI18n") - void populateFrequencyFields(Habit habit) - { - if (tvFreqNum == null) return; - if (tvFreqDen == null) return; - - int quickSelectPosition = -1; - - Frequency freq = habit.getFrequency(); - - if (freq.equals(Frequency.DAILY)) quickSelectPosition = 0; - - else if (freq.equals(Frequency.WEEKLY)) quickSelectPosition = 1; - - else if (freq.equals(Frequency.TWO_TIMES_PER_WEEK)) - quickSelectPosition = 2; - - else if (freq.equals(Frequency.FIVE_TIMES_PER_WEEK)) - quickSelectPosition = 3; - - if (quickSelectPosition >= 0) - showSimplifiedFrequency(quickSelectPosition); - - else showCustomFrequency(); - - tvFreqNum.setText(Integer.toString(freq.getNumerator())); - tvFreqDen.setText(Integer.toString(freq.getDenominator())); - } - - @SuppressWarnings("ConstantConditions") - void populateReminderFields(Habit habit) - { - if (!habit.hasReminder()) - { - tvReminderTime.setText(R.string.reminder_off); - llReminderDays.setVisibility(View.GONE); - return; - } - - Reminder reminder = habit.getReminder(); - - String time = - DateUtils.formatTime(frag.getContext(), reminder.getHour(), - reminder.getMinute()); - tvReminderTime.setText(time); - llReminderDays.setVisibility(View.VISIBLE); - - boolean weekdays[] = reminder.getDays().toArray(); - tvReminderDays.setText( - DateUtils.formatWeekdayList(frag.getContext(), weekdays)); - } - - private void showCustomFrequency() - { - if(sFrequency == null) return; - if(llCustomFrequency == null) return; - - sFrequency.setVisibility(View.GONE); - llCustomFrequency.setVisibility(View.VISIBLE); - } - - @SuppressLint("SetTextI18n") - private void showSimplifiedFrequency(int quickSelectPosition) - { - if(sFrequency == null) return; - if(llCustomFrequency == null) return; - - sFrequency.setVisibility(View.VISIBLE); - sFrequency.setSelection(quickSelectPosition); - llCustomFrequency.setVisibility(View.GONE); - } - - boolean validate(Habit habit) - { - Boolean valid = true; - - if (habit.getName().length() == 0) - { - tvName.setError( - frag.getString(R.string.validation_name_should_not_be_blank)); - valid = false; - } - - Frequency freq = habit.getFrequency(); - if (tvFreqNum != null && tvFreqDen != null) - { - if (freq.getNumerator() <= 0) - { - tvFreqNum.setError(frag.getString( - R.string.validation_number_should_be_positive)); - valid = false; - } - - if (freq.getNumerator() > freq.getDenominator()) - { - tvFreqNum.setError(frag.getString( - R.string.validation_at_most_one_rep_per_day)); - valid = false; - } - } - - return valid; - } -} diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BooleanHabitDialog.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BooleanHabitDialog.java index a2751ddc2..6a70e2815 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BooleanHabitDialog.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BooleanHabitDialog.java @@ -31,24 +31,20 @@ import org.isoron.uhabits.*; import org.isoron.uhabits.R; import org.isoron.uhabits.activities.*; import org.isoron.uhabits.activities.common.dialogs.*; +import org.isoron.uhabits.activities.habits.edit.views.*; import org.isoron.uhabits.commands.*; import org.isoron.uhabits.models.*; import org.isoron.uhabits.preferences.*; -import java.util.*; - import butterknife.*; public abstract class BooleanHabitDialog extends AppCompatDialogFragment { - @Nullable protected Habit originalHabit; - @Nullable protected Habit modifiedHabit; - @Nullable - protected BaseDialogHelper helper; + protected BooleanHabitDialogHelper helper; protected Preferences prefs; @@ -83,7 +79,8 @@ public abstract class BooleanHabitDialog extends AppCompatDialogFragment ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.edit_boolean_habit, container, false); + View view = + inflater.inflate(R.layout.edit_boolean_habit, container, false); HabitsApplication app = (HabitsApplication) getContext().getApplicationContext(); @@ -96,23 +93,40 @@ public abstract class BooleanHabitDialog extends AppCompatDialogFragment ButterKnife.bind(this, view); - helper = new BaseDialogHelper(this, view); + helper = new BooleanHabitDialogHelper(this, view); getDialog().setTitle(getTitle()); initializeHabits(); restoreSavedInstance(savedInstanceState); helper.populateForm(modifiedHabit); - return view; - } - @OnItemSelected(R.id.sFrequency) - public void onFrequencySelected(int position) - { - if (position < 0 || position > 4) throw new IllegalArgumentException(); - int freqNums[] = { 1, 1, 2, 5, 3 }; - int freqDens[] = { 1, 7, 7, 7, 7 }; - modifiedHabit.setFrequency( - new Frequency(freqNums[position], freqDens[position])); - helper.populateFrequencyFields(modifiedHabit); + helper.frequencyPanel.setFrequency(modifiedHabit.getFrequency()); + + if (modifiedHabit.hasReminder()) + helper.reminderPanel.setReminder(modifiedHabit.getReminder()); + + helper.reminderPanel.setController(new ReminderPanel.Controller() + { + @Override + public void onTimeClicked(int currentHour, int currentMin) + { + TimePickerDialog timePicker; + boolean is24HourMode = DateFormat.is24HourFormat(getContext()); + timePicker = TimePickerDialog.newInstance(helper.reminderPanel, + currentHour, currentMin, is24HourMode); + timePicker.show(getFragmentManager(), "timePicker"); + } + + @Override + public void onWeekdayClicked(WeekdayList currentDays) + { + WeekdayPickerDialog dialog = new WeekdayPickerDialog(); + dialog.setListener(helper.reminderPanel); + dialog.setSelectedDays(currentDays); + dialog.show(getFragmentManager(), "weekdayPicker"); + } + }); + + return view; } @Override @@ -121,13 +135,6 @@ public abstract class BooleanHabitDialog extends AppCompatDialogFragment { super.onSaveInstanceState(outState); outState.putInt("color", modifiedHabit.getColor()); - if (modifiedHabit.hasReminder()) - { - Reminder reminder = modifiedHabit.getReminder(); - outState.putInt("reminderMin", reminder.getMinute()); - outState.putInt("reminderHour", reminder.getHour()); - outState.putInt("reminderDays", reminder.getDays().toInteger()); - } } protected abstract int getTitle(); @@ -139,19 +146,6 @@ public abstract class BooleanHabitDialog extends AppCompatDialogFragment if (bundle == null) return; modifiedHabit.setColor( bundle.getInt("color", modifiedHabit.getColor())); - - modifiedHabit.setReminder(null); - - int hour = (bundle.getInt("reminderHour", -1)); - int minute = (bundle.getInt("reminderMin", -1)); - int days = (bundle.getInt("reminderDays", -1)); - - if (hour >= 0 && minute >= 0) - { - Reminder reminder = - new Reminder(hour, minute, new WeekdayList(days)); - modifiedHabit.setReminder(reminder); - } } protected abstract void saveHabit(); @@ -162,45 +156,20 @@ public abstract class BooleanHabitDialog extends AppCompatDialogFragment dismiss(); } - @OnClick(R.id.tvReminderTime) - @SuppressWarnings("ConstantConditions") - void onDateSpinnerClick() - { - int defaultHour = 8; - int defaultMin = 0; - - if (modifiedHabit.hasReminder()) - { - Reminder reminder = modifiedHabit.getReminder(); - defaultHour = reminder.getHour(); - defaultMin = reminder.getMinute(); - } - - showTimePicker(defaultHour, defaultMin); - } - @OnClick(R.id.buttonSave) void onSaveButtonClick() { helper.parseFormIntoHabit(modifiedHabit); + modifiedHabit.setReminder(helper.reminderPanel.getReminder()); + modifiedHabit.setFrequency(helper.frequencyPanel.getFrequency()); + + if (!helper.frequencyPanel.validate()) return; if (!helper.validate(modifiedHabit)) return; + saveHabit(); dismiss(); } - @OnClick(R.id.tvReminderDays) - @SuppressWarnings("ConstantConditions") - void onWeekdayClick() - { - if (!modifiedHabit.hasReminder()) return; - Reminder reminder = modifiedHabit.getReminder(); - - WeekdayPickerDialog dialog = new WeekdayPickerDialog(); - dialog.setListener(new OnWeekdaysPickedListener()); - dialog.setSelectedDays(reminder.getDays().toArray()); - dialog.show(getFragmentManager(), "weekdayPicker"); - } - @OnClick(R.id.buttonPickColor) void showColorPicker() { @@ -216,55 +185,4 @@ public abstract class BooleanHabitDialog extends AppCompatDialogFragment picker.show(getFragmentManager(), "picker"); } - - private void showTimePicker(int defaultHour, int defaultMin) - { - boolean is24HourMode = DateFormat.is24HourFormat(getContext()); - TimePickerDialog timePicker = - TimePickerDialog.newInstance(new OnTimeSetListener(), defaultHour, - defaultMin, is24HourMode); - timePicker.show(getFragmentManager(), "timePicker"); - } - - private class OnTimeSetListener - implements TimePickerDialog.OnTimeSetListener - { - @Override - public void onTimeCleared(RadialPickerLayout view) - { - modifiedHabit.clearReminder(); - helper.populateReminderFields(modifiedHabit); - } - - @Override - public void onTimeSet(RadialPickerLayout view, int hour, int minute) - { - Reminder reminder = - new Reminder(hour, minute, WeekdayList.EVERY_DAY); - modifiedHabit.setReminder(reminder); - helper.populateReminderFields(modifiedHabit); - } - } - - private class OnWeekdaysPickedListener - implements WeekdayPickerDialog.OnWeekdaysPickedListener - { - @Override - public void onWeekdaysPicked(boolean[] selectedDays) - { - if (isSelectionEmpty(selectedDays)) Arrays.fill(selectedDays, true); - - Reminder oldReminder = modifiedHabit.getReminder(); - modifiedHabit.setReminder( - new Reminder(oldReminder.getHour(), oldReminder.getMinute(), - new WeekdayList(selectedDays))); - helper.populateReminderFields(modifiedHabit); - } - - private boolean isSelectionEmpty(boolean[] selectedDays) - { - for (boolean d : selectedDays) if (d) return false; - return true; - } - } } diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BooleanHabitDialogHelper.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BooleanHabitDialogHelper.java new file mode 100644 index 000000000..edb8415cb --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BooleanHabitDialogHelper.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker 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. + * + * Loop Habit Tracker 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 program. If not, see . + */ + +package org.isoron.uhabits.activities.habits.edit; + +import android.support.v4.app.*; +import android.view.*; +import android.widget.*; + +import org.isoron.uhabits.R; +import org.isoron.uhabits.activities.habits.edit.views.*; +import org.isoron.uhabits.models.*; +import org.isoron.uhabits.utils.*; + +import butterknife.*; + +public class BooleanHabitDialogHelper +{ + private DialogFragment frag; + + @BindView(R.id.tvName) + TextView tvName; + + @BindView(R.id.tvDescription) + TextView tvDescription; + + @BindView(R.id.reminderPanel) + ReminderPanel reminderPanel; + + @BindView(R.id.frequencyPanel) + FrequencyPanel frequencyPanel; + + public BooleanHabitDialogHelper(DialogFragment frag, View view) + { + this.frag = frag; + ButterKnife.bind(this, view); + } + + protected void populateForm(final Habit habit) + { + tvName.setText(habit.getName()); + tvDescription.setText(habit.getDescription()); + populateColor(habit.getColor()); + } + + void parseFormIntoHabit(Habit habit) + { + habit.setName(tvName.getText().toString().trim()); + habit.setDescription(tvDescription.getText().toString().trim()); + } + + void populateColor(int paletteColor) + { + tvName.setTextColor( + ColorUtils.getColor(frag.getContext(), paletteColor)); + } + + boolean validate(Habit habit) + { + Boolean valid = true; + + if (habit.getName().isEmpty()) + { + tvName.setError(frag.getString(R.string.validation_name_should_not_be_blank)); + valid = false; + } + + return valid; + } +} diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/NumericalHabitDialogHelper.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/NumericalHabitDialogHelper.java index 5122ef504..2759bab12 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/NumericalHabitDialogHelper.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/NumericalHabitDialogHelper.java @@ -25,6 +25,7 @@ import android.view.*; import android.widget.*; import org.isoron.uhabits.R; +import org.isoron.uhabits.activities.habits.edit.views.*; import org.isoron.uhabits.models.*; import org.isoron.uhabits.utils.*; diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/ExampleEditText.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/views/ExampleEditText.java similarity index 93% rename from app/src/main/java/org/isoron/uhabits/activities/habits/edit/ExampleEditText.java rename to app/src/main/java/org/isoron/uhabits/activities/habits/edit/views/ExampleEditText.java index 6449d4db0..232b9b3f2 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/ExampleEditText.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/views/ExampleEditText.java @@ -17,7 +17,7 @@ * with this program. If not, see . */ -package org.isoron.uhabits.activities.habits.edit; +package org.isoron.uhabits.activities.habits.edit.views; import android.content.*; import android.support.annotation.*; @@ -31,6 +31,10 @@ import org.isoron.uhabits.utils.*; import static org.isoron.uhabits.utils.AttributeSetUtils.*; +/** + * An EditText that shows an example usage when there is no text + * currently set. The example disappears when the widget gains focus. + */ public class ExampleEditText extends EditText implements View.OnFocusChangeListener { diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/views/FrequencyPanel.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/views/FrequencyPanel.java new file mode 100644 index 000000000..cb4f86d56 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/views/FrequencyPanel.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker 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. + * + * Loop Habit Tracker 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 program. If not, see . + */ + +package org.isoron.uhabits.activities.habits.edit.views; + +import android.annotation.*; +import android.content.*; +import android.content.res.*; +import android.support.annotation.*; +import android.util.*; +import android.view.*; +import android.widget.*; + +import org.isoron.uhabits.R; +import org.isoron.uhabits.models.*; + +import butterknife.*; + +import static org.isoron.uhabits.R.id.*; + + +public class FrequencyPanel extends FrameLayout +{ + @BindView(numerator) + TextView tvNumerator; + + @BindView(R.id.denominator) + TextView tvDenominator; + + @BindView(R.id.spinner) + Spinner spinner; + + @BindView(R.id.customFreqPanel) + ViewGroup customFreqPanel; + + public FrequencyPanel(@NonNull Context context, + @Nullable AttributeSet attrs) + { + super(context, attrs); + + View view = inflate(context, R.layout.edit_habit_frequency, null); + ButterKnife.bind(this, view); + addView(view); + } + + @NonNull + public Frequency getFrequency() + { + String freqNum = tvNumerator.getText().toString(); + String freqDen = tvDenominator.getText().toString(); + + if (!freqNum.isEmpty() && !freqDen.isEmpty()) + { + int numerator = Integer.parseInt(freqNum); + int denominator = Integer.parseInt(freqDen); + return new Frequency(numerator, denominator); + } + + return Frequency.DAILY; + } + + @SuppressLint("SetTextI18n") + public void setFrequency(@NonNull Frequency freq) + { + int position = getQuickSelectPosition(freq); + + if (position >= 0) showSimplifiedFrequency(position); + else showCustomFrequency(); + + tvNumerator.setText(Integer.toString(freq.getNumerator())); + tvDenominator.setText(Integer.toString(freq.getDenominator())); + } + + @OnItemSelected(R.id.spinner) + public void onFrequencySelected(int position) + { + if (position < 0 || position > 4) throw new IllegalArgumentException(); + int freqNums[] = { 1, 1, 2, 5, 3 }; + int freqDens[] = { 1, 7, 7, 7, 7 }; + setFrequency(new Frequency(freqNums[position], freqDens[position])); + } + + public boolean validate() + { + boolean valid = true; + Resources res = getResources(); + + String freqNum = tvNumerator.getText().toString(); + String freqDen = tvDenominator.getText().toString(); + + if (freqDen.isEmpty()) + { + tvDenominator.setError( + res.getString(R.string.validation_show_not_be_blank)); + valid = false; + } + + if (freqNum.isEmpty()) + { + tvNumerator.setError( + res.getString(R.string.validation_show_not_be_blank)); + valid = false; + } + + if (!valid) return false; + + int numerator = Integer.parseInt(freqNum); + int denominator = Integer.parseInt(freqDen); + + if (numerator <= 0) + { + tvNumerator.setError( + res.getString(R.string.validation_number_should_be_positive)); + valid = false; + } + + if (numerator > denominator) + { + tvNumerator.setError( + res.getString(R.string.validation_at_most_one_rep_per_day)); + valid = false; + } + + return valid; + } + + private int getQuickSelectPosition(@NonNull Frequency freq) + { + if (freq.equals(Frequency.DAILY)) return 0; + if (freq.equals(Frequency.WEEKLY)) return 1; + if (freq.equals(Frequency.TWO_TIMES_PER_WEEK)) return 2; + if (freq.equals(Frequency.FIVE_TIMES_PER_WEEK)) return 3; + return -1; + } + + private void showCustomFrequency() + { + spinner.setVisibility(View.GONE); + customFreqPanel.setVisibility(View.VISIBLE); + } + + private void showSimplifiedFrequency(int quickSelectPosition) + { + spinner.setVisibility(View.VISIBLE); + spinner.setSelection(quickSelectPosition); + customFreqPanel.setVisibility(View.GONE); + } +} diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/views/ReminderPanel.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/views/ReminderPanel.java new file mode 100644 index 000000000..2c5fd5687 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/views/ReminderPanel.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker 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. + * + * Loop Habit Tracker 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 program. If not, see . + */ + +package org.isoron.uhabits.activities.habits.edit.views; + +import android.content.*; +import android.os.*; +import android.support.annotation.*; +import android.util.*; +import android.view.*; +import android.widget.*; + +import com.android.datetimepicker.time.*; + +import org.isoron.uhabits.R; +import org.isoron.uhabits.activities.common.dialogs.*; +import org.isoron.uhabits.activities.common.views.*; +import org.isoron.uhabits.models.*; + +import butterknife.*; + +import static org.isoron.uhabits.utils.DateUtils.*; + +public class ReminderPanel extends FrameLayout + implements TimePickerDialog.OnTimeSetListener, + WeekdayPickerDialog.OnWeekdaysPickedListener +{ + @BindView(R.id.tvReminderTime) + TextView tvReminderTime; + + @BindView(R.id.llReminderDays) + ViewGroup llReminderDays; + + @BindView(R.id.tvReminderDays) + TextView tvReminderDays; + + @Nullable + private Reminder reminder; + + @NonNull + private Controller controller; + + public ReminderPanel(@NonNull Context context, @Nullable AttributeSet attrs) + { + super(context, attrs); + + View view = inflate(context, R.layout.edit_habit_reminder, null); + ButterKnife.bind(this, view); + addView(view); + + controller = new Controller() {}; + setReminder(null); + } + + @Nullable + public Reminder getReminder() + { + return reminder; + } + + public void setReminder(@Nullable Reminder reminder) + { + this.reminder = reminder; + + if (reminder == null) + { + tvReminderTime.setText(R.string.reminder_off); + llReminderDays.setVisibility(View.GONE); + return; + } + + Context ctx = getContext(); + String time = formatTime(ctx, reminder.getHour(), reminder.getMinute()); + tvReminderTime.setText(time); + llReminderDays.setVisibility(View.VISIBLE); + + boolean weekdays[] = reminder.getDays().toArray(); + tvReminderDays.setText(formatWeekdayList(ctx, weekdays)); + } + + @Override + public void onTimeCleared(RadialPickerLayout view) + { + setReminder(null); + } + + @Override + public void onTimeSet(RadialPickerLayout view, int hour, int minute) + { + setReminder(new Reminder(hour, minute, WeekdayList.EVERY_DAY)); + } + + @Override + public void onWeekdaysSet(WeekdayList selectedDays) + { + if (reminder == null) return; + if (selectedDays.isEmpty()) selectedDays = WeekdayList.EVERY_DAY; + + setReminder(new Reminder(reminder.getHour(), reminder.getMinute(), + selectedDays)); + } + + public void setController(@NonNull Controller controller) + { + this.controller = controller; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) + { + BundleSavedState bss = (BundleSavedState) state; + if (!bss.bundle.isEmpty()) + { + int days = bss.bundle.getInt("days"); + int hour = bss.bundle.getInt("hour"); + int minute = bss.bundle.getInt("minute"); + reminder = new Reminder(hour, minute, new WeekdayList(days)); + setReminder(reminder); + } + super.onRestoreInstanceState(bss.getSuperState()); + } + + @Override + protected Parcelable onSaveInstanceState() + { + Parcelable superState = super.onSaveInstanceState(); + Bundle bundle = new Bundle(); + if (reminder != null) + { + bundle.putInt("days", reminder.getDays().toInteger()); + bundle.putInt("hour", reminder.getHour()); + bundle.putInt("minute", reminder.getMinute()); + } + return new BundleSavedState(superState, bundle); + } + + @OnClick(R.id.tvReminderTime) + void onDateSpinnerClick() + { + int hour = 8; + int min = 0; + + if (reminder != null) + { + hour = reminder.getHour(); + min = reminder.getMinute(); + } + + controller.onTimeClicked(hour, min); + } + + @OnClick(R.id.tvReminderDays) + void onWeekdayClicked() + { + if (reminder == null) return; + controller.onWeekdayClicked(reminder.getDays()); + } + + public interface Controller + { + /** + * Called when the user has clicked the widget to change the time of + * the reminder. + * + * @param currentHour hour previously picked by the user + * @param currentMin minute previously picked by the user + */ + default void onTimeClicked(int currentHour, int currentMin) {} + + /** + * Called when the used has clicked the widget to change the days + * of the reminder. + * + * @param currentDays days previously selected by the user. + */ + default void onWeekdayClicked(WeekdayList currentDays) {} + } +} diff --git a/app/src/main/java/org/isoron/uhabits/models/WeekdayList.java b/app/src/main/java/org/isoron/uhabits/models/WeekdayList.java index 21a35b97a..f6cbe4560 100644 --- a/app/src/main/java/org/isoron/uhabits/models/WeekdayList.java +++ b/app/src/main/java/org/isoron/uhabits/models/WeekdayList.java @@ -23,13 +23,12 @@ import java.util.*; public class WeekdayList { - public static WeekdayList EVERY_DAY = new WeekdayList(127); + public static final WeekdayList EVERY_DAY = new WeekdayList(127); private final boolean[] weekdays; public WeekdayList(int packedList) { - if(packedList == 0) packedList = 127; weekdays = new boolean[7]; int current = 1; @@ -42,16 +41,18 @@ public class WeekdayList public WeekdayList(boolean weekdays[]) { - boolean isEmpty = true; - for(boolean b : weekdays) if(b) isEmpty = false; - if(isEmpty) throw new IllegalArgumentException("empty list"); - this.weekdays = Arrays.copyOf(weekdays, 7); } + public boolean isEmpty() + { + for (boolean d : weekdays) if (d) return false; + return true; + } + public boolean[] toArray() { - return weekdays; + return Arrays.copyOf(weekdays, 7); } public int toInteger() diff --git a/app/src/main/res/layout/edit_boolean_habit.xml b/app/src/main/res/layout/edit_boolean_habit.xml index eda86d33d..d7d8215f3 100644 --- a/app/src/main/res/layout/edit_boolean_habit.xml +++ b/app/src/main/res/layout/edit_boolean_habit.xml @@ -53,82 +53,16 @@ style="@style/dialogFormInputMultiline" android:hint="@string/description_hint"/> - - - - - - - - - - - - - - - - - - + - - - + android:layout_width="match_parent" + android:layout_height="wrap_content"/> - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/edit_habit_reminder.xml b/app/src/main/res/layout/edit_habit_reminder.xml new file mode 100644 index 000000000..0e5318c36 --- /dev/null +++ b/app/src/main/res/layout/edit_habit_reminder.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/edit_numerical_habit.xml b/app/src/main/res/layout/edit_numerical_habit.xml index c57c954df..ea13786a6 100644 --- a/app/src/main/res/layout/edit_numerical_habit.xml +++ b/app/src/main/res/layout/edit_numerical_habit.xml @@ -61,7 +61,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - - Calendar Unit Count + This field should not be blank \ No newline at end of file diff --git a/app/src/test/java/org/isoron/uhabits/models/WeekdayListTest.java b/app/src/test/java/org/isoron/uhabits/models/WeekdayListTest.java index c8493cd87..406b6e39b 100644 --- a/app/src/test/java/org/isoron/uhabits/models/WeekdayListTest.java +++ b/app/src/test/java/org/isoron/uhabits/models/WeekdayListTest.java @@ -22,6 +22,7 @@ package org.isoron.uhabits.models; import org.isoron.uhabits.*; import org.junit.*; +import static junit.framework.Assert.*; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.core.IsEqual.*; @@ -48,6 +49,8 @@ public class WeekdayListTest extends BaseUnitTest public void testEmpty() { WeekdayList list = new WeekdayList(0); - assertThat(list.toArray(), equalTo(WeekdayList.EVERY_DAY.toArray())); + assertTrue(list.isEmpty()); + + assertFalse(WeekdayList.EVERY_DAY.isEmpty()); } }