Make reminder days into active days for the habit

pull/633/head
KristianTashkov 5 years ago
parent 1ffc079042
commit 7e98a62541

@ -69,9 +69,9 @@ public class EditHabitSteps
onView(withId(R.id.done_button)).perform(click()); onView(withId(R.id.done_button)).perform(click());
} }
public static void clickReminderDays() public static void clickActiveDays()
{ {
onView(withId(R.id.reminderDatePicker)).perform(click()); onView(withId(R.id.activeDaysDatePicker)).perform(click());
} }
public static void unselectAllDays() public static void unselectAllDays()

@ -80,7 +80,7 @@ public class HistoryChartTest extends BaseViewTest
chart.setIsEditable(true); chart.setIsEditable(true);
chart.tap(dpToPixels(340), dpToPixels(40)); chart.tap(dpToPixels(340), dpToPixels(40));
verify(controller).onToggleCheckmark(today, Checkmark.SKIP); verify(controller).onToggleCheckmark(today, Checkmark.SKIP_MANUAL);
chart.tap(dpToPixels(340), dpToPixels(40)); chart.tap(dpToPixels(340), dpToPixels(40));
verify(controller).onToggleCheckmark(today, Checkmark.NO); verify(controller).onToggleCheckmark(today, Checkmark.NO);
chart.tap(dpToPixels(340), dpToPixels(40)); chart.tap(dpToPixels(340), dpToPixels(40));

@ -50,7 +50,7 @@ public class NotesCardTest extends BaseViewTest
super.setUp(); super.setUp();
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); habit.setReminder(new Reminder(8, 30));
view = LayoutInflater view = LayoutInflater
.from(targetContext) .from(targetContext)

@ -47,7 +47,7 @@ public class SubtitleCardTest extends BaseViewTest
super.setUp(); super.setUp();
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); habit.setReminder(new Reminder(8, 30));
view = LayoutInflater view = LayoutInflater
.from(targetContext) .from(targetContext)

@ -71,7 +71,7 @@ public class CheckmarkWidgetTest extends BaseViewTest
// possible to capture intents sent to BroadcastReceivers. // possible to capture intents sent to BroadcastReceivers.
button.performClick(); button.performClick();
sleep(1000); sleep(1000);
assertThat(checkmarks.getTodayValue(), equalTo(SKIP)); assertThat(checkmarks.getTodayValue(), equalTo(SKIP_MANUAL));
button.performClick(); button.performClick();
sleep(1000); sleep(1000);

