mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Persist unit and target value of a habit
This commit is contained in:
@@ -12,7 +12,7 @@ android {
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 25
|
||||
|
||||
buildConfigField "Integer", "databaseVersion", "17"
|
||||
buildConfigField "Integer", "databaseVersion", "18"
|
||||
buildConfigField "String", "databaseFilename", "\"uhabits.db\""
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
3
app/src/main/assets/migrations/18.sql
Normal file
3
app/src/main/assets/migrations/18.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
alter table Habits add column target_type integer not null default 0;
|
||||
alter table Habits add column target_value real not null default 0;
|
||||
alter table Habits add column unit text not null default "";
|
||||
@@ -39,8 +39,7 @@ public class CreateBooleanHabitDialog extends BooleanHabitDialog
|
||||
{
|
||||
modifiedHabit = modelFactory.buildHabit();
|
||||
modifiedHabit.setFrequency(Frequency.DAILY);
|
||||
modifiedHabit.setColor(
|
||||
prefs.getDefaultHabitColor(modifiedHabit.getColor()));
|
||||
modifiedHabit.setColor(prefs.getDefaultHabitColor(modifiedHabit.getColor()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,6 +42,7 @@ public class CreateNumericalHabitDialog extends NumericalHabitDialog
|
||||
modifiedHabit.setColor(
|
||||
prefs.getDefaultHabitColor(modifiedHabit.getColor()));
|
||||
modifiedHabit.setType(Habit.NUMBER_HABIT);
|
||||
modifiedHabit.setTargetValue(100);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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 org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.commands.*;
|
||||
|
||||
public class EditNumericalHabitDialog extends NumericalHabitDialog
|
||||
{
|
||||
@Override
|
||||
protected int getTitle()
|
||||
{
|
||||
return R.string.edit_habit;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeHabits()
|
||||
{
|
||||
Long habitId = (Long) getArguments().get("habitId");
|
||||
if (habitId == null)
|
||||
throw new IllegalArgumentException("habitId must be specified");
|
||||
|
||||
originalHabit = habitList.getById(habitId);
|
||||
if (originalHabit == null)
|
||||
throw new IllegalStateException("habit is null");
|
||||
|
||||
modifiedHabit = modelFactory.buildHabit();
|
||||
modifiedHabit.copyFrom(originalHabit);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveHabit()
|
||||
{
|
||||
Command command = appComponent.getEditHabitCommandFactory().
|
||||
create(habitList, originalHabit, modifiedHabit);
|
||||
commandRunner.execute(command, originalHabit.getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 org.isoron.uhabits.models.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
public class EditNumericalHabitDialogFactory
|
||||
{
|
||||
@Inject
|
||||
public EditNumericalHabitDialogFactory()
|
||||
{
|
||||
}
|
||||
|
||||
public EditNumericalHabitDialog create(@NonNull Habit habit)
|
||||
{
|
||||
if (habit.getId() == null)
|
||||
throw new IllegalArgumentException("habit not saved");
|
||||
|
||||
EditNumericalHabitDialog dialog = new EditNumericalHabitDialog();
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("habitId", habit.getId());
|
||||
dialog.setArguments(args);
|
||||
return dialog;
|
||||
}
|
||||
}
|
||||
@@ -22,10 +22,8 @@ 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 android.widget.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.R;
|
||||
@@ -34,11 +32,12 @@ 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 org.isoron.uhabits.utils.*;
|
||||
|
||||
import butterknife.*;
|
||||
|
||||
import static org.isoron.uhabits.R.id.*;
|
||||
|
||||
public abstract class NumericalHabitDialog extends AppCompatDialogFragment
|
||||
{
|
||||
@Nullable
|
||||
@@ -47,9 +46,6 @@ public abstract class NumericalHabitDialog extends AppCompatDialogFragment
|
||||
@Nullable
|
||||
protected Habit modifiedHabit;
|
||||
|
||||
@Nullable
|
||||
protected BaseDialogHelper helper;
|
||||
|
||||
protected Preferences prefs;
|
||||
|
||||
protected CommandRunner commandRunner;
|
||||
@@ -62,6 +58,12 @@ public abstract class NumericalHabitDialog extends AppCompatDialogFragment
|
||||
|
||||
private ColorPickerDialogFactory colorPickerDialogFactory;
|
||||
|
||||
private NumericalHabitDialogHelper helper;
|
||||
|
||||
private boolean tvDescriptionInitialized = false;
|
||||
|
||||
private boolean tvUnitInitialized = false;
|
||||
|
||||
@Override
|
||||
public int getTheme()
|
||||
{
|
||||
@@ -72,10 +74,9 @@ public abstract class NumericalHabitDialog extends AppCompatDialogFragment
|
||||
public void onActivityCreated(Bundle savedInstanceState)
|
||||
{
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
BaseActivity activity = (BaseActivity) getActivity();
|
||||
colorPickerDialogFactory =
|
||||
activity.getComponent().getColorPickerDialogFactory();
|
||||
ActivityComponent component = activity.getComponent();
|
||||
colorPickerDialogFactory = component.getColorPickerDialogFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,7 +98,7 @@ public abstract class NumericalHabitDialog extends AppCompatDialogFragment
|
||||
|
||||
ButterKnife.bind(this, view);
|
||||
|
||||
helper = new BaseDialogHelper(this, view);
|
||||
helper = new NumericalHabitDialogHelper(this, view);
|
||||
getDialog().setTitle(getTitle());
|
||||
initializeHabits();
|
||||
restoreSavedInstance(savedInstanceState);
|
||||
@@ -106,18 +107,10 @@ public abstract class NumericalHabitDialog extends AppCompatDialogFragment
|
||||
}
|
||||
|
||||
@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();
|
||||
@@ -127,73 +120,60 @@ public abstract class NumericalHabitDialog extends AppCompatDialogFragment
|
||||
protected void restoreSavedInstance(@Nullable Bundle bundle)
|
||||
{
|
||||
if (bundle == null) return;
|
||||
modifiedHabit.setColor(
|
||||
bundle.getInt("color", modifiedHabit.getColor()));
|
||||
if (modifiedHabit == null) return;
|
||||
|
||||
int color = bundle.getInt("color", modifiedHabit.getColor());
|
||||
|
||||
modifiedHabit.setColor(color);
|
||||
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();
|
||||
|
||||
@OnFocusChange(tvDescription)
|
||||
void clearDefaultDescription(boolean focused)
|
||||
{
|
||||
if (!focused || tvDescriptionInitialized) return;
|
||||
tvDescriptionInitialized = true;
|
||||
clearDefaultText(helper.tvDescription);
|
||||
}
|
||||
|
||||
private void clearDefaultText(TextView textView)
|
||||
{
|
||||
StyledResources sr = new StyledResources(getContext());
|
||||
int color = sr.getColor(R.attr.highContrastTextColor);
|
||||
textView.setText("");
|
||||
textView.setTextColor(color);
|
||||
}
|
||||
|
||||
@OnFocusChange(tvUnit)
|
||||
void clearDefaultUnit(boolean focused)
|
||||
{
|
||||
if (!focused || tvUnitInitialized) return;
|
||||
tvUnitInitialized = true;
|
||||
clearDefaultText(helper.tvUnit);
|
||||
}
|
||||
|
||||
@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);
|
||||
helper.parseForm(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()
|
||||
{
|
||||
if (modifiedHabit == null) return;
|
||||
|
||||
int color = modifiedHabit.getColor();
|
||||
ColorPickerDialog picker = colorPickerDialogFactory.create(color);
|
||||
|
||||
@@ -206,55 +186,4 @@ public abstract class NumericalHabitDialog 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.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 NumericalHabitDialogHelper
|
||||
{
|
||||
private DialogFragment frag;
|
||||
|
||||
@BindView(R.id.tvName)
|
||||
TextView tvName;
|
||||
|
||||
@BindView(R.id.tvDescription)
|
||||
TextView tvDescription;
|
||||
|
||||
@BindView(R.id.tvUnit)
|
||||
TextView tvUnit;
|
||||
|
||||
@BindView(R.id.tvTargetCount)
|
||||
TextView tvTargetValue;
|
||||
|
||||
@BindView(R.id.tvTargetType)
|
||||
Spinner tvTargetType;
|
||||
|
||||
public NumericalHabitDialogHelper(DialogFragment frag, View view)
|
||||
{
|
||||
this.frag = frag;
|
||||
ButterKnife.bind(this, view);
|
||||
}
|
||||
|
||||
public void parseForm(Habit habit)
|
||||
{
|
||||
habit.setName(tvName.getText().toString().trim());
|
||||
habit.setDescription(tvDescription.getText().toString().trim());
|
||||
habit.setTargetType(tvTargetType.getSelectedItemPosition());
|
||||
habit.setTargetValue(
|
||||
Double.parseDouble(tvTargetValue.getText().toString()));
|
||||
habit.setUnit(tvUnit.getText().toString().trim());
|
||||
}
|
||||
|
||||
public void populateColor(int paletteColor)
|
||||
{
|
||||
tvName.setTextColor(
|
||||
ColorUtils.getColor(frag.getContext(), paletteColor));
|
||||
}
|
||||
|
||||
public void populateForm(final Habit habit)
|
||||
{
|
||||
tvName.setText(habit.getName());
|
||||
|
||||
if(!habit.getDescription().isEmpty())
|
||||
tvDescription.setText(habit.getDescription());
|
||||
|
||||
if(!habit.getUnit().isEmpty())
|
||||
tvUnit.setText(habit.getUnit());
|
||||
|
||||
tvTargetType.setSelection(habit.getTargetType());
|
||||
tvTargetValue.setText(String.format("%.0f", habit.getTargetValue()));
|
||||
populateColor(habit.getColor());
|
||||
}
|
||||
|
||||
public boolean validate(Habit habit)
|
||||
{
|
||||
Boolean valid = true;
|
||||
if (!validateName(habit)) valid = false;
|
||||
if (!validateTargetValue()) valid = false;
|
||||
return valid;
|
||||
}
|
||||
|
||||
private boolean validateTargetValue()
|
||||
{
|
||||
double value = Double.parseDouble(tvTargetValue.getText().toString());
|
||||
if(value <= 0)
|
||||
{
|
||||
tvTargetValue.setError(frag.getString(R.string.validation_number_should_be_positive));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean validateName(Habit habit)
|
||||
{
|
||||
if (habit.getName().isEmpty())
|
||||
{
|
||||
tvName.setError(frag.getString(R.string.validation_name_should_not_be_blank));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -83,8 +83,7 @@ public class ListHabitsController
|
||||
@NonNull ReminderScheduler reminderScheduler,
|
||||
@NonNull TaskRunner taskRunner,
|
||||
@NonNull WidgetUpdater widgetUpdater,
|
||||
@NonNull
|
||||
ImportDataTaskFactory importTaskFactory,
|
||||
@NonNull ImportDataTaskFactory importTaskFactory,
|
||||
@NonNull ExportCSVTaskFactory exportCSVFactory,
|
||||
@NonNull ExportDBTaskFactory exportDBFactory)
|
||||
{
|
||||
|
||||
@@ -97,8 +97,12 @@ public class ListHabitsScreen extends BaseScreen
|
||||
@NonNull
|
||||
private final ThemeSwitcher themeSwitcher;
|
||||
|
||||
@NonNull
|
||||
private CreateNumericalHabitDialogFactory createNumericalHabitDialogFactory;
|
||||
|
||||
@NonNull
|
||||
private EditNumericalHabitDialogFactory editNumericalHabitDialogFactory;
|
||||
|
||||
@Inject
|
||||
public ListHabitsScreen(@NonNull BaseActivity activity,
|
||||
@NonNull CommandRunner commandRunner,
|
||||
@@ -111,6 +115,7 @@ public class ListHabitsScreen extends BaseScreen
|
||||
@NonNull FilePickerDialogFactory filePickerDialogFactory,
|
||||
@NonNull ColorPickerDialogFactory colorPickerFactory,
|
||||
@NonNull EditBooleanHabitDialogFactory editBooleanHabitDialogFactory,
|
||||
@NonNull EditNumericalHabitDialogFactory editNumericalHabitDialogFactory,
|
||||
@NonNull CreateNumericalHabitDialogFactory createNumericalHabitDialogFactory)
|
||||
{
|
||||
super(activity);
|
||||
@@ -121,6 +126,7 @@ public class ListHabitsScreen extends BaseScreen
|
||||
this.createNumericalHabitDialogFactory = createNumericalHabitDialogFactory;
|
||||
this.createBooleanHabitDialogFactory = createBooleanHabitDialogFactory;
|
||||
this.editBooleanHabitDialogFactory = editBooleanHabitDialogFactory;
|
||||
this.editNumericalHabitDialogFactory = editNumericalHabitDialogFactory;
|
||||
this.dirFinder = dirFinder;
|
||||
this.filePickerDialogFactory = filePickerDialogFactory;
|
||||
this.intentFactory = intentFactory;
|
||||
@@ -214,9 +220,18 @@ public class ListHabitsScreen extends BaseScreen
|
||||
|
||||
public void showEditHabitScreen(Habit habit)
|
||||
{
|
||||
EditBooleanHabitDialog dialog;
|
||||
dialog = editBooleanHabitDialogFactory.create(habit);
|
||||
activity.showDialog(dialog, "editHabit");
|
||||
if(habit.isNumerical())
|
||||
{
|
||||
EditNumericalHabitDialog dialog;
|
||||
dialog = editNumericalHabitDialogFactory.create(habit);
|
||||
activity.showDialog(dialog, "editNumericalHabit");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditBooleanHabitDialog dialog;
|
||||
dialog = editBooleanHabitDialogFactory.create(habit);
|
||||
activity.showDialog(dialog, "editHabit");
|
||||
}
|
||||
}
|
||||
|
||||
public void showFAQScreen()
|
||||
|
||||
@@ -95,6 +95,8 @@ public class HabitCardListView extends RecyclerView
|
||||
cardView.setButtonCount(checkmarkCount);
|
||||
cardView.setDataOffset(dataOffset);
|
||||
cardView.setScore(score);
|
||||
cardView.setUnit(habit.getUnit());
|
||||
cardView.setThreshold(habit.getTargetValue());
|
||||
if (controller != null) setupCardViewController(holder);
|
||||
return cardView;
|
||||
}
|
||||
|
||||
@@ -101,12 +101,9 @@ public class HabitCardView extends FrameLayout
|
||||
numberPanel.setButtonCount(buttonCount);
|
||||
}
|
||||
|
||||
public void setValues(int values[])
|
||||
public void setThreshold(double threshold)
|
||||
{
|
||||
checkmarkPanel.setValues(values);
|
||||
numberPanel.setValues(values);
|
||||
numberPanel.setThreshold(10);
|
||||
postInvalidate();
|
||||
numberPanel.setThreshold(threshold);
|
||||
}
|
||||
|
||||
public void setController(Controller controller)
|
||||
@@ -153,6 +150,19 @@ public class HabitCardView extends FrameLayout
|
||||
updateBackground(isSelected);
|
||||
}
|
||||
|
||||
public void setUnit(String unit)
|
||||
{
|
||||
numberPanel.setUnit(unit);
|
||||
}
|
||||
|
||||
public void setValues(int values[])
|
||||
{
|
||||
checkmarkPanel.setValues(values);
|
||||
numberPanel.setValues(values);
|
||||
numberPanel.setThreshold(10);
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
public void triggerRipple(long timestamp)
|
||||
{
|
||||
long today = DateUtils.getStartOfToday();
|
||||
|
||||
@@ -46,7 +46,7 @@ public class NumberButtonView extends View
|
||||
|
||||
private int value;
|
||||
|
||||
private int threshold;
|
||||
private double threshold;
|
||||
|
||||
private String unit;
|
||||
|
||||
@@ -86,6 +86,11 @@ public class NumberButtonView extends View
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param v
|
||||
* @return
|
||||
*/
|
||||
private static String formatValue(int v)
|
||||
{
|
||||
double fv = (double) v;
|
||||
@@ -111,7 +116,7 @@ public class NumberButtonView extends View
|
||||
setOnLongClickListener(v -> controller.onLongClick());
|
||||
}
|
||||
|
||||
public void setThreshold(int threshold)
|
||||
public void setThreshold(double threshold)
|
||||
{
|
||||
this.threshold = threshold;
|
||||
postInvalidate();
|
||||
@@ -146,10 +151,9 @@ public class NumberButtonView extends View
|
||||
String fv = formatValue(value);
|
||||
|
||||
rect.set(0, 0, getWidth(), getHeight());
|
||||
rect.offset(0, - 0.1f * em);
|
||||
canvas.drawText(fv, rect.centerX(), rect.centerY(), pBold);
|
||||
|
||||
rect.offset(0, 1.25f * em);
|
||||
rect.offset(0, 1.2f * em);
|
||||
canvas.drawText(unit, rect.centerX(), rect.centerY(), pRegular);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public class NumberPanelView extends LinearLayout
|
||||
|
||||
private int values[];
|
||||
|
||||
private int threshold;
|
||||
private double threshold;
|
||||
|
||||
private int nButtons;
|
||||
|
||||
@@ -98,7 +98,7 @@ public class NumberPanelView extends LinearLayout
|
||||
int values[] = new int[nButtons];
|
||||
|
||||
for(int i = 0; i < nButtons; i++)
|
||||
values[i] = new Random().nextInt(threshold * 3);
|
||||
values[i] = new Random().nextInt((int)(threshold * 3));
|
||||
|
||||
setValues(values);
|
||||
}
|
||||
@@ -153,7 +153,7 @@ public class NumberPanelView extends LinearLayout
|
||||
setupButtons();
|
||||
}
|
||||
|
||||
public void setThreshold(int threshold)
|
||||
public void setThreshold(double threshold)
|
||||
{
|
||||
this.threshold = threshold;
|
||||
setupButtons();
|
||||
|
||||
@@ -33,6 +33,10 @@ import javax.inject.*;
|
||||
*/
|
||||
public class Habit
|
||||
{
|
||||
public static final int AT_LEAST = 0;
|
||||
|
||||
public static final int AT_MOST = 1;
|
||||
|
||||
public static final String HABIT_URI_FORMAT =
|
||||
"content://org.isoron.uhabits/habit/%d";
|
||||
|
||||
@@ -52,10 +56,8 @@ public class Habit
|
||||
@NonNull
|
||||
private Frequency frequency;
|
||||
|
||||
@NonNull
|
||||
private Integer color;
|
||||
private int color;
|
||||
|
||||
@NonNull
|
||||
private boolean archived;
|
||||
|
||||
@NonNull
|
||||
@@ -64,17 +66,24 @@ public class Habit
|
||||
@NonNull
|
||||
private ScoreList scores;
|
||||
|
||||
private int targetType;
|
||||
|
||||
private double targetValue;
|
||||
|
||||
private int type;
|
||||
|
||||
@NonNull
|
||||
private RepetitionList repetitions;
|
||||
|
||||
@NonNull
|
||||
private CheckmarkList checkmarks;
|
||||
|
||||
@NonNull
|
||||
private String unit;
|
||||
|
||||
@Nullable
|
||||
private Reminder reminder;
|
||||
|
||||
private int type;
|
||||
|
||||
private ModelObservable observable = new ModelObservable();
|
||||
|
||||
/**
|
||||
@@ -90,6 +99,11 @@ public class Habit
|
||||
this.archived = false;
|
||||
this.frequency = new Frequency(3, 7);
|
||||
this.type = YES_NO_HABIT;
|
||||
this.name = "";
|
||||
this.description = "";
|
||||
this.targetType = AT_LEAST;
|
||||
this.targetValue = 0;
|
||||
this.unit = "";
|
||||
|
||||
checkmarks = factory.buildCheckmarkList(this);
|
||||
streaks = factory.buildStreakList(this);
|
||||
@@ -120,6 +134,9 @@ public class Habit
|
||||
this.frequency = model.frequency;
|
||||
this.reminder = model.reminder;
|
||||
this.type = model.type;
|
||||
this.targetValue = model.targetValue;
|
||||
this.targetType = model.targetType;
|
||||
this.unit = model.unit;
|
||||
observable.notifyListeners();
|
||||
}
|
||||
|
||||
@@ -240,6 +257,29 @@ public class Habit
|
||||
return streaks;
|
||||
}
|
||||
|
||||
public int getTargetType()
|
||||
{
|
||||
return targetType;
|
||||
}
|
||||
|
||||
public void setTargetType(int targetType)
|
||||
{
|
||||
if (targetType != AT_LEAST && targetType != AT_MOST)
|
||||
throw new IllegalArgumentException();
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
public double getTargetValue()
|
||||
{
|
||||
return targetValue;
|
||||
}
|
||||
|
||||
public void setTargetValue(double targetValue)
|
||||
{
|
||||
if(targetValue < 0) throw new IllegalArgumentException();
|
||||
this.targetValue = targetValue;
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return type;
|
||||
@@ -253,6 +293,17 @@ public class Habit
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getUnit()
|
||||
{
|
||||
return unit;
|
||||
}
|
||||
|
||||
public void setUnit(@NonNull String unit)
|
||||
{
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public URI that identifies this habit
|
||||
*
|
||||
@@ -306,6 +357,9 @@ public class Habit
|
||||
.append("color", color)
|
||||
.append("archived", archived)
|
||||
.append("type", type)
|
||||
.append("targetType", targetType)
|
||||
.append("targetValue", targetValue)
|
||||
.append("unit", unit)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ public class HabitRecord extends Model implements SQLiteRecord
|
||||
public static String SELECT =
|
||||
"select id, color, description, freq_den, freq_num, " +
|
||||
"name, position, reminder_hour, reminder_min, " +
|
||||
"highlight, archived, reminder_days, type from habits ";
|
||||
"highlight, archived, reminder_days, type, target_type, " +
|
||||
"target_value, unit from habits ";
|
||||
|
||||
@Column(name = "name")
|
||||
public String name;
|
||||
@@ -83,6 +84,15 @@ public class HabitRecord extends Model implements SQLiteRecord
|
||||
@Column(name = "type")
|
||||
public Integer type;
|
||||
|
||||
@Column(name = "target_value")
|
||||
public Double targetValue;
|
||||
|
||||
@Column(name = "target_type")
|
||||
public Integer targetType;
|
||||
|
||||
@Column(name = "unit")
|
||||
public String unit;
|
||||
|
||||
public HabitRecord()
|
||||
{
|
||||
}
|
||||
@@ -148,6 +158,9 @@ public class HabitRecord extends Model implements SQLiteRecord
|
||||
this.color = model.getColor();
|
||||
this.archived = model.isArchived() ? 1 : 0;
|
||||
this.type = model.getType();
|
||||
this.targetType = model.getTargetType();
|
||||
this.targetValue = model.getTargetValue();
|
||||
this.unit = model.getUnit();
|
||||
|
||||
Frequency freq = model.getFrequency();
|
||||
this.freqNum = freq.getNumerator();
|
||||
@@ -181,6 +194,9 @@ public class HabitRecord extends Model implements SQLiteRecord
|
||||
archived = c.getInt(10);
|
||||
reminderDays = c.getInt(11);
|
||||
type = c.getInt(12);
|
||||
targetType = c.getInt(13);
|
||||
targetValue = c.getDouble(14);
|
||||
unit = c.getString(15);
|
||||
}
|
||||
|
||||
public void copyTo(Habit habit)
|
||||
@@ -192,6 +208,9 @@ public class HabitRecord extends Model implements SQLiteRecord
|
||||
habit.setArchived(this.archived != 0);
|
||||
habit.setId(this.getId());
|
||||
habit.setType(this.type);
|
||||
habit.setTargetType(this.targetType);
|
||||
habit.setTargetValue(this.targetValue);
|
||||
habit.setUnit(this.unit);
|
||||
|
||||
if (reminderHour != null && reminderMin != null)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
~ 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"
|
||||
@@ -30,56 +29,87 @@
|
||||
style="@style/dialogFormPanel">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/namePanel"
|
||||
style="@style/dialogFormRow">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/tvName"
|
||||
style="@style/dialogFormInput"
|
||||
android:hint="@string/name">
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/tilName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="6">
|
||||
|
||||
<requestFocus/>
|
||||
</EditText>
|
||||
<EditText
|
||||
android:id="@+id/tvName"
|
||||
style="@style/dialogFormInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/name">
|
||||
<requestFocus/>
|
||||
</EditText>
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/buttonPickColor"
|
||||
style="@style/dialogFormInputColor"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/color_picker_default_title"
|
||||
android:src="?dialogIconChangeColor"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/tvDescription"
|
||||
style="@style/dialogFormInputMultiline"
|
||||
android:hint="@string/description_hint"/>
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/reminderPanel"
|
||||
style="@style/dialogFormRow">
|
||||
<EditText
|
||||
android:id="@+id/tvDescription"
|
||||
style="@style/dialogFormInputMultiline"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Question"
|
||||
android:text="e.g. How many steps did you walk today?"
|
||||
android:textColor="?attr/mediumContrastTextColor"/>
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/TextView2"
|
||||
style="@style/dialogFormLabel"
|
||||
android:text="@string/reminder"/>
|
||||
<LinearLayout style="@style/dialogFormRow">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvReminderTime"
|
||||
style="@style/dialogFormSpinner"/>
|
||||
</LinearLayout>
|
||||
<Spinner
|
||||
android:id="@+id/tvTargetType"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="3"
|
||||
android:entries="@array/targetValues"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llReminderDays"
|
||||
style="@style/dialogFormRow">
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="2">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/TextView3"
|
||||
style="@style/dialogFormLabel"
|
||||
android:text=""/>
|
||||
<EditText
|
||||
android:id="@+id/tvTargetCount"
|
||||
style="@style/dialogFormInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Count"
|
||||
android:inputType="numberDecimal"
|
||||
android:text="100"
|
||||
/>
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvReminderDays"
|
||||
style="@style/dialogFormSpinner"/>
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="2">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/tvUnit"
|
||||
style="@style/dialogFormInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Unit"
|
||||
android:text="e.g. steps"
|
||||
android:textColor="?attr/mediumContrastTextColor"
|
||||
android:inputType="text"/>
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -87,17 +117,14 @@
|
||||
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">
|
||||
android:gravity="end">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonDiscard"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/discard"/>
|
||||
|
||||
<Button
|
||||
@@ -105,6 +132,7 @@
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/save"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -82,5 +82,16 @@
|
||||
<item>365</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="targetValues" translatable="false">
|
||||
<item>At least</item>
|
||||
<item>At most</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="targetIntervals" translatable="false">
|
||||
<item>daily</item>
|
||||
<item>weekly</item>
|
||||
<item>montly</item>
|
||||
</string-array>
|
||||
|
||||
<string name="snooze_interval_default" translatable="false">15</string>
|
||||
</resources>
|
||||
@@ -89,7 +89,6 @@
|
||||
<style name="dialogFormRow">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_marginTop">12dp</item>
|
||||
<item name="android:orientation">horizontal</item>
|
||||
<item name="android:minWidth">300dp</item>
|
||||
<item name="android:gravity">start|center_vertical</item>
|
||||
@@ -104,10 +103,11 @@
|
||||
<style name="dialogFormPanel">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_marginBottom">8dp</item>
|
||||
<item name="android:orientation">vertical</item>
|
||||
<item name="android:paddingLeft">24dp</item>
|
||||
<item name="android:paddingRight">24dp</item>
|
||||
<item name="android:paddingTop">12dp</item>
|
||||
<item name="android:paddingBottom">12dp</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -81,6 +81,8 @@ public class ListHabitsScreenTest extends BaseUnitTest
|
||||
|
||||
private CreateNumericalHabitDialogFactory createNumericalHabitDialogFactory;
|
||||
|
||||
private EditNumericalHabitDialogFactory editNumericalHabitDialogFactory;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp()
|
||||
@@ -98,12 +100,16 @@ public class ListHabitsScreenTest extends BaseUnitTest
|
||||
filePickerDialogFactory = mock(FilePickerDialogFactory.class);
|
||||
colorPickerDialogFactory = mock(ColorPickerDialogFactory.class);
|
||||
editHabitDialogFactory = mock(EditBooleanHabitDialogFactory.class);
|
||||
createNumericalHabitDialogFactory = mock(CreateNumericalHabitDialogFactory.class);
|
||||
editNumericalHabitDialogFactory =
|
||||
mock(EditNumericalHabitDialogFactory.class);
|
||||
createNumericalHabitDialogFactory =
|
||||
mock(CreateNumericalHabitDialogFactory.class);
|
||||
|
||||
screen = spy(new ListHabitsScreen(activity, commandRunner, dirFinder,
|
||||
rootView, intentFactory, themeSwitcher, confirmDeleteDialogFactory,
|
||||
createHabitDialogFactory, filePickerDialogFactory,
|
||||
colorPickerDialogFactory, editHabitDialogFactory,
|
||||
editNumericalHabitDialogFactory,
|
||||
createNumericalHabitDialogFactory));
|
||||
|
||||
doNothing().when(screen).showMessage(anyInt());
|
||||
@@ -126,6 +132,29 @@ public class ListHabitsScreenTest extends BaseUnitTest
|
||||
// verify(activity).showDialog(eq(dialog), any());
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void testOnAttached()
|
||||
{
|
||||
screen.onAttached();
|
||||
verify(commandRunner).addListener(screen);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnCommand()
|
||||
{
|
||||
Command c = mock(Command.class);
|
||||
when(c.getExecuteStringId()).thenReturn(R.string.toast_habit_deleted);
|
||||
screen.onCommandExecuted(c, null);
|
||||
verify(screen).showMessage(R.string.toast_habit_deleted);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnDetach()
|
||||
{
|
||||
screen.onDettached();
|
||||
verify(commandRunner).removeListener(screen);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnResult_bugReport()
|
||||
{
|
||||
@@ -264,27 +293,4 @@ public class ListHabitsScreenTest extends BaseUnitTest
|
||||
verify(themeSwitcher).toggleNightMode();
|
||||
verify(activity).restartWithFade();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnAttached()
|
||||
{
|
||||
screen.onAttached();
|
||||
verify(commandRunner).addListener(screen);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnDetach()
|
||||
{
|
||||
screen.onDettached();
|
||||
verify(commandRunner).removeListener(screen);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnCommand()
|
||||
{
|
||||
Command c = mock(Command.class);
|
||||
when(c.getExecuteStringId()).thenReturn(R.string.toast_habit_deleted);
|
||||
screen.onCommandExecuted(c, null);
|
||||
verify(screen).showMessage(R.string.toast_habit_deleted);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user