1
0
mirror of https://github.com/dzeiocom/OpenHealth.git synced 2025-04-22 19:02:16 +00:00

feat(app): Allow to use Pounds instead of Kilogram

This commit is contained in:
Florian Bouillon 2022-08-25 01:00:22 +02:00
parent 6f51d1bc55
commit 7b6eb75db8
Signed by: Florian Bouillon
GPG Key ID: BEEAF3722D0EBF64
27 changed files with 305 additions and 267 deletions

View File

@ -22,4 +22,9 @@ object Settings {
const val WEIGHT_GOAL = "com.dzeio.open-health.weight.goal" const val WEIGHT_GOAL = "com.dzeio.open-health.weight.goal"
/**
* format in which the weight the user want it to be displayed as
*/
const val MASS_UNIT = "com.dzeio.open-health.unit.mass"
} }

View File

@ -6,11 +6,11 @@ import com.dzeio.openhealth.core.BaseAdapter
import com.dzeio.openhealth.core.BaseViewHolder import com.dzeio.openhealth.core.BaseViewHolder
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.databinding.LayoutItemListBinding import com.dzeio.openhealth.databinding.LayoutItemListBinding
import com.dzeio.openhealth.units.WeightUnit import com.dzeio.openhealth.units.Units
class WeightAdapter : BaseAdapter<Weight, LayoutItemListBinding>() { class WeightAdapter : BaseAdapter<Weight, LayoutItemListBinding>() {
var unit: WeightUnit = WeightUnit.KG var unit: Units.Mass = Units.Mass.KILOGRAM
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> LayoutItemListBinding override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> LayoutItemListBinding
get() = LayoutItemListBinding::inflate get() = LayoutItemListBinding::inflate
@ -22,8 +22,11 @@ class WeightAdapter : BaseAdapter<Weight, LayoutItemListBinding>() {
item: Weight, item: Weight,
position: Int position: Int
) { ) {
val weightTxt = String.format("%.1f", item.weight * unit.fromKG)
holder.binding.value.text = "$weightTxt${unit.unit}"
holder.binding.value.text =
holder.itemView.context.getString(unit.unit, unit.formatToString(item.weight))
holder.binding.datetime.text = item.formatTimestamp() holder.binding.datetime.text = item.formatTimestamp()
holder.binding.edit.setOnClickListener { holder.binding.edit.setOnClickListener {
onItemClick?.invoke(item) onItemClick?.invoke(item)

View File

@ -76,6 +76,7 @@ class StepSource(
timeSinceLastRecord = timeSinceLastBoot timeSinceLastRecord = timeSinceLastBoot
runBlocking { runBlocking {
// keep check because shit as already happened where it send an event even before it is set
if (events != null) { if (events != null) {
events.send(diff) events.send(diff)
} }
@ -87,4 +88,4 @@ class StepSource(
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
Log.d(TAG, "[Accuracy changed]: Sensor: $sensor, Accuracy: $accuracy") Log.d(TAG, "[Accuracy changed]: Sensor: $sensor, Accuracy: $accuracy")
} }
} }

View File

@ -10,10 +10,13 @@ import java.text.DateFormat.getDateInstance
data class Weight( data class Weight(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long = 0, var id: Long = 0,
/**
* Store the weight in kilograms
*/
var weight: Float = 0f, var weight: Float = 0f,
@ColumnInfo(index = true) @ColumnInfo(index = true)
var timestamp: Long = System.currentTimeMillis(), var timestamp: Long = System.currentTimeMillis(),
var source: String = "" var source: String = ""
) { ) {
fun formatTimestamp(): String = getDateInstance().format(Date(timestamp)); fun formatTimestamp(): String = getDateInstance().format(Date(timestamp));
} }

View File

@ -90,5 +90,12 @@ class BrowseFragment :
binding.stepsText.setText("$it of xxx steps") binding.stepsText.setText("$it of xxx steps")
} }
viewModel.weight.observe(viewLifecycleOwner) {
binding.weightText.setText(String.format(
resources.getString(R.string.weight_current),
it
))
}
} }
} }

View File

