diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java index c33c17125..4d2734356 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java @@ -210,9 +210,8 @@ public class BaseAndroidTest extends TestCase Debug.stopMethodTracing(); } - protected Long day(int offset) + protected Timestamp day(int offset) { - return DateUtils.getStartOfToday() - - offset * DateUtils.millisecondsInOneDay; + return DateUtils.getToday().minus(offset); } } diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseUserInterfaceTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseUserInterfaceTest.java index 3150e05d3..b628e7ba0 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseUserInterfaceTest.java +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseUserInterfaceTest.java @@ -86,7 +86,7 @@ public class BaseUserInterfaceTest { prefs.reset(); prefs.setFirstRun(false); - prefs.updateLastHint(100, DateUtils.getStartOfToday()); + prefs.updateLastHint(100, DateUtils.getToday()); habitList.removeAll(); cache.refreshAllHabits(); Thread.sleep(1000); diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitFixtures.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitFixtures.java index f7a7cd9cf..c636f682b 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitFixtures.java +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitFixtures.java @@ -66,14 +66,13 @@ public class HabitFixtures habit.setFrequency(new Frequency(3, 7)); habit.setColor(7); - long day = DateUtils.millisecondsInOneDay; - long today = DateUtils.getStartOfToday(); + Timestamp today = DateUtils.getToday(); int marks[] = { 0, 1, 3, 5, 7, 8, 9, 10, 12, 14, 15, 17, 19, 20, 26, 27, 28, 50, 51, 52, 53, 54, 58, 60, 63, 65, 70, 71, 72, 73, 74, 75, 80, 81, 83, 89, 90, 91, 95, 102, 103, 108, 109, 120}; for (int mark : marks) - habit.getRepetitions().toggle(today - mark * day); + habit.getRepetitions().toggle(today.minus(mark)); return habit; } @@ -89,12 +88,12 @@ public class HabitFixtures habit.setUnit("steps"); habitList.add(habit); - long timestamp = DateUtils.getStartOfToday(); + Timestamp timestamp = DateUtils.getToday(); for (int value : LONG_NUMERICAL_HABIT_CHECKS) { Repetition r = new Repetition(timestamp, value); habit.getRepetitions().add(r); - timestamp -= DateUtils.millisecondsInOneDay; + timestamp = timestamp.minus(1); } return habit; @@ -108,11 +107,11 @@ public class HabitFixtures habit.setFrequency(new Frequency(2, 3)); habitList.add(habit); - long timestamp = DateUtils.getStartOfToday(); + Timestamp timestamp = DateUtils.getToday(); for (boolean c : LONG_HABIT_CHECKS) { if (c) habit.getRepetitions().toggle(timestamp); - timestamp -= DateUtils.millisecondsInOneDay; + timestamp = timestamp.minus(1); } return habit; diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/BarChartTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/BarChartTest.java index fdb7575a8..5a5b4255c 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/BarChartTest.java +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/BarChartTest.java @@ -44,10 +44,9 @@ public class BarChartTest extends BaseViewTest super.setUp(); Habit habit = fixtures.createLongNumericalHabit(); view = new BarChart(targetContext); - long today = DateUtils.getStartOfToday(); - long day = DateUtils.millisecondsInOneDay; + Timestamp today = DateUtils.getToday(); CheckmarkList checkmarks = habit.getCheckmarks(); - view.setCheckmarks(checkmarks.getByInterval(today - 20 * day, today)); + view.setCheckmarks(checkmarks.getByInterval(today.minus(20), today)); view.setColor(PaletteUtils.getColor(targetContext, habit.getColor())); view.setTarget(200.0); measureView(view, dpToPixels(300), dpToPixels(200)); diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.kt index 835259f18..b02e7c280 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.kt @@ -24,6 +24,7 @@ import android.support.test.runner.* import org.hamcrest.CoreMatchers.* import org.hamcrest.MatcherAssert.* import org.isoron.uhabits.* +import org.isoron.uhabits.core.models.* import org.isoron.uhabits.core.models.Checkmark.* import org.isoron.uhabits.utils.* import org.junit.* @@ -89,7 +90,7 @@ class CheckmarkPanelViewTest : BaseViewTest() { @Test fun testToggle() { - var timestamps = mutableListOf() + var timestamps = mutableListOf() view.onToggle = { timestamps.add(it) } view.buttons[0].performLongClick() view.buttons[2].performLongClick() @@ -99,12 +100,12 @@ class CheckmarkPanelViewTest : BaseViewTest() { @Test fun testToggle_withOffset() { - var timestamps = LongArray(0) + val timestamps = mutableListOf() view.dataOffset = 3 view.onToggle = { timestamps += it } view.buttons[0].performLongClick() view.buttons[2].performLongClick() view.buttons[3].performLongClick() - assertThat(timestamps, equalTo(longArrayOf(day(3), day(5), day(6)))) + assertThat(timestamps, equalTo(listOf(day(3), day(5), day(6)))) } } \ No newline at end of file diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt index 3e07e8d84..489f65247 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt @@ -24,6 +24,7 @@ import android.support.test.runner.* import org.hamcrest.CoreMatchers.* import org.hamcrest.MatcherAssert.* import org.isoron.uhabits.* +import org.isoron.uhabits.core.models.* import org.isoron.uhabits.utils.* import org.junit.* import org.junit.runner.* @@ -84,22 +85,22 @@ class NumberPanelViewTest : BaseViewTest() { @Test fun testEdit() { - var timestamps = LongArray(0) - view.onEdit = { timestamps += it } + val timestamps = mutableListOf() + view.onEdit = { timestamps.plusAssign(it) } view.buttons[0].performLongClick() view.buttons[2].performLongClick() view.buttons[3].performLongClick() - assertThat(timestamps, equalTo(longArrayOf(day(0), day(2), day(3)))) + assertThat(timestamps, equalTo(listOf(day(0), day(2), day(3)))) } @Test fun testEdit_withOffset() { - var timestamps = LongArray(0) + val timestamps = mutableListOf() view.dataOffset = 3 view.onEdit = { timestamps += it } view.buttons[0].performLongClick() view.buttons[2].performLongClick() view.buttons[3].performLongClick() - assertThat(timestamps, equalTo(longArrayOf(day(3), day(5), day(6)))) + assertThat(timestamps, equalTo(listOf(day(3), day(5), day(6)))) } } \ No newline at end of file diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/performance/PerformanceTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/performance/PerformanceTest.java index 16a06125d..99b5dbee4 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/performance/PerformanceTest.java +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/performance/PerformanceTest.java @@ -28,7 +28,7 @@ import org.junit.*; import org.junit.runner.*; @RunWith(AndroidJUnit4.class) -@LargeTest +@MediumTest public class PerformanceTest extends BaseAndroidTest { private Habit habit; diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/BarChart.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/BarChart.java index a81dec50a..b88b44f6f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/BarChart.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/BarChart.java @@ -115,14 +115,12 @@ public class BarChart extends ScrollableChart Random random = new Random(); List checkmarks = new LinkedList<>(); - long timestamp = DateUtils.getStartOfToday(); - long day = DateUtils.millisecondsInOneDay; + Timestamp today = DateUtils.getToday(); for (int i = 1; i < 100; i++) { int value = random.nextInt(1000); - checkmarks.add(new Checkmark(timestamp, value)); - timestamp -= day; + checkmarks.add(new Checkmark(today.minus(i), value)); } setCheckmarks(checkmarks); @@ -205,7 +203,7 @@ public class BarChart extends ScrollableChart if (offset >= checkmarks.size()) continue; double value = checkmarks.get(offset).getValue(); - long timestamp = checkmarks.get(offset).getTimestamp(); + Timestamp timestamp = checkmarks.get(offset).getTimestamp(); int height = (int) (columnHeight * value / maxValue); rect.set(0, 0, baseSize, height); @@ -286,13 +284,13 @@ public class BarChart extends ScrollableChart if (isTransparencyEnabled) pGraph.setXfermode(XFERMODE_SRC); } - private void drawFooter(Canvas canvas, RectF rect, long currentDate) + private void drawFooter(Canvas canvas, RectF rect, Timestamp currentDate) { - String yearText = dfYear.format(currentDate); - String monthText = dfMonth.format(currentDate); - String dayText = dfDay.format(currentDate); + String yearText = dfYear.format(currentDate.toJavaDate()); + String monthText = dfMonth.format(currentDate.toJavaDate()); + String dayText = dfDay.format(currentDate.toJavaDate()); - GregorianCalendar calendar = DateUtils.getCalendar(currentDate); + GregorianCalendar calendar = currentDate.toCalendar(); pText.setColor(textColor); String text; diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.java index f6f24e5d4..547bec8b4 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.java @@ -26,6 +26,7 @@ import android.util.*; import org.isoron.androidbase.utils.*; import org.isoron.uhabits.*; +import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.utils.*; import org.isoron.uhabits.utils.*; @@ -67,7 +68,7 @@ public class FrequencyChart extends ScrollableChart private boolean isBackgroundTransparent; @NonNull - private HashMap frequency; + private HashMap frequency; private int maxFreq; public FrequencyChart(Context context) @@ -90,23 +91,21 @@ public class FrequencyChart extends ScrollableChart postInvalidate(); } - public void setFrequency(HashMap frequency) + public void setFrequency(HashMap frequency) { this.frequency = frequency; maxFreq = getMaxFreq(frequency); postInvalidate(); } - private int getMaxFreq(HashMap frequency) + private int getMaxFreq(HashMap frequency) { int maxValue = 1; + for (Integer[] values : frequency.values()) - { for (Integer value : values) - { maxValue = Math.max(value, maxValue); - } - } + return maxValue; } @@ -194,7 +193,7 @@ public class FrequencyChart extends ScrollableChart private void drawColumn(Canvas canvas, RectF rect, GregorianCalendar date) { - Integer values[] = frequency.get(date.getTimeInMillis()); + Integer values[] = frequency.get(new Timestamp(date)); float rowHeight = rect.height() / 8.0f; prevRect.set(rect); @@ -324,7 +323,7 @@ public class FrequencyChart extends ScrollableChart for (int j = 0; j < 7; j++) values[j] = rand.nextInt(5); - frequency.put(date.getTimeInMillis(), values); + frequency.put(new Timestamp(date), values); date.add(Calendar.MONTH, -1); } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java index 3983e745b..9c6bde1d3 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java @@ -28,14 +28,15 @@ import android.view.*; import org.isoron.androidbase.utils.*; import org.isoron.uhabits.*; +import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.utils.*; import org.isoron.uhabits.utils.*; import java.text.*; import java.util.*; -import static org.isoron.uhabits.core.models.Checkmark.*; import static org.isoron.androidbase.utils.InterfaceUtils.*; +import static org.isoron.uhabits.core.models.Checkmark.*; public class HistoryChart extends ScrollableChart { @@ -135,10 +136,11 @@ public class HistoryChart extends ScrollableChart return false; } - final Long timestamp = positionToTimestamp(x, y); + final Timestamp timestamp = positionToTimestamp(x, y); if (timestamp == null) return false; - int offset = timestampToOffset(timestamp); + Timestamp today = DateUtils.getToday(); + int offset = timestamp.daysUntil(today); if (offset < checkmarks.length) { boolean isChecked = checkmarks[offset] == CHECKED_EXPLICITLY; @@ -435,7 +437,8 @@ public class HistoryChart extends ScrollableChart baseLocation = new RectF(); } - private Long positionToTimestamp(float x, float y) + @Nullable + private Timestamp positionToTimestamp(float x, float y) { int col = (int) (x / columnWidth); int row = (int) (y / columnWidth); @@ -450,15 +453,7 @@ public class HistoryChart extends ScrollableChart if (DateUtils.getStartOfDay(date.getTimeInMillis()) > DateUtils.getStartOfToday()) return null; - return date.getTimeInMillis(); - } - - private int timestampToOffset(Long timestamp) - { - Long day = DateUtils.millisecondsInOneDay; - Long today = DateUtils.getStartOfToday(); - - return (int) ((today - timestamp) / day); + return new Timestamp(date.getTimeInMillis()); } private void updateDate() @@ -478,6 +473,6 @@ public class HistoryChart extends ScrollableChart public interface Controller { - default void onToggleCheckmark(long timestamp) {} + default void onToggleCheckmark(Timestamp timestamp) {} } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/ScoreChart.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/ScoreChart.java index 6cbc2293c..3aff9dab5 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/ScoreChart.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/ScoreChart.java @@ -111,17 +111,15 @@ public class ScoreChart extends ScrollableChart scores = new LinkedList<>(); double previous = 0.5f; - long timestamp = DateUtils.getStartOfToday(); - long day = DateUtils.millisecondsInOneDay; + Timestamp timestamp = DateUtils.getToday(); for (int i = 1; i < 100; i++) { double step = 0.1f; double current = previous + random.nextDouble() * step * 2 - step; current = Math.max(0, Math.min(1.0f, current)); - scores.add(new Score(timestamp, current)); + scores.add(new Score(timestamp.minus(i), current)); previous = current; - timestamp -= day; } } @@ -189,7 +187,7 @@ public class ScoreChart extends ScrollableChart if (offset >= scores.size()) continue; double score = scores.get(offset).getValue(); - long timestamp = scores.get(offset).getTimestamp(); + Timestamp timestamp = scores.get(offset).getTimestamp(); int height = (int) (columnHeight * score); @@ -258,13 +256,13 @@ public class ScoreChart extends ScrollableChart if (isTransparencyEnabled) initCache(width, height); } - private void drawFooter(Canvas canvas, RectF rect, long currentDate) + private void drawFooter(Canvas canvas, RectF rect, Timestamp currentDate) { - String yearText = dfYear.format(currentDate); - String monthText = dfMonth.format(currentDate); - String dayText = dfDay.format(currentDate); + String yearText = dfYear.format(currentDate.toJavaDate()); + String monthText = dfMonth.format(currentDate.toJavaDate()); + String dayText = dfDay.format(currentDate.toJavaDate()); - GregorianCalendar calendar = DateUtils.getCalendar(currentDate); + GregorianCalendar calendar = currentDate.toCalendar(); String text; int year = calendar.get(Calendar.YEAR); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/StreakChart.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/StreakChart.java index d7c0267ae..3a3b8130e 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/StreakChart.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/StreakChart.java @@ -97,16 +97,15 @@ public class StreakChart extends View public void populateWithRandomData() { - long day = DateUtils.millisecondsInOneDay; - long start = DateUtils.getStartOfToday(); + Timestamp start = DateUtils.getToday(); LinkedList streaks = new LinkedList<>(); for (int i = 0; i < 10; i++) { int length = new Random().nextInt(100); - long end = start + length * day; + Timestamp end = start.plus(length); streaks.add(new Streak(start, end)); - start = end + day; + start = end.plus(1); } setStreaks(streaks); @@ -215,8 +214,8 @@ public class StreakChart extends View if (shouldShowLabels) { - String startLabel = dateFormat.format(new Date(streak.getStart())); - String endLabel = dateFormat.format(new Date(streak.getEnd())); + String startLabel = dateFormat.format(streak.getStart().toJavaDate()); + String endLabel = dateFormat.format(streak.getEnd().toJavaDate()); paint.setColor(textColor); paint.setTextAlign(Paint.Align.RIGHT); @@ -284,9 +283,9 @@ public class StreakChart extends View minLength = Math.min(minLength, s.getLength()); float lw1 = - paint.measureText(dateFormat.format(new Date(s.getStart()))); + paint.measureText(dateFormat.format(s.getStart().toJavaDate())); float lw2 = - paint.measureText(dateFormat.format(new Date(s.getEnd()))); + paint.measureText(dateFormat.format(s.getEnd().toJavaDate())); maxLabelWidth = Math.max(maxLabelWidth, Math.max(lw1, lw2)); } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt index 30d81a379..c0e8ae2e9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt @@ -22,6 +22,7 @@ package org.isoron.uhabits.activities.habits.list.views import android.content.* import com.google.auto.factory.* import org.isoron.androidbase.activities.* +import org.isoron.uhabits.core.models.* import org.isoron.uhabits.core.models.Checkmark.* import org.isoron.uhabits.core.preferences.* import org.isoron.uhabits.core.utils.* @@ -45,7 +46,7 @@ class CheckmarkPanelView( setupButtons() } - var onToggle: (Long) -> Unit = {} + var onToggle: (Timestamp) -> Unit = {} set(value) { field = value setupButtons() @@ -55,11 +56,10 @@ class CheckmarkPanelView( @Synchronized override fun setupButtons() { - val today = DateUtils.getStartOfToday() - val day = DateUtils.millisecondsInOneDay + val today = DateUtils.getToday() buttons.forEachIndexed { index, button -> - val timestamp = today - (index + dataOffset) * day + val timestamp = today.minus(index + dataOffset) button.value = when { index + dataOffset < values.size -> values[index + dataOffset] else -> UNCHECKED diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt index f948266de..f6adfcc16 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt @@ -171,10 +171,9 @@ class HabitCardView( updateBackground(isSelected) } - fun triggerRipple(timestamp: Long) { - val today = DateUtils.getStartOfToday() - val day = DateUtils.millisecondsInOneDay - val offset = ((today - timestamp) / day).toInt() - dataOffset + fun triggerRipple(timestamp: Timestamp) { + val today = DateUtils.getToday() + val offset = timestamp.daysUntil(today) - dataOffset val button = checkmarkPanel.buttons[offset] val y = button.height / 2.0f val x = checkmarkPanel.x + button.x + (button.width / 2).toFloat() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt index aaaabc2a6..81b082209 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt @@ -22,6 +22,7 @@ package org.isoron.uhabits.activities.habits.list.views import android.content.* import com.google.auto.factory.* import org.isoron.androidbase.activities.* +import org.isoron.uhabits.core.models.* import org.isoron.uhabits.core.preferences.* import org.isoron.uhabits.core.utils.* @@ -56,7 +57,7 @@ class NumberPanelView( setupButtons() } - var onEdit: (Long) -> Unit = {} + var onEdit: (Timestamp) -> Unit = {} set(value) { field = value setupButtons() @@ -66,11 +67,10 @@ class NumberPanelView( @Synchronized override fun setupButtons() { - val day = DateUtils.millisecondsInOneDay - val today = DateUtils.getStartOfToday() + val today = DateUtils.getToday() buttons.forEachIndexed { index, button -> - val timestamp = today - (index + dataOffset) * day + val timestamp = today.minus(index + dataOffset) button.value = when { index + dataOffset < values.size -> values[index + dataOffset] else -> 0.0 diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java index 0d562af86..eeb11c6aa 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java @@ -73,7 +73,7 @@ public class ShowHabitScreen extends BaseScreen } @Override - public void onToggleCheckmark(long timestamp) + public void onToggleCheckmark(Timestamp timestamp) { behavior.get().onToggleCheckmark(timestamp); } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.java index 67d5d1855..04ab5aea7 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.java @@ -98,9 +98,9 @@ public class BarCard extends HabitCard @Override public void doInBackground() { - long today = DateUtils.getStartOfToday(); + Timestamp today = DateUtils.getToday(); List checkmarks = - habit.getCheckmarks().getByInterval(0, today); + habit.getCheckmarks().getByInterval(Timestamp.ZERO, today); chart.setCheckmarks(checkmarks); } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.java index a890349fa..ff24596c3 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.java @@ -94,7 +94,7 @@ public class FrequencyCard extends HabitCard public void doInBackground() { RepetitionList reps = getHabit().getRepetitions(); - HashMap frequency = reps.getWeekdayFrequency(); + HashMap frequency = reps.getWeekdayFrequency(); chart.setFrequency(frequency); } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.java index 76d65f701..f1acb1cdd 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.java @@ -164,9 +164,9 @@ public class OverviewCard extends HabitCard ScoreList scores = habit.getScores(); - long today = DateUtils.getStartOfToday(); - long lastMonth = today - 30 * DateUtils.millisecondsInOneDay; - long lastYear = today - 365 * DateUtils.millisecondsInOneDay; + Timestamp today = DateUtils.getToday(); + Timestamp lastMonth = today.minus(30); + Timestamp lastYear = today.minus(365); cache.todayScore = (float) scores.getTodayValue(); cache.lastMonthScore = (float) scores.getValue(lastMonth); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.kt b/uhabits-android/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.kt index 19b0467b7..51a770753 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.kt @@ -45,7 +45,7 @@ class FireSettingReceiver : BroadcastReceiver() { .build() allHabits = app.component.habitList val args = parseIntent(intent) ?: return - val timestamp = DateUtils.getStartOfToday() + val timestamp = DateUtils.getToday() val controller = component.widgetController when (args.action) { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt index 3ce896490..676e55a4f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt @@ -42,16 +42,16 @@ class IntentParser return habit } - private fun parseTimestamp(intent: Intent): Long { - val today = DateUtils.getStartOfToday() + private fun parseTimestamp(intent: Intent): Timestamp { + val today = DateUtils.getToday().unixTime var timestamp = intent.getLongExtra("timestamp", today) timestamp = DateUtils.getStartOfDay(timestamp) if (timestamp < 0 || timestamp > today) throw IllegalArgumentException("timestamp is not valid") - return timestamp + return Timestamp(timestamp) } - class CheckmarkIntentData(var habit: Habit, var timestamp: Long) + class CheckmarkIntentData(var habit: Habit, var timestamp: Timestamp) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt index 0db84034d..2758ba934 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt @@ -35,13 +35,13 @@ class PendingIntentFactory @AppContext private val context: Context, private val intentFactory: IntentFactory) { - fun addCheckmark(habit: Habit, timestamp: Long?): PendingIntent = + fun addCheckmark(habit: Habit, timestamp: Timestamp?): PendingIntent = PendingIntent.getBroadcast( context, 1, Intent(context, WidgetReceiver::class.java).apply { data = Uri.parse(habit.uriString) action = WidgetReceiver.ACTION_ADD_REPETITION - if (timestamp != null) putExtra("timestamp", timestamp) + if (timestamp != null) putExtra("timestamp", timestamp.unixTime) }, FLAG_UPDATE_CURRENT) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt index 6be4c455a..1a13d417f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt @@ -48,7 +48,7 @@ class AndroidNotificationTray override fun showNotification(habit: Habit, notificationId: Int, - timestamp: Long, + timestamp: Timestamp, reminderTime: Long) { val checkAction = Action( diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java index 3b4015aa8..4be20914c 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java @@ -128,7 +128,7 @@ public class PebbleReceiver extends PebbleDataReceiver Habit habit = habitList.getById(habitId); if (habit == null) return; - long today = DateUtils.getStartOfToday(); + Timestamp today = DateUtils.getToday(); commandRunner.execute( new ToggleRepetitionCommand(habitList, habit, today), habitId); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.java index 854113fc0..ae88f55c9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.java @@ -58,7 +58,7 @@ public class ReminderController } public void onShowReminder(@NonNull Habit habit, - long timestamp, + Timestamp timestamp, long reminderTime) { notificationTray.show(habit, timestamp, reminderTime); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java index 4831127e3..cb382a950 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java @@ -79,8 +79,8 @@ public class ReminderReceiver extends BroadcastReceiver { case ACTION_SHOW_REMINDER: if (habit == null) return; - reminderController.onShowReminder(habit, timestamp, - reminderTime); + reminderController.onShowReminder(habit, + new Timestamp(timestamp), reminderTime); break; case ACTION_DISMISS_REMINDER: diff --git a/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.java b/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.java index 50b7711d6..93b199a10 100644 --- a/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.java +++ b/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.java @@ -80,8 +80,8 @@ public class ReminderControllerTest extends BaseAndroidJVMTest public void testOnShowReminder() throws Exception { Habit habit = mock(Habit.class); - controller.onShowReminder(habit, 123, 456); - verify(notificationTray).show(habit, 123, 456); + controller.onShowReminder(habit, Timestamp.ZERO.plus(100), 456); + verify(notificationTray).show(habit, Timestamp.ZERO.plus(100), 456); verify(reminderScheduler).scheduleAll(); } diff --git a/uhabits-android/src/test/java/org/isoron/uhabits/receivers/WidgetControllerTest.java b/uhabits-android/src/test/java/org/isoron/uhabits/receivers/WidgetControllerTest.java index 73364c80f..250395778 100644 --- a/uhabits-android/src/test/java/org/isoron/uhabits/receivers/WidgetControllerTest.java +++ b/uhabits-android/src/test/java/org/isoron/uhabits/receivers/WidgetControllerTest.java @@ -40,7 +40,7 @@ public class WidgetControllerTest extends BaseAndroidJVMTest private Habit habit; - private long today; + private Timestamp today; private NotificationTray notificationTray; @@ -49,7 +49,7 @@ public class WidgetControllerTest extends BaseAndroidJVMTest { super.setUp(); - today = DateUtils.getStartOfToday(); + today = DateUtils.getToday(); habit = fixtures.createEmptyHabit(); commandRunner = mock(CommandRunner.class); notificationTray = mock(NotificationTray.class); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.java index 9264a9c90..1857304a5 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.java @@ -31,7 +31,7 @@ public class CreateRepetitionCommand extends Command @NonNull final Habit habit; - final long timestamp; + final Timestamp timestamp; final int value; @@ -42,7 +42,7 @@ public class CreateRepetitionCommand extends Command Repetition newRep; public CreateRepetitionCommand(@NonNull Habit habit, - long timestamp, + Timestamp timestamp, int value) { this.timestamp = timestamp; @@ -108,7 +108,7 @@ public class CreateRepetitionCommand extends Command if(habitId == null) throw new RuntimeException("Habit not saved"); this.habit = habitId; - this.repTimestamp = command.timestamp; + this.repTimestamp = command.timestamp.getUnixTime(); this.value = command.value; } @@ -118,7 +118,8 @@ public class CreateRepetitionCommand extends Command if(h == null) throw new HabitNotFoundException(); CreateRepetitionCommand command; - command = new CreateRepetitionCommand(h, repTimestamp, value); + command = new CreateRepetitionCommand( + h, new Timestamp(repTimestamp), value); command.setId(id); return command; } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/EditHabitCommand.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/EditHabitCommand.java index 2870f4400..3d4f010d6 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/EditHabitCommand.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/EditHabitCommand.java @@ -98,7 +98,7 @@ public class EditHabitCommand extends Command habitList.update(habit); if (hasFrequencyChanged || hasTargetChanged) - habit.invalidateNewerThan(0); + habit.invalidateNewerThan(Timestamp.ZERO); } public static class Record diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommand.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommand.java index e3b2ac793..033f9b581 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommand.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommand.java @@ -31,14 +31,14 @@ public class ToggleRepetitionCommand extends Command @NonNull private HabitList list; - final long timestamp; + final Timestamp timestamp; @NonNull final Habit habit; public ToggleRepetitionCommand(@NonNull HabitList list, @NonNull Habit habit, - long timestamp) + Timestamp timestamp) { super(); this.list = list; @@ -90,7 +90,7 @@ public class ToggleRepetitionCommand extends Command Long habitId = command.habit.getId(); if (habitId == null) throw new RuntimeException("Habit not saved"); - this.repTimestamp = command.timestamp; + this.repTimestamp = command.timestamp.getUnixTime(); this.habit = habitId; } @@ -100,7 +100,8 @@ public class ToggleRepetitionCommand extends Command if (h == null) throw new HabitNotFoundException(); ToggleRepetitionCommand command; - command = new ToggleRepetitionCommand(habitList, h, repTimestamp); + command = new ToggleRepetitionCommand( + habitList, h, new Timestamp(repTimestamp)); command.setId(id); return command; } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.java index eaa3743bb..d192400c8 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.java @@ -76,7 +76,7 @@ public class HabitBullCSVImporter extends AbstractImporter Calendar date = DateUtils.getStartOfTodayCalendar(); date.set(year, month - 1, day); - long timestamp = date.getTimeInMillis(); + Timestamp timestamp = new Timestamp(date.getTimeInMillis()); int value = Integer.parseInt(line[4]); if (value != 1) continue; diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitsCSVExporter.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitsCSVExporter.java index 9665332fe..e8a8f3769 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitsCSVExporter.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitsCSVExporter.java @@ -173,9 +173,9 @@ public class HabitsCSVExporter writeMultipleHabitsHeader(scoresWriter); writeMultipleHabitsHeader(checksWriter); - long[] timeframe = getTimeframe(); - long oldest = timeframe[0]; - long newest = DateUtils.getStartOfToday(); + Timestamp[] timeframe = getTimeframe(); + Timestamp oldest = timeframe[0]; + Timestamp newest = DateUtils.getToday(); List checkmarks = new ArrayList<>(); List scores = new ArrayList<>(); @@ -185,11 +185,11 @@ public class HabitsCSVExporter scores.add(h.getScores().getValues(oldest, newest)); } - int days = DateUtils.getDaysBetween(oldest, newest); + int days = oldest.daysUntil(newest); SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat(); for (int i = 0; i <= days; i++) { - Date day = new Date(newest - i * DateUtils.millisecondsInOneDay); + Date day = newest.minus(i).toJavaDate(); String date = dateFormat.format(day); StringBuilder sb = new StringBuilder(); @@ -238,20 +238,20 @@ public class HabitsCSVExporter * * @return the timeframe containing the oldest timestamp and the newest timestamp */ - private long[] getTimeframe() + private Timestamp[] getTimeframe() { - long oldest = Long.MAX_VALUE; - long newest = -1; + Timestamp oldest = Timestamp.ZERO.plus(1000000); + Timestamp newest = Timestamp.ZERO; for (Habit h : selectedHabits) { if(h.getRepetitions().getOldest() == null || h.getRepetitions().getNewest() == null) continue; - long currOld = h.getRepetitions().getOldest().getTimestamp(); - long currNew = h.getRepetitions().getNewest().getTimestamp(); - oldest = currOld > oldest ? oldest : currOld; - newest = currNew < newest ? newest : currNew; + Timestamp currOld = h.getRepetitions().getOldest().getTimestamp(); + Timestamp currNew = h.getRepetitions().getNewest().getTimestamp(); + oldest = currOld.isOlderThan(oldest) ? oldest : currOld; + newest = currNew.isNewerThan(newest) ? newest : currNew; } - return new long[]{oldest, newest}; + return new Timestamp[]{oldest, newest}; } private String writeZipFile() throws IOException diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.java index 006d314f3..adebec91e 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.java @@ -109,7 +109,7 @@ public class LoopDBImporter extends AbstractImporter habitRecord.id.toString()); for (RepetitionRecord r : reps) - h.getRepetitions().toggle(r.timestamp, r.value); + h.getRepetitions().toggle(new Timestamp(r.timestamp), r.value); } } } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/RewireDBImporter.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/RewireDBImporter.java index cc55864f1..66c986a14 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/RewireDBImporter.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/RewireDBImporter.java @@ -165,7 +165,7 @@ public class RewireDBImporter extends AbstractImporter GregorianCalendar cal = DateUtils.getStartOfTodayCalendar(); cal.set(year, month - 1, day); - habit.getRepetitions().toggle(cal.getTimeInMillis()); + habit.getRepetitions().toggle(new Timestamp(cal)); } while (c.moveToNext()); } finally diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/TickmateDBImporter.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/TickmateDBImporter.java index 505f1d154..eac6a7fe4 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/io/TickmateDBImporter.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/io/TickmateDBImporter.java @@ -100,7 +100,7 @@ public class TickmateDBImporter extends AbstractImporter GregorianCalendar cal = DateUtils.getStartOfTodayCalendar(); cal.set(year, month, day); - habit.getRepetitions().toggle(cal.getTimeInMillis()); + habit.getRepetitions().toggle(new Timestamp(cal)); } while (c.moveToNext()); } finally diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Checkmark.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Checkmark.java index 79a54d1ed..bb6ccc4f3 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Checkmark.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Checkmark.java @@ -52,7 +52,7 @@ public final class Checkmark */ public static final int UNCHECKED = 0; - private final long timestamp; + private final Timestamp timestamp; /** * The value of the checkmark. @@ -65,17 +65,12 @@ public final class Checkmark */ private final int value; - public Checkmark(long timestamp, int value) + public Checkmark(Timestamp timestamp, int value) { this.timestamp = timestamp; this.value = value; } - public int compareNewer(Checkmark other) - { - return Long.signum(this.getTimestamp() - other.getTimestamp()); - } - @Override public boolean equals(Object o) { @@ -91,7 +86,7 @@ public final class Checkmark .isEquals(); } - public long getTimestamp() + public Timestamp getTimestamp() { return timestamp; } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/CheckmarkList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/CheckmarkList.java index 21e33242c..5133fcf1c 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/CheckmarkList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/CheckmarkList.java @@ -30,10 +30,7 @@ import java.util.*; import javax.annotation.concurrent.*; -import static java.lang.Math.min; -import static org.isoron.uhabits.core.models.Checkmark.CHECKED_EXPLICITLY; -import static org.isoron.uhabits.core.models.Checkmark.CHECKED_IMPLICITLY; -import static org.isoron.uhabits.core.models.Checkmark.UNCHECKED; +import static org.isoron.uhabits.core.models.Checkmark.*; /** * The collection of {@link Checkmark}s belonging to a habit. @@ -57,32 +54,30 @@ public abstract class CheckmarkList { if (reps.length == 0) throw new IllegalArgumentException(); - long day = DateUtils.millisecondsInOneDay; - long today = DateUtils.getStartOfToday(); - - long begin = reps[0].getTimestamp(); - if (intervals.size() > 0) begin = min(begin, intervals.get(0).begin); - - int nDays = (int) ((today - begin) / day) + 1; + Timestamp today = DateUtils.getToday(); + Timestamp begin = reps[0].getTimestamp(); + if (intervals.size() > 0) begin = Timestamp.oldest(begin, intervals.get(0).begin); + int nDays = begin.daysUntil(today) + 1; List checkmarks = new ArrayList<>(nDays); for (int i = 0; i < nDays; i++) - checkmarks.add(new Checkmark(today - day * i, UNCHECKED)); + checkmarks.add(new Checkmark(today.minus(i), UNCHECKED)); for (Interval interval : intervals) { - for (long date = interval.begin; date <= interval.end; date += day) + for (int i = 0; i < interval.length(); i++) { - if (date > today) continue; - int offset = (int) ((today - date) / day); + Timestamp date = interval.begin.plus(i); + int offset = date.daysUntil(today); + if (offset < 0) continue; checkmarks.set(offset, new Checkmark(date, CHECKED_IMPLICITLY)); } } for (Repetition rep : reps) { - long date = rep.getTimestamp(); - int offset = (int) ((today - date) / day); + Timestamp date = rep.getTimestamp(); + int offset = date.daysUntil(today); checkmarks.set(offset, new Checkmark(date, CHECKED_EXPLICITLY)); } @@ -104,7 +99,6 @@ public abstract class CheckmarkList static ArrayList buildIntervals(@NonNull Frequency freq, @NonNull Repetition[] reps) { - long day = DateUtils.millisecondsInOneDay; int num = freq.getNumerator(); int den = freq.getDenominator(); @@ -114,12 +108,12 @@ public abstract class CheckmarkList Repetition first = reps[i]; Repetition last = reps[i + num - 1]; - long distance = (last.getTimestamp() - first.getTimestamp()) / day; + long distance = first.getTimestamp().daysUntil(last.getTimestamp()); if (distance >= den) continue; - long begin = first.getTimestamp(); - long center = last.getTimestamp(); - long end = begin + (den - 1) * day; + Timestamp begin = first.getTimestamp(); + Timestamp center = last.getTimestamp(); + Timestamp end = begin.plus(den - 1); intervals.add(new Interval(begin, center, end)); } @@ -134,17 +128,15 @@ public abstract class CheckmarkList */ static void snapIntervalsTogether(@NonNull ArrayList intervals) { - long day = DateUtils.millisecondsInOneDay; - for (int i = 1; i < intervals.size(); i++) { Interval curr = intervals.get(i); Interval prev = intervals.get(i - 1); - long distance = curr.begin - prev.end - day; - if (distance <= 0 || curr.end - distance < curr.center) continue; - intervals.set(i, new Interval(curr.begin - distance, curr.center, - curr.end - distance)); + int gap = prev.end.daysUntil(curr.begin) - 1; + if (gap <= 0 || curr.end.minus(gap).isOlderThan(curr.center)) continue; + intervals.set(i, new Interval(curr.begin.minus(gap), curr.center, + curr.end.minus(gap))); } } @@ -176,8 +168,8 @@ public abstract class CheckmarkList Repetition oldestRep = habit.getRepetitions().getOldest(); if (oldestRep == null) return new int[0]; - Long fromTimestamp = oldestRep.getTimestamp(); - Long toTimestamp = DateUtils.getStartOfToday(); + Timestamp fromTimestamp = oldestRep.getTimestamp(); + Timestamp toTimestamp = DateUtils.getToday(); return getValues(fromTimestamp, toTimestamp); } @@ -195,8 +187,8 @@ public abstract class CheckmarkList * @return the list of checkmarks within the interval. */ @NonNull - public abstract List getByInterval(long fromTimestamp, - long toTimestamp); + public abstract List getByInterval(Timestamp fromTimestamp, + Timestamp toTimestamp); /** * Returns the checkmark for today. @@ -207,7 +199,7 @@ public abstract class CheckmarkList public synchronized final Checkmark getToday() { compute(); - long today = DateUtils.getStartOfToday(); + Timestamp today = DateUtils.getToday(); return getByInterval(today, today).get(0); } @@ -236,9 +228,9 @@ public abstract class CheckmarkList * @param to timestamp for the newest checkmark * @return values for the checkmarks inside the given interval */ - public final int[] getValues(long from, long to) + public final int[] getValues(Timestamp from, Timestamp to) { - if (from > to) return new int[0]; + if (from.isNewerThan(to)) return new int[0]; List checkmarks = getByInterval(from, to); int values[] = new int[checkmarks.size()]; @@ -257,7 +249,7 @@ public abstract class CheckmarkList * * @param timestamp the timestamp */ - public abstract void invalidateNewerThan(long timestamp); + public abstract void invalidateNewerThan(Timestamp timestamp); /** * Writes the entire list of checkmarks to the given writer, in CSV format. @@ -275,14 +267,14 @@ public abstract class CheckmarkList values = getAllValues(); } - long timestamp = DateUtils.getStartOfToday(); + Timestamp timestamp = DateUtils.getToday(); SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat(); for (int value : values) { - String date = dateFormat.format(new Date(timestamp)); + String date = dateFormat.format(timestamp.toJavaDate()); out.write(String.format("%s,%d\n", date, value)); - timestamp -= DateUtils.millisecondsInOneDay; + timestamp = timestamp.minus(1); } } @@ -292,15 +284,15 @@ public abstract class CheckmarkList */ protected final synchronized void compute() { - final long today = DateUtils.getStartOfToday(); + final Timestamp today = DateUtils.getToday(); Checkmark newest = getNewestComputed(); - if (newest != null && newest.getTimestamp() == today) return; - invalidateNewerThan(0); + if (newest != null && newest.getTimestamp().equals(today)) return; + invalidateNewerThan(Timestamp.ZERO); Repetition oldestRep = habit.getRepetitions().getOldest(); if (oldestRep == null) return; - final long from = oldestRep.getTimestamp(); + final Timestamp from = oldestRep.getTimestamp(); Repetition reps[] = habit .getRepetitions() @@ -331,20 +323,18 @@ public abstract class CheckmarkList { if (reps.length == 0) throw new IllegalArgumentException(); - long day = DateUtils.millisecondsInOneDay; - long today = DateUtils.getStartOfToday(); - long begin = reps[0].getTimestamp(); + Timestamp today = DateUtils.getToday(); + Timestamp begin = reps[0].getTimestamp(); - int nDays = (int) ((today - begin) / day) + 1; + int nDays = begin.daysUntil(today) + 1; List checkmarks = new ArrayList<>(nDays); for (int i = 0; i < nDays; i++) - checkmarks.add(new Checkmark(today - day * i, 0)); + checkmarks.add(new Checkmark(today.minus(i), 0)); for (Repetition rep : reps) { - long date = rep.getTimestamp(); - int offset = (int) ((today - date) / day); - checkmarks.set(offset, new Checkmark(date, rep.getValue())); + int offset = rep.getTimestamp().daysUntil(today); + checkmarks.set(offset, new Checkmark(rep.getTimestamp(), rep.getValue())); } add(checkmarks); @@ -360,19 +350,23 @@ public abstract class CheckmarkList static class Interval { - final long begin; + final Timestamp begin; - final long center; + final Timestamp center; - final long end; + final Timestamp end; - Interval(long begin, long center, long end) + Interval(Timestamp begin, Timestamp center, Timestamp end) { this.begin = begin; this.center = center; this.end = end; } + public int length() { + return begin.daysUntil(end) + 1; + } + @Override public boolean equals(Object o) { diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java index 276874d2e..4a4d3e1a1 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java @@ -303,7 +303,7 @@ public class Habit return data.reminder != null; } - public void invalidateNewerThan(long timestamp) + public void invalidateNewerThan(Timestamp timestamp) { getScores().invalidateNewerThan(timestamp); getCheckmarks().invalidateNewerThan(timestamp); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/HabitList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/HabitList.java index 7e0346959..4e9facf8e 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/HabitList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/HabitList.java @@ -162,9 +162,9 @@ public abstract class HabitList implements Iterable { for (Habit h : this) { - h.getCheckmarks().invalidateNewerThan(0); - h.getStreaks().invalidateNewerThan(0); - h.getScores().invalidateNewerThan(0); + h.getCheckmarks().invalidateNewerThan(Timestamp.ZERO); + h.getStreaks().invalidateNewerThan(Timestamp.ZERO); + h.getScores().invalidateNewerThan(Timestamp.ZERO); } } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Repetition.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Repetition.java index 323577588..762234696 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Repetition.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Repetition.java @@ -28,7 +28,7 @@ import org.apache.commons.lang3.builder.*; public final class Repetition { - private final long timestamp; + private final Timestamp timestamp; /** * The value of the repetition. @@ -47,7 +47,7 @@ public final class Repetition * * @param timestamp the time this repetition occurred. */ - public Repetition(long timestamp, int value) + public Repetition(Timestamp timestamp, int value) { this.timestamp = timestamp; this.value = value; @@ -67,7 +67,7 @@ public final class Repetition .isEquals(); } - public long getTimestamp() + public Timestamp getTimestamp() { return timestamp; } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/RepetitionList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/RepetitionList.java index d6ac2786b..e465eed3e 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/RepetitionList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/RepetitionList.java @@ -60,7 +60,7 @@ public abstract class RepetitionList * @return true if list contains repetition with given timestamp, false * otherwise. */ - public boolean containsTimestamp(long timestamp) + public boolean containsTimestamp(Timestamp timestamp) { return (getByTimestamp(timestamp) != null); } @@ -77,8 +77,8 @@ public abstract class RepetitionList * @param toTimestamp timestamp of the end of the interval * @return list of repetitions within given time interval */ - public abstract List getByInterval(long fromTimestamp, - long toTimestamp); + public abstract List getByInterval(Timestamp fromTimestamp, + Timestamp toTimestamp); /** * Returns the repetition that has the given timestamp, or null if none @@ -88,7 +88,7 @@ public abstract class RepetitionList * @return the repetition that has the given timestamp. */ @Nullable - public abstract Repetition getByTimestamp(long timestamp); + public abstract Repetition getByTimestamp(Timestamp timestamp); @NonNull public ModelObservable getObservable() @@ -132,18 +132,19 @@ public abstract class RepetitionList * @return total number of repetitions by month versus day of week */ @NonNull - public HashMap getWeekdayFrequency() + public HashMap getWeekdayFrequency() { - List reps = getByInterval(0, DateUtils.getStartOfToday()); - HashMap map = new HashMap<>(); + List reps = + getByInterval(Timestamp.ZERO, DateUtils.getToday()); + HashMap map = new HashMap<>(); for (Repetition r : reps) { - Calendar date = DateUtils.getCalendar(r.getTimestamp()); - int weekday = DateUtils.getWeekday(r.getTimestamp()); + Calendar date = r.getTimestamp().toCalendar(); + int weekday = r.getTimestamp().getWeekday(); date.set(Calendar.DAY_OF_MONTH, 1); - long timestamp = date.getTimeInMillis(); + Timestamp timestamp = new Timestamp(date.getTimeInMillis()); Integer[] list = map.get(timestamp); if (list == null) @@ -184,14 +185,12 @@ public abstract class RepetitionList * @return the repetition that has been added or removed. */ @NonNull - public Repetition toggle(long timestamp) + public synchronized Repetition toggle(Timestamp timestamp) { if(habit.isNumerical()) throw new IllegalStateException("habit must NOT be numerical"); - timestamp = DateUtils.getStartOfDay(timestamp); Repetition rep = getByTimestamp(timestamp); - if (rep != null) remove(rep); else { @@ -211,7 +210,7 @@ public abstract class RepetitionList @NonNull public abstract long getTotalCount(); - public void toggle(long timestamp, int value) + public void toggle(Timestamp timestamp, int value) { Repetition rep = getByTimestamp(timestamp); if(rep != null) remove(rep); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Score.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Score.java index 71739f34a..550e96dab 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Score.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Score.java @@ -32,14 +32,14 @@ public final class Score * Timestamp of the day to which this score applies. Time of day should be * midnight (UTC). */ - private final long timestamp; + private final Timestamp timestamp; /** * Value of the score. */ private final double value; - public Score(long timestamp, double value) + public Score(Timestamp timestamp, double value) { this.timestamp = timestamp; this.value = value; @@ -72,10 +72,10 @@ public final class Score public int compareNewer(Score other) { - return Long.signum(this.getTimestamp() - other.getTimestamp()); + return getTimestamp().compare(other.getTimestamp()); } - public long getTimestamp() + public Timestamp getTimestamp() { return timestamp; } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/ScoreList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/ScoreList.java index 0f9c19145..43959c11c 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/ScoreList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/ScoreList.java @@ -69,7 +69,7 @@ public abstract class ScoreList implements Iterable */ public double getTodayValue() { - return getValue(DateUtils.getStartOfToday()); + return getValue(DateUtils.getToday()); } /** @@ -81,11 +81,11 @@ public abstract class ScoreList implements Iterable * @param timestamp the timestamp of a day * @return score value for that day */ - public final synchronized double getValue(long timestamp) + public final synchronized double getValue(Timestamp timestamp) { compute(timestamp, timestamp); Score s = getComputedByTimestamp(timestamp); - if(s == null) throw new IllegalStateException(); + if (s == null) throw new IllegalStateException(); return s.getValue(); } @@ -102,8 +102,8 @@ public abstract class ScoreList implements Iterable * @return the list of scores within the interval. */ @NonNull - public abstract List getByInterval(long fromTimestamp, - long toTimestamp); + public abstract List getByInterval(@NonNull Timestamp fromTimestamp, + @NonNull Timestamp toTimestamp); /** * Returns the values of the scores that fall inside a certain interval @@ -118,12 +118,12 @@ public abstract class ScoreList implements Iterable * @param to timestamp for the newest score * @return values for the scores inside the given interval */ - public final double[] getValues(long from, long to) + public final double[] getValues(Timestamp from, Timestamp to) { List scores = getByInterval(from, to); double[] values = new double[scores.size()]; - for(int i = 0; i < values.length; i++) + for (int i = 0; i < values.length; i++) values[i] = scores.get(i).getValue(); return values; @@ -132,7 +132,7 @@ public abstract class ScoreList implements Iterable public List groupBy(DateUtils.TruncateField field) { computeAll(); - HashMap> groups = getGroupedValues(field); + HashMap> groups = getGroupedValues(field); List scores = groupsToAvgScores(groups); Collections.sort(scores, (s1, s2) -> s2.compareNewer(s1)); return scores; @@ -145,7 +145,7 @@ public abstract class ScoreList implements Iterable * * @param timestamp the oldest timestamp that should be invalidated */ - public abstract void invalidateNewerThan(long timestamp); + public abstract void invalidateNewerThan(Timestamp timestamp); @Override public Iterator iterator() @@ -171,9 +171,8 @@ public abstract class ScoreList implements Iterable for (Score s : this) { - String timestamp = dateFormat.format(s.getTimestamp()); - String score = - String.format("%.4f", s.getValue()); + String timestamp = dateFormat.format(s.getTimestamp().getUnixTime()); + String score = String.format("%.4f", s.getValue()); out.write(String.format("%s,%s\n", timestamp, score)); } } @@ -192,25 +191,24 @@ public abstract class ScoreList implements Iterable * @param from timestamp of the beginning of the interval * @param to timestamp of the end of the time interval */ - protected synchronized void compute(long from, long to) + protected synchronized void compute(@NonNull Timestamp from, + @NonNull Timestamp to) { - final long day = DateUtils.millisecondsInOneDay; - Score newest = getNewestComputed(); Score oldest = getOldestComputed(); if (newest == null) { Repetition oldestRep = habit.getRepetitions().getOldest(); - if (oldestRep != null) - from = Math.min(from, oldestRep.getTimestamp()); + if (oldestRep != null) from = + Timestamp.oldest(from, oldestRep.getTimestamp()); forceRecompute(from, to, 0); } else { if (oldest == null) throw new IllegalStateException(); - forceRecompute(from, oldest.getTimestamp() - day, 0); - forceRecompute(newest.getTimestamp() + day, to, + forceRecompute(from, oldest.getTimestamp().minus(1), 0); + forceRecompute(newest.getTimestamp().plus(1), to, newest.getValue()); } } @@ -224,7 +222,7 @@ public abstract class ScoreList implements Iterable Repetition oldestRep = habit.getRepetitions().getOldest(); if (oldestRep == null) return; - long today = DateUtils.getStartOfToday(); + Timestamp today = DateUtils.getToday(); compute(oldestRep.getTimestamp(), today); } @@ -236,7 +234,7 @@ public abstract class ScoreList implements Iterable * @return the score with given timestamp, or null not yet computed. */ @Nullable - protected abstract Score getComputedByTimestamp(long timestamp); + protected abstract Score getComputedByTimestamp(Timestamp timestamp); /** * Returns the most recent score that has already been computed. If no score @@ -263,11 +261,11 @@ public abstract class ScoreList implements Iterable * @param previousValue value of the score on the day immediately before the * interval begins */ - private void forceRecompute(long from, long to, double previousValue) + private void forceRecompute(@NonNull Timestamp from, + @NonNull Timestamp to, + double previousValue) { - if(from > to) return; - - final long day = DateUtils.millisecondsInOneDay; + if (from.isNewerThan(to)) return; final double freq = habit.getFrequency().toDouble(); final int checkmarkValues[] = habit.getCheckmarks().getValues(from, to); @@ -278,31 +276,31 @@ public abstract class ScoreList implements Iterable { double value = checkmarkValues[checkmarkValues.length - i - 1]; - if(habit.isNumerical()) + if (habit.isNumerical()) { value /= 1000; value /= habit.getTargetValue(); value = Math.min(1, value); } - if(!habit.isNumerical() && value > 0) - value = 1; + if (!habit.isNumerical() && value > 0) value = 1; previousValue = Score.compute(freq, previousValue, value); - scores.add(new Score(from + day * i, previousValue)); + scores.add(new Score(from.plus(i), previousValue)); } add(scores); } @NonNull - private HashMap> getGroupedValues(DateUtils.TruncateField field) + private HashMap> getGroupedValues(DateUtils.TruncateField field) { - HashMap> groups = new HashMap<>(); + HashMap> groups = new HashMap<>(); for (Score s : this) { - long groupTimestamp = DateUtils.truncate(field, s.getTimestamp()); + Timestamp groupTimestamp = new Timestamp( + DateUtils.truncate(field, s.getTimestamp().getUnixTime())); if (!groups.containsKey(groupTimestamp)) groups.put(groupTimestamp, new ArrayList<>()); @@ -314,11 +312,11 @@ public abstract class ScoreList implements Iterable } @NonNull - private List groupsToAvgScores(HashMap> groups) + private List groupsToAvgScores(HashMap> groups) { List scores = new LinkedList<>(); - for (Long timestamp : groups.keySet()) + for (Timestamp timestamp : groups.keySet()) { double meanValue = 0.0; ArrayList groupValues = groups.get(timestamp); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Streak.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Streak.java index aff58c180..e557eb4d3 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Streak.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Streak.java @@ -20,15 +20,14 @@ package org.isoron.uhabits.core.models; import org.apache.commons.lang3.builder.*; -import org.isoron.uhabits.core.utils.*; public final class Streak { - private final long start; + private final Timestamp start; - private final long end; + private final Timestamp end; - public Streak(long start, long end) + public Streak(Timestamp start, Timestamp end) { this.start = start; this.end = end; @@ -39,25 +38,25 @@ public final class Streak if (this.getLength() != other.getLength()) return Long.signum(this.getLength() - other.getLength()); - return Long.signum(this.getEnd() - other.getEnd()); + return compareNewer(other); } public int compareNewer(Streak other) { - return Long.signum(this.getEnd() - other.getEnd()); + return end.compare(other.end); } - public long getEnd() + public Timestamp getEnd() { return end; } - public long getLength() + public int getLength() { - return (end - start) / DateUtils.millisecondsInOneDay + 1; + return start.daysUntil(end) + 1; } - public long getStart() + public Timestamp getStart() { return start; } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/StreakList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/StreakList.java index ae2bc3032..0eef1cdbc 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/StreakList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/StreakList.java @@ -63,14 +63,13 @@ public abstract class StreakList return observable; } - public abstract void invalidateNewerThan(long timestamp); + public abstract void invalidateNewerThan(Timestamp timestamp); public synchronized void rebuild() { - long today = DateUtils.getStartOfToday(); - - Long beginning = findBeginning(); - if (beginning == null || beginning > today) return; + Timestamp today = DateUtils.getToday(); + Timestamp beginning = findBeginning(); + if (beginning == null || beginning.isNewerThan(today)) return; int checks[] = habit.getCheckmarks().getValues(beginning, today); List streaks = checkmarksToStreaks(beginning, checks); @@ -88,15 +87,15 @@ public abstract class StreakList * @return the list of streaks. */ @NonNull - protected List checkmarksToStreaks(long beginning, int[] checks) + protected List checkmarksToStreaks(Timestamp beginning, int[] checks) { - ArrayList transitions = getTransitions(beginning, checks); + ArrayList transitions = getTransitions(beginning, checks); List streaks = new LinkedList<>(); for (int i = 0; i < transitions.size(); i += 2) { - long start = transitions.get(i); - long end = transitions.get(i + 1); + Timestamp start = transitions.get(i); + Timestamp end = transitions.get(i + 1); streaks.add(new Streak(start, end)); } @@ -109,14 +108,13 @@ public abstract class StreakList * @return */ @Nullable - protected Long findBeginning() + protected Timestamp findBeginning() { Streak newestStreak = getNewestComputed(); if (newestStreak != null) return newestStreak.getStart(); Repetition oldestRep = habit.getRepetitions().getOldest(); if (oldestRep != null) return oldestRep.getTimestamp(); - return null; } @@ -129,21 +127,19 @@ public abstract class StreakList * @return the list of transitions */ @NonNull - protected ArrayList getTransitions(long beginning, int[] checks) + protected ArrayList getTransitions(Timestamp beginning, int[] checks) { - long day = DateUtils.millisecondsInOneDay; - long current = beginning; - - ArrayList list = new ArrayList<>(); + ArrayList list = new ArrayList<>(); + Timestamp current = beginning; list.add(current); for (int i = 1; i < checks.length; i++) { - current += day; + 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 - day); + if ((checks[j + 1] > 0 && checks[j] == 0)) list.add(current.minus(1)); } if (list.size() % 2 == 1) list.add(current); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Timestamp.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Timestamp.java new file mode 100644 index 000000000..a4d8fc911 --- /dev/null +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Timestamp.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2015-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.models; + +import org.apache.commons.lang3.builder.*; + +import java.util.*; + +import static java.util.Calendar.DAY_OF_WEEK; + +public class Timestamp +{ + + public static final long DAY_LENGTH = 86400000; + + public static final Timestamp ZERO = new Timestamp(0); + + private final long unixTime; + + public Timestamp(long unixTime) + { + if (unixTime < 0 || unixTime % DAY_LENGTH != 0) + throw new IllegalArgumentException( + "Invalid unix time: " + unixTime); + + this.unixTime = unixTime; + } + + public Timestamp(GregorianCalendar cal) + { + this(cal.getTimeInMillis()); + } + + public long getUnixTime() + { + return unixTime; + } + + /** + * Returns -1 if this timestamp is older than the given timestamp, 1 if this + * timestamp is newer, or zero if they are equal. + */ + public int compare(Timestamp other) + { + return Long.signum(this.unixTime - other.unixTime); + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + Timestamp timestamp = (Timestamp) o; + + return new EqualsBuilder() + .append(unixTime, timestamp.unixTime) + .isEquals(); + } + + @Override + public int hashCode() + { + return new HashCodeBuilder(17, 37).append(unixTime).toHashCode(); + } + + /** + * Given two timestamps, returns whichever timestamp is the oldest one. + */ + public static Timestamp oldest(Timestamp first, Timestamp second) + { + return first.unixTime < second.unixTime ? first : second; + } + + public Timestamp minus(int days) + { + return plus(-days); + } + + public Timestamp plus(int days) + { + return new Timestamp(unixTime + DAY_LENGTH * days); + } + + /** + * Returns the number of days between this timestamp and the given one. If + * the other timestamp equals this one, returns zero. If the other timestamp + * is older than this one, returns a negative number. + */ + public int daysUntil(Timestamp other) + { + return (int) ((other.unixTime - this.unixTime) / DAY_LENGTH); + } + + public boolean isNewerThan(Timestamp other) + { + return compare(other) > 0; + } + + public boolean isOlderThan(Timestamp other) + { + return compare(other) < 0; + } + + + public Date toJavaDate() + { + return new Date(unixTime); + } + + public GregorianCalendar toCalendar() + { + GregorianCalendar day = + new GregorianCalendar(TimeZone.getTimeZone("GMT")); + day.setTimeInMillis(unixTime); + return day; + } + + @Override + public String toString() + { + return new ToStringBuilder(this) + .append("unixTime", unixTime) + .toString(); + } + + public int getWeekday() + { + return toCalendar().get(DAY_OF_WEEK) % 7; + } +} diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryCheckmarkList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryCheckmarkList.java index b6d3ee718..1a46cc434 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryCheckmarkList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryCheckmarkList.java @@ -22,12 +22,9 @@ package org.isoron.uhabits.core.models.memory; import android.support.annotation.*; import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.utils.*; import java.util.*; -import static org.isoron.uhabits.core.utils.DateUtils.*; - /** * In-memory implementation of {@link CheckmarkList}. */ @@ -45,42 +42,42 @@ public class MemoryCheckmarkList extends CheckmarkList public void add(List checkmarks) { list.addAll(checkmarks); - Collections.sort(list, (c1, c2) -> c2.compareNewer(c1)); + Collections.sort(list, + (c1, c2) -> c2.getTimestamp().compare(c1.getTimestamp())); } @NonNull @Override - public List getByInterval(long fromTimestamp, long toTimestamp) + public synchronized List getByInterval(Timestamp from, + Timestamp to) { compute(); - long newestTimestamp = Long.MIN_VALUE; - long oldestTimestamp = Long.MAX_VALUE; + Timestamp newestComputed = new Timestamp(0); + Timestamp oldestComputed = new Timestamp(0).plus(1000000); Checkmark newest = getNewestComputed(); Checkmark oldest = getOldestComputed(); - if(newest != null) newestTimestamp = newest.getTimestamp(); - if(oldest != null) oldestTimestamp = oldest.getTimestamp(); - long days = (newestTimestamp - oldestTimestamp) / - DateUtils.millisecondsInOneDay; + if(newest != null) newestComputed = newest.getTimestamp(); + if(oldest != null) oldestComputed = oldest.getTimestamp(); + + List filtered = new ArrayList<>( + Math.max(0, oldestComputed.daysUntil(newestComputed) + 1)); - List filtered = new ArrayList<>((int) days); - for(long time = toTimestamp; time >= fromTimestamp; time -= millisecondsInOneDay) + for(int i = 0; i <= from.daysUntil(to); i++) { - if(time > newestTimestamp || time < oldestTimestamp) - filtered.add(new Checkmark(time, Checkmark.UNCHECKED)); + Timestamp t = to.minus(i); + if(t.isNewerThan(newestComputed) || t.isOlderThan(oldestComputed)) + filtered.add(new Checkmark(t, Checkmark.UNCHECKED)); else - { - int offset = (int) ((newestTimestamp - time) / millisecondsInOneDay); - filtered.add(list.get(offset)); - } + filtered.add(list.get(t.daysUntil(newestComputed))); } return filtered; } @Override - public void invalidateNewerThan(long timestamp) + public void invalidateNewerThan(Timestamp timestamp) { list.clear(); observable.notifyListeners(); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryRepetitionList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryRepetitionList.java index 8bd6441ed..fe4dc1f06 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryRepetitionList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryRepetitionList.java @@ -46,28 +46,29 @@ public class MemoryRepetitionList extends RepetitionList } @Override - public List getByInterval(long fromTimestamp, long toTimestamp) + public List getByInterval(Timestamp fromTimestamp, Timestamp toTimestamp) { ArrayList filtered = new ArrayList<>(); for (Repetition r : list) { - long t = r.getTimestamp(); - if (t >= fromTimestamp && t <= toTimestamp) filtered.add(r); + Timestamp t = r.getTimestamp(); + if (t.isOlderThan(fromTimestamp) || t.isNewerThan(toTimestamp)) continue; + filtered.add(r); } Collections.sort(filtered, - (r1, r2) -> Long.compare(r1.getTimestamp(), r2.getTimestamp())); + (r1, r2) -> r1.getTimestamp().compare(r2.getTimestamp())); return filtered; } @Nullable @Override - public Repetition getByTimestamp(long timestamp) + public Repetition getByTimestamp(Timestamp timestamp) { for (Repetition r : list) - if (r.getTimestamp() == timestamp) return r; + if (r.getTimestamp().equals(timestamp)) return r; return null; } @@ -76,15 +77,15 @@ public class MemoryRepetitionList extends RepetitionList @Override public Repetition getOldest() { - long oldestTime = Long.MAX_VALUE; + Timestamp oldestTimestamp = Timestamp.ZERO.plus(1000000); Repetition oldestRep = null; for (Repetition rep : list) { - if (rep.getTimestamp() < oldestTime) + if (rep.getTimestamp().isOlderThan(oldestTimestamp)) { oldestRep = rep; - oldestTime = rep.getTimestamp(); + oldestTimestamp = rep.getTimestamp(); } } @@ -95,15 +96,15 @@ public class MemoryRepetitionList extends RepetitionList @Override public Repetition getNewest() { - long newestTime = -1; + Timestamp newestTimestamp = Timestamp.ZERO; Repetition newestRep = null; for (Repetition rep : list) { - if (rep.getTimestamp() > newestTime) + if (rep.getTimestamp().isNewerThan(newestTimestamp)) { newestRep = rep; - newestTime = rep.getTimestamp(); + newestTimestamp = rep.getTimestamp(); } } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryScoreList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryScoreList.java index cfe1730bf..1c13d2b1f 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryScoreList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryScoreList.java @@ -40,37 +40,41 @@ public class MemoryScoreList extends ScoreList { list.addAll(scores); Collections.sort(list, - (s1, s2) -> Long.signum(s2.getTimestamp() - s1.getTimestamp())); + (s1, s2) -> s2.getTimestamp().compare(s1.getTimestamp())); getObservable().notifyListeners(); } @NonNull @Override - public List getByInterval(long fromTimestamp, long toTimestamp) + public List getByInterval(@NonNull Timestamp fromTimestamp, + @NonNull Timestamp toTimestamp) { compute(fromTimestamp, toTimestamp); List filtered = new LinkedList<>(); for (Score s : list) - if (s.getTimestamp() >= fromTimestamp && - s.getTimestamp() <= toTimestamp) filtered.add(s); + { + if (s.getTimestamp().isNewerThan(toTimestamp) || + s.getTimestamp().isOlderThan(fromTimestamp)) continue; + filtered.add(s); + } return filtered; } @Nullable @Override - public Score getComputedByTimestamp(long timestamp) + public Score getComputedByTimestamp(Timestamp timestamp) { for (Score s : list) - if (s.getTimestamp() == timestamp) return s; + if (s.getTimestamp().equals(timestamp)) return s; return null; } @Override - public void invalidateNewerThan(long timestamp) + public void invalidateNewerThan(Timestamp timestamp) { list.clear(); getObservable().notifyListeners(); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryStreakList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryStreakList.java index a388d7ae1..0f7444855 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryStreakList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryStreakList.java @@ -41,13 +41,14 @@ public class MemoryStreakList extends StreakList Streak newest = null; for (Streak s : list) - if (newest == null || s.getEnd() > newest.getEnd()) newest = s; + if (newest == null || s.getEnd().isNewerThan(newest.getEnd())) + newest = s; return newest; } @Override - public void invalidateNewerThan(long timestamp) + public void invalidateNewerThan(Timestamp timestamp) { list.clear(); observable.notifyListeners(); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/SQLiteRepetitionList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/SQLiteRepetitionList.java index 3dd0690b3..dbf7a81b3 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/SQLiteRepetitionList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/SQLiteRepetitionList.java @@ -79,7 +79,7 @@ public class SQLiteRepetitionList extends RepetitionList } @Override - public List getByInterval(long timeFrom, long timeTo) + public List getByInterval(Timestamp timeFrom, Timestamp timeTo) { loadRecords(); return list.getByInterval(timeFrom, timeTo); @@ -87,7 +87,7 @@ public class SQLiteRepetitionList extends RepetitionList @Override @Nullable - public Repetition getByTimestamp(long timestamp) + public Repetition getByTimestamp(Timestamp timestamp) { loadRecords(); return list.getByTimestamp(timestamp); @@ -115,7 +115,7 @@ public class SQLiteRepetitionList extends RepetitionList check(habit.getId()); repository.execSQL( "delete from repetitions where habit = ? and timestamp = ?", - habit.getId(), repetition.getTimestamp()); + habit.getId(), repetition.getTimestamp().getUnixTime()); observable.notifyListeners(); } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/records/RepetitionRecord.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/records/RepetitionRecord.java index 30bc1958e..0bd5d2552 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/records/RepetitionRecord.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/records/RepetitionRecord.java @@ -46,12 +46,12 @@ public class RepetitionRecord public void copyFrom(Repetition repetition) { - timestamp = repetition.getTimestamp(); + timestamp = repetition.getTimestamp().getUnixTime(); value = repetition.getValue(); } public Repetition toRepetition() { - return new Repetition(timestamp, value); + return new Repetition(new Timestamp(timestamp), value); } } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/preferences/Preferences.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/preferences/Preferences.java index 50985bdd4..043f77389 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/preferences/Preferences.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/preferences/Preferences.java @@ -94,9 +94,11 @@ public class Preferences return storage.getInt("last_hint_number", -1); } - public long getLastHintTimestamp() + public Timestamp getLastHintTimestamp() { - return storage.getLong("last_hint_timestamp", -1); + long unixTime = storage.getLong("last_hint_timestamp", -1); + if (unixTime < 0) return null; + else return new Timestamp(unixTime); } public long getLastSync() @@ -274,10 +276,10 @@ public class Preferences return shouldReverseCheckmarks; } - public void updateLastHint(int number, long timestamp) + public void updateLastHint(int number, Timestamp timestamp) { storage.putInt("last_hint_number", number); - storage.putLong("last_hint_timestamp", timestamp); + storage.putLong("last_hint_timestamp", timestamp.getUnixTime()); } public interface Listener diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/reminders/ReminderScheduler.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/reminders/ReminderScheduler.java index f1a6224fb..e31ed71ed 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/reminders/ReminderScheduler.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/reminders/ReminderScheduler.java @@ -71,7 +71,7 @@ public class ReminderScheduler implements CommandRunner.Listener sys.scheduleShowReminder(reminderTime, habit, timestamp); } - public void scheduleAll() + public synchronized void scheduleAll() { HabitList reminderHabits = habitList.getFiltered(HabitMatcher.WITH_ALARM); @@ -99,7 +99,7 @@ public class ReminderScheduler implements CommandRunner.Listener Long time = calendar.getTimeInMillis(); if (DateUtils.getLocalTime() > time) - time += DateUtils.millisecondsInOneDay; + time += DateUtils.DAY_LENGTH; return applyTimezone(time); } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/test/HabitFixtures.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/test/HabitFixtures.java index 6f0a984ee..4e27c9960 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/test/HabitFixtures.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/test/HabitFixtures.java @@ -57,14 +57,13 @@ public class HabitFixtures habit.setFrequency(new Frequency(3, 7)); habit.setColor(4); - long day = DateUtils.millisecondsInOneDay; - long today = DateUtils.getStartOfToday(); + Timestamp today = DateUtils.getToday(); int marks[] = { 0, 1, 3, 5, 7, 8, 9, 10, 12, 14, 15, 17, 19, 20, 26, 27, 28, 50, 51, 52, 53, 54, 58, 60, 63, 65, 70, 71, 72, 73, 74, 75, 80, 81, 83, 89, 90, 91, 95, 102, 103, 108, 109, 120}; for (int mark : marks) - habit.getRepetitions().toggle(today - mark * day); + habit.getRepetitions().toggle(today.minus(mark)); return habit; } @@ -81,14 +80,13 @@ public class HabitFixtures habit.setColor(1); saveIfSQLite(habit); - long day = DateUtils.millisecondsInOneDay; - long today = DateUtils.getStartOfToday(); + Timestamp today = DateUtils.getToday(); int times[] = { 0, 1, 3, 5, 7, 8, 9, 10 }; int values[] = { 100, 200, 300, 400, 500, 600, 700, 800 }; for(int i = 0; i < times.length; i++) { - long timestamp = today - times[i] * day; + Timestamp timestamp = today.minus(times[i]); habit.getRepetitions().add(new Repetition(timestamp, values[i])); } @@ -103,11 +101,11 @@ public class HabitFixtures habit.setFrequency(new Frequency(2, 3)); saveIfSQLite(habit); - long timestamp = DateUtils.getStartOfToday(); + Timestamp timestamp = DateUtils.getToday(); for (boolean c : NON_DAILY_HABIT_CHECKS) { if (c) habit.getRepetitions().toggle(timestamp); - timestamp -= DateUtils.millisecondsInOneDay; + timestamp = timestamp.minus(1); } return habit; diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/NotificationTray.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/NotificationTray.java index 82eb4cd39..19c23db51 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/NotificationTray.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/NotificationTray.java @@ -102,7 +102,7 @@ public class NotificationTray reshowAll(); } - public void show(@NonNull Habit habit, long timestamp, long reminderTime) + public void show(@NonNull Habit habit, Timestamp timestamp, long reminderTime) { NotificationData data = new NotificationData(timestamp, reminderTime); active.put(habit, data); @@ -143,17 +143,17 @@ public class NotificationTray void showNotification(Habit habit, int notificationId, - long timestamp, + Timestamp timestamp, long reminderTime); } class NotificationData { - public final long timestamp; + public final Timestamp timestamp; public final long reminderTime; - public NotificationData(long timestamp, long reminderTime) + public NotificationData(Timestamp timestamp, long reminderTime) { this.timestamp = timestamp; this.reminderTime = reminderTime; @@ -166,7 +166,7 @@ public class NotificationTray private final Habit habit; - private final long timestamp; + private final Timestamp timestamp; private final long reminderTime; @@ -200,7 +200,7 @@ public class NotificationTray Reminder reminder = habit.getReminder(); boolean reminderDays[] = reminder.getDays().toArray(); - int weekday = DateUtils.getWeekday(timestamp); + int weekday = timestamp.getWeekday(); return reminderDays[weekday]; } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.java index aec031950..0b545a155 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.java @@ -304,9 +304,9 @@ public class HabitCardListCache implements CommandRunner.Listener newData.copyScoresFrom(data); newData.copyCheckmarksFrom(data); - long day = DateUtils.millisecondsInOneDay; - long dateTo = DateUtils.getStartOfDay(DateUtils.getLocalTime()); - long dateFrom = dateTo - (checkmarkCount - 1) * day; + Timestamp dateTo = new Timestamp( + DateUtils.getStartOfDay(DateUtils.getLocalTime())); + Timestamp dateFrom = dateTo.minus(checkmarkCount - 1); runner.publishProgress(this, -1); @@ -319,8 +319,9 @@ public class HabitCardListCache implements CommandRunner.Listener if (targetId != null && !targetId.equals(id)) continue; newData.scores.put(id, habit.getScores().getTodayValue()); - newData.checkmarks.put(id, - habit.getCheckmarks().getValues(dateFrom, dateTo)); + newData.checkmarks.put(id, habit + .getCheckmarks() + .getValues(dateFrom, dateTo)); runner.publishProgress(this, position); } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/HintList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/HintList.java index 56bf7b23f..fd9fe5397 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/HintList.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/HintList.java @@ -23,6 +23,7 @@ import android.support.annotation.*; import com.google.auto.factory.*; +import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.preferences.*; import org.isoron.uhabits.core.utils.*; @@ -64,7 +65,7 @@ public class HintList int next = prefs.getLastHintNumber() + 1; if (next >= hints.length) return null; - prefs.updateLastHint(next, DateUtils.getStartOfToday()); + prefs.updateLastHint(next, DateUtils.getToday()); return hints[next]; } @@ -75,7 +76,8 @@ public class HintList */ public boolean shouldShow() { - long lastHintTimestamp = prefs.getLastHintTimestamp(); - return (DateUtils.getStartOfToday() > lastHintTimestamp); + Timestamp today = DateUtils.getToday(); + Timestamp lastHintTimestamp = prefs.getLastHintTimestamp(); + return (lastHintTimestamp.isOlderThan(today)); } } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java index a6d132440..45dcc18f1 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java @@ -78,7 +78,7 @@ public class ListHabitsBehavior screen.showHabitScreen(h); } - public void onEdit(@NonNull Habit habit, long timestamp) + public void onEdit(@NonNull Habit habit, Timestamp timestamp) { CheckmarkList checkmarks = habit.getCheckmarks(); double oldValue = checkmarks.getValues(timestamp, timestamp)[0]; @@ -109,7 +109,7 @@ public class ListHabitsBehavior public void onFirstRun() { prefs.setFirstRun(false); - prefs.updateLastHint(-1, DateUtils.getStartOfToday()); + prefs.updateLastHint(-1, DateUtils.getToday()); screen.showIntroScreen(); } @@ -149,7 +149,7 @@ public class ListHabitsBehavior if (prefs.isFirstRun()) onFirstRun(); } - public void onToggle(@NonNull Habit habit, long timestamp) + public void onToggle(@NonNull Habit habit, Timestamp timestamp) { commandRunner.execute( new ToggleRepetitionCommand(habitList, habit, timestamp), diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java index 9a7ced67e..907b60f1b 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java @@ -56,7 +56,7 @@ public class ShowHabitBehavior screen.showEditHistoryScreen(); } - public void onToggleCheckmark(long timestamp) + public void onToggleCheckmark(Timestamp timestamp) { commandRunner.execute( new ToggleRepetitionCommand(habitList, habit, timestamp), null); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java index ff79c6578..1f9500123 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java @@ -46,7 +46,7 @@ public class WidgetBehavior this.notificationTray = notificationTray; } - public void onAddRepetition(@NonNull Habit habit, long timestamp) + public void onAddRepetition(@NonNull Habit habit, Timestamp timestamp) { Repetition rep = habit.getRepetitions().getByTimestamp(timestamp); if (rep != null) return; @@ -54,19 +54,19 @@ public class WidgetBehavior notificationTray.cancel(habit); } - public void onRemoveRepetition(@NonNull Habit habit, long timestamp) + public void onRemoveRepetition(@NonNull Habit habit, Timestamp timestamp) { Repetition rep = habit.getRepetitions().getByTimestamp(timestamp); if (rep == null) return; performToggle(habit, timestamp); } - public void onToggleRepetition(@NonNull Habit habit, long timestamp) + public void onToggleRepetition(@NonNull Habit habit, Timestamp timestamp) { performToggle(habit, timestamp); } - private void performToggle(@NonNull Habit habit, long timestamp) + private void performToggle(@NonNull Habit habit, Timestamp timestamp) { commandRunner.execute( new ToggleRepetitionCommand(habitList, habit, timestamp), diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/utils/DateUtils.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/utils/DateUtils.java index 59dc12f19..4ab22f85c 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/utils/DateUtils.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/utils/DateUtils.java @@ -19,6 +19,10 @@ package org.isoron.uhabits.core.utils; +import android.support.annotation.*; + +import org.isoron.uhabits.core.models.*; + import java.util.*; import static java.util.Calendar.*; @@ -32,7 +36,7 @@ public abstract class DateUtils /** * Number of milliseconds in one day. */ - public static long millisecondsInOneDay = 24 * 60 * 60 * 1000; + public static long DAY_LENGTH = 24 * 60 * 60 * 1000; public static long applyTimezone(long localTimestamp) { @@ -49,7 +53,7 @@ public abstract class DateUtils return dayOfWeek + "\n" + dayOfMonth; } - public static GregorianCalendar getCalendar(long timestamp) + private static GregorianCalendar getCalendar(long timestamp) { GregorianCalendar day = new GregorianCalendar(TimeZone.getTimeZone("GMT")); @@ -57,7 +61,7 @@ public abstract class DateUtils return day; } - public static String[] getDayNames(int format) + private static String[] getDayNames(int format) { String[] wdays = new String[7]; @@ -130,9 +134,15 @@ public abstract class DateUtils return getDayNames(SHORT); } + @NonNull + public static Timestamp getToday() + { + return new Timestamp(getStartOfToday()); + } + public static long getStartOfDay(long timestamp) { - return (timestamp / millisecondsInOneDay) * millisecondsInOneDay; + return (timestamp / DAY_LENGTH) * DAY_LENGTH; } public static long getStartOfToday() @@ -142,7 +152,7 @@ public abstract class DateUtils public static long millisecondsUntilTomorrow() { - return getStartOfToday() + millisecondsInOneDay - getLocalTime(); + return getStartOfToday() + DAY_LENGTH - getLocalTime(); } public static GregorianCalendar getStartOfTodayCalendar() @@ -150,7 +160,7 @@ public abstract class DateUtils return getCalendar(getStartOfToday()); } - public static TimeZone getTimezone() + private static TimeZone getTimezone() { if(fixedTimeZone != null) return fixedTimeZone; return TimeZone.getDefault(); @@ -161,25 +171,6 @@ public abstract class DateUtils fixedTimeZone = tz; } - public static int getWeekday(long timestamp) - { - GregorianCalendar day = getCalendar(timestamp); - return javaWeekdayToLoopWeekday(day.get(DAY_OF_WEEK)); - } - - /** - * Throughout the code, it is assumed that the weekdays are numbered from 0 - * (Saturday) to 6 (Friday). In the Java Calendar they are numbered from 1 - * (Sunday) to 7 (Saturday). This function converts from Java to our - * internal representation. - * - * @return weekday number in the internal interpretation - */ - public static int javaWeekdayToLoopWeekday(int number) - { - return number % 7; - } - public static long removeTimezone(long timestamp) { TimeZone tz = getTimezone(); @@ -230,18 +221,4 @@ public abstract class DateUtils { MONTH, WEEK_NUMBER, YEAR, QUARTER } - - /** - * Gets the number of days between two timestamps (exclusively). - * - * @param t1 the first timestamp to use in milliseconds - * @param t2 the second timestamp to use in milliseconds - * @return the number of days between the two timestamps - */ - public static int getDaysBetween(long t1, long t2) - { - Date d1 = new Date(t1); - Date d2 = new Date(t2); - return (int) (Math.abs((d2.getTime() - d1.getTime()) / millisecondsInOneDay)); - } } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/utils/MidnightTimer.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/utils/MidnightTimer.java index 1ddacdade..8d3a89480 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/utils/MidnightTimer.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/utils/MidnightTimer.java @@ -57,7 +57,7 @@ public class MidnightTimer executor = Executors.newSingleThreadScheduledExecutor(); executor.scheduleAtFixedRate(() -> notifyListeners(), DateUtils.millisecondsUntilTomorrow() + 1000, - DateUtils.millisecondsInOneDay, TimeUnit.MILLISECONDS); + DateUtils.DAY_LENGTH, TimeUnit.MILLISECONDS); } public synchronized void removeListener(MidnightListener listener) diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CommandParserTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CommandParserTest.java index 376804068..37fab9c3d 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CommandParserTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CommandParserTest.java @@ -96,7 +96,7 @@ public class CommandParserTest extends BaseUnitTest public void testDecodeCreateRepCommand() throws JSONException { CreateRepetitionCommand original, decoded; - original = new CreateRepetitionCommand(habit, 1000, 5); + original = new CreateRepetitionCommand(habit, Timestamp.ZERO.plus(100), 5); decoded = (CreateRepetitionCommand) parser.parse(original.toJson()); MatcherAssert.assertThat(decoded.getId(), equalTo(original.getId())); @@ -140,7 +140,8 @@ public class CommandParserTest extends BaseUnitTest public void testDecodeToggleCommand() throws JSONException { ToggleRepetitionCommand original, decoded; - original = new ToggleRepetitionCommand(habitList, habit, 1000); + original = new ToggleRepetitionCommand(habitList, habit, + Timestamp.ZERO.plus(100)); decoded = (ToggleRepetitionCommand) parser.parse(original.toJson()); MatcherAssert.assertThat(decoded.getId(), equalTo(original.getId())); diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.java index 62dd89fce..5d44ba1ec 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.java @@ -35,7 +35,7 @@ public class CreateRepetitionCommandTest extends BaseUnitTest private Habit habit; - private long today; + private Timestamp today; @Override @Before @@ -46,7 +46,7 @@ public class CreateRepetitionCommandTest extends BaseUnitTest habit = fixtures.createShortHabit(); habitList.add(habit); - today = DateUtils.getStartOfToday(); + today = DateUtils.getToday(); command = new CreateRepetitionCommand(habit, today, 100); } diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommandTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommandTest.java index 6fdc0e571..8c698a2d2 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommandTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/commands/ToggleRepetitionCommandTest.java @@ -33,7 +33,7 @@ public class ToggleRepetitionCommandTest extends BaseUnitTest private ToggleRepetitionCommand command; private Habit habit; - private long today; + private Timestamp today; @Override @Before @@ -44,7 +44,7 @@ public class ToggleRepetitionCommandTest extends BaseUnitTest habit = fixtures.createShortHabit(); habitList.add(habit); - today = DateUtils.getStartOfToday(); + today = DateUtils.getToday(); command = new ToggleRepetitionCommand(habitList, habit, today); } diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/io/ImportTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/io/ImportTest.java index ae414d812..73671d7e7 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/io/ImportTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/io/ImportTest.java @@ -121,7 +121,7 @@ public class ImportTest extends BaseUnitTest { GregorianCalendar date = DateUtils.getStartOfTodayCalendar(); date.set(year, month - 1, day); - return h.getRepetitions().containsTimestamp(date.getTimeInMillis()); + return h.getRepetitions().containsTimestamp(new Timestamp(date)); } private void importFromFile(String assetFilename) throws IOException diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/CheckmarkListTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/CheckmarkListTest.java index c05bb2005..b3b55034f 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/CheckmarkListTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/CheckmarkListTest.java @@ -28,9 +28,7 @@ import java.util.*; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.core.IsEqual.*; -import static org.isoron.uhabits.core.models.Checkmark.CHECKED_EXPLICITLY; -import static org.isoron.uhabits.core.models.Checkmark.CHECKED_IMPLICITLY; -import static org.isoron.uhabits.core.models.Checkmark.UNCHECKED; +import static org.isoron.uhabits.core.models.Checkmark.*; public class CheckmarkListTest extends BaseUnitTest { @@ -49,9 +47,6 @@ public class CheckmarkListTest extends BaseUnitTest { super.setUp(); - dayLength = DateUtils.millisecondsInOneDay; - today = DateUtils.getStartOfToday(); - nonDailyHabit = fixtures.createShortHabit(); habitList.add(nonDailyHabit); @@ -281,7 +276,9 @@ public class CheckmarkListTest extends BaseUnitTest @Test public void test_getValues_withInvalidInterval() { - int values[] = nonDailyHabit.getCheckmarks().getValues(100L, -100L); + int values[] = nonDailyHabit + .getCheckmarks() + .getValues(new Timestamp(0L).plus(100), new Timestamp(0L)); assertThat(values, equalTo(new int[0])); } @@ -305,7 +302,9 @@ public class CheckmarkListTest extends BaseUnitTest UNCHECKED }; - int[] actualValues = nonDailyHabit.getCheckmarks().getValues(from, to); + int[] actualValues = nonDailyHabit + .getCheckmarks() + .getValues(new Timestamp(from), new Timestamp(to)); assertThat(actualValues, equalTo(expectedValues)); } @@ -344,15 +343,14 @@ public class CheckmarkListTest extends BaseUnitTest assertThat(writer.toString(), equalTo(expectedCSV)); } - private long day(int offset) + private Timestamp day(int offset) { - return DateUtils.getStartOfToday() - - offset * DateUtils.millisecondsInOneDay; + return DateUtils.getToday().minus(offset); } private void travelInTime(int days) { DateUtils.setFixedLocalTime( - FIXED_LOCAL_TIME + days * DateUtils.millisecondsInOneDay); + FIXED_LOCAL_TIME + days * Timestamp.DAY_LENGTH); } } diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitTest.java index aca472851..40dfa03e9 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitTest.java @@ -87,7 +87,7 @@ public class HabitTest extends BaseUnitTest { Habit h = modelFactory.buildHabit(); assertFalse(h.isCompletedToday()); - h.getRepetitions().toggle(getStartOfToday()); + h.getRepetitions().toggle(getToday()); assertTrue(h.isCompletedToday()); } @@ -100,19 +100,19 @@ public class HabitTest extends BaseUnitTest h.setTargetValue(100.0); assertFalse(h.isCompletedToday()); - h.getRepetitions().toggle(getStartOfToday(), 200); + h.getRepetitions().toggle(getToday(), 200); assertTrue(h.isCompletedToday()); - h.getRepetitions().toggle(getStartOfToday(), 100); + h.getRepetitions().toggle(getToday(), 100); assertTrue(h.isCompletedToday()); - h.getRepetitions().toggle(getStartOfToday(), 50); + h.getRepetitions().toggle(getToday(), 50); assertFalse(h.isCompletedToday()); h.setTargetType(Habit.AT_MOST); - h.getRepetitions().toggle(getStartOfToday(), 200); + h.getRepetitions().toggle(getToday(), 200); assertFalse(h.isCompletedToday()); - h.getRepetitions().toggle(getStartOfToday(), 100); + h.getRepetitions().toggle(getToday(), 100); assertTrue(h.isCompletedToday()); - h.getRepetitions().toggle(getStartOfToday(), 50); + h.getRepetitions().toggle(getToday(), 50); assertTrue(h.isCompletedToday()); } diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/RepetitionListTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/RepetitionListTest.java index 326a4047a..4259bcab1 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/RepetitionListTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/RepetitionListTest.java @@ -29,7 +29,6 @@ import java.util.*; import static junit.framework.TestCase.assertFalse; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.Is.*; import static org.hamcrest.core.IsEqual.*; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -43,7 +42,7 @@ public class RepetitionListTest extends BaseUnitTest @NonNull private Habit habit; - private long today; + private Timestamp today; private long day; @@ -58,14 +57,13 @@ public class RepetitionListTest extends BaseUnitTest habit = fixtures.createEmptyHabit(); reps = habit.getRepetitions(); - today = DateUtils.getStartOfToday(); - day = DateUtils.millisecondsInOneDay; + today = DateUtils.getToday(); - reps.toggle(today - 3 * day); - reps.toggle(today - 2 * day); + reps.toggle(today.minus(3)); + reps.toggle(today.minus(2)); reps.toggle(today); - reps.toggle(today - 7 * day); - reps.toggle(today - 5 * day); + reps.toggle(today.minus(7)); + reps.toggle(today.minus(5)); listener = mock(ModelObservable.Listener.class); reps.getObservable().addListener(listener); @@ -82,19 +80,19 @@ public class RepetitionListTest extends BaseUnitTest @Test public void test_contains() { - assertThat(reps.containsTimestamp(today), is(true)); - assertThat(reps.containsTimestamp(today - 2 * day), is(true)); - assertThat(reps.containsTimestamp(today - 3 * day), is(true)); + assertTrue(reps.containsTimestamp(today)); + assertTrue(reps.containsTimestamp(today.minus(2))); + assertTrue(reps.containsTimestamp(today.minus(3))); - assertThat(reps.containsTimestamp(today - day), is(false)); - assertThat(reps.containsTimestamp(today - 4 * day), is(false)); + assertFalse(reps.containsTimestamp(today.minus(1))); + assertFalse(reps.containsTimestamp(today.minus(4))); } @Test public void test_getOldest() { Repetition rep = reps.getOldest(); - assertThat(rep.getTimestamp(), is(equalTo(today - 7 * day))); + assertThat(rep.getTimestamp(), equalTo(today.minus(7))); } @Test @@ -134,28 +132,28 @@ public class RepetitionListTest extends BaseUnitTest weekdayCount[month][week]++; monthCount[month]++; } - reps.toggle(day.getTimeInMillis()); + reps.toggle(new Timestamp(day)); } } day.add(Calendar.DAY_OF_YEAR, 1); } - HashMap freq = + HashMap freq = reps.getWeekdayFrequency(); // Repetitions until November should be counted correctly for (int month = 0; month < 11; month++) { day.set(2015, month, 1); - Integer actualCount[] = freq.get(day.getTimeInMillis()); + Integer actualCount[] = freq.get(new Timestamp(day)); if (monthCount[month] == 0) assertThat(actualCount, equalTo(null)); else assertThat(actualCount, equalTo(weekdayCount[month])); } // Repetitions in December should be discarded day.set(2015, 11, 1); - assertThat(freq.get(day.getTimeInMillis()), equalTo(null)); + assertThat(freq.get(new Timestamp(day)), equalTo(null)); } @Test @@ -167,9 +165,9 @@ public class RepetitionListTest extends BaseUnitTest verify(listener).onModelChange(); reset(listener); - assertFalse(reps.containsTimestamp(today - day)); - reps.toggle(today - day); - assertTrue(reps.containsTimestamp(today - day)); + assertFalse(reps.containsTimestamp(today.minus(1))); + reps.toggle(today.minus(1)); + assertTrue(reps.containsTimestamp(today.minus(1))); verify(listener).onModelChange(); reset(listener); diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/ScoreListTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/ScoreListTest.java index efc96e600..54b63f5d6 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/ScoreListTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/ScoreListTest.java @@ -117,11 +117,11 @@ public class ScoreListTest extends BaseUnitTest }; ScoreList scores = habit.getScores(); - long current = DateUtils.getStartOfToday(); + Timestamp current = DateUtils.getToday(); for (double expectedValue : expectedValues) { assertThat(scores.getValue(current), closeTo(expectedValue, E)); - current -= DateUtils.millisecondsInOneDay; + current = current.minus(1); } } @@ -130,11 +130,9 @@ public class ScoreListTest extends BaseUnitTest { toggleRepetitions(0, 20); - long today = DateUtils.getStartOfToday(); - long day = DateUtils.millisecondsInOneDay; - - long from = today - 4 * day; - long to = today - 2 * day; + Timestamp today = DateUtils.getToday(); + Timestamp from = today.minus(4); + Timestamp to = today.minus(2); double[] expected = { 0.617008, 0.596033, 0.573909, @@ -169,7 +167,7 @@ public class ScoreListTest extends BaseUnitTest assertThat(habit.getScores().getTodayValue(), closeTo(0.101149, E)); habit.setFrequency(new Frequency(1, 2)); - habit.getScores().invalidateNewerThan(0); + habit.getScores().invalidateNewerThan(new Timestamp(0)); assertThat(habit.getScores().getTodayValue(), closeTo(0.051922, E)); } @@ -194,10 +192,9 @@ public class ScoreListTest extends BaseUnitTest private void toggleRepetitions(final int from, final int to) { RepetitionList reps = habit.getRepetitions(); - long today = DateUtils.getStartOfToday(); - long day = DateUtils.millisecondsInOneDay; + Timestamp today = DateUtils.getToday(); for (int i = from; i < to; i++) - reps.toggle(today - i * day); + reps.toggle(today.minus(i)); } } diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/StreakListTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/StreakListTest.java index 77db730c4..e01a38b34 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/StreakListTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/StreakListTest.java @@ -38,7 +38,7 @@ public class StreakListTest extends BaseUnitTest private long day; - private long today; + private Timestamp today; private ModelObservable.Listener listener; @@ -54,25 +54,23 @@ public class StreakListTest extends BaseUnitTest listener = mock(ModelObservable.Listener.class); streaks.getObservable().addListener(listener); - - today = DateUtils.getStartOfToday(); - day = DateUtils.millisecondsInOneDay; + today = DateUtils.getToday(); } @Test public void testFindBeginning_withEmptyHistory() { Habit habit2 = fixtures.createEmptyHabit(); - Long beginning = habit2.getStreaks().findBeginning(); - assertThat(beginning, is(nullValue())); + Timestamp beginning = habit2.getStreaks().findBeginning(); + assertNull(beginning); } @Test public void testFindBeginning_withLongHistory() { streaks.rebuild(); - streaks.invalidateNewerThan(0); - assertThat(streaks.findBeginning(), equalTo(today - 120 * day)); + streaks.invalidateNewerThan(new Timestamp(0)); + assertThat(streaks.findBeginning(), equalTo(today.minus(120))); } @Test @@ -82,11 +80,11 @@ public class StreakListTest extends BaseUnitTest assertThat(all.size(), equalTo(22)); - assertThat(all.get(3).getEnd(), equalTo(today - 7 * day)); - assertThat(all.get(3).getStart(), equalTo(today - 10 * day)); + assertThat(all.get(3).getEnd(), equalTo(today.minus(7))); + assertThat(all.get(3).getStart(), equalTo(today.minus(10))); - assertThat(all.get(17).getEnd(), equalTo(today - 89 * day)); - assertThat(all.get(17).getStart(), equalTo(today - 91 * day)); + assertThat(all.get(17).getEnd(), equalTo(today.minus(89))); + assertThat(all.get(17).getStart(), equalTo(today.minus(91))); } @Test @@ -95,16 +93,16 @@ public class StreakListTest extends BaseUnitTest List best = streaks.getBest(4); assertThat(best.size(), equalTo(4)); - assertThat(best.get(0).getLength(), equalTo(4L)); - assertThat(best.get(1).getLength(), equalTo(3L)); - assertThat(best.get(2).getLength(), equalTo(5L)); - assertThat(best.get(3).getLength(), equalTo(6L)); + assertThat(best.get(0).getLength(), equalTo(4)); + assertThat(best.get(1).getLength(), equalTo(3)); + assertThat(best.get(2).getLength(), equalTo(5)); + assertThat(best.get(3).getLength(), equalTo(6)); best = streaks.getBest(2); assertThat(best.size(), equalTo(2)); - assertThat(best.get(0).getLength(), equalTo(5L)); - assertThat(best.get(1).getLength(), equalTo(6L)); + assertThat(best.get(0).getLength(), equalTo(5)); + assertThat(best.get(1).getLength(), equalTo(6)); } @Test @@ -113,7 +111,7 @@ public class StreakListTest extends BaseUnitTest Streak s = streaks.getNewestComputed(); assertThat(s.getEnd(), equalTo(today)); - streaks.invalidateNewerThan(today - 8 * day); + streaks.invalidateNewerThan(today.minus(8)); verify(listener).onModelChange(); s = streaks.getNewestComputed(); diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/TimestampTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/TimestampTest.java new file mode 100644 index 000000000..55155a8a4 --- /dev/null +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/TimestampTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015-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.models; + +import org.isoron.uhabits.core.*; +import org.isoron.uhabits.core.utils.*; +import org.junit.*; + +import static junit.framework.TestCase.assertFalse; +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertTrue; + +public class TimestampTest extends BaseUnitTest +{ + @Test + public void testCompare() throws Exception + { + Timestamp t1 = DateUtils.getToday(); + Timestamp t2 = t1.minus(1); + Timestamp t3 = t1.plus(3); + + assertThat(t1.compare(t2), greaterThan(0)); + assertThat(t1.compare(t1), equalTo(0)); + assertThat(t1.compare(t3), lessThan(0)); + + assertTrue(t1.isNewerThan(t2)); + assertFalse(t1.isNewerThan(t1)); + assertFalse(t2.isNewerThan(t1)); + + assertTrue(t2.isOlderThan(t1)); + assertFalse(t1.isOlderThan(t2)); + } + + @Test + public void testDaysUntil() throws Exception + { + Timestamp t = DateUtils.getToday(); + assertThat(t.daysUntil(t), equalTo(0)); + + assertThat(t.daysUntil(t.plus(1)), equalTo(1)); + assertThat(t.daysUntil(t.plus(3)), equalTo(3)); + assertThat(t.daysUntil(t.plus(300)), equalTo(300)); + + assertThat(t.daysUntil(t.minus(1)), equalTo(-1)); + assertThat(t.daysUntil(t.minus(3)), equalTo(-3)); + assertThat(t.daysUntil(t.minus(300)), equalTo(-300)); + } + + +} diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/SQLiteRepetitionListTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/SQLiteRepetitionListTest.java index f26d06a62..734002868 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/SQLiteRepetitionListTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/SQLiteRepetitionListTest.java @@ -31,17 +31,16 @@ import org.junit.*; import java.util.*; -import static junit.framework.TestCase.assertNotNull; -import static junit.framework.TestCase.assertNull; +import static junit.framework.TestCase.*; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.core.IsEqual.*; -import static org.isoron.uhabits.core.models.Checkmark.CHECKED_EXPLICITLY; +import static org.isoron.uhabits.core.models.Checkmark.*; public class SQLiteRepetitionListTest extends BaseUnitTest { private Habit habit; - private long today; + private Timestamp today; private RepetitionList repetitions; @@ -62,20 +61,19 @@ public class SQLiteRepetitionListTest extends BaseUnitTest habit = fixtures.createLongHabit(); repetitions = habit.getRepetitions(); - today = DateUtils.getStartOfToday(); - day = DateUtils.millisecondsInOneDay; + today = DateUtils.getToday(); } @Test public void testAdd() { - RepetitionRecord record = getByTimestamp(today + day); + RepetitionRecord record = getByTimestamp(today.plus(1)); assertNull(record); - Repetition rep = new Repetition(today + day, CHECKED_EXPLICITLY); + Repetition rep = new Repetition(today.plus(1), CHECKED_EXPLICITLY); habit.getRepetitions().add(rep); - record = getByTimestamp(today + day); + record = getByTimestamp(today.plus(1)); assertNotNull(record); assertThat(record.value, equalTo(CHECKED_EXPLICITLY)); } @@ -84,12 +82,12 @@ public class SQLiteRepetitionListTest extends BaseUnitTest public void testGetByInterval() { List reps = - repetitions.getByInterval(today - 10 * day, today); + repetitions.getByInterval(today.minus(10), today); assertThat(reps.size(), equalTo(8)); - assertThat(reps.get(0).getTimestamp(), equalTo(today - 10 * day)); - assertThat(reps.get(4).getTimestamp(), equalTo(today - 5 * day)); - assertThat(reps.get(5).getTimestamp(), equalTo(today - 3 * day)); + assertThat(reps.get(0).getTimestamp(), equalTo(today.minus(10))); + assertThat(reps.get(4).getTimestamp(), equalTo(today.minus(5))); + assertThat(reps.get(5).getTimestamp(), equalTo(today.minus(3))); } @Test @@ -99,7 +97,7 @@ public class SQLiteRepetitionListTest extends BaseUnitTest assertNotNull(rep); assertThat(rep.getTimestamp(), equalTo(today)); - rep = repetitions.getByTimestamp(today - 2 * day); + rep = repetitions.getByTimestamp(today.minus(2)); assertNull(rep); } @@ -108,7 +106,7 @@ public class SQLiteRepetitionListTest extends BaseUnitTest { Repetition rep = repetitions.getOldest(); assertNotNull(rep); - assertThat(rep.getTimestamp(), equalTo(today - 120 * day)); + assertThat(rep.getTimestamp(), equalTo(today.minus(120))); } @Test @@ -133,11 +131,11 @@ public class SQLiteRepetitionListTest extends BaseUnitTest } @Nullable - private RepetitionRecord getByTimestamp(long timestamp) + private RepetitionRecord getByTimestamp(Timestamp timestamp) { String query = "where habit = ? and timestamp = ?"; String params[] = { - Long.toString(habit.getId()), Long.toString(timestamp) + Long.toString(habit.getId()), Long.toString(timestamp.getUnixTime()) }; return repository.findFirst(query, params); diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/records/RepetitionRecordTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/records/RepetitionRecordTest.java index ec2d0eba0..1ac7851e1 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/records/RepetitionRecordTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/records/RepetitionRecordTest.java @@ -33,7 +33,7 @@ public class RepetitionRecordTest extends BaseUnitTest @Test public void testRecord() throws Exception { - Repetition rep = new Repetition(2000L, 50); + Repetition rep = new Repetition(Timestamp.ZERO.plus(100), 50); RepetitionRecord record = new RepetitionRecord(); record.copyFrom(rep); assertThat(rep, equalTo(record.toRepetition())); diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java index 9c28255ce..29fc565c8 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java @@ -85,7 +85,7 @@ public class HabitCardListCacheTest extends BaseUnitTest public void testCommandListener_single() { Habit h2 = habitList.getByPosition(2); - long today = DateUtils.getStartOfToday(); + Timestamp today = DateUtils.getToday(); commandRunner.execute(new ToggleRepetitionCommand(habitList, h2, today), h2.getId()); @@ -106,12 +106,10 @@ public class HabitCardListCacheTest extends BaseUnitTest assertThat(cache.getHabitByPosition(3), equalTo(h)); assertThat(cache.getScore(h.getId()), equalTo(score)); - long today = DateUtils.getStartOfToday(); - long day = DateUtils.millisecondsInOneDay; - + Timestamp today = DateUtils.getToday(); int[] actualCheckmarks = cache.getCheckmarks(h.getId()); int[] expectedCheckmarks = - h.getCheckmarks().getValues(today - 9 * day, today); + h.getCheckmarks().getValues(today.minus(9), today); assertThat(actualCheckmarks, equalTo(expectedCheckmarks)); } diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.java index e9e72e6d2..5bedaeb5c 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.java @@ -20,6 +20,7 @@ package org.isoron.uhabits.core.ui.screens.habits.list; import org.isoron.uhabits.core.*; +import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.preferences.*; import org.isoron.uhabits.core.utils.*; import org.junit.*; @@ -41,16 +42,16 @@ public class HintListTest extends BaseUnitTest @Mock private Preferences prefs; - private long today; + private Timestamp today; - private long yesterday; + private Timestamp yesterday; @Override public void setUp() throws Exception { super.setUp(); - today = DateUtils.getStartOfToday(); - yesterday = today - DateUtils.millisecondsInOneDay; + today = DateUtils.getToday(); + yesterday = today.minus(1); hints = new String[]{ "hint1", "hint2", "hint3" }; hintList = new HintList(prefs, hints); diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java index 3a727db42..93d93b861 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java @@ -83,7 +83,7 @@ public class ListHabitsBehaviorTest extends BaseUnitTest @Test public void testOnEdit() { - behavior.onEdit(habit2, DateUtils.getStartOfToday()); + behavior.onEdit(habit2, DateUtils.getToday()); verify(screen).showNumberPicker(eq(0.1), eq("miles"), picker.capture()); picker.getValue().onNumberPicked(100); assertThat(habit2.getCheckmarks().getTodayValue(), equalTo(100000)); @@ -173,7 +173,7 @@ public class ListHabitsBehaviorTest extends BaseUnitTest public void testOnToggle() { assertTrue(habit1.isCompletedToday()); - behavior.onToggle(habit1, DateUtils.getStartOfToday()); + behavior.onToggle(habit1, DateUtils.getToday()); assertFalse(habit1.isCompletedToday()); } diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/utils/DateUtilsTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/utils/DateUtilsTest.java index 989d5c3d8..11590260c 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/utils/DateUtilsTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/utils/DateUtilsTest.java @@ -134,17 +134,4 @@ public class DateUtilsTest extends BaseUnitTest assertThat(DateUtils.truncate(field, t1), equalTo(expected)); assertThat(DateUtils.truncate(field, t2), equalTo(expected)); } - - @Test - public void test_getDaysBetween() - { - long t1 = timestamp(2016, JANUARY, 1); - long t2 = timestamp(2016, JANUARY, 10); - long t3 = timestamp(2016, DECEMBER, 31); - - assertThat(DateUtils.getDaysBetween(t1, t1), equalTo(0)); - assertThat(DateUtils.getDaysBetween(t1, t2), equalTo(9)); - assertThat(DateUtils.getDaysBetween(t1, t3), equalTo(365)); - assertThat(DateUtils.getDaysBetween(t3, t1), equalTo(365)); - } }