From 13826f4934e24bfd1a04ae79ddfcdf420cb5dc70 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Thu, 31 Dec 2020 00:10:29 -0600 Subject: [PATCH] ShowHabitActivity: Move presenters and view models to uhabits-core --- .../common/views/ScoreChartTest.java | 10 +- ...cyCardTest.kt => FrequencyCardViewTest.kt} | 9 +- ...toryCardTest.kt => HistoryCardViewTest.kt} | 11 +- .../habits/show/views/NotesCardViewTest.kt | 1 + .../habits/show/views/OverviewCardViewTest.kt | 1 + ...{ScoreCardTest.kt => ScoreCardViewTest.kt} | 15 ++- .../habits/show/views/StreakCardViewTest.kt | 1 + .../habits/show/views/SubtitleCardViewTest.kt | 11 +- .../common/dialogs/HistoryEditorDialog.java | 6 +- .../habits/show/ShowHabitActivity.kt | 24 ++-- .../activities/habits/show/ShowHabitView.kt | 92 +------------- .../show/views/{BarCard.kt => BarCardView.kt} | 52 +------- ...{FrequencyCard.kt => FrequencyCardView.kt} | 26 +--- .../{HistoryCard.kt => HistoryCardView.kt} | 34 +----- .../views/{NotesCard.kt => NotesCardView.kt} | 10 +- .../{OverviewCard.kt => OverviewCardView.kt} | 38 +----- .../activities/habits/show/views/ScoreCard.kt | 114 ------------------ .../habits/show/views/ScoreCardView.kt | 59 +++++++++ .../{StreakCard.kt => StreakCardView.kt} | 20 +-- .../{SubtitleCard.kt => SubtitleCardView.kt} | 49 ++------ .../habits/show/views/TargetCardView.kt | 52 ++++++++ .../isoron/uhabits/widgets/HistoryWidget.kt | 6 +- .../org/isoron/uhabits/widgets/ScoreWidget.kt | 10 +- .../isoron/uhabits/widgets/TargetWidget.kt | 9 +- .../src/main/res/layout/show_habit.xml | 8 +- .../core/ui/screens/habits/show/ShowHabit.kt | 106 ++++++++++++++++ .../ui/screens/habits/show/views/BarCard.kt | 68 +++++++++++ .../habits/show/views/FrequencyCard.kt | 44 +++++++ .../screens/habits/show/views/HistoryCard.kt | 53 ++++++++ .../ui/screens/habits/show/views/NotesCard.kt | 32 +++++ .../screens/habits/show/views/OverviewCard.kt | 56 +++++++++ .../ui/screens/habits/show/views/ScoreCard.kt | 79 ++++++++++++ .../screens/habits/show/views/StreakCart.kt | 38 ++++++ .../screens/habits/show/views/SubtitleCard.kt | 49 ++++++++ .../screens}/habits/show/views/TargetCard.kt | 72 ++++------- 35 files changed, 754 insertions(+), 511 deletions(-) rename android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/{FrequencyCardTest.kt => FrequencyCardViewTest.kt} (85%) rename android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/{HistoryCardTest.kt => HistoryCardViewTest.kt} (88%) rename android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/{ScoreCardTest.kt => ScoreCardViewTest.kt} (78%) rename android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/{BarCard.kt => BarCardView.kt} (62%) rename android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/{FrequencyCard.kt => FrequencyCardView.kt} (67%) rename android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/{HistoryCard.kt => HistoryCardView.kt} (63%) rename android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/{NotesCard.kt => NotesCardView.kt} (86%) rename android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/{OverviewCard.kt => OverviewCardView.kt} (65%) delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCard.kt create mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardView.kt rename android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/{StreakCard.kt => StreakCardView.kt} (73%) rename android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/{SubtitleCard.kt => SubtitleCardView.kt} (76%) create mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/TargetCardView.kt create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabit.kt create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/BarCard.kt create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/FrequencyCard.kt create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/NotesCard.kt create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/OverviewCard.kt create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/ScoreCard.kt create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/StreakCart.kt create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/SubtitleCard.kt rename android/{uhabits-android/src/main/java/org/isoron/uhabits/activities => uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens}/habits/show/views/TargetCard.kt (58%) diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/ScoreChartTest.java b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/ScoreChartTest.java index d68ddb526..6b45576b9 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/ScoreChartTest.java +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/ScoreChartTest.java @@ -23,8 +23,8 @@ import androidx.test.ext.junit.runners.*; import androidx.test.filters.*; import org.isoron.uhabits.*; -import org.isoron.uhabits.activities.habits.show.views.*; import org.isoron.uhabits.core.models.*; +import org.isoron.uhabits.core.ui.screens.habits.show.views.*; import org.isoron.uhabits.utils.*; import org.junit.*; import org.junit.runner.*; @@ -49,8 +49,8 @@ public class ScoreChartTest extends BaseViewTest fixtures.purgeHabits(habitList); habit = fixtures.createLongHabit(); - presenter = new ScoreCardPresenter(habit, prefs.getFirstWeekday()); - ScoreCardViewModel model = presenter.present(0); + presenter = new ScoreCardPresenter(); + ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekday(), 0); view = new ScoreChart(targetContext); view.setScores(model.getScores()); @@ -84,7 +84,7 @@ public class ScoreChartTest extends BaseViewTest @Test public void testRender_withMonthlyBucket() throws Throwable { - ScoreCardViewModel model = presenter.present(2); + ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekday(), 2); view.setScores(model.getScores()); view.setBucketSize(model.getBucketSize()); view.invalidate(); @@ -102,7 +102,7 @@ public class ScoreChartTest extends BaseViewTest @Test public void testRender_withYearlyBucket() throws Throwable { - ScoreCardViewModel model = presenter.present(4); + ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekday(), 4); view.setScores(model.getScores()); view.setBucketSize(model.getBucketSize()); view.invalidate(); diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardViewTest.kt similarity index 85% rename from android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardTest.kt rename to android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardViewTest.kt index ef40fb082..18ce75c1f 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardViewTest.kt @@ -24,15 +24,16 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.R +import org.isoron.uhabits.core.ui.screens.habits.show.views.FrequencyCardPresenter import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) @MediumTest -class FrequencyCardTest : BaseViewTest() { +class FrequencyCardViewTest : BaseViewTest() { val PATH = "habits/show/FrequencyCard/" - private lateinit var view: FrequencyCard + private lateinit var view: FrequencyCardView @Before override fun setUp() { @@ -41,8 +42,8 @@ class FrequencyCardTest : BaseViewTest() { view = LayoutInflater .from(targetContext) .inflate(R.layout.show_habit, null) - .findViewById(R.id.frequencyCard) as FrequencyCard - view.update(FrequencyCardPresenter(habit, 0).present()) + .findViewById(R.id.frequencyCard) as FrequencyCardView + view.update(FrequencyCardPresenter().present(habit = habit, firstWeekday = 0)) measureView(view, 800f, 600f) } diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardViewTest.kt similarity index 88% rename from android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardTest.kt rename to android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardViewTest.kt index 040675c94..b39fb51dd 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardViewTest.kt @@ -24,14 +24,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.R +import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) @MediumTest -class HistoryCardTest : BaseViewTest() { - private lateinit var view: HistoryCard +class HistoryCardViewTest : BaseViewTest() { + private lateinit var view: HistoryCardView val PATH = "habits/show/HistoryCard/" @Before @@ -41,13 +42,13 @@ class HistoryCardTest : BaseViewTest() { view = LayoutInflater .from(targetContext) .inflate(R.layout.show_habit, null) - .findViewById(R.id.historyCard) as HistoryCard + .findViewById(R.id.historyCard) as HistoryCardView view.update( - HistoryCardPresenter( + HistoryCardPresenter().present( habit = habit, firstWeekday = 1, isSkipEnabled = false - ).present() + ) ) measureView(view, 800f, 600f) } diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardViewTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardViewTest.kt index 8ee1e67e2..f7e274ba6 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardViewTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardViewTest.kt @@ -25,6 +25,7 @@ import androidx.test.filters.MediumTest import org.hamcrest.Matchers.equalTo import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.R +import org.isoron.uhabits.core.ui.screens.habits.show.views.NotesCardViewModel import org.junit.Assert.assertThat import org.junit.Before import org.junit.Test diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt index 94de408bf..3bf6edaa4 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt @@ -25,6 +25,7 @@ import androidx.test.filters.MediumTest import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.R 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.Test import org.junit.runner.RunWith diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardViewTest.kt similarity index 78% rename from android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardTest.kt rename to android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardViewTest.kt index 035cf8678..3c1981c53 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardViewTest.kt @@ -24,15 +24,16 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.R +import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardPresenter import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) @MediumTest -class ScoreCardTest : BaseViewTest() { +class ScoreCardViewTest : BaseViewTest() { val PATH = "habits/show/ScoreCard/" - private lateinit var view: ScoreCard + private lateinit var view: ScoreCardView @Before override fun setUp() { @@ -41,8 +42,14 @@ class ScoreCardTest : BaseViewTest() { view = LayoutInflater .from(targetContext) .inflate(R.layout.show_habit, null) - .findViewById(R.id.scoreCard) as ScoreCard - view.update(ScoreCardPresenter(habit, 0).present(0)) + .findViewById(R.id.scoreCard) as ScoreCardView + view.update( + ScoreCardPresenter().present( + habit = habit, + firstWeekday = 0, + spinnerPosition = 0, + ) + ) measureView(view, 800f, 600f) } diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/StreakCardViewTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/StreakCardViewTest.kt index 5321438e6..2968ccfab 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/StreakCardViewTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/StreakCardViewTest.kt @@ -24,6 +24,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.R +import org.isoron.uhabits.core.ui.screens.habits.show.views.StreakCardViewModel import org.junit.Before import org.junit.Test import org.junit.runner.RunWith diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt index 44e425017..076e226c8 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt @@ -23,7 +23,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import org.isoron.uhabits.BaseViewTest 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.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.Test import org.junit.runner.RunWith @@ -44,11 +48,12 @@ class SubtitleCardViewTest : BaseViewTest() { view.update( SubtitleCardViewModel( color = PaletteColor(7), - frequencyText = "3 times in 7 days", + frequency = Frequency(3, 7), isNumerical = false, question = "Did you meditate this morning?", - reminderText = "8:30 AM", - targetText = "", + reminder = Reminder(8, 30, EVERY_DAY), + unit = "", + targetValue = 0.0, ) ) measureView(view, 800f, 200f) diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.java index 72fad14b1..8996a9d9a 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.java @@ -31,12 +31,12 @@ import android.util.*; import org.isoron.uhabits.*; 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.models.*; import org.isoron.uhabits.core.preferences.*; import org.isoron.uhabits.core.tasks.*; import org.isoron.uhabits.core.ui.callbacks.*; +import org.isoron.uhabits.core.ui.screens.habits.show.views.*; import org.isoron.uhabits.utils.*; import org.jetbrains.annotations.*; @@ -179,11 +179,11 @@ public class HistoryEditorDialog extends AppCompatDialogFragment @Override public void doInBackground() { - HistoryCardViewModel model = new HistoryCardPresenter( + HistoryCardViewModel model = new HistoryCardPresenter().present( habit, prefs.getFirstWeekday(), prefs.isSkipEnabled() - ).present(); + ); checkmarks = model.getEntries(); } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt index bd1af8215..9b22bdfef 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt @@ -34,16 +34,22 @@ import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialogFactory import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory import org.isoron.uhabits.core.commands.Command import org.isoron.uhabits.core.commands.CommandRunner +import org.isoron.uhabits.core.models.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.ShowHabitMenuBehavior +import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitPresenter import org.isoron.uhabits.intents.IntentFactory class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { + private val presenter = ShowHabitPresenter() + private lateinit var commandRunner: CommandRunner private lateinit var menu: ShowHabitMenu - private lateinit var presenter: ShowHabitPresenter private lateinit var view: ShowHabitView + private lateinit var habit: Habit + private lateinit var preferences: Preferences private val scope = CoroutineScope(Dispatchers.Main) @@ -52,17 +58,12 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { val appComponent = (applicationContext as HabitsApplication).component val habitList = appComponent.habitList - val habit = habitList.getById(ContentUris.parseId(intent.data!!))!! - val preferences = appComponent.preferences + habit = habitList.getById(ContentUris.parseId(intent.data!!))!! + preferences = appComponent.preferences commandRunner = appComponent.commandRunner AndroidThemeSwitcher(this, preferences).apply() view = ShowHabitView(this) - presenter = ShowHabitPresenter( - context = this, - habit = habit, - preferences = appComponent.preferences, - ) val screen = ShowHabitScreen( activity = this, @@ -129,7 +130,12 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { fun refresh() { scope.launch { - view.update(presenter.present()) + view.update( + presenter.present( + habit = habit, + preferences = preferences, + ) + ) } } } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt index 562215dc8..3b84db82f 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt @@ -22,45 +22,10 @@ package org.isoron.uhabits.activities.habits.show import android.content.Context import android.view.LayoutInflater import android.widget.FrameLayout -import org.isoron.uhabits.activities.habits.show.views.BarCardPresenter -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.core.ui.screens.habits.show.ShowHabitViewModel import org.isoron.uhabits.databinding.ShowHabitBinding 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) { 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, - ), - ) - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt similarity index 62% rename from android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.kt rename to android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt index 813244a60..44c7a40f2 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt @@ -24,25 +24,11 @@ import android.view.LayoutInflater import android.view.View import android.widget.AdapterView import android.widget.LinearLayout -import org.isoron.uhabits.activities.habits.show.views.ScoreCardPresenter.Companion.getTruncateField -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.core.ui.screens.habits.show.views.BarCardViewModel import org.isoron.uhabits.databinding.ShowHabitBarBinding import org.isoron.uhabits.utils.toThemedAndroidColor -data class BarCardViewModel( - val entries: List, - val bucketSize: Int, - val color: PaletteColor, - val isNumerical: Boolean, - val numericalSpinnerPosition: Int, - val boolSpinnerPosition: Int, -) - -class BarCard(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { +class BarCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { private var binding = ShowHabitBarBinding.inflate(LayoutInflater.from(context), this) 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, - ) - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardView.kt similarity index 67% rename from android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.kt rename to android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardView.kt index fb9719672..1e2568f10 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardView.kt @@ -22,20 +22,11 @@ import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import android.widget.LinearLayout -import org.isoron.uhabits.core.models.Habit -import org.isoron.uhabits.core.models.PaletteColor -import org.isoron.uhabits.core.models.Timestamp +import org.isoron.uhabits.core.ui.screens.habits.show.views.FrequencyCardViewModel import org.isoron.uhabits.databinding.ShowHabitFrequencyBinding import org.isoron.uhabits.utils.toThemedAndroidColor -import java.util.HashMap -data class FrequencyCardViewModel( - val frequency: HashMap>, - val firstWeekday: Int, - val color: PaletteColor, -) - -class FrequencyCard(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { +class FrequencyCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { 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) } } - -class FrequencyCardPresenter( - val habit: Habit, - val firstWeekday: Int, -) { - fun present() = FrequencyCardViewModel( - color = habit.color, - frequency = habit.originalEntries.computeWeekdayFrequency( - isNumerical = habit.isNumerical - ), - firstWeekday = firstWeekday, - ) -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCard.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt similarity index 63% rename from android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCard.kt rename to android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt index 2627d9eda..8c6b55471 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCard.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt @@ -22,21 +22,11 @@ import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import android.widget.LinearLayout -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.core.ui.screens.habits.show.views.HistoryCardViewModel import org.isoron.uhabits.databinding.ShowHabitHistoryBinding import org.isoron.uhabits.utils.toThemedAndroidColor -data class HistoryCardViewModel( - val entries: IntArray, - val color: PaletteColor, - val firstWeekday: Int, - val isNumerical: Boolean, - val isSkipEnabled: Boolean, -) - -class HistoryCard(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { +class HistoryCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { 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, - ) - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/NotesCard.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/NotesCardView.kt similarity index 86% rename from android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/NotesCard.kt rename to android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/NotesCardView.kt index 50e51d438..788f92c75 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/NotesCard.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/NotesCardView.kt @@ -23,11 +23,9 @@ import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater 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 -data class NotesCardViewModel(val description: String) - class NotesCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { private val binding = ShowHabitNotesBinding.inflate(LayoutInflater.from(context), this) fun update(data: NotesCardViewModel) { @@ -40,9 +38,3 @@ class NotesCardView(context: Context, attrs: AttributeSet) : LinearLayout(contex invalidate() } } - -class NotesCardPresenter(val habit: Habit) { - fun present() = NotesCardViewModel( - description = habit.description, - ) -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardView.kt similarity index 65% rename from android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.kt rename to android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardView.kt index cb3a8fce9..d57fe84ed 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardView.kt @@ -22,25 +22,12 @@ import android.content.Context 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.Entry.Companion.YES_MANUAL -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.core.ui.screens.habits.show.views.OverviewCardViewModel import org.isoron.uhabits.databinding.ShowHabitOverviewBinding import org.isoron.uhabits.utils.StyledResources 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) { private val binding = ShowHabitOverviewBinding.inflate(LayoutInflater.from(context), this) @@ -71,26 +58,3 @@ class OverviewCardView(context: Context, attrs: AttributeSet) : LinearLayout(con 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, - ) - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCard.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCard.kt deleted file mode 100644 index 2dcdc9d08..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCard.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2016 Álinson Santos Xavier - * - * 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 . - */ -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, - 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, - ) - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardView.kt new file mode 100644 index 000000000..0bc74b1d7 --- /dev/null +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardView.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * 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 . + */ +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<*>?) { + } + } + } +} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCard.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCardView.kt similarity index 73% rename from android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCard.kt rename to android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCardView.kt index 661cc8484..baa18f0fa 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCard.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCardView.kt @@ -22,19 +22,10 @@ import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import android.widget.LinearLayout -import kotlinx.coroutines.Dispatchers -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.core.ui.screens.habits.show.views.StreakCardViewModel import org.isoron.uhabits.databinding.ShowHabitStreakBinding import org.isoron.uhabits.utils.toThemedAndroidColor -data class StreakCardViewModel( - val color: PaletteColor, - val bestStreaks: List -) - class StreakCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { private val binding = ShowHabitStreakBinding.inflate(LayoutInflater.from(context), this) fun update(data: StreakCardViewModel) { @@ -45,12 +36,3 @@ class StreakCardView(context: Context, attrs: AttributeSet) : LinearLayout(conte postInvalidate() } } - -class StreakCartPresenter(val habit: Habit) { - suspend fun present(): StreakCardViewModel = Dispatchers.IO { - return@IO StreakCardViewModel( - color = habit.color, - bestStreaks = habit.streaks.getBest(10), - ) - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCard.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt similarity index 76% rename from android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCard.kt rename to android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt index 0e70c3e4f..2cc143fa0 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCard.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt @@ -28,23 +28,13 @@ import android.widget.LinearLayout import org.isoron.uhabits.R import org.isoron.uhabits.activities.habits.list.views.toShortString 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.ui.screens.habits.show.views.SubtitleCardViewModel import org.isoron.uhabits.databinding.ShowHabitSubtitleBinding import org.isoron.uhabits.utils.InterfaceUtils import org.isoron.uhabits.utils.formatTime import org.isoron.uhabits.utils.toThemedAndroidColor 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) { 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 } + @SuppressLint("SetTextI18n") fun update(data: SubtitleCardViewModel) { 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.text = data.question - binding.reminderLabel.text = data.reminderText - binding.targetText.text = data.targetText + binding.reminderLabel.text = if (reminder != null) { + 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.targetIcon.visibility = View.VISIBLE @@ -77,32 +73,9 @@ class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(con 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") - private fun Frequency.format(): String { + private fun Frequency.format(resources: Resources): String { val num = this.numerator val den = this.denominator if (num == den) { diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/TargetCardView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/TargetCardView.kt new file mode 100644 index 000000000..2dd02022b --- /dev/null +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/TargetCardView.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * 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 . + */ +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) + } + } +} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt index eeace136e..d1393d5be 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt @@ -23,8 +23,8 @@ import android.app.PendingIntent import android.content.Context import android.view.View 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.ui.screens.habits.show.views.HistoryCardPresenter import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.widgets.views.GraphWidgetView @@ -43,11 +43,11 @@ class HistoryWidget( val widgetView = view as GraphWidgetView widgetView.setBackgroundAlpha(preferedBackgroundAlpha) if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f) - val model = HistoryCardPresenter( + val model = HistoryCardPresenter().present( habit = habit, isSkipEnabled = prefs.isSkipEnabled, firstWeekday = prefs.firstWeekday, - ).present() + ) (widgetView.dataView as HistoryChart).apply { setFirstWeekday(model.firstWeekday) setSkipEnabled(model.isSkipEnabled) diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt index edac3d118..cb5a74889 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt @@ -22,8 +22,8 @@ package org.isoron.uhabits.widgets import android.content.Context import android.view.View 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.ui.screens.habits.show.views.ScoreCardPresenter import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.widgets.views.GraphWidgetView @@ -37,8 +37,12 @@ class ScoreWidget( pendingIntentFactory.showHabit(habit) override fun refreshData(view: View) { - val presenter = ScoreCardPresenter(habit, prefs.firstWeekday) - val viewModel = presenter.present(prefs.scoreCardSpinnerPosition) + val presenter = ScoreCardPresenter() + val viewModel = presenter.present( + habit = habit, + firstWeekday = prefs.firstWeekday, + spinnerPosition = prefs.scoreCardSpinnerPosition + ) val widgetView = view as GraphWidgetView widgetView.setBackgroundAlpha(preferedBackgroundAlpha) if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f) diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt index 3b3f7a53d..b097785a1 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt @@ -25,8 +25,9 @@ import android.view.ViewGroup.LayoutParams import android.view.ViewGroup.LayoutParams.MATCH_PARENT import kotlinx.coroutines.runBlocking 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.ui.screens.habits.show.views.TargetCardPresenter import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.widgets.views.GraphWidgetView @@ -44,11 +45,11 @@ class TargetWidget( widgetView.setBackgroundAlpha(preferedBackgroundAlpha) if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f) val chart = (widgetView.dataView as TargetChart) - val presenter = TargetCardPresenter(habit, prefs.firstWeekday, context.resources) - val data = presenter.present() + val presenter = TargetCardPresenter() + val data = presenter.present(habit, prefs.firstWeekday) chart.setColor(data.color.toThemedAndroidColor(context)) chart.setTargets(data.targets) - chart.setLabels(data.labels) + chart.setLabels(data.intervals.map { intervalToLabel(context.resources, it) }) chart.setValues(data.values) } diff --git a/android/uhabits-android/src/main/res/layout/show_habit.xml b/android/uhabits-android/src/main/res/layout/show_habit.xml index 401921532..e2edc87a4 100644 --- a/android/uhabits-android/src/main/res/layout/show_habit.xml +++ b/android/uhabits-android/src/main/res/layout/show_habit.xml @@ -62,17 +62,17 @@ style="@style/Card" android:paddingTop="12dp"/> - - - - diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabit.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabit.kt new file mode 100644 index 000000000..72cce2936 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabit.kt @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * 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 . + */ + +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, + ), + ) + } +} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/BarCard.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/BarCard.kt new file mode 100644 index 000000000..e91ded06f --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/BarCard.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * 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 . + */ + +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, + 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, + ) + } +} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/FrequencyCard.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/FrequencyCard.kt new file mode 100644 index 000000000..85e319a24 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/FrequencyCard.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * 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 . + */ + +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>, +) + +class FrequencyCardPresenter { + fun present( + habit: Habit, + firstWeekday: Int, + ) = FrequencyCardViewModel( + color = habit.color, + frequency = habit.originalEntries.computeWeekdayFrequency( + isNumerical = habit.isNumerical + ), + firstWeekday = firstWeekday, + ) +} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt new file mode 100644 index 000000000..94b8040c9 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * 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 . + */ + +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, + ) + } +} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/NotesCard.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/NotesCard.kt new file mode 100644 index 000000000..b210f7ec7 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/NotesCard.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * 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 . + */ + +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, + ) +} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/OverviewCard.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/OverviewCard.kt new file mode 100644 index 000000000..d37c520c4 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/OverviewCard.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * 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 . + */ + +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, + ) + } +} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/ScoreCard.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/ScoreCard.kt new file mode 100644 index 000000000..5813e7c28 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/ScoreCard.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * 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 . + */ + +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, + 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, + ) + } +} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/StreakCart.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/StreakCart.kt new file mode 100644 index 000000000..381da43ee --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/StreakCart.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * 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 . + */ + +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 +) + +class StreakCartPresenter { + fun present(habit: Habit): StreakCardViewModel { + return StreakCardViewModel( + color = habit.color, + bestStreaks = habit.streaks.getBest(10), + ) + } +} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/SubtitleCard.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/SubtitleCard.kt new file mode 100644 index 000000000..f39d78fae --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/SubtitleCard.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * 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 . + */ + +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, + ) +} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/TargetCard.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/TargetCard.kt similarity index 58% rename from android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/TargetCard.kt rename to android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/TargetCard.kt index 4add0f185..6e6ac81c1 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/TargetCard.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/TargetCard.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Álinson Santos Xavier + * Copyright (C) 2016-2020 Álinson Santos Xavier * * 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 * with this program. If not, see . */ -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 kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.invoke -import org.isoron.uhabits.R +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.groupedSum 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.Calendar @@ -44,55 +30,41 @@ data class TargetCardViewModel( val color: PaletteColor, val values: List = listOf(), val targets: List = listOf(), - val labels: List = listOf(), + val intervals: List = listOf(), ) -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.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 { +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) val valueToday = entries.groupedSum( - truncateField = DAY, + truncateField = DateUtils.TruncateField.DAY, isNumerical = habit.isNumerical ).firstOrNull()?.value ?: 0 val valueThisWeek = entries.groupedSum( - truncateField = WEEK_NUMBER, + truncateField = DateUtils.TruncateField.WEEK_NUMBER, firstWeekday = firstWeekday, isNumerical = habit.isNumerical ).firstOrNull()?.value ?: 0 val valueThisMonth = entries.groupedSum( - truncateField = MONTH, + truncateField = DateUtils.TruncateField.MONTH, isNumerical = habit.isNumerical ).firstOrNull()?.value ?: 0 val valueThisQuarter = entries.groupedSum( - truncateField = QUARTER, + truncateField = DateUtils.TruncateField.QUARTER, isNumerical = habit.isNumerical ).firstOrNull()?.value ?: 0 val valueThisYear = entries.groupedSum( - truncateField = YEAR, + truncateField = DateUtils.TruncateField.YEAR, isNumerical = habit.isNumerical ).firstOrNull()?.value ?: 0 @@ -121,18 +93,18 @@ class TargetCardPresenter( targets.add(targetThisQuarter) targets.add(targetThisYear) - val labels = ArrayList() - if (habit.frequency.denominator <= 1) labels.add(resources.getString(R.string.today)) - if (habit.frequency.denominator <= 7) labels.add(resources.getString(R.string.week)) - labels.add(resources.getString(R.string.month)) - labels.add(resources.getString(R.string.quarter)) - labels.add(resources.getString(R.string.year)) + val intervals = ArrayList() + 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@IO TargetCardViewModel( + return TargetCardViewModel( color = habit.color, values = values, - labels = labels, targets = targets, + intervals = intervals, ) } }