ShowHabitActivity: Move presenters and view models to uhabits-core

pull/707/head
Alinson S. Xavier 5 years ago
parent 1cdbc53dc5
commit 13826f4934

@ -23,8 +23,8 @@ import androidx.test.ext.junit.runners.*;
import androidx.test.filters.*; import androidx.test.filters.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.show.views.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.ui.screens.habits.show.views.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
import org.junit.*; import org.junit.*;
import org.junit.runner.*; import org.junit.runner.*;
@ -49,8 +49,8 @@ public class ScoreChartTest extends BaseViewTest
fixtures.purgeHabits(habitList); fixtures.purgeHabits(habitList);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
presenter = new ScoreCardPresenter(habit, prefs.getFirstWeekday()); presenter = new ScoreCardPresenter();
ScoreCardViewModel model = presenter.present(0); ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekday(), 0);
view = new ScoreChart(targetContext); view = new ScoreChart(targetContext);
view.setScores(model.getScores()); view.setScores(model.getScores());
@ -84,7 +84,7 @@ public class ScoreChartTest extends BaseViewTest
@Test @Test
public void testRender_withMonthlyBucket() throws Throwable public void testRender_withMonthlyBucket() throws Throwable
{ {
ScoreCardViewModel model = presenter.present(2); ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekday(), 2);
view.setScores(model.getScores()); view.setScores(model.getScores());
view.setBucketSize(model.getBucketSize()); view.setBucketSize(model.getBucketSize());
view.invalidate(); view.invalidate();
@ -102,7 +102,7 @@ public class ScoreChartTest extends BaseViewTest
@Test @Test
public void testRender_withYearlyBucket() throws Throwable public void testRender_withYearlyBucket() throws Throwable
{ {
ScoreCardViewModel model = presenter.present(4); ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekday(), 4);
view.setScores(model.getScores()); view.setScores(model.getScores());
view.setBucketSize(model.getBucketSize()); view.setBucketSize(model.getBucketSize());
view.invalidate(); view.invalidate();

@ -24,15 +24,16 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.ui.screens.habits.show.views.FrequencyCardPresenter
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@MediumTest @MediumTest
class FrequencyCardTest : BaseViewTest() { class FrequencyCardViewTest : BaseViewTest() {
val PATH = "habits/show/FrequencyCard/" val PATH = "habits/show/FrequencyCard/"
private lateinit var view: FrequencyCard private lateinit var view: FrequencyCardView
@Before @Before
override fun setUp() { override fun setUp() {
@ -41,8 +42,8 @@ class FrequencyCardTest : BaseViewTest() {
view = LayoutInflater view = LayoutInflater
.from(targetContext) .from(targetContext)
.inflate(R.layout.show_habit, null) .inflate(R.layout.show_habit, null)
.findViewById<View>(R.id.frequencyCard) as FrequencyCard .findViewById<View>(R.id.frequencyCard) as FrequencyCardView
view.update(FrequencyCardPresenter(habit, 0).present()) view.update(FrequencyCardPresenter().present(habit = habit, firstWeekday = 0))
measureView(view, 800f, 600f) measureView(view, 800f, 600f)
} }

@ -24,14 +24,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@MediumTest @MediumTest
class HistoryCardTest : BaseViewTest() { class HistoryCardViewTest : BaseViewTest() {
private lateinit var view: HistoryCard private lateinit var view: HistoryCardView
val PATH = "habits/show/HistoryCard/" val PATH = "habits/show/HistoryCard/"
@Before @Before
@ -41,13 +42,13 @@ class HistoryCardTest : BaseViewTest() {
view = LayoutInflater view = LayoutInflater
.from(targetContext) .from(targetContext)
.inflate(R.layout.show_habit, null) .inflate(R.layout.show_habit, null)
.findViewById<View>(R.id.historyCard) as HistoryCard .findViewById<View>(R.id.historyCard) as HistoryCardView
view.update( view.update(
HistoryCardPresenter( HistoryCardPresenter().present(
habit = habit, habit = habit,
firstWeekday = 1, firstWeekday = 1,
isSkipEnabled = false isSkipEnabled = false
).present() )
) )
measureView(view, 800f, 600f) measureView(view, 800f, 600f)
} }

@ -25,6 +25,7 @@ import androidx.test.filters.MediumTest
import org.hamcrest.Matchers.equalTo import org.hamcrest.Matchers.equalTo
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.ui.screens.habits.show.views.NotesCardViewModel
import org.junit.Assert.assertThat import org.junit.Assert.assertThat
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

@ -25,6 +25,7 @@ import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.ui.screens.habits.show.views.OverviewCardViewModel
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith

@ -24,15 +24,16 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardPresenter
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@MediumTest @MediumTest
class ScoreCardTest : BaseViewTest() { class ScoreCardViewTest : BaseViewTest() {
val PATH = "habits/show/ScoreCard/" val PATH = "habits/show/ScoreCard/"
private lateinit var view: ScoreCard private lateinit var view: ScoreCardView
@Before @Before
override fun setUp() { override fun setUp() {
@ -41,8 +42,14 @@ class ScoreCardTest : BaseViewTest() {
view = LayoutInflater view = LayoutInflater
.from(targetContext) .from(targetContext)
.inflate(R.layout.show_habit, null) .inflate(R.layout.show_habit, null)
.findViewById<View>(R.id.scoreCard) as ScoreCard .findViewById<View>(R.id.scoreCard) as ScoreCardView
view.update(ScoreCardPresenter(habit, 0).present(0)) view.update(
ScoreCardPresenter().present(
habit = habit,
firstWeekday = 0,
spinnerPosition = 0,
)
)
measureView(view, 800f, 600f) measureView(view, 800f, 600f)
} }

@ -24,6 +24,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.ui.screens.habits.show.views.StreakCardViewModel
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith

@ -23,7 +23,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.Frequency
import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Reminder
import org.isoron.uhabits.core.models.WeekdayList.EVERY_DAY
import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardViewModel
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -44,11 +48,12 @@ class SubtitleCardViewTest : BaseViewTest() {
view.update( view.update(
SubtitleCardViewModel( SubtitleCardViewModel(
color = PaletteColor(7), color = PaletteColor(7),
frequencyText = "3 times in 7 days", frequency = Frequency(3, 7),
isNumerical = false, isNumerical = false,
question = "Did you meditate this morning?", question = "Did you meditate this morning?",
reminderText = "8:30 AM", reminder = Reminder(8, 30, EVERY_DAY),
targetText = "", unit = "",
targetValue = 0.0,
) )
) )
measureView(view, 800f, 200f) measureView(view, 800f, 200f)

@ -31,12 +31,12 @@ import android.util.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.common.views.*; import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.activities.habits.show.views.*;
import org.isoron.uhabits.core.commands.*; import org.isoron.uhabits.core.commands.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*; import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.tasks.*; import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.core.ui.callbacks.*; import org.isoron.uhabits.core.ui.callbacks.*;
import org.isoron.uhabits.core.ui.screens.habits.show.views.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
import org.jetbrains.annotations.*; import org.jetbrains.annotations.*;
@ -179,11 +179,11 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
@Override @Override
public void doInBackground() public void doInBackground()
{ {
HistoryCardViewModel model = new HistoryCardPresenter( HistoryCardViewModel model = new HistoryCardPresenter().present(
habit, habit,
prefs.getFirstWeekday(), prefs.getFirstWeekday(),
prefs.isSkipEnabled() prefs.isSkipEnabled()
).present(); );
checkmarks = model.getEntries(); checkmarks = model.getEntries();
} }

@ -34,16 +34,22 @@ import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialogFactory
import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory
import org.isoron.uhabits.core.commands.Command import org.isoron.uhabits.core.commands.Command
import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitBehavior import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitBehavior
import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitMenuBehavior import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitMenuBehavior
import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitPresenter
import org.isoron.uhabits.intents.IntentFactory import org.isoron.uhabits.intents.IntentFactory
class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
private val presenter = ShowHabitPresenter()
private lateinit var commandRunner: CommandRunner private lateinit var commandRunner: CommandRunner
private lateinit var menu: ShowHabitMenu private lateinit var menu: ShowHabitMenu
private lateinit var presenter: ShowHabitPresenter
private lateinit var view: ShowHabitView private lateinit var view: ShowHabitView
private lateinit var habit: Habit
private lateinit var preferences: Preferences
private val scope = CoroutineScope(Dispatchers.Main) private val scope = CoroutineScope(Dispatchers.Main)
@ -52,17 +58,12 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
val appComponent = (applicationContext as HabitsApplication).component val appComponent = (applicationContext as HabitsApplication).component
val habitList = appComponent.habitList val habitList = appComponent.habitList
val habit = habitList.getById(ContentUris.parseId(intent.data!!))!! habit = habitList.getById(ContentUris.parseId(intent.data!!))!!
val preferences = appComponent.preferences preferences = appComponent.preferences
commandRunner = appComponent.commandRunner commandRunner = appComponent.commandRunner
AndroidThemeSwitcher(this, preferences).apply() AndroidThemeSwitcher(this, preferences).apply()
view = ShowHabitView(this) view = ShowHabitView(this)
presenter = ShowHabitPresenter(
context = this,
habit = habit,
preferences = appComponent.preferences,
)
val screen = ShowHabitScreen( val screen = ShowHabitScreen(
activity = this, activity = this,
@ -129,7 +130,12 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
fun refresh() { fun refresh() {
scope.launch { scope.launch {
view.update(presenter.present()) view.update(
presenter.present(
habit = habit,
preferences = preferences,
)
)
} }
} }
} }

@ -22,45 +22,10 @@ package org.isoron.uhabits.activities.habits.show
import android.content.Context import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.FrameLayout import android.widget.FrameLayout
import org.isoron.uhabits.activities.habits.show.views.BarCardPresenter import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitViewModel
import org.isoron.uhabits.activities.habits.show.views.BarCardViewModel
import org.isoron.uhabits.activities.habits.show.views.FrequencyCardPresenter
import org.isoron.uhabits.activities.habits.show.views.FrequencyCardViewModel
import org.isoron.uhabits.activities.habits.show.views.HistoryCardPresenter
import org.isoron.uhabits.activities.habits.show.views.HistoryCardViewModel
import org.isoron.uhabits.activities.habits.show.views.NotesCardPresenter
import org.isoron.uhabits.activities.habits.show.views.NotesCardViewModel
import org.isoron.uhabits.activities.habits.show.views.OverviewCardPresenter
import org.isoron.uhabits.activities.habits.show.views.OverviewCardViewModel
import org.isoron.uhabits.activities.habits.show.views.ScoreCardPresenter
import org.isoron.uhabits.activities.habits.show.views.ScoreCardViewModel
import org.isoron.uhabits.activities.habits.show.views.StreakCardViewModel
import org.isoron.uhabits.activities.habits.show.views.StreakCartPresenter
import org.isoron.uhabits.activities.habits.show.views.SubtitleCardPresenter
import org.isoron.uhabits.activities.habits.show.views.SubtitleCardViewModel
import org.isoron.uhabits.activities.habits.show.views.TargetCardPresenter
import org.isoron.uhabits.activities.habits.show.views.TargetCardViewModel
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.databinding.ShowHabitBinding import org.isoron.uhabits.databinding.ShowHabitBinding
import org.isoron.uhabits.utils.setupToolbar import org.isoron.uhabits.utils.setupToolbar
data class ShowHabitViewModel(
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,
)
class ShowHabitView(context: Context) : FrameLayout(context) { class ShowHabitView(context: Context) : FrameLayout(context) {
private val binding = ShowHabitBinding.inflate(LayoutInflater.from(context)) private val binding = ShowHabitBinding.inflate(LayoutInflater.from(context))
@ -96,58 +61,3 @@ class ShowHabitView(context: Context) : FrameLayout(context) {
} }
} }
} }
class ShowHabitPresenter(
val habit: Habit,
val context: Context,
val preferences: Preferences,
) {
private val subtitleCardPresenter = SubtitleCardPresenter(habit, context)
private val overviewCardPresenter = OverviewCardPresenter(habit)
private val notesCardPresenter = NotesCardPresenter(habit)
private val targetCardPresenter = TargetCardPresenter(
habit = habit,
firstWeekday = preferences.firstWeekday,
resources = context.resources,
)
private val streakCartPresenter = StreakCartPresenter(habit)
private val scoreCardPresenter = ScoreCardPresenter(
habit = habit,
firstWeekday = preferences.firstWeekday,
)
private val frequencyCardPresenter = FrequencyCardPresenter(
habit = habit,
firstWeekday = preferences.firstWeekday,
)
private val historyCardViewModel = HistoryCardPresenter(
habit = habit,
firstWeekday = preferences.firstWeekday,
isSkipEnabled = preferences.isSkipEnabled,
)
private val barCardPresenter = BarCardPresenter(
habit = habit,
firstWeekday = preferences.firstWeekday,
)
suspend fun present(): ShowHabitViewModel {
return ShowHabitViewModel(
title = habit.name,
color = habit.color,
isNumerical = habit.isNumerical,
subtitle = subtitleCardPresenter.present(),
overview = overviewCardPresenter.present(),
notes = notesCardPresenter.present(),
target = targetCardPresenter.present(),
streaks = streakCartPresenter.present(),
scores = scoreCardPresenter.present(
spinnerPosition = preferences.scoreCardSpinnerPosition
),
frequency = frequencyCardPresenter.present(),
history = historyCardViewModel.present(),
bar = barCardPresenter.present(
boolSpinnerPosition = preferences.barCardBoolSpinnerPosition,
numericalSpinnerPosition = preferences.barCardNumericalSpinnerPosition,
),
)
}
}

@ -24,25 +24,11 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.LinearLayout import android.widget.LinearLayout
import org.isoron.uhabits.activities.habits.show.views.ScoreCardPresenter.Companion.getTruncateField import org.isoron.uhabits.core.ui.screens.habits.show.views.BarCardViewModel
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.utils.DateUtils
import org.isoron.uhabits.databinding.ShowHabitBarBinding import org.isoron.uhabits.databinding.ShowHabitBarBinding
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
data class BarCardViewModel( class BarCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
val entries: List<Entry>,
val bucketSize: Int,
val color: PaletteColor,
val isNumerical: Boolean,
val numericalSpinnerPosition: Int,
val boolSpinnerPosition: Int,
)
class BarCard(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private var binding = ShowHabitBarBinding.inflate(LayoutInflater.from(context), this) private var binding = ShowHabitBarBinding.inflate(LayoutInflater.from(context), this)
var onNumericalSpinnerPosition: (position: Int) -> Unit = {} var onNumericalSpinnerPosition: (position: Int) -> Unit = {}
@ -94,37 +80,3 @@ class BarCard(context: Context, attrs: AttributeSet) : LinearLayout(context, att
} }
} }
} }
class BarCardPresenter(
val habit: Habit,
val firstWeekday: Int,
) {
val numericalBucketSizes = intArrayOf(1, 7, 31, 92, 365)
val boolBucketSizes = intArrayOf(7, 31, 92, 365)
fun present(
numericalSpinnerPosition: Int,
boolSpinnerPosition: Int,
): BarCardViewModel {
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 = getTruncateField(bucketSize),
firstWeekday = firstWeekday,
isNumerical = habit.isNumerical,
)
return BarCardViewModel(
entries = entries,
bucketSize = bucketSize,
color = habit.color,
isNumerical = habit.isNumerical,
numericalSpinnerPosition = numericalSpinnerPosition,
boolSpinnerPosition = boolSpinnerPosition,
)
}
}

@ -22,20 +22,11 @@ import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.ui.screens.habits.show.views.FrequencyCardViewModel
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.databinding.ShowHabitFrequencyBinding import org.isoron.uhabits.databinding.ShowHabitFrequencyBinding
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
import java.util.HashMap
data class FrequencyCardViewModel( class FrequencyCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
val frequency: HashMap<Timestamp, Array<Int>>,
val firstWeekday: Int,
val color: PaletteColor,
)
class FrequencyCard(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private var binding = ShowHabitFrequencyBinding.inflate(LayoutInflater.from(context), this) private var binding = ShowHabitFrequencyBinding.inflate(LayoutInflater.from(context), this)
@ -47,16 +38,3 @@ class FrequencyCard(context: Context, attrs: AttributeSet) : LinearLayout(contex
binding.frequencyChart.setColor(androidColor) binding.frequencyChart.setColor(androidColor)
} }
} }
class FrequencyCardPresenter(
val habit: Habit,
val firstWeekday: Int,
) {
fun present() = FrequencyCardViewModel(
color = habit.color,
frequency = habit.originalEntries.computeWeekdayFrequency(
isNumerical = habit.isNumerical
),
firstWeekday = firstWeekday,
)
}

