From ecea212c83a2666305143b80ae02a131eb52cd58 Mon Sep 17 00:00:00 2001 From: Robert Buessow Date: Wed, 10 May 2023 17:02:14 +0200 Subject: [PATCH] Support heart rate in overview graph --- .../activities/HistoryBrowseActivity.kt | 3 +++ .../nightscout/core/graph/OverviewData.kt | 5 +++- .../core/graph/data/HeartRateDataPoint.kt | 24 +++++++++++++++++++ .../data/PointsWithLabelGraphSeries.java | 7 +++++- .../interfaces/overview/OverviewMenus.kt | 5 ++-- core/ui/src/main/res/values-night/styles.xml | 1 + core/ui/src/main/res/values/attrs.xml | 3 ++- core/ui/src/main/res/values/colors.xml | 1 + core/ui/src/main/res/values/styles.xml | 1 + .../overview/OverviewDataImpl.kt | 3 +++ .../general/overview/OverviewFragment.kt | 6 ++++- .../general/overview/OverviewMenusImpl.kt | 5 ++-- .../general/overview/graphData/GraphData.kt | 11 ++++++++- plugins/main/src/main/res/values/strings.xml | 2 ++ .../workflow/PrepareTreatmentsDataWorker.kt | 10 +++++++- 15 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 core/graph/src/main/java/info/nightscout/core/graph/data/HeartRateDataPoint.kt diff --git a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt index a22c9ba427..83b3813f61 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt @@ -327,6 +327,7 @@ class HistoryBrowseActivity : TranslatedDaggerAppCompatActivity() { var useRatioForScale = false var useDSForScale = false var useBGIForScale = false + var useHRForScale = false when { menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true @@ -335,6 +336,7 @@ class HistoryBrowseActivity : TranslatedDaggerAppCompatActivity() { menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true + menuChartSettings[g + 1][OverviewMenus.CharType.HR.ordinal] -> useHRForScale = true } val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] @@ -345,6 +347,7 @@ class HistoryBrowseActivity : TranslatedDaggerAppCompatActivity() { if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8) if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(useRatioForScale, if (useRatioForScale) 1.0 else 0.8) if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && config.isDev()) secondGraphData.addDeviationSlope(useDSForScale, 1.0) + if (menuChartSettings[g + 1][OverviewMenus.CharType.HR.ordinal] && config.isDev()) secondGraphData.addHeartRate(useHRForScale, 1.0) // set manual x bounds to have nice steps secondGraphData.formatAxis(historyBrowserData.overviewData.fromTime, historyBrowserData.overviewData.endTime) diff --git a/core/graph/src/main/java/info/nightscout/core/graph/OverviewData.kt b/core/graph/src/main/java/info/nightscout/core/graph/OverviewData.kt index 9a1eea13ba..c566cbb511 100644 --- a/core/graph/src/main/java/info/nightscout/core/graph/OverviewData.kt +++ b/core/graph/src/main/java/info/nightscout/core/graph/OverviewData.kt @@ -150,4 +150,7 @@ interface OverviewData { val dsMinScale: Scale var dsMaxSeries: LineGraphSeries var dsMinSeries: LineGraphSeries -} \ No newline at end of file + var heartRateScale: Scale + var heartRateGraphSeries: LineGraphSeries + +} diff --git a/core/graph/src/main/java/info/nightscout/core/graph/data/HeartRateDataPoint.kt b/core/graph/src/main/java/info/nightscout/core/graph/data/HeartRateDataPoint.kt new file mode 100644 index 0000000000..1fef69a2b5 --- /dev/null +++ b/core/graph/src/main/java/info/nightscout/core/graph/data/HeartRateDataPoint.kt @@ -0,0 +1,24 @@ +package info.nightscout.core.graph.data + +import android.content.Context +import android.graphics.Paint +import info.nightscout.database.entities.HeartRate +import info.nightscout.shared.interfaces.ResourceHelper + +class HeartRateDataPoint( + private val data: HeartRate, + private val rh: ResourceHelper, +) : DataPointWithLabelInterface { + + override fun getX(): Double = (data.timestamp - data.duration).toDouble() + override fun getY(): Double = data.beatsPerMinute + override fun setY(y: Double) {} + + override val label: String = "" + override val duration = data.duration + override val shape = PointsWithLabelGraphSeries.Shape.HEARTRATE + override val size = 1f + override val paintStyle: Paint.Style = Paint.Style.FILL + + override fun color(context: Context?): Int = rh.gac(context, info.nightscout.core.ui.R.attr.heartRateColor) +} diff --git a/core/graph/src/main/java/info/nightscout/core/graph/data/PointsWithLabelGraphSeries.java b/core/graph/src/main/java/info/nightscout/core/graph/data/PointsWithLabelGraphSeries.java index 47f744a9fa..49f560efc3 100644 --- a/core/graph/src/main/java/info/nightscout/core/graph/data/PointsWithLabelGraphSeries.java +++ b/core/graph/src/main/java/info/nightscout/core/graph/data/PointsWithLabelGraphSeries.java @@ -54,7 +54,8 @@ public class PointsWithLabelGraphSeries e GENERAL_WITH_DURATION, COB_FAIL_OVER, IOB_PREDICTION, - BUCKETED_BG + BUCKETED_BG, + HEARTRATE, } /** @@ -324,6 +325,10 @@ public class PointsWithLabelGraphSeries e mPaint.setStrokeWidth(5); canvas.drawRect(endX - 3, bounds.top + py - 3, xPlusLength + 3, bounds.bottom + py + 3, mPaint); } + } else if (value.getShape() == Shape.HEARTRATE) { + mPaint.setStyle(Paint.Style.FILL_AND_STROKE); + mPaint.setStrokeWidth(0); + canvas.drawCircle(endX, endY, 1F, mPaint); } // set values above point } diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/overview/OverviewMenus.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/overview/OverviewMenus.kt index 0129bcbe19..9622530524 100644 --- a/core/interfaces/src/main/java/info/nightscout/interfaces/overview/OverviewMenus.kt +++ b/core/interfaces/src/main/java/info/nightscout/interfaces/overview/OverviewMenus.kt @@ -15,7 +15,8 @@ interface OverviewMenus { BGI, SEN, ACT, - DEVSLOPE + DEVSLOPE, + HR, } val setting: List> @@ -23,4 +24,4 @@ interface OverviewMenus { fun setupChartMenu(context: Context, chartButton: ImageButton) fun enabledTypes(graph: Int): String fun isEnabledIn(type: CharType): Int -} \ No newline at end of file +} diff --git a/core/ui/src/main/res/values-night/styles.xml b/core/ui/src/main/res/values-night/styles.xml index 6e3ca1508f..e78363af48 100644 --- a/core/ui/src/main/res/values-night/styles.xml +++ b/core/ui/src/main/res/values-night/styles.xml @@ -216,6 +216,7 @@ @color/inRangeBackground @color/devSlopePos @color/devSlopeNeg + @color/heartRate @color/deviationGrey @color/deviationBlack @color/deviationGreen diff --git a/core/ui/src/main/res/values/attrs.xml b/core/ui/src/main/res/values/attrs.xml index 380bb21a83..cc75771f30 100644 --- a/core/ui/src/main/res/values/attrs.xml +++ b/core/ui/src/main/res/values/attrs.xml @@ -181,6 +181,7 @@ + @@ -221,4 +222,4 @@ - \ No newline at end of file + diff --git a/core/ui/src/main/res/values/colors.xml b/core/ui/src/main/res/values/colors.xml index 86f1a39470..91179d4355 100644 --- a/core/ui/src/main/res/values/colors.xml +++ b/core/ui/src/main/res/values/colors.xml @@ -153,6 +153,7 @@ #00EEEE #FFFFFF00 #FFFF00FF + #FFFFFF66 #F6CE22 #FF0000 #7484E2 diff --git a/core/ui/src/main/res/values/styles.xml b/core/ui/src/main/res/values/styles.xml index a1bf69ad9d..e9029cc2be 100644 --- a/core/ui/src/main/res/values/styles.xml +++ b/core/ui/src/main/res/values/styles.xml @@ -219,6 +219,7 @@ @color/inRangeBackground @color/devSlopePos @color/devSlopeNeg + @color/heartRate @color/deviationGrey @color/deviationBlack @color/deviationGreen diff --git a/implementation/src/main/java/info/nightscout/implementation/overview/OverviewDataImpl.kt b/implementation/src/main/java/info/nightscout/implementation/overview/OverviewDataImpl.kt index dd153fa18c..c7bf701bcd 100644 --- a/implementation/src/main/java/info/nightscout/implementation/overview/OverviewDataImpl.kt +++ b/implementation/src/main/java/info/nightscout/implementation/overview/OverviewDataImpl.kt @@ -87,6 +87,7 @@ class OverviewDataImpl @Inject constructor( dsMinSeries = LineGraphSeries() treatmentsSeries = PointsWithLabelGraphSeries() epsSeries = PointsWithLabelGraphSeries() + heartRateGraphSeries = LineGraphSeries() } override fun initRange() { @@ -322,4 +323,6 @@ class OverviewDataImpl @Inject constructor( override val dsMinScale = Scale() override var dsMaxSeries: LineGraphSeries = LineGraphSeries() override var dsMinSeries: LineGraphSeries = LineGraphSeries() + override var heartRateScale = Scale() + override var heartRateGraphSeries: LineGraphSeries = LineGraphSeries() } diff --git a/plugins/main/src/main/java/info/nightscout/plugins/general/overview/OverviewFragment.kt b/plugins/main/src/main/java/info/nightscout/plugins/general/overview/OverviewFragment.kt index f59254d745..e4714d1079 100644 --- a/plugins/main/src/main/java/info/nightscout/plugins/general/overview/OverviewFragment.kt +++ b/plugins/main/src/main/java/info/nightscout/plugins/general/overview/OverviewFragment.kt @@ -1030,6 +1030,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList var useRatioForScale = false var useDSForScale = false var useBGIForScale = false + var useHRForScale = false when { menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true @@ -1038,6 +1039,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true + menuChartSettings[g + 1][OverviewMenus.CharType.HR.ordinal] -> useHRForScale = true } val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] @@ -1052,6 +1054,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList if (useDSForScale) 1.0 else 0.8, useRatioForScale ) + if (menuChartSettings[g + 1][OverviewMenus.CharType.HR.ordinal]) secondGraphData.addHeartRate(useHRForScale, if (useHRForScale) 1.0 else 0.8) // set manual x bounds to have nice steps secondGraphData.formatAxis(overviewData.fromTime, overviewData.endTime) @@ -1067,7 +1070,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] || - menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] + menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] || + menuChartSettings[g + 1][OverviewMenus.CharType.HR.ordinal] ).toVisibility() secondaryGraphsData[g].performUpdate() } diff --git a/plugins/main/src/main/java/info/nightscout/plugins/general/overview/OverviewMenusImpl.kt b/plugins/main/src/main/java/info/nightscout/plugins/general/overview/OverviewMenusImpl.kt index d9d1abd0a1..b4fb21b8e9 100644 --- a/plugins/main/src/main/java/info/nightscout/plugins/general/overview/OverviewMenusImpl.kt +++ b/plugins/main/src/main/java/info/nightscout/plugins/general/overview/OverviewMenusImpl.kt @@ -47,7 +47,8 @@ class OverviewMenusImpl @Inject constructor( BGI(R.string.overview_show_bgi, info.nightscout.core.ui.R.attr.bgiColor, info.nightscout.core.ui.R.attr.menuTextColor, primary = false, secondary = true, shortnameId = R.string.bgi_shortname), SEN(R.string.overview_show_sensitivity, info.nightscout.core.ui.R.attr.ratioColor, info.nightscout.core.ui.R.attr.menuTextColorInverse, primary = false, secondary = true, shortnameId = R.string.sensitivity_shortname), ACT(R.string.overview_show_activity, info.nightscout.core.ui.R.attr.activityColor, info.nightscout.core.ui.R.attr.menuTextColor, primary = true, secondary = false, shortnameId = R.string.activity_shortname), - DEVSLOPE(R.string.overview_show_deviation_slope, info.nightscout.core.ui.R.attr.devSlopePosColor, info.nightscout.core.ui.R.attr.menuTextColor, primary = false, secondary = true, shortnameId = R.string.devslope_shortname) + DEVSLOPE(R.string.overview_show_deviation_slope, info.nightscout.core.ui.R.attr.devSlopePosColor, info.nightscout.core.ui.R.attr.menuTextColor, primary = false, secondary = true, shortnameId = R.string.devslope_shortname), + HR(R.string.overview_show_heartRate, info.nightscout.core.ui.R.attr.heartRateColor, info.nightscout.core.ui.R.attr.menuTextColor, primary = false, secondary = true, shortnameId = R.string.heartRate_shortname), } companion object { @@ -202,4 +203,4 @@ class OverviewMenusImpl @Inject constructor( return -1 } -} \ No newline at end of file +} diff --git a/plugins/main/src/main/java/info/nightscout/plugins/general/overview/graphData/GraphData.kt b/plugins/main/src/main/java/info/nightscout/plugins/general/overview/graphData/GraphData.kt index 1efaf873c1..f7898f954d 100644 --- a/plugins/main/src/main/java/info/nightscout/plugins/general/overview/graphData/GraphData.kt +++ b/plugins/main/src/main/java/info/nightscout/plugins/general/overview/graphData/GraphData.kt @@ -258,5 +258,14 @@ class GraphData( // draw it graph.onDataChanged(false, false) } -} + fun addHeartRate(useForScale: Boolean, scale: Double) { + val maxHR = overviewData.heartRateGraphSeries.highestValueY + if (useForScale) { + minY = 0.0 + maxY = maxHR + } + addSeries(overviewData.heartRateGraphSeries) + overviewData.heartRateScale.multiplier = maxY * scale / maxHR + } +} diff --git a/plugins/main/src/main/res/values/strings.xml b/plugins/main/src/main/res/values/strings.xml index 754ea02211..df582c2e6f 100644 --- a/plugins/main/src/main/res/values/strings.xml +++ b/plugins/main/src/main/res/values/strings.xml @@ -291,6 +291,7 @@ Predictions Treatments + Heart Rate Deviation slope Activity Blood Glucose Impact @@ -308,6 +309,7 @@ ABS DEVSLOPE TREAT + HR SENS Graph scale Graph diff --git a/workflow/src/main/java/info/nightscout/workflow/PrepareTreatmentsDataWorker.kt b/workflow/src/main/java/info/nightscout/workflow/PrepareTreatmentsDataWorker.kt index f012e8c4b9..f5e2a3e747 100644 --- a/workflow/src/main/java/info/nightscout/workflow/PrepareTreatmentsDataWorker.kt +++ b/workflow/src/main/java/info/nightscout/workflow/PrepareTreatmentsDataWorker.kt @@ -3,6 +3,7 @@ package info.nightscout.workflow import android.content.Context import androidx.work.WorkerParameters import androidx.work.workDataOf +import com.jjoe64.graphview.series.LineGraphSeries import info.nightscout.core.events.EventIobCalculationProgress import info.nightscout.core.graph.OverviewData import info.nightscout.core.graph.data.BolusDataPoint @@ -10,6 +11,8 @@ import info.nightscout.core.graph.data.CarbsDataPoint import info.nightscout.core.graph.data.DataPointWithLabelInterface import info.nightscout.core.graph.data.EffectiveProfileSwitchDataPoint import info.nightscout.core.graph.data.ExtendedBolusDataPoint +import info.nightscout.core.graph.data.FixedLineGraphSeries +import info.nightscout.core.graph.data.HeartRateDataPoint import info.nightscout.core.graph.data.PointsWithLabelGraphSeries import info.nightscout.core.graph.data.TherapyEventDataPoint import info.nightscout.core.utils.receivers.DataWorkerStorage @@ -129,6 +132,11 @@ class PrepareTreatmentsDataWorker( data.overviewData.therapyEventSeries = PointsWithLabelGraphSeries(filteredTherapyEvents.toTypedArray()) data.overviewData.epsSeries = PointsWithLabelGraphSeries(filteredEps.toTypedArray()) + data.overviewData.heartRateGraphSeries = LineGraphSeries( + repository.getHeartRatesFromTimeToTime(fromTime, endTime) + .map { hr -> HeartRateDataPoint(hr, rh) } + .toTypedArray()).apply { color = rh.gac(null, info.nightscout.core.ui.R.attr.heartRateColor) } + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_TREATMENTS_DATA, 100, null)) return Result.success() } @@ -149,4 +157,4 @@ class PrepareTreatmentsDataWorker( private fun List.filterTimeframe(fromTime: Long, endTime: Long): List = filter { it.x + it.duration >= fromTime && it.x <= endTime } -} \ No newline at end of file +}