show treatments in overview graph

This commit is contained in:
Milos Kozak 2016-07-17 15:04:33 +02:00
parent c5736b6bf3
commit d82a696bfb
7 changed files with 456 additions and 39 deletions

View file

@ -83,4 +83,5 @@ public class BgReading implements DataPointInterface {
public double getY() {
return valueToUnits(units);
}
}

View file

@ -1,10 +1,5 @@
package info.nightscout.androidaps.db;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
@ -16,17 +11,16 @@ import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.client.data.DbLogger;
import info.nightscout.androidaps.plugins.Overview.GraphSeriesExtension.DataPointWithLabelInterface;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
@DatabaseTable(tableName = "Treatments")
public class Treatment {
public class Treatment implements DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(Treatment.class);
public long getTimeIndex() {
@ -99,6 +93,39 @@ public class Treatment {
"}";
}
// DataPointInterface
@Override
public double getX() {
return timeIndex;
}
// default when no sgv around available
private double yValue = 0;
@Override
public double getY() {
return yValue;
}
@Override
public String getLabel() {
String label = "";
if (insulin > 0) label += DecimalFormatter.to2Decimal(insulin) + "U";
if (carbs > 0) label += (label.equals("") ? "" : " ") + DecimalFormatter.to0Decimal(carbs) + "g";
return label;
}
public void setYValue(List<BgReading> bgReadingsArray) {
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
if (profile == null) return;
for (int r = bgReadingsArray.size() - 1; r >= 0; r--) {
BgReading reading = bgReadingsArray.get(r);
if (reading.timeIndex > timeIndex) continue;
yValue = NSProfile.fromMgdlToUnits(reading.value, profile.getUnits());
break;
}
}
public void sendToNSClient() {
JSONObject data = new JSONObject();
try {
@ -113,31 +140,4 @@ public class Treatment {
ConfigBuilderFragment.uploadCareportalEntryToNS(data);
}
public void updateToNSClient() {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbUpdate");
bundle.putString("collection", "treatments");
JSONObject data = new JSONObject();
try {
data.put("eventType", "Meal Bolus");
data.put("insulin", insulin);
data.put("carbs", carbs.intValue());
data.put("created_at", DateUtil.toISOString(created_at));
data.put("timeIndex", timeIndex);
} catch (JSONException e) {
e.printStackTrace();
}
bundle.putString("data", data.toString());
bundle.putString("_id", _id);
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
List<ResolveInfo> q = context.getPackageManager().queryBroadcastReceivers(intent, 0);
if (q.size() < 1) {
log.error("DBUPDATE No receivers");
} else if (Config.logNSUpload)
log.debug("DBUPDATE dbUpdate " + q.size() + " receivers " + _id + " " + data.toString());
}
}
}

View file

@ -1,5 +1,8 @@
package info.nightscout.androidaps.interfaces;
import java.util.List;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
@ -11,4 +14,5 @@ public interface TreatmentsInterface {
void updateTotalIOB();
IobTotal getLastCalculation();
TreatmentsFragment.MealData getMealData();
List<Treatment> getTreatments();
}

View file

@ -0,0 +1,52 @@
package info.nightscout.androidaps.plugins.Overview.GraphSeriesExtension;
/**
* GraphView
* Copyright (C) 2014 Jonas Gehring
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License,
* with the "Linking Exception", which can be found at the license.txt
* file in this program.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* with the "Linking Exception" along with this program; if not,
* write to the author Jonas Gehring <g.jjoe64@gmail.com>.
*/
/**
* Added by mike
*/
import com.jjoe64.graphview.series.DataPointInterface;
/**
* interface of data points. Implement this in order
* to use your class in {@link com.jjoe64.graphview.series.Series}.
*
* You can also use the default implementation {@link com.jjoe64.graphview.series.DataPoint} so
* you do not have to implement it for yourself.
*
* @author jjoe64
*/
public interface DataPointWithLabelInterface extends DataPointInterface{
/**
* @return the x value
*/
public double getX();
/**
* @return the y value
*/
public double getY();
/**
* @return the label value
*/
public String getLabel();
}

View file

@ -0,0 +1,333 @@
package info.nightscout.androidaps.plugins.Overview.GraphSeriesExtension;
/**
* GraphView
* Copyright (C) 2014 Jonas Gehring
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License,
* with the "Linking Exception", which can be found at the license.txt
* file in this program.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* with the "Linking Exception" along with this program; if not,
* write to the author Jonas Gehring <g.jjoe64@gmail.com>.
*/
/**
* Added by mike
*/
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.BaseSeries;
import java.util.Iterator;
/**
* Series that plots the data as points.
* The points can be different shapes or a
* complete custom drawing.
*
* @author jjoe64
*/
public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> extends BaseSeries<E> {
/**
* interface to implement a custom
* drawing for the data points.
*/
public static interface CustomShape {
/**
* called when drawing a single data point.
* use the x and y coordinates to render your
* drawing at this point.
*
* @param canvas canvas to draw on
* @param paint internal paint object. this has the correct color.
* But you can use your own paint.
* @param x x-coordinate the point has to be drawn to
* @param y y-coordinate the point has to be drawn to
* @param dataPoint the related data point
*/
void draw(Canvas canvas, Paint paint, float x, float y, DataPointWithLabelInterface dataPoint);
}
/**
* choose a predefined shape to render for
* each data point.
* You can also render a custom drawing via {@link com.jjoe64.graphview.series.PointsGraphSeries.CustomShape}
*/
public enum Shape {
/**
* draws a point / circle
*/
POINT,
/**
* draws a triangle
*/
TRIANGLE,
/**
* draws a rectangle
*/
RECTANGLE
}
/**
* wrapped styles for this series
*/
private final class Styles {
/**
* this is used for the size of the shape that
* will be drawn.
* This is useless if you are using a custom shape.
*/
float size;
/**
* the shape that will be drawn for each point.
*/
Shape shape;
}
/**
* wrapped styles
*/
private Styles mStyles;
/**
* internal paint object
*/
private Paint mPaint;
/**
* handler to use a custom drawing
*/
private CustomShape mCustomShape;
/**
* creates the series without data
*/
public PointsWithLabelGraphSeries() {
init();
}
/**
* creates the series with data
*
* @param data datapoints
*/
public PointsWithLabelGraphSeries(E[] data) {
super(data);
init();
}
/**
* inits the internal objects
* set the defaults
*/
protected void init() {
mStyles = new Styles();
mStyles.size = 20f;
mPaint = new Paint();
mPaint.setStrokeCap(Paint.Cap.ROUND);
setShape(Shape.POINT);
}
/**
* plot the data to the viewport
*
* @param graphView graphview
* @param canvas canvas to draw on
* @param isSecondScale whether it is the second scale
*/
@Override
public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) {
resetDataPoints();
// get data
double maxX = graphView.getViewport().getMaxX(false);
double minX = graphView.getViewport().getMinX(false);
double maxY;
double minY;
if (isSecondScale) {
maxY = graphView.getSecondScale().getMaxY();
minY = graphView.getSecondScale().getMinY();
} else {
maxY = graphView.getViewport().getMaxY(false);
minY = graphView.getViewport().getMinY(false);
}
Iterator<E> values = getValues(minX, maxX);
// draw background
double lastEndY = 0;
double lastEndX = 0;
// draw data
mPaint.setColor(getColor());
double diffY = maxY - minY;
double diffX = maxX - minX;
float graphHeight = graphView.getGraphContentHeight();
float graphWidth = graphView.getGraphContentWidth();
float graphLeft = graphView.getGraphContentLeft();
float graphTop = graphView.getGraphContentTop();
lastEndY = 0;
lastEndX = 0;
float firstX = 0;
int i=0;
while (values.hasNext()) {
E value = values.next();
double valY = value.getY() - minY;
double ratY = valY / diffY;
double y = graphHeight * ratY;
double valX = value.getX() - minX;
double ratX = valX / diffX;
double x = graphWidth * ratX;
double orgX = x;
double orgY = y;
// overdraw
boolean overdraw = false;
if (x > graphWidth) { // end right
overdraw = true;
}
if (y < 0) { // end bottom
overdraw = true;
}
if (y > graphHeight) { // end top
overdraw = true;
}
/* Fix a bug that continue to show the DOT after Y axis */
if(x < 0) {
overdraw = true;
}
float endX = (float) x + (graphLeft + 1);
float endY = (float) (graphTop - y) + graphHeight;
registerDataPoint(endX, endY, value);
// draw data point
if (!overdraw) {
if (mCustomShape != null) {
mCustomShape.draw(canvas, mPaint, endX, endY, value);
} else if (mStyles.shape == Shape.POINT) {
canvas.drawCircle(endX, endY, mStyles.size, mPaint);
} else if (mStyles.shape == Shape.RECTANGLE) {
canvas.drawRect(endX-mStyles.size, endY-mStyles.size, endX+mStyles.size, endY+mStyles.size, mPaint);
} else if (mStyles.shape == Shape.TRIANGLE) {
Point[] points = new Point[3];
points[0] = new Point((int)endX, (int)(endY-getSize()));
points[1] = new Point((int)(endX+getSize()), (int)(endY+getSize()*0.67));
points[2] = new Point((int)(endX-getSize()), (int)(endY+getSize()*0.67));
drawArrows(points, canvas, mPaint);
}
// set values above point
if (value.getLabel() != null) {
float px = endX;
float py = endY - (int) (getSize());
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((int) (getSize() * 2.5));
mPaint.setFakeBoldText(true);
canvas.drawText(value.getLabel(), px + getSize(), py, mPaint);
canvas.restore();
}
}
i++;
}
}
/**
* helper to render triangle
*
* @param point array with 3 coordinates
* @param canvas canvas to draw on
* @param paint paint object
*/
private void drawArrows(Point[] point, Canvas canvas, Paint paint) {
float [] points = new float[8];
points[0] = point[0].x;
points[1] = point[0].y;
points[2] = point[1].x;
points[3] = point[1].y;
points[4] = point[2].x;
points[5] = point[2].y;
points[6] = point[0].x;
points[7] = point[0].y;
canvas.drawVertices(Canvas.VertexMode.TRIANGLES, 8, points, 0, null, 0, null, 0, null, 0, 0, paint);
Path path = new Path();
path.moveTo(point[0].x , point[0].y);
path.lineTo(point[1].x,point[1].y);
path.lineTo(point[2].x,point[2].y);
canvas.drawPath(path,paint);
}
/**
* This is used for the size of the shape that
* will be drawn.
* This is useless if you are using a custom shape.
*
* @return the size of the shape
*/
public float getSize() {
return mStyles.size;
}
/**
* This is used for the size of the shape that
* will be drawn.
* This is useless if you are using a custom shape.
*
* @param radius the size of the shape
*/
public void setSize(float radius) {
mStyles.size = radius;
}
/**
* @return the shape that will be drawn for each point
*/
public Shape getShape() {
return mStyles.shape;
}
/**
* @param s the shape that will be drawn for each point
*/
public void setShape(Shape s) {
mStyles.shape = s;
}
/**
* Use a custom handler to render your own
* drawing for each data point.
*
* @param shape handler to use a custom drawing
*/
public void setCustomShape(CustomShape shape) {
mCustomShape = shape;
}
}

View file

@ -44,6 +44,7 @@ import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui;
@ -59,6 +60,7 @@ import info.nightscout.androidaps.plugins.Overview.Dialogs.NewExtendedBolusDialo
import info.nightscout.androidaps.plugins.Overview.Dialogs.NewTempBasalDialog;
import info.nightscout.androidaps.plugins.Overview.Dialogs.NewTreatmentDialog;
import info.nightscout.androidaps.plugins.Overview.Dialogs.WizardDialog;
import info.nightscout.androidaps.plugins.Overview.GraphSeriesExtension.PointsWithLabelGraphSeries;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
@ -520,6 +522,7 @@ public class OverviewFragment extends Fragment implements PluginBase {
LineGraphSeries<DataPoint> seriesNow = null;
PointsGraphSeries<BgReading> seriesInRage = null;
PointsGraphSeries<BgReading> seriesOutOfRange = null;
PointsWithLabelGraphSeries<Treatment> seriesTreatments = null;
// remove old data from graph
bgGraph.removeAllSeries();
@ -606,7 +609,6 @@ public class OverviewFragment extends Fragment implements PluginBase {
seriesOutOfRange.setColor(Color.RED);
}
// **** HIGH and LOW targets graph ****
DataPoint[] lowDataPoints = new DataPoint[]{
new DataPoint(fromTime, lowLine),
@ -639,6 +641,25 @@ public class OverviewFragment extends Fragment implements PluginBase {
seriesNow.setCustomPaint(paint);
// Treatments
List<Treatment> treatments = MainApp.getConfigBuilder().getActiveTreatments().getTreatments();
List<Treatment> filteredTreatments = new ArrayList<Treatment>();
for (int tx = 0; tx < treatments.size(); tx ++) {
Treatment t = treatments.get(tx);
if (t.getTimeIndex() < fromTime || t.getTimeIndex() > now) continue;
t.setYValue(bgReadingsArray);
filteredTreatments.add(t);
}
Treatment[] treatmentsArray = new Treatment[filteredTreatments.size()];
treatmentsArray = filteredTreatments.toArray(treatmentsArray);
if (treatmentsArray.length > 0) {
bgGraph.addSeries(seriesTreatments = new PointsWithLabelGraphSeries<Treatment>(treatmentsArray));
seriesTreatments.setShape(PointsWithLabelGraphSeries.Shape.TRIANGLE);
seriesTreatments.setSize(10);
seriesTreatments.setColor(Color.CYAN);
}
// set manual x bounds to have nice steps
bgGraph.getViewport().setMaxX(toTime);
bgGraph.getViewport().setMinX(fromTime);

View file

@ -180,6 +180,12 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
return result;
}
@Override
public List<Treatment> getTreatments() {
return treatments;
}
public static class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TreatmentsViewHolder> {
List<Treatment> treatments;