Merge pull request #1867 from Paulusma/IA-in-BG-graph

Insulin Activity in bg graph
This commit is contained in:
Milos Kozak 2019-07-15 15:27:04 +02:00 committed by GitHub
commit b26b583f2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 170 additions and 7 deletions

View file

@ -52,7 +52,7 @@ public class HistoryBrowseActivity extends AppCompatActivity {
ImageButton chartButton;
boolean showBasal = true;
boolean showIob, showCob, showDev, showRat, showDevslope;
boolean showIob, showCob, showDev, showRat, showActPrim, showActSec, showDevslope;
@BindView(R.id.historybrowse_date)
@ -285,6 +285,10 @@ public class HistoryBrowseActivity extends AppCompatActivity {
// set manual x bounds to have nice steps
graphData.formatAxis(fromTime, toTime);
if(showActPrim) {
graphData.addActivity(fromTime, toTime, false,1d);
}
// Treatments
graphData.addTreatments(fromTime, toTime);
@ -305,6 +309,7 @@ public class HistoryBrowseActivity extends AppCompatActivity {
boolean useCobForScale = false;
boolean useDevForScale = false;
boolean useRatioForScale = false;
boolean useIAForScale = false;
boolean useDSForScale = false;
if (showIob) {
@ -315,6 +320,8 @@ public class HistoryBrowseActivity extends AppCompatActivity {
useDevForScale = true;
} else if (showRat) {
useRatioForScale = true;
} else if (showActSec) {
useIAForScale = true;
} else if (showDevslope) {
useDSForScale = true;
}
@ -327,6 +334,8 @@ public class HistoryBrowseActivity extends AppCompatActivity {
secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1d);
if (showRat)
secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1d);
if (showActSec)
secondGraphData.addActivity(fromTime, toTime, useIAForScale, useIAForScale? 2d: 1d);
if (showDevslope)
secondGraphData.addDeviationSlope(fromTime, toTime, useDSForScale, 1d);
@ -337,14 +346,14 @@ public class HistoryBrowseActivity extends AppCompatActivity {
// do GUI update
runOnUiThread(() -> {
if (showIob || showCob || showDev || showRat || showDevslope) {
if (showIob || showCob || showDev || showRat || showActSec || showDevslope) {
iobGraph.setVisibility(View.VISIBLE);
} else {
iobGraph.setVisibility(View.GONE);
}
// finally enforce drawing of graphs
graphData.performUpdate();
if (showIob || showCob || showDev || showRat || showDevslope)
if (showIob || showCob || showDev || showRat || showActSec || showDevslope)
secondGraphData.performUpdate();
});
}).start();
@ -353,22 +362,37 @@ public class HistoryBrowseActivity extends AppCompatActivity {
private void setupChartMenu() {
chartButton = (ImageButton) findViewById(R.id.overview_chartMenuButton);
chartButton.setOnClickListener(v -> {
MenuItem item;
MenuItem item,dividerItem;
CharSequence title;
int titleMaxChars = 0;
SpannableString s;
PopupMenu popup = new PopupMenu(v.getContext(), v);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.BAS.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_basals));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.basal, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showBasal);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.ACTPRIM.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showActPrim);
dividerItem = popup.getMenu().add("");
dividerItem.setEnabled(false);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.IOB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_iob));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.iob, null)), 0, s.length(), 0);
item.setTitle(s);
@ -377,6 +401,7 @@ public class HistoryBrowseActivity extends AppCompatActivity {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.COB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_cob));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.cob, null)), 0, s.length(), 0);
item.setTitle(s);
@ -385,6 +410,7 @@ public class HistoryBrowseActivity extends AppCompatActivity {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEV.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_deviations));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.deviations, null)), 0, s.length(), 0);
item.setTitle(s);
@ -393,15 +419,27 @@ public class HistoryBrowseActivity extends AppCompatActivity {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.SEN.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_sensitivity));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.ratio, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showRat);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.ACTSEC.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showActSec);
if (MainApp.devBranch) {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal(), Menu.NONE, "Deviation slope");
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.devslopepos, null)), 0, s.length(), 0);
item.setTitle(s);
@ -409,6 +447,10 @@ public class HistoryBrowseActivity extends AppCompatActivity {
item.setChecked(showDevslope);
}
// Fairly good guestimate for required divider text size...
title = new String(new char[titleMaxChars+10]).replace("\0", "_");
dividerItem.setTitle(title);
popup.setOnMenuItemClickListener(item1 -> {
if (item1.getItemId() == OverviewFragment.CHARTTYPE.BAS.ordinal()) {
showBasal = !item1.isChecked();
@ -420,6 +462,10 @@ public class HistoryBrowseActivity extends AppCompatActivity {
showDev = !item1.isChecked();
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.SEN.ordinal()) {
showRat = !item1.isChecked();
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTPRIM.ordinal()) {
showActPrim = !item1.isChecked();
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTSEC.ordinal()) {
showActSec = !item1.isChecked();
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal()) {
showDevslope = !item1.isChecked();
}

View file

@ -189,7 +189,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
Handler sLoopHandler = new Handler();
Runnable sRefreshLoop = null;
public enum CHARTTYPE {PRE, BAS, IOB, COB, DEV, SEN, DEVSLOPE}
public enum CHARTTYPE {PRE, BAS, IOB, COB, DEV, SEN, ACTPRIM, ACTSEC, DEVSLOPE}
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledUpdate = null;
@ -350,14 +350,15 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
else
predictionsAvailable = false;
MenuItem item;
MenuItem item,dividerItem;
CharSequence title;
int titleMaxChars = 0;
SpannableString s;
PopupMenu popup = new PopupMenu(v.getContext(), v);
if (predictionsAvailable) {
item = popup.getMenu().add(Menu.NONE, CHARTTYPE.PRE.ordinal(), Menu.NONE, "Predictions");
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.prediction, null)), 0, s.length(), 0);
item.setTitle(s);
@ -367,14 +368,28 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
item = popup.getMenu().add(Menu.NONE, CHARTTYPE.BAS.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_basals));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.basal, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(SP.getBoolean("showbasals", true));
item = popup.getMenu().add(Menu.NONE, CHARTTYPE.ACTPRIM.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(SP.getBoolean("showactivityprimary", true));
dividerItem = popup.getMenu().add("");
dividerItem.setEnabled(false);
item = popup.getMenu().add(Menu.NONE, CHARTTYPE.IOB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_iob));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.iob, null)), 0, s.length(), 0);
item.setTitle(s);
@ -383,6 +398,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
item = popup.getMenu().add(Menu.NONE, CHARTTYPE.COB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_cob));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.cob, null)), 0, s.length(), 0);
item.setTitle(s);
@ -391,6 +407,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
item = popup.getMenu().add(Menu.NONE, CHARTTYPE.DEV.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_deviations));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.deviations, null)), 0, s.length(), 0);
item.setTitle(s);
@ -399,15 +416,26 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
item = popup.getMenu().add(Menu.NONE, CHARTTYPE.SEN.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_sensitivity));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.ratio, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(SP.getBoolean("showratios", false));
item = popup.getMenu().add(Menu.NONE, CHARTTYPE.ACTSEC.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity));
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(SP.getBoolean("showactivitysecondary", true));
if (MainApp.devBranch) {
item = popup.getMenu().add(Menu.NONE, CHARTTYPE.DEVSLOPE.ordinal(), Menu.NONE, "Deviation slope");
title = item.getTitle();
if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.devslopepos, null)), 0, s.length(), 0);
item.setTitle(s);
@ -415,6 +443,10 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
item.setChecked(SP.getBoolean("showdevslope", false));
}
// Fairly good guestimate for required divider text size...
title = new String(new char[titleMaxChars+10]).replace("\0", "_");
dividerItem.setTitle(title);
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
@ -430,6 +462,10 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
SP.putBoolean("showdeviations", !item.isChecked());
} else if (item.getItemId() == CHARTTYPE.SEN.ordinal()) {
SP.putBoolean("showratios", !item.isChecked());
} else if (item.getItemId() == CHARTTYPE.ACTPRIM.ordinal()) {
SP.putBoolean("showactivityprimary", !item.isChecked());
} else if (item.getItemId() == CHARTTYPE.ACTSEC.ordinal()) {
SP.putBoolean("showactivitysecondary", !item.isChecked());
} else if (item.getItemId() == CHARTTYPE.DEVSLOPE.ordinal()) {
SP.putBoolean("showdevslope", !item.isChecked());
}
@ -1424,6 +1460,10 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
// set manual x bounds to have nice steps
graphData.formatAxis(fromTime, endTime);
if(SP.getBoolean("showactivityprimary", true)) {
graphData.addActivity(fromTime, endTime, false,1d);
}
// Treatments
graphData.addTreatments(fromTime, endTime);
@ -1449,6 +1489,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
boolean useDevForScale = false;
boolean useRatioForScale = false;
boolean useDSForScale = false;
boolean useIAForScale = false;
if (SP.getBoolean("showiob", true)) {
useIobForScale = true;
@ -1458,6 +1499,8 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
useDevForScale = true;
} else if (SP.getBoolean("showratios", false)) {
useRatioForScale = true;
} else if (SP.getBoolean("showactivitysecondary", false)) {
useIAForScale = true;
} else if (SP.getBoolean("showdevslope", false)) {
useDSForScale = true;
}
@ -1470,6 +1513,8 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
secondGraphData.addDeviations(fromTime, now, useDevForScale, 1d);
if (SP.getBoolean("showratios", false))
secondGraphData.addRatio(fromTime, now, useRatioForScale, 1d);
if(SP.getBoolean("showactivitysecondary", true))
secondGraphData.addActivity(fromTime, endTime, useIAForScale,useIAForScale ? 2d: 1d);
if (SP.getBoolean("showdevslope", false) && MainApp.devBranch)
secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1d);
@ -1486,6 +1531,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
|| SP.getBoolean("showcob", true)
|| SP.getBoolean("showdeviations", false)
|| SP.getBoolean("showratios", false)
|| SP.getBoolean("showactivitysecondary", false)
|| SP.getBoolean("showdevslope", false)) {
iobGraph.setVisibility(View.VISIBLE);
} else {

View file

@ -21,6 +21,7 @@ import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent;
@ -46,6 +47,7 @@ import info.nightscout.androidaps.plugins.general.overview.graphExtensions.TimeA
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.Round;
import info.nightscout.androidaps.utils.SP;
/**
* Created by mike on 18.10.2017.
@ -344,6 +346,59 @@ public class GraphData {
? Profile.fromMgdlToUnits(bgReadingsArray.get(0).value, units) : Profile.fromMgdlToUnits(100, units);
}
public void addActivity(long fromTime, long toTime, boolean useForScale, double scale) {
FixedLineGraphSeries<ScaledDataPoint> actSeriesHist;
List<ScaledDataPoint> actArrayHist = new ArrayList<>();
FixedLineGraphSeries<ScaledDataPoint> actSeriesPred;
List<ScaledDataPoint> actArrayPred = new ArrayList<>();
double now = System.currentTimeMillis();
Scale actScale = new Scale();
IobTotal total = null;
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
Profile profile = ProfileFunctions.getInstance().getProfile(time);
double act = 0d;
if (profile == null) continue;
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile);
act = total.activity;
if(time<=now)
actArrayHist.add(new ScaledDataPoint(time, act, actScale));
else
actArrayPred.add(new ScaledDataPoint(time, act, actScale));
}
ScaledDataPoint[] actData = new ScaledDataPoint[actArrayHist.size()];
actData = actArrayHist.toArray(actData);
actSeriesHist = new FixedLineGraphSeries<>(actData);
actSeriesHist.setDrawBackground(false);
actSeriesHist.setColor(MainApp.gc(R.color.activity));
actSeriesHist.setThickness(3);
addSeries(actSeriesHist);
actData = new ScaledDataPoint[actArrayPred.size()];
actData = actArrayPred.toArray(actData);
actSeriesPred = new FixedLineGraphSeries<>(actData);
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setPathEffect(new DashPathEffect(new float[]{4, 4}, 0));
paint.setColor(MainApp.gc(R.color.activity));
actSeriesPred.setCustomPaint(paint);
double maxIAValue = SP.getDouble(R.string.key_scale_insulin_activity, 0.05);
if (useForScale) {
maxY = maxIAValue;
minY = -maxIAValue;
}
actScale.setMultiplier(maxY * scale / maxIAValue);
addSeries(actSeriesPred);
}
// scale in % of vertical size (like 0.3)
public void addIob(long fromTime, long toTime, boolean useForScale, double scale) {
FixedLineGraphSeries<ScaledDataPoint> iobSeries;

View file

@ -9,6 +9,7 @@
<color name="uam">#c9bd60</color>
<color name="zt">#00d2d2</color>
<color name="ratio">#FFFFFF</color>
<color name="activity">#d3f166</color>
<color name="devslopepos">#FFFFFF00</color>
<color name="devslopeneg">#FFFF00FF</color>
<color name="inrange">#00FF00</color>

View file

@ -1002,6 +1002,7 @@
<string name="ns_autobackfill_summary">Autobackfill missig BGs from NS</string>
<string name="key_ns_autobackfill" translatable="false">ns_autobackfill</string>
<string name="loop_smbsetbypump_label">SMB set by pump</string>
<string name="overview_show_activity">Activity</string>
<string name="overview_show_sensitivity">Sensitivity</string>
<string name="overview_show_deviations">Deviations</string>
<string name="overview_show_cob">Carbs On Board</string>
@ -1374,6 +1375,8 @@
<string name="old_version">old version</string>
<string name="very_old_version">very old version</string>
<string name="new_version_warning">New version for at least %1$d days available! Fallback to LGS after 60 days, loop will be disabled after 90 days</string>
<string name="key_scale_insulin_activity" translatable="false">scale_insulin_activity</string>
<string name="scale_insulin_activity">Graph scale insulin activity [U/min]</string>
<string name="twohours">2h</string>
<string name="formatinsulinunits">%1$.2fU</string>

View file

@ -10,6 +10,18 @@
android:title="@string/keep_screen_on_title"
android:summary="@string/keep_screen_on_summary"/>
<com.andreabaccega.widget.ValidatingEditTextPreference
android:defaultValue="0.05"
android:inputType="numberDecimal"
android:key="@string/key_scale_insulin_activity"
android:maxLines="1"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/scale_insulin_activity"
validate:floatmaxNumber="10.0"
validate:floatminNumber="0.0"
validate:testType="floatNumericRange" />
<PreferenceScreen android:title="@string/overview_buttons_selection">
<SwitchPreference