mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Issue 1316: Skip measurable habit (#1319)
Co-authored-by: Jakub Kalinowski <kalj@netcompany.com>
This commit is contained in:
@@ -22,6 +22,7 @@ package org.isoron.uhabits.activities.common.dialogs
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.DialogInterface.BUTTON_NEGATIVE
|
||||
import android.text.InputFilter
|
||||
import android.text.Spanned
|
||||
import android.view.LayoutInflater
|
||||
@@ -33,7 +34,11 @@ import android.widget.EditText
|
||||
import android.widget.NumberPicker
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import org.isoron.uhabits.HabitsApplication
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.core.models.Frequency
|
||||
import org.isoron.uhabits.core.models.Frequency.Companion.DAILY
|
||||
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
|
||||
import org.isoron.uhabits.inject.ActivityContext
|
||||
import org.isoron.uhabits.utils.InterfaceUtils
|
||||
@@ -52,6 +57,7 @@ class NumberPickerFactory
|
||||
unit: String,
|
||||
notes: String,
|
||||
dateString: String,
|
||||
frequency: Frequency,
|
||||
callback: ListHabitsBehavior.NumberPickerCallback
|
||||
): AlertDialog {
|
||||
val inflater = LayoutInflater.from(context)
|
||||
@@ -92,7 +98,7 @@ class NumberPickerFactory
|
||||
picker2.value = intValue % 100
|
||||
|
||||
etNotes.setText(notes)
|
||||
val dialog = AlertDialog.Builder(context)
|
||||
val dialogBuilder = AlertDialog.Builder(context)
|
||||
.setView(view)
|
||||
.setTitle(dateString)
|
||||
.setPositiveButton(R.string.save) { _, _ ->
|
||||
@@ -108,9 +114,24 @@ class NumberPickerFactory
|
||||
.setOnDismissListener {
|
||||
callback.onNumberPickerDismissed()
|
||||
}
|
||||
.create()
|
||||
|
||||
if (frequency == DAILY) {
|
||||
dialogBuilder.setNegativeButton(R.string.skip_day) { _, _ ->
|
||||
picker.clearFocus()
|
||||
val v = Entry.SKIP.toDouble() / 1000
|
||||
val note = etNotes.text.toString()
|
||||
callback.onNumberPicked(v, note)
|
||||
}
|
||||
}
|
||||
|
||||
val dialog = dialogBuilder.create()
|
||||
|
||||
dialog.setOnShowListener {
|
||||
val preferences =
|
||||
(context.applicationContext as HabitsApplication).component.preferences
|
||||
if (!preferences.isSkipEnabled) {
|
||||
dialog.getButton(BUTTON_NEGATIVE).visibility = View.GONE
|
||||
}
|
||||
showSoftInput(dialog, pickerInputText)
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,8 @@ class FrequencyChart : ScrollableChart {
|
||||
rect[0f, 0f, baseSize.toFloat()] = baseSize.toFloat()
|
||||
rect.offset(prevRect!!.left, prevRect!!.top + baseSize * j)
|
||||
val i = localeWeekdayList[j] % 7
|
||||
if (values != null) drawMarker(canvas, rect, values[i])
|
||||
if (values != null)
|
||||
drawMarker(canvas, rect, values[i])
|
||||
rect.offset(0f, rowHeight)
|
||||
}
|
||||
drawFooter(canvas, rect, date)
|
||||
@@ -222,11 +223,14 @@ class FrequencyChart : ScrollableChart {
|
||||
}
|
||||
|
||||
private fun drawMarker(canvas: Canvas, rect: RectF?, value: Int?) {
|
||||
// value can be negative when the entry is skipped
|
||||
val valueCopy = value?.let { max(0, it) }
|
||||
|
||||
val padding = rect!!.height() * 0.2f
|
||||
// maximal allowed mark radius
|
||||
val maxRadius = (rect.height() - 2 * padding) / 2.0f
|
||||
// the real mark radius is scaled down by a factor depending on the maximal frequency
|
||||
val scale = 1.0f / maxFreq * value!!
|
||||
val scale = 1.0f / maxFreq * valueCopy!!
|
||||
val radius = maxRadius * scale
|
||||
val colorIndex = min((colors.size - 1), ((colors.size - 1) * scale).roundToInt())
|
||||
pGraph!!.color = colors[colorIndex]
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.isoron.uhabits.core.commands.CreateHabitCommand
|
||||
import org.isoron.uhabits.core.commands.DeleteHabitsCommand
|
||||
import org.isoron.uhabits.core.commands.EditHabitCommand
|
||||
import org.isoron.uhabits.core.commands.UnarchiveHabitsCommand
|
||||
import org.isoron.uhabits.core.models.Frequency
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.PaletteColor
|
||||
import org.isoron.uhabits.core.tasks.TaskRunner
|
||||
@@ -230,9 +231,10 @@ class ListHabitsScreen
|
||||
unit: String,
|
||||
notes: String,
|
||||
dateString: String,
|
||||
frequency: Frequency,
|
||||
callback: ListHabitsBehavior.NumberPickerCallback
|
||||
) {
|
||||
numberPickerFactory.create(value, unit, notes, dateString, callback).show()
|
||||
numberPickerFactory.create(value, unit, notes, dateString, frequency, callback).show()
|
||||
}
|
||||
|
||||
override fun showCheckmarkDialog(
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import android.view.View.OnLongClickListener
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST
|
||||
import org.isoron.uhabits.core.models.NumericalHabitType.AT_MOST
|
||||
import org.isoron.uhabits.core.preferences.Preferences
|
||||
@@ -143,6 +144,12 @@ class NumberButtonView(
|
||||
private val lowContrast: Int
|
||||
private val mediumContrast: Int
|
||||
|
||||
private val paint = TextPaint().apply {
|
||||
typeface = getFontAwesome()
|
||||
isAntiAlias = true
|
||||
textAlign = Paint.Align.CENTER
|
||||
}
|
||||
|
||||
private val pUnit: TextPaint = TextPaint().apply {
|
||||
textSize = getDimension(context, R.dimen.smallerTextSize)
|
||||
typeface = NORMAL_TYPEFACE
|
||||
@@ -176,6 +183,11 @@ class NumberButtonView(
|
||||
val textSize: Float
|
||||
|
||||
when {
|
||||
value == Entry.SKIP.toDouble() / 1000 -> {
|
||||
label = resources.getString(R.string.fa_skipped)
|
||||
textSize = dim(R.dimen.smallTextSize)
|
||||
typeface = getFontAwesome()
|
||||
}
|
||||
value >= 0 -> {
|
||||
label = value.toShortString()
|
||||
typeface = BOLD_TYPEFACE
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog
|
||||
import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory
|
||||
import org.isoron.uhabits.core.commands.Command
|
||||
import org.isoron.uhabits.core.commands.CommandRunner
|
||||
import org.isoron.uhabits.core.models.Frequency
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.PaletteColor
|
||||
import org.isoron.uhabits.core.preferences.Preferences
|
||||
@@ -169,9 +170,10 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
|
||||
unit: String,
|
||||
notes: String,
|
||||
dateString: String,
|
||||
callback: ListHabitsBehavior.NumberPickerCallback,
|
||||
frequency: Frequency,
|
||||
callback: ListHabitsBehavior.NumberPickerCallback
|
||||
) {
|
||||
NumberPickerFactory(this@ShowHabitActivity).create(value, unit, notes, dateString, callback).show()
|
||||
NumberPickerFactory(this@ShowHabitActivity).create(value, unit, notes, dateString, frequency, callback).show()
|
||||
}
|
||||
|
||||
override fun showCheckmarkDialog(
|
||||
|
||||
@@ -81,6 +81,7 @@ class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPi
|
||||
data.habit.unit,
|
||||
entry.notes,
|
||||
today.toDialogDateString(),
|
||||
data.habit.frequency,
|
||||
this
|
||||
).show()
|
||||
}
|
||||
|
||||
@@ -225,6 +225,7 @@
|
||||
<string name="increment">Increment</string>
|
||||
<string name="decrement">Decrement</string>
|
||||
<string name="pref_skip_title">Enable skip days</string>
|
||||
<string name="skip_day">Skip</string>
|
||||
<string name="pref_skip_description">Toggle twice to add a skip instead of a checkmark. Skips keep your score unchanged and don\'t break your streak.</string>
|
||||
<string name="pref_unknown_title">Show question marks for missing data</string>
|
||||
<string name="pref_unknown_description">Differentiate days without data from actual lapses. To enter a lapse, toggle twice.</string>
|
||||
|
||||
@@ -276,6 +276,8 @@ open class EntryList {
|
||||
* For numerical habits, non-positive entry values are converted to zero. For boolean habits, each
|
||||
* YES_MANUAL value is converted to 1000 and all other values are converted to zero.
|
||||
*
|
||||
* SKIP values are converted to zero (if they weren't, each SKIP day would count as 0.003).
|
||||
*
|
||||
* The returned list is sorted by timestamp, with the newest entry coming first and the oldest entry
|
||||
* coming last. If the original list has gaps in it (for example, weeks or months without any
|
||||
* entries), then the list produced by this method will also have gaps.
|
||||
@@ -289,6 +291,9 @@ fun List<Entry>.groupedSum(
|
||||
): List<Entry> {
|
||||
return this.map { (timestamp, value) ->
|
||||
if (isNumerical) {
|
||||
if (value == SKIP)
|
||||
Entry(timestamp, 0)
|
||||
else
|
||||
Entry(timestamp, max(0, value))
|
||||
} else {
|
||||
Entry(timestamp, if (value == YES_MANUAL) 1000 else 0)
|
||||
@@ -301,6 +306,31 @@ fun List<Entry>.groupedSum(
|
||||
}.entries.map { (timestamp, entries) ->
|
||||
Entry(timestamp, entries.sumOf { it.value })
|
||||
}.sortedBy { (timestamp, _) ->
|
||||
- timestamp.unixTime
|
||||
-timestamp.unixTime
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of days with vaLue SKIP in the given period.
|
||||
*/
|
||||
fun List<Entry>.countSkippedDays(
|
||||
truncateField: DateUtils.TruncateField,
|
||||
firstWeekday: Int = Calendar.SATURDAY
|
||||
): List<Entry> {
|
||||
return this.map { (timestamp, value) ->
|
||||
if (value == SKIP) {
|
||||
Entry(timestamp, 1)
|
||||
} else {
|
||||
Entry(timestamp, 0)
|
||||
}
|
||||
}.groupBy { entry ->
|
||||
entry.timestamp.truncate(
|
||||
truncateField,
|
||||
firstWeekday,
|
||||
)
|
||||
}.entries.map { (timestamp, entries) ->
|
||||
Entry(timestamp, entries.sumOf { it.value })
|
||||
}.sortedBy { (timestamp, _) ->
|
||||
-timestamp.unixTime
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ class ScoreList {
|
||||
}
|
||||
|
||||
val normalizedRollingSum = rollingSum / 1000
|
||||
if (values[offset] != Entry.SKIP) {
|
||||
val percentageCompleted = if (!isAtMost) {
|
||||
if (targetValue > 0)
|
||||
min(1.0, normalizedRollingSum / targetValue)
|
||||
@@ -107,13 +108,17 @@ class ScoreList {
|
||||
1.0
|
||||
} else {
|
||||
if (targetValue > 0) {
|
||||
(1 - ((normalizedRollingSum - targetValue) / targetValue)).coerceIn(0.0, 1.0)
|
||||
(1 - ((normalizedRollingSum - targetValue) / targetValue)).coerceIn(
|
||||
0.0,
|
||||
1.0
|
||||
)
|
||||
} else {
|
||||
if (normalizedRollingSum > 0) 0.0 else 1.0
|
||||
}
|
||||
}
|
||||
|
||||
previousValue = compute(freq, previousValue, percentageCompleted)
|
||||
}
|
||||
} else {
|
||||
if (values[offset] == Entry.YES_MANUAL) {
|
||||
rollingSum += 1.0
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.isoron.uhabits.core.ui.screens.habits.list
|
||||
import org.isoron.platform.time.LocalDate
|
||||
import org.isoron.uhabits.core.commands.CommandRunner
|
||||
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
|
||||
import org.isoron.uhabits.core.models.Frequency
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.HabitList
|
||||
import org.isoron.uhabits.core.models.HabitType
|
||||
@@ -58,6 +59,7 @@ open class ListHabitsBehavior @Inject constructor(
|
||||
habit.unit,
|
||||
entry.notes,
|
||||
timestamp.toDialogDateString(),
|
||||
habit.frequency
|
||||
) { newValue: Double, newNotes: String, ->
|
||||
val value = (newValue * 1000).roundToInt()
|
||||
commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes))
|
||||
@@ -167,6 +169,7 @@ open class ListHabitsBehavior @Inject constructor(
|
||||
unit: String,
|
||||
notes: String,
|
||||
dateString: String,
|
||||
frequency: Frequency,
|
||||
callback: NumberPickerCallback
|
||||
)
|
||||
fun showCheckmarkDialog(
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.core.models.Entry.Companion.SKIP
|
||||
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.Frequency
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.HabitList
|
||||
import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST
|
||||
@@ -123,6 +124,7 @@ class HistoryCardPresenter(
|
||||
habit.unit,
|
||||
entry.notes,
|
||||
timestamp.toDialogDateString(),
|
||||
frequency = habit.frequency
|
||||
) { newValue: Double, newNotes: String ->
|
||||
val thousands = (newValue * 1000).roundToInt()
|
||||
commandRunner.run(
|
||||
@@ -154,6 +156,7 @@ class HistoryCardPresenter(
|
||||
entries.map {
|
||||
when {
|
||||
it.value == Entry.UNKNOWN -> OFF
|
||||
it.value == SKIP -> HATCHED
|
||||
(habit.targetType == AT_MOST) && (it.value / 1000.0 <= habit.targetValue) -> ON
|
||||
(habit.targetType == AT_LEAST) && (it.value / 1000.0 >= habit.targetValue) -> ON
|
||||
else -> GREY
|
||||
@@ -196,8 +199,10 @@ class HistoryCardPresenter(
|
||||
unit: String,
|
||||
notes: String,
|
||||
dateString: String,
|
||||
callback: ListHabitsBehavior.NumberPickerCallback,
|
||||
frequency: Frequency,
|
||||
callback: ListHabitsBehavior.NumberPickerCallback
|
||||
)
|
||||
|
||||
fun showCheckmarkDialog(
|
||||
selectedValue: Int,
|
||||
notes: String,
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.isoron.uhabits.core.ui.screens.habits.show.views
|
||||
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.PaletteColor
|
||||
import org.isoron.uhabits.core.models.countSkippedDays
|
||||
import org.isoron.uhabits.core.models.groupedSum
|
||||
import org.isoron.uhabits.core.ui.views.Theme
|
||||
import org.isoron.uhabits.core.utils.DateUtils
|
||||
@@ -51,37 +52,59 @@ class TargetCardPresenter {
|
||||
isNumerical = habit.isNumerical
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val skippedDayToday = entries.countSkippedDays(
|
||||
truncateField = DateUtils.TruncateField.DAY
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val valueThisWeek = entries.groupedSum(
|
||||
truncateField = DateUtils.TruncateField.WEEK_NUMBER,
|
||||
firstWeekday = firstWeekday,
|
||||
isNumerical = habit.isNumerical
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val skippedDaysThisWeek = entries.countSkippedDays(
|
||||
truncateField = DateUtils.TruncateField.WEEK_NUMBER,
|
||||
firstWeekday = firstWeekday
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val valueThisMonth = entries.groupedSum(
|
||||
truncateField = DateUtils.TruncateField.MONTH,
|
||||
isNumerical = habit.isNumerical
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val skippedDaysThisMonth = entries.countSkippedDays(
|
||||
truncateField = DateUtils.TruncateField.MONTH,
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val valueThisQuarter = entries.groupedSum(
|
||||
truncateField = DateUtils.TruncateField.QUARTER,
|
||||
isNumerical = habit.isNumerical
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val skippedDaysThisQuarter = entries.countSkippedDays(
|
||||
truncateField = DateUtils.TruncateField.QUARTER
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val valueThisYear = entries.groupedSum(
|
||||
truncateField = DateUtils.TruncateField.YEAR,
|
||||
isNumerical = habit.isNumerical
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val skippedDaysThisYear = entries.countSkippedDays(
|
||||
truncateField = DateUtils.TruncateField.YEAR
|
||||
).firstOrNull()?.value ?: 0
|
||||
|
||||
val cal = DateUtils.getStartOfTodayCalendarWithOffset()
|
||||
val daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH)
|
||||
val daysInQuarter = 91
|
||||
val daysInYear = cal.getActualMaximum(Calendar.DAY_OF_YEAR)
|
||||
|
||||
val targetToday = habit.targetValue / habit.frequency.denominator
|
||||
val targetThisWeek = targetToday * 7
|
||||
val targetThisMonth = targetToday * daysInMonth
|
||||
val targetThisQuarter = targetToday * daysInQuarter
|
||||
val targetThisYear = targetToday * daysInYear
|
||||
val dailyTarget = habit.targetValue / habit.frequency.denominator
|
||||
val targetToday = dailyTarget * (1 - skippedDayToday)
|
||||
val targetThisWeek = dailyTarget * (7 - skippedDaysThisWeek)
|
||||
val targetThisMonth = dailyTarget * (daysInMonth - skippedDaysThisMonth)
|
||||
val targetThisQuarter = dailyTarget * (daysInQuarter - skippedDaysThisQuarter)
|
||||
val targetThisYear = dailyTarget * (daysInYear - skippedDaysThisYear)
|
||||
|
||||
val values = ArrayList<Double>()
|
||||
if (habit.frequency.denominator <= 1) values.add(valueToday / 1e3)
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.number.IsCloseTo
|
||||
import org.hamcrest.number.OrderingComparison
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.models.Entry.Companion.SKIP
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -381,6 +382,66 @@ class NumericalAtLeastScoreListTest : NumericalScoreListTest() {
|
||||
}
|
||||
}
|
||||
|
||||
class NumericalAtLeastScoreListWithSkipTest : NumericalScoreListTest() {
|
||||
@Before
|
||||
@Throws(Exception::class)
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
habit = fixtures.createEmptyNumericalHabit(NumericalHabitType.AT_LEAST)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_getValue() {
|
||||
addEntries(0, 10, 2000)
|
||||
addEntries(10, 11, SKIP)
|
||||
addEntries(11, 15, 2000)
|
||||
addEntries(15, 16, SKIP)
|
||||
addEntries(16, 20, 2000)
|
||||
val expectedValues = doubleArrayOf(
|
||||
0.617008,
|
||||
0.596033,
|
||||
0.573910,
|
||||
0.550574,
|
||||
0.525961,
|
||||
0.500000,
|
||||
0.472617,
|
||||
0.443734,
|
||||
0.413270,
|
||||
0.381137,
|
||||
0.347244, // skipped day should have the same score as the previous day
|
||||
0.347244,
|
||||
0.311495,
|
||||
0.273788,
|
||||
0.234017,
|
||||
0.192067, // skipped day should have the same score as the previous day
|
||||
0.192067,
|
||||
0.147820,
|
||||
0.101149,
|
||||
0.051922,
|
||||
0.000000,
|
||||
0.000000,
|
||||
0.000000
|
||||
)
|
||||
checkScoreValues(expectedValues)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun skipsShouldNotAffectScore() {
|
||||
addEntries(0, 500, 1000)
|
||||
val initialScore = habit.scores[today].value
|
||||
|
||||
addEntries(500, 1000, SKIP)
|
||||
assertThat(habit.scores[today].value, IsCloseTo.closeTo(initialScore, E))
|
||||
|
||||
addEntries(0, 300, 1000)
|
||||
addEntries(300, 500, SKIP)
|
||||
addEntries(500, 700, 1000)
|
||||
|
||||
// skipped days should be treated as if they never existed
|
||||
assertThat(habit.scores[today].value, IsCloseTo.closeTo(initialScore, E))
|
||||
}
|
||||
}
|
||||
|
||||
class NumericalAtMostScoreListTest : NumericalScoreListTest() {
|
||||
@Before
|
||||
@Throws(Exception::class)
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.core.IsEqual.equalTo
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
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.preferences.Preferences
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||
@@ -79,7 +80,14 @@ class ListHabitsBehaviorTest : BaseUnitTest() {
|
||||
@Test
|
||||
fun testOnEdit() {
|
||||
behavior.onEdit(habit2, getToday())
|
||||
verify(screen).showNumberPicker(eq(0.1), eq("miles"), eq(""), eq("Jan 25, 2015"), picker.capture())
|
||||
verify(screen).showNumberPicker(
|
||||
eq(0.1),
|
||||
eq("miles"),
|
||||
eq(""),
|
||||
eq("Jan 25, 2015"),
|
||||
eq(Frequency.DAILY),
|
||||
picker.capture()
|
||||
)
|
||||
picker.lastValue.onNumberPicked(100.0, "")
|
||||
val today = getTodayWithOffset()
|
||||
assertThat(habit2.computedEntries.get(today).value, equalTo(100000))
|
||||
|
||||
Reference in New Issue
Block a user