@ -400,7 +400,7 @@ public class HistoryChart extends ScrollableChart
float round = dpToPixels(getContext(), 2); float round = dpToPixels(getContext(), 2);
canvas.drawRoundRect(location, round, round, pSquareBg); canvas.drawRoundRect(location, round, round, pSquareBg);
if (!isNumerical && checkmark == SKIP) if (!isNumerical && (checkmark == SKIP_MANUAL || checkmark == SKIP_AUTO))
{ {
pSquareBg.setColor(backgroundColor); pSquareBg.setColor(backgroundColor);
pSquareBg.setStrokeWidth(columnWidth * 0.025f); pSquareBg.setStrokeWidth(columnWidth * 0.025f);

@ -54,7 +54,7 @@ class EditHabitActivity : AppCompatActivity() {
var freqDen = 1 var freqDen = 1
var reminderHour = -1 var reminderHour = -1
var reminderMin = -1 var reminderMin = -1
var reminderDays: WeekdayList = WeekdayList.EVERY_DAY var activeDays: WeekdayList = WeekdayList.EVERY_DAY
override fun onCreate(state: Bundle?) { override fun onCreate(state: Bundle?) {
super.onCreate(state) super.onCreate(state)
@ -77,8 +77,9 @@ class EditHabitActivity : AppCompatActivity() {
if (habit.hasReminder()) { if (habit.hasReminder()) {
reminderHour = habit.reminder.hour reminderHour = habit.reminder.hour
reminderMin = habit.reminder.minute reminderMin = habit.reminder.minute
reminderDays = habit.reminder.days
} }
activeDays = habit.activeDays
binding.nameInput.setText(habit.name) binding.nameInput.setText(habit.name)
binding.questionInput.setText(habit.question) binding.questionInput.setText(habit.question)
binding.notesInput.setText(habit.description) binding.notesInput.setText(habit.description)
@ -96,7 +97,7 @@ class EditHabitActivity : AppCompatActivity() {
freqDen = state.getInt("freqDen") freqDen = state.getInt("freqDen")
reminderHour = state.getInt("reminderHour") reminderHour = state.getInt("reminderHour")
reminderMin = state.getInt("reminderMin") reminderMin = state.getInt("reminderMin")
reminderDays = WeekdayList(state.getInt("reminderDays")) activeDays = WeekdayList(state.getInt("activeDays"))
} }
updateColors() updateColors()
@ -168,21 +169,21 @@ class EditHabitActivity : AppCompatActivity() {
override fun onTimeCleared(view: RadialPickerLayout?) { override fun onTimeCleared(view: RadialPickerLayout?) {
reminderHour = -1 reminderHour = -1
reminderMin = -1 reminderMin = -1
reminderDays = WeekdayList.EVERY_DAY
populateReminder() populateReminder()
} }
}, currentHour, currentMin, is24HourMode, androidColor) }, currentHour, currentMin, is24HourMode, androidColor)
dialog.show(supportFragmentManager, "timePicker") dialog.show(supportFragmentManager, "timePicker")
} }
binding.reminderDatePicker.setOnClickListener { populateActiveDays()
binding.activeDaysDatePicker.setOnClickListener {
val dialog = WeekdayPickerDialog() val dialog = WeekdayPickerDialog()
dialog.setListener { days -> dialog.setListener { days ->
reminderDays = days activeDays = days
if (reminderDays.isEmpty) reminderDays = WeekdayList.EVERY_DAY if (activeDays.isEmpty) activeDays = WeekdayList.EVERY_DAY
populateReminder() populateActiveDays()
} }
dialog.setSelectedDays(reminderDays) dialog.setSelectedDays(activeDays)
dialog.show(supportFragmentManager, "dayPicker") dialog.show(supportFragmentManager, "dayPicker")
} }
@ -210,8 +211,9 @@ class EditHabitActivity : AppCompatActivity() {
habit.description = notesInput.text.trim().toString() habit.description = notesInput.text.trim().toString()
habit.color = paletteColor habit.color = paletteColor
if (reminderHour >= 0) { if (reminderHour >= 0) {
habit.setReminder(Reminder(reminderHour, reminderMin, reminderDays)) habit.setReminder(Reminder(reminderHour, reminderMin))
} }
habit.activeDays = activeDays
habit.frequency = Frequency(freqNum, freqDen) habit.frequency = Frequency(freqNum, freqDen)
if (habitType == Habit.NUMBER_HABIT) { if (habitType == Habit.NUMBER_HABIT) {
habit.targetValue = targetInput.text.toString().toDouble() habit.targetValue = targetInput.text.toString().toDouble()
@ -251,18 +253,17 @@ class EditHabitActivity : AppCompatActivity() {
private fun populateReminder() { private fun populateReminder() {
if (reminderHour < 0) { if (reminderHour < 0) {
binding.reminderTimePicker.text = getString(R.string.reminder_off) binding.reminderTimePicker.text = getString(R.string.reminder_off)
binding.reminderDatePicker.visibility = View.GONE
binding.reminderDivider.visibility = View.GONE
} else { } else {
val time = AndroidDateUtils.formatTime(this, reminderHour, reminderMin) val time = AndroidDateUtils.formatTime(this, reminderHour, reminderMin)
val daysArray = reminderDays.toArray()
binding.reminderTimePicker.text = time binding.reminderTimePicker.text = time
binding.reminderDatePicker.visibility = View.VISIBLE
binding.reminderDivider.visibility = View.VISIBLE
binding.reminderDatePicker.text = AndroidDateUtils.formatWeekdayList(this, daysArray)
} }
} }
private fun populateActiveDays() {
val daysArray = activeDays.toArray()
binding.activeDaysDatePicker.text = AndroidDateUtils.formatWeekdayList(this, daysArray)
}
private fun populateFrequency() { private fun populateFrequency() {
binding.booleanFrequencyPicker.text = when { binding.booleanFrequencyPicker.text = when {
freqNum == 1 && freqDen == 1 -> getString(R.string.every_day) freqNum == 1 && freqDen == 1 -> getString(R.string.every_day)
@ -301,7 +302,7 @@ class EditHabitActivity : AppCompatActivity() {
putInt("freqDen", freqDen) putInt("freqDen", freqDen)
putInt("reminderHour", reminderHour) putInt("reminderHour", reminderHour)
putInt("reminderMin", reminderMin) putInt("reminderMin", reminderMin)
putInt("reminderDays", reminderDays.toInteger()) putInt("activeDays", activeDays.toInteger())
} }
} }
} }

@ -104,11 +104,12 @@ class CheckmarkButtonView(
fun draw(canvas: Canvas) { fun draw(canvas: Canvas) {
paint.color = when (value) { paint.color = when (value) {
YES_MANUAL -> color YES_MANUAL -> color
SKIP -> color SKIP_MANUAL -> color
else -> lowContrastColor else -> lowContrastColor
} }
val id = when (value) { val id = when (value) {
SKIP -> R.string.fa_skipped SKIP_MANUAL -> R.string.fa_skipped
SKIP_AUTO -> R.string.fa_skipped
NO -> R.string.fa_times NO -> R.string.fa_times
else -> R.string.fa_check else -> R.string.fa_check
} }

@ -76,7 +76,7 @@ public class CheckmarkWidgetView extends HabitWidgetView {
switch (checkmarkState) { switch (checkmarkState) {
case Checkmark.YES_MANUAL: case Checkmark.YES_MANUAL:
case Checkmark.SKIP: case Checkmark.SKIP_MANUAL:
bgColor = activeColor; bgColor = activeColor;
fgColor = res.getColor(R.attr.highContrastReverseTextColor); fgColor = res.getColor(R.attr.highContrastReverseTextColor);
setShadowAlpha(0x4f); setShadowAlpha(0x4f);
@ -85,6 +85,7 @@ public class CheckmarkWidgetView extends HabitWidgetView {
break; break;
case Checkmark.YES_AUTO: case Checkmark.YES_AUTO:
case Checkmark.SKIP_AUTO:
case Checkmark.NO: case Checkmark.NO:
default: default:
getResources().getString(R.string.fa_times); getResources().getString(R.string.fa_times);
@ -118,7 +119,8 @@ public class CheckmarkWidgetView extends HabitWidgetView {
case Checkmark.YES_MANUAL: case Checkmark.YES_MANUAL:
case Checkmark.YES_AUTO: case Checkmark.YES_AUTO:
return getResources().getString(R.string.fa_check); return getResources().getString(R.string.fa_check);
case Checkmark.SKIP: case Checkmark.SKIP_MANUAL:
case Checkmark.SKIP_AUTO:
return getResources().getString(R.string.fa_skipped); return getResources().getString(R.string.fa_skipped);
case Checkmark.NO: case Checkmark.NO:
default: default:

@ -199,19 +199,22 @@
style="@style/FormDropdown" style="@style/FormDropdown"
android:id="@+id/reminderTimePicker" android:id="@+id/reminderTimePicker"
android:text="@string/reminder_off" /> android:text="@string/reminder_off" />
</LinearLayout>
</FrameLayout>
<View <!-- ActiveDays -->
style="@style/FormDivider" <FrameLayout style="@style/FormOuterBox">
android:id="@+id/reminderDivider"/> <LinearLayout style="@style/FormInnerBox">
<TextView
style="@style/FormLabel"
android:text="@string/active_days" />
<TextView <TextView
style="@style/FormDropdown" style="@style/FormDropdown"
android:id="@+id/reminderDatePicker" android:id="@+id/activeDaysDatePicker"
android:text="" /> android:text="" />
</LinearLayout> </LinearLayout>
</FrameLayout> </FrameLayout>
<!-- Notes --> <!-- Notes -->
<FrameLayout style="@style/FormOuterBox"> <FrameLayout style="@style/FormOuterBox">
<LinearLayout style="@style/FormInnerBox"> <LinearLayout style="@style/FormInnerBox">

@ -179,6 +179,7 @@
<string name="first_day_of_the_week">First day of the week</string> <string name="first_day_of_the_week">First day of the week</string>
<string name="default_reminder_question">Have you completed this habit today?</string> <string name="default_reminder_question">Have you completed this habit today?</string>
<string name="notes">Notes</string> <string name="notes">Notes</string>
<string name="active_days">Active on</string>
<string name="example_notes">(Optional)</string> <string name="example_notes">(Optional)</string>
<string name="yes_or_no_example">e.g. Did you wake up early today? Did you exercise? Did you play chess?</string> <string name="yes_or_no_example">e.g. Did you wake up early today? Did you exercise? Did you play chess?</string>
<string name="measurable">Measurable</string> <string name="measurable">Measurable</string>

@ -22,5 +22,5 @@ package org.isoron.uhabits.core;
public class Config public class Config
{ {
public static final String DATABASE_FILENAME = "uhabits.db"; public static final String DATABASE_FILENAME = "uhabits.db";
public static int DATABASE_VERSION = 23; public static int DATABASE_VERSION = 24;
} }

@ -46,6 +46,8 @@ public class EditHabitCommand extends Command
final boolean hasTargetChanged; final boolean hasTargetChanged;
final boolean hasActiveDaysChanged;
public EditHabitCommand(@Provided @NonNull ModelFactory modelFactory, public EditHabitCommand(@Provided @NonNull ModelFactory modelFactory,
@NonNull HabitList habitList, @NonNull HabitList habitList,
@NonNull Habit original, @NonNull Habit original,
@ -68,6 +70,7 @@ public class EditHabitCommand extends Command
hasTargetChanged = hasTargetChanged =
(original.getTargetType() != modified.getTargetType() || (original.getTargetType() != modified.getTargetType() ||
original.getTargetValue() != modified.getTargetValue()); original.getTargetValue() != modified.getTargetValue());
hasActiveDaysChanged = original.getActiveDays() != modified.getActiveDays();
} }
@Override @Override
@ -97,7 +100,7 @@ public class EditHabitCommand extends Command
habit.copyFrom(model); habit.copyFrom(model);
habitList.update(habit); habitList.update(habit);
if (hasFrequencyChanged || hasTargetChanged) if (hasFrequencyChanged || hasTargetChanged || hasActiveDaysChanged)
habit.invalidateNewerThan(Timestamp.ZERO); habit.invalidateNewerThan(Timestamp.ZERO);
} }

@ -189,21 +189,21 @@ public class RewireDBImporter extends AbstractImporter
int rewireReminder = Integer.parseInt(c.getString(0)); int rewireReminder = Integer.parseInt(c.getString(0));
if (rewireReminder <= 0 || rewireReminder >= 1440) return; if (rewireReminder <= 0 || rewireReminder >= 1440) return;
boolean reminderDays[] = new boolean[7]; boolean activeDays[] = new boolean[7];
String activeDays[] = c.getString(1).split(","); String rewireActiveDays[] = c.getString(1).split(",");
for (String d : activeDays) for (String d : rewireActiveDays)
{ {
int idx = (Integer.parseInt(d) + 1) % 7; int idx = (Integer.parseInt(d) + 1) % 7;
reminderDays[idx] = true; activeDays[idx] = true;
} }
int hour = rewireReminder / 60; int hour = rewireReminder / 60;
int minute = rewireReminder % 60; int minute = rewireReminder % 60;
WeekdayList days = new WeekdayList(reminderDays);
Reminder reminder = new Reminder(hour, minute, days); Reminder reminder = new Reminder(hour, minute);
habit.setReminder(reminder); habit.setReminder(reminder);
habit.setActiveDays(new WeekdayList(activeDays));
habitList.update(habit); habitList.update(habit);
} }
finally finally

@ -37,10 +37,15 @@ import static org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle;
@ThreadSafe @ThreadSafe
public final class Checkmark public final class Checkmark
{ {
/**
* Indicates that there was an implicit skip at the timestamp.
*/
public static final int SKIP_AUTO = 4;
/** /**
* Indicates that there was an explicit skip at the timestamp. * Indicates that there was an explicit skip at the timestamp.
*/ */
public static final int SKIP = 3; public static final int SKIP_MANUAL = 3;
/** /**
* Indicates that there was a repetition at the timestamp. * Indicates that there was a repetition at the timestamp.
@ -64,7 +69,7 @@ public final class Checkmark
/** /**
* The value of the checkmark. * The value of the checkmark.
* <p> * <p>
* For boolean habits, this equals either NO, YES_AUTO, YES_MANUAL or SKIP. * For boolean habits, this equals either NO, YES_AUTO, YES_MANUAL, SKIP_MANUAL or SKIP_AUTO.
* <p> * <p>
* For numerical habits, this number is stored in thousandths. That * For numerical habits, this number is stored in thousandths. That
* is, if the user enters value 1.50 on the app, it is stored as 1500. * is, if the user enters value 1.50 on the app, it is stored as 1500.

@ -51,7 +51,8 @@ public abstract class CheckmarkList
@NonNull @NonNull
static List<Checkmark> buildCheckmarksFromIntervals(Repetition[] reps, static List<Checkmark> buildCheckmarksFromIntervals(Repetition[] reps,
ArrayList<Interval> intervals) ArrayList<Interval> intervals,
boolean[] activeDays)
{ {
if (reps.length == 0) throw new IllegalArgumentException(); if (reps.length == 0) throw new IllegalArgumentException();
@ -75,6 +76,16 @@ public abstract class CheckmarkList
} }
} }
int realWeekday =
DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK) % 7;
for (int i = 0; i < nDays; i++)
{
if (!activeDays[realWeekday])
checkmarks.set(i, new Checkmark(today.minus(i), SKIP_AUTO));
realWeekday = (realWeekday + 6) % 7;
}
for (Repetition rep : reps) for (Repetition rep : reps)
{ {
Timestamp date = rep.getTimestamp(); Timestamp date = rep.getTimestamp();
@ -386,7 +397,7 @@ public abstract class CheckmarkList
ArrayList<Interval> intervals; ArrayList<Interval> intervals;
intervals = buildIntervals(habit.getFrequency(), reps); intervals = buildIntervals(habit.getFrequency(), reps);
snapIntervalsTogether(intervals); snapIntervalsTogether(intervals);
add(buildCheckmarksFromIntervals(reps, intervals)); add(buildCheckmarksFromIntervals(reps, intervals, habit.getActiveDays().toArray()));
} }
public List<Checkmark> getAll() { public List<Checkmark> getAll() {

@ -279,6 +279,17 @@ public class Habit
data.unit = unit; data.unit = unit;
} }
@NonNull
public synchronized WeekdayList getActiveDays()
{
return data.activeDays;
}
public synchronized void setActiveDays(@NonNull WeekdayList activeDays)
{
data.activeDays = activeDays;
}
/** /**
* Returns the public URI that identifies this habit * Returns the public URI that identifies this habit
* *
@ -393,6 +404,9 @@ public class Habit
@Nullable @Nullable
public Reminder reminder; public Reminder reminder;
@Nullable
private WeekdayList activeDays;
public int position; public int position;
public HabitData() public HabitData()
@ -408,6 +422,7 @@ public class Habit
this.targetValue = 100; this.targetValue = 100;
this.unit = ""; this.unit = "";
this.position = 0; this.position = 0;
this.activeDays = WeekdayList.EVERY_DAY;
} }
public HabitData(@NonNull HabitData model) public HabitData(@NonNull HabitData model)
@ -424,6 +439,7 @@ public class Habit
this.unit = model.unit; this.unit = model.unit;
this.reminder = model.reminder; this.reminder = model.reminder;
this.position = model.position; this.position = model.position;
this.activeDays = model.activeDays;
} }
@Override @Override
@ -442,6 +458,7 @@ public class Habit
.append("reminder", reminder) .append("reminder", reminder)
.append("position", position) .append("position", position)
.append("question", question) .append("question", question)
.append("activeDays", activeDays)
.toString(); .toString();
} }
@ -467,6 +484,7 @@ public class Habit
.append(reminder, habitData.reminder) .append(reminder, habitData.reminder)
.append(position, habitData.position) .append(position, habitData.position)
.append(question, habitData.question) .append(question, habitData.question)
.append(activeDays, habitData.activeDays)
.isEquals(); .isEquals();
} }
@ -486,6 +504,7 @@ public class Habit
.append(reminder) .append(reminder)
.append(position) .append(position)
.append(question) .append(question)
.append(activeDays)
.toHashCode(); .toHashCode();
} }
} }

@ -32,19 +32,10 @@ public final class Reminder
private final int minute; private final int minute;
private final WeekdayList days; public Reminder(int hour, int minute)
public Reminder(int hour, int minute, @NonNull WeekdayList days)
{ {
this.hour = hour; this.hour = hour;
this.minute = minute; this.minute = minute;
this.days = days;
}
@NonNull
public WeekdayList getDays()
{
return days;
} }
public int getHour() public int getHour()
@ -74,7 +65,6 @@ public final class Reminder
return new EqualsBuilder() return new EqualsBuilder()
.append(hour, reminder.hour) .append(hour, reminder.hour)
.append(minute, reminder.minute) .append(minute, reminder.minute)
.append(days, reminder.days)
.isEquals(); .isEquals();
} }
@ -84,7 +74,6 @@ public final class Reminder
return new HashCodeBuilder(17, 37) return new HashCodeBuilder(17, 37)
.append(hour) .append(hour)
.append(minute) .append(minute)
.append(days)
.toHashCode(); .toHashCode();
} }
@ -94,7 +83,6 @@ public final class Reminder
return new ToStringBuilder(this, defaultToStringStyle()) return new ToStringBuilder(this, defaultToStringStyle())
.append("hour", hour) .append("hour", hour)
.append("minute", minute) .append("minute", minute)
.append("days", days)
.toString(); .toString();
} }
} }

@ -36,7 +36,7 @@ public final class Repetition
/** /**
* The value of the repetition. * The value of the repetition.
* *
* For boolean habits, this equals YES_MANUAL if performed or SKIP if skipped. * For boolean habits, this equals YES_MANUAL if performed or SKIP_MANUAL if skipped.
* For numerical habits, this number is stored in thousandths. That is, if the user enters * For numerical habits, this number is stored in thousandths. That is, if the user enters
* value 1.50 on the app, it is here stored as 1500. * value 1.50 on the app, it is here stored as 1500.
*/ */
@ -61,11 +61,12 @@ public final class Repetition
switch(value) { switch(value) {
case NO: case NO:
case YES_AUTO: case YES_AUTO:
case SKIP_AUTO:
return YES_MANUAL; return YES_MANUAL;
case YES_MANUAL: case YES_MANUAL:
return SKIP; return SKIP_MANUAL;
default: default:
case SKIP: case SKIP_MANUAL:
return NO; return NO;
} }
} }

@ -267,21 +267,33 @@ public abstract class ScoreList implements Iterable<Score>
{ {
if (from.isNewerThan(to)) return; if (from.isNewerThan(to)) return;
final double freq = habit.getFrequency().toDouble(); final int activeDays = habit.getActiveDays().count();
final Frequency frequency = habit.getFrequency();
final double nonSkippedDays = (double)frequency.getDenominator() * activeDays / 7;
final double freq = Math.min((double)frequency.getNumerator() / nonSkippedDays, 1);
final int checkmarkValues[] = habit.getCheckmarks().getValues(from, to); final int checkmarkValues[] = habit.getCheckmarks().getValues(from, to);
List<Score> scores = new LinkedList<>(); List<Score> scores = new LinkedList<>();
for (int i = 0; i < checkmarkValues.length; i++) for (int i = 0; i < checkmarkValues.length; i++)
{ {
boolean isSkip = false;
double value = checkmarkValues[checkmarkValues.length - i - 1]; double value = checkmarkValues[checkmarkValues.length - i - 1];
if (habit.isNumerical()) if (habit.isNumerical())
{ {
value /= 1000; value /= 1000;
value /= habit.getTargetValue(); value /= habit.getTargetValue();
value = Math.min(1, value);
} else if(value == Checkmark.SKIP_AUTO)
{
isSkip = true;
}
else value = Math.min(1, value);
if(!isSkip)
{
previousValue = Score.compute(freq, previousValue, value);
} }
value = Math.min(1, value);
previousValue = Score.compute(freq, previousValue, value);
scores.add(new Score(from.plus(i), previousValue)); scores.add(new Score(from.plus(i), previousValue));
} }

@ -73,6 +73,15 @@ public final class WeekdayList
return packedList; return packedList;
} }
public int count() {
int count = 0;
for (int i = 0; i < 7; i++)
{
if (weekdays[i]) count += 1;
}
return count;
}
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {

@ -57,8 +57,8 @@ public class HabitRecord
@Column(name = "reminder_min") @Column(name = "reminder_min")
public Integer reminderMin; public Integer reminderMin;
@Column(name = "reminder_days") @Column(name = "active_days")
public Integer reminderDays; public Integer activeDays;
@Column @Column
public Integer highlight; public Integer highlight;
@ -99,7 +99,7 @@ public class HabitRecord
Frequency freq = model.getFrequency(); Frequency freq = model.getFrequency();
this.freqNum = freq.getNumerator(); this.freqNum = freq.getNumerator();
this.freqDen = freq.getDenominator(); this.freqDen = freq.getDenominator();
this.reminderDays = 0; this.activeDays = 0;
this.reminderMin = null; this.reminderMin = null;
this.reminderHour = null; this.reminderHour = null;
@ -108,8 +108,8 @@ public class HabitRecord
Reminder reminder = model.getReminder(); Reminder reminder = model.getReminder();
this.reminderHour = reminder.getHour(); this.reminderHour = reminder.getHour();
this.reminderMin = reminder.getMinute(); this.reminderMin = reminder.getMinute();
this.reminderDays = reminder.getDays().toInteger();
} }
this.activeDays = model.getActiveDays().toInteger();
} }
public void copyTo(Habit habit) public void copyTo(Habit habit)
@ -129,8 +129,8 @@ public class HabitRecord
if (reminderHour != null && reminderMin != null) if (reminderHour != null && reminderMin != null)
{ {
habit.setReminder(new Reminder(reminderHour, reminderMin, habit.setReminder(new Reminder(reminderHour, reminderMin));
new WeekdayList(reminderDays)));
} }
habit.setActiveDays(new WeekdayList(this.activeDays));
} }
} }

