Implement numerical habits with AT_MOST target type

This commit is contained in:
KristianTashkov
2021-09-11 23:23:52 +03:00
parent fc1478645b
commit 804edfa64e
11 changed files with 155 additions and 34 deletions

View File

@@ -59,9 +59,10 @@ data class Habit(
val today = DateUtils.getTodayWithOffset()
val value = computedEntries.get(today).value
return if (isNumerical) {
val targetValuePerDay = (targetValue / frequency.denominator)
when (targetType) {
NumericalHabitType.AT_LEAST -> value / 1000.0 >= targetValue
NumericalHabitType.AT_MOST -> value / 1000.0 <= targetValue
NumericalHabitType.AT_LEAST -> value / 1000.0 >= targetValuePerDay
NumericalHabitType.AT_MOST -> value / 1000.0 <= targetValuePerDay
}
} else {
value != Entry.NO && value != Entry.UNKNOWN
@@ -72,9 +73,10 @@ data class Habit(
val today = DateUtils.getTodayWithOffset()
val value = computedEntries.get(today).value
return if (isNumerical) {
val targetValuePerDay = (targetValue / frequency.denominator)
when (targetType) {
NumericalHabitType.AT_LEAST -> value / 1000.0 < targetValue
NumericalHabitType.AT_MOST -> value / 1000.0 > targetValue
NumericalHabitType.AT_LEAST -> value / 1000.0 < targetValuePerDay
NumericalHabitType.AT_MOST -> value / 1000.0 > targetValuePerDay
}
} else {
value == Entry.NO
@@ -96,6 +98,7 @@ data class Habit(
scores.recompute(
frequency = frequency,
isNumerical = isNumerical,
numericalHabitType = targetType,
targetValue = targetValue,
computedEntries = computedEntries,
from = from,

View File

@@ -68,6 +68,7 @@ class ScoreList {
fun recompute(
frequency: Frequency,
isNumerical: Boolean,
numericalHabitType: NumericalHabitType,
targetValue: Double,
computedEntries: EntryList,
from: Timestamp,
@@ -91,18 +92,37 @@ class ScoreList {
}
var previousValue = 0.0
val numericalUnknownDayValue = (targetValue * 2 * 1000) / denominator
for (i in values.indices) {
val offset = values.size - i - 1
if (isNumerical) {
rollingSum += max(0, values[offset])
if (values[offset] >= 0)
rollingSum += values[offset]
else if (numericalHabitType == NumericalHabitType.AT_MOST)
rollingSum += numericalUnknownDayValue
if (offset + denominator < values.size) {
rollingSum -= values[offset + denominator]
if (values[offset + denominator] >= 0) {
rollingSum -= values[offset + denominator]
} else if (numericalHabitType == NumericalHabitType.AT_MOST) {
rollingSum -= numericalUnknownDayValue
}
}
val percentageCompleted = if (targetValue > 0) {
min(1.0, rollingSum / 1000 / targetValue)
} else {
1.0
var percentageCompleted = 0.0
val normalizedRollingSum = rollingSum / 1000
if (numericalHabitType == NumericalHabitType.AT_LEAST) {
percentageCompleted = if (targetValue > 0)
min(1.0, normalizedRollingSum / targetValue)
else
1.0
} else if (numericalHabitType == NumericalHabitType.AT_MOST) {
percentageCompleted = if (targetValue > 0 && normalizedRollingSum > targetValue)
max(
0.0, 1 - ((normalizedRollingSum - targetValue) / targetValue)
)
else if (normalizedRollingSum <= targetValue) 1.0 else 0.0
}
previousValue = compute(freq, previousValue, percentageCompleted)
} else {
if (values[offset] == Entry.YES_MANUAL) {

View File

@@ -29,6 +29,7 @@ import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.NumericalHabitType
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.preferences.Preferences
@@ -105,12 +106,21 @@ class HistoryCardPresenter(
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
val entries = habit.computedEntries.getByInterval(oldest, today)
val series = if (habit.isNumerical) {
entries.map {
Entry(it.timestamp, max(0, it.value))
}.map {
when (it.value) {
0 -> HistoryChart.Square.OFF
else -> HistoryChart.Square.ON
if (habit.targetType == NumericalHabitType.AT_LEAST) {
entries.map {
when (max(0, it.value)) {
0 -> HistoryChart.Square.OFF
else -> HistoryChart.Square.ON
}
}
} else {
entries.map {
if (it.value < 0) habit.targetValue * 2.0 * 1000.0 else it.value / 1000.0
}.map {
when {
it <= habit.targetValue -> HistoryChart.Square.ON
else -> HistoryChart.Square.OFF
}
}
}
} else {

View File

@@ -128,6 +128,10 @@ class ScoreListTest : BaseUnitTest() {
habit.targetValue = 0.0
habit.recompute()
assertTrue(habit.scores[today].value.isFinite())
habit.targetType = NumericalHabitType.AT_MOST
habit.recompute()
assertTrue(habit.scores[today].value.isFinite())
}
@Test