@ -22,21 +22,11 @@ import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardViewModel
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.utils.DateUtils
import org.isoron.uhabits.databinding.ShowHabitHistoryBinding import org.isoron.uhabits.databinding.ShowHabitHistoryBinding
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
data class HistoryCardViewModel( class HistoryCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
val entries: IntArray,
val color: PaletteColor,
val firstWeekday: Int,
val isNumerical: Boolean,
val isSkipEnabled: Boolean,
)
class HistoryCard(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private var binding = ShowHabitHistoryBinding.inflate(LayoutInflater.from(context), this) private var binding = ShowHabitHistoryBinding.inflate(LayoutInflater.from(context), this)
@ -58,23 +48,3 @@ class HistoryCard(context: Context, attrs: AttributeSet) : LinearLayout(context,
} }
} }
} }
class HistoryCardPresenter(
val habit: Habit,
val firstWeekday: Int,
val isSkipEnabled: Boolean,
) {
fun present(): HistoryCardViewModel {
val today = DateUtils.getTodayWithOffset()
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
val entries = habit.computedEntries.getByInterval(oldest, today).map { it.value }.toIntArray()
return HistoryCardViewModel(
entries = entries,
color = habit.color,
firstWeekday = firstWeekday,
isNumerical = habit.isNumerical,
isSkipEnabled = isSkipEnabled,
)
}
}