@ -219,10 +219,10 @@ public class NotificationTray
if (!habit.hasReminder()) return false; if (!habit.hasReminder()) return false;
Reminder reminder = habit.getReminder(); Reminder reminder = habit.getReminder();
boolean reminderDays[] = reminder.getDays().toArray(); boolean activeDays[] = habit.getActiveDays().toArray();
int weekday = timestamp.getWeekday(); int weekday = timestamp.getWeekday();
return reminderDays[weekday]; return activeDays[weekday];
} }
} }
} }

@ -0,0 +1,3 @@
alter table Habits add column active_days integer not null default 127;
update Habits set active_days = reminder_days

@ -38,6 +38,7 @@ import java.io.*;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.*;
import static org.isoron.uhabits.core.Config.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
@ -125,7 +126,7 @@ public class BaseUnitTest
DriverManager.getConnection("jdbc:sqlite::memory:")); DriverManager.getConnection("jdbc:sqlite::memory:"));
db.execute("pragma user_version=8;"); db.execute("pragma user_version=8;");
MigrationHelper helper = new MigrationHelper(db); MigrationHelper helper = new MigrationHelper(db);
helper.migrateTo(23); helper.migrateTo(DATABASE_VERSION);
return db; return db;
} }
catch (SQLException e) catch (SQLException e)

