From ae4ac801a0cfe7bc1bc73aa5c3858e59c702d17f Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Tue, 22 Dec 2020 16:17:40 -0600 Subject: [PATCH] Restructure ShowHabitActivity --- .../uhabits/HabitsActivityTestComponent.kt | 1 - ...{NotesCardTest.kt => NotesCardViewTest.kt} | 20 ++- ...iewCardTest.kt => OverviewCardViewTest.kt} | 9 +- ...tleCardTest.kt => SubtitleCardViewTest.kt} | 13 +- .../org/isoron/uhabits/activities/DataView.kt | 45 ------- .../activities/HabitsActivityComponent.kt | 3 - .../isoron/uhabits/activities/Presenter.kt | 68 ----------- .../habits/show/ShowHabitActivity.kt | 115 +++++++++++++++++- .../activities/habits/show/ShowHabitModule.kt | 35 ------ .../habits/show/ShowHabitPresenter.kt | 113 ----------------- .../habits/show/ShowHabitRootView.kt | 100 --------------- .../habits/show/ShowHabitScreen.java | 30 ++--- .../habits/show/ShowHabitViewModel.kt | 37 ------ .../habits/show/ShowHabitsMenu.java | 39 +++--- .../activities/habits/show/views/NotesCard.kt | 17 ++- .../habits/show/views/OverviewCard.kt | 37 +++++- .../habits/show/views/SubtitleCard.kt | 80 +++++++++++- .../habits/show/views/TargetCard.kt | 35 ++---- .../isoron/uhabits/utils/ViewExtensions.kt | 26 +++- .../isoron/uhabits/widgets/TargetWidget.kt | 23 ++-- .../src/main/res/layout/show_habit.xml | 6 +- 21 files changed, 337 insertions(+), 515 deletions(-) rename android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/{NotesCardTest.kt => NotesCardViewTest.kt} (76%) rename android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/{OverviewCardTest.kt => OverviewCardViewTest.kt} (90%) rename android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/{SubtitleCardTest.kt => SubtitleCardViewTest.kt} (84%) delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/DataView.kt delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/Presenter.kt delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitModule.kt delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitPresenter.kt delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitRootView.kt delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitViewModel.kt diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt index a3fb21ba3..79d34cad9 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt @@ -38,7 +38,6 @@ class TestModule { ActivityContextModule::class, HabitsActivityModule::class, ListHabitsModule::class, - ShowHabitModule::class, HabitModule::class, TestModule::class ), dependencies = arrayOf(HabitsApplicationComponent::class)) diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardViewTest.kt similarity index 76% rename from android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardTest.kt rename to android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardViewTest.kt index 0fe9ff0aa..17ec9e10c 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/NotesCardViewTest.kt @@ -19,18 +19,20 @@ package org.isoron.uhabits.activities.habits.show.views import android.view.* +import android.view.View.* import androidx.test.ext.junit.runners.* import androidx.test.filters.* +import org.hamcrest.Matchers.* import org.isoron.uhabits.* -import org.isoron.uhabits.activities.habits.show.* import org.junit.* +import org.junit.Assert.* import org.junit.runner.* @RunWith(AndroidJUnit4::class) @MediumTest -class NotesCardTest : BaseViewTest() { +class NotesCardViewTest : BaseViewTest() { val PATH = "habits/show/NotesCard" - private lateinit var view: NotesCard + private lateinit var view: NotesCardView @Before override fun setUp() { @@ -39,24 +41,18 @@ class NotesCardTest : BaseViewTest() { .from(targetContext) .inflate(R.layout.show_habit, null) .findViewById(R.id.notesCard) - view.onData(ShowHabitViewModel( - description = "This is a test description", - )) + view.update(NotesCardViewModel(description = "This is a test description")) measureView(view, 800f, 200f) } @Test - @Throws(Exception::class) fun testRender() { assertRenders(view, "$PATH/render.png") } @Test - @Throws(Exception::class) fun testRenderEmptyDescription() { - view.onData(ShowHabitViewModel( - description = "", - )) - assertRenders(view, "$PATH/render-empty-description.png") + view.update(NotesCardViewModel(description = "")) + assertThat(view.visibility, equalTo(GONE)) } } \ No newline at end of file diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt similarity index 90% rename from android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardTest.kt rename to android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt index dba789cb6..06ea8b7a7 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt @@ -22,16 +22,15 @@ import android.view.* import androidx.test.ext.junit.runners.* import androidx.test.filters.* import org.isoron.uhabits.* -import org.isoron.uhabits.activities.habits.show.* import org.isoron.uhabits.core.models.* import org.junit.* import org.junit.runner.* @RunWith(AndroidJUnit4::class) @MediumTest -class OverviewCardTest : BaseViewTest() { +class OverviewCardViewTest : BaseViewTest() { val PATH = "habits/show/OverviewCard/" - private lateinit var view: OverviewCard + private lateinit var view: OverviewCardView @Before override fun setUp() { @@ -39,8 +38,8 @@ class OverviewCardTest : BaseViewTest() { view = LayoutInflater .from(targetContext) .inflate(R.layout.show_habit, null) - .findViewById(R.id.overviewCard) as OverviewCard - view.onData(ShowHabitViewModel( + .findViewById(R.id.overviewCard) as OverviewCardView + view.update(OverviewCardViewModel( scoreToday = 0.74f, scoreMonthDiff = 0.23f, scoreYearDiff = 0.74f, diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardTest.kt b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt similarity index 84% rename from android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardTest.kt rename to android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt index 617f33cd3..b611b5e99 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardTest.kt +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt @@ -22,15 +22,15 @@ import android.view.* import androidx.test.ext.junit.runners.* import androidx.test.filters.* import org.isoron.uhabits.* -import org.isoron.uhabits.activities.habits.show.* +import org.isoron.uhabits.core.models.* import org.junit.* import org.junit.runner.* @RunWith(AndroidJUnit4::class) @MediumTest -class SubtitleCardTest : BaseViewTest() { +class SubtitleCardViewTest : BaseViewTest() { val PATH = "habits/show/SubtitleCard/" - private lateinit var view: SubtitleCard + private lateinit var view: SubtitleCardView @Before override fun setUp() { @@ -39,10 +39,13 @@ class SubtitleCardTest : BaseViewTest() { .from(targetContext) .inflate(R.layout.show_habit, null) .findViewById(R.id.subtitleCard) - view.onData(ShowHabitViewModel( + view.update(SubtitleCardViewModel( + color = PaletteColor(7), + frequencyText = "3 times in 7 days", + isNumerical = false, question = "Did you meditate this morning?", reminderText = "8:30 AM", - frequencyText = "3 times in 7 days", + targetText = "", )) measureView(view, 800f, 200f) } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/DataView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/DataView.kt deleted file mode 100644 index 6332fb92a..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/DataView.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.activities - -import android.content.* -import android.util.* -import android.widget.* - -abstract class DataView( - context: Context, - attrs: AttributeSet, -) : LinearLayout(context, attrs), Presenter.Listener { - - lateinit var presenter: Presenter - - override fun onAttachedToWindow() { - super.onAttachedToWindow() - presenter.addListener(this) - presenter.requestData(this) - } - - override fun onDetachedFromWindow() { - presenter.removeListener(this) - super.onDetachedFromWindow() - } - - abstract override fun onData(data: T) -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/HabitsActivityComponent.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/HabitsActivityComponent.kt index 3cc205971..93e7dce7e 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/HabitsActivityComponent.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/HabitsActivityComponent.kt @@ -36,11 +36,9 @@ import org.isoron.uhabits.core.ui.screens.habits.list.* BaseActivityModule::class, HabitsActivityModule::class, ListHabitsModule::class, - ShowHabitModule::class, HabitModule::class ), dependencies = arrayOf(HabitsApplicationComponent::class)) interface HabitsActivityComponent { - val showHabitPresenter: ShowHabitPresenter val colorPickerDialogFactory: ColorPickerDialogFactory val habitCardListAdapter: HabitCardListAdapter val listHabitsBehavior: ListHabitsBehavior @@ -48,6 +46,5 @@ interface HabitsActivityComponent { val listHabitsRootView: ListHabitsRootView val listHabitsScreen: ListHabitsScreen val listHabitsSelectionMenu: ListHabitsSelectionMenu - val showHabitScreen: ShowHabitScreen val themeSwitcher: ThemeSwitcher } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/Presenter.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/Presenter.kt deleted file mode 100644 index 57290c015..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/Presenter.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.activities - -import org.isoron.uhabits.core.commands.* - -abstract class Presenter( - val commandRunner: CommandRunner, -) : CommandRunner.Listener { - - private val listeners = mutableListOf>() - private var data: M? = null - - fun onResume() { - commandRunner.addListener(this) - data = refresh() - notifyListeners() - } - - abstract fun refresh(): M - - fun onPause() { - commandRunner.removeListener(this) - } - - fun addListener(listener: Listener) { - listeners.add(listener) - } - - fun removeListener(listener: Listener) { - listeners.remove(listener) - } - - fun requestData(listener: Listener) { - if (data == null) data = refresh() - listener.onData(data!!) - } - - override fun onCommandExecuted(command: Command?, refreshKey: Long?) { - data = refresh() - notifyListeners() - } - - private fun notifyListeners() { - for (l in listeners) l.onData(data!!) - } - - interface Listener { - fun onData(data: T) - } -} \ No newline at end of file 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 454a7a56e..4c4811fe8 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 @@ -18,22 +18,127 @@ */ package org.isoron.uhabits.activities.habits.show +import android.content.* import android.os.* -import org.isoron.uhabits.activities.* +import android.view.* +import android.widget.* +import androidx.appcompat.app.* +import kotlinx.coroutines.* +import org.isoron.uhabits.* +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.databinding.* +import org.isoron.uhabits.utils.* + +class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { + private lateinit var view: ShowHabitView + private lateinit var presenter: ShowHabitPresenter + private lateinit var commandRunner: CommandRunner + private val scope = CoroutineScope(Dispatchers.Main) -class ShowHabitActivity : HabitsActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setScreen(component.showHabitScreen) + val appComponent = (applicationContext as HabitsApplication).component + val habitList = appComponent.habitList + val habit = habitList.getById(ContentUris.parseId(intent.data!!))!! + commandRunner = appComponent.commandRunner + + view = ShowHabitView(this) + presenter = ShowHabitPresenter( + habit = habit, + context = this, + preferences = appComponent.preferences + ) + setContentView(view) } override fun onResume() { super.onResume() - component.showHabitPresenter.onResume() + commandRunner.addListener(this) + updateViews() } override fun onPause() { - component.showHabitPresenter.onPause() + commandRunner.removeListener(this) super.onPause() } + + override fun onCommandExecuted(command: Command?, refreshKey: Long?) { + updateViews() + } + + private fun updateViews() { + scope.launch { + view.update(presenter.present()) + } + } +} + +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, +) + +class ShowHabitView(context: Context) : FrameLayout(context) { + private val binding = ShowHabitBinding.inflate(LayoutInflater.from(context)) + + init { + addView(binding.root) + } + + fun update(data: ShowHabitViewModel) { + setupToolbar(binding.toolbar, title = data.title, color = data.color) + binding.subtitleCard.update(data.subtitle) + binding.overviewCard.update(data.overview) + binding.notesCard.update(data.notes) + binding.targetCard.update(data.target) + + if (data.isNumerical) { + binding.overviewCard.visibility = GONE + binding.streakCard.visibility = GONE + } else { + binding.targetCard.visibility = GONE + } + } + + fun setController(controller: Controller) { + binding.historyCard.setController(controller) + } + + interface Controller : HistoryCard.Controller +} + +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 + ) + + 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(), + ) + } + } \ No newline at end of file diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitModule.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitModule.kt deleted file mode 100644 index f21122e6a..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitModule.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2017 Á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 - -import dagger.* -import org.isoron.uhabits.activities.* -import org.isoron.uhabits.core.ui.screens.habits.show.* - -@Module -abstract class ShowHabitModule { - @Binds - abstract fun getScreen(screen: ShowHabitScreen): ShowHabitBehavior.Screen - - @Binds - abstract fun getMenuScreen(screen: ShowHabitScreen): ShowHabitMenuBehavior.Screen - - @Binds - abstract fun getSystem(system: HabitsDirFinder): ShowHabitMenuBehavior.System -} \ No newline at end of file diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitPresenter.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitPresenter.kt deleted file mode 100644 index a0ba4b7b2..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitPresenter.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.activities.habits.show - -import android.annotation.* -import android.content.* -import org.isoron.androidbase.activities.* -import org.isoron.uhabits.* -import org.isoron.uhabits.activities.* -import org.isoron.uhabits.activities.habits.list.views.* -import org.isoron.uhabits.core.commands.* -import org.isoron.uhabits.core.models.* -import org.isoron.uhabits.core.preferences.* -import org.isoron.uhabits.core.utils.* -import org.isoron.uhabits.utils.* -import java.util.* -import javax.inject.* - -@ActivityScope -class ShowHabitPresenter -@Inject constructor( - val habit: Habit, - val preferences: Preferences, - commandRunner: CommandRunner, - @ActivityContext val context: Context, -) : Presenter(commandRunner) { - - private val resources = context.resources - - override fun refresh(): ShowHabitViewModel { - val today = DateUtils.getTodayWithOffset() - val lastMonth = today.minus(30) - val lastYear = today.minus(365) - - val reminderText = if (habit.hasReminder()) { - formatTime(context, habit.reminder.hour, habit.reminder.minute)!! - } else { - resources.getString(R.string.reminder_off) - } - - val scores = habit.scores - val scoreToday = scores.todayValue.toFloat() - val scoreLastMonth = scores.getValue(lastMonth).toFloat() - val scoreLastYear = scores.getValue(lastYear).toFloat() - - return ShowHabitViewModel( - title = habit.name, - description = habit.description, - question = habit.question, - color = habit.color, - isNumerical = habit.isNumerical, - scoreToday = scoreToday, - scoreMonthDiff = scoreToday - scoreLastMonth, - scoreYearDiff = scoreToday - scoreLastYear, - totalCount = habit.repetitions.totalCount, - targetText = "${habit.targetValue.toShortString()} ${habit.unit}", - frequencyText = habit.frequency.format(), - reminderText = reminderText, - ) - } - - @SuppressLint("StringFormatMatches") - private fun Frequency.format(): String { - val num = this.numerator - val den = this.denominator - if (num == den) { - return resources.getString(R.string.every_day) - } - if (den == 7) { - return resources.getString(R.string.x_times_per_week, num) - } - if (den == 30 || den == 31) { - return resources.getString(R.string.x_times_per_month, num) - } - if (num == 1) { - if (den == 7) { - return resources.getString(R.string.every_week) - } - if (den % 7 == 0) { - return resources.getString(R.string.every_x_weeks, den / 7) - } - if (den == 30 || den == 31) { - return resources.getString(R.string.every_month) - } - return resources.getString(R.string.every_x_days, den) - } - return String.format( - Locale.US, - "%d %s %d %s", - num, - resources.getString(R.string.times_every), - den, - resources.getString(R.string.days), - ) - } -} \ No newline at end of file diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitRootView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitRootView.kt deleted file mode 100644 index a26d8ae3d..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitRootView.kt +++ /dev/null @@ -1,100 +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 - -import android.content.* -import android.view.* -import org.isoron.androidbase.activities.* -import org.isoron.androidbase.utils.* -import org.isoron.uhabits.* -import org.isoron.uhabits.activities.* -import org.isoron.uhabits.activities.habits.show.views.* -import org.isoron.uhabits.core.models.* -import org.isoron.uhabits.databinding.* -import org.isoron.uhabits.utils.* -import javax.inject.* - -@ActivityScope -class ShowHabitRootView -@Inject constructor( - @ActivityContext context: Context, - private val habit: Habit, - private val presenter: ShowHabitPresenter, - targetCardPresenter: TargetCardPresenter, -) : BaseRootView(context), Presenter.Listener { - - private var controller: Controller = object : Controller {} - private var binding = ShowHabitBinding.inflate(LayoutInflater.from(context)) - - init { - addView(binding.root) - displayHomeAsUp = true - - binding.overviewCard.presenter = presenter - binding.notesCard.presenter = presenter - binding.subtitleCard.presenter = presenter - binding.targetCard.presenter = targetCardPresenter - - binding.scoreCard.habit = habit - binding.historyCard.habit = habit - binding.streakCard.habit = habit - binding.frequencyCard.habit = habit - binding.barCard.habit = habit - - initToolbar() - } - - override fun getToolbarColor(): Int { - val res = StyledResources(context) - return if (!res.getBoolean(R.attr.useHabitColorAsPrimary)) super.getToolbarColor() - else habit.color.toThemedAndroidColor(context) - } - - fun setController(controller: Controller) { - this.controller = controller - binding.historyCard.setController(controller) - } - - override fun onAttachedToWindow() { - super.onAttachedToWindow() - presenter.addListener(this) - presenter.requestData(this) - } - - override fun onDetachedFromWindow() { - presenter.removeListener(this) - super.onDetachedFromWindow() - } - - override fun onData(data: ShowHabitViewModel) { - binding.toolbar.title = data.title - if (data.isNumerical) { - binding.overviewCard.visibility = GONE - binding.streakCard.visibility = GONE - } else { - binding.targetCard.visibility = GONE - } - controller.onToolbarChanged() - } - - interface Controller : HistoryCard.Controller { - fun onToolbarChanged() {} - } - -} \ No newline at end of file diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java index cf1dcfbd2..995438aff 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java @@ -40,8 +40,8 @@ import dagger.*; public class ShowHabitScreen extends BaseScreen implements ShowHabitMenuBehavior.Screen, ShowHabitBehavior.Screen, - HistoryEditorDialog.Controller, - ShowHabitRootView.Controller + HistoryEditorDialog.Controller + //ShowHabitRootView.Controller { @NonNull private final Habit habit; @@ -60,7 +60,7 @@ public class ShowHabitScreen extends BaseScreen @Inject public ShowHabitScreen(@NonNull BaseActivity activity, @NonNull Habit habit, - @NonNull ShowHabitRootView view, + //@NonNull ShowHabitRootView view, @NonNull ShowHabitsMenu menu, @NonNull ConfirmDeleteDialogFactory confirmDeleteDialogFactory, @NonNull IntentFactory intentFactory, @@ -70,20 +70,20 @@ public class ShowHabitScreen extends BaseScreen super(activity); this.intentFactory = intentFactory; setMenu(menu); - setRootView(view); + //setRootView(view); this.habit = habit; this.behavior = behavior; this.confirmDeleteDialogFactory = confirmDeleteDialogFactory; this.numberPickerFactory = numberPickerFactory; - view.setController(this); + //view.setController(this); } - @Override - public void onEditHistoryButtonClick() - { - behavior.get().onEditHistory(); - } +// @Override +// public void onEditHistoryButtonClick() +// { +// behavior.get().onEditHistory(); +// } @Override public void showNumberPicker(double value, @@ -99,11 +99,11 @@ public class ShowHabitScreen extends BaseScreen behavior.get().onToggleCheckmark(timestamp, value); } - @Override - public void onToolbarChanged() - { - invalidateToolbar(); - } +// @Override +// public void onToolbarChanged() +// { +// invalidateToolbar(); +// } @Override public void reattachDialogs() diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitViewModel.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitViewModel.kt deleted file mode 100644 index ad2fa0704..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitViewModel.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.activities.habits.show - -import org.isoron.uhabits.core.models.* - -data class ShowHabitViewModel( - val title: String = "", - val description: String = "", - val question: String = "", - val isNumerical: Boolean = false, - val scoreToday: Float = 0f, - val scoreMonthDiff: Float = 0f, - val scoreYearDiff: Float = 0f, - val totalCount: Long = 0L, - val color: PaletteColor = PaletteColor(1), - val targetText: String = "", - val frequencyText: String = "", - val reminderText: String = "", -) \ No newline at end of file diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitsMenu.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitsMenu.java index 39c14c198..76eca4357 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitsMenu.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitsMenu.java @@ -35,18 +35,19 @@ import dagger.*; @ActivityScope public class ShowHabitsMenu extends BaseMenu { - @NonNull - private Lazy behavior; +// @NonNull +// private Lazy behavior; + @NonNull private final Preferences prefs; @Inject public ShowHabitsMenu(@NonNull BaseActivity activity, - @NonNull Lazy behavior, + //@NonNull Lazy behavior, @NonNull Preferences prefs) { super(activity); - this.behavior = behavior; + //this.behavior = behavior; this.prefs = prefs; } @@ -64,21 +65,21 @@ public class ShowHabitsMenu extends BaseMenu { switch (item.getItemId()) { - case R.id.action_edit_habit: - behavior.get().onEditHabit(); - return true; - - case R.id.export: - behavior.get().onExportCSV(); - return true; - - case R.id.action_delete: - behavior.get().onDeleteHabit(); - return true; - - case R.id.action_randomize: - behavior.get().onRandomize(); - return true; +// case R.id.action_edit_habit: +// behavior.get().onEditHabit(); +// return true; +// +// case R.id.export: +// behavior.get().onExportCSV(); +// return true; +// +// case R.id.action_delete: +// behavior.get().onDeleteHabit(); +// return true; +// +// case R.id.action_randomize: +// behavior.get().onRandomize(); +// return true; default: return false; 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/NotesCard.kt index b9ad17f1f..0bd0fe1d0 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/NotesCard.kt @@ -22,20 +22,27 @@ package org.isoron.uhabits.activities.habits.show.views import android.content.* import android.util.* import android.view.* -import org.isoron.uhabits.activities.* -import org.isoron.uhabits.activities.habits.show.* +import android.widget.* +import org.isoron.uhabits.core.models.* import org.isoron.uhabits.databinding.* -class NotesCard(context: Context, attrs: AttributeSet) : DataView(context, attrs) { +data class NotesCardViewModel(val description: String) +class NotesCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { private val binding = ShowHabitNotesBinding.inflate(LayoutInflater.from(context), this) - - override fun onData(data: ShowHabitViewModel) { + fun update(data: NotesCardViewModel) { if (data.description.isEmpty()) { visibility = GONE } else { visibility = VISIBLE binding.habitNotes.text = data.description } + invalidate() } +} + +class NotesCardPresenter(val habit: Habit) { + fun present() = NotesCardViewModel( + description = habit.description, + ) } \ No newline at end of file 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/OverviewCard.kt index 5a7515823..0090a5395 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/OverviewCard.kt @@ -21,14 +21,24 @@ package org.isoron.uhabits.activities.habits.show.views import android.content.* import android.util.* import android.view.* +import android.widget.* +import kotlinx.coroutines.* import org.isoron.androidbase.utils.* import org.isoron.uhabits.* -import org.isoron.uhabits.activities.* -import org.isoron.uhabits.activities.habits.show.* +import org.isoron.uhabits.core.models.* +import org.isoron.uhabits.core.utils.* import org.isoron.uhabits.databinding.* import org.isoron.uhabits.utils.* -class OverviewCard(context: Context, attrs: AttributeSet) : DataView(context, attrs) { +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) @@ -37,7 +47,7 @@ class OverviewCard(context: Context, attrs: AttributeSet) : DataView(context, attrs) { +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) @@ -38,7 +52,7 @@ class SubtitleCard(context: Context, attrs: AttributeSet) : DataView = listOf(), ) -class TargetCardView(context: Context, attrs: AttributeSet) : DataView(context, attrs) { - +class TargetCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { private val binding = ShowHabitTargetBinding.inflate(LayoutInflater.from(context), this) - - override fun onData(data: TargetCardViewModel) { + 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() } } -@ActivityScope -class TargetCardPresenter -@Inject constructor( +class TargetCardPresenter( val habit: Habit, - val preferences: Preferences, - @ActivityContext val context: Context, - commandRunner: CommandRunner, -) : Presenter(commandRunner) { - - val resources = context.resources - - override fun refresh(): TargetCardViewModel { + val firstWeekday: Int, + val resources: Resources, +) { + suspend fun present(): TargetCardViewModel = Dispatchers.IO { val checkmarks = habit.checkmarks val valueToday = checkmarks.todayValue / 1e3 - val valueThisWeek = checkmarks.getThisWeekValue(preferences.firstWeekday) / 1e3 + val valueThisWeek = checkmarks.getThisWeekValue(firstWeekday) / 1e3 val valueThisMonth = checkmarks.thisMonthValue / 1e3 val valueThisQuarter = checkmarks.thisQuarterValue / 1e3 val valueThisYear = checkmarks.thisYearValue / 1e3 @@ -105,7 +96,7 @@ class TargetCardPresenter labels.add(resources.getString(R.string.quarter)) labels.add(resources.getString(R.string.year)) - return TargetCardViewModel( + return@IO TargetCardViewModel( color = habit.color, values = values, labels = labels, diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt index f2ff5e1f6..0c56165b3 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt @@ -20,15 +20,18 @@ package org.isoron.uhabits.utils import android.graphics.* -import androidx.annotation.* -import androidx.appcompat.widget.Toolbar +import android.graphics.drawable.* import android.view.* import android.view.ViewGroup.LayoutParams.* import android.widget.* import android.widget.RelativeLayout.* -import com.google.android.material.snackbar.Snackbar +import androidx.annotation.* +import androidx.appcompat.app.* +import androidx.appcompat.widget.Toolbar +import com.google.android.material.snackbar.* import org.isoron.androidbase.utils.* import org.isoron.uhabits.* +import org.isoron.uhabits.core.models.* fun RelativeLayout.addBelow(view: View, subject: View, @@ -83,6 +86,23 @@ fun View.showMessage(@StringRes stringId: Int) { } } +fun View.setupToolbar(toolbar: Toolbar, title: String, color: PaletteColor) { + toolbar.elevation = InterfaceUtils.dpToPixels(context, 2f) + val res = StyledResources(context) + toolbar.title = title + val toolbarColor = if (!res.getBoolean(R.attr.useHabitColorAsPrimary)) { + StyledResources(context).getColor(org.isoron.androidbase.R.attr.colorPrimary) + } else { + color.toThemedAndroidColor(context) + } + val darkerColor = ColorUtils.mixColors(toolbarColor, Color.BLACK, 0.75f) + toolbar.background = ColorDrawable(toolbarColor) + val activity = context as AppCompatActivity + activity.window.statusBarColor = darkerColor + activity.setSupportActionBar(toolbar) + activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) +} + fun Int.toMeasureSpec(mode: Int) = View.MeasureSpec.makeMeasureSpec(this, mode) 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 8890354d0..2053a7a9f 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 @@ -23,6 +23,7 @@ import android.content.* import android.view.* import android.view.ViewGroup.* import android.view.ViewGroup.LayoutParams.* +import kotlinx.coroutines.* import org.isoron.uhabits.activities.common.views.* import org.isoron.uhabits.activities.habits.show.views.* import org.isoron.uhabits.core.models.* @@ -38,17 +39,17 @@ class TargetWidget( override fun getOnClickPendingIntent(context: Context) = pendingIntentFactory.showHabit(habit) - override fun refreshData(view: View) { - val widgetView = view as GraphWidgetView - widgetView.setBackgroundAlpha(preferedBackgroundAlpha) - if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f) - val chart = (widgetView.dataView as TargetChart) - val presenter = TargetCardPresenter(habit, prefs, context, commandRunner) - val data = presenter.refresh() - chart.setColor(data.color.toThemedAndroidColor(context)) - chart.setTargets(data.targets) - chart.setLabels(data.labels) - chart.setValues(data.values) + override fun refreshData(view: View) = runBlocking { + val widgetView = view as GraphWidgetView + 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() + chart.setColor(data.color.toThemedAndroidColor(context)) + chart.setTargets(data.targets) + chart.setLabels(data.labels) + chart.setValues(data.values) } override fun buildView(): View { 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 7cec786b9..41c7e6582 100644 --- a/android/uhabits-android/src/main/res/layout/show_habit.xml +++ b/android/uhabits-android/src/main/res/layout/show_habit.xml @@ -43,16 +43,16 @@ style="@style/CardList" android:clipToPadding="false"> - - -