@ -5,21 +5,36 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.dzeio.openhealth.core.BaseViewModel import com.dzeio.openhealth.core.BaseViewModel
import com.dzeio.openhealth.data.step.StepRepository import com.dzeio.openhealth.data.step.StepRepository
import com.dzeio.openhealth.data.weight.WeightRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class BrowseViewModel @Inject internal constructor( class BrowseViewModel @Inject internal constructor(
stepRepository: StepRepository stepRepository: StepRepository,
weightRepository: WeightRepository
) : BaseViewModel() { ) : BaseViewModel() {
private val _steps = MutableLiveData(0) private val _steps = MutableLiveData(0)
val steps: LiveData<Int> = _steps val steps: LiveData<Int> = _steps
private val _weight = MutableLiveData(0f)
val weight: LiveData<Float> = _weight
init { init {
viewModelScope.launch { viewModelScope.launch {
_steps.postValue(stepRepository.todaySteps()) _steps.postValue(stepRepository.todaySteps())
} }
viewModelScope.launch {
weightRepository.lastWeight().collectLatest {
if (it == null) {
return@collectLatest
}
_weight.postValue(it.weight)
}
}
} }
} }

View File

@ -7,7 +7,6 @@ import android.graphics.Canvas
import android.graphics.RectF import android.graphics.RectF
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.dzeio.openhealth.core.BaseFragment import com.dzeio.openhealth.core.BaseFragment
@ -15,13 +14,12 @@ import com.dzeio.openhealth.data.water.Water
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.databinding.FragmentHomeBinding import com.dzeio.openhealth.databinding.FragmentHomeBinding
import com.dzeio.openhealth.graphs.WeightChart import com.dzeio.openhealth.graphs.WeightChart
import com.dzeio.openhealth.ui.weight.AddWeightDialog import com.dzeio.openhealth.ui.weight.WeightDialog
import com.dzeio.openhealth.units.UnitFactory import com.dzeio.openhealth.units.UnitFactory
import com.dzeio.openhealth.utils.DrawUtils import com.dzeio.openhealth.utils.DrawUtils
import com.dzeio.openhealth.utils.GraphUtils 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 kotlinx.coroutines.flow.collectLatest
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -39,7 +37,11 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
super.onStart() super.onStart()
// Bindings // Bindings
binding.addWeight.setOnClickListener { binding.addWeight.setOnClickListener {
AddWeightDialog().show(requireActivity().supportFragmentManager, null) findNavController().navigate(
HomeFragmentDirections.actionNavHomeToNavWeightDialog(
WeightDialog.DialogTypes.ADD_WEIGHT.ordinal
)
)
} }
binding.fragmentHomeWaterAdd.setOnClickListener { binding.fragmentHomeWaterAdd.setOnClickListener {
@ -94,13 +96,6 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
) )
) )
lifecycleScope.launchWhenStarted {
viewModel.fetchWeights().collectLatest {
updateGraph(it)
}
updateWater(0)
}
viewModel.water.observe(viewLifecycleOwner) { viewModel.water.observe(viewLifecycleOwner) {
if (it != null) { if (it != null) {
updateWater(it.value) updateWater(it.value)
@ -109,13 +104,18 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
} }
} }
viewModel.goalWeight.observe(viewLifecycleOwner) { viewModel.weights.observe(viewLifecycleOwner) {
lifecycleScope.launchWhenStarted { if (it != null) {
viewModel.fetchWeights().collectLatest { updateGraph(it)
updateGraph(it)
}
} }
}
viewModel.goalWeight.observe(viewLifecycleOwner) {
if (viewModel.weights.value != null) updateGraph(viewModel.weights.value!!)
}
viewModel.massUnit.observe(viewLifecycleOwner) {
if (viewModel.weights.value != null) updateGraph(viewModel.weights.value!!)
} }
} }
@ -124,7 +124,7 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
binding.weightGraph, binding.weightGraph,
requireView(), requireView(),
list, list,
viewModel.weightUnit, viewModel.massUnit.value!!,
viewModel.goalWeight.value viewModel.goalWeight.value
) )

View File