@ -41,7 +41,7 @@ public class CreateHabitCommandTest extends BaseUnitTest
model = fixtures.createEmptyHabit(); model = fixtures.createEmptyHabit();
model.setName("New habit"); model.setName("New habit");
model.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); model.setReminder(new Reminder(8, 30));
command = new CreateHabitCommand(modelFactory, habitList, model); command = new CreateHabitCommand(modelFactory, habitList, model);
} }

@ -98,8 +98,8 @@ public class ImportTest extends BaseUnitTest
Reminder reminder = habit.getReminder(); Reminder reminder = habit.getReminder();
assertThat(reminder.getHour(), equalTo(8)); assertThat(reminder.getHour(), equalTo(8));
assertThat(reminder.getMinute(), equalTo(0)); assertThat(reminder.getMinute(), equalTo(0));
boolean[] reminderDays = { false, true, true, true, true, true, false }; boolean[] activeDays = { false, true, true, true, true, true, false };
assertThat(reminder.getDays().toArray(), equalTo(reminderDays)); assertThat(habit.getActiveDays().toArray(), equalTo(activeDays));
} }
@Test @Test

@ -93,7 +93,8 @@ public class CheckmarkListTest extends BaseUnitTest
expected.add(new Checkmark(day(10), YES_MANUAL)); expected.add(new Checkmark(day(10), YES_MANUAL));
List<Checkmark> actual = List<Checkmark> actual =
CheckmarkList.buildCheckmarksFromIntervals(reps, intervals); CheckmarkList.buildCheckmarksFromIntervals(
reps, intervals, WeekdayList.EVERY_DAY.toArray());
assertThat(actual, equalTo(expected)); assertThat(actual, equalTo(expected));
} }
@ -111,7 +112,39 @@ public class CheckmarkListTest extends BaseUnitTest
expected.add(new Checkmark(day(0), YES_MANUAL)); expected.add(new Checkmark(day(0), YES_MANUAL));
List<Checkmark> actual = List<Checkmark> actual =
CheckmarkList.buildCheckmarksFromIntervals(reps, intervals); CheckmarkList.buildCheckmarksFromIntervals(
reps, intervals, WeekdayList.EVERY_DAY.toArray());
assertThat(actual, equalTo(expected));
}
@Test
public void test_buildCheckmarksFromIntervals_3() throws Exception
{
Repetition reps[] = new Repetition[]{
new Repetition(day(10), YES_MANUAL),
new Repetition(day(1), YES_MANUAL),
};
ArrayList<CheckmarkList.Interval> intervals = new ArrayList<>();
intervals.add(new CheckmarkList.Interval(day(10), day(10), day(9)));
intervals.add(new CheckmarkList.Interval(day(1), day(1), day(0)));
List<Checkmark> expected = new ArrayList<>();
expected.add(new Checkmark(day(0), SKIP_AUTO));
expected.add(new Checkmark(day(1), YES_MANUAL));
expected.add(new Checkmark(day(2), NO));
expected.add(new Checkmark(day(3), NO));
expected.add(new Checkmark(day(4), NO));
expected.add(new Checkmark(day(5), NO));
expected.add(new Checkmark(day(6), NO));
expected.add(new Checkmark(day(7), SKIP_AUTO));
expected.add(new Checkmark(day(8), SKIP_AUTO));
expected.add(new Checkmark(day(9), YES_AUTO));
expected.add(new Checkmark(day(10), YES_MANUAL));
boolean[] activeDays = {false, false, true, true, true, true, true};
List<Checkmark> actual =
CheckmarkList.buildCheckmarksFromIntervals(reps, intervals, activeDays);
assertThat(actual, equalTo(expected)); assertThat(actual, equalTo(expected));
} }
@ -181,7 +214,7 @@ public class CheckmarkListTest extends BaseUnitTest
{ {
Repetition[] reps = new Repetition[]{ Repetition[] reps = new Repetition[]{
new Repetition(day(30), YES_MANUAL), new Repetition(day(30), YES_MANUAL),
new Repetition(day(20), SKIP), new Repetition(day(20), SKIP_MANUAL),
new Repetition(day(10), YES_MANUAL), new Repetition(day(10), YES_MANUAL),
}; };

@ -58,7 +58,7 @@ public class HabitListTest extends BaseUnitTest
habitsArray.add(habit); habitsArray.add(habit);
if (i % 3 == 0) if (i % 3 == 0)
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); habit.setReminder(new Reminder(8, 30));
} }
habitsArray.get(0).setArchived(true); habitsArray.get(0).setArchived(true);

