diff --git a/README.md b/README.md
index 8cf4091..db7a3f0 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ Permissions requests are for specifics usage and are only requests the first tim
| Permission | Why is it requested |
|:--------------------:|:-----------------------------------------------------------|
| ACTIVITY_RECOGNITION | Device Steps Usage |
- | INTERNET | Food fetching from OpenFoodFact |
+| INTERNET | Food fetching from OpenFoodFact |
| POST_NOTIFICATIONS | send notifications for water intake and device steps usage |
No other permissions are used.
diff --git a/app/src/debug/res/layout/fragment_list_weight.xml b/app/src/debug/res/layout/fragment_list_weight.xml
new file mode 100644
index 0000000..c65def0
--- /dev/null
+++ b/app/src/debug/res/layout/fragment_list_weight.xml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt b/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt
index 9289d8d..737218c 100644
--- a/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt
+++ b/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt
@@ -88,9 +88,7 @@ class StepsHomeFragment :
}
xAxis.apply {
- increment = 86400000.0
-// displayCount = 168
-// displayCount = 10
+ dataWidth = 604800000.0
textPaint.color = MaterialColors.getColor(
requireView(),
com.google.android.material.R.attr.colorOnPrimaryContainer
diff --git a/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightFragment.kt b/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightFragment.kt
index 5c0ed3b..d329bdf 100644
--- a/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightFragment.kt
+++ b/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightFragment.kt
@@ -10,15 +10,18 @@ import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.LinearLayoutManager
+import com.dzeio.charts.Entry
+import com.dzeio.charts.series.LineSerie
import com.dzeio.openhealth.R
import com.dzeio.openhealth.adapters.WeightAdapter
import com.dzeio.openhealth.core.BaseFragment
import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.databinding.FragmentListWeightBinding
-import com.dzeio.openhealth.graphs.WeightChart
-import com.dzeio.openhealth.utils.GraphUtils
import com.google.android.material.color.MaterialColors
import dagger.hilt.android.AndroidEntryPoint
+import java.text.DateFormat
+import java.util.Date
+import java.util.Locale
@AndroidEntryPoint
class ListWeightFragment :
@@ -57,7 +60,7 @@ class ListWeightFragment :
}
}
- val recycler = binding.list.apply {
+ binding.list.apply {
val manager = LinearLayoutManager(requireContext())
layoutManager = manager
this.adapter = adapter
@@ -65,7 +68,6 @@ class ListWeightFragment :
viewModel.massUnit.observe(viewLifecycleOwner) {
adapter.unit = it
-// adapter.notifyDataSetChanged()
}
viewModel.weights.observe(viewLifecycleOwner) {
@@ -77,28 +79,88 @@ class ListWeightFragment :
}
}
- GraphUtils.lineChartSetup(
- binding.chart,
- MaterialColors.getColor(
+ val chart = binding.chart
+
+ val serie = LineSerie(chart).apply {
+ linePaint.color = MaterialColors.getColor(
requireView(),
com.google.android.material.R.attr.colorPrimary
- ),
- MaterialColors.getColor(
- requireView(),
- com.google.android.material.R.attr.colorOnBackground
)
- )
+ textPaint.color = MaterialColors.getColor(
+ requireView(),
+ com.google.android.material.R.attr.colorOnPrimary
+ )
+ }
+
+ chart.apply {
+ series = arrayListOf(serie)
+
+ yAxis.apply {
+ textLabel.color = MaterialColors.getColor(
+ requireView(),
+ com.google.android.material.R.attr.colorOnPrimaryContainer
+ )
+ linePaint.color = MaterialColors.getColor(
+ requireView(),
+ com.google.android.material.R.attr.colorOnPrimaryContainer
+ )
+
+ onValueFormat = { value -> "${value.toInt()}" }
+ }
+
+ xAxis.apply {
+ // 7 day history
+// increment = (7 * 24 * 60 * 60 * 1000).toDouble()
+ textPaint.color = MaterialColors.getColor(
+ requireView(),
+ com.google.android.material.R.attr.colorOnPrimaryContainer
+ )
+ textPaint.textSize = 32f
+ onValueFormat = onValueFormat@{
+ val formatter = DateFormat.getDateTimeInstance(
+ DateFormat.SHORT,
+ DateFormat.SHORT,
+ Locale.getDefault()
+ )
+ return@onValueFormat formatter.format(Date(it.toLong()))
+ }
+
+ }
+ }
+
+ // Debug button
+ if (binding.debugRandomValues != null) {
+ binding.debugRandomValues.setOnClickListener {
+ viewModel.generateRandomValues()
+ }
+ binding.debugRandomValues.setOnLongClickListener {
+ viewModel.delete(viewModel.weights.value!!)
+ return@setOnLongClickListener true
+ }
+ }
}
private fun updateGraph(list: List) {
- WeightChart.setup(
- binding.chart,
- requireView(),
- list,
- viewModel.massUnit.value!!,
- viewModel.goalWeight.value,
- false
- )
+ val chart = binding.chart
+ val serie = chart.series[0] as LineSerie
+
+ val entries: ArrayList = arrayListOf()
+
+ list.forEach {
+ entries.add(Entry(
+ it.timestamp.toDouble(),
+ it.weight
+ ))
+ }
+ serie.entries = entries
+
+ if (list.isEmpty()) {
+ chart.xAxis.x = 0.0
+ } else {
+ chart.xAxis.x = list[0].timestamp.toDouble()
+ }
+
+ chart.refresh()
}
@Deprecated("Deprecated in Java")
diff --git a/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightViewModel.kt b/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightViewModel.kt
index 49b2e16..4496563 100644
--- a/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightViewModel.kt
+++ b/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightViewModel.kt
@@ -13,6 +13,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
+import kotlin.random.Random
@HiltViewModel
class ListWeightViewModel @Inject internal constructor(
@@ -48,4 +49,20 @@ class ListWeightViewModel @Inject internal constructor(
}
}
}
+
+ fun generateRandomValues(): Unit {
+ viewModelScope.launch {
+ weightRepository.addWeight(
+ Weight(
+ weight = Random.nextInt(0, 100).toFloat()
+ )
+ )
+ }
+ }
+
+ fun delete(list: List) {
+ viewModelScope.launch {
+ for (item in list) weightRepository.deleteWeight(item)
+ }
+ }
}
diff --git a/app/src/main/java/com/dzeio/openhealth/units/Units.kt b/app/src/main/java/com/dzeio/openhealth/units/Units.kt
index 443f502..fe29673 100644
--- a/app/src/main/java/com/dzeio/openhealth/units/Units.kt
+++ b/app/src/main/java/com/dzeio/openhealth/units/Units.kt
@@ -91,7 +91,7 @@ object Units {
);
fun formatToString(value: Int): String {
- return String.format("%d", value * modifier)
+ return String.format("%.0f", (value * modifier))
}
companion object {
diff --git a/app/src/main/res/values/health_permissions.xml b/app/src/main/res/values/health_permissions.xml
deleted file mode 100644
index 2c2a0fe..0000000
--- a/app/src/main/res/values/health_permissions.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- - androidx.health.permission.HeartRate.READ
- - androidx.health.permission.HeartRate.WRITE
- - androidx.health.permission.Steps.READ
- - androidx.health.permission.Steps.WRITE
-
-
diff --git a/charts/src/main/java/com/dzeio/charts/ChartView.kt b/charts/src/main/java/com/dzeio/charts/ChartView.kt
index e498cdd..d48b004 100644
--- a/charts/src/main/java/com/dzeio/charts/ChartView.kt
+++ b/charts/src/main/java/com/dzeio/charts/ChartView.kt
@@ -34,9 +34,7 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet
private val scroller = ChartScroll(this).apply {
var lastMovement = 0.0
setOnChartMoved { movementX, _ ->
-
-// Log.d(TAG, "scrolled: ${(movementX - lastMovement) * (xAxis.increment / 10)}")
- xAxis.x = xAxis.x + (movementX - lastMovement) * (xAxis.increment * xAxis.displayCount / width)
+ xAxis.x += (movementX - lastMovement) * xAxis.getDataWidth() / width
lastMovement = movementX.toDouble()
refresh()
}
@@ -140,4 +138,13 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet
performClick()
return scroller.onTouchEvent(event)
}
+
+ override fun getDataset(): ArrayList {
+ val data: ArrayList = arrayListOf()
+ for (serie in series) {
+ data.addAll(serie.entries)
+ }
+ data.sortBy { it.x }
+ return data.filterIndexed { index, entry -> data.indexOf(entry) == index } as ArrayList
+ }
}
diff --git a/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt b/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt
index 0bd97cf..b566f21 100644
--- a/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt
+++ b/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt
@@ -39,4 +39,9 @@ interface ChartViewInterface {
* this function should be run if you change parameters in the view
*/
fun refresh()
+
+ /**
+ * @return the whole dataset (sorted and cleaned up of dupps)
+ */
+ fun getDataset(): ArrayList
}
\ No newline at end of file
diff --git a/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt b/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt
index dc3cecd..458c6b6 100644
--- a/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt
+++ b/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt
@@ -13,7 +13,7 @@ class XAxis(
) : XAxisInterface {
override var x: Double = 0.0
set(value) {
- val max = getXMax() - increment * displayCount
+ val max = getXMax() - getDataWidth()
val min = getXMin()
if (value > max && min <= max) {
field = max
@@ -29,10 +29,13 @@ class XAxis(
}
override var enabled = true
- override var increment: Double = 1.0
- override var displayCount: Int = 10
+
+ override var dataWidth: Double? = null
+
override var labelCount: Int = 2
+ var spacing = 16.0
+
override val textPaint = Paint().apply {
isAntiAlias = true
color = Color.parseColor("#FC496D")
@@ -42,27 +45,28 @@ class XAxis(
private val rect = Rect()
- override fun getPositionOnRect(entry: Entry, rect: RectF): Double {
- return translatePositionToRect(entry.x, rect)
+ override fun getPositionOnRect(entry: Entry, drawableSpace: RectF): Double {
+ return translatePositionToRect(entry.x, drawableSpace)
}
- fun translatePositionToRect(value: Double, rect: RectF): Double {
- val rectItem = rect.width() / displayCount // item size in graph
- return rectItem * value / increment
- }
-
- override fun getXOffset(rect: RectF): Double {
- return translatePositionToRect(x, rect)
+ fun translatePositionToRect(value: Double, drawableSpace: RectF): Double {
+ return drawableSpace.width() * (value - x) / getDataWidth()
}
override fun getXMax(): Double {
return view.series.maxOf { serie ->
+ if (serie.entries.isEmpty()) {
+ return 0.0
+ }
serie.entries.maxOf { entry -> entry.x }
}
}
override fun getXMin(): Double {
return view.series.minOf { serie ->
+ if (serie.entries.isEmpty()) {
+ return 0.0
+ }
serie.entries.minOf { entry -> entry.x }
}
}
@@ -77,7 +81,7 @@ class XAxis(
var maxHeight = 0f
val graphIncrement = space.width() / (labelCount - 1)
- val valueIncrement = (displayCount * increment / (labelCount - 1)).toDouble()
+ val valueIncrement = (getDataWidth() / (labelCount - 1)).toDouble()
for (index in 0 until labelCount) {
val text = onValueFormat(x + valueIncrement * index)
textPaint.getTextBounds(text, 0, text.length, rect)
@@ -89,7 +93,6 @@ class XAxis(
xPos = space.right - rect.width()
}
-
canvas.drawText(
text,
xPos,
@@ -103,4 +106,20 @@ class XAxis(
override fun refresh() {
// TODO("Not yet implemented")
}
+
+ override fun getEntryWidth(drawableSpace: RectF): Double {
+ var smallest = -1.0
+ val dataset = view.getDataset()
+ for (idx in 0 until dataset.size - 1) {
+ val distance = dataset[idx + 1].x - dataset[idx].x
+ if (smallest == -1.0 || smallest > distance) {
+ smallest = distance
+ }
+ }
+ return drawableSpace.width() * smallest / getDataWidth() - spacing
+ }
+
+ override fun getDataWidth(): Double {
+ return dataWidth ?: (getXMax() - getXMin())
+ }
}
diff --git a/charts/src/main/java/com/dzeio/charts/axis/XAxisInterface.kt b/charts/src/main/java/com/dzeio/charts/axis/XAxisInterface.kt
index b4e7716..daa9f55 100644
--- a/charts/src/main/java/com/dzeio/charts/axis/XAxisInterface.kt
+++ b/charts/src/main/java/com/dzeio/charts/axis/XAxisInterface.kt
@@ -18,20 +18,19 @@ sealed interface XAxisInterface {
var x: Double
/**
- * X increment
+ * the "width" of the graph
+ *
+ * if not set it will be `XMax - XMin`
+ *
+ * ex: to display a 7 days graph history with x values being timestamp in secs, use 7*24*60*60
*/
- var increment: Double
+ var dataWidth: Double?
/**
* text Paint
*/
val textPaint: Paint
- /**
- * indicate the max number of entries are displayed
- */
- var displayCount: Int
-
/**
* indicate the number of labels displayed
*/
@@ -49,12 +48,7 @@ sealed interface XAxisInterface {
*
* @return the left side of the position of the entry
*/
- fun getPositionOnRect(entry: Entry, rect: RectF): Double
-
- /**
- * get the graph offset for X (kinda like [getPositionOnRect])
- */
- fun getXOffset(rect: RectF): Double
+ fun getPositionOnRect(entry: Entry, drawableSpace: RectF): Double
/**
* get the maximum the X can get to
@@ -66,6 +60,18 @@ sealed interface XAxisInterface {
*/
fun getXMin(): Double
+ /**
+ * get the size of an entry in the graph
+ *
+ * @return the size in [drawableSpace] px
+ */
+ fun getEntryWidth(drawableSpace: RectF): Double
+
+ /**
+ * return the currently used dataWidth
+ */
+ fun getDataWidth(): Double
+
/**
* onDraw event that will draw the XAxis
*
diff --git a/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt b/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt
index e4e4813..50226fa 100644
--- a/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt
+++ b/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt
@@ -5,6 +5,7 @@ import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.RectF
+import android.util.Log
import com.dzeio.charts.ChartView
import com.dzeio.charts.utils.drawRoundRect
@@ -35,9 +36,8 @@ class BarSerie(
private val rect = Rect()
override fun onDraw(canvas: Canvas, drawableSpace: RectF) {
- val spacing = drawableSpace.width() / view.xAxis.displayCount / 10
- val barWidth = drawableSpace.width() / view.xAxis.displayCount - spacing
val displayedEntries = getDisplayedEntries()
+ val barWidth = view.xAxis.getEntryWidth(drawableSpace).toFloat()
val max = view.yAxis.getYMax()
val min = view.yAxis.getYMin()
@@ -46,21 +46,10 @@ class BarSerie(
for (entry in displayedEntries) {
// calculated height in percent from 0 to 100
val top = (1 - entry.y / max) * drawableSpace.height() + drawableSpace.top
- var posX = drawableSpace.left + (view.xAxis.getPositionOnRect(
+ var posX = drawableSpace.left + view.xAxis.getPositionOnRect(
entry,
drawableSpace
- ) - view.xAxis.getXOffset(drawableSpace)).toFloat()
-// Log.d(TAG, "gpor = ${view.xAxis.getPositionOnRect(entry, space)}, gxo = ${view.xAxis.getXOffset(space)}")
-// Log.d(TAG, "max = $max, y = ${entry.y}, height = $height")
-// Log.d(TAG, "posX: ${posX / 60 / 60 / 1000}, offsetX = ${view.xAxis.x / (1000 * 60 * 60)}, x = ${entry.x / (1000 * 60 * 60)}, pouet: ${(view.xAxis.x + view.xAxis.displayCount * view.xAxis.increment) / (1000 * 60 * 60)}")
-
-// Log.d(
-// TAG, """
-// ${posX},
-// $top,
-// ${(posX + barWidth)},
-// ${drawableSpace.bottom}""".trimIndent()
-// )
+ ).toFloat()
val right = (posX + barWidth).coerceAtMost(drawableSpace.right)
diff --git a/charts/src/main/java/com/dzeio/charts/series/BaseSerie.kt b/charts/src/main/java/com/dzeio/charts/series/BaseSerie.kt
index 9f354da..dfce84b 100644
--- a/charts/src/main/java/com/dzeio/charts/series/BaseSerie.kt
+++ b/charts/src/main/java/com/dzeio/charts/series/BaseSerie.kt
@@ -19,14 +19,28 @@ sealed class BaseSerie(
override var entries: ArrayList = arrayListOf()
override fun getDisplayedEntries(): ArrayList {
- // -+ view.xAxis.increment = one out of display
- val minX = view.xAxis.x - view.xAxis.increment
- val maxX =
- view.xAxis.x + view.xAxis.displayCount * view.xAxis.increment + view.xAxis.increment
+ val minX = view.xAxis.x
+ val maxX = minX + view.xAxis.getDataWidth()
- return entries.filter {
- return@filter it.x in minX..maxX
- } as ArrayList
+ val result: ArrayList = arrayListOf()
+
+ var lastIndex = -1
+ for (i in 0 until entries.size) {
+ val it = entries[i]
+ if (it.x in minX..maxX) {
+ if (result.size === 0 && i > 0) {
+ result.add((entries[i - 1]))
+ }
+ lastIndex = i
+ result.add(it)
+ }
+ }
+
+ if (lastIndex < entries.size - 1) {
+ result.add(entries [lastIndex + 1])
+ }
+
+ return result
}
abstract override fun onDraw(canvas: Canvas, drawableSpace: RectF)
diff --git a/charts/src/main/java/com/dzeio/charts/series/LineSerie.kt b/charts/src/main/java/com/dzeio/charts/series/LineSerie.kt
new file mode 100644
index 0000000..289e8cc
--- /dev/null
+++ b/charts/src/main/java/com/dzeio/charts/series/LineSerie.kt
@@ -0,0 +1,74 @@
+package com.dzeio.charts.series
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.RectF
+import com.dzeio.charts.ChartView
+
+class LineSerie(
+ private val view: ChartView
+) : BaseSerie(view) {
+
+ private companion object {
+ const val TAG = "Charts/LineSerie"
+ }
+
+ init {
+ view.series.add(this)
+ }
+
+ val linePaint = Paint().apply {
+ isAntiAlias = true
+ color = Color.parseColor("#123456")
+ strokeWidth = 5f
+ }
+
+ val textPaint = Paint().apply {
+ isAntiAlias = true
+ color = Color.parseColor("#FC496D")
+ textSize = 30f
+ textAlign = Paint.Align.CENTER
+ }
+
+ override fun onDraw(canvas: Canvas, drawableSpace: RectF) {
+ val displayedEntries = getDisplayedEntries()
+ displayedEntries.sortBy { it.x }
+ val max = view.yAxis.getYMax()
+
+ var previousPosX: Float? = null
+ var previousPosY: Float? = null
+
+ for (entry in displayedEntries) {
+ // calculated height in percent from 0 to 100
+ val top = (1 - entry.y / max) * drawableSpace.height() + drawableSpace.top
+ val posX = (drawableSpace.left +
+ view.xAxis.getPositionOnRect(entry, drawableSpace) +
+ view.xAxis.getEntryWidth(drawableSpace) / 2f).toFloat()
+
+ // handle color recoloration
+ val paint = Paint(linePaint)
+
+ if (entry.color != null) {
+ paint.color = entry.color!!
+ }
+
+ // draw smol point
+ if (posX < drawableSpace.right) {
+ canvas.drawCircle(posX, top, paint.strokeWidth, paint)
+ }
+
+ // draw line
+ if (previousPosX != null && previousPosY != null) {
+ canvas.drawLine(previousPosX, previousPosY, posX, top, paint)
+
+ }
+ previousPosX = posX
+ previousPosY = top
+ }
+ }
+
+ override fun refresh() {
+// TODO("Not yet implemented")
+ }
+}