diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt
index fcad26125..5edae637f 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt
@@ -62,6 +62,7 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener {
firstWeekday = preferences.firstWeekday,
paletteColor = habit.color,
series = emptyList(),
+ defaultSquare = HistoryChart.Square.OFF,
theme = themeSwitcher.currentTheme,
today = DateUtils.getTodayWithOffset().toLocalDate(),
onDateClickedListener = onDateClickedListener ?: OnDateClickedListener { },
@@ -101,6 +102,7 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener {
theme = LightTheme()
)
chart?.series = model.series
+ chart?.defaultSquare = model.defaultSquare
dataView.postInvalidate()
}
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt
index 1a02d8845..cd5dde85b 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt
@@ -35,11 +35,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import com.android.datetimepicker.time.RadialPickerLayout
import com.android.datetimepicker.time.TimePickerDialog
-import kotlinx.android.synthetic.main.activity_edit_habit.nameInput
-import kotlinx.android.synthetic.main.activity_edit_habit.notesInput
-import kotlinx.android.synthetic.main.activity_edit_habit.questionInput
-import kotlinx.android.synthetic.main.activity_edit_habit.targetInput
-import kotlinx.android.synthetic.main.activity_edit_habit.unitInput
+import kotlinx.android.synthetic.main.activity_edit_habit.*
import org.isoron.platform.gui.toInt
import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R
@@ -50,6 +46,7 @@ import org.isoron.uhabits.activities.common.dialogs.WeekdayPickerDialog
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.commands.CreateHabitCommand
import org.isoron.uhabits.core.commands.EditHabitCommand
+import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Frequency
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitType
@@ -116,6 +113,10 @@ class EditHabitActivity : AppCompatActivity() {
binding.questionInput.setText(habit.question)
binding.notesInput.setText(habit.description)
binding.unitInput.setText(habit.unit)
+ binding.defaultValueInput.setText((habit.defaultValue / 1000.0).toString())
+ binding.defaultNo.isChecked = habit.defaultValue == Entry.NO
+ binding.defaultYes.isChecked = habit.defaultValue == Entry.YES_MANUAL
+ binding.defaultSkip.isChecked = habit.defaultValue == Entry.SKIP
binding.targetInput.setText(habit.targetValue.toString())
} else {
habitType = HabitType.fromInt(intent.getIntExtra("habitType", HabitType.YES_NO.value))
@@ -138,11 +139,15 @@ class EditHabitActivity : AppCompatActivity() {
HabitType.YES_NO -> {
binding.unitOuterBox.visibility = View.GONE
binding.targetOuterBox.visibility = View.GONE
+ binding.numericalFrequencyOuterBox.visibility = View.GONE
+ if (!component.preferences.isSkipEnabled)
+ binding.defaultSkip.visibility = View.GONE
}
HabitType.NUMERICAL -> {
binding.nameInput.hint = getString(R.string.measurable_short_example)
binding.questionInput.hint = getString(R.string.measurable_question_example)
binding.frequencyOuterBox.visibility = View.GONE
+ binding.yesNoDefaultOuterBox.visibility = View.GONE
}
}
@@ -264,6 +269,15 @@ class EditHabitActivity : AppCompatActivity() {
habit.targetValue = targetInput.text.toString().toDouble()
habit.targetType = NumericalHabitType.AT_LEAST
habit.unit = unitInput.text.trim().toString()
+ habit.defaultValue = kotlin.math.floor(
+ defaultValueInput.text.toString().toDouble() * 1000.0
+ ).toInt()
+ } else {
+ habit.defaultValue = when {
+ defaultYes.isChecked -> Entry.YES_MANUAL
+ defaultSkip.isChecked -> Entry.SKIP
+ else -> Entry.NO
+ }
}
habit.type = habitType
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt
index 339cc46b4..75aa3fdde 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt
@@ -65,6 +65,12 @@ class CheckmarkButtonView(
invalidate()
}
+ var defaultValue: Int = 0
+ set(value) {
+ field = value
+ invalidate()
+ }
+
var value: Int = 0
set(value) {
field = value
@@ -128,7 +134,8 @@ class CheckmarkButtonView(
}
fun draw(canvas: Canvas) {
- paint.color = when (value) {
+ val realValue = if (value != UNKNOWN) value else defaultValue
+ paint.color = when (realValue) {
YES_MANUAL, YES_AUTO, SKIP -> color
NO -> {
if (preferences.areQuestionMarksEnabled) mediumContrastColor
@@ -136,15 +143,14 @@ class CheckmarkButtonView(
}
else -> lowContrastColor
}
- val id = when (value) {
+ var id = when (realValue) {
SKIP -> R.string.fa_skipped
NO -> R.string.fa_times
- UNKNOWN -> {
- if (preferences.areQuestionMarksEnabled) R.string.fa_question
- else R.string.fa_times
- }
else -> R.string.fa_check
}
+ if (value == UNKNOWN && preferences.areQuestionMarksEnabled)
+ id = R.string.fa_question
+
if (value == YES_AUTO) {
paint.strokeWidth = 5f
paint.style = Paint.Style.STROKE
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 136ea0050..0804a09c4 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
@@ -48,6 +48,12 @@ class CheckmarkPanelView(
setupButtons()
}
+ var defaultValue = 0
+ set(value) {
+ field = value
+ setupButtons()
+ }
+
var color = 0
set(value) {
field = value
@@ -72,6 +78,7 @@ class CheckmarkPanelView(
index + dataOffset < values.size -> values[index + dataOffset]
else -> UNKNOWN
}
+ button.defaultValue = defaultValue
button.color = color
button.onToggle = { value -> onToggle(timestamp, value) }
}
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 c59b61ec1..63ea6a5d2 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
@@ -228,6 +228,7 @@ class HabitCardView(
}
checkmarkPanel.apply {
color = c
+ defaultValue = h.defaultValue
visibility = when (h.isNumerical) {
true -> View.GONE
false -> View.VISIBLE
@@ -235,6 +236,7 @@ class HabitCardView(
}
numberPanel.apply {
color = c
+ defaultValue = h.defaultValue / 1000.0
units = h.unit
threshold = h.targetValue
visibility = when (h.isNumerical) {
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt
index 3e48ed1a6..08931affe 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt
@@ -76,6 +76,12 @@ class NumberButtonView(
invalidate()
}
+ var defaultValue = 0.0
+ set(value) {
+ field = value
+ invalidate()
+ }
+
var value = 0.0
set(value) {
field = value
@@ -153,9 +159,10 @@ class NumberButtonView(
}
fun draw(canvas: Canvas) {
+ val realValue = if (value >= 0) value else defaultValue
val activeColor = when {
- value <= 0.0 -> lowContrast
- value < threshold -> mediumContrast
+ realValue == 0.0 -> lowContrast
+ realValue < threshold -> mediumContrast
else -> color
}
@@ -175,7 +182,7 @@ class NumberButtonView(
textSize = dim(R.dimen.smallerTextSize)
}
else -> {
- label = "0"
+ label = defaultValue.toShortString()
typeface = BOLD_TYPEFACE
textSize = dim(R.dimen.smallTextSize)
}
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 491656a77..9b990b9a1 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
@@ -47,6 +47,12 @@ class NumberPanelView(
setupButtons()
}
+ var defaultValue = 0.0
+ set(value) {
+ field = value
+ setupButtons()
+ }
+
var threshold = 0.0
set(value) {
field = value
@@ -83,6 +89,7 @@ class NumberPanelView(
index + dataOffset < values.size -> values[index + dataOffset]
else -> 0.0
}
+ button.defaultValue = defaultValue
button.color = color
button.threshold = threshold
button.units = units
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt
index c60e84bd1..f429e1718 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt
@@ -43,6 +43,7 @@ class HistoryCardView(context: Context, attrs: AttributeSet) : LinearLayout(cont
theme = state.theme,
dateFormatter = JavaLocalDateFormatter(Locale.getDefault()),
series = state.series,
+ defaultSquare = state.defaultSquare,
firstWeekday = state.firstWeekday,
)
binding.chart.postInvalidate()
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt
index 2e26a487b..1467688f6 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt
@@ -56,7 +56,9 @@ class HistoryWidget(
theme = WidgetTheme(),
)
(widgetView.dataView as AndroidDataView).apply {
- (this.view as HistoryChart).series = model.series
+ val historyChart = (this.view as HistoryChart)
+ historyChart.series = model.series
+ historyChart.defaultSquare = model.defaultSquare
}
}
@@ -71,6 +73,7 @@ class HistoryWidget(
dateFormatter = JavaLocalDateFormatter(Locale.getDefault()),
firstWeekday = prefs.firstWeekday,
series = listOf(),
+ defaultSquare = HistoryChart.Square.OFF
)
}
).apply {
diff --git a/uhabits-android/src/main/res/layout/activity_edit_habit.xml b/uhabits-android/src/main/res/layout/activity_edit_habit.xml
index b3a33c373..a8e91e7f0 100644
--- a/uhabits-android/src/main/res/layout/activity_edit_habit.xml
+++ b/uhabits-android/src/main/res/layout/activity_edit_habit.xml
@@ -151,6 +151,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ android:text="@string/startAt" />
+ android:text="0"/>
-
+ android:text="@string/target" />
+
+
+
+
+
+
+
+
+
-
Developers
Version %s
Frequency
+ Default value
Checkmark
Checkmark Stack Widget
Frequency Stack Widget
@@ -186,9 +187,11 @@
Unit
e.g. Did you exercise today?
Question
+ Starts at
Target
Yes
No
+ Skip
Change sound, vibration, light and other notification settings
Customize notifications
View privacy policy
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/Constants.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/Constants.kt
index 1388cb5f8..be6c9634b 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/Constants.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/Constants.kt
@@ -20,4 +20,4 @@ package org.isoron.uhabits.core
const val DATABASE_FILENAME = "uhabits.db"
-const val DATABASE_VERSION = 24
+const val DATABASE_VERSION = 25
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 2d354e7b8..be7690894 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
@@ -35,6 +35,7 @@ data class Habit(
var targetValue: Double = 0.0,
var type: HabitType = HabitType.YES_NO,
var unit: String = "",
+ var defaultValue: Int = 0,
var uuid: String? = null,
val computedEntries: EntryList,
val originalEntries: EntryList,
@@ -69,7 +70,7 @@ data class Habit(
}
fun isFailedToday(): Boolean {
- val today = DateUtils.getTodayWithOffset()
+ var today = DateUtils.getTodayWithOffset()
val value = computedEntries.get(today).value
return if (isNumerical) {
when (targetType) {
@@ -88,15 +89,17 @@ data class Habit(
isNumerical = isNumerical,
)
- val to = DateUtils.getTodayWithOffset().plus(30)
+ val today = DateUtils.getTodayWithOffset()
+ val to = today.plus(30)
val entries = computedEntries.getKnown()
- var from = entries.lastOrNull()?.timestamp ?: to
+ var from = entries.lastOrNull()?.timestamp ?: today
if (from.isNewerThan(to)) from = to
scores.recompute(
frequency = frequency,
isNumerical = isNumerical,
targetValue = targetValue,
+ defaultValue = defaultValue,
computedEntries = computedEntries,
from = from,
to = to,
@@ -123,6 +126,7 @@ data class Habit(
this.targetValue = other.targetValue
this.type = other.type
this.unit = other.unit
+ this.defaultValue = other.defaultValue
this.uuid = other.uuid
}
@@ -143,6 +147,7 @@ data class Habit(
if (targetValue != other.targetValue) return false
if (type != other.type) return false
if (unit != other.unit) return false
+ if (defaultValue != other.defaultValue) return false
if (uuid != other.uuid) return false
return true
@@ -162,6 +167,7 @@ data class Habit(
result = 31 * result + targetValue.hashCode()
result = 31 * result + type.value
result = 31 * result + unit.hashCode()
+ result = 31 * result + defaultValue.hashCode()
result = 31 * result + (uuid?.hashCode() ?: 0)
return result
}
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ScoreList.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ScoreList.kt
index b5dff17de..eff6fad7a 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ScoreList.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ScoreList.kt
@@ -22,7 +22,6 @@ import org.isoron.uhabits.core.models.Score.Companion.compute
import java.util.ArrayList
import java.util.HashMap
import javax.annotation.concurrent.ThreadSafe
-import kotlin.math.max
import kotlin.math.min
@ThreadSafe
@@ -69,18 +68,18 @@ class ScoreList {
frequency: Frequency,
isNumerical: Boolean,
targetValue: Double,
+ defaultValue: Int,
computedEntries: EntryList,
from: Timestamp,
to: Timestamp,
) {
map.clear()
- if (computedEntries.getKnown().isEmpty()) return
- if (from.isNewerThan(to)) return
- var rollingSum = 0.0
var numerator = frequency.numerator
var denominator = frequency.denominator
val freq = frequency.toDouble()
- val values = computedEntries.getByInterval(from, to).map { it.value }.toIntArray()
+ val values = computedEntries.getByInterval(from, to).map {
+ if (it.value >= 0) it.value else defaultValue
+ }.toIntArray()
// For non-daily boolean habits, we double the numerator and the denominator to smooth
// out irregular repetition schedules (for example, weekly habits performed on different
@@ -90,19 +89,32 @@ class ScoreList {
denominator *= 2
}
+ var rollingSum = 0.0
var previousValue = 0.0
+ val numericalPercentageComplete = { valueAccumulated: Double ->
+ if (targetValue > 0) {
+ min(1.0, valueAccumulated / 1000.0 / targetValue)
+ } else {
+ 1.0
+ }
+ }
+ if (isNumerical) {
+ rollingSum = defaultValue.toDouble() * denominator
+ previousValue = numericalPercentageComplete(rollingSum)
+ rollingSum -= defaultValue
+ } else if (defaultValue == Entry.YES_MANUAL) {
+ previousValue = 1.0
+ rollingSum = denominator.toDouble() - 1
+ }
+
for (i in values.indices) {
val offset = values.size - i - 1
if (isNumerical) {
- rollingSum += max(0, values[offset])
+ rollingSum += values[offset]
if (offset + denominator < values.size) {
rollingSum -= values[offset + denominator]
}
- val percentageCompleted = if (targetValue > 0) {
- min(1.0, rollingSum / 1000 / targetValue)
- } else {
- 1.0
- }
+ val percentageCompleted = numericalPercentageComplete(rollingSum)
previousValue = compute(freq, previousValue, percentageCompleted)
} else {
if (values[offset] == Entry.YES_MANUAL) {
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt
index dc0386799..627c20171 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt
@@ -82,6 +82,9 @@ class HabitRecord {
@field:Column
var unit: String? = null
+ @field:Column
+ var defaultValue: Int? = null
+
@field:Column
var id: Long? = null
@@ -99,6 +102,7 @@ class HabitRecord {
targetType = model.targetType.value
targetValue = model.targetValue
unit = model.unit
+ defaultValue = model.defaultValue
position = model.position
question = model.question
uuid = model.uuid
@@ -128,6 +132,7 @@ class HabitRecord {
habit.targetType = NumericalHabitType.fromInt(targetType!!)
habit.targetValue = targetValue!!
habit.unit = unit!!
+ habit.defaultValue = defaultValue!!
habit.position = position!!
habit.uuid = uuid
if (reminderHour != null && reminderMin != null) {
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt
index 89fb09af4..e09066c22 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt
@@ -20,6 +20,7 @@ package org.isoron.uhabits.core.ui.screens.habits.list
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
+import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.Timestamp
@@ -48,9 +49,10 @@ open class ListHabitsBehavior @Inject constructor(
fun onEdit(habit: Habit, timestamp: Timestamp?) {
val entries = habit.computedEntries
- val oldValue = entries.get(timestamp!!).value.toDouble()
+ var oldValue = entries.get(timestamp!!).value
+ oldValue = if (oldValue != Entry.UNKNOWN) oldValue else habit.defaultValue
screen.showNumberPicker(
- oldValue / 1000,
+ oldValue.toDouble() / 1000,
habit.unit
) { newValue: Double ->
val value = (newValue * 1000).roundToInt()
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt
index bd201e0c5..f988855d9 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt
@@ -25,6 +25,7 @@ import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Entry.Companion.SKIP
+import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN
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
@@ -37,13 +38,13 @@ import org.isoron.uhabits.core.ui.views.HistoryChart
import org.isoron.uhabits.core.ui.views.OnDateClickedListener
import org.isoron.uhabits.core.ui.views.Theme
import org.isoron.uhabits.core.utils.DateUtils
-import kotlin.math.max
import kotlin.math.roundToInt
data class HistoryCardState(
val color: PaletteColor,
val firstWeekday: DayOfWeek,
val series: List,
+ val defaultSquare: HistoryChart.Square,
val theme: Theme,
val today: LocalDate,
)
@@ -61,7 +62,8 @@ class HistoryCardPresenter(
screen.showFeedback()
if (habit.isNumerical) {
val entries = habit.computedEntries
- val oldValue = entries.get(timestamp).value
+ var oldValue = entries.get(timestamp).value
+ oldValue = if (oldValue != UNKNOWN) oldValue else habit.defaultValue
screen.showNumberPicker(oldValue / 1000.0, habit.unit) { newValue: Double ->
val thousands = (newValue * 1000).roundToInt()
commandRunner.run(
@@ -74,7 +76,8 @@ class HistoryCardPresenter(
)
}
} else {
- val currentValue = habit.computedEntries.get(timestamp).value
+ var currentValue = habit.computedEntries.get(timestamp).value
+ currentValue = if (currentValue != UNKNOWN) currentValue else habit.defaultValue
val nextValue = Entry.nextToggleValue(
value = currentValue,
isSkipEnabled = preferences.isSkipEnabled,
@@ -103,26 +106,33 @@ class HistoryCardPresenter(
): HistoryCardState {
val today = DateUtils.getTodayWithOffset()
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
- }
+ val entryValues = habit.computedEntries.getByInterval(oldest, today).map {
+ if (it.value != UNKNOWN) it.value else habit.defaultValue
+ }
+ val numericalToSquares = { value: Int ->
+ when (value) {
+ 0 -> HistoryChart.Square.OFF
+ else -> HistoryChart.Square.ON
}
- } else {
- entries.map {
- when (it.value) {
- YES_MANUAL -> HistoryChart.Square.ON
- YES_AUTO -> HistoryChart.Square.DIMMED
- SKIP -> HistoryChart.Square.HATCHED
- else -> HistoryChart.Square.OFF
- }
+ }
+ val yesNoToSquares = { value: Int ->
+ when (value) {
+ YES_MANUAL -> HistoryChart.Square.ON
+ YES_AUTO -> HistoryChart.Square.DIMMED
+ SKIP -> HistoryChart.Square.HATCHED
+ else -> HistoryChart.Square.OFF
}
}
+ val series = if (habit.isNumerical) {
+ entryValues.map(numericalToSquares)
+ } else {
+ entryValues.map(yesNoToSquares)
+ }
+ val defaultSquare = if (habit.isNumerical) {
+ numericalToSquares(habit.defaultValue)
+ } else {
+ yesNoToSquares(habit.defaultValue)
+ }
return HistoryCardState(
color = habit.color,
@@ -130,6 +140,7 @@ class HistoryCardPresenter(
today = today.toLocalDate(),
theme = theme,
series = series,
+ defaultSquare = defaultSquare
)
}
}
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt
index 699cc2ee6..f0da7a196 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt
@@ -41,6 +41,7 @@ class HistoryChart(
var firstWeekday: DayOfWeek,
var paletteColor: PaletteColor,
var series: List,
+ var defaultSquare: Square,
var theme: Theme,
var today: LocalDate,
var onDateClickedListener: OnDateClickedListener = OnDateClickedListener { },
@@ -189,7 +190,7 @@ class HistoryChart(
offset: Int,
) {
- val value = if (offset >= series.size) Square.OFF else series[offset]
+ val value = if (offset >= series.size) defaultSquare else series[offset]
val squareColor: Color
val color = theme.color(paletteColor.paletteIndex)
squareColor = when (value) {
diff --git a/uhabits-core/src/jvmMain/resources/migrations/25.sql b/uhabits-core/src/jvmMain/resources/migrations/25.sql
new file mode 100644
index 000000000..7a10e60da
--- /dev/null
+++ b/uhabits-core/src/jvmMain/resources/migrations/25.sql
@@ -0,0 +1 @@
+alter table Habits add column defaultValue integer not null default 0;
\ No newline at end of file