Add profile chart trarget and dia

This commit is contained in:
Andries Smit 2022-02-08 20:14:44 +01:00
parent b6e2eaf0ef
commit 7410333177
11 changed files with 250 additions and 52 deletions

View file

@ -18,10 +18,11 @@ class ActivityGraph : GraphView {
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
fun show(insulin: Insulin) { fun show(insulin: Insulin, diaSample: Double? = null) {
removeAllSeries() removeAllSeries()
val dia = diaSample ?: insulin.dia
mSecondScale = null mSecondScale = null
val hours = floor(insulin.dia + 1).toLong() val hours = floor(dia + 1).toLong()
val bolus = Bolus( val bolus = Bolus(
timestamp = 0, timestamp = 0,
amount = 1.0, amount = 1.0,
@ -31,7 +32,7 @@ class ActivityGraph : GraphView {
val iobArray: MutableList<DataPoint> = ArrayList() val iobArray: MutableList<DataPoint> = ArrayList()
var time: Long = 0 var time: Long = 0
while (time <= T.hours(hours).msecs()) { while (time <= T.hours(hours).msecs()) {
val iob = insulin.iobCalcForTreatment(bolus, time, insulin.dia) val iob = insulin.iobCalcForTreatment(bolus, time, dia)
activityArray.add(DataPoint(T.msecs(time).mins().toDouble(), iob.activityContrib)) activityArray.add(DataPoint(T.msecs(time).mins().toDouble(), iob.activityContrib))
iobArray.add(DataPoint(T.msecs(time).mins().toDouble(), iob.iobContrib)) iobArray.add(DataPoint(T.msecs(time).mins().toDouble(), iob.iobContrib))
time += T.mins(5).msecs() time += T.mins(5).msecs()

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.profile.local
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -20,7 +21,6 @@ import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.GlucoseUnit import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
@ -31,8 +31,10 @@ import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.ui.SpinnerHelper import info.nightscout.androidaps.utils.ui.SpinnerHelper
import info.nightscout.androidaps.utils.ui.TimeListEdit import info.nightscout.androidaps.utils.ui.TimeListEdit
import info.nightscout.shared.SafeParse import info.nightscout.shared.SafeParse
import info.nightscout.shared.logging.AAPSLogger
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
import java.math.RoundingMode
import java.text.DecimalFormat import java.text.DecimalFormat
import javax.inject.Inject import javax.inject.Inject
@ -61,6 +63,8 @@ class LocalProfileFragment : DaggerFragment() {
binding.basalGraph.show(ProfileSealed.Pure(it)) binding.basalGraph.show(ProfileSealed.Pure(it))
binding.icGraph.show(ProfileSealed.Pure(it)) binding.icGraph.show(ProfileSealed.Pure(it))
binding.isfGraph.show(ProfileSealed.Pure(it)) binding.isfGraph.show(ProfileSealed.Pure(it))
binding.targetGraph.show(ProfileSealed.Pure(it))
binding.insulinGraph.show(activePlugin.activeInsulin, SafeParse.stringToDouble(binding.dia.text))
} }
} }
@ -130,14 +134,22 @@ class LocalProfileFragment : DaggerFragment() {
binding.name.addTextChangedListener(textWatch) binding.name.addTextChangedListener(textWatch)
binding.dia.setParams(currentProfile.dia, hardLimits.minDia(), hardLimits.maxDia(), 0.1, DecimalFormat("0.0"), false, null, textWatch) binding.dia.setParams(currentProfile.dia, hardLimits.minDia(), hardLimits.maxDia(), 0.1, DecimalFormat("0.0"), false, null, textWatch)
binding.dia.tag = "LP_DIA" binding.dia.tag = "LP_DIA"
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.ic_holder, "IC", rh.gs(R.string.ic_label), currentProfile.ic, null, hardLimits.minIC(), hardLimits.maxIC(), 0.1, DecimalFormat("0.0"), save) TimeListEdit(context, aapsLogger, dateUtil, view, R.id.ic_holder, "IC", rh.gs(R.string.ic_label), currentProfile.ic, null, doubleArrayOf(hardLimits.minIC(), hardLimits.maxIC()), null, 0.1, DecimalFormat ("0.0"), save)
basalView = TimeListEdit(context, aapsLogger, dateUtil, view, R.id.basal_holder, "BASAL", rh.gs(R.string.basal_label) + ": " + sumLabel(), currentProfile.basal, null, pumpDescription.basalMinimumRate, pumpDescription.basalMaximumRate, 0.01, DecimalFormat("0.00"), save) basalView = TimeListEdit(context, aapsLogger, dateUtil, view, R.id.basal_holder, "BASAL", rh.gs(R.string.basal_label) + ": " + sumLabel(), currentProfile.basal, null, doubleArrayOf(pumpDescription.basalMinimumRate, pumpDescription.basalMaximumRate), null, 0.01, DecimalFormat("0.00"), save)
if (units == Constants.MGDL) { if (units == Constants.MGDL) {
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.isf_holder, "ISF", rh.gs(R.string.isf_label), currentProfile.isf, null, HardLimits.MIN_ISF, HardLimits.MAX_ISF, 1.0, DecimalFormat("0"), save) val isfRange = doubleArrayOf(HardLimits.MIN_ISF, HardLimits.MAX_ISF)
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.target, "TARGET", rh.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, HardLimits.VERY_HARD_LIMIT_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TARGET_BG[1], 1.0, DecimalFormat("0"), save) TimeListEdit(context, aapsLogger, dateUtil, view, R.id.isf_holder, "ISF", rh.gs(R.string.isf_label), currentProfile.isf, null, isfRange , null, 1.0, DecimalFormat("0"), save)
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.target_holder, "TARGET", rh.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, HardLimits.VERY_HARD_LIMIT_MIN_BG, HardLimits.VERY_HARD_LIMIT_TARGET_BG, 1.0, DecimalFormat("0"), save)
} else { } else {
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.isf_holder, "ISF", rh.gs(R.string.isf_label), currentProfile.isf, null, Profile.fromMgdlToUnits(HardLimits.MIN_ISF, GlucoseUnit.MMOL), Profile.fromMgdlToUnits(HardLimits.MAX_ISF, GlucoseUnit.MMOL), 0.1, DecimalFormat("0.0"), save) val isfRange = doubleArrayOf(roundUp(Profile.fromMgdlToUnits(HardLimits.MIN_ISF, GlucoseUnit.MMOL)),
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.target, "TARGET", rh.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, Profile.fromMgdlToUnits(HardLimits.VERY_HARD_LIMIT_TARGET_BG[0], GlucoseUnit.MMOL), Profile.fromMgdlToUnits(HardLimits.VERY_HARD_LIMIT_TARGET_BG[1], GlucoseUnit.MMOL), 0.1, DecimalFormat("0.0"), save) roundDown(Profile.fromMgdlToUnits(HardLimits.MAX_ISF, GlucoseUnit.MMOL)))
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.isf_holder, "ISF", rh.gs(R.string.isf_label), currentProfile.isf, null,isfRange , null, 0.1, DecimalFormat("0.0"), save)
val range1 = doubleArrayOf(roundUp(Profile.fromMgdlToUnits(HardLimits.VERY_HARD_LIMIT_MIN_BG[0], GlucoseUnit.MMOL)),
roundDown(Profile.fromMgdlToUnits(HardLimits.VERY_HARD_LIMIT_MIN_BG[1], GlucoseUnit.MMOL)))
val range2 = doubleArrayOf(roundUp(Profile.fromMgdlToUnits(HardLimits.VERY_HARD_LIMIT_MAX_BG[0], GlucoseUnit.MMOL)),
roundDown(Profile.fromMgdlToUnits(HardLimits.VERY_HARD_LIMIT_MAX_BG[1], GlucoseUnit.MMOL)))
Log.i("TimeListEdit", "build: range1" + range1[0] + " " + range1[1] + " range2" + range2[0] + " " + range2[1])
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.target_holder, "TARGET", rh.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, range1 , range2, 0.1, DecimalFormat("0.0"), save)
} }
// Spinner // Spinner
@ -175,6 +187,8 @@ class LocalProfileFragment : DaggerFragment() {
binding.basalGraph.show(ProfileSealed.Pure(it)) binding.basalGraph.show(ProfileSealed.Pure(it))
binding.icGraph.show(ProfileSealed.Pure(it)) binding.icGraph.show(ProfileSealed.Pure(it))
binding.isfGraph.show(ProfileSealed.Pure(it)) binding.isfGraph.show(ProfileSealed.Pure(it))
binding.targetGraph.show(ProfileSealed.Pure(it))
binding.insulinGraph.show(activePlugin.activeInsulin, SafeParse.stringToDouble(binding.dia.text))
} }
binding.profileAdd.setOnClickListener { binding.profileAdd.setOnClickListener {
@ -265,6 +279,14 @@ class LocalProfileFragment : DaggerFragment() {
updateGUI() updateGUI()
} }
private fun roundUp(number: Double): Double {
return number.toBigDecimal().setScale(1, RoundingMode.UP).toDouble()
}
private fun roundDown(number: Double): Double {
return number.toBigDecimal().setScale(1, RoundingMode.DOWN).toDouble()
}
private fun updateGUI() { private fun updateGUI() {
if (_binding == null) return if (_binding == null) return
val isValid = localProfilePlugin.isValidEditState(activity) val isValid = localProfilePlugin.isValidEditState(activity)

View file

@ -57,6 +57,8 @@ public class TimeListEdit {
private final double step; private final double step;
private final double min; private final double min;
private final double max; private final double max;
private final double min2;
private final double max2;
private final NumberFormat formatter; private final NumberFormat formatter;
private final Runnable save; private final Runnable save;
private LinearLayout layout; private LinearLayout layout;
@ -68,7 +70,7 @@ public class TimeListEdit {
Context context, Context context,
AAPSLogger aapsLogger, AAPSLogger aapsLogger,
DateUtil dateUtil, DateUtil dateUtil,
View view, int resLayoutId, String tagPrefix, String label, JSONArray data1, JSONArray data2, double min, double max, double step, NumberFormat formatter, Runnable save) { View view, int resLayoutId, String tagPrefix, String label, JSONArray data1, JSONArray data2, double[] range1, double[] range2, double step, NumberFormat formatter, Runnable save) {
this.context = context; this.context = context;
this.aapsLogger = aapsLogger; this.aapsLogger = aapsLogger;
this.dateUtil = dateUtil; this.dateUtil = dateUtil;
@ -79,8 +81,10 @@ public class TimeListEdit {
this.data1 = data1; this.data1 = data1;
this.data2 = data2; this.data2 = data2;
this.step = step; this.step = step;
this.min = min; this.min = range1[0];
this.max = max; this.max = range1[1];
this.min2 = range2 != null ? range2[0] : 0;
this.max2 = range2 != null ? range2[1] : 0;
this.formatter = formatter; this.formatter = formatter;
this.save = save; this.save = save;
buildView(); buildView();
@ -177,7 +181,13 @@ public class TimeListEdit {
numberPickers1[position].setTextWatcher(new TextWatcher() { numberPickers1[position].setTextWatcher(new TextWatcher() {
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
editItem(position, secondFromMidnight(position), SafeParse.stringToDouble(numberPickers1[position].getText()), value2(position)); Double value1 = SafeParse.stringToDouble(numberPickers1[position].getText());
Double value2 = value2(position);
if (data2 != null && value1 > value2) {
value2 = value1;
numberPickers2[position].setValue(value2);
}
editItem(position, secondFromMidnight(position), value1, value2);
callSave(); callSave();
log(); log();
} }
@ -197,7 +207,13 @@ public class TimeListEdit {
numberPickers2[position].setTextWatcher(new TextWatcher() { numberPickers2[position].setTextWatcher(new TextWatcher() {
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
editItem(position, secondFromMidnight(position), value1(position), SafeParse.stringToDouble(numberPickers2[position].getText())); Double value1 = value1(position);
Double value2 = SafeParse.stringToDouble(numberPickers2[position].getText());
if (data2 != null && value2 < value1) {
value1 = value2;
numberPickers1[position].setValue(value1);
}
editItem(position, secondFromMidnight(position), value1, value2);
callSave(); callSave();
log(); log();
} }
@ -246,7 +262,7 @@ public class TimeListEdit {
fillSpinner(timeSpinner, secondFromMidnight(i), previous, next); fillSpinner(timeSpinner, secondFromMidnight(i), previous, next);
editText1.setParams(value1(i), min, max, step, formatter, false, null); editText1.setParams(value1(i), min, max, step, formatter, false, null);
editText2.setParams(value2(i), min, max, step, formatter, false, null); editText2.setParams(value2(i), min2, max2, step, formatter, false, null);
if (data2 == null) { if (data2 == null) {
editText2.setVisibility(View.GONE); editText2.setVisibility(View.GONE);

View file

@ -35,6 +35,40 @@
</LinearLayout> </LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="2dip"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="@color/list_delimiter" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginBottom="10dp"
android:labelFor="@+id/name"
android:text="@string/profile_name"
android:textAppearance="?android:attr/textAppearanceMedium" />
<EditText
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:ems="10"
android:importantForAutofill="no"
android:inputType="text" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -152,32 +186,13 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="10dp" android:gravity="center_horizontal"
android:orientation="horizontal"> android:text="@string/dia_label"
android:textColor="@android:color/white"
<TextView android:textSize="20sp" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginBottom="10dp"
android:labelFor="@+id/name"
android:text="@string/profile_name"
android:textAppearance="?android:attr/textAppearanceMedium" />
<EditText
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:ems="10"
android:importantForAutofill="no"
android:inputType="text" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -210,6 +225,12 @@
</LinearLayout> </LinearLayout>
<info.nightscout.androidaps.plugins.insulin.ActivityGraph
android:id="@+id/insulin_graph"
android:layout_width="match_parent"
android:layout_height="100dip"
android:layout_margin="20dp" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -225,7 +246,7 @@
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:orientation="vertical" /> android:orientation="vertical" />
<info.nightscout.androidaps.utils.ui.BasalProfileGraph <info.nightscout.androidaps.utils.ui.IcProfileGraph
android:id="@+id/ic_graph" android:id="@+id/ic_graph"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="100dip" android:layout_height="100dip"
@ -277,10 +298,22 @@
<LinearLayout <LinearLayout
android:id="@+id/target" android:id="@+id/target"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/target_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:orientation="vertical"> android:orientation="vertical" />
<info.nightscout.androidaps.utils.ui.TargetBgProfileGraph
android:id="@+id/target_graph"
android:layout_width="match_parent"
android:layout_height="100dip"
android:layout_margin="20dp" />
</LinearLayout> </LinearLayout>

View file

@ -151,6 +151,7 @@ class ProfileViewerDialog : DaggerDialogFragment() {
binding.basalGraph.show(profile1, profile2) binding.basalGraph.show(profile1, profile2)
binding.isfGraph.show(profile1, profile2) binding.isfGraph.show(profile1, profile2)
binding.icGraph.show(profile1, profile2) binding.icGraph.show(profile1, profile2)
binding.targetGraph.show(profile1, profile2)
} }
binding.noprofile.visibility = View.GONE binding.noprofile.visibility = View.GONE
@ -171,6 +172,7 @@ class ProfileViewerDialog : DaggerDialogFragment() {
binding.basalGraph.show(it) binding.basalGraph.show(it)
binding.isfGraph.show(it) binding.isfGraph.show(it)
binding.icGraph.show(it) binding.icGraph.show(it)
binding.targetGraph.show(it)
binding.noprofile.visibility = View.GONE binding.noprofile.visibility = View.GONE
val validity = it.isValid("ProfileViewDialog", activePlugin.activePump, config, rh, rxBus, hardLimits, false) val validity = it.isValid("ProfileViewDialog", activePlugin.activePump, config, rh, rxBus, hardLimits, false)

View file

@ -2,12 +2,14 @@ package info.nightscout.androidaps.utils.ui
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import com.jjoe64.graphview.DefaultLabelFormatter
import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.GraphView
import com.jjoe64.graphview.series.DataPoint import com.jjoe64.graphview.series.DataPoint
import com.jjoe64.graphview.series.LineGraphSeries import com.jjoe64.graphview.series.LineGraphSeries
import info.nightscout.androidaps.core.R import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import java.text.NumberFormat
import java.util.ArrayList import java.util.ArrayList
import kotlin.math.max import kotlin.math.max
@ -36,6 +38,10 @@ class BasalProfileGraph : GraphView {
viewport.setMaxY(Round.ceilTo(profile.getMaxDailyBasal() * 1.1, 0.5)) viewport.setMaxY(Round.ceilTo(profile.getMaxDailyBasal() * 1.1, 0.5))
gridLabelRenderer.numHorizontalLabels = 13 gridLabelRenderer.numHorizontalLabels = 13
gridLabelRenderer.verticalLabelsColor = basalSeries.color gridLabelRenderer.verticalLabelsColor = basalSeries.color
val nf: NumberFormat = NumberFormat.getInstance()
nf.maximumFractionDigits = 1
gridLabelRenderer.setLabelFormatter(DefaultLabelFormatter(nf, nf))
} }
fun show(profile1: Profile, profile2: Profile) { fun show(profile1: Profile, profile2: Profile) {

View file

@ -2,12 +2,14 @@ package info.nightscout.androidaps.utils.ui
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import com.jjoe64.graphview.DefaultLabelFormatter
import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.GraphView
import com.jjoe64.graphview.series.DataPoint import com.jjoe64.graphview.series.DataPoint
import com.jjoe64.graphview.series.LineGraphSeries import com.jjoe64.graphview.series.LineGraphSeries
import info.nightscout.androidaps.core.R import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import java.text.NumberFormat
import java.util.* import java.util.*
import kotlin.math.max import kotlin.math.max
@ -39,6 +41,10 @@ class IcProfileGraph : GraphView {
viewport.setMaxY(Round.ceilTo(maxIc * 1.1, 0.5)) viewport.setMaxY(Round.ceilTo(maxIc * 1.1, 0.5))
gridLabelRenderer.numHorizontalLabels = 13 gridLabelRenderer.numHorizontalLabels = 13
gridLabelRenderer.verticalLabelsColor = icSeries.color gridLabelRenderer.verticalLabelsColor = icSeries.color
val nf: NumberFormat = NumberFormat.getInstance()
nf.maximumFractionDigits = 1
gridLabelRenderer.setLabelFormatter(DefaultLabelFormatter(nf, nf))
} }
fun show(profile1: Profile, profile2: Profile) { fun show(profile1: Profile, profile2: Profile) {

View file

@ -2,13 +2,14 @@ package info.nightscout.androidaps.utils.ui
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import com.jjoe64.graphview.DefaultLabelFormatter
import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.GraphView
import com.jjoe64.graphview.series.DataPoint import com.jjoe64.graphview.series.DataPoint
import com.jjoe64.graphview.series.LineGraphSeries import com.jjoe64.graphview.series.LineGraphSeries
import info.nightscout.androidaps.core.R import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import java.util.ArrayList import java.text.NumberFormat
import kotlin.math.max import kotlin.math.max
class IsfProfileGraph : GraphView { class IsfProfileGraph : GraphView {
@ -31,15 +32,21 @@ class IsfProfileGraph : GraphView {
val isfSeries: LineGraphSeries<DataPoint> = LineGraphSeries(isfDataPoints) val isfSeries: LineGraphSeries<DataPoint> = LineGraphSeries(isfDataPoints)
addSeries(isfSeries) addSeries(isfSeries)
isfSeries.thickness = 8 isfSeries.thickness = 8
isfSeries.isDrawBackground = false isfSeries.isDrawBackground = true
viewport.isXAxisBoundsManual = true viewport.isXAxisBoundsManual = true
viewport.setMinX(0.0) viewport.setMinX(0.0)
viewport.setMaxX(24.0) viewport.setMaxX(24.0)
viewport.isYAxisBoundsManual = true viewport.isYAxisBoundsManual = true
viewport.setMinY(0.0) viewport.setMinY(0.0)
viewport.setMaxY(Round.ceilTo(maxIsf * 1.1, 0.5)) val maxY = Round.ceilTo(maxIsf * 1.1, 0.5)
viewport.setMaxY(maxY)
gridLabelRenderer.numHorizontalLabels = 13 gridLabelRenderer.numHorizontalLabels = 13
gridLabelRenderer.labelVerticalWidth = 40
gridLabelRenderer.verticalLabelsColor = isfSeries.color gridLabelRenderer.verticalLabelsColor = isfSeries.color
val nf: NumberFormat = NumberFormat.getInstance()
nf.maximumFractionDigits = 1
gridLabelRenderer.setLabelFormatter(DefaultLabelFormatter(nf, nf))
} }
fun show(profile1: Profile, profile2: Profile) { fun show(profile1: Profile, profile2: Profile) {

View file

@ -0,0 +1,99 @@
package info.nightscout.androidaps.utils.ui
import android.content.Context
import android.util.AttributeSet
import com.jjoe64.graphview.DefaultLabelFormatter
import com.jjoe64.graphview.GraphView
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.AreaGraphSeries
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DoubleDataPoint
import java.text.NumberFormat
import java.util.ArrayList
import kotlin.math.max
class TargetBgProfileGraph : GraphView {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
fun show(profile: Profile) {
removeAllSeries()
val targetArray: MutableList<DoubleDataPoint> = ArrayList()
var maxValue = 0.0
val units = profile.units
for (hour in 0..23) {
val valueLow = Profile.fromMgdlToUnits(profile.getTargetLowMgdlTimeFromMidnight(hour * 60 * 60), units)
val valueHigh = Profile.fromMgdlToUnits(profile.getTargetHighMgdlTimeFromMidnight(hour * 60 * 60), units)
maxValue = max(maxValue, valueHigh)
targetArray.add(DoubleDataPoint(hour.toDouble(), valueLow, valueHigh))
targetArray.add(DoubleDataPoint((hour + 1).toDouble(), valueLow, valueHigh))
}
val targetDataPoints: Array<DoubleDataPoint> = Array(targetArray.size) { i -> targetArray[i] }
val targetSeries: AreaGraphSeries<DoubleDataPoint> = AreaGraphSeries(targetDataPoints)
addSeries(targetSeries)
targetSeries.isDrawBackground = true
viewport.isXAxisBoundsManual = true
viewport.setMinX(0.0)
viewport.setMaxX(24.0)
viewport.isYAxisBoundsManual = true
viewport.setMinY(0.0)
viewport.setMaxY(Round.ceilTo(maxValue * 1.1, 0.5))
gridLabelRenderer.numHorizontalLabels = 13
gridLabelRenderer.verticalLabelsColor = targetSeries.color
val nf: NumberFormat = NumberFormat.getInstance()
nf.maximumFractionDigits = if (units == GlucoseUnit.MMOL) 1 else 0
gridLabelRenderer.setLabelFormatter(DefaultLabelFormatter(nf, nf))
}
fun show(profile1: Profile, profile2: Profile) {
removeAllSeries()
val targetArray1: MutableList<DoubleDataPoint> = ArrayList()
var maxValue = 0.0
val units = profile1.units
for (hour in 0..23) {
val valueLow = Profile.fromMgdlToUnits(profile1.getTargetLowMgdlTimeFromMidnight(hour * 60 * 60), units)
val valueHigh = Profile.fromMgdlToUnits(profile1.getTargetHighMgdlTimeFromMidnight(hour * 60 * 60), units)
maxValue = max(maxValue, valueHigh)
targetArray1.add(DoubleDataPoint(hour.toDouble(), valueLow, valueHigh))
targetArray1.add(DoubleDataPoint((hour + 1).toDouble(), valueLow, valueHigh))
}
val targetDataPoints1: Array<DoubleDataPoint> = Array(targetArray1.size) { i -> targetArray1[i] }
val targetSeries1: AreaGraphSeries<DoubleDataPoint> = AreaGraphSeries(targetDataPoints1)
addSeries(targetSeries1)
targetSeries1.isDrawBackground = true
val targetArray2: MutableList<DoubleDataPoint> = ArrayList()
for (hour in 0..23) {
val valueLow = Profile.fromMgdlToUnits(profile2.getTargetLowMgdlTimeFromMidnight(hour * 60 * 60), units)
val valueHigh = Profile.fromMgdlToUnits(profile2.getTargetHighMgdlTimeFromMidnight(hour * 60 * 60), units)
maxValue = max(maxValue, valueHigh)
targetArray2.add(DoubleDataPoint(hour.toDouble(), valueLow, valueHigh))
targetArray2.add(DoubleDataPoint((hour + 1).toDouble(), valueLow, valueHigh))
}
val targetDataPoints2: Array<DoubleDataPoint> = Array(targetArray2.size) { i -> targetArray2[i] }
val targetSeries2: AreaGraphSeries<DoubleDataPoint> = AreaGraphSeries(targetDataPoints2)
addSeries(targetSeries2)
targetSeries2.isDrawBackground = false
targetSeries2.color = context.getColor(R.color.examinedProfile)
viewport.isXAxisBoundsManual = true
viewport.setMinX(0.0)
viewport.setMaxX(24.0)
viewport.isYAxisBoundsManual = true
viewport.setMinY(0.0)
viewport.setMaxY(Round.ceilTo(maxValue * 1.1, 0.5))
gridLabelRenderer.numHorizontalLabels = 13
gridLabelRenderer.verticalLabelsColor = targetSeries1.color
val nf: NumberFormat = NumberFormat.getInstance()
nf.maximumFractionDigits = if (units == GlucoseUnit.MMOL) 1 else 0
gridLabelRenderer.setLabelFormatter(DefaultLabelFormatter(nf, nf))
}
}

View file

@ -434,6 +434,12 @@
</LinearLayout> </LinearLayout>
<info.nightscout.androidaps.utils.ui.TargetBgProfileGraph
android:id="@+id/target_graph"
android:layout_width="match_parent"
android:layout_height="100dip"
android:layout_margin="20dp" />
<include <include
android:id="@+id/close_layout" android:id="@+id/close_layout"
layout="@layout/close" /> layout="@layout/close" />

View file

@ -106,11 +106,11 @@
<string name="noprofileset">NO PROFILE SET</string> <string name="noprofileset">NO PROFILE SET</string>
<string name="date">Date</string> <string name="date">Date</string>
<string name="units_label">Units</string> <string name="units_label">Units</string>
<string name="dia_label">DIA</string> <string name="dia_label">Duration of Insulin Action</string>
<string name="ic_label">IC</string> <string name="ic_label">Insulin to Carb ratio</string>
<string name="isf_label">ISF</string> <string name="isf_label">Insulin Sensitivity Factor</string>
<string name="basal_label">Basal</string> <string name="basal_label">Basel rate</string>
<string name="target_label">Target</string> <string name="target_label">Blood Glucose Target</string>
<string name="initializing">Initializing ...</string> <string name="initializing">Initializing ...</string>
<string name="serialnumber">Serial number</string> <string name="serialnumber">Serial number</string>
<string name="battery_label">Battery</string> <string name="battery_label">Battery</string>