1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-07-07 14:11:36 +02:00

Replace the Combined Charts with simple Line Charts

Fixes #808
The datasets had to be separed in order to fill the area below each line with the right color.
This commit is contained in:
Daniele Gobbetti 2017-11-01 17:34:46 +01:00
parent 8f8b6bdf46
commit e7839f1c39
8 changed files with 80 additions and 91 deletions

View File

@ -1,7 +1,7 @@
### Changelog ### Changelog
#### Version NEXT #### Version NEXT
* Charts: added preference to disable swiping charts left/right * Charts: added preference to disable swiping charts left/right and some UI changes
#### Version 0.22.1 #### Version 0.22.1
* Mi Band 2: Fix being detected as Amazfit Bip which lead to various problems especially on newly paired devices * Mi Band 2: Fix being detected as Amazfit Bip which lead to various problems especially on newly paired devices

View File

@ -35,16 +35,12 @@ import com.github.mikephil.charting.charts.BarLineChartBase;
import com.github.mikephil.charting.charts.Chart; import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.components.AxisBase; import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.ChartData; import com.github.mikephil.charting.data.ChartData;
import com.github.mikephil.charting.data.CombinedData;
import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet; import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.IAxisValueFormatter; import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -419,7 +415,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
*/ */
protected abstract void renderCharts(); protected abstract void renderCharts();
protected DefaultChartsData<CombinedData> refresh(GBDevice gbDevice, List<? extends ActivitySample> samples) { protected DefaultChartsData<LineData> refresh(GBDevice gbDevice, List<? extends ActivitySample> samples) {
// Calendar cal = GregorianCalendar.getInstance(); // Calendar cal = GregorianCalendar.getInstance();
// cal.clear(); // cal.clear();
TimestampTranslation tsTranslation = new TimestampTranslation(); TimestampTranslation tsTranslation = new TimestampTranslation();
@ -429,7 +425,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
// ArrayList<String> xLabels = null; // ArrayList<String> xLabels = null;
LOG.info("" + getTitle() + ": number of samples:" + samples.size()); LOG.info("" + getTitle() + ": number of samples:" + samples.size());
CombinedData combinedData; LineData lineData;
if (samples.size() > 1) { if (samples.size() > 1) {
boolean annotate = true; boolean annotate = true;
boolean use_steps_as_movement; boolean use_steps_as_movement;
@ -437,10 +433,12 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
int last_type = ActivityKind.TYPE_UNKNOWN; int last_type = ActivityKind.TYPE_UNKNOWN;
int numEntries = samples.size(); int numEntries = samples.size();
List<BarEntry> activityEntries = new ArrayList<>(numEntries); List<Entry> activityEntries = new ArrayList<>(numEntries);
List<Entry> deepSleepEntries = new ArrayList<>(numEntries);
List<Entry> lightSleepEntries = new ArrayList<>(numEntries);
List<Entry> notWornEntries = new ArrayList<>(numEntries);
boolean hr = supportsHeartrate(gbDevice); boolean hr = supportsHeartrate(gbDevice);
List<Entry> heartrateEntries = hr ? new ArrayList<Entry>(numEntries) : null; List<Entry> heartrateEntries = hr ? new ArrayList<Entry>(numEntries) : null;
List<Integer> colors = new ArrayList<>(numEntries); // this is kinda inefficient...
int lastHrSampleIndex = -1; int lastHrSampleIndex = -1;
for (int i = 0; i < numEntries; i++) { for (int i = 0; i < numEntries; i++) {
@ -466,15 +464,34 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
float value = movement; float value = movement;
switch (type) { switch (type) {
case ActivityKind.TYPE_DEEP_SLEEP: case ActivityKind.TYPE_DEEP_SLEEP:
value += SleepUtils.Y_VALUE_DEEP_SLEEP; if (last_type != type) { //FIXME: this is ugly but it works (repeated in each case)
colors.add(akDeepSleep.color); deepSleepEntries.add(createLineEntry(0, ts - 1));
lightSleepEntries.add(createLineEntry(0, ts));
notWornEntries.add(createLineEntry(0, ts));
activityEntries.add(createLineEntry(0, ts));
}
deepSleepEntries.add(createLineEntry(value + SleepUtils.Y_VALUE_DEEP_SLEEP, ts));
break; break;
case ActivityKind.TYPE_LIGHT_SLEEP: case ActivityKind.TYPE_LIGHT_SLEEP:
colors.add(akLightSleep.color); if (last_type != type) {
lightSleepEntries.add(createLineEntry(0, ts - 1));
deepSleepEntries.add(createLineEntry(0, ts));
notWornEntries.add(createLineEntry(0, ts));
activityEntries.add(createLineEntry(0, ts));
}
lightSleepEntries.add(createLineEntry(value, ts));
break; break;
case ActivityKind.TYPE_NOT_WORN: case ActivityKind.TYPE_NOT_WORN:
value = SleepUtils.Y_VALUE_DEEP_SLEEP; //a small value, just to show something on the graphs if (last_type != type) {
colors.add(akNotWorn.color); notWornEntries.add(createLineEntry(0, ts - 1));
lightSleepEntries.add(createLineEntry(0, ts));
deepSleepEntries.add(createLineEntry(0, ts));
activityEntries.add(createLineEntry(0, ts));
}
notWornEntries.add(createLineEntry(SleepUtils.Y_VALUE_DEEP_SLEEP, ts)); //a small value, just to show something on the graphs
break; break;
default: default:
// short steps = sample.getSteps(); // short steps = sample.getSteps();
@ -483,9 +500,15 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
// movement = steps; // movement = steps;
// } // }
// value = ((float) movement) / movement_divisor; // value = ((float) movement) / movement_divisor;
colors.add(akActivity.color); if (last_type != type) {
activityEntries.add(createLineEntry(0, ts - 1));
lightSleepEntries.add(createLineEntry(0, ts));
notWornEntries.add(createLineEntry(0, ts));
deepSleepEntries.add(createLineEntry(0, ts));
}
activityEntries.add(createLineEntry(value, ts));
} }
activityEntries.add(createBarEntry(value, ts));
if (hr && isValidHeartRateValue(sample.getHeartRate())) { if (hr && isValidHeartRateValue(sample.getHeartRate())) {
if (lastHrSampleIndex > -1 && ts - lastHrSampleIndex > 1800*HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) { if (lastHrSampleIndex > -1 && ts - lastHrSampleIndex > 1800*HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) {
heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1)); heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1));
@ -519,35 +542,36 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
// chart.getXAxis().addLimitLine(line); // chart.getXAxis().addLimitLine(line);
// } // }
// } // }
// last_type = type;
} }
last_type = type;
} }
BarDataSet activitySet = createActivitySet(activityEntries, colors, "Activity");
// create a data object with the datasets List<ILineDataSet> lineDataSets = new ArrayList<>();
// combinedData = new CombinedData(xLabels); LineDataSet activitySet = createDataSet(activityEntries, akActivity.color, "Activity");
combinedData = new CombinedData(); lineDataSets.add(activitySet);
List<IBarDataSet> list = new ArrayList<>(); LineDataSet deepSleepSet = createDataSet(deepSleepEntries, akDeepSleep.color, "Deep Sleep");
list.add(activitySet); lineDataSets.add(deepSleepSet);
BarData barData = new BarData(list); LineDataSet lightSleepSet = createDataSet(lightSleepEntries, akLightSleep.color, "Light Sleep");
barData.setBarWidth(200f); lineDataSets.add(lightSleepSet);
// barData.setGroupSpace(0); LineDataSet notWornSet = createDataSet(notWornEntries, akNotWorn.color, "Not worn");
combinedData.setData(barData); lineDataSets.add(notWornSet);
if (hr && heartrateEntries.size() > 0) { if (hr && heartrateEntries.size() > 0) {
LineDataSet heartrateSet = createHeartrateSet(heartrateEntries, "Heart Rate"); LineDataSet heartrateSet = createHeartrateSet(heartrateEntries, "Heart Rate");
LineData lineData = new LineData(heartrateSet);
combinedData.setData(lineData); lineDataSets.add(heartrateSet);
} }
lineData = new LineData(lineDataSets);
// chart.setDescription(getString(R.string.sleep_activity_date_range, dateStringFrom, dateStringTo)); // chart.setDescription(getString(R.string.sleep_activity_date_range, dateStringFrom, dateStringTo));
// chart.setDescriptionPosition(?, ?); // chart.setDescriptionPosition(?, ?);
} else { } else {
combinedData = new CombinedData(); lineData = new LineData();
} }
IAxisValueFormatter xValueFormatter = new SampleXLabelFormatter(tsTranslation); IAxisValueFormatter xValueFormatter = new SampleXLabelFormatter(tsTranslation);
return new DefaultChartsData(combinedData, xValueFormatter); return new DefaultChartsData(lineData, xValueFormatter);
} }
protected boolean isValidHeartRateValue(int value) { protected boolean isValidHeartRateValue(int value) {
@ -567,24 +591,21 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
protected abstract void setupLegend(Chart chart); protected abstract void setupLegend(Chart chart);
protected BarEntry createBarEntry(float value, int xValue) {
return new BarEntry(xValue, value);
}
protected Entry createLineEntry(float value, int xValue) { protected Entry createLineEntry(float value, int xValue) {
return new Entry(xValue, value); return new Entry(xValue, value);
} }
protected BarDataSet createActivitySet(List<BarEntry> values, List<Integer> colors, String label) { protected LineDataSet createDataSet(List<Entry> values, Integer color, String label) {
BarDataSet set1 = new BarDataSet(values, label); LineDataSet set1 = new LineDataSet(values, label);
set1.setColors(colors); set1.setColor(color);
// set1.setDrawCubic(true); // set1.setDrawCubic(true);
// set1.setCubicIntensity(0.2f); // set1.setCubicIntensity(0.2f);
// //set1.setDrawFilled(true); set1.setDrawFilled(true);
// set1.setDrawCircles(false); set1.setDrawCircles(false);
// set1.setLineWidth(2f); // set1.setLineWidth(2f);
// set1.setCircleSize(5f); // set1.setCircleSize(5f);
// set1.setFillColor(ColorTemplate.getHoloBlue()); set1.setFillColor(color);
set1.setFillAlpha(255);
set1.setDrawValues(false); set1.setDrawValues(false);
// set1.setHighLightColor(Color.rgb(128, 0, 255)); // set1.setHighLightColor(Color.rgb(128, 0, 255));
// set1.setColor(Color.rgb(89, 178, 44)); // set1.setColor(Color.rgb(89, 178, 44));
@ -614,40 +635,6 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
return set1; return set1;
} }
protected BarDataSet createDeepSleepSet(List<BarEntry> values, String label) {
BarDataSet set1 = new BarDataSet(values, label);
// set1.setDrawCubic(true);
// set1.setCubicIntensity(0.2f);
// //set1.setDrawFilled(true);
// set1.setDrawCircles(false);
// set1.setLineWidth(2f);
// set1.setCircleSize(5f);
// set1.setFillColor(ColorTemplate.getHoloBlue());
set1.setDrawValues(false);
// set1.setHighLightColor(Color.rgb(244, 117, 117));
// set1.setColor(Color.rgb(76, 90, 255));
set1.setValueTextColor(CHART_TEXT_COLOR);
return set1;
}
protected BarDataSet createLightSleepSet(List<BarEntry> values, String label) {
BarDataSet set1 = new BarDataSet(values, label);
// set1.setDrawCubic(true);
// set1.setCubicIntensity(0.2f);
// //set1.setDrawFilled(true);
// set1.setDrawCircles(false);
// set1.setLineWidth(2f);
// set1.setCircleSize(5f);
// set1.setFillColor(ColorTemplate.getHoloBlue());
set1.setDrawValues(false);
// set1.setHighLightColor(Color.rgb(244, 117, 117));
// set1.setColor(Color.rgb(182, 191, 255));
set1.setValueTextColor(CHART_TEXT_COLOR);
// set1.setColor(Color.CYAN);
return set1;
}
protected RefreshTask createRefreshTask(String task, Context context) { protected RefreshTask createRefreshTask(String task, Context context) {
return new RefreshTask(task, context); return new RefreshTask(task, context);
} }

View File

@ -25,11 +25,12 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.github.mikephil.charting.animation.Easing; import com.github.mikephil.charting.animation.Easing;
import com.github.mikephil.charting.charts.BarLineChartBase;
import com.github.mikephil.charting.charts.Chart; import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.LegendEntry; import com.github.mikephil.charting.components.LegendEntry;
import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.LineData;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -47,7 +48,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
public class ActivitySleepChartFragment extends AbstractChartFragment { public class ActivitySleepChartFragment extends AbstractChartFragment {
protected static final Logger LOG = LoggerFactory.getLogger(ActivitySleepChartFragment.class); protected static final Logger LOG = LoggerFactory.getLogger(ActivitySleepChartFragment.class);
private BarLineChartBase mChart; private LineChart mChart;
private int mSmartAlarmFrom = -1; private int mSmartAlarmFrom = -1;
private int mSmartAlarmTo = -1; private int mSmartAlarmTo = -1;
@ -59,7 +60,7 @@ public class ActivitySleepChartFragment extends AbstractChartFragment {
Bundle savedInstanceState) { Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_charts, container, false); View rootView = inflater.inflate(R.layout.fragment_charts, container, false);
mChart = (BarLineChartBase) rootView.findViewById(R.id.activitysleepchart); mChart = (LineChart) rootView.findViewById(R.id.activitysleepchart);
setupChart(); setupChart();
@ -136,7 +137,7 @@ public class ActivitySleepChartFragment extends AbstractChartFragment {
mChart.getLegend().setTextColor(LEGEND_TEXT_COLOR); mChart.getLegend().setTextColor(LEGEND_TEXT_COLOR);
mChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317 mChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317
mChart.getXAxis().setValueFormatter(dcd.getXValueFormatter()); mChart.getXAxis().setValueFormatter(dcd.getXValueFormatter());
mChart.setData(dcd.getData()); mChart.setData((LineData) dcd.getData());
} }
@Override @Override

View File

@ -26,13 +26,13 @@ import android.view.ViewGroup;
import com.github.mikephil.charting.animation.Easing; import com.github.mikephil.charting.animation.Easing;
import com.github.mikephil.charting.charts.Chart; import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.CombinedChart; import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.charts.PieChart; import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.LegendEntry; import com.github.mikephil.charting.components.LegendEntry;
import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.CombinedData;
import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.PieData; import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet; import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry; import com.github.mikephil.charting.data.PieEntry;
@ -60,7 +60,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
public class SleepChartFragment extends AbstractChartFragment { public class SleepChartFragment extends AbstractChartFragment {
protected static final Logger LOG = LoggerFactory.getLogger(ActivitySleepChartFragment.class); protected static final Logger LOG = LoggerFactory.getLogger(ActivitySleepChartFragment.class);
private CombinedChart mActivityChart; private LineChart mActivityChart;
private PieChart mSleepAmountChart; private PieChart mSleepAmountChart;
private int mSmartAlarmFrom = -1; private int mSmartAlarmFrom = -1;
@ -136,7 +136,7 @@ public class SleepChartFragment extends AbstractChartFragment {
Bundle savedInstanceState) { Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_sleepchart, container, false); View rootView = inflater.inflate(R.layout.fragment_sleepchart, container, false);
mActivityChart = (CombinedChart) rootView.findViewById(R.id.sleepchart); mActivityChart = (LineChart) rootView.findViewById(R.id.sleepchart);
mSleepAmountChart = (PieChart) rootView.findViewById(R.id.sleepchart_pie_light_deep); mSleepAmountChart = (PieChart) rootView.findViewById(R.id.sleepchart_pie_light_deep);
setupActivityChart(); setupActivityChart();
@ -262,10 +262,10 @@ public class SleepChartFragment extends AbstractChartFragment {
} }
private static class MyChartsData extends ChartsData { private static class MyChartsData extends ChartsData {
private final DefaultChartsData<CombinedData> chartsData; private final DefaultChartsData<LineData> chartsData;
private final MySleepChartsData pieData; private final MySleepChartsData pieData;
public MyChartsData(MySleepChartsData pieData, DefaultChartsData<CombinedData> chartsData) { public MyChartsData(MySleepChartsData pieData, DefaultChartsData<LineData> chartsData) {
this.pieData = pieData; this.pieData = pieData;
this.chartsData = chartsData; this.chartsData = chartsData;
} }
@ -274,7 +274,7 @@ public class SleepChartFragment extends AbstractChartFragment {
return pieData; return pieData;
} }
public DefaultChartsData<CombinedData> getChartsData() { public DefaultChartsData<LineData> getChartsData() {
return chartsData; return chartsData;
} }
} }

View File

@ -11,7 +11,7 @@
android:layout_weight="40"> android:layout_weight="40">
</com.github.mikephil.charting.charts.PieChart> </com.github.mikephil.charting.charts.PieChart>
<com.github.mikephil.charting.charts.CombinedChart <com.github.mikephil.charting.charts.LineChart
android:id="@+id/sleepchart" android:id="@+id/sleepchart"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"

View File

@ -4,7 +4,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment"> tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment">
<com.github.mikephil.charting.charts.CombinedChart <com.github.mikephil.charting.charts.LineChart
android:id="@+id/activitysleepchart" android:id="@+id/activitysleepchart"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View File

@ -11,7 +11,7 @@
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_weight="20"></com.github.mikephil.charting.charts.PieChart> android:layout_weight="20"></com.github.mikephil.charting.charts.PieChart>
<com.github.mikephil.charting.charts.CombinedChart <com.github.mikephil.charting.charts.LineChart
android:id="@+id/sleepchart" android:id="@+id/sleepchart"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<changelog> <changelog>
<release version="next"> <release version="next">
<change>Charts: added preference to disable swiping charts left/right</change> <change>Charts: added preference to disable swiping charts left/right and some UI changes
</change>
</release> </release>
<release version="0.22.1" versioncode="109"> <release version="0.22.1" versioncode="109">
<change>Mi Band 2: Fix being detected as Amazfit Bip which lead to various problems especially on newly paired devices</change> <change>Mi Band 2: Fix being detected as Amazfit Bip which lead to various problems especially on newly paired devices</change>