From 1a05f7d85d24ecdf0e749ede463387bc9866e6fc Mon Sep 17 00:00:00 2001 From: KristianTashkov Date: Sat, 22 Aug 2020 15:35:35 -0500 Subject: [PATCH] Allow user to skip days without breaking streak Co-authored-by: Alinson S. Xavier --- .../habits/show/HistoryCard/render.png | Bin 54906 -> 54911 bytes .../list/views/CheckmarkPanelViewTest.kt | 6 +- .../uhabits/widgets/CheckmarkWidgetTest.java | 3 + .../activities/common/views/HistoryChart.java | 40 +++++-- .../habits/list/views/CheckmarkButtonView.kt | 12 +- .../habits/list/views/CheckmarkPanelView.kt | 4 +- .../habits/list/views/HabitCardView.kt | 4 +- .../habits/show/ShowHabitScreen.java | 4 +- .../NumericalCheckmarkWidgetActivity.kt | 2 +- .../widgets/views/CheckmarkWidgetView.java | 4 +- .../src/main/res/values/fontawesome.xml | 1 + .../receivers/WidgetControllerTest.java | 2 +- .../uhabits/core/commands/CommandParser.java | 4 - .../commands/CreateRepetitionCommand.java | 11 +- .../commands/ToggleRepetitionCommand.java | 109 ------------------ .../isoron/uhabits/core/models/Checkmark.java | 9 +- .../uhabits/core/models/CheckmarkList.java | 2 +- .../uhabits/core/models/Repetition.java | 24 +++- .../uhabits/core/models/RepetitionList.java | 15 +-- .../isoron/uhabits/core/models/ScoreList.java | 15 ++- .../models/memory/MemoryRepetitionList.java | 6 +- .../core/reminders/ReminderScheduler.java | 2 +- .../uhabits/core/ui/NotificationTray.java | 14 +-- .../habits/list/ListHabitsBehavior.java | 6 +- .../habits/show/ShowHabitBehavior.java | 4 +- .../habits/show/ShowHabitMenuBehavior.java | 2 +- .../core/ui/widgets/WidgetBehavior.java | 18 ++- .../core/commands/CommandParserTest.java | 14 --- .../commands/ToggleRepetitionCommandTest.java | 76 ------------ .../habits/list/HabitCardListCacheTest.java | 4 +- .../habits/list/ListHabitsBehaviorTest.java | 2 +- 31 files changed, 127 insertions(+), 292 deletions(-) delete mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommand.java delete mode 100644 android/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommandTest.java diff --git a/android/uhabits-android/src/androidTest/assets/views-v26/habits/show/HistoryCard/render.png b/android/uhabits-android/src/androidTest/assets/views-v26/habits/show/HistoryCard/render.png index 284fc59df930d8531862c350db493f332f7b7fc7..9752b3fe5cef6f94eb04bd838945db9a3183b704 100644 GIT binary patch delta 33130 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 BPNx6> delta 33079 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 XGcQe;sV_?7z#myj#rruDPhb8Id)a;K diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.kt index 024b0fa7f..9a7255f94 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.kt @@ -93,8 +93,8 @@ class CheckmarkPanelViewTest : BaseViewTest() { @Test fun testToggle() { - var timestamps = mutableListOf() - view.onToggle = { timestamps.add(it) } + val timestamps = mutableListOf() + view.onToggle = { t, _ -> timestamps.add(t) } view.buttons[0].performLongClick() view.buttons[2].performLongClick() view.buttons[3].performLongClick() @@ -105,7 +105,7 @@ class CheckmarkPanelViewTest : BaseViewTest() { fun testToggle_withOffset() { val timestamps = mutableListOf() view.dataOffset = 3 - view.onToggle = { timestamps += it } + view.onToggle = { t, _ -> timestamps += t } view.buttons[0].performLongClick() view.buttons[2].performLongClick() view.buttons[3].performLongClick() diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/CheckmarkWidgetTest.java b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/CheckmarkWidgetTest.java index 0aeb4762f..45ce2067f 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/CheckmarkWidgetTest.java +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/CheckmarkWidgetTest.java @@ -70,7 +70,10 @@ public class CheckmarkWidgetTest extends BaseViewTest // possible to capture intents sent to BroadcastReceivers. button.performClick(); sleep(1000); + assertThat(checkmarks.getTodayValue(), equalTo(SKIPPED)); + button.performClick(); + sleep(1000); assertThat(checkmarks.getTodayValue(), equalTo(UNCHECKED)); } 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 93b488b78..97e347e79 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 @@ -147,11 +147,10 @@ public class HistoryChart extends ScrollableChart int offset = timestamp.daysUntil(today); if (offset < checkmarks.length) { - boolean isChecked = checkmarks[offset] == CHECKED_EXPLICITLY; - checkmarks[offset] = (isChecked ? UNCHECKED : CHECKED_EXPLICITLY); + checkmarks[offset] = Repetition.nextToggleValue(checkmarks[offset]); } - controller.onToggleCheckmark(timestamp); + controller.onToggleCheckmark(timestamp, checkmarks[offset]); postInvalidate(); return true; } @@ -362,21 +361,42 @@ public class HistoryChart extends ScrollableChart GregorianCalendar date, int checkmarkOffset) { + int checkmark = 0; if (checkmarkOffset >= checkmarks.length) pSquareBg.setColor(colors[0]); else { - int checkmark = checkmarks[checkmarkOffset]; - if(checkmark == 0) pSquareBg.setColor(colors[0]); + checkmark = checkmarks[checkmarkOffset]; + if(checkmark == 0) + pSquareBg.setColor(colors[0]); else if(checkmark < target) - { - pSquareBg.setColor(isNumerical ? textColor : colors[1]); - } - else pSquareBg.setColor(colors[2]); + pSquareBg.setColor(colors[1]); + else + pSquareBg.setColor(colors[2]); } pSquareFg.setColor(reverseTextColor); + pSquareFg.setStrokeWidth(columnWidth * 0.025f); + float round = dpToPixels(getContext(), 2); canvas.drawRoundRect(location, round, round, pSquareBg); + + if (!isNumerical && checkmark == SKIPPED) + { + canvas.save(); + canvas.clipRect(location); + float offset = - columnWidth; + for (int k = 0; k < 10; k++) + { + offset += columnWidth / 5; + canvas.drawLine(location.left + offset, + location.bottom, + location.right + offset, + location.top, + pSquareFg); + } + canvas.restore(); + } + String text = Integer.toString(date.get(Calendar.DAY_OF_MONTH)); canvas.drawText(text, location.centerX(), location.centerY() + squareTextOffset, pSquareFg); @@ -492,6 +512,6 @@ public class HistoryChart extends ScrollableChart public interface Controller { - default void onToggleCheckmark(Timestamp timestamp) {} + default void onToggleCheckmark(Timestamp timestamp, int value) {} } } 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 77981995a..aebdae734 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 @@ -27,6 +27,7 @@ import android.view.View.MeasureSpec.* import com.google.auto.factory.* import org.isoron.androidbase.activities.* import org.isoron.uhabits.* +import org.isoron.uhabits.core.models.* import org.isoron.uhabits.core.models.Checkmark.* import org.isoron.uhabits.core.preferences.* import org.isoron.uhabits.utils.* @@ -51,7 +52,7 @@ class CheckmarkButtonView( invalidate() } - var onToggle: () -> Unit = {} + var onToggle: (Int) -> Unit = {} private var drawer = Drawer() init { @@ -61,11 +62,8 @@ class CheckmarkButtonView( } fun performToggle() { - onToggle() - value = when (value) { - CHECKED_EXPLICITLY -> UNCHECKED - else -> CHECKED_EXPLICITLY - } + value = Repetition.nextToggleValue(value) + onToggle(value) performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) invalidate() } @@ -106,9 +104,11 @@ class CheckmarkButtonView( fun draw(canvas: Canvas) { paint.color = when (value) { CHECKED_EXPLICITLY -> color + SKIPPED -> color else -> lowContrastColor } val id = when (value) { + SKIPPED -> R.string.fa_skipped UNCHECKED -> R.string.fa_times else -> R.string.fa_check } 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 c0e8ae2e9..81ee667c8 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 @@ -46,7 +46,7 @@ class CheckmarkPanelView( setupButtons() } - var onToggle: (Timestamp) -> Unit = {} + var onToggle: (Timestamp, Int) -> Unit = {_, _ ->} set(value) { field = value setupButtons() @@ -65,7 +65,7 @@ class CheckmarkPanelView( else -> UNCHECKED } button.color = color - button.onToggle = { onToggle(timestamp) } + button.onToggle = { value -> onToggle(timestamp, value) } } } } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt index f6adfcc16..e7891253d 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt @@ -121,9 +121,9 @@ class HabitCardView( } checkmarkPanel = checkmarkPanelFactory.create().apply { - onToggle = { timestamp -> + onToggle = { timestamp, value -> triggerRipple(timestamp) - habit?.let { behavior.onToggle(it, timestamp) } + habit?.let { behavior.onToggle(it, timestamp, value) } } } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java index d19eb7cb5..3e85f80b9 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java @@ -81,9 +81,9 @@ public class ShowHabitScreen extends BaseScreen } @Override - public void onToggleCheckmark(Timestamp timestamp) + public void onToggleCheckmark(Timestamp timestamp, int value) { - behavior.get().onToggleCheckmark(timestamp); + behavior.get().onToggleCheckmark(timestamp, value); } @Override diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt index cc1b22421..c021d90c2 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt @@ -46,7 +46,7 @@ class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPi val component = app.component val parser = app.component.intentParser data = parser.parseCheckmarkIntent(intent) - behavior = WidgetBehavior(component.habitList, component.commandRunner, component.notificationTray) + behavior = WidgetBehavior(component.commandRunner, component.notificationTray) widgetUpdater = component.widgetUpdater showNumberSelector(this) } 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 68971ca55..c278a6635 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 @@ -76,6 +76,7 @@ public class CheckmarkWidgetView extends HabitWidgetView { switch (checkmarkState) { case Checkmark.CHECKED_EXPLICITLY: + case Checkmark.SKIPPED: bgColor = activeColor; fgColor = res.getColor(R.attr.highContrastReverseTextColor); setShadowAlpha(0x4f); @@ -117,7 +118,8 @@ public class CheckmarkWidgetView extends HabitWidgetView { case Checkmark.CHECKED_EXPLICITLY: case Checkmark.CHECKED_IMPLICITLY: return getResources().getString(R.string.fa_check); - + case Checkmark.SKIPPED: + return getResources().getString(R.string.fa_skipped); case Checkmark.UNCHECKED: 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 33c296549..7c95f1b38 100644 --- a/android/uhabits-android/src/main/res/values/fontawesome.xml +++ b/android/uhabits-android/src/main/res/values/fontawesome.xml @@ -23,6 +23,7 @@ + diff --git a/android/uhabits-android/src/test/java/org/isoron/uhabits/receivers/WidgetControllerTest.java b/android/uhabits-android/src/test/java/org/isoron/uhabits/receivers/WidgetControllerTest.java index 250395778..fcfcc5504 100644 --- a/android/uhabits-android/src/test/java/org/isoron/uhabits/receivers/WidgetControllerTest.java +++ b/android/uhabits-android/src/test/java/org/isoron/uhabits/receivers/WidgetControllerTest.java @@ -54,7 +54,7 @@ public class WidgetControllerTest extends BaseAndroidJVMTest commandRunner = mock(CommandRunner.class); notificationTray = mock(NotificationTray.class); controller = - new WidgetBehavior(habitList, commandRunner, notificationTray); + new WidgetBehavior(commandRunner, notificationTray); } @Test diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CommandParser.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CommandParser.java index 8a5919ce4..3a4989494 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CommandParser.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CommandParser.java @@ -72,10 +72,6 @@ public class CommandParser .fromJson(json, EditHabitCommand.Record.class) .toCommand(modelFactory, habitList); - if (event.equals("Toggle")) return gson - .fromJson(json, ToggleRepetitionCommand.Record.class) - .toCommand(habitList); - if (event.equals("Unarchive")) return gson .fromJson(json, UnarchiveHabitsCommand.Record.class) .toCommand(habitList); diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.java index 4a1fbf43c..f89695873 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.java @@ -58,8 +58,11 @@ public class CreateRepetitionCommand extends Command previousRep = reps.getByTimestamp(timestamp); if (previousRep != null) reps.remove(previousRep); - newRep = new Repetition(timestamp, value); - reps.add(newRep); + if (value > 0) + { + newRep = new Repetition(timestamp, value); + reps.add(newRep); + } habit.invalidateNewerThan(timestamp); } @@ -80,9 +83,7 @@ public class CreateRepetitionCommand extends Command @Override public void undo() { - if(newRep == null) throw new IllegalStateException(); - habit.getRepetitions().remove(newRep); - + if(newRep != null) habit.getRepetitions().remove(newRep); if (previousRep != null) habit.getRepetitions().add(previousRep); habit.invalidateNewerThan(timestamp); } diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommand.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommand.java deleted file mode 100644 index 5e2e575c1..000000000 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommand.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2016 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.core.commands; - -import androidx.annotation.*; - -import org.isoron.uhabits.core.models.*; - -/** - * Command to toggle a repetition. - */ -public class ToggleRepetitionCommand extends Command -{ - @NonNull - private HabitList list; - - final Timestamp timestamp; - - @NonNull - final Habit habit; - - public ToggleRepetitionCommand(@NonNull HabitList list, - @NonNull Habit habit, - Timestamp timestamp) - { - super(); - this.list = list; - this.timestamp = timestamp; - this.habit = habit; - } - - @Override - public void execute() - { - habit.getRepetitions().toggle(timestamp); - list.update(habit); - } - - @NonNull - public Habit getHabit() - { - return habit; - } - - @Override - @NonNull - public Record toRecord() - { - return new Record(this); - } - - @Override - public void undo() - { - execute(); - } - - public static class Record - { - @NonNull - public String id; - - @NonNull - public String event = "Toggle"; - - public long habit; - - public long repTimestamp; - - public Record(@NonNull ToggleRepetitionCommand command) - { - id = command.getId(); - Long habitId = command.habit.getId(); - if (habitId == null) throw new RuntimeException("Habit not saved"); - - this.repTimestamp = command.timestamp.getUnixTime(); - this.habit = habitId; - } - - public ToggleRepetitionCommand toCommand(@NonNull HabitList habitList) - { - Habit h = habitList.getById(habit); - if (h == null) throw new HabitNotFoundException(); - - ToggleRepetitionCommand command; - command = new ToggleRepetitionCommand( - habitList, h, new Timestamp(repTimestamp)); - command.setId(id); - return command; - } - } -} \ No newline at end of file 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 6683d6543..e5cc08808 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 @@ -37,6 +37,11 @@ import static org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle; @ThreadSafe public final class Checkmark { + /** + * Indicates that there was an explicit skip at the timestamp. + */ + public static final int SKIPPED = 3; + /** * Indicates that there was a repetition at the timestamp. */ @@ -59,8 +64,8 @@ public final class Checkmark /** * The value of the checkmark. *