@ -1,11 +1,9 @@
package com.dzeio.openhealth.ui.home package com.dzeio.openhealth.ui.home
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.dzeio.openhealth.Application.Companion.TAG
import com.dzeio.openhealth.Settings import com.dzeio.openhealth.Settings
import com.dzeio.openhealth.core.BaseViewModel import com.dzeio.openhealth.core.BaseViewModel
import com.dzeio.openhealth.data.water.Water import com.dzeio.openhealth.data.water.Water
@ -13,6 +11,7 @@ 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.UnitFactory
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
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
@ -30,13 +29,16 @@ class HomeViewModel @Inject internal constructor(
private val _water = MutableLiveData<Water?>(null) private val _water = MutableLiveData<Water?>(null)
val water: LiveData<Water?> = _water val water: LiveData<Water?> = _water
private val _weights = MutableLiveData<List<Weight>?>(null)
val weights: LiveData<List<Weight>?> = _weights
var waterCupSize = settings.getInt("water_cup_size", 200) var waterCupSize = settings.getInt("water_cup_size", 200)
var waterUnit = var waterUnit =
UnitFactory.volume(settings.getString("water_unit", "milliliter") ?: "Milliliter") UnitFactory.volume(settings.getString("water_unit", "milliliter") ?: "Milliliter")
var weightUnit = private val _massUnit = MutableLiveData(Units.Mass.KILOGRAM)
UnitFactory.mass(settings.getString("weight_unit", "kilogram") ?: "kilogram") val massUnit: LiveData<Units.Mass> = _massUnit
val goalWeight = config.getFloat(Settings.WEIGHT_GOAL).toLiveData() val goalWeight = config.getFloat(Settings.WEIGHT_GOAL).toLiveData()
@ -47,16 +49,23 @@ class HomeViewModel @Inject internal constructor(
init { init {
viewModelScope.launch { viewModelScope.launch {
waterRepository.todayWater().collectLatest { waterRepository.todayWater().collectLatest {
_water.value = it _water.postValue(it)
} }
} }
// don't listen for prefs changes
settings.registerOnSharedPreferenceChangeListener { _, key -> viewModelScope.launch {
Log.d(TAG, "Pref changed: $key") weightRepository.getWeights().collectLatest {
when (key) { _weights.postValue(it)
"water_cup_size" -> { }
waterCupSize = settings.getInt("water_cup_size", 200) }
}
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!!))
} }
} }
} }

View File

