diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Frequency.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Frequency.kt index 64ee3287f..6e659c7ad 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Frequency.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Frequency.kt @@ -45,5 +45,8 @@ data class Frequency( @JvmField val WEEKLY = Frequency(1, 7) + + @JvmField + val MONTHLY = Frequency(1, 30) } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt index 68bbabc08..91f409a43 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt @@ -57,14 +57,27 @@ data class Habit( fun isCompletedToday(): Boolean { val today = DateUtils.getTodayWithOffset() - val value = computedEntries.get(today).value return if (isNumerical) { + val firstDayToConsider = fetchFirstDayToConsider() + val value = computedEntries.getByInterval(firstDayToConsider, today) + .filter { it.value > -1 } + .sumOf { it.value } when (targetType) { NumericalHabitType.AT_LEAST -> value / 1000.0 >= targetValue NumericalHabitType.AT_MOST -> value / 1000.0 <= targetValue } } else { - value != Entry.NO && value != Entry.UNKNOWN + val todayValue = computedEntries.get(today).value + todayValue != Entry.NO && todayValue != Entry.UNKNOWN + } + } + + private fun fetchFirstDayToConsider(): Timestamp { + return when(frequency) { + Frequency.DAILY -> DateUtils.getTodayWithOffset() + Frequency.WEEKLY -> DateUtils.getFirstDayOfCurrentWeekWithOffset() + Frequency.MONTHLY -> DateUtils.getFirstDayOfCurrentMonthWithOffset() + else -> throw NotImplementedError() } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateUtils.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateUtils.kt index 7c2c0a4fd..c18b7aedd 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateUtils.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateUtils.kt @@ -22,7 +22,12 @@ import org.isoron.uhabits.core.models.Timestamp import java.util.Calendar import java.util.Calendar.DAY_OF_MONTH import java.util.Calendar.DAY_OF_WEEK +import java.util.Calendar.HOUR_OF_DAY +import java.util.Calendar.MILLISECOND +import java.util.Calendar.MINUTE +import java.util.Calendar.SECOND import java.util.Calendar.SHORT +import java.util.Calendar.getInstance import java.util.Date import java.util.GregorianCalendar import java.util.Locale @@ -184,6 +189,12 @@ abstract class DateUtils { @JvmStatic fun getTodayWithOffset(): Timestamp = Timestamp(getStartOfTodayWithOffset()) + @JvmStatic + fun getFirstDayOfCurrentWeekWithOffset(): Timestamp = Timestamp(getStartOfFirstDayOfCurrentWeekWithOffset()) + + @JvmStatic + fun getFirstDayOfCurrentMonthWithOffset(): Timestamp = Timestamp(getStartOfFirstDayOfCurrentMonthWithOffset()) + @JvmStatic fun getStartOfDay(timestamp: Long): Long = (timestamp / DAY_LENGTH) * DAY_LENGTH @@ -205,6 +216,12 @@ abstract class DateUtils { @JvmStatic fun getStartOfTodayWithOffset(): Long = getStartOfDayWithOffset(getLocalTime()) + @JvmStatic + fun getStartOfFirstDayOfCurrentWeekWithOffset(): Long = getStartOfDayWithOffset(getFirstDayOfCurrentWeek()) + + @JvmStatic + fun getStartOfFirstDayOfCurrentMonthWithOffset(): Long = getStartOfDayWithOffset(getFirstDayOfCurrentMonth()) + @JvmStatic fun millisecondsUntilTomorrowWithOffset(): Long = getStartOfTomorrowWithOffset() - getLocalTime() @@ -214,6 +231,26 @@ abstract class DateUtils { @JvmStatic fun getStartOfTodayCalendarWithOffset(): GregorianCalendar = getCalendar(getStartOfTodayWithOffset()) + private fun getFirstDayOfCurrentWeek(): Long { + val cal = getInstance() + cal[HOUR_OF_DAY] = 0 + cal.clear(MINUTE) + cal.clear(SECOND) + cal.clear(MILLISECOND) + cal[DAY_OF_WEEK] = getFirstWeekdayNumberAccordingToLocale() + return getLocalTime(cal.timeInMillis) + } + + private fun getFirstDayOfCurrentMonth(): Long { + val cal = getInstance() + cal[HOUR_OF_DAY] = 0 + cal.clear(MINUTE) + cal.clear(SECOND) + cal.clear(MILLISECOND) + cal[DAY_OF_MONTH] = 1 + return getLocalTime(cal.timeInMillis) + } + private fun getTimeZone(): TimeZone { return fixedTimeZone ?: TimeZone.getDefault() }