mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-26 02:25:50 +01:00
Improved sleep chart #45
- use just one data set, because multiple data sets is not supported by MPAndroidChart (the way we need it) Now there is hardly any space between the bars anymore Also: - allow scaling x and y axis independently via pinch gesture - set fixed y max value (1.0) so that the display is stable and independent of the actual available data - (at least temporarily) display y labels
This commit is contained in:
parent
8709b95a95
commit
a5ae7acc63
@ -36,6 +36,18 @@ import nodomain.freeyourgadget.gadgetbridge.R;
|
|||||||
|
|
||||||
|
|
||||||
public class SleepChartActivity extends Activity {
|
public class SleepChartActivity extends Activity {
|
||||||
|
private static final class ActivityKind {
|
||||||
|
public final byte type;
|
||||||
|
public final String label;
|
||||||
|
public final Integer color;
|
||||||
|
|
||||||
|
public ActivityKind(byte type, String label, Integer color) {
|
||||||
|
this.type = type;
|
||||||
|
this.label = label;
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static final String ACTION_REFRESH
|
public static final String ACTION_REFRESH
|
||||||
= "nodomain.freeyourgadget.gadgetbride.chart.action.refresh";
|
= "nodomain.freeyourgadget.gadgetbride.chart.action.refresh";
|
||||||
protected static final Logger LOG = LoggerFactory.getLogger(SleepChartActivity.class);
|
protected static final Logger LOG = LoggerFactory.getLogger(SleepChartActivity.class);
|
||||||
@ -48,6 +60,10 @@ public class SleepChartActivity extends Activity {
|
|||||||
private int mSmartAlarmGoneOff = -1;
|
private int mSmartAlarmGoneOff = -1;
|
||||||
private GBDevice mGBDevice = null;
|
private GBDevice mGBDevice = null;
|
||||||
|
|
||||||
|
private ActivityKind akActivity = new ActivityKind(GBActivitySample.TYPE_UNKNOWN, "Activity", Color.rgb(89, 178, 44));
|
||||||
|
private ActivityKind akLightSleep = new ActivityKind(GBActivitySample.TYPE_LIGHT_SLEEP, "Light Sleep", Color.rgb(182, 191, 255));
|
||||||
|
private ActivityKind akDeepSleep = new ActivityKind(GBActivitySample.TYPE_DEEP_SLEEP, "Deep Sleep", Color.rgb(76, 90, 255));
|
||||||
|
|
||||||
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
@ -103,7 +119,7 @@ public class SleepChartActivity extends Activity {
|
|||||||
mChart.setScaleEnabled(true);
|
mChart.setScaleEnabled(true);
|
||||||
|
|
||||||
// if disabled, scaling can be done on x- and y-axis separately
|
// if disabled, scaling can be done on x- and y-axis separately
|
||||||
mChart.setPinchZoom(true);
|
// mChart.setPinchZoom(true);
|
||||||
|
|
||||||
mChart.setDrawGridBackground(false);
|
mChart.setDrawGridBackground(false);
|
||||||
|
|
||||||
@ -119,6 +135,8 @@ public class SleepChartActivity extends Activity {
|
|||||||
YAxis y = mChart.getAxisLeft();
|
YAxis y = mChart.getAxisLeft();
|
||||||
y.setDrawGridLines(false);
|
y.setDrawGridLines(false);
|
||||||
// y.setDrawLabels(false);
|
// y.setDrawLabels(false);
|
||||||
|
// TODO: make fixed max value optional
|
||||||
|
y.setAxisMaxValue(1f);
|
||||||
y.setDrawTopYLabelEntry(false);
|
y.setDrawTopYLabelEntry(false);
|
||||||
y.setTextColor(Color.WHITE);
|
y.setTextColor(Color.WHITE);
|
||||||
|
|
||||||
@ -224,9 +242,10 @@ public class SleepChartActivity extends Activity {
|
|||||||
|
|
||||||
int numEntries = samples.size();
|
int numEntries = samples.size();
|
||||||
List<String> xLabels = new ArrayList<>(numEntries);
|
List<String> xLabels = new ArrayList<>(numEntries);
|
||||||
List<BarEntry> deepSleepEntries = new ArrayList<>(numEntries / 4);
|
// List<BarEntry> deepSleepEntries = new ArrayList<>(numEntries / 4);
|
||||||
List<BarEntry> lightSleepEntries = new ArrayList<>(numEntries / 4);
|
// List<BarEntry> lightSleepEntries = new ArrayList<>(numEntries / 4);
|
||||||
List<BarEntry> activityEntries = new ArrayList<>(numEntries);
|
List<BarEntry> activityEntries = new ArrayList<>(numEntries);
|
||||||
|
List<Integer> colors = new ArrayList<>(numEntries); // this is kinda inefficient...
|
||||||
|
|
||||||
for (int i = 0; i < numEntries; i++) {
|
for (int i = 0; i < numEntries; i++) {
|
||||||
GBActivitySample sample = samples.get(i);
|
GBActivitySample sample = samples.get(i);
|
||||||
@ -250,15 +269,13 @@ public class SleepChartActivity extends Activity {
|
|||||||
float value;
|
float value;
|
||||||
if (type == GBActivitySample.TYPE_DEEP_SLEEP) {
|
if (type == GBActivitySample.TYPE_DEEP_SLEEP) {
|
||||||
value = 0.01f;
|
value = 0.01f;
|
||||||
deepSleepEntries.add(createEntry(value, i));
|
activityEntries.add(createEntry(value, i));
|
||||||
lightSleepEntries.add(emptyEntry);
|
colors.add(akDeepSleep.color);
|
||||||
activityEntries.add(emptyEntry);
|
|
||||||
} else {
|
} else {
|
||||||
if (type == GBActivitySample.TYPE_LIGHT_SLEEP) {
|
if (type == GBActivitySample.TYPE_LIGHT_SLEEP) {
|
||||||
value = ((float) movement / movement_divisor);
|
value = ((float) movement / movement_divisor);
|
||||||
lightSleepEntries.add(createEntry(value, i));
|
activityEntries.add(createEntry(value, i));
|
||||||
deepSleepEntries.add(emptyEntry);
|
colors.add(akLightSleep.color);
|
||||||
activityEntries.add(emptyEntry);
|
|
||||||
} else {
|
} else {
|
||||||
byte steps = sample.getSteps();
|
byte steps = sample.getSteps();
|
||||||
if (use_steps_as_movement && steps != 0) {
|
if (use_steps_as_movement && steps != 0) {
|
||||||
@ -267,8 +284,7 @@ public class SleepChartActivity extends Activity {
|
|||||||
}
|
}
|
||||||
value = ((float) movement / movement_divisor);
|
value = ((float) movement / movement_divisor);
|
||||||
activityEntries.add(createEntry(value, i));
|
activityEntries.add(createEntry(value, i));
|
||||||
lightSleepEntries.add(emptyEntry);
|
colors.add(akActivity.color);
|
||||||
deepSleepEntries.add(emptyEntry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,21 +309,25 @@ public class SleepChartActivity extends Activity {
|
|||||||
|
|
||||||
mChart.getXAxis().setValues(xLabels);
|
mChart.getXAxis().setValues(xLabels);
|
||||||
|
|
||||||
BarDataSet deepSleepSet = createDeepSleepSet(deepSleepEntries, "Deep Sleep");
|
// BarDataSet deepSleepSet = createDeepSleepSet(deepSleepEntries, "Deep Sleep");
|
||||||
BarDataSet lightSleepSet = createLightSleepSet(lightSleepEntries, "Light Sleep");
|
// BarDataSet lightSleepSet = createLightSleepSet(lightSleepEntries, "Light Sleep");
|
||||||
BarDataSet activitySet = createActivitySet(activityEntries, "Activity");
|
BarDataSet activitySet = createActivitySet(activityEntries, colors, "Activity");
|
||||||
|
|
||||||
ArrayList<BarDataSet> dataSets = new ArrayList<>();
|
ArrayList<BarDataSet> dataSets = new ArrayList<>();
|
||||||
dataSets.add(deepSleepSet);
|
// dataSets.add(deepSleepSet);
|
||||||
dataSets.add(lightSleepSet);
|
// dataSets.add(lightSleepSet);
|
||||||
dataSets.add(activitySet);
|
dataSets.add(activitySet);
|
||||||
|
|
||||||
// create a data object with the datasets
|
// create a data object with the datasets
|
||||||
BarData data = new BarData(xLabels, dataSets);
|
BarData data = new BarData(xLabels, dataSets);
|
||||||
|
data.setGroupSpace(0);
|
||||||
|
|
||||||
mChart.setDescription(getString(R.string.sleep_activity_date_range, dateStringFrom, dateStringTo));
|
mChart.setDescription(getString(R.string.sleep_activity_date_range, dateStringFrom, dateStringTo));
|
||||||
// mChart.setDescriptionPosition(?, ?);
|
// mChart.setDescriptionPosition(?, ?);
|
||||||
// set data
|
// set data
|
||||||
|
|
||||||
|
setupLegend(mChart);
|
||||||
|
|
||||||
mChart.setData(data);
|
mChart.setData(data);
|
||||||
|
|
||||||
mChart.animateX(1000, Easing.EasingOption.EaseInOutQuart);
|
mChart.animateX(1000, Easing.EasingOption.EaseInOutQuart);
|
||||||
@ -316,6 +336,19 @@ public class SleepChartActivity extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupLegend(BarLineChartBase chart) {
|
||||||
|
List<Integer> legendColors = new ArrayList<>(3);
|
||||||
|
List<String> legendLabels = new ArrayList<>(3);
|
||||||
|
legendColors.add(akActivity.color);
|
||||||
|
legendLabels.add(akActivity.label);
|
||||||
|
legendColors.add(akLightSleep.color);
|
||||||
|
legendLabels.add(akLightSleep.label);
|
||||||
|
legendColors.add(akDeepSleep.color);
|
||||||
|
legendLabels.add(akDeepSleep.label);
|
||||||
|
chart.getLegend().setColors(legendColors);
|
||||||
|
chart.getLegend().setLabels(legendLabels);
|
||||||
|
}
|
||||||
|
|
||||||
private BarEntry createEntry(float value, int index) {
|
private BarEntry createEntry(float value, int index) {
|
||||||
return new BarEntry(value, index);
|
return new BarEntry(value, index);
|
||||||
}
|
}
|
||||||
@ -330,8 +363,9 @@ public class SleepChartActivity extends Activity {
|
|||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BarDataSet createActivitySet(List<BarEntry> values, String label) {
|
private BarDataSet createActivitySet(List<BarEntry> values, List<Integer> colors, String label) {
|
||||||
BarDataSet set1 = new BarDataSet(values, label);
|
BarDataSet set1 = new BarDataSet(values, label);
|
||||||
|
set1.setColors(colors);
|
||||||
// set1.setDrawCubic(true);
|
// set1.setDrawCubic(true);
|
||||||
// set1.setCubicIntensity(0.2f);
|
// set1.setCubicIntensity(0.2f);
|
||||||
// //set1.setDrawFilled(true);
|
// //set1.setDrawFilled(true);
|
||||||
@ -341,7 +375,7 @@ public class SleepChartActivity extends Activity {
|
|||||||
// set1.setFillColor(ColorTemplate.getHoloBlue());
|
// set1.setFillColor(ColorTemplate.getHoloBlue());
|
||||||
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));
|
||||||
set1.setValueTextColor(Color.WHITE);
|
set1.setValueTextColor(Color.WHITE);
|
||||||
return set1;
|
return set1;
|
||||||
}
|
}
|
||||||
@ -357,7 +391,7 @@ public class SleepChartActivity extends Activity {
|
|||||||
// set1.setFillColor(ColorTemplate.getHoloBlue());
|
// set1.setFillColor(ColorTemplate.getHoloBlue());
|
||||||
set1.setDrawValues(false);
|
set1.setDrawValues(false);
|
||||||
// set1.setHighLightColor(Color.rgb(244, 117, 117));
|
// set1.setHighLightColor(Color.rgb(244, 117, 117));
|
||||||
set1.setColor(Color.rgb(76, 90, 255));
|
// set1.setColor(Color.rgb(76, 90, 255));
|
||||||
set1.setValueTextColor(Color.WHITE);
|
set1.setValueTextColor(Color.WHITE);
|
||||||
return set1;
|
return set1;
|
||||||
}
|
}
|
||||||
@ -374,7 +408,7 @@ public class SleepChartActivity extends Activity {
|
|||||||
// set1.setFillColor(ColorTemplate.getHoloBlue());
|
// set1.setFillColor(ColorTemplate.getHoloBlue());
|
||||||
set1.setDrawValues(false);
|
set1.setDrawValues(false);
|
||||||
// set1.setHighLightColor(Color.rgb(244, 117, 117));
|
// set1.setHighLightColor(Color.rgb(244, 117, 117));
|
||||||
set1.setColor(Color.rgb(182, 191, 255));
|
// set1.setColor(Color.rgb(182, 191, 255));
|
||||||
set1.setValueTextColor(Color.WHITE);
|
set1.setValueTextColor(Color.WHITE);
|
||||||
// set1.setColor(Color.CYAN);
|
// set1.setColor(Color.CYAN);
|
||||||
return set1;
|
return set1;
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.charts;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import com.github.mikephil.charting.charts.BarChart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A BarChart with some specific customization, like
|
||||||
|
* <li>using a custom legend renderer that always uses fixed labels and colors</li>
|
||||||
|
*/
|
||||||
|
public class CustomBarChart extends BarChart {
|
||||||
|
|
||||||
|
public CustomBarChart(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomBarChart(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomBarChart(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
super.init();
|
||||||
|
mLegendRenderer = new CustomLegendRenderer(getViewPortHandler(), getLegend());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.charts;
|
||||||
|
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
|
||||||
|
import com.github.mikephil.charting.components.Legend;
|
||||||
|
import com.github.mikephil.charting.data.ChartData;
|
||||||
|
import com.github.mikephil.charting.renderer.LegendRenderer;
|
||||||
|
import com.github.mikephil.charting.utils.ViewPortHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A legend renderer that does *not* calculate the labels and colors automatically
|
||||||
|
* from the data sets or the data entries.
|
||||||
|
*
|
||||||
|
* Instead, they have to be provided manually, because otherwise the legend will
|
||||||
|
* be empty.
|
||||||
|
*/
|
||||||
|
public class CustomLegendRenderer extends LegendRenderer {
|
||||||
|
public CustomLegendRenderer(ViewPortHandler viewPortHandler, Legend legend) {
|
||||||
|
super(viewPortHandler, legend);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void computeLegend(ChartData<?> data) {
|
||||||
|
// don't call super to avoid computing colors and labels
|
||||||
|
// super.computeLegend(data);
|
||||||
|
|
||||||
|
Typeface tf = mLegend.getTypeface();
|
||||||
|
|
||||||
|
if (tf != null)
|
||||||
|
mLegendLabelPaint.setTypeface(tf);
|
||||||
|
|
||||||
|
mLegendLabelPaint.setTextSize(mLegend.getTextSize());
|
||||||
|
mLegendLabelPaint.setColor(mLegend.getTextColor());
|
||||||
|
|
||||||
|
// calculate all dimensions of the mLegend
|
||||||
|
mLegend.calculateDimensions(mLegendLabelPaint);
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<com.github.mikephil.charting.charts.BarChart
|
<nodomain.freeyourgadget.gadgetbridge.charts.CustomBarChart
|
||||||
android:id="@+id/sleepchart2"
|
android:id="@+id/sleepchart2"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
Loading…
Reference in New Issue
Block a user