mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-07 01:28:52 -06:00
Remove ShowHabitScreen and ShowHabitBehavior
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user