@ -23,11 +23,9 @@ import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.ui.screens.habits.show.views.NotesCardViewModel
import org.isoron.uhabits.databinding.ShowHabitNotesBinding import org.isoron.uhabits.databinding.ShowHabitNotesBinding
data class NotesCardViewModel(val description: String)
class NotesCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { class NotesCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private val binding = ShowHabitNotesBinding.inflate(LayoutInflater.from(context), this) private val binding = ShowHabitNotesBinding.inflate(LayoutInflater.from(context), this)
fun update(data: NotesCardViewModel) { fun update(data: NotesCardViewModel) {
@ -40,9 +38,3 @@ class NotesCardView(context: Context, attrs: AttributeSet) : LinearLayout(contex
invalidate() invalidate()
} }
} }
class NotesCardPresenter(val habit: Habit) {
fun present() = NotesCardViewModel(
description = habit.description,
)
}

@ -22,25 +22,12 @@ import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.invoke
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL import org.isoron.uhabits.core.ui.screens.habits.show.views.OverviewCardViewModel
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.utils.DateUtils
import org.isoron.uhabits.databinding.ShowHabitOverviewBinding import org.isoron.uhabits.databinding.ShowHabitOverviewBinding
import org.isoron.uhabits.utils.StyledResources import org.isoron.uhabits.utils.StyledResources
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
data class OverviewCardViewModel(
val color: PaletteColor,
val scoreMonthDiff: Float,
val scoreYearDiff: Float,
val scoreToday: Float,
val totalCount: Long,
)
class OverviewCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { class OverviewCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private val binding = ShowHabitOverviewBinding.inflate(LayoutInflater.from(context), this) private val binding = ShowHabitOverviewBinding.inflate(LayoutInflater.from(context), this)
@ -71,26 +58,3 @@ class OverviewCardView(context: Context, attrs: AttributeSet) : LinearLayout(con
postInvalidate() postInvalidate()
} }
} }
class OverviewCardPresenter(val habit: Habit) {
suspend fun present(): OverviewCardViewModel = Dispatchers.IO {
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 == YES_MANUAL }
.count()
.toLong()
return@IO OverviewCardViewModel(
color = habit.color,
scoreToday = scoreToday,
scoreMonthDiff = scoreToday - scoreLastMonth,
scoreYearDiff = scoreToday - scoreLastYear,
totalCount = totalCount,
)
}
}

