From d4474df53e66a69214271b705701028893ee7bac Mon Sep 17 00:00:00 2001 From: Volker Richert <v.richert@addmore.de> Date: Sat, 7 Jan 2017 15:37:19 +0100 Subject: [PATCH] - change to scatter chat - enable touch an chat - implement long click to zoom out (fit to screen) --- .../android/medtronic/MainActivity.java | 260 +++++++++++------- .../model/medtronicNg/PumpStatusEvent.java | 4 +- app/src/main/res/layout/activity_main.xml | 2 +- 3 files changed, 163 insertions(+), 103 deletions(-) diff --git a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java index 21d22f3..8e55bdf 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java +++ b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java @@ -33,28 +33,28 @@ import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.widget.TextView; import android.widget.TextView.BufferType; -import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.charts.ScatterChart; import com.github.mikephil.charting.components.AxisBase; -import com.github.mikephil.charting.components.Description; import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.Entry; -import com.github.mikephil.charting.data.LineData; -import com.github.mikephil.charting.data.realm.implementation.RealmLineDataSet; -import com.github.mikephil.charting.formatter.DefaultAxisValueFormatter; +import com.github.mikephil.charting.data.ScatterData; +import com.github.mikephil.charting.data.ScatterDataSet; +import com.github.mikephil.charting.data.realm.implementation.RealmScatterDataSet; import com.github.mikephil.charting.formatter.IAxisValueFormatter; import com.github.mikephil.charting.formatter.IValueFormatter; -import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; +import com.github.mikephil.charting.interfaces.datasets.IScatterDataSet; +import com.github.mikephil.charting.listener.ChartTouchListener; +import com.github.mikephil.charting.listener.OnChartGestureListener; import com.github.mikephil.charting.utils.ColorTemplate; import com.github.mikephil.charting.utils.ViewPortHandler; import com.google.android.gms.appindexing.Action; -import com.google.android.gms.appindexing.AppIndex; import com.google.android.gms.appindexing.Thing; -import com.google.android.gms.common.api.GoogleApiClient; import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.materialdrawer.AccountHeaderBuilder; import com.mikepenz.materialdrawer.Drawer; @@ -64,9 +64,9 @@ import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import java.text.DateFormat; import java.text.DecimalFormat; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Locale; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; @@ -96,7 +96,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc SharedPreferences prefs = null; private PumpInfo mActivePump; private TextView mTextViewLog; // This will eventually move to a status page. - private LineChart mChart; + private ScatterChart mChart; private Intent mNightscoutUploadService; private Handler mUiRefreshHandler = new Handler(); private Runnable mUiRefreshRunnable = new RefreshDisplayRunnable(); @@ -252,10 +252,43 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc .build(); mTextViewLog = (TextView) findViewById(R.id.textview_log); - mChart = (LineChart) findViewById(R.id.chart); + mChart = (ScatterChart) findViewById(R.id.chart); mChart.setDescription(null); // Hide the description + mChart.setTouchEnabled(true); + mChart.setPinchZoom(true); + mChart.setHighlightPerDragEnabled(false); + mChart.setHighlightPerTapEnabled(false); + mChart.setOnChartGestureListener(new OnChartGestureListener() { + + @Override + public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {} + + @Override + public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {} + + @Override + public void onChartLongPressed(MotionEvent me) { + mChart.fitScreen(); + } + + @Override + public void onChartDoubleTapped(MotionEvent me) {} + + @Override + public void onChartSingleTapped(MotionEvent me) {} + + @Override + public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {} + + @Override + public void onChartScale(MotionEvent me, float scaleX, float scaleY) {} + + @Override + public void onChartTranslate(MotionEvent me, float dX, float dY) {} + }); + XAxis xAxis = mChart.getXAxis(); xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); xAxis.setTextSize(10f); @@ -622,113 +655,138 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc } // FIXME - grab the last item from the activePump's getPumpHistory - RealmResults<PumpStatusEvent> results = - mRealm.where(PumpStatusEvent.class) - .greaterThan("eventDate", new Date(System.currentTimeMillis() - 1000*60*60*24)) - .findAllSorted("eventDate", Sort.ASCENDING); + updateChart(mRealm.where(PumpStatusEvent.class) + .greaterThan("eventDate", new Date(System.currentTimeMillis() - 1000*60*60*24)) + .findAllSorted("eventDate", Sort.ASCENDING)); - updateChart(results); - - if (pumpStatusData == null) { - return; - } + if (pumpStatusData != null) { - String sgvString, units; - if (prefs.getBoolean("mmolxl", false)) { - DecimalFormat df; - if (prefs.getBoolean("mmolDecimals", false)) - df = new DecimalFormat("0.00"); - else - df = new DecimalFormat("0.0"); + String sgvString, units; + if (prefs.getBoolean("mmolxl", false)) { + DecimalFormat df; + if (prefs.getBoolean("mmolDecimals", false)) + df = new DecimalFormat("0.00"); + else + df = new DecimalFormat("0.0"); - float fBgValue = (float) pumpStatusData.getSgv(); - sgvString = df.format(fBgValue / 18.016f); - units = "mmol/L"; - Log.d(TAG, "mmolxl true --> " + sgvString); + float fBgValue = (float) pumpStatusData.getSgv(); + sgvString = df.format(fBgValue / 18.016f); + units = "mmol/L"; + Log.d(TAG, "mmolxl true --> " + sgvString); - } else { - sgvString = String.valueOf(pumpStatusData.getSgv()); - units = "mg/dL"; - Log.d(TAG, "mmolxl false --> " + sgvString); - } + } else { + sgvString = String.valueOf(pumpStatusData.getSgv()); + units = "mg/dL"; + Log.d(TAG, "mmolxl false --> " + sgvString); + } - textViewBg.setText(sgvString); - textViewUnits.setText(units); - textViewBgTime.setText(DateUtils.getRelativeTimeSpanString(pumpStatusData.getEventDate().getTime())); - textViewTrend.setText(Html.fromHtml(renderTrendHtml(pumpStatusData.getCgmTrend()))); - textViewIOB.setText(String.format(Locale.getDefault(), "%.2f", pumpStatusData.getActiveInsulin())); - - ActionMenuItemView batIcon = ((ActionMenuItemView) findViewById(R.id.status_battery)); - if (batIcon != null) { - switch (pumpStatusData.getBatteryPercentage()) { - case 0: - batIcon.setTitle("0%"); - batIcon.setIcon(getResources().getDrawable(R.drawable.battery_0)); - break; - case 25: - batIcon.setTitle("25%"); - batIcon.setIcon(getResources().getDrawable(R.drawable.battery_25)); - break; - case 50: - batIcon.setTitle("50%"); - batIcon.setIcon(getResources().getDrawable(R.drawable.battery_50)); - break; - case 75: - batIcon.setTitle("75%"); - batIcon.setIcon(getResources().getDrawable(R.drawable.battery_75)); - break; - case 100: - batIcon.setTitle("100%"); - batIcon.setIcon(getResources().getDrawable(R.drawable.battery_100)); - break; - default: - batIcon.setTitle(getResources().getString(R.string.menu_name_status)); - batIcon.setIcon(getResources().getDrawable(R.drawable.battery_unknown)); + textViewBg.setText(sgvString); + textViewUnits.setText(units); + textViewBgTime.setText(DateUtils.getRelativeTimeSpanString(pumpStatusData.getEventDate().getTime())); + textViewTrend.setText(Html.fromHtml(renderTrendHtml(pumpStatusData.getCgmTrend()))); + textViewIOB.setText(String.format(Locale.getDefault(), "%.2f", pumpStatusData.getActiveInsulin())); + + ActionMenuItemView batIcon = ((ActionMenuItemView) findViewById(R.id.status_battery)); + if (batIcon != null) { + switch (pumpStatusData.getBatteryPercentage()) { + case 0: + batIcon.setTitle("0%"); + batIcon.setIcon(getResources().getDrawable(R.drawable.battery_0)); + break; + case 25: + batIcon.setTitle("25%"); + batIcon.setIcon(getResources().getDrawable(R.drawable.battery_25)); + break; + case 50: + batIcon.setTitle("50%"); + batIcon.setIcon(getResources().getDrawable(R.drawable.battery_50)); + break; + case 75: + batIcon.setTitle("75%"); + batIcon.setIcon(getResources().getDrawable(R.drawable.battery_75)); + break; + case 100: + batIcon.setTitle("100%"); + batIcon.setIcon(getResources().getDrawable(R.drawable.battery_100)); + break; + default: + batIcon.setTitle(getResources().getString(R.string.menu_name_status)); + batIcon.setIcon(getResources().getDrawable(R.drawable.battery_unknown)); + } } - } + } // Run myself again in 60 seconds; mUiRefreshHandler.postDelayed(this, 60000L); } private void updateChart(RealmResults<PumpStatusEvent> results) { - if (results.size() == 0) return; - PumsStatusLineDataSet lineDataSet = new PumsStatusLineDataSet(results, "eventDate", "sgv"); - - lineDataSet.setDrawCircleHole(false); - lineDataSet.setColor(ColorTemplate.rgb("#FF5722")); - lineDataSet.setCircleColor(ColorTemplate.rgb("#FF5722")); - lineDataSet.setLineWidth(1.8f); - lineDataSet.setCircleRadius(3.6f); - lineDataSet.setValueTextColor(Color.WHITE); - lineDataSet.setValueFormatter(new IValueFormatter() { - @Override - public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { - DecimalFormat df; + int size = results.size(); + if (size == 0) return; + + List<Entry> entries = new ArrayList<Entry>(size); + int[] colors = new int[size * 2]; // getColor is called with (i/2) + + for (PumpStatusEvent pumpStatus: results) { + // turn your data into Entry objects + int sgv = pumpStatus.getSgv(), + pos = entries.size() * 2; + + entries.add(new Entry(pumpStatus.getEventDate().getTime(), pumpStatus.getSgv())); + if (sgv < 80) + colors[pos] = colors[pos+1] = Color.RED; + else if (sgv <= 180) + colors[pos] = colors[pos+1] = Color.GREEN; + else if (sgv <= 260) + colors[pos] = colors[pos+1] = Color.YELLOW; + else + colors[pos] = colors[pos+1] = Color.RED; + } - if (prefs.getBoolean("mmolxl", false)) { - if (prefs.getBoolean("mmolDecimals", false)) - df = new DecimalFormat("0.00"); - else - df = new DecimalFormat("0.0"); + if (mChart.getData() == null) { + mChart.setMinimumHeight(200); - return df.format(value / 18.016f); - } else { - return new DecimalFormat("0").format(value); + ScatterDataSet dataSet = new ScatterDataSet(entries, null); + + dataSet.setColors(colors); + dataSet.setValueTextColor(Color.WHITE); + dataSet.setScatterShape(ScatterChart.ScatterShape.CIRCLE); + dataSet.setScatterShapeSize(7.2f); + dataSet.setValueFormatter(new IValueFormatter() { + @Override + public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { + DecimalFormat df; + + if (prefs.getBoolean("mmolxl", false)) { + if (prefs.getBoolean("mmolDecimals", false)) + df = new DecimalFormat("0.00"); + else + df = new DecimalFormat("0.0"); + + return df.format(value / 18.016f); + } else { + return new DecimalFormat("0").format(value); + } } - } - }); + }); - ArrayList<ILineDataSet> dataSets = new ArrayList<ILineDataSet>(); - dataSets.add(lineDataSet); + ArrayList<IScatterDataSet> dataSets = new ArrayList<IScatterDataSet>(); + dataSets.add(dataSet); - LineData lineData = new LineData(dataSets); + ScatterData lineData = new ScatterData(dataSets); + mChart.setData(lineData); + } else { + ((ScatterDataSet)mChart.getScatterData().getDataSets().get(0)).setValues(entries); + ((ScatterDataSet)mChart.getScatterData().getDataSets().get(0)).setColors(colors); + //dataSet.notifyDataSetChanged(); + } - // set data - mChart.setMinimumHeight(200); - mChart.setData(lineData); + //TODO: make the display timespan configurable mChart.getXAxis().setAxisMaximum(System.currentTimeMillis()); + mChart.getXAxis().setAxisMinimum(mChart.getXAxis().getAxisMaximum() - 24 * 60 * 60 * 1000); + + mChart.postInvalidate(); } } @@ -841,13 +899,13 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc } } - private class PumsStatusLineDataSet extends RealmLineDataSet<PumpStatusEvent> { + private class PumsStatusDataSet extends RealmScatterDataSet<PumpStatusEvent> { - public PumsStatusLineDataSet(RealmResults<PumpStatusEvent> result, String yValuesField) { + public PumsStatusDataSet(RealmResults<PumpStatusEvent> result, String yValuesField) { super(result, yValuesField); } - public PumsStatusLineDataSet(RealmResults<PumpStatusEvent> result, String xValuesField, String yValuesField) { + public PumsStatusDataSet(RealmResults<PumpStatusEvent> result, String xValuesField, String yValuesField) { super(result, xValuesField, yValuesField); } diff --git a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java index ba62b7d..60ad396 100644 --- a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java +++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java @@ -1,5 +1,7 @@ package info.nightscout.android.model.medtronicNg; +import com.github.mikephil.charting.interfaces.datasets.IScatterDataSet; + import java.util.Date; import io.realm.RealmObject; @@ -9,7 +11,7 @@ import io.realm.annotations.Index; /** * Created by lgoedhart on 4/06/2016. */ -public class PumpStatusEvent extends RealmObject { +public class PumpStatusEvent extends RealmObject { @Index private Date eventDate; // The actual time of the event (assume the capture device eventDate/time is accurate) private Date pumpDate; // The eventDate/time on the pump at the time of the event diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b4286d3..1360a2b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -119,7 +119,7 @@ </LinearLayout> - <com.github.mikephil.charting.charts.LineChart + <com.github.mikephil.charting.charts.ScatterChart android:id="@+id/chart" android:layout_width="match_parent" android:layout_height="wrap_content" -- GitLab