mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Create view-model and presenter for TargetCard; reduce boilerplate
This commit is contained in:
@@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.uhabits.activities.habits.show.views;
|
|
||||||
|
|
||||||
import androidx.test.filters.*;
|
|
||||||
import androidx.test.runner.*;
|
|
||||||
import android.view.*;
|
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.junit.*;
|
|
||||||
import org.junit.runner.*;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@MediumTest
|
|
||||||
public class SubtitleCardTest extends BaseViewTest
|
|
||||||
{
|
|
||||||
public static final String PATH = "habits/show/SubtitleCard/";
|
|
||||||
|
|
||||||
private SubtitleCard view;
|
|
||||||
|
|
||||||
private Habit habit;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
@Override
|
|
||||||
public void setUp()
|
|
||||||
{
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
habit = fixtures.createLongHabit();
|
|
||||||
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
|
|
||||||
|
|
||||||
view = LayoutInflater
|
|
||||||
.from(targetContext)
|
|
||||||
.inflate(R.layout.show_habit, null)
|
|
||||||
.findViewById(R.id.subtitleCard);
|
|
||||||
|
|
||||||
view.setHabit(habit);
|
|
||||||
view.refreshData();
|
|
||||||
|
|
||||||
measureView(view, 800, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender() throws Exception
|
|
||||||
{
|
|
||||||
assertRenders(view, PATH + "render.png");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.isoron.uhabits.activities.habits.show.views
|
||||||
|
|
||||||
|
import android.view.*
|
||||||
|
import androidx.test.ext.junit.runners.*
|
||||||
|
import androidx.test.filters.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.activities.habits.show.*
|
||||||
|
import org.junit.*
|
||||||
|
import org.junit.runner.*
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@MediumTest
|
||||||
|
class SubtitleCardTest : BaseViewTest() {
|
||||||
|
val PATH = "habits/show/SubtitleCard/"
|
||||||
|
private lateinit var view: SubtitleCard
|
||||||
|
|
||||||
|
@Before
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
view = LayoutInflater
|
||||||
|
.from(targetContext)
|
||||||
|
.inflate(R.layout.show_habit, null)
|
||||||
|
.findViewById(R.id.subtitleCard)
|
||||||
|
view.onData(ShowHabitViewModel(
|
||||||
|
question = "Did you meditate this morning?",
|
||||||
|
reminderText = "8:30 AM",
|
||||||
|
frequencyText = "3 times in 7 days",
|
||||||
|
))
|
||||||
|
measureView(view, 800f, 200f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender() {
|
||||||
|
assertRenders(view, PATH + "render.png")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2020 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.isoron.uhabits.activities
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.util.*
|
||||||
|
import android.widget.*
|
||||||
|
|
||||||
|
abstract class DataView<T>(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet,
|
||||||
|
) : LinearLayout(context, attrs), Presenter.Listener<T> {
|
||||||
|
|
||||||
|
lateinit var presenter: Presenter<T>
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2020 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.isoron.uhabits.activities
|
||||||
|
|
||||||
|
import org.isoron.uhabits.core.commands.*
|
||||||
|
|
||||||
|
abstract class Presenter<M>(
|
||||||
|
val commandRunner: CommandRunner,
|
||||||
|
) : CommandRunner.Listener {
|
||||||
|
|
||||||
|
private val listeners = mutableListOf<Listener<M>>()
|
||||||
|
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<M>) {
|
||||||
|
listeners.add(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeListener(listener: Listener<M>) {
|
||||||
|
listeners.remove(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestData(listener: Listener<M>) {
|
||||||
|
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<T> {
|
||||||
|
fun onData(data: T)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import android.annotation.*
|
|||||||
import android.content.*
|
import android.content.*
|
||||||
import org.isoron.androidbase.activities.*
|
import org.isoron.androidbase.activities.*
|
||||||
import org.isoron.uhabits.*
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.activities.*
|
||||||
import org.isoron.uhabits.activities.habits.list.views.*
|
import org.isoron.uhabits.activities.habits.list.views.*
|
||||||
import org.isoron.uhabits.core.commands.*
|
import org.isoron.uhabits.core.commands.*
|
||||||
import org.isoron.uhabits.core.models.*
|
import org.isoron.uhabits.core.models.*
|
||||||
@@ -36,47 +37,14 @@ import javax.inject.*
|
|||||||
class ShowHabitPresenter
|
class ShowHabitPresenter
|
||||||
@Inject constructor(
|
@Inject constructor(
|
||||||
val habit: Habit,
|
val habit: Habit,
|
||||||
val commandRunner: CommandRunner,
|
|
||||||
val preferences: Preferences,
|
val preferences: Preferences,
|
||||||
|
commandRunner: CommandRunner,
|
||||||
@ActivityContext val context: Context,
|
@ActivityContext val context: Context,
|
||||||
) : CommandRunner.Listener {
|
) : Presenter<ShowHabitViewModel>(commandRunner) {
|
||||||
|
|
||||||
private val listeners = mutableListOf<Listener>()
|
|
||||||
private var data = ShowHabitViewModel()
|
|
||||||
private val resources = context.resources
|
private val resources = context.resources
|
||||||
|
|
||||||
fun onResume() {
|
override fun refresh(): ShowHabitViewModel {
|
||||||
commandRunner.addListener(this)
|
|
||||||
refresh()
|
|
||||||
notifyListeners()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onPause() {
|
|
||||||
commandRunner.removeListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addListener(listener: Listener) {
|
|
||||||
listeners.add(listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeListener(listener: Listener) {
|
|
||||||
listeners.remove(listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun requestData(listener: Listener) {
|
|
||||||
listener.onData(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCommandExecuted(command: Command?, refreshKey: Long?) {
|
|
||||||
refresh()
|
|
||||||
notifyListeners()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun notifyListeners() {
|
|
||||||
for (l in listeners) l.onData(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun refresh() {
|
|
||||||
val today = DateUtils.getTodayWithOffset()
|
val today = DateUtils.getTodayWithOffset()
|
||||||
val lastMonth = today.minus(30)
|
val lastMonth = today.minus(30)
|
||||||
val lastYear = today.minus(365)
|
val lastYear = today.minus(365)
|
||||||
@@ -92,46 +60,7 @@ class ShowHabitPresenter
|
|||||||
val scoreLastMonth = scores.getValue(lastMonth).toFloat()
|
val scoreLastMonth = scores.getValue(lastMonth).toFloat()
|
||||||
val scoreLastYear = scores.getValue(lastYear).toFloat()
|
val scoreLastYear = scores.getValue(lastYear).toFloat()
|
||||||
|
|
||||||
val checkmarks = habit.checkmarks
|
return ShowHabitViewModel(
|
||||||
val valueToday = checkmarks.todayValue / 1e3
|
|
||||||
val valueThisWeek = checkmarks.getThisWeekValue(preferences.firstWeekday) / 1e3
|
|
||||||
val valueThisMonth = checkmarks.thisMonthValue / 1e3
|
|
||||||
val valueThisQuarter = checkmarks.thisQuarterValue / 1e3
|
|
||||||
val valueThisYear = checkmarks.thisYearValue / 1e3
|
|
||||||
|
|
||||||
val cal = DateUtils.getStartOfTodayCalendarWithOffset()
|
|
||||||
val daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH)
|
|
||||||
val daysInQuarter = 91
|
|
||||||
val daysInYear = cal.getActualMaximum(Calendar.DAY_OF_YEAR)
|
|
||||||
|
|
||||||
val targetToday = habit.getTargetValue() / habit.frequency.denominator
|
|
||||||
val targetThisWeek = targetToday * 7
|
|
||||||
val targetThisMonth = targetToday * daysInMonth
|
|
||||||
val targetThisQuarter = targetToday * daysInQuarter
|
|
||||||
val targetThisYear = targetToday * daysInYear
|
|
||||||
|
|
||||||
val targetCompleted = ArrayList<Double>()
|
|
||||||
if (habit.frequency.denominator <= 1) targetCompleted.add(valueToday)
|
|
||||||
if (habit.frequency.denominator <= 7) targetCompleted.add(valueThisWeek)
|
|
||||||
targetCompleted.add(valueThisMonth)
|
|
||||||
targetCompleted.add(valueThisQuarter)
|
|
||||||
targetCompleted.add(valueThisYear)
|
|
||||||
|
|
||||||
val targetTotal = ArrayList<Double>()
|
|
||||||
if (habit.frequency.denominator <= 1) targetTotal.add(targetToday)
|
|
||||||
if (habit.frequency.denominator <= 7) targetTotal.add(targetThisWeek)
|
|
||||||
targetTotal.add(targetThisMonth)
|
|
||||||
targetTotal.add(targetThisQuarter)
|
|
||||||
targetTotal.add(targetThisYear)
|
|
||||||
|
|
||||||
val targetLabels = ArrayList<String>()
|
|
||||||
if (habit.frequency.denominator <= 1) targetLabels.add(resources.getString(R.string.today))
|
|
||||||
if (habit.frequency.denominator <= 7) targetLabels.add(resources.getString(R.string.week))
|
|
||||||
targetLabels.add(resources.getString(R.string.month))
|
|
||||||
targetLabels.add(resources.getString(R.string.quarter))
|
|
||||||
targetLabels.add(resources.getString(R.string.year))
|
|
||||||
|
|
||||||
data = ShowHabitViewModel(
|
|
||||||
title = habit.name,
|
title = habit.name,
|
||||||
description = habit.description,
|
description = habit.description,
|
||||||
question = habit.question,
|
question = habit.question,
|
||||||
@@ -144,9 +73,6 @@ class ShowHabitPresenter
|
|||||||
targetText = "${habit.targetValue.toShortString()} ${habit.unit}",
|
targetText = "${habit.targetValue.toShortString()} ${habit.unit}",
|
||||||
frequencyText = habit.frequency.format(),
|
frequencyText = habit.frequency.format(),
|
||||||
reminderText = reminderText,
|
reminderText = reminderText,
|
||||||
targetCompleted = targetCompleted,
|
|
||||||
targetTotal = targetTotal,
|
|
||||||
targetLabels = targetLabels,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,8 +110,4 @@ class ShowHabitPresenter
|
|||||||
resources.getString(R.string.days),
|
resources.getString(R.string.days),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Listener {
|
|
||||||
fun onData(data: ShowHabitViewModel)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,7 @@ import android.view.*
|
|||||||
import org.isoron.androidbase.activities.*
|
import org.isoron.androidbase.activities.*
|
||||||
import org.isoron.androidbase.utils.*
|
import org.isoron.androidbase.utils.*
|
||||||
import org.isoron.uhabits.*
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.activities.*
|
||||||
import org.isoron.uhabits.activities.habits.show.views.*
|
import org.isoron.uhabits.activities.habits.show.views.*
|
||||||
import org.isoron.uhabits.core.models.*
|
import org.isoron.uhabits.core.models.*
|
||||||
import org.isoron.uhabits.databinding.*
|
import org.isoron.uhabits.databinding.*
|
||||||
@@ -35,7 +36,8 @@ class ShowHabitRootView
|
|||||||
@ActivityContext context: Context,
|
@ActivityContext context: Context,
|
||||||
private val habit: Habit,
|
private val habit: Habit,
|
||||||
private val presenter: ShowHabitPresenter,
|
private val presenter: ShowHabitPresenter,
|
||||||
) : BaseRootView(context), ShowHabitPresenter.Listener {
|
targetCardPresenter: TargetCardPresenter,
|
||||||
|
) : BaseRootView(context), Presenter.Listener<ShowHabitViewModel> {
|
||||||
|
|
||||||
private var controller: Controller = object : Controller {}
|
private var controller: Controller = object : Controller {}
|
||||||
private var binding = ShowHabitBinding.inflate(LayoutInflater.from(context))
|
private var binding = ShowHabitBinding.inflate(LayoutInflater.from(context))
|
||||||
@@ -47,7 +49,7 @@ class ShowHabitRootView
|
|||||||
binding.overviewCard.presenter = presenter
|
binding.overviewCard.presenter = presenter
|
||||||
binding.notesCard.presenter = presenter
|
binding.notesCard.presenter = presenter
|
||||||
binding.subtitleCard.presenter = presenter
|
binding.subtitleCard.presenter = presenter
|
||||||
binding.targetCard.presenter = presenter
|
binding.targetCard.presenter = targetCardPresenter
|
||||||
|
|
||||||
binding.scoreCard.habit = habit
|
binding.scoreCard.habit = habit
|
||||||
binding.historyCard.habit = habit
|
binding.historyCard.habit = habit
|
||||||
|
|||||||
@@ -34,7 +34,4 @@ data class ShowHabitViewModel(
|
|||||||
val targetText: String = "",
|
val targetText: String = "",
|
||||||
val frequencyText: String = "",
|
val frequencyText: String = "",
|
||||||
val reminderText: String = "",
|
val reminderText: String = "",
|
||||||
val targetCompleted: List<Double> = listOf(),
|
|
||||||
val targetTotal: List<Double> = listOf(),
|
|
||||||
val targetLabels: List<String> = listOf(),
|
|
||||||
)
|
)
|
||||||
@@ -1,30 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2020 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.activities.habits.show.views
|
package org.isoron.uhabits.activities.habits.show.views
|
||||||
|
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.util.*
|
import android.util.*
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.*
|
import org.isoron.uhabits.activities.*
|
||||||
import org.isoron.uhabits.activities.habits.show.*
|
import org.isoron.uhabits.activities.habits.show.*
|
||||||
import org.isoron.uhabits.databinding.*
|
import org.isoron.uhabits.databinding.*
|
||||||
|
|
||||||
class NotesCard(
|
class NotesCard(context: Context, attrs: AttributeSet) : DataView<ShowHabitViewModel>(context, attrs) {
|
||||||
context: Context,
|
|
||||||
attrs: AttributeSet
|
|
||||||
) : LinearLayout(context, attrs), ShowHabitPresenter.Listener {
|
|
||||||
|
|
||||||
private val binding = ShowHabitNotesBinding.inflate(LayoutInflater.from(context), this)
|
private val binding = ShowHabitNotesBinding.inflate(LayoutInflater.from(context), this)
|
||||||
lateinit var presenter: ShowHabitPresenter
|
|
||||||
|
|
||||||
override fun onAttachedToWindow() {
|
|
||||||
super.onAttachedToWindow()
|
|
||||||
presenter.addListener(this)
|
|
||||||
presenter.requestData(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
|
||||||
presenter.removeListener(this)
|
|
||||||
super.onDetachedFromWindow()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onData(data: ShowHabitViewModel) {
|
override fun onData(data: ShowHabitViewModel) {
|
||||||
if (data.description.isEmpty()) {
|
if (data.description.isEmpty()) {
|
||||||
|
|||||||
@@ -21,48 +21,16 @@ package org.isoron.uhabits.activities.habits.show.views
|
|||||||
import android.content.*
|
import android.content.*
|
||||||
import android.util.*
|
import android.util.*
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.*
|
|
||||||
import org.isoron.androidbase.utils.*
|
import org.isoron.androidbase.utils.*
|
||||||
import org.isoron.uhabits.*
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.activities.*
|
||||||
import org.isoron.uhabits.activities.habits.show.*
|
import org.isoron.uhabits.activities.habits.show.*
|
||||||
import org.isoron.uhabits.databinding.*
|
import org.isoron.uhabits.databinding.*
|
||||||
import org.isoron.uhabits.utils.*
|
import org.isoron.uhabits.utils.*
|
||||||
|
|
||||||
class OverviewCard : LinearLayout, ShowHabitPresenter.Listener {
|
class OverviewCard(context: Context, attrs: AttributeSet) : DataView<ShowHabitViewModel>(context, attrs) {
|
||||||
|
|
||||||
private val binding = ShowHabitOverviewBinding.inflate(LayoutInflater.from(context), this)
|
private val binding = ShowHabitOverviewBinding.inflate(LayoutInflater.from(context), this)
|
||||||
lateinit var presenter: ShowHabitPresenter
|
|
||||||
|
|
||||||
constructor(context: Context) : super(context) {
|
|
||||||
init()
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
|
||||||
init()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun init() {
|
|
||||||
if (isInEditMode) initEditMode()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttachedToWindow() {
|
|
||||||
super.onAttachedToWindow()
|
|
||||||
presenter.addListener(this)
|
|
||||||
presenter.requestData(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
|
||||||
presenter.removeListener(this)
|
|
||||||
super.onDetachedFromWindow()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initEditMode() {
|
|
||||||
onData(ShowHabitViewModel(
|
|
||||||
scoreToday = 0.6f,
|
|
||||||
scoreMonthDiff = 0.42f,
|
|
||||||
scoreYearDiff = 0.75f,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun formatPercentageDiff(percentageDiff: Float): String {
|
private fun formatPercentageDiff(percentageDiff: Float): String {
|
||||||
return String.format("%s%.0f%%", if (percentageDiff >= 0) "+" else "\u2212",
|
return String.format("%s%.0f%%", if (percentageDiff >= 0) "+" else "\u2212",
|
||||||
|
|||||||
@@ -21,44 +21,21 @@ package org.isoron.uhabits.activities.habits.show.views
|
|||||||
import android.content.*
|
import android.content.*
|
||||||
import android.util.*
|
import android.util.*
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.*
|
|
||||||
import org.isoron.androidbase.utils.*
|
import org.isoron.androidbase.utils.*
|
||||||
|
import org.isoron.uhabits.activities.*
|
||||||
import org.isoron.uhabits.activities.habits.show.*
|
import org.isoron.uhabits.activities.habits.show.*
|
||||||
import org.isoron.uhabits.core.models.*
|
|
||||||
import org.isoron.uhabits.databinding.*
|
import org.isoron.uhabits.databinding.*
|
||||||
import org.isoron.uhabits.utils.*
|
import org.isoron.uhabits.utils.*
|
||||||
|
|
||||||
class SubtitleCard(
|
class SubtitleCard(context: Context, attrs: AttributeSet) : DataView<ShowHabitViewModel>(context, attrs) {
|
||||||
context: Context,
|
|
||||||
attrs: AttributeSet,
|
|
||||||
) : LinearLayout(context, attrs), ShowHabitPresenter.Listener {
|
|
||||||
|
|
||||||
private val binding = ShowHabitSubtitleBinding.inflate(LayoutInflater.from(context), this)
|
private val binding = ShowHabitSubtitleBinding.inflate(LayoutInflater.from(context), this)
|
||||||
lateinit var presenter: ShowHabitPresenter
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val fontAwesome = InterfaceUtils.getFontAwesome(context)
|
val fontAwesome = InterfaceUtils.getFontAwesome(context)
|
||||||
binding.targetIcon.typeface = fontAwesome
|
binding.targetIcon.typeface = fontAwesome
|
||||||
binding.frequencyIcon.typeface = fontAwesome
|
binding.frequencyIcon.typeface = fontAwesome
|
||||||
binding.reminderIcon.typeface = fontAwesome
|
binding.reminderIcon.typeface = fontAwesome
|
||||||
if (isInEditMode) onData(ShowHabitViewModel(
|
|
||||||
isNumerical = false,
|
|
||||||
frequencyText = "Every day",
|
|
||||||
question = "How many steps did you walk today?",
|
|
||||||
color = PaletteColor(1),
|
|
||||||
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttachedToWindow() {
|
|
||||||
super.onAttachedToWindow()
|
|
||||||
presenter.addListener(this)
|
|
||||||
presenter.requestData(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
|
||||||
presenter.removeListener(this)
|
|
||||||
super.onDetachedFromWindow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onData(data: ShowHabitViewModel) {
|
override fun onData(data: ShowHabitViewModel) {
|
||||||
|
|||||||
@@ -21,36 +21,95 @@ package org.isoron.uhabits.activities.habits.show.views
|
|||||||
import android.content.*
|
import android.content.*
|
||||||
import android.util.*
|
import android.util.*
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.*
|
import org.isoron.androidbase.activities.*
|
||||||
import org.isoron.uhabits.activities.habits.show.*
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.activities.*
|
||||||
|
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.databinding.*
|
import org.isoron.uhabits.databinding.*
|
||||||
import org.isoron.uhabits.utils.*
|
import org.isoron.uhabits.utils.*
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.*
|
||||||
|
|
||||||
class TargetCard(
|
data class TargetCardViewModel(
|
||||||
context: Context,
|
val color: PaletteColor,
|
||||||
attrs: AttributeSet,
|
val values: List<Double> = listOf(),
|
||||||
) : LinearLayout(context, attrs), ShowHabitPresenter.Listener {
|
val targets: List<Double> = listOf(),
|
||||||
|
val labels: List<String> = listOf(),
|
||||||
|
)
|
||||||
|
|
||||||
|
class TargetCardView(context: Context, attrs: AttributeSet) : DataView<TargetCardViewModel>(context, attrs) {
|
||||||
|
|
||||||
private val binding = ShowHabitTargetBinding.inflate(LayoutInflater.from(context), this)
|
private val binding = ShowHabitTargetBinding.inflate(LayoutInflater.from(context), this)
|
||||||
lateinit var presenter: ShowHabitPresenter
|
|
||||||
|
|
||||||
override fun onAttachedToWindow() {
|
override fun onData(data: TargetCardViewModel) {
|
||||||
super.onAttachedToWindow()
|
|
||||||
presenter.addListener(this)
|
|
||||||
presenter.requestData(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
|
||||||
presenter.removeListener(this)
|
|
||||||
super.onDetachedFromWindow()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onData(data: ShowHabitViewModel) {
|
|
||||||
val androidColor = data.color.toThemedAndroidColor(context)
|
val androidColor = data.color.toThemedAndroidColor(context)
|
||||||
binding.targetChart.setValues(data.targetCompleted)
|
binding.targetChart.setValues(data.values)
|
||||||
binding.targetChart.setTargets(data.targetTotal)
|
binding.targetChart.setTargets(data.targets)
|
||||||
binding.targetChart.setLabels(data.targetLabels)
|
binding.targetChart.setLabels(data.labels)
|
||||||
binding.title.setTextColor(androidColor)
|
binding.title.setTextColor(androidColor)
|
||||||
binding.targetChart.setColor(androidColor)
|
binding.targetChart.setColor(androidColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ActivityScope
|
||||||
|
class TargetCardPresenter
|
||||||
|
@Inject constructor(
|
||||||
|
val habit: Habit,
|
||||||
|
val preferences: Preferences,
|
||||||
|
@ActivityContext val context: Context,
|
||||||
|
commandRunner: CommandRunner,
|
||||||
|
) : Presenter<TargetCardViewModel>(commandRunner) {
|
||||||
|
|
||||||
|
val resources = context.resources
|
||||||
|
|
||||||
|
override fun refresh(): TargetCardViewModel {
|
||||||
|
val checkmarks = habit.checkmarks
|
||||||
|
val valueToday = checkmarks.todayValue / 1e3
|
||||||
|
val valueThisWeek = checkmarks.getThisWeekValue(preferences.firstWeekday) / 1e3
|
||||||
|
val valueThisMonth = checkmarks.thisMonthValue / 1e3
|
||||||
|
val valueThisQuarter = checkmarks.thisQuarterValue / 1e3
|
||||||
|
val valueThisYear = checkmarks.thisYearValue / 1e3
|
||||||
|
|
||||||
|
val cal = DateUtils.getStartOfTodayCalendarWithOffset()
|
||||||
|
val daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH)
|
||||||
|
val daysInQuarter = 91
|
||||||
|
val daysInYear = cal.getActualMaximum(Calendar.DAY_OF_YEAR)
|
||||||
|
|
||||||
|
val targetToday = habit.getTargetValue() / habit.frequency.denominator
|
||||||
|
val targetThisWeek = targetToday * 7
|
||||||
|
val targetThisMonth = targetToday * daysInMonth
|
||||||
|
val targetThisQuarter = targetToday * daysInQuarter
|
||||||
|
val targetThisYear = targetToday * daysInYear
|
||||||
|
|
||||||
|
val values = ArrayList<Double>()
|
||||||
|
if (habit.frequency.denominator <= 1) values.add(valueToday)
|
||||||
|
if (habit.frequency.denominator <= 7) values.add(valueThisWeek)
|
||||||
|
values.add(valueThisMonth)
|
||||||
|
values.add(valueThisQuarter)
|
||||||
|
values.add(valueThisYear)
|
||||||
|
|
||||||
|
val targets = ArrayList<Double>()
|
||||||
|
if (habit.frequency.denominator <= 1) targets.add(targetToday)
|
||||||
|
if (habit.frequency.denominator <= 7) targets.add(targetThisWeek)
|
||||||
|
targets.add(targetThisMonth)
|
||||||
|
targets.add(targetThisQuarter)
|
||||||
|
targets.add(targetThisYear)
|
||||||
|
|
||||||
|
val labels = ArrayList<String>()
|
||||||
|
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))
|
||||||
|
|
||||||
|
return TargetCardViewModel(
|
||||||
|
color = habit.color,
|
||||||
|
values = values,
|
||||||
|
labels = labels,
|
||||||
|
targets = targets,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.widget.*;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.isoron.uhabits.*;
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.core.commands.*;
|
||||||
import org.isoron.uhabits.core.preferences.*;
|
import org.isoron.uhabits.core.preferences.*;
|
||||||
import org.isoron.uhabits.intents.*;
|
import org.isoron.uhabits.intents.*;
|
||||||
|
|
||||||
@@ -49,6 +50,9 @@ public abstract class BaseWidget
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected final CommandRunner commandRunner;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private WidgetDimensions dimensions;
|
private WidgetDimensions dimensions;
|
||||||
|
|
||||||
@@ -62,6 +66,7 @@ public abstract class BaseWidget
|
|||||||
|
|
||||||
widgetPrefs = app.getComponent().getWidgetPreferences();
|
widgetPrefs = app.getComponent().getWidgetPreferences();
|
||||||
prefs = app.getComponent().getPreferences();
|
prefs = app.getComponent().getPreferences();
|
||||||
|
commandRunner = app.getComponent().getCommandRunner();
|
||||||
pendingIntentFactory = app.getComponent().getPendingIntentFactory();
|
pendingIntentFactory = app.getComponent().getPendingIntentFactory();
|
||||||
dimensions = new WidgetDimensions(getDefaultWidth(), getDefaultHeight(),
|
dimensions = new WidgetDimensions(getDefaultWidth(), getDefaultHeight(),
|
||||||
getDefaultWidth(), getDefaultHeight());
|
getDefaultWidth(), getDefaultHeight());
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.view.ViewGroup.LayoutParams.*
|
|||||||
import org.isoron.uhabits.activities.common.views.*
|
import org.isoron.uhabits.activities.common.views.*
|
||||||
import org.isoron.uhabits.activities.habits.show.views.*
|
import org.isoron.uhabits.activities.habits.show.views.*
|
||||||
import org.isoron.uhabits.core.models.*
|
import org.isoron.uhabits.core.models.*
|
||||||
|
import org.isoron.uhabits.utils.*
|
||||||
import org.isoron.uhabits.widgets.views.*
|
import org.isoron.uhabits.widgets.views.*
|
||||||
|
|
||||||
class TargetWidget(
|
class TargetWidget(
|
||||||
@@ -38,15 +39,16 @@ class TargetWidget(
|
|||||||
pendingIntentFactory.showHabit(habit)
|
pendingIntentFactory.showHabit(habit)
|
||||||
|
|
||||||
override fun refreshData(view: View) {
|
override fun refreshData(view: View) {
|
||||||
// val widgetView = view as GraphWidgetView
|
val widgetView = view as GraphWidgetView
|
||||||
// widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
|
widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
|
||||||
// if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f)
|
if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f)
|
||||||
// val chart = (widgetView.dataView as TargetChart)
|
val chart = (widgetView.dataView as TargetChart)
|
||||||
// with(TargetCard.RefreshTask(context, habit, prefs.firstWeekday, chart, null)) {
|
val presenter = TargetCardPresenter(habit, prefs, context, commandRunner)
|
||||||
// onPreExecute()
|
val data = presenter.refresh()
|
||||||
// doInBackground()
|
chart.setColor(data.color.toThemedAndroidColor(context))
|
||||||
// onPostExecute()
|
chart.setTargets(data.targets)
|
||||||
// }
|
chart.setLabels(data.labels)
|
||||||
|
chart.setValues(data.values)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun buildView(): View {
|
override fun buildView(): View {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
style="@style/Card"
|
style="@style/Card"
|
||||||
android:paddingTop="12dp"/>
|
android:paddingTop="12dp"/>
|
||||||
|
|
||||||
<org.isoron.uhabits.activities.habits.show.views.TargetCard
|
<org.isoron.uhabits.activities.habits.show.views.TargetCardView
|
||||||
android:id="@+id/targetCard"
|
android:id="@+id/targetCard"
|
||||||
style="@style/Card"
|
style="@style/Card"
|
||||||
android:paddingTop="12dp"/>
|
android:paddingTop="12dp"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user