@ -1,114 +0,0 @@
/*
* Copyright (C) 2016 Á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.activities.habits.show.views
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.AdapterView
import android.widget.LinearLayout
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.utils.DateUtils
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.DAY
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.MONTH
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.QUARTER
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.WEEK_NUMBER
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.YEAR
import org.isoron.uhabits.databinding.ShowHabitScoreBinding
import org.isoron.uhabits.utils.toThemedAndroidColor
data class ScoreCardViewModel(
val scores: List<Score>,
val bucketSize: Int,
val spinnerPosition: Int,
val color: PaletteColor,
)
class ScoreCard(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private var binding = ShowHabitScoreBinding.inflate(LayoutInflater.from(context), this)
var onSpinnerPosition: (position: Int) -> Unit = {}
fun update(data: ScoreCardViewModel) {
val androidColor = data.color.toThemedAndroidColor(context)
binding.title.setTextColor(androidColor)
binding.spinner.setSelection(data.spinnerPosition)
binding.scoreView.setScores(data.scores)
binding.scoreView.reset()
binding.scoreView.setBucketSize(data.bucketSize)
binding.scoreView.setColor(androidColor)
binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
onSpinnerPosition(position)
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
}
}
class ScoreCardPresenter(
val habit: Habit,
val firstWeekday: Int,
) {
companion object {
val BUCKET_SIZES = intArrayOf(1, 7, 31, 92, 365)
fun getTruncateField(bucketSize: Int): DateUtils.TruncateField {
when (bucketSize) {
1 -> return DAY
7 -> return WEEK_NUMBER
31 -> return MONTH
92 -> return QUARTER
365 -> return YEAR
else -> return MONTH
}
}
}
fun present(spinnerPosition: Int): ScoreCardViewModel {
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 ScoreCardViewModel(
color = habit.color,
scores = scores,
bucketSize = bucketSize,
spinnerPosition = spinnerPosition,
)
}
}

@ -0,0 +1,59 @@
/*
* Copyright (C) 2016 Á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.activities.habits.show.views
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.AdapterView
import android.widget.LinearLayout
import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardViewModel
import org.isoron.uhabits.databinding.ShowHabitScoreBinding
import org.isoron.uhabits.utils.toThemedAndroidColor
class ScoreCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private var binding = ShowHabitScoreBinding.inflate(LayoutInflater.from(context), this)
var onSpinnerPosition: (position: Int) -> Unit = {}
fun update(data: ScoreCardViewModel) {
val androidColor = data.color.toThemedAndroidColor(context)
binding.title.setTextColor(androidColor)
binding.spinner.setSelection(data.spinnerPosition)
binding.scoreView.setScores(data.scores)
binding.scoreView.reset()
binding.scoreView.setBucketSize(data.bucketSize)
binding.scoreView.setColor(androidColor)
binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
onSpinnerPosition(position)
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
}
}

@ -22,19 +22,10 @@ import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import kotlinx.coroutines.Dispatchers import org.isoron.uhabits.core.ui.screens.habits.show.views.StreakCardViewModel
import kotlinx.coroutines.invoke
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Streak
import org.isoron.uhabits.databinding.ShowHabitStreakBinding import org.isoron.uhabits.databinding.ShowHabitStreakBinding
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
data class StreakCardViewModel(
val color: PaletteColor,
val bestStreaks: List<Streak>
)
class StreakCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { class StreakCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private val binding = ShowHabitStreakBinding.inflate(LayoutInflater.from(context), this) private val binding = ShowHabitStreakBinding.inflate(LayoutInflater.from(context), this)
fun update(data: StreakCardViewModel) { fun update(data: StreakCardViewModel) {
@ -45,12 +36,3 @@ class StreakCardView(context: Context, attrs: AttributeSet) : LinearLayout(conte
postInvalidate() postInvalidate()
} }
} }
class StreakCartPresenter(val habit: Habit) {
suspend fun present(): StreakCardViewModel = Dispatchers.IO {
return@IO StreakCardViewModel(
color = habit.color,
bestStreaks = habit.streaks.getBest(10),
)
}
}

@ -28,23 +28,13 @@ import android.widget.LinearLayout
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.activities.habits.list.views.toShortString import org.isoron.uhabits.activities.habits.list.views.toShortString
import org.isoron.uhabits.core.models.Frequency import org.isoron.uhabits.core.models.Frequency
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardViewModel
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.databinding.ShowHabitSubtitleBinding import org.isoron.uhabits.databinding.ShowHabitSubtitleBinding
import org.isoron.uhabits.utils.InterfaceUtils import org.isoron.uhabits.utils.InterfaceUtils
import org.isoron.uhabits.utils.formatTime import org.isoron.uhabits.utils.formatTime
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
import java.util.Locale import java.util.Locale
data class SubtitleCardViewModel(
val color: PaletteColor,
val frequencyText: String,
val isNumerical: Boolean,
val question: String,
val reminderText: String,
val targetText: String,
)
class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private val binding = ShowHabitSubtitleBinding.inflate(LayoutInflater.from(context), this) private val binding = ShowHabitSubtitleBinding.inflate(LayoutInflater.from(context), this)
@ -56,13 +46,19 @@ class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(con
binding.reminderIcon.typeface = fontAwesome binding.reminderIcon.typeface = fontAwesome
} }
@SuppressLint("SetTextI18n")
fun update(data: SubtitleCardViewModel) { fun update(data: SubtitleCardViewModel) {
val color = data.color.toThemedAndroidColor(context) val color = data.color.toThemedAndroidColor(context)
binding.frequencyLabel.text = data.frequencyText val reminder = data.reminder
binding.frequencyLabel.text = data.frequency.format(resources)
binding.questionLabel.setTextColor(color) binding.questionLabel.setTextColor(color)
binding.questionLabel.text = data.question binding.questionLabel.text = data.question
binding.reminderLabel.text = data.reminderText binding.reminderLabel.text = if (reminder != null) {
binding.targetText.text = data.targetText formatTime(context, reminder.hour, reminder.minute)
} else {
resources.getString(R.string.reminder_off)
}
binding.targetText.text = "${data.targetValue.toShortString()} ${data.unit}"
binding.questionLabel.visibility = View.VISIBLE binding.questionLabel.visibility = View.VISIBLE
binding.targetIcon.visibility = View.VISIBLE binding.targetIcon.visibility = View.VISIBLE
@ -77,32 +73,9 @@ class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(con
postInvalidate() postInvalidate()
} }
}
class SubtitleCardPresenter(
val habit: Habit,
val context: Context,
) {
val resources: Resources = context.resources
fun present(): SubtitleCardViewModel {
val reminderText = if (habit.hasReminder()) {
formatTime(context, habit.reminder!!.hour, habit.reminder!!.minute)!!
} else {
resources.getString(R.string.reminder_off)
}
return SubtitleCardViewModel(
color = habit.color,
frequencyText = habit.frequency.format(),
isNumerical = habit.isNumerical,
question = habit.question,
reminderText = reminderText,
targetText = "${habit.targetValue.toShortString()} ${habit.unit}",
)
}
@SuppressLint("StringFormatMatches") @SuppressLint("StringFormatMatches")
private fun Frequency.format(): String { private fun Frequency.format(resources: Resources): String {
val num = this.numerator val num = this.numerator
val den = this.denominator val den = this.denominator
if (num == den) { if (num == den) {

@ -0,0 +1,52 @@
/*
* Copyright (C) 2016 Á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.activities.habits.show.views
import android.content.Context
import android.content.res.Resources
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import org.isoron.uhabits.R
import org.isoron.uhabits.core.ui.screens.habits.show.views.TargetCardViewModel
import org.isoron.uhabits.databinding.ShowHabitTargetBinding
import org.isoron.uhabits.utils.toThemedAndroidColor
class TargetCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private val binding = ShowHabitTargetBinding.inflate(LayoutInflater.from(context), this)
fun update(data: TargetCardViewModel) {
val androidColor = data.color.toThemedAndroidColor(context)
binding.targetChart.setValues(data.values)
binding.targetChart.setTargets(data.targets)
binding.targetChart.setLabels(data.intervals.map { intervalToLabel(resources, it) })
binding.title.setTextColor(androidColor)
binding.targetChart.setColor(androidColor)
postInvalidate()
}
companion object {
fun intervalToLabel(resources: Resources, interval: Int) = when (interval) {
1 -> resources.getString(R.string.today)
7 -> resources.getString(R.string.week)
30 -> resources.getString(R.string.month)
91 -> resources.getString(R.string.quarter)
else -> resources.getString(R.string.year)
}
}
}

@ -23,8 +23,8 @@ import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.view.View import android.view.View
import org.isoron.uhabits.activities.common.views.HistoryChart import org.isoron.uhabits.activities.common.views.HistoryChart
import org.isoron.uhabits.activities.habits.show.views.HistoryCardPresenter
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
import org.isoron.uhabits.widgets.views.GraphWidgetView import org.isoron.uhabits.widgets.views.GraphWidgetView
@ -43,11 +43,11 @@ class HistoryWidget(
val widgetView = view as GraphWidgetView val widgetView = view as GraphWidgetView
widgetView.setBackgroundAlpha(preferedBackgroundAlpha) widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f) if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f)
val model = HistoryCardPresenter( val model = HistoryCardPresenter().present(
habit = habit, habit = habit,
isSkipEnabled = prefs.isSkipEnabled, isSkipEnabled = prefs.isSkipEnabled,
firstWeekday = prefs.firstWeekday, firstWeekday = prefs.firstWeekday,
).present() )
(widgetView.dataView as HistoryChart).apply { (widgetView.dataView as HistoryChart).apply {
setFirstWeekday(model.firstWeekday) setFirstWeekday(model.firstWeekday)
setSkipEnabled(model.isSkipEnabled) setSkipEnabled(model.isSkipEnabled)

@ -22,8 +22,8 @@ package org.isoron.uhabits.widgets
import android.content.Context import android.content.Context
import android.view.View import android.view.View
import org.isoron.uhabits.activities.common.views.ScoreChart import org.isoron.uhabits.activities.common.views.ScoreChart
import org.isoron.uhabits.activities.habits.show.views.ScoreCardPresenter
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardPresenter
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
import org.isoron.uhabits.widgets.views.GraphWidgetView import org.isoron.uhabits.widgets.views.GraphWidgetView
@ -37,8 +37,12 @@ class ScoreWidget(
pendingIntentFactory.showHabit(habit) pendingIntentFactory.showHabit(habit)
override fun refreshData(view: View) { override fun refreshData(view: View) {
val presenter = ScoreCardPresenter(habit, prefs.firstWeekday) val presenter = ScoreCardPresenter()
val viewModel = presenter.present(prefs.scoreCardSpinnerPosition) val viewModel = presenter.present(
habit = habit,
firstWeekday = prefs.firstWeekday,
spinnerPosition = prefs.scoreCardSpinnerPosition
)
val widgetView = view as GraphWidgetView val widgetView = view as GraphWidgetView
widgetView.setBackgroundAlpha(preferedBackgroundAlpha) widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f) if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f)

@ -25,8 +25,9 @@ import android.view.ViewGroup.LayoutParams
import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.isoron.uhabits.activities.common.views.TargetChart import org.isoron.uhabits.activities.common.views.TargetChart
import org.isoron.uhabits.activities.habits.show.views.TargetCardPresenter import org.isoron.uhabits.activities.habits.show.views.TargetCardView.Companion.intervalToLabel
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.ui.screens.habits.show.views.TargetCardPresenter
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
import org.isoron.uhabits.widgets.views.GraphWidgetView import org.isoron.uhabits.widgets.views.GraphWidgetView
@ -44,11 +45,11 @@ class TargetWidget(
widgetView.setBackgroundAlpha(preferedBackgroundAlpha) widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f) if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f)
val chart = (widgetView.dataView as TargetChart) val chart = (widgetView.dataView as TargetChart)
val presenter = TargetCardPresenter(habit, prefs.firstWeekday, context.resources) val presenter = TargetCardPresenter()
val data = presenter.present() val data = presenter.present(habit, prefs.firstWeekday)
chart.setColor(data.color.toThemedAndroidColor(context)) chart.setColor(data.color.toThemedAndroidColor(context))
chart.setTargets(data.targets) chart.setTargets(data.targets)
chart.setLabels(data.labels) chart.setLabels(data.intervals.map { intervalToLabel(context.resources, it) })
chart.setValues(data.values) chart.setValues(data.values)
} }

@ -62,17 +62,17 @@
style="@style/Card" style="@style/Card"
android:paddingTop="12dp"/> android:paddingTop="12dp"/>
<org.isoron.uhabits.activities.habits.show.views.ScoreCard <org.isoron.uhabits.activities.habits.show.views.ScoreCardView
android:id="@+id/scoreCard" android:id="@+id/scoreCard"
style="@style/Card" style="@style/Card"
android:gravity="center"/> android:gravity="center"/>
<org.isoron.uhabits.activities.habits.show.views.BarCard <org.isoron.uhabits.activities.habits.show.views.BarCardView
android:id="@+id/barCard" android:id="@+id/barCard"
style="@style/Card" style="@style/Card"
android:gravity="center"/> android:gravity="center"/>
<org.isoron.uhabits.activities.habits.show.views.HistoryCard <org.isoron.uhabits.activities.habits.show.views.HistoryCardView
android:id="@+id/historyCard" android:id="@+id/historyCard"
style="@style/Card" style="@style/Card"
android:gravity="center" android:gravity="center"
@ -82,7 +82,7 @@
android:id="@+id/streakCard" android:id="@+id/streakCard"
style="@style/Card"/> style="@style/Card"/>
<org.isoron.uhabits.activities.habits.show.views.FrequencyCard <org.isoron.uhabits.activities.habits.show.views.FrequencyCardView
android:id="@+id/frequencyCard" android:id="@+id/frequencyCard"
style="@style/Card"/> style="@style/Card"/>

@ -0,0 +1,106 @@
/*
* Copyright (C) 2016-2020 Á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.uhabits.core.models.Habit
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.FrequencyCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.FrequencyCardViewModel
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.NotesCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.NotesCardViewModel
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.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.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.TargetCardPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.views.TargetCardViewModel
data class ShowHabitViewModel(
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,
)
class ShowHabitPresenter {
fun present(
habit: Habit,
preferences: Preferences,
): 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.firstWeekday,
),
streaks = StreakCartPresenter().present(
habit = habit,
),
scores = ScoreCardPresenter().present(
spinnerPosition = preferences.scoreCardSpinnerPosition,
habit = habit,
firstWeekday = preferences.firstWeekday,
),
frequency = FrequencyCardPresenter().present(
habit = habit,
firstWeekday = preferences.firstWeekday,
),
history = HistoryCardPresenter().present(
habit = habit,
firstWeekday = preferences.firstWeekday,
isSkipEnabled = preferences.isSkipEnabled,
),
bar = BarCardPresenter().present(
habit = habit,
firstWeekday = preferences.firstWeekday,
boolSpinnerPosition = preferences.barCardBoolSpinnerPosition,
numericalSpinnerPosition = preferences.barCardNumericalSpinnerPosition,
),
)
}
}

@ -0,0 +1,68 @@
/*
* Copyright (C) 2016-2020 Á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.views
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.utils.DateUtils
data class BarCardViewModel(
val boolSpinnerPosition: Int,
val bucketSize: Int,
val color: PaletteColor,
val entries: List<Entry>,
val isNumerical: Boolean,
val numericalSpinnerPosition: Int,
)
class BarCardPresenter {
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,
): BarCardViewModel {
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 BarCardViewModel(
entries = entries,
bucketSize = bucketSize,
color = habit.color,
isNumerical = habit.isNumerical,
numericalSpinnerPosition = numericalSpinnerPosition,
boolSpinnerPosition = boolSpinnerPosition,
)
}
}

@ -0,0 +1,44 @@
/*
* Copyright (C) 2016-2020 Á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.views
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Timestamp
import java.util.HashMap
data class FrequencyCardViewModel(
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,
)
}

@ -0,0 +1,53 @@
/*
* Copyright (C) 2016-2020 Á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.views
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.utils.DateUtils
data class HistoryCardViewModel(
val color: PaletteColor,
val entries: IntArray,
val firstWeekday: Int,
val isNumerical: Boolean,
val isSkipEnabled: Boolean,
)
class HistoryCardPresenter {
fun present(
habit: Habit,
firstWeekday: Int,
isSkipEnabled: Boolean,
): HistoryCardViewModel {
val today = DateUtils.getTodayWithOffset()
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
val entries =
habit.computedEntries.getByInterval(oldest, today).map { it.value }.toIntArray()
return HistoryCardViewModel(
entries = entries,
color = habit.color,
firstWeekday = firstWeekday,
isNumerical = habit.isNumerical,
isSkipEnabled = isSkipEnabled,
)
}
}

@ -0,0 +1,32 @@
/*
* Copyright (C) 2016-2020 Á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.views
import org.isoron.uhabits.core.models.Habit
data class NotesCardViewModel(
val description: String,
)
class NotesCardPresenter {
fun present(habit: Habit) = NotesCardViewModel(
description = habit.description,
)
}

@ -0,0 +1,56 @@
/*
* Copyright (C) 2016-2020 Á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.views
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.utils.DateUtils
data class OverviewCardViewModel(
val color: PaletteColor,
val scoreMonthDiff: Float,
val scoreYearDiff: Float,
val scoreToday: Float,
val totalCount: Long,
)
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,
)
}
}

@ -0,0 +1,79 @@
/*
* Copyright (C) 2016-2020 Á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.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.utils.DateUtils
data class ScoreCardViewModel(
val scores: List<Score>,
val bucketSize: Int,
val spinnerPosition: Int,
val color: PaletteColor,
)
class ScoreCardPresenter {
companion object {
val BUCKET_SIZES = intArrayOf(1, 7, 31, 92, 365)
fun getTruncateField(bucketSize: Int): DateUtils.TruncateField {
when (bucketSize) {
1 -> return DateUtils.TruncateField.DAY
7 -> return DateUtils.TruncateField.WEEK_NUMBER
31 -> return DateUtils.TruncateField.MONTH
92 -> return DateUtils.TruncateField.QUARTER
365 -> return DateUtils.TruncateField.YEAR
else -> return DateUtils.TruncateField.MONTH
}
}
}
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
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,
)
}
}

@ -0,0 +1,38 @@
/*
* Copyright (C) 2016-2020 Á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.views
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Streak
data class StreakCardViewModel(
val color: PaletteColor,
val bestStreaks: List<Streak>
)
class StreakCartPresenter {
fun present(habit: Habit): StreakCardViewModel {
return StreakCardViewModel(
color = habit.color,
bestStreaks = habit.streaks.getBest(10),
)
}
}

@ -0,0 +1,49 @@
/*
* Copyright (C) 2016-2020 Á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.views
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.models.Reminder
data class SubtitleCardViewModel(
val color: PaletteColor,
val frequency: Frequency,
val isNumerical: Boolean,
val question: String,
val reminder: Reminder?,
val targetValue: Double,
val unit: String,
)
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,
)
}

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com> * Copyright (C) 2016-2020 Álinson Santos Xavier <isoron@gmail.com>
* *
* This file is part of Loop Habit Tracker. * This file is part of Loop Habit Tracker.
* *
@ -16,27 +16,13 @@
* You should have received a copy of the GNU General Public License along * You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.isoron.uhabits.activities.habits.show.views
import android.content.Context package org.isoron.uhabits.core.ui.screens.habits.show.views
import android.content.res.Resources
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.invoke
import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.groupedSum import org.isoron.uhabits.core.models.groupedSum
import org.isoron.uhabits.core.utils.DateUtils import org.isoron.uhabits.core.utils.DateUtils
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.DAY
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.MONTH
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.QUARTER
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.WEEK_NUMBER
import org.isoron.uhabits.core.utils.DateUtils.TruncateField.YEAR
import org.isoron.uhabits.databinding.ShowHabitTargetBinding
import org.isoron.uhabits.utils.toThemedAndroidColor
import java.util.ArrayList import java.util.ArrayList
import java.util.Calendar import java.util.Calendar
@ -44,55 +30,41 @@ data class TargetCardViewModel(
val color: PaletteColor, val color: PaletteColor,
val values: List<Double> = listOf(), val values: List<Double> = listOf(),
val targets: List<Double> = listOf(), val targets: List<Double> = listOf(),
val labels: List<String> = listOf(), val intervals: List<Int> = listOf(),
) )
class TargetCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { class TargetCardPresenter {
private val binding = ShowHabitTargetBinding.inflate(LayoutInflater.from(context), this) fun present(
fun update(data: TargetCardViewModel) { habit: Habit,
val androidColor = data.color.toThemedAndroidColor(context) firstWeekday: Int,
binding.targetChart.setValues(data.values) ): TargetCardViewModel {
binding.targetChart.setTargets(data.targets)
binding.targetChart.setLabels(data.labels)
binding.title.setTextColor(androidColor)
binding.targetChart.setColor(androidColor)
postInvalidate()
}
}
class TargetCardPresenter(
val habit: Habit,
val firstWeekday: Int,
val resources: Resources,
) {
suspend fun present(): TargetCardViewModel = Dispatchers.IO {
val today = DateUtils.getTodayWithOffset() val today = DateUtils.getTodayWithOffset()
val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today val oldest = habit.computedEntries.getKnown().lastOrNull()?.timestamp ?: today
val entries = habit.computedEntries.getByInterval(oldest, today) val entries = habit.computedEntries.getByInterval(oldest, today)
val valueToday = entries.groupedSum( val valueToday = entries.groupedSum(
truncateField = DAY, truncateField = DateUtils.TruncateField.DAY,
isNumerical = habit.isNumerical isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0 ).firstOrNull()?.value ?: 0
val valueThisWeek = entries.groupedSum( val valueThisWeek = entries.groupedSum(
truncateField = WEEK_NUMBER, truncateField = DateUtils.TruncateField.WEEK_NUMBER,
firstWeekday = firstWeekday, firstWeekday = firstWeekday,
isNumerical = habit.isNumerical isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0 ).firstOrNull()?.value ?: 0
val valueThisMonth = entries.groupedSum( val valueThisMonth = entries.groupedSum(
truncateField = MONTH, truncateField = DateUtils.TruncateField.MONTH,
isNumerical = habit.isNumerical isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0 ).firstOrNull()?.value ?: 0
val valueThisQuarter = entries.groupedSum( val valueThisQuarter = entries.groupedSum(
truncateField = QUARTER, truncateField = DateUtils.TruncateField.QUARTER,
isNumerical = habit.isNumerical isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0 ).firstOrNull()?.value ?: 0
val valueThisYear = entries.groupedSum( val valueThisYear = entries.groupedSum(
truncateField = YEAR, truncateField = DateUtils.TruncateField.YEAR,
isNumerical = habit.isNumerical isNumerical = habit.isNumerical
).firstOrNull()?.value ?: 0 ).firstOrNull()?.value ?: 0
@ -121,18 +93,18 @@ class TargetCardPresenter(
targets.add(targetThisQuarter) targets.add(targetThisQuarter)
targets.add(targetThisYear) targets.add(targetThisYear)
val labels = ArrayList<String>() val intervals = ArrayList<Int>()
if (habit.frequency.denominator <= 1) labels.add(resources.getString(R.string.today)) if (habit.frequency.denominator <= 1) intervals.add(1)
if (habit.frequency.denominator <= 7) labels.add(resources.getString(R.string.week)) if (habit.frequency.denominator <= 7) intervals.add(7)
labels.add(resources.getString(R.string.month)) intervals.add(30)
labels.add(resources.getString(R.string.quarter)) intervals.add(91)
labels.add(resources.getString(R.string.year)) intervals.add(365)
return@IO TargetCardViewModel( return TargetCardViewModel(
color = habit.color, color = habit.color,
values = values, values = values,
labels = labels,
targets = targets, targets = targets,
intervals = intervals,
) )
} }
} }
Loading…
Cancel
Save