diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java
index 2363554a7..c3995a892 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java
@@ -391,7 +391,7 @@ public class HistoryChart extends ScrollableChart
else
{
checkmark = checkmarks[checkmarkOffset];
- if(checkmark == 0)
+ if(checkmark <= 0)
{
pSquareBg.setColor(colors[0]);
pSquareFg.setColor(textColors[1]);
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt
index 166158ea2..4b55d1b97 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt
@@ -114,6 +114,7 @@ class CheckmarkButtonView(
val id = when (value) {
SKIP -> R.string.fa_skipped
NO -> R.string.fa_times
+ UNKNOWN -> R.string.fa_question
else -> R.string.fa_check
}
val label = resources.getString(id)
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt
index 4696f0bb5..8048ad0c1 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt
@@ -62,7 +62,7 @@ class CheckmarkPanelView(
val timestamp = today.minus(index + dataOffset)
button.value = when {
index + dataOffset < values.size -> values[index + dataOffset]
- else -> NO
+ else -> UNKNOWN
}
button.color = color
button.onToggle = { value -> onToggle(timestamp, value) }
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java
index 8b4e08bc8..fd554d2c7 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java
@@ -86,8 +86,8 @@ public class CheckmarkWidgetView extends HabitWidgetView {
case Checkmark.YES_AUTO:
case Checkmark.NO:
+ case Checkmark.UNKNOWN:
default:
- getResources().getString(R.string.fa_times);
bgColor = res.getColor(R.attr.cardBgColor);
fgColor = res.getColor(R.attr.mediumContrastTextColor);
setShadowAlpha(0x00);
@@ -120,6 +120,8 @@ public class CheckmarkWidgetView extends HabitWidgetView {
return getResources().getString(R.string.fa_check);
case Checkmark.SKIP:
return getResources().getString(R.string.fa_skipped);
+ case Checkmark.UNKNOWN:
+ return getResources().getString(R.string.fa_question);
case Checkmark.NO:
default:
return getResources().getString(R.string.fa_times);
diff --git a/android/uhabits-android/src/main/res/values/fontawesome.xml b/android/uhabits-android/src/main/res/values/fontawesome.xml
index 7c95f1b38..f12f99732 100644
--- a/android/uhabits-android/src/main/res/values/fontawesome.xml
+++ b/android/uhabits-android/src/main/res/values/fontawesome.xml
@@ -26,6 +26,7 @@
+
@@ -281,7 +282,6 @@
-
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Checkmark.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Checkmark.java
index 88bc0ae05..acaada1ca 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Checkmark.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Checkmark.java
@@ -43,27 +43,32 @@ import static org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle;
public final class Checkmark
{
/**
- * Indicates that there was an explicit skip at the timestamp.
+ * Checkmark value indicating that the habit is not applicable for this timestamp.
*/
public static final int SKIP = 3;
/**
- * Indicates that there was a repetition at the timestamp.
+ * Checkmark value indicating that the user has performed the habit at this timestamp.
*/
public static final int YES_MANUAL = 2;
/**
- * Indicates that there was no repetition at the timestamp, but one was not
- * expected in any case, due to the frequency of the habit.
+ * Checkmark value indicating that the user did not perform the habit, but they were not
+ * expected to, because of the frequency of the habit.
*/
public static final int YES_AUTO = 1;
/**
- * Indicates that there was no repetition at the timestamp, even though a
- * repetition was expected.
+ * Checkmark value indicating that the user did not perform the habit, even though they were
+ * expected to perform it.
*/
public static final int NO = 0;
+ /**
+ * Checkmark value indicating that no data is available for the given timestamp.
+ */
+ public static final int UNKNOWN = -1;
+
private final Timestamp timestamp;
/**
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/CheckmarkList.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/CheckmarkList.java
index 9e838d6c3..f92247ab8 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/CheckmarkList.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/CheckmarkList.java
@@ -62,7 +62,7 @@ public abstract class CheckmarkList
int nDays = begin.daysUntil(today) + 1;
List checkmarks = new ArrayList<>(nDays);
for (int i = 0; i < nDays; i++)
- checkmarks.add(new Checkmark(today.minus(i), NO));
+ checkmarks.add(new Checkmark(today.minus(i), UNKNOWN));
for (Interval interval : intervals)
{
@@ -79,7 +79,10 @@ public abstract class CheckmarkList
{
Timestamp date = rep.getTimestamp();
int offset = date.daysUntil(today);
- checkmarks.set(offset, new Checkmark(date, rep.getValue()));
+ int value = rep.getValue();
+ int prevValue = checkmarks.get(offset).getValue();
+ if (prevValue < value)
+ checkmarks.set(offset, new Checkmark(date, value));
}
return checkmarks;
@@ -224,7 +227,7 @@ public abstract class CheckmarkList
{
Checkmark today = getToday();
if (today != null) return today.getValue();
- else return NO;
+ else return UNKNOWN;
}
public synchronized int getThisWeekValue(int firstWeekday)
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java
index 6d2a555cd..19a0f5119 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java
@@ -332,7 +332,7 @@ public class Habit
else
return todayCheckmark / 1000.0 <= data.targetValue;
}
- else return (todayCheckmark != NO);
+ else return (todayCheckmark != NO && todayCheckmark != UNKNOWN);
}
public synchronized boolean isNumerical()
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Repetition.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Repetition.java
index a41546cb8..9c3ec30f9 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Repetition.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Repetition.java
@@ -60,6 +60,7 @@ public final class Repetition
{
switch(value) {
case NO:
+ case UNKNOWN:
case YES_AUTO:
return YES_MANUAL;
case YES_MANUAL:
@@ -74,6 +75,7 @@ public final class Repetition
{
switch(value) {
case NO:
+ case UNKNOWN:
case YES_AUTO:
return YES_MANUAL;
default:
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/RepetitionList.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/RepetitionList.java
index bdb61658d..682c865e3 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/RepetitionList.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/RepetitionList.java
@@ -85,7 +85,7 @@ public abstract class RepetitionList
public int getValue(Timestamp timestamp)
{
Repetition rep = getByTimestamp(timestamp);
- if (rep == null) return Checkmark.NO;
+ if (rep == null) return Checkmark.UNKNOWN;
return rep.getValue();
}
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/StreakList.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/StreakList.java
index 036ca2119..054c197cc 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/StreakList.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/StreakList.java
@@ -138,8 +138,8 @@ public abstract class StreakList
current = current.plus(1);
int j = checks.length - i - 1;
- if ((checks[j + 1] == 0 && checks[j] > 0)) list.add(current);
- if ((checks[j + 1] > 0 && checks[j] == 0)) list.add(current.minus(1));
+ if ((checks[j + 1] <= 0 && checks[j] > 0)) list.add(current);
+ if ((checks[j + 1] > 0 && checks[j] <= 0)) list.add(current.minus(1));
}
if (list.size() % 2 == 1) list.add(current);
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryCheckmarkList.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryCheckmarkList.java
index 3504c2a3d..b6f8e29b9 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryCheckmarkList.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryCheckmarkList.java
@@ -68,7 +68,7 @@ public class MemoryCheckmarkList extends CheckmarkList
{
Timestamp t = to.minus(i);
if(t.isNewerThan(newestComputed) || t.isOlderThan(oldestComputed))
- filtered.add(new Checkmark(t, Checkmark.NO));
+ filtered.add(new Checkmark(t, Checkmark.UNKNOWN));
else
filtered.add(list.get(t.daysUntil(newestComputed)));
}
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/test/HabitFixtures.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/test/HabitFixtures.java
index 7ac134f07..4ab2675a8 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/test/HabitFixtures.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/test/HabitFixtures.java
@@ -142,7 +142,9 @@ public class HabitFixtures
Timestamp timestamp = DateUtils.getToday();
for (boolean c : NON_DAILY_HABIT_CHECKS)
{
- if (c) habit.getRepetitions().setValue(timestamp, YES_MANUAL);
+ int value = NO;
+ if (c) value = YES_MANUAL;
+ habit.getRepetitions().setValue(timestamp, value);
timestamp = timestamp.minus(1);
}
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/NotificationTray.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/NotificationTray.java
index 4ada13756..f41b57e43 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/NotificationTray.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/NotificationTray.java
@@ -186,7 +186,7 @@ public class NotificationTray
{
systemTray.log("Showing notification for habit=" + habit.id);
- if (todayValue != Checkmark.NO) {
+ if (todayValue != Checkmark.UNKNOWN) {
systemTray.log(String.format(
Locale.US,
"Habit %d already checked. Skipping.",
diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/CheckmarkListTest.java b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/CheckmarkListTest.java
index 802ca9e23..54787bed1 100644
--- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/CheckmarkListTest.java
+++ b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/CheckmarkListTest.java
@@ -80,14 +80,14 @@ public class CheckmarkListTest extends BaseUnitTest
intervals.add(new CheckmarkList.Interval(day(2), day(2), day(1)));
List expected = new ArrayList<>();
- expected.add(new Checkmark(day(0), NO));
+ expected.add(new Checkmark(day(0), UNKNOWN));
expected.add(new Checkmark(day(1), YES_MANUAL));
expected.add(new Checkmark(day(2), YES_MANUAL));
- expected.add(new Checkmark(day(3), NO));
+ expected.add(new Checkmark(day(3), UNKNOWN));
expected.add(new Checkmark(day(4), YES_AUTO));
expected.add(new Checkmark(day(5), YES_MANUAL));
expected.add(new Checkmark(day(6), YES_AUTO));
- expected.add(new Checkmark(day(7), NO));
+ expected.add(new Checkmark(day(7), UNKNOWN));
expected.add(new Checkmark(day(8), YES_AUTO));
expected.add(new Checkmark(day(9), YES_AUTO));
expected.add(new Checkmark(day(10), YES_MANUAL));
@@ -220,9 +220,9 @@ public class CheckmarkListTest extends BaseUnitTest
travelInTime(3);
int[] expectedValues = {
- NO,
- NO,
- NO,
+ UNKNOWN,
+ UNKNOWN,
+ UNKNOWN,
YES_MANUAL,
NO,
YES_AUTO,
@@ -296,7 +296,7 @@ public class CheckmarkListTest extends BaseUnitTest
assertThat(checkmarks.getTodayValue(), equalTo(YES_MANUAL));
travelInTime(1);
- assertThat(checkmarks.getTodayValue(), equalTo(NO));
+ assertThat(checkmarks.getTodayValue(), equalTo(UNKNOWN));
}
@Test
@@ -320,12 +320,12 @@ public class CheckmarkListTest extends BaseUnitTest
YES_AUTO,
YES_MANUAL,
YES_MANUAL,
- NO,
- NO,
- NO,
- NO,
- NO,
- NO
+ UNKNOWN,
+ UNKNOWN,
+ UNKNOWN,
+ UNKNOWN,
+ UNKNOWN,
+ UNKNOWN
};
int[] actualValues = nonDailyHabit.getCheckmarks().getValues(from, to);
@@ -475,7 +475,7 @@ public class CheckmarkListTest extends BaseUnitTest
assertThat(checkmarks.getThisMonthValue(), equalTo(1006));
DateUtils.setFixedLocalTime(unixTime(2000, MAY, 1));
- assertThat(checkmarks.getTodayValue(), equalTo(0));
+ assertThat(checkmarks.getTodayValue(), equalTo(UNKNOWN));
assertThat(checkmarks.getThisWeekValue(SATURDAY), equalTo(0));
assertThat(checkmarks.getThisMonthValue(), equalTo(0));
}