show treatments in overview graph
This commit is contained in:
parent
c5736b6bf3
commit
d82a696bfb
7 changed files with 456 additions and 39 deletions
|
@ -83,4 +83,5 @@ public class BgReading implements DataPointInterface {
|
|||
public double getY() {
|
||||
return valueToUnits(units);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue