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 284fc59df..9752b3fe5 100644 Binary files a/android/uhabits-android/src/androidTest/assets/views-v26/habits/show/HistoryCard/render.png and b/android/uhabits-android/src/androidTest/assets/views-v26/habits/show/HistoryCard/render.png differ 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()); }