@ -60,7 +60,8 @@ public class HabitTest extends BaseUnitTest
model.setArchived(true); model.setArchived(true);
model.setColor(0); model.setColor(0);
model.setFrequency(new Frequency(10, 20)); model.setFrequency(new Frequency(10, 20));
model.setReminder(new Reminder(8, 30, new WeekdayList(1))); model.setReminder(new Reminder(8, 30));
model.setActiveDays(new WeekdayList(1));
Habit habit = modelFactory.buildHabit(); Habit habit = modelFactory.buildHabit();
habit.copyFrom(model); habit.copyFrom(model);
@ -77,7 +78,7 @@ public class HabitTest extends BaseUnitTest
Habit h = modelFactory.buildHabit(); Habit h = modelFactory.buildHabit();
assertThat(h.hasReminder(), is(false)); assertThat(h.hasReminder(), is(false));
h.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); h.setReminder(new Reminder(8, 30));
assertThat(h.hasReminder(), is(true)); assertThat(h.hasReminder(), is(true));
h.clearReminder(); h.clearReminder();
@ -148,15 +149,15 @@ public class HabitTest extends BaseUnitTest
public void testToString() throws Exception public void testToString() throws Exception
{ {
Habit h = modelFactory.buildHabit(); Habit h = modelFactory.buildHabit();
h.setReminder(new Reminder(22, 30, WeekdayList.EVERY_DAY)); h.setReminder(new Reminder(22, 30));
String expected = "{id: <null>, data: {name: , description: ," + String expected = "{id: <null>, data: {name: , description: ," +
" frequency: {numerator: 3, denominator: 7}," + " frequency: {numerator: 3, denominator: 7}," +
" color: 8, archived: false, targetType: 0," + " color: 8, archived: false, targetType: 0," +
" targetValue: 100.0, type: 0, unit: ," + " targetValue: 100.0, type: 0, unit: ," +
" reminder: {hour: 22, minute: 30," + " reminder: {hour: 22, minute: 30}," +
" days: {weekdays: [true,true,true,true,true,true,true]}}," + " position: 0, question: ," +
" position: 0, question: }}"; " activeDays: {weekdays: [true,true,true,true,true,true,true]}}}";
assertThat(h.toString(), equalTo(expected)); assertThat(h.toString(), equalTo(expected));
} }
} }