- * For boolean habits, this equals either UNCHECKED, CHECKED_EXPLICITLY, - * or CHECKED_IMPLICITLY. + * For boolean habits, this equals either UNCHECKED, CHECKED_EXPLICITLY, CHECKED_IMPLICITLY + * or SKIPPED. *

* 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. 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 3fdb8d61f..7de1b8e67 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 @@ -79,7 +79,7 @@ public abstract class CheckmarkList { Timestamp date = rep.getTimestamp(); int offset = date.daysUntil(today); - checkmarks.set(offset, new Checkmark(date, CHECKED_EXPLICITLY)); + checkmarks.set(offset, new Checkmark(date, rep.getValue())); } return checkmarks; 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 413c06364..b2ef09040 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 @@ -27,10 +27,11 @@ import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import static org.isoron.uhabits.core.models.Checkmark.*; import static org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle; /** - * Represents a record that the user has performed a certain habit at a certain + * Represents a record that the user has performed or skipped a certain habit at a certain * date. */ public final class Repetition @@ -41,9 +42,9 @@ public final class Repetition /** * The value of the repetition. * - * For boolean habits, this always equals Checkmark.CHECKED_EXPLICITLY. - * 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. + * For boolean habits, this equals CHECKED_EXPLICITLY if performed or SKIPPED if skipped. + * 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. */ private final int value; @@ -61,6 +62,21 @@ public final class Repetition this.value = value; } + public static int nextToggleValue(int value) + { + switch(value) { + case UNCHECKED: + case CHECKED_IMPLICITLY: + return CHECKED_EXPLICITLY; + case CHECKED_EXPLICITLY: + return SKIPPED; + default: + case SKIPPED: + return UNCHECKED; + } + } + + @Override public boolean equals(Object o) { 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 a7541129e..3330fd08e 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 @@ -119,15 +119,15 @@ public abstract class RepetitionList public abstract Repetition getNewest(); /** - * Returns the total number of repetitions for each month, from the first + * Returns the total number of successful repetitions for each month, from the first * repetition until today, grouped by day of week. *

* The repetitions are returned in a HashMap. The key is the timestamp for * the first day of the month, at midnight (00:00). The value is an integer * array with 7 entries. The first entry contains the total number of - * repetitions during the specified month that occurred on a Saturday. The + * successful repetitions during the specified month that occurred on a Saturday. The * second entry corresponds to Sunday, and so on. If there are no - * repetitions during a certain month, the value is null. + * successful repetitions during a certain month, the value is null. * * @return total number of repetitions by month versus day of week */ @@ -140,6 +140,9 @@ public abstract class RepetitionList for (Repetition r : reps) { + if (!habit.isNumerical() && r.getValue() != Checkmark.CHECKED_EXPLICITLY) + continue; + Calendar date = r.getTimestamp().toCalendar(); int weekday = r.getTimestamp().getWeekday(); date.set(Calendar.DAY_OF_MONTH, 1); @@ -202,12 +205,6 @@ public abstract class RepetitionList return rep; } - /** - * Returns the number of all repetitions - * - * @return number of all repetitions - */ - @NonNull public abstract long getTotalCount(); public void toggle(Timestamp timestamp, int value) diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/ScoreList.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/ScoreList.java index b8d7c1eae..24784d549 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/ScoreList.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/ScoreList.java @@ -275,17 +275,16 @@ public abstract class ScoreList implements Iterable for (int i = 0; i < checkmarkValues.length; i++) { double value = checkmarkValues[checkmarkValues.length - i - 1]; - - if (habit.isNumerical()) + if (!habit.isNumerical() || value != Checkmark.SKIPPED) { - value /= 1000; - value /= habit.getTargetValue(); + if (habit.isNumerical()) + { + value /= 1000; + value /= habit.getTargetValue(); + } value = Math.min(1, value); + previousValue = Score.compute(freq, previousValue, value); } - - if (!habit.isNumerical() && value > 0) value = 1; - - previousValue = Score.compute(freq, previousValue, value); scores.add(new Score(from.plus(i), previousValue)); } diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryRepetitionList.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryRepetitionList.java index 6dce2f9d3..88221bbd3 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryRepetitionList.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryRepetitionList.java @@ -121,7 +121,11 @@ public class MemoryRepetitionList extends RepetitionList @Override public long getTotalCount() { - return list.size(); + int count = 0; + for (Repetition rep : list) + if (rep.getValue() == Checkmark.CHECKED_EXPLICITLY) + count++; + return count; } @Override diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/reminders/ReminderScheduler.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/reminders/ReminderScheduler.java index ab00c78eb..901bb9087 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/reminders/ReminderScheduler.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/reminders/ReminderScheduler.java @@ -59,7 +59,7 @@ public class ReminderScheduler implements CommandRunner.Listener public synchronized void onCommandExecuted(@NonNull Command command, @Nullable Long refreshKey) { - if (command instanceof ToggleRepetitionCommand) return; + if (command instanceof CreateRepetitionCommand) return; if (command instanceof ChangeHabitColorCommand) return; scheduleAll(); } 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 790097df2..42f08579d 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 @@ -76,17 +76,11 @@ public class NotificationTray public void onCommandExecuted(@NonNull Command command, @Nullable Long refreshKey) { - if (command instanceof ToggleRepetitionCommand) + if (command instanceof CreateRepetitionCommand) { - ToggleRepetitionCommand toggleCmd = - (ToggleRepetitionCommand) command; - - Habit habit = toggleCmd.getHabit(); - taskRunner.execute(() -> - { - if (habit.getCheckmarks().getTodayValue() != - Checkmark.UNCHECKED) cancel(habit); - }); + CreateRepetitionCommand createCmd = (CreateRepetitionCommand) command; + Habit habit = createCmd.getHabit(); + cancel(habit); } if (command instanceof DeleteHabitsCommand) diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java index d293cb3c8..72a434abb 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java @@ -149,11 +149,11 @@ public class ListHabitsBehavior if (prefs.isFirstRun()) onFirstRun(); } - public void onToggle(@NonNull Habit habit, Timestamp timestamp) + public void onToggle(@NonNull Habit habit, Timestamp timestamp, int value) { commandRunner.execute( - new ToggleRepetitionCommand(habitList, habit, timestamp), - habit.getId()); + new CreateRepetitionCommand(habit, timestamp, value), + habit.getId()); } public enum Message diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java index f7644ad44..d685f3a8b 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java @@ -56,10 +56,10 @@ public class ShowHabitBehavior screen.showEditHistoryScreen(); } - public void onToggleCheckmark(Timestamp timestamp) + public void onToggleCheckmark(Timestamp timestamp, int value) { commandRunner.execute( - new ToggleRepetitionCommand(habitList, habit, timestamp), null); + new CreateRepetitionCommand(habit, timestamp, value), null); } public interface Screen diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.java index dc2744fbd..f60ee0b94 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.java @@ -110,7 +110,7 @@ public class ShowHabitMenuBehavior if (i % 7 == 0) strength = max(0, min(100, strength + 10 * random.nextGaussian())); if (random.nextInt(100) > strength) continue; - int value = 1; + int value = Checkmark.CHECKED_EXPLICITLY; if (habit.isNumerical()) value = (int) (1000 + 250 * random.nextGaussian() * strength / 100) * 1000; diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java index 46966cecf..16f32022f 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java @@ -29,19 +29,15 @@ import javax.inject.*; public class WidgetBehavior { - private HabitList habitList; - @NonNull private final CommandRunner commandRunner; private NotificationTray notificationTray; @Inject - public WidgetBehavior(@NonNull HabitList habitList, - @NonNull CommandRunner commandRunner, + public WidgetBehavior(@NonNull CommandRunner commandRunner, @NonNull NotificationTray notificationTray) { - this.habitList = habitList; this.commandRunner = commandRunner; this.notificationTray = notificationTray; } @@ -51,7 +47,7 @@ public class WidgetBehavior notificationTray.cancel(habit); Repetition rep = habit.getRepetitions().getByTimestamp(timestamp); if (rep != null) return; - performToggle(habit, timestamp); + performToggle(habit, timestamp, Checkmark.CHECKED_EXPLICITLY); } public void onRemoveRepetition(@NonNull Habit habit, Timestamp timestamp) @@ -59,18 +55,20 @@ public class WidgetBehavior notificationTray.cancel(habit); Repetition rep = habit.getRepetitions().getByTimestamp(timestamp); if (rep == null) return; - performToggle(habit, timestamp); + performToggle(habit, timestamp, Checkmark.UNCHECKED); } public void onToggleRepetition(@NonNull Habit habit, Timestamp timestamp) { - performToggle(habit, timestamp); + Repetition previous = habit.getRepetitions().getByTimestamp(timestamp); + if(previous == null) performToggle(habit, timestamp, Checkmark.CHECKED_EXPLICITLY); + else performToggle(habit, timestamp, Repetition.nextToggleValue(previous.getValue())); } - private void performToggle(@NonNull Habit habit, Timestamp timestamp) + private void performToggle(@NonNull Habit habit, Timestamp timestamp, int value) { commandRunner.execute( - new ToggleRepetitionCommand(habitList, habit, timestamp), + new CreateRepetitionCommand(habit, timestamp, value), habit.getId()); } diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CommandParserTest.java b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CommandParserTest.java index 1285868d5..5902714d8 100644 --- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CommandParserTest.java +++ b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CommandParserTest.java @@ -136,20 +136,6 @@ public class CommandParserTest extends BaseUnitTest .getData())); } - @Test - public void testDecodeToggleCommand() throws JSONException - { - ToggleRepetitionCommand original, decoded; - original = new ToggleRepetitionCommand(habitList, habit, - Timestamp.ZERO.plus(100)); - decoded = (ToggleRepetitionCommand) parser.parse(original.toJson()); - - MatcherAssert.assertThat(decoded.getId(), equalTo(original.getId())); - MatcherAssert.assertThat(decoded.timestamp, equalTo(original - .timestamp)); - MatcherAssert.assertThat(decoded.habit, equalTo(original.habit)); - } - @Test public void testDecodeUnarchiveCommand() throws JSONException { diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommandTest.java b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommandTest.java deleted file mode 100644 index 677eaaa10..000000000 --- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommandTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2017 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.core.commands; - -import org.isoron.uhabits.core.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.utils.*; -import org.junit.*; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; - -public class ToggleRepetitionCommandTest extends BaseUnitTest -{ - - private ToggleRepetitionCommand command; - private Habit habit; - private Timestamp today; - - @Override - @Before - public void setUp() throws Exception - { - super.setUp(); - - habit = fixtures.createShortHabit(); - habitList.add(habit); - - today = DateUtils.getToday(); - command = new ToggleRepetitionCommand(habitList, habit, today); - } - - @Test - public void testExecuteUndoRedo() - { - assertTrue(habit.getRepetitions().containsTimestamp(today)); - - command.execute(); - assertFalse(habit.getRepetitions().containsTimestamp(today)); - - command.undo(); - assertTrue(habit.getRepetitions().containsTimestamp(today)); - - command.execute(); - assertFalse(habit.getRepetitions().containsTimestamp(today)); - } - - @Test - public void testRecord() - { - ToggleRepetitionCommand.Record rec = command.toRecord(); - ToggleRepetitionCommand other = rec.toCommand(habitList); - - assertThat(command.getId(), equalTo(other.getId())); - assertThat(command.timestamp, equalTo(other.timestamp)); - assertThat(command.habit, equalTo(other.habit)); - } -} diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java index bc10a4548..125b64f44 100644 --- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java +++ b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java @@ -84,9 +84,7 @@ public class HabitCardListCacheTest extends BaseUnitTest { Habit h2 = habitList.getByPosition(2); Timestamp today = DateUtils.getToday(); - commandRunner.execute(new ToggleRepetitionCommand(habitList, h2, today), - h2.getId()); - + commandRunner.execute(new CreateRepetitionCommand(h2, today, Checkmark.UNCHECKED), h2.getId()); verify(listener).onItemChanged(2); verify(listener).onRefreshFinished(); verifyNoMoreInteractions(listener); diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java index 0ed3fbbab..4ce83d78e 100644 --- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java +++ b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java @@ -173,7 +173,7 @@ public class ListHabitsBehaviorTest extends BaseUnitTest public void testOnToggle() { assertTrue(habit1.isCompletedToday()); - behavior.onToggle(habit1, DateUtils.getToday()); + behavior.onToggle(habit1, DateUtils.getToday(), Checkmark.UNCHECKED); assertFalse(habit1.isCompletedToday()); }