1
0
mirror of https://github.com/dzeiocom/OpenHealth.git synced 2025-06-07 15:29:55 +00:00

fix: Water animation down is not working (#22)

This commit is contained in:
Florian Bouillon 2023-01-07 22:36:18 +01:00
parent 643861bf1e
commit 1f4ecc06ad
Signed by: Florian Bouillon
GPG Key ID: BEEAF3722D0EBF64
4 changed files with 136 additions and 51 deletions

View File

@ -21,6 +21,7 @@ import com.dzeio.openhealth.utils.GraphUtils
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.math.max import kotlin.math.max
import kotlin.math.min
@AndroidEntryPoint @AndroidEntryPoint
class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewModel::class.java) { class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewModel::class.java) {
@ -43,6 +44,10 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
) )
} }
/**
* Water Intake
*/
binding.fragmentHomeWaterAdd.setOnClickListener { binding.fragmentHomeWaterAdd.setOnClickListener {
val water = viewModel.water.value val water = viewModel.water.value
if (water == null || !water.isToday()) { if (water == null || !water.isToday()) {
@ -75,14 +80,17 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
} }
} }
// handle button to go to weight home
binding.listWeight.setOnClickListener { binding.listWeight.setOnClickListener {
findNavController().navigate(HomeFragmentDirections.actionNavHomeToNavListWeight()) findNavController().navigate(HomeFragmentDirections.actionNavHomeToNavListWeight())
} }
// handle button to go to water intake home
binding.gotoWaterHome.setOnClickListener { binding.gotoWaterHome.setOnClickListener {
findNavController().navigate(HomeFragmentDirections.actionNavHomeToNavWaterHome()) findNavController().navigate(HomeFragmentDirections.actionNavHomeToNavWaterHome())
} }
// Make a line Chart using the graph library
GraphUtils.lineChartSetup( GraphUtils.lineChartSetup(
binding.weightGraph, binding.weightGraph,
MaterialColors.getColor( MaterialColors.getColor(
@ -95,6 +103,7 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
) )
) )
// Update the water intake Graph when the water intake changes
viewModel.water.observe(viewLifecycleOwner) { viewModel.water.observe(viewLifecycleOwner) {
if (it != null) { if (it != null) {
updateWater(it.value) updateWater(it.value)
@ -103,29 +112,41 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
} }
} }
// Update the steps Graph when the steps count changes
viewModel.steps.observe(viewLifecycleOwner) { viewModel.steps.observe(viewLifecycleOwner) {
binding.stepsCurrent.text = it.toString() binding.stepsCurrent.text = it.toString()
} }
// Update the steps Graph when the goal changes
viewModel.stepsGoal.observe(viewLifecycleOwner) { viewModel.stepsGoal.observe(viewLifecycleOwner) {
if (it == null) {
binding.stepsTotal.text = ""
return@observe
}
binding.stepsTotal.text = it.toString() binding.stepsTotal.text = it.toString()
} }
// update the graph when the weight changes
viewModel.weights.observe(viewLifecycleOwner) { viewModel.weights.observe(viewLifecycleOwner) {
if (it != null) { if (it != null) {
updateGraph(it) updateGraph(it)
} }
} }
// update the graph when the goal weight change
viewModel.goalWeight.observe(viewLifecycleOwner) { viewModel.goalWeight.observe(viewLifecycleOwner) {
if (viewModel.weights.value != null) updateGraph(viewModel.weights.value!!) if (viewModel.weights.value != null) updateGraph(viewModel.weights.value!!)
} }
// update the graph when the weight unit change
viewModel.massUnit.observe(viewLifecycleOwner) { viewModel.massUnit.observe(viewLifecycleOwner) {
if (viewModel.weights.value != null) updateGraph(viewModel.weights.value!!) if (viewModel.weights.value != null) updateGraph(viewModel.weights.value!!)
} }
} }
/**
* Function that update the graph for the weight
*/
private fun updateGraph(list: List<Weight>) { private fun updateGraph(list: List<Weight>) {
WeightChart.setup( WeightChart.setup(
binding.weightGraph, binding.weightGraph,
@ -134,40 +155,37 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
viewModel.massUnit.value!!, viewModel.massUnit.value!!,
viewModel.goalWeight.value viewModel.goalWeight.value
) )
// legend.apply {
// isEnabled = true
// form = Legend.LegendForm.LINE
//
// if (goal != null) {
// val legendEntry = LegendEntry().apply {
// label = "Weight Goal"
// formColor = Color.RED
// }
// setCustom(arrayOf(legendEntry))
// }
// }
} }
/**
* the waterintake old value to keep for value update
*/
private var oldValue = 0f private var oldValue = 0f
/**
* function that update the water count in the home page
*/
private fun updateWater(newValue: Int) { private fun updateWater(newValue: Int) {
// get the current Unit
val waterUnit = val waterUnit =
Units.Volume.find(settings.getString("water_unit", "milliliter") ?: "Milliliter") Units.Volume.find(settings.getString("water_unit", "milliliter") ?: "Milliliter")
// Update the count
binding.fragmentHomeWaterCurrent.text = binding.fragmentHomeWaterCurrent.text =
String.format( String.format(
resources.getString(waterUnit.unit), resources.getString(waterUnit.unit),
(newValue * waterUnit.modifier).toInt() (newValue * waterUnit.modifier).toInt()
) )
// TODO: move it elsewhere
binding.fragmentHomeWaterTotal.text = binding.fragmentHomeWaterTotal.text =
String.format( String.format(
resources.getString(waterUnit.unit), resources.getString(waterUnit.unit),
viewModel.dailyWaterIntake viewModel.dailyWaterIntake
) )
// get the with/height of the ImageView
var width = 1500 var width = 1500
var height = 750 var height = 750
@ -177,6 +195,7 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
} }
// Prepare the update animation
val animator = ValueAnimator.ofInt( val animator = ValueAnimator.ofInt(
this.oldValue.toInt(), this.oldValue.toInt(),
newValue newValue
@ -186,7 +205,6 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
this.oldValue = (it.animatedValue as Int).toFloat() this.oldValue = (it.animatedValue as Int).toFloat()
val value = 100 * it.animatedValue as Int / viewModel.dailyWaterIntake.toFloat() val value = 100 * it.animatedValue as Int / viewModel.dailyWaterIntake.toFloat()
// Log.d("Test2", "${this.oldValue}")
val graph = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val graph = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(graph) val canvas = Canvas(graph)
@ -209,9 +227,10 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
3f 3f
) )
// Draw the big Arc
DrawUtils.drawArc( DrawUtils.drawArc(
canvas, canvas,
max(value, 1f), min(max(value, 0.01f), 100f),
rect, rect,
MaterialColors.getColor( MaterialColors.getColor(
requireView(), requireView(),
@ -219,9 +238,15 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
), ),
6f 6f
) )
// save the canvas
canvas.save() canvas.save()
// send it
binding.background.setImageBitmap(graph) binding.background.setImageBitmap(graph)
} }
// start the animation
animator.start() animator.start()
} }
} }

