Update habit creation dialogs

pull/157/merge
Alinson S. Xavier 9 years ago
parent 5c1ccfe6fe
commit d03edf2895

@ -20,6 +20,7 @@
package org.isoron.uhabits.activities.habits.edit; package org.isoron.uhabits.activities.habits.edit;
import android.annotation.*; import android.annotation.*;
import android.support.annotation.*;
import android.support.v4.app.*; import android.support.v4.app.*;
import android.view.*; import android.view.*;
import android.widget.*; import android.widget.*;
@ -40,9 +41,11 @@ public class BaseDialogHelper
@BindView(R.id.tvDescription) @BindView(R.id.tvDescription)
TextView tvDescription; TextView tvDescription;
@Nullable
@BindView(R.id.tvFreqNum) @BindView(R.id.tvFreqNum)
TextView tvFreqNum; TextView tvFreqNum;
@Nullable
@BindView(R.id.tvFreqDen) @BindView(R.id.tvFreqDen)
TextView tvFreqDen; TextView tvFreqDen;
@ -52,9 +55,11 @@ public class BaseDialogHelper
@BindView(R.id.tvReminderDays) @BindView(R.id.tvReminderDays)
TextView tvReminderDays; TextView tvReminderDays;
@Nullable
@BindView(R.id.sFrequency) @BindView(R.id.sFrequency)
Spinner sFrequency; Spinner sFrequency;
@Nullable
@BindView(R.id.llCustomFrequency) @BindView(R.id.llCustomFrequency)
ViewGroup llCustomFrequency; ViewGroup llCustomFrequency;
@ -69,9 +74,8 @@ public class BaseDialogHelper
protected void populateForm(final Habit habit) protected void populateForm(final Habit habit)
{ {
if (habit.getName() != null) tvName.setText(habit.getName()); tvName.setText(habit.getName());
if (habit.getDescription() != null) tvDescription.setText(habit.getDescription());
tvDescription.setText(habit.getDescription());
populateColor(habit.getColor()); populateColor(habit.getColor());
populateFrequencyFields(habit); populateFrequencyFields(habit);
@ -82,13 +86,17 @@ public class BaseDialogHelper
{ {
habit.setName(tvName.getText().toString().trim()); habit.setName(tvName.getText().toString().trim());
habit.setDescription(tvDescription.getText().toString().trim()); habit.setDescription(tvDescription.getText().toString().trim());
String freqNum = tvFreqNum.getText().toString();
String freqDen = tvFreqDen.getText().toString(); if (tvFreqDen != null && tvFreqNum != null)
if (!freqNum.isEmpty() && !freqDen.isEmpty())
{ {
int numerator = Integer.parseInt(freqNum); String freqNum = tvFreqNum.getText().toString();
int denominator = Integer.parseInt(freqDen); String freqDen = tvFreqDen.getText().toString();
habit.setFrequency(new Frequency(numerator, denominator)); if (!freqNum.isEmpty() && !freqDen.isEmpty())
{
int numerator = Integer.parseInt(freqNum);
int denominator = Integer.parseInt(freqDen);
habit.setFrequency(new Frequency(numerator, denominator));
}
} }
} }
@ -101,15 +109,16 @@ public class BaseDialogHelper
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
void populateFrequencyFields(Habit habit) void populateFrequencyFields(Habit habit)
{ {
if (tvFreqNum == null) return;
if (tvFreqDen == null) return;
int quickSelectPosition = -1; int quickSelectPosition = -1;
Frequency freq = habit.getFrequency(); Frequency freq = habit.getFrequency();
if (freq.equals(Frequency.DAILY)) if (freq.equals(Frequency.DAILY)) quickSelectPosition = 0;
quickSelectPosition = 0;
else if (freq.equals(Frequency.WEEKLY)) else if (freq.equals(Frequency.WEEKLY)) quickSelectPosition = 1;
quickSelectPosition = 1;
else if (freq.equals(Frequency.TWO_TIMES_PER_WEEK)) else if (freq.equals(Frequency.TWO_TIMES_PER_WEEK))
quickSelectPosition = 2; quickSelectPosition = 2;
@ -144,13 +153,16 @@ public class BaseDialogHelper
tvReminderTime.setText(time); tvReminderTime.setText(time);
llReminderDays.setVisibility(View.VISIBLE); llReminderDays.setVisibility(View.VISIBLE);
boolean weekdays[] = reminder.getDays().toArray(); boolean weekdays[] = reminder.getDays().toArray();
tvReminderDays.setText( tvReminderDays.setText(
DateUtils.formatWeekdayList(frag.getContext(), weekdays)); DateUtils.formatWeekdayList(frag.getContext(), weekdays));
} }
private void showCustomFrequency() private void showCustomFrequency()
{ {
if(sFrequency == null) return;
if(llCustomFrequency == null) return;
sFrequency.setVisibility(View.GONE); sFrequency.setVisibility(View.GONE);
llCustomFrequency.setVisibility(View.VISIBLE); llCustomFrequency.setVisibility(View.VISIBLE);
} }
@ -158,6 +170,9 @@ public class BaseDialogHelper
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private void showSimplifiedFrequency(int quickSelectPosition) private void showSimplifiedFrequency(int quickSelectPosition)
{ {
if(sFrequency == null) return;
if(llCustomFrequency == null) return;
sFrequency.setVisibility(View.VISIBLE); sFrequency.setVisibility(View.VISIBLE);
sFrequency.setSelection(quickSelectPosition); sFrequency.setSelection(quickSelectPosition);
llCustomFrequency.setVisibility(View.GONE); llCustomFrequency.setVisibility(View.GONE);
@ -175,19 +190,21 @@ public class BaseDialogHelper
} }
Frequency freq = habit.getFrequency(); Frequency freq = habit.getFrequency();
if (tvFreqNum != null && tvFreqDen != null)
if (freq.getNumerator() <= 0)
{ {
tvFreqNum.setError( if (freq.getNumerator() <= 0)
frag.getString(R.string.validation_number_should_be_positive)); {
valid = false; tvFreqNum.setError(frag.getString(
} R.string.validation_number_should_be_positive));
valid = false;
if (freq.getNumerator() > freq.getDenominator()) }
{
tvFreqNum.setError( if (freq.getNumerator() > freq.getDenominator())
frag.getString(R.string.validation_at_most_one_rep_per_day)); {
valid = false; tvFreqNum.setError(frag.getString(
R.string.validation_at_most_one_rep_per_day));
valid = false;
}
} }
return valid; return valid;

@ -39,7 +39,7 @@ import java.util.*;
import butterknife.*; import butterknife.*;
public abstract class BaseDialog extends AppCompatDialogFragment public abstract class BooleanHabitDialog extends AppCompatDialogFragment
{ {
@Nullable @Nullable
protected Habit originalHabit; protected Habit originalHabit;
@ -62,6 +62,12 @@ public abstract class BaseDialog extends AppCompatDialogFragment
private ColorPickerDialogFactory colorPickerDialogFactory; private ColorPickerDialogFactory colorPickerDialogFactory;
@Override
public int getTheme()
{
return R.style.DialogWithTitle;
}
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) public void onActivityCreated(Bundle savedInstanceState)
{ {
@ -77,7 +83,7 @@ public abstract class BaseDialog extends AppCompatDialogFragment
ViewGroup container, ViewGroup container,
Bundle savedInstanceState) Bundle savedInstanceState)
{ {
View view = inflater.inflate(R.layout.edit_habit, container, false); View view = inflater.inflate(R.layout.edit_boolean_habit, container, false);
HabitsApplication app = HabitsApplication app =
(HabitsApplication) getContext().getApplicationContext(); (HabitsApplication) getContext().getApplicationContext();
@ -201,7 +207,8 @@ public abstract class BaseDialog extends AppCompatDialogFragment
int color = modifiedHabit.getColor(); int color = modifiedHabit.getColor();
ColorPickerDialog picker = colorPickerDialogFactory.create(color); ColorPickerDialog picker = colorPickerDialogFactory.create(color);
picker.setListener(c -> { picker.setListener(c ->
{
prefs.setDefaultHabitColor(c); prefs.setDefaultHabitColor(c);
modifiedHabit.setColor(c); modifiedHabit.setColor(c);
helper.populateColor(c); helper.populateColor(c);

@ -26,7 +26,7 @@ import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
@AutoFactory(allowSubclasses = true) @AutoFactory(allowSubclasses = true)
public class CreateHabitDialog extends BaseDialog public class CreateBooleanHabitDialog extends BooleanHabitDialog
{ {
@Override @Override
protected int getTitle() protected int getTitle()

@ -0,0 +1,55 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.activities.habits.edit;
import com.google.auto.factory.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*;
@AutoFactory(allowSubclasses = true)
public class CreateNumericalHabitDialog extends NumericalHabitDialog
{
@Override
protected int getTitle()
{
return R.string.create_habit;
}
@Override
protected void initializeHabits()
{
modifiedHabit = modelFactory.buildHabit();
modifiedHabit.setFrequency(Frequency.DAILY);
modifiedHabit.setColor(
prefs.getDefaultHabitColor(modifiedHabit.getColor()));
modifiedHabit.setType(Habit.NUMBER_HABIT);
}
@Override
protected void saveHabit()
{
Command command = appComponent
.getCreateHabitCommandFactory()
.create(habitList, modifiedHabit);
commandRunner.execute(command, null);
}
}

@ -22,7 +22,7 @@ package org.isoron.uhabits.activities.habits.edit;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.commands.*; import org.isoron.uhabits.commands.*;
public class EditHabitDialog extends BaseDialog public class EditBooleanHabitDialog extends BooleanHabitDialog
{ {
@Override @Override
protected int getTitle() protected int getTitle()

@ -26,19 +26,19 @@ import org.isoron.uhabits.models.*;
import javax.inject.*; import javax.inject.*;
public class EditHabitDialogFactory public class EditBooleanHabitDialogFactory
{ {
@Inject @Inject
public EditHabitDialogFactory() public EditBooleanHabitDialogFactory()
{ {
} }
public EditHabitDialog create(@NonNull Habit habit) public EditBooleanHabitDialog create(@NonNull Habit habit)
{ {
if (habit.getId() == null) if (habit.getId() == null)
throw new IllegalArgumentException("habit not saved"); throw new IllegalArgumentException("habit not saved");
EditHabitDialog dialog = new EditHabitDialog(); EditBooleanHabitDialog dialog = new EditBooleanHabitDialog();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLong("habitId", habit.getId()); args.putLong("habitId", habit.getId());
dialog.setArguments(args); dialog.setArguments(args);

@ -0,0 +1,260 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.activities.habits.edit;
import android.os.*;
import android.support.annotation.*;
import android.support.v7.app.*;
import android.text.format.*;
import android.view.*;
import com.android.datetimepicker.time.*;
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.commands.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.preferences.*;
import java.util.*;
import butterknife.*;
public abstract class NumericalHabitDialog extends AppCompatDialogFragment
{
@Nullable
protected Habit originalHabit;
@Nullable
protected Habit modifiedHabit;
@Nullable
protected BaseDialogHelper helper;
protected Preferences prefs;
protected CommandRunner commandRunner;
protected HabitList habitList;
protected AppComponent appComponent;
protected ModelFactory modelFactory;
private ColorPickerDialogFactory colorPickerDialogFactory;
@Override
public int getTheme()
{
return R.style.DialogWithTitle;
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
BaseActivity activity = (BaseActivity) getActivity();
colorPickerDialogFactory =
activity.getComponent().getColorPickerDialogFactory();
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState)
{
View view =
inflater.inflate(R.layout.edit_numerical_habit, container, false);
HabitsApplication app =
(HabitsApplication) getContext().getApplicationContext();
appComponent = app.getComponent();
prefs = appComponent.getPreferences();
habitList = appComponent.getHabitList();
commandRunner = appComponent.getCommandRunner();
modelFactory = appComponent.getModelFactory();
ButterKnife.bind(this, view);
helper = new BaseDialogHelper(this, view);
getDialog().setTitle(getTitle());
initializeHabits();
restoreSavedInstance(savedInstanceState);
helper.populateForm(modifiedHabit);
return view;
}
@Override
@SuppressWarnings("ConstantConditions")
public void onSaveInstanceState(Bundle outState)
{
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();
protected abstract void initializeHabits();
protected void restoreSavedInstance(@Nullable Bundle bundle)
{
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();
@OnClick(R.id.buttonDiscard)
void onButtonDiscardClick()
{
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);
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()
{
int color = modifiedHabit.getColor();
ColorPickerDialog picker = colorPickerDialogFactory.create(color);
picker.setListener(c ->
{
prefs.setDefaultHabitColor(c);
modifiedHabit.setColor(c);
helper.populateColor(c);
});
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;
}
}
}

@ -82,7 +82,8 @@ public class ListHabitsScreen extends BaseScreen
private final ConfirmDeleteDialogFactory confirmDeleteDialogFactory; private final ConfirmDeleteDialogFactory confirmDeleteDialogFactory;
@NonNull @NonNull
private final CreateHabitDialogFactory createHabitDialogFactory; private final CreateBooleanHabitDialogFactory
createBooleanHabitDialogFactory;
@NonNull @NonNull
private final FilePickerDialogFactory filePickerDialogFactory; private final FilePickerDialogFactory filePickerDialogFactory;
@ -91,11 +92,13 @@ public class ListHabitsScreen extends BaseScreen
private final ColorPickerDialogFactory colorPickerFactory; private final ColorPickerDialogFactory colorPickerFactory;
@NonNull @NonNull
private final EditHabitDialogFactory editHabitDialogFactory; private final EditBooleanHabitDialogFactory editBooleanHabitDialogFactory;
@NonNull @NonNull
private final ThemeSwitcher themeSwitcher; private final ThemeSwitcher themeSwitcher;
private CreateNumericalHabitDialogFactory createNumericalHabitDialogFactory;
@Inject @Inject
public ListHabitsScreen(@NonNull BaseActivity activity, public ListHabitsScreen(@NonNull BaseActivity activity,
@NonNull CommandRunner commandRunner, @NonNull CommandRunner commandRunner,
@ -103,24 +106,21 @@ public class ListHabitsScreen extends BaseScreen
@NonNull ListHabitsRootView rootView, @NonNull ListHabitsRootView rootView,
@NonNull IntentFactory intentFactory, @NonNull IntentFactory intentFactory,
@NonNull ThemeSwitcher themeSwitcher, @NonNull ThemeSwitcher themeSwitcher,
@NonNull @NonNull ConfirmDeleteDialogFactory confirmDeleteDialogFactory,
ConfirmDeleteDialogFactory confirmDeleteDialogFactory, @NonNull CreateBooleanHabitDialogFactory createBooleanHabitDialogFactory,
@NonNull @NonNull FilePickerDialogFactory filePickerDialogFactory,
CreateHabitDialogFactory createHabitDialogFactory, @NonNull ColorPickerDialogFactory colorPickerFactory,
@NonNull @NonNull EditBooleanHabitDialogFactory editBooleanHabitDialogFactory,
FilePickerDialogFactory filePickerDialogFactory, @NonNull CreateNumericalHabitDialogFactory createNumericalHabitDialogFactory)
@NonNull
ColorPickerDialogFactory colorPickerFactory,
@NonNull
EditHabitDialogFactory editHabitDialogFactory)
{ {
super(activity); super(activity);
setRootView(rootView); setRootView(rootView);
this.editHabitDialogFactory = editHabitDialogFactory;
this.colorPickerFactory = colorPickerFactory; this.colorPickerFactory = colorPickerFactory;
this.commandRunner = commandRunner; this.commandRunner = commandRunner;
this.confirmDeleteDialogFactory = confirmDeleteDialogFactory; this.confirmDeleteDialogFactory = confirmDeleteDialogFactory;
this.createHabitDialogFactory = createHabitDialogFactory; this.createNumericalHabitDialogFactory = createNumericalHabitDialogFactory;
this.createBooleanHabitDialogFactory = createBooleanHabitDialogFactory;
this.editBooleanHabitDialogFactory = editBooleanHabitDialogFactory;
this.dirFinder = dirFinder; this.dirFinder = dirFinder;
this.filePickerDialogFactory = filePickerDialogFactory; this.filePickerDialogFactory = filePickerDialogFactory;
this.intentFactory = intentFactory; this.intentFactory = intentFactory;
@ -182,57 +182,41 @@ public class ListHabitsScreen extends BaseScreen
public void showCreateHabitScreen() public void showCreateHabitScreen()
{ {
activity.showDialog(createHabitDialogFactory.create(), "editHabit"); Dialog dialog = new AlertDialog.Builder(activity)
.setTitle("Type of habit")
.setItems(R.array.habitTypes, (d, which) -> {
if(which == 0) showCreateBooleanHabitScreen();
else showCreateNumericalHabitScreen();
})
.create();
dialog.show();
} }
public void showDeleteConfirmationScreen(ConfirmDeleteDialog.Callback callback) private void showCreateNumericalHabitScreen()
{ {
activity.showDialog(confirmDeleteDialogFactory.create(callback)); CreateNumericalHabitDialog dialog;
dialog = createNumericalHabitDialogFactory.create();
activity.showDialog(dialog, "editHabit");
} }
public void showEditHabitScreen(Habit habit) public void showCreateBooleanHabitScreen()
{ {
EditHabitDialog dialog = editHabitDialogFactory.create(habit); CreateBooleanHabitDialog dialog;
dialog = createBooleanHabitDialogFactory.create();
activity.showDialog(dialog, "editHabit"); activity.showDialog(dialog, "editHabit");
} }
public void showNumberPicker(int initialValue, public void showDeleteConfirmationScreen(ConfirmDeleteDialog.Callback callback)
@NonNull NumberPickerCallback callback)
{ {
LayoutInflater inflater = activity.getLayoutInflater(); activity.showDialog(confirmDeleteDialogFactory.create(callback));
View view = inflater.inflate(R.layout.number_picker_dialog, null); }
final NumberPicker picker =
(NumberPicker) view.findViewById(R.id.picker);
picker.setMinValue(0);
picker.setMaxValue(Integer.MAX_VALUE);
picker.setValue(initialValue);
picker.setWrapSelectorWheel(false);
AlertDialog dialog = new AlertDialog.Builder(activity)
.setView(view)
.setTitle(R.string.change_value)
.setPositiveButton(android.R.string.ok, (d, which) -> {
picker.clearFocus();
callback.onNumberPicked(picker.getValue());
}).create();
InterfaceUtils.setupEditorAction(picker, (v, actionId, event) -> {
if (actionId == IME_ACTION_DONE)
dialog.getButton(BUTTON_POSITIVE).performClick();
return false;
});
dialog.show();
Window window = dialog.getWindow(); public void showEditHabitScreen(Habit habit)
if (window != null) {
{ EditBooleanHabitDialog dialog;
int width = (int) dpToPixels(activity, 200); dialog = editBooleanHabitDialogFactory.create(habit);
int height = (int) dpToPixels(activity, 275); activity.showDialog(dialog, "editHabit");
window.setLayout(width, height);
}
} }
public void showFAQScreen() public void showFAQScreen()
@ -288,6 +272,48 @@ public class ListHabitsScreen extends BaseScreen
activity.startActivity(intent); activity.startActivity(intent);
} }
public void showNumberPicker(int initialValue,
@NonNull NumberPickerCallback callback)
{
LayoutInflater inflater = activity.getLayoutInflater();
View view = inflater.inflate(R.layout.number_picker_dialog, null);
final NumberPicker picker =
(NumberPicker) view.findViewById(R.id.picker);
picker.setMinValue(0);
picker.setMaxValue(Integer.MAX_VALUE);
picker.setValue(initialValue);
picker.setWrapSelectorWheel(false);
AlertDialog dialog = new AlertDialog.Builder(activity)
.setView(view)
.setTitle(R.string.change_value)
.setPositiveButton(android.R.string.ok, (d, which) ->
{
picker.clearFocus();
callback.onNumberPicked(picker.getValue());
})
.create();
InterfaceUtils.setupEditorAction(picker, (v, actionId, event) ->
{
if (actionId == IME_ACTION_DONE)
dialog.getButton(BUTTON_POSITIVE).performClick();
return false;
});
dialog.show();
Window window = dialog.getWindow();
if (window != null)
{
int width = (int) dpToPixels(activity, 200);
int height = (int) dpToPixels(activity, 275);
window.setLayout(width, height);
}
}
public void showSettingsScreen() public void showSettingsScreen()
{ {
Intent intent = intentFactory.startSettingsActivity(activity); Intent intent = intentFactory.startSettingsActivity(activity);

@ -106,12 +106,6 @@ public class HabitCardView extends FrameLayout
checkmarkPanel.setValues(values); checkmarkPanel.setValues(values);
numberPanel.setValues(values); numberPanel.setValues(values);
numberPanel.setThreshold(10); numberPanel.setThreshold(10);
// int[] magnitudes = new int[]{10, 100, 1000, 10000};
// int threshold = magnitudes[new Random().nextInt(4)];
// numberPanel.setThreshold(threshold);
// numberPanel.initEditMode();
postInvalidate(); postInvalidate();
} }
@ -239,9 +233,9 @@ public class HabitCardView extends FrameLayout
checkmarkPanel.setColor(color); checkmarkPanel.setColor(color);
numberPanel.setColor(color); numberPanel.setColor(color);
boolean isNumberHabit = true; //(new Random().nextInt(3) == 0); boolean isNumerical = habit.isNumerical();
checkmarkPanel.setVisibility(isNumberHabit ? GONE : VISIBLE); checkmarkPanel.setVisibility(isNumerical ? GONE : VISIBLE);
numberPanel.setVisibility(isNumberHabit ? VISIBLE : GONE); numberPanel.setVisibility(isNumerical ? VISIBLE : GONE);
postInvalidate(); postInvalidate();
} }

@ -38,17 +38,18 @@ public class ShowHabitScreen extends BaseScreen
private ShowHabitController controller; private ShowHabitController controller;
@NonNull @NonNull
private final EditHabitDialogFactory editHabitDialogFactory; private final EditBooleanHabitDialogFactory editBooleanHabitDialogFactory;
@Inject @Inject
public ShowHabitScreen(@NonNull BaseActivity activity, public ShowHabitScreen(@NonNull BaseActivity activity,
@NonNull Habit habit, @NonNull Habit habit,
@NonNull ShowHabitRootView view, @NonNull ShowHabitRootView view,
@NonNull EditHabitDialogFactory editHabitDialogFactory) @NonNull
EditBooleanHabitDialogFactory editBooleanHabitDialogFactory)
{ {
super(activity); super(activity);
setRootView(view); setRootView(view);
this.editHabitDialogFactory = editHabitDialogFactory; this.editBooleanHabitDialogFactory = editBooleanHabitDialogFactory;
this.habit = habit; this.habit = habit;
} }
@ -71,7 +72,7 @@ public class ShowHabitScreen extends BaseScreen
public void showEditHabitDialog() public void showEditHabitDialog()
{ {
EditHabitDialog dialog = editHabitDialogFactory.create(habit); EditBooleanHabitDialog dialog = editBooleanHabitDialogFactory.create(habit);
activity.showDialog(dialog, "editHabit"); activity.showDialog(dialog, "editHabit");
} }

@ -36,6 +36,10 @@ public class Habit
public static final String HABIT_URI_FORMAT = public static final String HABIT_URI_FORMAT =
"content://org.isoron.uhabits/habit/%d"; "content://org.isoron.uhabits/habit/%d";
public static final int NUMBER_HABIT = 1;
public static final int YES_NO_HABIT = 0;
@Nullable @Nullable
private Long id; private Long id;
@ -69,6 +73,8 @@ public class Habit
@Nullable @Nullable
private Reminder reminder; private Reminder reminder;
private int type;
private ModelObservable observable = new ModelObservable(); private ModelObservable observable = new ModelObservable();
/** /**
@ -83,6 +89,7 @@ public class Habit
this.color = 5; this.color = 5;
this.archived = false; this.archived = false;
this.frequency = new Frequency(3, 7); this.frequency = new Frequency(3, 7);
this.type = YES_NO_HABIT;
checkmarks = factory.buildCheckmarkList(this); checkmarks = factory.buildCheckmarkList(this);
streaks = factory.buildStreakList(this); streaks = factory.buildStreakList(this);
@ -112,6 +119,7 @@ public class Habit
this.archived = model.isArchived(); this.archived = model.isArchived();
this.frequency = model.frequency; this.frequency = model.frequency;
this.reminder = model.reminder; this.reminder = model.reminder;
this.type = model.type;
observable.notifyListeners(); observable.notifyListeners();
} }
@ -232,6 +240,19 @@ public class Habit
return streaks; return streaks;
} }
public int getType()
{
return type;
}
public void setType(int type)
{
if (type != YES_NO_HABIT && type != NUMBER_HABIT)
throw new IllegalArgumentException();
this.type = type;
}
/** /**
* Returns the public URI that identifies this habit * Returns the public URI that identifies this habit
* *
@ -253,6 +274,13 @@ public class Habit
return reminder != null; return reminder != null;
} }
public void invalidateNewerThan(long timestamp)
{
getScores().invalidateNewerThan(timestamp);
getCheckmarks().invalidateNewerThan(timestamp);
getStreaks().invalidateNewerThan(timestamp);
}
public boolean isArchived() public boolean isArchived()
{ {
return archived; return archived;
@ -263,6 +291,11 @@ public class Habit
this.archived = archived; this.archived = archived;
} }
public boolean isNumerical()
{
return type == NUMBER_HABIT;
}
@Override @Override
public String toString() public String toString()
{ {
@ -272,13 +305,7 @@ public class Habit
.append("description", description) .append("description", description)
.append("color", color) .append("color", color)
.append("archived", archived) .append("archived", archived)
.append("type", type)
.toString(); .toString();
} }
public void invalidateNewerThan(long timestamp)
{
getScores().invalidateNewerThan(timestamp);
getCheckmarks().invalidateNewerThan(timestamp);
getStreaks().invalidateNewerThan(timestamp);
}
} }

@ -22,8 +22,6 @@ package org.isoron.uhabits.models.sqlite.records;
import android.annotation.*; import android.annotation.*;
import android.database.*; import android.database.*;
import android.support.annotation.*; import android.support.annotation.*;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.activeandroid.*; import com.activeandroid.*;
import com.activeandroid.annotation.*; import com.activeandroid.annotation.*;
@ -44,7 +42,7 @@ public class HabitRecord extends Model implements SQLiteRecord
public static String SELECT = public static String SELECT =
"select id, color, description, freq_den, freq_num, " + "select id, color, description, freq_den, freq_num, " +
"name, position, reminder_hour, reminder_min, " + "name, position, reminder_hour, reminder_min, " +
"highlight, archived, reminder_days from habits "; "highlight, archived, reminder_days, type from habits ";
@Column(name = "name") @Column(name = "name")
public String name; public String name;
@ -82,6 +80,9 @@ public class HabitRecord extends Model implements SQLiteRecord
@Column(name = "archived") @Column(name = "archived")
public Integer archived; public Integer archived;
@Column(name = "type")
public Integer type;
public HabitRecord() public HabitRecord()
{ {
} }
@ -146,6 +147,8 @@ public class HabitRecord extends Model implements SQLiteRecord
this.highlight = 0; this.highlight = 0;
this.color = model.getColor(); this.color = model.getColor();
this.archived = model.isArchived() ? 1 : 0; this.archived = model.isArchived() ? 1 : 0;
this.type = model.getType();
Frequency freq = model.getFrequency(); Frequency freq = model.getFrequency();
this.freqNum = freq.getNumerator(); this.freqNum = freq.getNumerator();
this.freqDen = freq.getDenominator(); this.freqDen = freq.getDenominator();
@ -177,6 +180,7 @@ public class HabitRecord extends Model implements SQLiteRecord
highlight = c.getInt(9); highlight = c.getInt(9);
archived = c.getInt(10); archived = c.getInt(10);
reminderDays = c.getInt(11); reminderDays = c.getInt(11);
type = c.getInt(12);
} }
public void copyTo(Habit habit) public void copyTo(Habit habit)
@ -187,6 +191,7 @@ public class HabitRecord extends Model implements SQLiteRecord
habit.setColor(this.color); habit.setColor(this.color);
habit.setArchived(this.archived != 0); habit.setArchived(this.archived != 0);
habit.setId(this.getId()); habit.setId(this.getId());
habit.setType(this.type);
if (reminderHour != null && reminderMin != null) if (reminderHour != null && reminderMin != null)
{ {

@ -22,7 +22,7 @@
style="@style/dialogForm" style="@style/dialogForm"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context=".activities.habits.edit.BaseDialog" tools:context=".activities.habits.edit.BooleanHabitDialog"
tools:ignore="MergeRootFrame"> tools:ignore="MergeRootFrame">
<LinearLayout <LinearLayout

@ -0,0 +1,110 @@
<!--
~ Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
~
~ 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 <http://www.gnu.org/licenses/>.
-->
<LinearLayout
android:id="@+id/container"
style="@style/dialogForm"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".activities.habits.edit.BooleanHabitDialog"
tools:ignore="MergeRootFrame">
<LinearLayout
android:id="@+id/formPanel"
style="@style/dialogFormPanel">
<LinearLayout
android:id="@+id/namePanel"
style="@style/dialogFormRow">
<EditText
android:id="@+id/tvName"
style="@style/dialogFormInput"
android:hint="@string/name">
<requestFocus/>
</EditText>
<ImageButton
android:id="@+id/buttonPickColor"
style="@style/dialogFormInputColor"
android:contentDescription="@string/color_picker_default_title"
android:src="?dialogIconChangeColor"/>
</LinearLayout>
<EditText
android:id="@+id/tvDescription"
style="@style/dialogFormInputMultiline"
android:hint="@string/description_hint"/>
<LinearLayout
android:id="@+id/reminderPanel"
style="@style/dialogFormRow">
<TextView
android:id="@+id/TextView2"
style="@style/dialogFormLabel"
android:text="@string/reminder"/>
<TextView
android:id="@+id/tvReminderTime"
style="@style/dialogFormSpinner"/>
</LinearLayout>
<LinearLayout
android:id="@+id/llReminderDays"
style="@style/dialogFormRow">
<TextView
android:id="@+id/TextView3"
style="@style/dialogFormLabel"
android:text=""/>
<TextView
android:id="@+id/tvReminderDays"
style="@style/dialogFormSpinner"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:paddingEnd="16dp"
android:paddingLeft="0dp"
android:paddingRight="16dp"
android:paddingStart="0dp">
<Button
android:id="@+id/buttonDiscard"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/discard"/>
<Button
android:id="@+id/buttonSave"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save"/>
</LinearLayout>
</LinearLayout>

@ -55,6 +55,11 @@
<item>@string/custom_frequency</item> <item>@string/custom_frequency</item>
</string-array> </string-array>
<string-array name="habitTypes" translatable="false">
<item>Yes or No</item>
<item>Number</item>
</string-array>
<string-array name="actions" translatable="false"> <string-array name="actions" translatable="false">
<item>@string/check</item> <item>@string/check</item>
<item>@string/uncheck</item> <item>@string/uncheck</item>

@ -256,4 +256,8 @@
<style name="TimePickerDialog" parent="@style/Theme.AppCompat.Light.Dialog"> <style name="TimePickerDialog" parent="@style/Theme.AppCompat.Light.Dialog">
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
</style> </style>
<style name="DialogWithTitle" parent="@style/Theme.AppCompat.Light.Dialog">
<item name="windowNoTitle">false</item>
</style>
</resources> </resources>

@ -61,7 +61,7 @@ public class ListHabitsScreenTest extends BaseUnitTest
private ConfirmDeleteDialogFactory confirmDeleteDialogFactory; private ConfirmDeleteDialogFactory confirmDeleteDialogFactory;
private CreateHabitDialogFactory createHabitDialogFactory; private CreateBooleanHabitDialogFactory createHabitDialogFactory;
private FilePickerDialogFactory filePickerDialogFactory; private FilePickerDialogFactory filePickerDialogFactory;
@ -73,12 +73,14 @@ public class ListHabitsScreenTest extends BaseUnitTest
private ColorPickerDialogFactory colorPickerDialogFactory; private ColorPickerDialogFactory colorPickerDialogFactory;
private EditHabitDialogFactory editHabitDialogFactory; private EditBooleanHabitDialogFactory editHabitDialogFactory;
private ThemeSwitcher themeSwitcher; private ThemeSwitcher themeSwitcher;
private ListHabitsScreen baseScreen; private ListHabitsScreen baseScreen;
private CreateNumericalHabitDialogFactory createNumericalHabitDialogFactory;
@Before @Before
@Override @Override
public void setUp() public void setUp()
@ -92,15 +94,17 @@ public class ListHabitsScreenTest extends BaseUnitTest
intentFactory = mock(IntentFactory.class); intentFactory = mock(IntentFactory.class);
themeSwitcher = mock(ThemeSwitcher.class); themeSwitcher = mock(ThemeSwitcher.class);
confirmDeleteDialogFactory = mock(ConfirmDeleteDialogFactory.class); confirmDeleteDialogFactory = mock(ConfirmDeleteDialogFactory.class);
createHabitDialogFactory = mock(CreateHabitDialogFactory.class); createHabitDialogFactory = mock(CreateBooleanHabitDialogFactory.class);
filePickerDialogFactory = mock(FilePickerDialogFactory.class); filePickerDialogFactory = mock(FilePickerDialogFactory.class);
colorPickerDialogFactory = mock(ColorPickerDialogFactory.class); colorPickerDialogFactory = mock(ColorPickerDialogFactory.class);
editHabitDialogFactory = mock(EditHabitDialogFactory.class); editHabitDialogFactory = mock(EditBooleanHabitDialogFactory.class);
createNumericalHabitDialogFactory = mock(CreateNumericalHabitDialogFactory.class);
screen = spy(new ListHabitsScreen(activity, commandRunner, dirFinder, screen = spy(new ListHabitsScreen(activity, commandRunner, dirFinder,
rootView, intentFactory, themeSwitcher, confirmDeleteDialogFactory, rootView, intentFactory, themeSwitcher, confirmDeleteDialogFactory,
createHabitDialogFactory, filePickerDialogFactory, createHabitDialogFactory, filePickerDialogFactory,
colorPickerDialogFactory, editHabitDialogFactory)); colorPickerDialogFactory, editHabitDialogFactory,
createNumericalHabitDialogFactory));
doNothing().when(screen).showMessage(anyInt()); doNothing().when(screen).showMessage(anyInt());
@ -114,7 +118,7 @@ public class ListHabitsScreenTest extends BaseUnitTest
@Test @Test
public void testCreateHabitScreen() public void testCreateHabitScreen()
{ {
CreateHabitDialog dialog = mock(CreateHabitDialog.class); CreateBooleanHabitDialog dialog = mock(CreateBooleanHabitDialog.class);
when(createHabitDialogFactory.create()).thenReturn(dialog); when(createHabitDialogFactory.create()).thenReturn(dialog);
screen.showCreateHabitScreen(); screen.showCreateHabitScreen();
@ -189,7 +193,7 @@ public class ListHabitsScreenTest extends BaseUnitTest
@Test @Test
public void testShowEditHabitScreen() public void testShowEditHabitScreen()
{ {
EditHabitDialog dialog = mock(EditHabitDialog.class); EditBooleanHabitDialog dialog = mock(EditBooleanHabitDialog.class);
when(editHabitDialogFactory.create(habit)).thenReturn(dialog); when(editHabitDialogFactory.create(habit)).thenReturn(dialog);
screen.showEditHabitScreen(habit); screen.showEditHabitScreen(habit);

Loading…
Cancel
Save