@ -13,14 +13,21 @@ import com.dzeio.openhealth.Application
import com.dzeio.openhealth.BuildConfig import com.dzeio.openhealth.BuildConfig
import com.dzeio.openhealth.R import com.dzeio.openhealth.R
import com.dzeio.openhealth.Settings import com.dzeio.openhealth.Settings
import com.dzeio.openhealth.units.UnitFactory import com.dzeio.openhealth.units.Units
import com.dzeio.openhealth.utils.Configuration
import com.dzeio.openhealth.utils.LocaleUtils import com.dzeio.openhealth.utils.LocaleUtils
import dagger.hilt.android.AndroidEntryPoint
import java.util.Locale import java.util.Locale
import javax.inject.Inject
@AndroidEntryPoint
class SettingsFragment : PreferenceFragmentCompat() { class SettingsFragment : PreferenceFragmentCompat() {
@Inject
lateinit var config: Configuration
private companion object { private companion object {
const val TAG = "${Application.TAG}/SettingsFragment" const val TAG = "${Application.TAG}/Settings"
} }
val settings: SharedPreferences by lazy { val settings: SharedPreferences by lazy {
@ -31,53 +38,42 @@ class SettingsFragment : PreferenceFragmentCompat() {
setPreferencesFromResource(R.xml.preferences, rootKey) setPreferencesFromResource(R.xml.preferences, rootKey)
// Force only numbers on Goal // Force only numbers on Goal
val weightGoal = findPreference<EditTextPreference>(Settings.WEIGHT_GOAL) val weightGoal = findPreference<EditTextPreference>("tmp_goal_weight")
weightGoal?.apply { weightGoal?.apply {
setOnBindEditTextListener { setOnBindEditTextListener {
it.inputType = InputType.TYPE_CLASS_NUMBER it.setSelectAllOnFocus(true)
it.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
} }
val value = settings.getString(Settings.WEIGHT_GOAL, null)
val modifier = UnitFactory.mass(settings.getString("weight_unit", null) ?: "kilogram") val value = config.getFloat(Settings.WEIGHT_GOAL)
if (value != null && value.isNotEmpty()) { setOnPreferenceClickListener {
text = (value.toFloat() * modifier.modifier).toString() if (value.value != null) {
val unit = config.getString(Settings.MASS_UNIT).value
text = if (unit == null) {
value.value!!.toString()
} else {
val modifier = Units.Mass.find(unit).modifier
(value.value!! * modifier).toString()
}
}
return@setOnPreferenceClickListener true
} }
setOnPreferenceChangeListener { _, newValue -> setOnPreferenceChangeListener { _, newValue ->
val alue = ((newValue as String).toInt() / modifier.modifier).toInt().toString() val unit = config.getString(Settings.MASS_UNIT).value
settings.edit() var modifier = Units.Mass.KILOGRAM.modifier
.putString( if (unit != null) {
Settings.WEIGHT_GOAL, modifier = Units.Mass.find(unit).modifier
alue }
)
.apply() value.value = ((newValue as String).toFloat() / modifier)
text = alue
return@setOnPreferenceChangeListener false return@setOnPreferenceChangeListener false
} }
} }
// 251 kg
// 553 lb
findPreference<ListPreference>("weight_unit")?.apply {
setOnPreferenceChangeListener { _, newValue ->
val unit = settings.getString("weight_unit", "kilogram")
?: return@setOnPreferenceChangeListener true
val goal = settings.getString(Settings.WEIGHT_GOAL, null)
?: return@setOnPreferenceChangeListener true
val modifier = UnitFactory.mass(newValue as String)
val oldModifier = UnitFactory.mass(unit)
val value =
(goal.toFloat() / oldModifier.modifier * modifier.modifier).toInt().toString()
settings.edit()
.putString(
Settings.WEIGHT_GOAL,
value
)
.apply()
weightGoal?.text = value
return@setOnPreferenceChangeListener true
}
}
val languagesPreference = findPreference<ListPreference>(Settings.APP_LANGUAGE) val languagesPreference = findPreference<ListPreference>(Settings.APP_LANGUAGE)
Log.d(TAG, Locale.getDefault().language) Log.d(TAG, Locale.getDefault().language)
languagesPreference?.apply { languagesPreference?.apply {

View File

@ -1,65 +0,0 @@
package com.dzeio.openhealth.ui.weight
import android.view.LayoutInflater
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.dzeio.openhealth.R
import com.dzeio.openhealth.core.BaseDialog
import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.databinding.DialogAddWeightBinding
import com.dzeio.openhealth.ui.home.HomeViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class AddWeightDialog :
BaseDialog<HomeViewModel, DialogAddWeightBinding>(HomeViewModel::class.java) {
override val bindingInflater: (LayoutInflater) -> DialogAddWeightBinding = DialogAddWeightBinding::inflate
override fun onBuilderInit(builder: MaterialAlertDialogBuilder) {
super.onBuilderInit(builder)
builder.apply {
setTitle("Add your weight (kg)")
setIcon(activity?.let { ContextCompat.getDrawable(it, R.drawable.ic_outline_timeline_24) })
setPositiveButton("Validate") { _, _ ->
save()
}
setNegativeButton("Cancel") { dialog, _ ->
dialog.cancel()
}
}
}
override fun onCreated() {
super.onCreated()
lifecycleScope.launchWhenStarted {
viewModel.lastWeight().collect {
if (it != null) {
binding.kg.value = it.weight.toInt()
binding.gram.value = ((it.weight - it.weight.toInt()) * 10).toInt()
}
}
}
binding.kg.maxValue = 636
binding.kg.minValue = 0
binding.gram.maxValue = 9
binding.gram.minValue = 0
}
private fun save() {
val weight = Weight().apply {
weight = binding.kg.value + (binding.gram.value.toFloat() / 10)
source = "OpenHealth"
}
lifecycleScope.launchWhenCreated {
viewModel.addWeight(weight)
}
// callback?.invoke()
dialog?.dismiss()
}
}

View File

@ -7,7 +7,6 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -17,11 +16,9 @@ import com.dzeio.openhealth.core.BaseFragment
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.databinding.FragmentListWeightBinding import com.dzeio.openhealth.databinding.FragmentListWeightBinding
import com.dzeio.openhealth.graphs.WeightChart import com.dzeio.openhealth.graphs.WeightChart
import com.dzeio.openhealth.units.WeightUnit
import com.dzeio.openhealth.utils.GraphUtils 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 kotlinx.coroutines.flow.collectLatest
@AndroidEntryPoint @AndroidEntryPoint
class ListWeightFragment : class ListWeightFragment :
@ -50,41 +47,33 @@ class ListWeightFragment :
) )
} }
val recycler = binding.list val adapter = WeightAdapter().apply {
onItemClick = {
val manager = LinearLayoutManager(requireContext()) findNavController().navigate(
recycler.layoutManager = manager ListWeightFragmentDirections.actionNavListWeightToNavEditWeight(
it.id
val adapter = WeightAdapter() )
val unit = settings.getString("weight_unit", "Kilogram") ?: "Kilogram"
adapter.unit = WeightUnit.fromSettings(unit)
adapter.onItemClick = {
findNavController().navigate(
ListWeightFragmentDirections.actionNavListWeightToNavEditWeight(
it.id
) )
)
// EditWeightDialog().show(requireActivity().supportFragmentManager, "dialog")
}
recycler.adapter = adapter
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
viewModel.fetchWeights().collectLatest {
updateGraph(it)
val itt = it.toMutableList()
itt.sortWith { o1, o2 -> if (o1.timestamp > o2.timestamp) -1 else 1 }
adapter.set(itt)
} }
} }
viewModel.goalWeight.observe(viewLifecycleOwner) { val recycler = binding.list.apply {
viewLifecycleOwner.lifecycleScope.launchWhenCreated { val manager = LinearLayoutManager(requireContext())
viewModel.fetchWeights().collectLatest { layoutManager = manager
updateGraph(it) this.adapter = adapter
} }
viewModel.massUnit.observe(viewLifecycleOwner) {
adapter.unit = it
// adapter.notifyDataSetChanged()
}
viewModel.weights.observe(viewLifecycleOwner) {
if (it != null) {
val itt = it.toMutableList()
itt.sortWith { o1, o2 -> if (o1.timestamp > o2.timestamp) -1 else 1 }
adapter.set(itt)
updateGraph(it)
} }
} }
@ -106,18 +95,20 @@ class ListWeightFragment :
binding.chart, binding.chart,
requireView(), requireView(),
list, list,
viewModel.weightUnit, viewModel.massUnit.value!!,
viewModel.goalWeight.value, viewModel.goalWeight.value,
false false
) )
} }
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) { override fun onPrepareOptionsMenu(menu: Menu) {
menu.findItem(R.id.action_add).isVisible = true menu.findItem(R.id.action_add).isVisible = true
super.onPrepareOptionsMenu(menu) super.onPrepareOptionsMenu(menu)
} }
@Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) { return when (item.itemId) {
R.id.action_add -> { R.id.action_add -> {

View File

@ -1,11 +1,17 @@
package com.dzeio.openhealth.ui.weight 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.Settings
import com.dzeio.openhealth.core.BaseViewModel import com.dzeio.openhealth.core.BaseViewModel
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.utils.Configuration import com.dzeio.openhealth.utils.Configuration
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@ -14,16 +20,32 @@ class ListWeightViewModel @Inject internal constructor(
private val settings: Configuration private val settings: Configuration
) : BaseViewModel() { ) : BaseViewModel() {
private val _massUnit = MutableLiveData(Units.Mass.KILOGRAM)
val massUnit: LiveData<Units.Mass> = _massUnit
private val _goalWeight = settings.getFloat(Settings.WEIGHT_GOAL) private val _goalWeight = settings.getFloat(Settings.WEIGHT_GOAL)
var weightUnit =
UnitFactory.mass(settings.getString("weight_unit").value ?: "kilogram")
val goalWeight = _goalWeight.toLiveData() val goalWeight = _goalWeight.toLiveData()
fun fetchWeights() = weightRepository.getWeights() private val _weights = MutableLiveData<List<Weight>?>(null)
val weights: LiveData<List<Weight>?> = _weights
fun setWeightGoal(value: Float) {
_goalWeight.value = value init {
viewModelScope.launch {
weightRepository.getWeights().collectLatest {
_weights.postValue(it)
}
}
settings.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!!))
}
}
} }
} }

