Remove ShowHabitScreen and ShowHabitBehavior

This commit is contained in:
2021-01-02 00:45:16 -06:00
parent 162eac3bdf
commit cb6843e08b
40 changed files with 658 additions and 686 deletions

View File

@@ -19,92 +19,124 @@
package org.isoron.uhabits.core.ui.screens.habits.show
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.screens.habits.show.views.BarCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.BarCardViewModel
import org.isoron.uhabits.core.ui.screens.habits.show.views.BarCardState
import org.isoron.uhabits.core.ui.screens.habits.show.views.FrequencyCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.FrequencyCardViewModel
import org.isoron.uhabits.core.ui.screens.habits.show.views.FrequencyCardState
import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardViewModel
import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardState
import org.isoron.uhabits.core.ui.screens.habits.show.views.NotesCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.NotesCardViewModel
import org.isoron.uhabits.core.ui.screens.habits.show.views.NotesCardState
import org.isoron.uhabits.core.ui.screens.habits.show.views.OverviewCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.OverviewCardViewModel
import org.isoron.uhabits.core.ui.screens.habits.show.views.OverviewCardState
import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardViewModel
import org.isoron.uhabits.core.ui.screens.habits.show.views.StreakCardViewModel
import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardState
import org.isoron.uhabits.core.ui.screens.habits.show.views.StreakCardState
import org.isoron.uhabits.core.ui.screens.habits.show.views.StreakCartPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardViewModel
import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardState
import org.isoron.uhabits.core.ui.screens.habits.show.views.TargetCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.TargetCardViewModel
import org.isoron.uhabits.core.ui.screens.habits.show.views.TargetCardState
import org.isoron.uhabits.core.ui.views.Theme
data class ShowHabitViewModel(
data class ShowHabitState(
val title: String = "",
val isNumerical: Boolean = false,
val color: PaletteColor = PaletteColor(1),
val subtitle: SubtitleCardViewModel,
val overview: OverviewCardViewModel,
val notes: NotesCardViewModel,
val target: TargetCardViewModel,
val streaks: StreakCardViewModel,
val scores: ScoreCardViewModel,
val frequency: FrequencyCardViewModel,
val history: HistoryCardViewModel,
val bar: BarCardViewModel,
val subtitle: SubtitleCardState,
val overview: OverviewCardState,
val notes: NotesCardState,
val target: TargetCardState,
val streaks: StreakCardState,
val scores: ScoreCardState,
val frequency: FrequencyCardState,
val history: HistoryCardState,
val bar: BarCardState,
)
class ShowHabitPresenter {
fun present(
habit: Habit,
preferences: Preferences,
theme: Theme,
): ShowHabitViewModel {
return ShowHabitViewModel(
title = habit.name,
color = habit.color,
isNumerical = habit.isNumerical,
subtitle = SubtitleCardPresenter().present(
habit = habit,
),
overview = OverviewCardPresenter().present(
habit = habit,
),
notes = NotesCardPresenter().present(
habit = habit,
),
target = TargetCardPresenter().present(
habit = habit,
firstWeekday = preferences.firstWeekdayInt,
),
streaks = StreakCartPresenter().present(
habit = habit,
),
scores = ScoreCardPresenter().present(
spinnerPosition = preferences.scoreCardSpinnerPosition,
habit = habit,
firstWeekday = preferences.firstWeekdayInt,
),
frequency = FrequencyCardPresenter().present(
habit = habit,
firstWeekday = preferences.firstWeekdayInt,
),
history = HistoryCardPresenter().present(
habit = habit,
firstWeekday = preferences.firstWeekday,
isSkipEnabled = preferences.isSkipEnabled,
theme = theme,
),
bar = BarCardPresenter().present(
habit = habit,
firstWeekday = preferences.firstWeekdayInt,
boolSpinnerPosition = preferences.barCardBoolSpinnerPosition,
numericalSpinnerPosition = preferences.barCardNumericalSpinnerPosition,
theme = theme,
),
)
class ShowHabitPresenter(
val habit: Habit,
val habitList: HabitList,
val preferences: Preferences,
val screen: Screen,
val commandRunner: CommandRunner,
) {
val historyCardPresenter = HistoryCardPresenter(
commandRunner = commandRunner,
habit = habit,
habitList = habitList,
preferences = preferences,
screen = screen,
)
val barCardPresenter = BarCardPresenter(
preferences = preferences,
screen = screen,
)
val scoreCardPresenter = ScoreCardPresenter(
preferences = preferences,
screen = screen,
)
companion object {
fun buildState(
habit: Habit,
preferences: Preferences,
theme: Theme,
): ShowHabitState {
return ShowHabitState(
title = habit.name,
color = habit.color,
isNumerical = habit.isNumerical,
subtitle = SubtitleCardPresenter.buildState(
habit = habit,
),
overview = OverviewCardPresenter.buildState(
habit = habit,
),
notes = NotesCardPresenter.buildState(
habit = habit,
),
target = TargetCardPresenter.buildState(
habit = habit,
firstWeekday = preferences.firstWeekdayInt,
),
streaks = StreakCartPresenter.buildState(
habit = habit,
),
scores = ScoreCardPresenter.buildState(
spinnerPosition = preferences.scoreCardSpinnerPosition,
habit = habit,
firstWeekday = preferences.firstWeekdayInt,
),
frequency = FrequencyCardPresenter.buildState(
habit = habit,
firstWeekday = preferences.firstWeekdayInt,
),
history = HistoryCardPresenter.buildState(
habit = habit,
firstWeekday = preferences.firstWeekday,
theme = theme,
),
bar = BarCardPresenter.buildState(
habit = habit,
firstWeekday = preferences.firstWeekdayInt,
boolSpinnerPosition = preferences.barCardBoolSpinnerPosition,
numericalSpinnerPosition = preferences.barCardNumericalSpinnerPosition,
theme = theme,
),
)
}
}
interface Screen :
BarCardPresenter.Screen,
ScoreCardPresenter.Screen,
HistoryCardPresenter.Screen
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.core.ui.screens.habits.show
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.Entry
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
import org.isoron.uhabits.core.ui.views.OnDateClickedListener
import kotlin.math.roundToInt
class ShowHabitBehavior(
private val habitList: HabitList,
private val commandRunner: CommandRunner,
private val habit: Habit,
private val screen: Screen,
private val preferences: Preferences,
) : OnDateClickedListener {
fun onScoreCardSpinnerPosition(position: Int) {
preferences.scoreCardSpinnerPosition = position
screen.updateWidgets()
screen.refresh()
}
fun onBarCardBoolSpinnerPosition(position: Int) {
preferences.barCardBoolSpinnerPosition = position
screen.updateWidgets()
screen.refresh()
}
fun onBarCardNumericalSpinnerPosition(position: Int) {
preferences.barCardNumericalSpinnerPosition = position
screen.refresh()
screen.updateWidgets()
}
fun onClickEditHistory() {
screen.showHistoryEditorDialog(this)
}
override fun onDateClicked(date: LocalDate) {
val timestamp = date.timestamp
screen.touchFeedback()
if (habit.isNumerical) {
val entries = habit.computedEntries
val oldValue = entries.get(timestamp).value
screen.showNumberPicker(oldValue / 1000.0, habit.unit) { newValue: Double ->
val thousands = (newValue * 1000).roundToInt()
commandRunner.run(
CreateRepetitionCommand(
habitList,
habit,
timestamp,
thousands,
),
)
}
} else {
val currentValue = habit.computedEntries.get(timestamp).value
val nextValue = if (preferences.isSkipEnabled) {
Entry.nextToggleValueWithSkip(currentValue)
} else {
Entry.nextToggleValueWithoutSkip(currentValue)
}
commandRunner.run(
CreateRepetitionCommand(
habitList,
habit,
timestamp,
nextValue,
),
)
}
}
interface Screen {
fun showNumberPicker(
value: Double,
unit: String,
callback: ListHabitsBehavior.NumberPickerCallback,
)
fun updateWidgets()
fun refresh()
fun showHistoryEditorDialog(listener: OnDateClickedListener)
fun touchFeedback()
}
}

View File

@@ -30,7 +30,7 @@ import org.isoron.uhabits.core.utils.DateUtils
import java.io.File
import java.util.Random
class ShowHabitMenuBehavior(
class ShowHabitMenuPresenter(
private val commandRunner: CommandRunner,
private val habit: Habit,
private val habitList: HabitList,
@@ -85,9 +85,7 @@ class ShowHabitMenuBehavior(
fun showEditHabitScreen(habit: Habit)
fun showMessage(m: Message?)
fun showSendFileScreen(filename: String)
fun showDeleteConfirmationScreen(
callback: OnConfirmedCallback
)
fun showDeleteConfirmationScreen(callback: OnConfirmedCallback)
fun close()
fun refresh()
}

View File

@@ -23,10 +23,11 @@ import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.groupedSum
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.views.Theme
import org.isoron.uhabits.core.utils.DateUtils
data class BarCardViewModel(
data class BarCardState(
val theme: Theme,
val boolSpinnerPosition: Int,
val bucketSize: Int,
@@ -36,37 +37,59 @@ data class BarCardViewModel(
val numericalSpinnerPosition: Int,
)
class BarCardPresenter {
val numericalBucketSizes = intArrayOf(1, 7, 31, 92, 365)
val boolBucketSizes = intArrayOf(7, 31, 92, 365)
class BarCardPresenter(
val preferences: Preferences,
val screen: Screen,
) {
companion object {
val numericalBucketSizes = intArrayOf(1, 7, 31, 92, 365)
val boolBucketSizes = intArrayOf(7, 31, 92, 365)
fun present(
habit: Habit,
firstWeekday: Int,
numericalSpinnerPosition: Int,
boolSpinnerPosition: Int,
theme: Theme,
): BarCardViewModel {
val bucketSize = if (habit.isNumerical) {
numericalBucketSizes[numericalSpinnerPosition]
} else {
boolBucketSizes[boolSpinnerPosition]
fun buildState(
habit: Habit,
firstWeekday: Int,
numericalSpinnerPosition: Int,
boolSpinnerPosition: Int,
theme: Theme,
): BarCardState {
val bucketSize = if (habit.isNumerical) {
numericalBucketSizes[numericalSpinnerPosition]
} else {
boolBucketSizes[boolSpinnerPosition]
}
val today = DateUtils.getToday()
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
val entries = habit.computedEntries.getByInterval(oldest, today).groupedSum(
truncateField = ScoreCardPresenter.getTruncateField(bucketSize),
firstWeekday = firstWeekday,
isNumerical = habit.isNumerical,
)
return BarCardState(
theme = theme,
entries = entries,
bucketSize = bucketSize,
color = habit.color,
isNumerical = habit.isNumerical,
numericalSpinnerPosition = numericalSpinnerPosition,
boolSpinnerPosition = boolSpinnerPosition,
)
}
val today = DateUtils.getToday()
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
val entries = habit.computedEntries.getByInterval(oldest, today).groupedSum(
truncateField = ScoreCardPresenter.getTruncateField(bucketSize),
firstWeekday = firstWeekday,
isNumerical = habit.isNumerical,
)
return BarCardViewModel(
theme = theme,
entries = entries,
bucketSize = bucketSize,
color = habit.color,
isNumerical = habit.isNumerical,
numericalSpinnerPosition = numericalSpinnerPosition,
boolSpinnerPosition = boolSpinnerPosition,
)
}
fun onNumericalSpinnerPosition(position: Int) {
preferences.barCardNumericalSpinnerPosition = position
screen.updateWidgets()
screen.refresh()
}
fun onBoolSpinnerPosition(position: Int) {
preferences.barCardBoolSpinnerPosition = position
screen.updateWidgets()
screen.refresh()
}
interface Screen {
fun updateWidgets()
fun refresh()
}
}

View File

@@ -24,21 +24,23 @@ import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Timestamp
import java.util.HashMap
data class FrequencyCardViewModel(
data class FrequencyCardState(
val color: PaletteColor,
val firstWeekday: Int,
val frequency: HashMap<Timestamp, Array<Int>>,
)
class FrequencyCardPresenter {
fun present(
habit: Habit,
firstWeekday: Int,
) = FrequencyCardViewModel(
color = habit.color,
frequency = habit.originalEntries.computeWeekdayFrequency(
isNumerical = habit.isNumerical
),
firstWeekday = firstWeekday,
)
companion object {
fun buildState(
habit: Habit,
firstWeekday: Int,
) = FrequencyCardState(
color = habit.color,
frequency = habit.originalEntries.computeWeekdayFrequency(
isNumerical = habit.isNumerical
),
firstWeekday = firstWeekday,
)
}
}

View File

@@ -21,18 +21,25 @@ package org.isoron.uhabits.core.ui.screens.habits.show.views
import org.isoron.platform.time.DayOfWeek
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.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.Habit
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
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 HistoryCardViewModel(
data class HistoryCardState(
val color: PaletteColor,
val firstWeekday: DayOfWeek,
val series: List<HistoryChart.Square>,
@@ -40,42 +47,99 @@ data class HistoryCardViewModel(
val today: LocalDate,
)
class HistoryCardPresenter {
fun present(
habit: Habit,
firstWeekday: DayOfWeek,
isSkipEnabled: Boolean,
theme: Theme,
): HistoryCardViewModel {
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
}
class HistoryCardPresenter(
val commandRunner: CommandRunner,
val habit: Habit,
val habitList: HabitList,
val preferences: Preferences,
val screen: Screen,
) : OnDateClickedListener {
override fun onDateClicked(date: LocalDate) {
val timestamp = date.timestamp
screen.showFeedback()
if (habit.isNumerical) {
val entries = habit.computedEntries
val oldValue = entries.get(timestamp).value
screen.showNumberPicker(oldValue / 1000.0, habit.unit) { newValue: Double ->
val thousands = (newValue * 1000).roundToInt()
commandRunner.run(
CreateRepetitionCommand(
habitList,
habit,
timestamp,
thousands,
),
)
}
} 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 currentValue = habit.computedEntries.get(timestamp).value
val nextValue = if (preferences.isSkipEnabled) {
Entry.nextToggleValueWithSkip(currentValue)
} else {
Entry.nextToggleValueWithoutSkip(currentValue)
}
commandRunner.run(
CreateRepetitionCommand(
habitList,
habit,
timestamp,
nextValue,
),
)
}
}
fun onClickEditButton() {
screen.showHistoryEditorDialog(this)
}
companion object {
fun buildState(
habit: Habit,
firstWeekday: DayOfWeek,
theme: Theme,
): 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
}
}
} else {
entries.map {
when (it.value) {
YES_MANUAL -> HistoryChart.Square.ON
YES_AUTO -> HistoryChart.Square.DIMMED
SKIP -> HistoryChart.Square.HATCHED
else -> HistoryChart.Square.OFF
}
}
}
}
return HistoryCardViewModel(
color = habit.color,
firstWeekday = firstWeekday,
today = today.toLocalDate(),
theme = theme,
series = series,
return HistoryCardState(
color = habit.color,
firstWeekday = firstWeekday,
today = today.toLocalDate(),
theme = theme,
series = series,
)
}
}
interface Screen {
fun showHistoryEditorDialog(listener: OnDateClickedListener)
fun showFeedback()
fun showNumberPicker(
value: Double,
unit: String,
callback: ListHabitsBehavior.NumberPickerCallback,
)
}
}

View File

@@ -21,12 +21,14 @@ package org.isoron.uhabits.core.ui.screens.habits.show.views
import org.isoron.uhabits.core.models.Habit
data class NotesCardViewModel(
data class NotesCardState(
val description: String,
)
class NotesCardPresenter {
fun present(habit: Habit) = NotesCardViewModel(
description = habit.description,
)
companion object {
fun buildState(habit: Habit) = NotesCardState(
description = habit.description,
)
}
}

View File

@@ -24,7 +24,7 @@ import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.utils.DateUtils
data class OverviewCardViewModel(
data class OverviewCardState(
val color: PaletteColor,
val scoreMonthDiff: Float,
val scoreYearDiff: Float,
@@ -33,24 +33,26 @@ data class OverviewCardViewModel(
)
class OverviewCardPresenter {
fun present(habit: Habit): OverviewCardViewModel {
val today = DateUtils.getTodayWithOffset()
val lastMonth = today.minus(30)
val lastYear = today.minus(365)
val scores = habit.scores
val scoreToday = scores.get(today).value.toFloat()
val scoreLastMonth = scores.get(lastMonth).value.toFloat()
val scoreLastYear = scores.get(lastYear).value.toFloat()
val totalCount = habit.originalEntries.getKnown()
.filter { it.value == Entry.YES_MANUAL }
.count()
.toLong()
return OverviewCardViewModel(
color = habit.color,
scoreToday = scoreToday,
scoreMonthDiff = scoreToday - scoreLastMonth,
scoreYearDiff = scoreToday - scoreLastYear,
totalCount = totalCount,
)
companion object {
fun buildState(habit: Habit): OverviewCardState {
val today = DateUtils.getTodayWithOffset()
val lastMonth = today.minus(30)
val lastYear = today.minus(365)
val scores = habit.scores
val scoreToday = scores.get(today).value.toFloat()
val scoreLastMonth = scores.get(lastMonth).value.toFloat()
val scoreLastYear = scores.get(lastYear).value.toFloat()
val totalCount = habit.originalEntries.getKnown()
.filter { it.value == Entry.YES_MANUAL }
.count()
.toLong()
return OverviewCardState(
color = habit.color,
scoreToday = scoreToday,
scoreMonthDiff = scoreToday - scoreLastMonth,
scoreYearDiff = scoreToday - scoreLastYear,
totalCount = totalCount,
)
}
}
}

View File

@@ -22,16 +22,20 @@ 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.Score
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.utils.DateUtils
data class ScoreCardViewModel(
data class ScoreCardState(
val scores: List<Score>,
val bucketSize: Int,
val spinnerPosition: Int,
val color: PaletteColor,
)
class ScoreCardPresenter {
class ScoreCardPresenter(
val preferences: Preferences,
val screen: Screen,
) {
companion object {
val BUCKET_SIZES = intArrayOf(1, 7, 31, 92, 365)
fun getTruncateField(bucketSize: Int): DateUtils.TruncateField {
@@ -44,36 +48,47 @@ class ScoreCardPresenter {
else -> return DateUtils.TruncateField.MONTH
}
}
fun buildState(
habit: Habit,
firstWeekday: Int,
spinnerPosition: Int,
): ScoreCardState {
val bucketSize = BUCKET_SIZES[spinnerPosition]
val today = DateUtils.getTodayWithOffset()
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
val field = getTruncateField(bucketSize)
val scores = habit.scores.getByInterval(oldest, today).groupBy {
DateUtils.truncate(field, it.timestamp, firstWeekday)
}.map { (timestamp, scores) ->
Score(
timestamp,
scores.map {
it.value
}.average()
)
}.sortedBy {
it.timestamp
}.reversed()
return ScoreCardState(
color = habit.color,
scores = scores,
bucketSize = bucketSize,
spinnerPosition = spinnerPosition,
)
}
}
fun present(
habit: Habit,
firstWeekday: Int,
spinnerPosition: Int,
): ScoreCardViewModel {
val bucketSize = BUCKET_SIZES[spinnerPosition]
val today = DateUtils.getTodayWithOffset()
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
fun onSpinnerPosition(position: Int) {
preferences.scoreCardSpinnerPosition = position
screen.updateWidgets()
screen.refresh()
}
val field = getTruncateField(bucketSize)
val scores = habit.scores.getByInterval(oldest, today).groupBy {
DateUtils.truncate(field, it.timestamp, firstWeekday)
}.map { (timestamp, scores) ->
Score(
timestamp,
scores.map {
it.value
}.average()
)
}.sortedBy {
it.timestamp
}.reversed()
return ScoreCardViewModel(
color = habit.color,
scores = scores,
bucketSize = bucketSize,
spinnerPosition = spinnerPosition,
)
interface Screen {
fun updateWidgets()
fun refresh()
}
}

View File

@@ -23,16 +23,18 @@ import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Streak
data class StreakCardViewModel(
data class StreakCardState(
val color: PaletteColor,
val bestStreaks: List<Streak>
)
class StreakCartPresenter {
fun present(habit: Habit): StreakCardViewModel {
return StreakCardViewModel(
color = habit.color,
bestStreaks = habit.streaks.getBest(10),
)
companion object {
fun buildState(habit: Habit): StreakCardState {
return StreakCardState(
color = habit.color,
bestStreaks = habit.streaks.getBest(10),
)
}
}
}

View File

@@ -24,7 +24,7 @@ import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Reminder
data class SubtitleCardViewModel(
data class SubtitleCardState(
val color: PaletteColor,
val frequency: Frequency,
val isNumerical: Boolean,
@@ -35,15 +35,17 @@ data class SubtitleCardViewModel(
)
class SubtitleCardPresenter {
fun present(
habit: Habit,
): SubtitleCardViewModel = SubtitleCardViewModel(
color = habit.color,
frequency = habit.frequency,
isNumerical = habit.isNumerical,
question = habit.question,
reminder = habit.reminder,
targetValue = habit.targetValue,
unit = habit.unit,
)
companion object {
fun buildState(
habit: Habit,
): SubtitleCardState = SubtitleCardState(
color = habit.color,
frequency = habit.frequency,
isNumerical = habit.isNumerical,
question = habit.question,
reminder = habit.reminder,
targetValue = habit.targetValue,
unit = habit.unit,
)
}
}

View File

@@ -26,7 +26,7 @@ import org.isoron.uhabits.core.utils.DateUtils
import java.util.ArrayList
import java.util.Calendar
data class TargetCardViewModel(
data class TargetCardState(
val color: PaletteColor,
val values: List<Double> = listOf(),
val targets: List<Double> = listOf(),
@@ -34,77 +34,79 @@ data class TargetCardViewModel(
)
class TargetCardPresenter {
fun present(
habit: Habit,
firstWeekday: Int,
): TargetCardViewModel {
val today = DateUtils.getTodayWithOffset()
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
val entries = habit.computedEntries.getByInterval(oldest, today)
companion object {
fun buildState(
habit: Habit,
firstWeekday: Int,
): TargetCardState {
val today = DateUtils.getTodayWithOffset()
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
val entries = habit.computedEntries.getByInterval(oldest, today)
val valueToday = entries.groupedSum(
truncateField = DateUtils.TruncateField.DAY,
isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0
val valueToday = entries.groupedSum(
truncateField = DateUtils.TruncateField.DAY,
isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0
val valueThisWeek = entries.groupedSum(
truncateField = DateUtils.TruncateField.WEEK_NUMBER,
firstWeekday = firstWeekday,
isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0
val valueThisWeek = entries.groupedSum(
truncateField = DateUtils.TruncateField.WEEK_NUMBER,
firstWeekday = firstWeekday,
isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0
val valueThisMonth = entries.groupedSum(
truncateField = DateUtils.TruncateField.MONTH,
isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0
val valueThisMonth = entries.groupedSum(
truncateField = DateUtils.TruncateField.MONTH,
isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0
val valueThisQuarter = entries.groupedSum(
truncateField = DateUtils.TruncateField.QUARTER,
isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0
val valueThisQuarter = entries.groupedSum(
truncateField = DateUtils.TruncateField.QUARTER,
isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0
val valueThisYear = entries.groupedSum(
truncateField = DateUtils.TruncateField.YEAR,
isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0
val valueThisYear = entries.groupedSum(
truncateField = DateUtils.TruncateField.YEAR,
isNumerical = habit.isNumerical
).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 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 targetToday = habit.targetValue / habit.frequency.denominator
val targetThisWeek = targetToday * 7
val targetThisMonth = targetToday * daysInMonth
val targetThisQuarter = targetToday * daysInQuarter
val targetThisYear = targetToday * daysInYear
val values = ArrayList<Double>()
if (habit.frequency.denominator <= 1) values.add(valueToday / 1e3)
if (habit.frequency.denominator <= 7) values.add(valueThisWeek / 1e3)
values.add(valueThisMonth / 1e3)
values.add(valueThisQuarter / 1e3)
values.add(valueThisYear / 1e3)
val values = ArrayList<Double>()
if (habit.frequency.denominator <= 1) values.add(valueToday / 1e3)
if (habit.frequency.denominator <= 7) values.add(valueThisWeek / 1e3)
values.add(valueThisMonth / 1e3)
values.add(valueThisQuarter / 1e3)
values.add(valueThisYear / 1e3)
val targets = ArrayList<Double>()
if (habit.frequency.denominator <= 1) targets.add(targetToday)
if (habit.frequency.denominator <= 7) targets.add(targetThisWeek)
targets.add(targetThisMonth)
targets.add(targetThisQuarter)
targets.add(targetThisYear)
val targets = ArrayList<Double>()
if (habit.frequency.denominator <= 1) targets.add(targetToday)
if (habit.frequency.denominator <= 7) targets.add(targetThisWeek)
targets.add(targetThisMonth)
targets.add(targetThisQuarter)
targets.add(targetThisYear)
val intervals = ArrayList<Int>()
if (habit.frequency.denominator <= 1) intervals.add(1)
if (habit.frequency.denominator <= 7) intervals.add(7)
intervals.add(30)
intervals.add(91)
intervals.add(365)
val intervals = ArrayList<Int>()
if (habit.frequency.denominator <= 1) intervals.add(1)
if (habit.frequency.denominator <= 7) intervals.add(7)
intervals.add(30)
intervals.add(91)
intervals.add(365)
return TargetCardViewModel(
color = habit.color,
values = values,
targets = targets,
intervals = intervals,
)
return TargetCardState(
color = habit.color,
values = values,
targets = targets,
intervals = intervals,
)
}
}
}

View File

@@ -31,25 +31,25 @@ import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
public class ShowHabitMenuBehaviorTest extends BaseUnitTest
public class ShowHabitMenuPresenterTest extends BaseUnitTest
{
private ShowHabitMenuBehavior.System system;
private ShowHabitMenuPresenter.System system;
private ShowHabitMenuBehavior.Screen screen;
private ShowHabitMenuPresenter.Screen screen;
private Habit habit;
private ShowHabitMenuBehavior menu;
private ShowHabitMenuPresenter menu;
@Override
public void setUp() throws Exception
{
super.setUp();
system = mock(ShowHabitMenuBehavior.System.class);
screen = mock(ShowHabitMenuBehavior.Screen.class);
system = mock(ShowHabitMenuPresenter.System.class);
screen = mock(ShowHabitMenuPresenter.Screen.class);
habit = fixtures.createShortHabit();
menu = new ShowHabitMenuBehavior(commandRunner, habit, habitList, screen, system, taskRunner);
menu = new ShowHabitMenuPresenter(commandRunner, habit, habitList, screen, system, taskRunner);
}
@Test