Merge pull request #1292 from Andries-Smit/new-profile-editor

profile editor add DIA and Target Chart
This commit is contained in:
Milos Kozak 2022-02-10 22:25:24 +01:00 committed by GitHub
commit 064642339e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 251 additions and 49 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_long_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_long_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_long_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_long_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_long_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_long_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
@ -277,11 +298,23 @@
<LinearLayout <LinearLayout
android:id="@+id/target" android:id="@+id/target"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout
android:id="@+id/target_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
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>
<Button <Button

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

@ -43,7 +43,7 @@ public class AreaGraphSeries<E extends DoubleDataPoint> extends BaseSeries<E> {
/** /**
* the thickness of the line. * the thickness of the line.
* This option will be ignored if you are * This option will be ignored if you are
* using a custom paint via {@link #setCustomPaint(android.graphics.Paint)} * using a custom paint via {@link #setCustomPaint(Paint)}
*/ */
private int thickness = 5; private int thickness = 5;
@ -342,7 +342,7 @@ public class AreaGraphSeries<E extends DoubleDataPoint> extends BaseSeries<E> {
/** /**
* the thickness of the line. * the thickness of the line.
* This option will be ignored if you are * This option will be ignored if you are
* using a custom paint via {@link #setCustomPaint(android.graphics.Paint)} * using a custom paint via {@link #setCustomPaint(Paint)}
* *
* @return the thickness of the line * @return the thickness of the line
*/ */
@ -353,7 +353,7 @@ public class AreaGraphSeries<E extends DoubleDataPoint> extends BaseSeries<E> {
/** /**
* the thickness of the line. * the thickness of the line.
* This option will be ignored if you are * This option will be ignored if you are
* using a custom paint via {@link #setCustomPaint(android.graphics.Paint)} * using a custom paint via {@link #setCustomPaint(Paint)}
* *
* @param thickness thickness of the line * @param thickness thickness of the line
*/ */

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,20 @@ 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
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

@ -111,6 +111,11 @@
<string name="isf_label">ISF</string> <string name="isf_label">ISF</string>
<string name="basal_label">Basal</string> <string name="basal_label">Basal</string>
<string name="target_label">Target</string> <string name="target_label">Target</string>
<string name="dia_long_label">Duration of Insulin Action</string>
<string name="ic_long_label">Insulin to Carb ratio</string>
<string name="isf_long_label">Insulin Sensitivity Factor</string>
<string name="basal_long_label">Basel rate</string>
<string name="target_long_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>