View File

@ -3,21 +3,22 @@ package com.dzeio.openhealth.ui.weight
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import com.dzeio.openhealth.R import com.dzeio.openhealth.R
import com.dzeio.openhealth.core.BaseDialog import com.dzeio.openhealth.core.BaseDialog
import com.dzeio.openhealth.databinding.DialogAddWeightBinding import com.dzeio.openhealth.databinding.DialogWeightBinding
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint @AndroidEntryPoint
class WeightDialog : class WeightDialog :
BaseDialog<WeightDialogViewModel, DialogAddWeightBinding>(WeightDialogViewModel::class.java) { BaseDialog<WeightDialogViewModel, DialogWeightBinding>(WeightDialogViewModel::class.java) {
private val args: WeightDialogArgs by navArgs() private val args: WeightDialogArgs by navArgs()
override val bindingInflater: (LayoutInflater) -> DialogAddWeightBinding = override val bindingInflater: (LayoutInflater) -> DialogWeightBinding =
DialogAddWeightBinding::inflate DialogWeightBinding::inflate
override fun onBuilderInit(builder: MaterialAlertDialogBuilder) { override fun onBuilderInit(builder: MaterialAlertDialogBuilder) {
super.onBuilderInit(builder) super.onBuilderInit(builder)
@ -48,11 +49,14 @@ class WeightDialog :
super.onCreated() super.onCreated()
setValue(0f) setValue(0f)
if (args.dialogType == DialogTypes.EDIT_GOAL.ordinal) { if (args.dialogType == DialogTypes.ADD_WEIGHT.ordinal) {
Log.d("TAG", viewModel.toString()) viewModel.initWithWeight(null)
Log.d("TAG", viewModel.goalWeight.value.toString()) viewModel.weight.observe(this) {
if (it != null) setValue(it.weight * viewModel.format.modifier)
}
} else if (args.dialogType == DialogTypes.EDIT_GOAL.ordinal) {
viewModel.goalWeight.observe(this) { viewModel.goalWeight.observe(this) {
if (it != null) setValue(it) if (it != null) setValue(it * viewModel.format.modifier)
} }
} }
@ -85,6 +89,14 @@ class WeightDialog :
*/ */
private fun runAction(click: Int) { private fun runAction(click: Int) {
when (DialogTypes.values()[args.dialogType]) { when (DialogTypes.values()[args.dialogType]) {
DialogTypes.ADD_WEIGHT -> {
val value = getValue()
if (click == 0) {
lifecycleScope.launchWhenCreated {
viewModel.addWeight(value)
}
}
}
DialogTypes.EDIT_GOAL -> { DialogTypes.EDIT_GOAL -> {
if (click == 1) { if (click == 1) {
return return
@ -106,6 +118,7 @@ class WeightDialog :
val icon: Drawable? = null, val icon: Drawable? = null,
val thirdText: Int? = null val thirdText: Int? = null
) { ) {
ADD_WEIGHT("Add Weight", null),
EDIT_GOAL("Edit Goal", null, R.string.goal_remove) EDIT_GOAL("Edit Goal", null, R.string.goal_remove)
} }
} }

View File

@ -1,11 +1,17 @@
package com.dzeio.openhealth.ui.weight 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.Settings
import com.dzeio.openhealth.core.BaseViewModel import com.dzeio.openhealth.core.BaseViewModel
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.utils.Configuration import com.dzeio.openhealth.utils.Configuration
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@ -16,12 +22,38 @@ class WeightDialogViewModel @Inject internal constructor(
private val _goalWeight = settings.getFloat(Settings.WEIGHT_GOAL) private val _goalWeight = settings.getFloat(Settings.WEIGHT_GOAL)
var weightUnit =
UnitFactory.mass(settings.getString("weight_unit").value ?: "kilogram")
val goalWeight = _goalWeight.toLiveData() val goalWeight = _goalWeight.toLiveData()
private val _weight = MutableLiveData<Weight?>(null)
val weight: LiveData<Weight?> = _weight
val format =
Units.Mass.find(settings.getString(Settings.MASS_UNIT).value ?: Units.Mass.KILOGRAM.id)
fun initWithWeight(id: Long?) {
viewModelScope.launch {
if (id != null) {
weightRepository.getWeight(id).collectLatest {
_weight.postValue(it)
}
} else {
weightRepository.lastWeight().collectLatest {
_weight.postValue(it)
}
}
}
}
suspend fun addWeight(weight: Float) {
weightRepository.addWeight(Weight(weight = weight / format.modifier))
}
fun setWeightGoal(value: Float?) { fun setWeightGoal(value: Float?) {
_goalWeight.value = value if (value != null) {
_goalWeight.value = value / format.modifier
} else {
_goalWeight.value = null
}
} }
} }

View File

@ -1,6 +1,7 @@
package com.dzeio.openhealth.units package com.dzeio.openhealth.units
object UnitFactory { object UnitFactory {
@Deprecated("Move to Units.Mass.find")
fun mass(unit: String): Units.Mass { fun mass(unit: String): Units.Mass {
return when (unit.lowercase()) { return when (unit.lowercase()) {
"kilogram", "kilograms", "kg" -> Units.Mass.KILOGRAM "kilogram", "kilograms", "kg" -> Units.Mass.KILOGRAM
@ -9,6 +10,7 @@ object UnitFactory {
} }
} }
@Deprecated("Move to Units.Volume.find")
fun volume(unit: String): Units.Volume { fun volume(unit: String): Units.Volume {
return when (unit.lowercase()) { return when (unit.lowercase()) {
"milliliter", "milliliters", "ml" -> Units.Volume.MILLILITER "milliliter", "milliliters", "ml" -> Units.Volume.MILLILITER

View File

@ -4,6 +4,7 @@ import com.dzeio.openhealth.R
object Units { object Units {
enum class Mass( enum class Mass(
val id: String,
/** /**
* Value based on the Kilogram * Value based on the Kilogram
*/ */
@ -13,22 +14,42 @@ object Units {
val unit: Int val unit: Int
) { ) {
KILOGRAM( KILOGRAM(
"kg",
1f, 1f,
R.string.unit_mass_kilogram_name_singular, R.string.unit_mass_kilogram_name_singular,
R.string.unit_mass_kilogram_name_plural, R.string.unit_mass_kilogram_name_plural,
R.string.unit_mass_kilogram_unit R.string.unit_mass_kilogram_unit
), ),
POUND( POUND(
0.45359237f, "lbs",
2.204623f,
R.string.unit_mass_pound_name_singular, R.string.unit_mass_pound_name_singular,
R.string.unit_mass_pound_name_plural, R.string.unit_mass_pound_name_plural,
R.string.unit_mass_pound_unit R.string.unit_mass_pound_unit
) );
companion object {
fun find(value: String): Mass {
return Mass.values().find {
it.id == value
} ?: KILOGRAM
}
}
fun format(value: Float): Float {
return value * modifier
}
fun formatToString(value: Float): String {
return String.format("%.1f", value * modifier)
}
} }
enum class Volume( enum class Volume(
val id: String,
/** /**
* Value based on the Kilogram * Value based on the Milliliter
*/ */
val modifier: Float, val modifier: Float,
val singular: Int, val singular: Int,
@ -36,22 +57,33 @@ object Units {
val unit: Int val unit: Int
) { ) {
MILLILITER( MILLILITER(
"ml",
1f, 1f,
R.string.unit_volume_milliliter_name_singular, R.string.unit_volume_milliliter_name_singular,
R.string.unit_volume_milliliter_name_plural, R.string.unit_volume_milliliter_name_plural,
R.string.unit_volume_milliliter_unit R.string.unit_volume_milliliter_unit
), ),
IMPERIAL_OUNCE( IMPERIAL_OUNCE(
"ioz",
0.03519503f, 0.03519503f,
R.string.unit_volume_imperial_ounce_name_singular, R.string.unit_volume_imperial_ounce_name_singular,
R.string.unit_volume_imperial_ounce_name_plural, R.string.unit_volume_imperial_ounce_name_plural,
R.string.unit_volume_ounce_unit R.string.unit_volume_ounce_unit
), ),
US_OUNCE( US_OUNCE(
"uoz",
0.03381413f, 0.03381413f,
R.string.unit_volume_us_ounce_name_singular, R.string.unit_volume_us_ounce_name_singular,
R.string.unit_volume_us_ounce_name_plural, R.string.unit_volume_us_ounce_name_plural,
R.string.unit_volume_ounce_unit R.string.unit_volume_ounce_unit
) );
companion object {
fun find(value: String): Volume {
return Volume.values().find {
it.id == value
} ?: MILLILITER
}
}
} }
} }

View File

@ -1,5 +1,6 @@
package com.dzeio.openhealth.units package com.dzeio.openhealth.units
@Deprecated("Move to Units.Volume")
enum class WaterUnit( enum class WaterUnit(
val unit: String, val unit: String,
val fromML: Float val fromML: Float

View File

@ -1,19 +0,0 @@
package com.dzeio.openhealth.units
enum class WeightUnit(
val unit: String,
val fromKG: Float
) {
KG("kg", 1f),
LBS("lbs", 2.2046226218488f);
companion object {
fun fromSettings(value: String): WeightUnit {
return when (value.lowercase()) {
"kilogram" -> KG
"pounds" -> LBS
else -> KG
}
}
}
}

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">
<android.widget.NumberPicker
android:id="@+id/kg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<android.widget.NumberPicker
android:id="@+id/gram"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:progress="0" />
</LinearLayout>

View File

@ -16,7 +16,6 @@
<android.widget.NumberPicker <android.widget.NumberPicker
android:id="@+id/gram" android:id="@+id/gram"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content" />
android:progress="0" />
</LinearLayout> </LinearLayout>

View File

@ -208,6 +208,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Weight" /> android:text="Weight" />
<TextView
android:layout_width="match_parent"
android:id="@+id/weight_text"
android:layout_height="wrap_content"
tools:text="current weight: xxkg" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -24,6 +24,9 @@
<action <action
android:id="@+id/action_nav_home_to_nav_add_weight_dialog" android:id="@+id/action_nav_home_to_nav_add_weight_dialog"
app:destination="@id/nav_add_weight_dialog" /> app:destination="@id/nav_add_weight_dialog" />
<action
android:id="@+id/action_nav_home_to_nav_weight_dialog"
app:destination="@id/nav_weight_dialog" />
</fragment> </fragment>
<fragment <fragment

View File

@ -41,6 +41,7 @@
<string name="edit_daily_goal">Modifier le but journalier</string> <string name="edit_daily_goal">Modifier le but journalier</string>
<string name="permission_declined">Vous avez décliné une permission, vous ne pouvez pas utiliser cette extension suaf si vous réactivez la permission manuellement</string> <string name="permission_declined">Vous avez décliné une permission, vous ne pouvez pas utiliser cette extension suaf si vous réactivez la permission manuellement</string>
<string name="menu_steps">Pas</string> <string name="menu_steps">Pas</string>
<string name="weight_current">Poid actuel: %1$s%2$s</string>
<!-- Error Activity Translations --> <!-- Error Activity Translations -->
<string name="error_app_crash">Une Erreur est survenu lors de l\'utilisation de l\'application</string> <string name="error_app_crash">Une Erreur est survenu lors de l\'utilisation de l\'application</string>

View File

@ -4,13 +4,4 @@
<item>Male</item> <item>Male</item>
<item>Female</item> <item>Female</item>
</string-array> </string-array>
<string-array name="weight_units">
<item name="kg">@string/unit_mass_kilogram_name_plural</item>
<item name="lb">@string/unit_mass_pound_name_singular</item>
</string-array>
<string-array name="water_units">
<item name="ml">@string/unit_volume_milliliter_name_singular</item>
<item name="us_oz">@string/unit_volume_imperial_ounce_name_singular</item>
<item name="im_oz">@string/unit_volume_us_ounce_name_singular</item>
</string-array>
</resources> </resources>

View File

@ -17,7 +17,7 @@
<string name="unit_mass_pound_name_singular">Pound</string> <string name="unit_mass_pound_name_singular">Pound</string>
<string name="unit_mass_pound_name_plural">Pounds</string> <string name="unit_mass_pound_name_plural">Pounds</string>
<string name="unit_mass_pound_unit" translatable="false">%1$slb</string> <string name="unit_mass_pound_unit" translatable="false">%1$slbs</string>
<string name="unit_volume_milliliter_name_singular">Milliliter</string> <string name="unit_volume_milliliter_name_singular">Milliliter</string>
<string name="unit_volume_milliliter_name_plural">Milliliters</string> <string name="unit_volume_milliliter_name_plural">Milliliters</string>
@ -52,6 +52,7 @@
<string name="permission_declined">You declined a permission, you can\'t use this extension unless you enable it manually</string> <string name="permission_declined">You declined a permission, you can\'t use this extension unless you enable it manually</string>
<string name="edit_daily_goal">Modifiy daily goal</string> <string name="edit_daily_goal">Modifiy daily goal</string>
<string name="menu_steps">Steps</string> <string name="menu_steps">Steps</string>
<string name="weight_current">Current weight: %1$s%2$s</string>
<!-- Error Activity Translations --> <!-- Error Activity Translations -->

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Units stored in `com/dzeio/openhealth/units/Units.kt` with their respective ids -->
<resources>
<string-array name="mass_units">
<item name="kg">kg</item>
<item name="lbs">lbs</item>
</string-array>
<string-array name="volume_units">
<item name="ml">ml</item>
<item name="us_oz">uoz</item>
<item name="im_oz">ioz</item>
</string-array>
</resources>

View File

@ -22,18 +22,16 @@
android:title="Height" /> android:title="Height" />
<EditTextPreference <EditTextPreference
android:key="com.dzeio.open-health.weight.goal" android:key="tmp_goal_weight"
android:selectAllOnFocus="true" android:selectAllOnFocus="true"
android:singleLine="true" android:singleLine="true"
android:digits="0123456789"
android:inputType="numberDecimal"
android:title="Goal Weight" /> android:title="Goal Weight" />
<ListPreference <ListPreference
android:defaultValue="1" android:defaultValue="kg"
android:entries="@array/weight_units" android:entries="@array/mass_units"
android:entryValues="@array/weight_units" android:entryValues="@array/mass_units"
android:key="weight_unit" android:key="com.dzeio.open-health.unit.mass"
android:title="Weight Unit" /> android:title="Mass Unit" />
</PreferenceCategory> </PreferenceCategory>
@ -44,11 +42,11 @@
android:key="water_hourly_notification" android:key="water_hourly_notification"
android:title="Enable Hourly Notification" /> android:title="Enable Hourly Notification" />
<ListPreference <ListPreference
android:defaultValue="Millimeters" android:defaultValue="ml"
android:entries="@array/water_units" android:entries="@array/volume_units"
android:entryValues="@array/water_units" android:entryValues="@array/volume_units"
android:key="water_unit" android:key="water_unit"
android:title="Water Unit" /> android:title="Volume Unit" />
<EditTextPreference <EditTextPreference
android:defaultValue="2700" android:defaultValue="2700"
android:key="water_intake" android:key="water_intake"