@ -70,7 +70,7 @@ public class SQLiteHabitListTest extends BaseUnitTest
habitsArray.add(habit); habitsArray.add(habit);
if (i % 3 == 0) if (i % 3 == 0)
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); habit.setReminder(new Reminder(8, 30));
} }
habitsArray.get(0).setArchived(true); habitsArray.get(0).setArchived(true);

@ -40,7 +40,7 @@ public class HabitRecordTest extends BaseUnitTest
original.setColor(1); original.setColor(1);
original.setArchived(true); original.setArchived(true);
original.setFrequency(Frequency.THREE_TIMES_PER_WEEK); original.setFrequency(Frequency.THREE_TIMES_PER_WEEK);
original.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); original.setReminder(new Reminder(8, 30));
original.setId(1000L); original.setId(1000L);
original.setPosition(20); original.setPosition(20);

@ -73,8 +73,8 @@ public class ReminderSchedulerTest extends BaseUnitTest
Habit h1 = fixtures.createEmptyHabit(); Habit h1 = fixtures.createEmptyHabit();
Habit h2 = fixtures.createEmptyHabit(); Habit h2 = fixtures.createEmptyHabit();
Habit h3 = fixtures.createEmptyHabit(); Habit h3 = fixtures.createEmptyHabit();
h1.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); h1.setReminder(new Reminder(8, 30));
h2.setReminder(new Reminder(18, 30, WeekdayList.EVERY_DAY)); h2.setReminder(new Reminder(18, 30));
h3.setReminder(null); h3.setReminder(null);
habitList.add(h1); habitList.add(h1);
habitList.add(h2); habitList.add(h2);
@ -94,7 +94,7 @@ public class ReminderSchedulerTest extends BaseUnitTest
long atTime = unixTime(2015, 1, 30, 11, 30); long atTime = unixTime(2015, 1, 30, 11, 30);
long expectedCheckmarkTime = unixTime(2015, 1, 30, 0, 0); long expectedCheckmarkTime = unixTime(2015, 1, 30, 0, 0);
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); habit.setReminder(new Reminder(8, 30));
scheduleAndVerify(atTime, expectedCheckmarkTime, atTime); scheduleAndVerify(atTime, expectedCheckmarkTime, atTime);
} }
@ -109,7 +109,7 @@ public class ReminderSchedulerTest extends BaseUnitTest
long regularReminderTime = applyTimezone(unixTime(2015, 1, 2, 8, 30)); long regularReminderTime = applyTimezone(unixTime(2015, 1, 2, 8, 30));
long todayCheckmarkTime = unixTime(2015, 1, 1, 0, 0); long todayCheckmarkTime = unixTime(2015, 1, 1, 0, 0);
long tomorrowCheckmarkTime = unixTime(2015, 1, 2, 0, 0); long tomorrowCheckmarkTime = unixTime(2015, 1, 2, 0, 0);
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); habit.setReminder(new Reminder(8, 30));
when(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInFuture); when(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInFuture);
reminderScheduler.schedule(habit); reminderScheduler.schedule(habit);
@ -129,7 +129,7 @@ public class ReminderSchedulerTest extends BaseUnitTest
long expectedCheckmarkTime = unixTime(2015, 1, 26, 0, 0); long expectedCheckmarkTime = unixTime(2015, 1, 26, 0, 0);
long expectedReminderTime = unixTime(2015, 1, 26, 12, 30); long expectedReminderTime = unixTime(2015, 1, 26, 12, 30);
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); habit.setReminder(new Reminder(8, 30));
scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime); scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime);
} }
@ -142,7 +142,7 @@ public class ReminderSchedulerTest extends BaseUnitTest
long expectedCheckmarkTime = unixTime(2015, 1, 27, 0, 0); long expectedCheckmarkTime = unixTime(2015, 1, 27, 0, 0);
long expectedReminderTime = unixTime(2015, 1, 27, 12, 30); long expectedReminderTime = unixTime(2015, 1, 27, 12, 30);
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); habit.setReminder(new Reminder(8, 30));
scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime); scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime);
} }

Loading…
Cancel
Save