View File

@ -1,6 +1,5 @@
package com.dzeio.openhealth.ui.home package com.dzeio.openhealth.ui.home
import android.content.SharedPreferences
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
@ -11,7 +10,6 @@ import com.dzeio.openhealth.data.water.Water
import com.dzeio.openhealth.data.water.WaterRepository import com.dzeio.openhealth.data.water.WaterRepository
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.data.weight.WeightRepository import com.dzeio.openhealth.data.weight.WeightRepository
import com.dzeio.openhealth.units.UnitFactory
import com.dzeio.openhealth.units.Units import com.dzeio.openhealth.units.Units
import com.dzeio.openhealth.utils.Configuration import com.dzeio.openhealth.utils.Configuration
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@ -24,51 +22,73 @@ class HomeViewModel @Inject internal constructor(
private val weightRepository: WeightRepository, private val weightRepository: WeightRepository,
private val waterRepository: WaterRepository, private val waterRepository: WaterRepository,
stepRepository: StepRepository, stepRepository: StepRepository,
settings: SharedPreferences,
config: Configuration config: Configuration
) : BaseViewModel() { ) : BaseViewModel() {
private val _steps = MutableLiveData(0) private val _steps = MutableLiveData(0)
/**
* Steps taken today by the user
*/
val steps: LiveData<Int> = _steps val steps: LiveData<Int> = _steps
private val _stepsGoal: MutableLiveData<Int?> = MutableLiveData() /**
val stepsGoal: LiveData<Int?> = _stepsGoal * Number of steps the use should do today
*/
val stepsGoal: LiveData<Int?> = config.getInt(Settings.STEPS_GOAL).toLiveData()
private val _water = MutableLiveData<Water?>(null) private val _water = MutableLiveData<Water?>(null)
/**
* Quantity of water the user drank today
*/
val water: LiveData<Water?> = _water val water: LiveData<Water?> = _water
private val _weights = MutableLiveData<List<Weight>?>(null) private val _weights = MutableLiveData<List<Weight>?>(null)
/**
* The list of weight of the user
*/
val weights: LiveData<List<Weight>?> = _weights val weights: LiveData<List<Weight>?> = _weights
/**
* The size of a cup for the quick water intake add
*/
var waterCupSize = config.getInt("water_cup_size").toLiveData() var waterCupSize = config.getInt("water_cup_size").toLiveData()
var waterUnit = /**
UnitFactory.volume(settings.getString("water_unit", "milliliter") ?: "Milliliter") * The unit used to display the water intake of the user
*/
var waterUnit = Units.Volume.find(config.getString("water_unit").value ?: "ml")
private val _massUnit = MutableLiveData(Units.Mass.KILOGRAM) private val _massUnit = MutableLiveData(Units.Mass.KILOGRAM)
/**
* The Mass unit used by the user
*/
val massUnit: LiveData<Units.Mass> = _massUnit val massUnit: LiveData<Units.Mass> = _massUnit
/**
* the User weight goal
*/
val goalWeight = config.getFloat(Settings.WEIGHT_GOAL).toLiveData() val goalWeight = config.getFloat(Settings.WEIGHT_GOAL).toLiveData()
val dailyWaterIntake: Int = val dailyWaterIntake: Float = (config.getFloat("water_intake").value ?: 1200f) * waterUnit.modifier
((settings.getString("water_intake", "1200")?.toFloatOrNull() ?: 1200f) * waterUnit.modifier)
.toInt()
init { init {
// Fetch today's water intake
viewModelScope.launch { viewModelScope.launch {
waterRepository.todayWater().collectLatest { waterRepository.todayWater().collectLatest {
_water.postValue(it) _water.postValue(it)
} }
} }
// Fetch the user weights
viewModelScope.launch { viewModelScope.launch {
_steps.postValue(stepRepository.todaySteps()) _steps.postValue(stepRepository.todaySteps())
} }
this._stepsGoal.postValue( // fetch the user weights
config.getInt(Settings.STEPS_GOAL).value
)
viewModelScope.launch { viewModelScope.launch {
weightRepository.getWeights().collectLatest { weightRepository.getWeights().collectLatest {
_weights.postValue(it) _weights.postValue(it)
@ -86,24 +106,6 @@ class HomeViewModel @Inject internal constructor(
} }
} }
/**
* @deprecated
*/
fun fetchWeights() = weightRepository.getWeights()
/**
* @deprecated
*/
fun lastWeight() = weightRepository.lastWeight()
fun fetchWeight(id: Long) = weightRepository.getWeight(id)
suspend fun deleteWeight(weight: Weight) = weightRepository.deleteWeight(weight)
suspend fun addWeight(weight: Weight) = weightRepository.addWeight(weight)
fun fetchTodayWater() = waterRepository.todayWater()
fun updateWater(water: Water) { fun updateWater(water: Water) {
viewModelScope.launch { viewModelScope.launch {
waterRepository.addWater(water) waterRepository.addWater(water)

View File

@ -20,12 +20,10 @@ import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.timepicker.MaterialTimePicker import com.google.android.material.timepicker.MaterialTimePicker
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import java.util.*
@AndroidEntryPoint @AndroidEntryPoint
class EditWeightDialog : class EditWeightDialog :
BaseFullscreenDialog<HomeViewModel, DialogEditWeightBinding>(HomeViewModel::class.java) { BaseFullscreenDialog<EditWeightDialogViewModel, DialogEditWeightBinding>(HomeViewModel::class.java) {
override val bindingInflater: (LayoutInflater) -> DialogEditWeightBinding = override val bindingInflater: (LayoutInflater) -> DialogEditWeightBinding =
DialogEditWeightBinding::inflate DialogEditWeightBinding::inflate

View File

@ -0,0 +1,60 @@
package com.dzeio.openhealth.ui.weight
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.dzeio.openhealth.Settings
import com.dzeio.openhealth.core.BaseViewModel
import com.dzeio.openhealth.data.water.Water
import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.data.weight.WeightRepository
import com.dzeio.openhealth.units.Units
import com.dzeio.openhealth.utils.Configuration
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class EditWeightDialogViewModel @Inject internal constructor(
private val weightRepository: WeightRepository,
config: Configuration
) : BaseViewModel() {
private val _water = MutableLiveData<Water?>(null)
/**
* Quantity of water the user drank today
*/
val water: LiveData<Water?> = _water
private val _weights = MutableLiveData<List<Weight>?>(null)
private val _massUnit = MutableLiveData(Units.Mass.KILOGRAM)
init {
// fetch the user weights
viewModelScope.launch {
weightRepository.getWeights().collectLatest {
_weights.postValue(it)
}
}
config.getString(Settings.MASS_UNIT).apply {
addObserver {
if (it == null) return@addObserver
_massUnit.postValue(Units.Mass.find(it))
}
if (value != null) {
_massUnit.postValue(Units.Mass.find(value!!))
}
}
}
fun fetchWeight(id: Long) = weightRepository.getWeight(id)
suspend fun deleteWeight(weight: Weight) = weightRepository.deleteWeight(weight)
suspend fun addWeight(weight: Weight) = weightRepository.addWeight(weight)
}