diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index 388d1b9a..d3c49a5d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -87,7 +87,6 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { }; private boolean mChartDirty = true; private AsyncTask refreshTask; - protected XIndexLabelFormatter xIndexFormatter = new XIndexLabelFormatter(); public boolean isChartDirty() { return mChartDirty; @@ -344,6 +343,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } protected void configureChartDefaults(Chart chart) { + chart.getXAxis().setValueFormatter(new TimestampValueFormatter()); chart.getDescription().setText(""); // if enabled, the chart will always start at zero on the y-axis @@ -355,7 +355,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { // enable touch gestures chart.setTouchEnabled(true); - chart.getXAxis().setValueFormatter(xIndexFormatter); + chart.getXAxis().setGranularity(60*5); setupLegend(chart); } @@ -408,13 +408,14 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { */ protected abstract void renderCharts(); - protected DefaultChartsData refresh(GBDevice gbDevice, List samples) { - Calendar cal = GregorianCalendar.getInstance(); - cal.clear(); - Date date; - String dateStringFrom = ""; - String dateStringTo = ""; - ArrayList xLabels = null; + protected DefaultChartsData refresh(GBDevice gbDevice, List samples) { +// Calendar cal = GregorianCalendar.getInstance(); +// cal.clear(); + int tsOffset = 0; +// Date date; +// String dateStringFrom = ""; +// String dateStringTo = ""; +// ArrayList xLabels = null; LOG.info("" + getTitle() + ": number of samples:" + samples.size()); CombinedData combinedData; @@ -424,11 +425,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { int last_type = ActivityKind.TYPE_UNKNOWN; - SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm"); - SimpleDateFormat annotationDateFormat = new SimpleDateFormat("HH:mm"); - int numEntries = samples.size(); - xLabels = new ArrayList<>(numEntries); List activityEntries = new ArrayList<>(numEntries); boolean hr = supportsHeartrate(gbDevice); List heartrateEntries = hr ? new ArrayList(numEntries) : null; @@ -438,18 +435,27 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { for (int i = 0; i < numEntries; i++) { ActivitySample sample = samples.get(i); int type = sample.getKind(); - - // determine start and end dates + int ts; if (i == 0) { - cal.setTimeInMillis(sample.getTimestamp() * 1000L); // make sure it's converted to long - date = cal.getTime(); - dateStringFrom = dateFormat.format(date); - } else if (i == samples.size() - 1) { - cal.setTimeInMillis(sample.getTimestamp() * 1000L); // same here - date = cal.getTime(); - dateStringTo = dateFormat.format(date); + tsOffset = sample.getTimestamp(); + ts = 0; + } else { + ts = sample.getTimestamp() - tsOffset; } +// System.out.println(ts); +// ts = i; + // determine start and end dates +// if (i == 0) { +// cal.setTimeInMillis(ts * 1000L); // make sure it's converted to long +// date = cal.getTime(); +// dateStringFrom = dateFormat.format(date); +// } else if (i == samples.size() - 1) { +// cal.setTimeInMillis(ts * 1000L); // same here +// date = cal.getTime(); +// dateStringTo = dateFormat.format(date); +// } + float movement = sample.getIntensity(); float value = movement; @@ -474,23 +480,23 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { // value = ((float) movement) / movement_divisor; colors.add(akActivity.color); } - activityEntries.add(createBarEntry(value, i)); + activityEntries.add(createBarEntry(value, ts)); if (hr && isValidHeartRateValue(sample.getHeartRate())) { - if (lastHrSampleIndex > -1 && i - lastHrSampleIndex > HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) { + if (lastHrSampleIndex > -1 && ts - lastHrSampleIndex > 60*HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) { heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1)); - heartrateEntries.add(createLineEntry(0, i - 1)); + heartrateEntries.add(createLineEntry(0, ts - 1)); } - heartrateEntries.add(createLineEntry(sample.getHeartRate(), i)); - lastHrSampleIndex = i; + heartrateEntries.add(createLineEntry(sample.getHeartRate(), ts)); + lastHrSampleIndex = ts; } String xLabel = ""; if (annotate) { - cal.setTimeInMillis(sample.getTimestamp() * 1000L); - date = cal.getTime(); - String dateString = annotationDateFormat.format(date); - xLabel = dateString; +// cal.setTimeInMillis((ts + tsOffset) * 1000L); +// date = cal.getTime(); +// String dateString = annotationDateFormat.format(date); +// xLabel = dateString; // if (last_type != type) { // if (isSleep(last_type) && !isSleep(type)) { // // woken up @@ -508,9 +514,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { // chart.getXAxis().addLimitLine(line); // } // } - last_type = type; +// last_type = type; } - xLabels.add(xLabel); } BarDataSet activitySet = createActivitySet(activityEntries, colors, "Activity"); @@ -520,6 +525,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { List list = new ArrayList<>(); list.add(activitySet); BarData barData = new BarData(list); + barData.setBarWidth(100f); // barData.setGroupSpace(0); combinedData.setData(barData); @@ -532,11 +538,11 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { // chart.setDescription(getString(R.string.sleep_activity_date_range, dateStringFrom, dateStringTo)); // chart.setDescriptionPosition(?, ?); } else { -// combinedData = new CombinedData(Collections.emptyList()); combinedData = new CombinedData(); } - return new DefaultChartsData(combinedData, xLabels); + IAxisValueFormatter xValueFormatter = new SampleXLabelFormatter(tsOffset); + return new DefaultChartsData(combinedData, xValueFormatter); } protected boolean isValidHeartRateValue(int value) { @@ -556,12 +562,12 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { protected abstract void setupLegend(Chart chart); - protected BarEntry createBarEntry(float value, int index) { - return new BarEntry(index, value); + protected BarEntry createBarEntry(float value, int xValue) { + return new BarEntry(xValue, value); } - protected Entry createLineEntry(float value, int index) { - return new Entry(index, value); + protected Entry createLineEntry(float value, int xValue) { + return new Entry(xValue, value); } protected BarDataSet createActivitySet(List values, List colors, String label) { @@ -702,7 +708,15 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } protected List getSamples(DBHandler db, GBDevice device) { - return getSamples(db, device, getTSStart(), getTSEnd()); + List samples = getSamples(db, device, getTSStart(), getTSEnd()); +// List samples2 = new ArrayList<>(); +// int min = Math.min(samples.size(), 10); +// int min = Math.min(samples.size(), 10); +// for (int i = 0; i < min; i++) { +// samples2.add(samples.get(i)); +// } +// return samples2; + return samples; } private int getTSEnd() { @@ -719,10 +733,15 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { public static class DefaultChartsData> extends ChartsData { private final T data; + private IAxisValueFormatter xValueFormatter; - public DefaultChartsData(T data, ArrayList xLabels) { + public DefaultChartsData(T data, IAxisValueFormatter xValueFormatter) { + this.xValueFormatter = xValueFormatter; this.data = data; - setxLabels(xLabels); + } + + public IAxisValueFormatter getXValueFormatter() { + return xValueFormatter; } public T getData() { @@ -730,14 +749,40 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } } - protected static class XIndexLabelFormatter implements IAxisValueFormatter { + protected static class SampleXLabelFormatter implements IAxisValueFormatter { + private final int tsOffset; + SimpleDateFormat annotationDateFormat = new SimpleDateFormat("HH:mm"); +// SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm"); + Calendar cal = GregorianCalendar.getInstance(); - private ArrayList xLabels; + public SampleXLabelFormatter(int tsOffset) { + this.tsOffset = tsOffset; - public void setxLabels(ArrayList xLabels) { - this.xLabels = xLabels; + } + // TODO: this does not work. Cannot use precomputed labels + @Override + public String getFormattedValue(float value, AxisBase axis) { + cal.clear(); + int ts = (int) value; + cal.setTimeInMillis((ts + tsOffset) * 1000L); + Date date = cal.getTime(); + String dateString = annotationDateFormat.format(date); + return dateString; } + @Override + public int getDecimalDigits() { + return 0; + } + } + + protected static class PreformattedXIndexLabelFormatter implements IAxisValueFormatter { + private ArrayList xLabels; + + public PreformattedXIndexLabelFormatter(ArrayList xLabels) { + this.xLabels = xLabels; + + } @Override public String getFormattedValue(float value, AxisBase axis) { int index = (int) value; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java index f9c9eb24..43be544f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java @@ -71,8 +71,8 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { y.setDrawGridLines(false); // y.setDrawLabels(false); // TODO: make fixed max value optional - y.setAxisMaxValue(1f); - y.setAxisMinValue(0); + y.setAxisMaximum(1f); + y.setAxisMinimum(0); y.setDrawTopYLabelEntry(false); y.setTextColor(CHART_TEXT_COLOR); @@ -85,8 +85,8 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setTextColor(CHART_TEXT_COLOR); - yAxisRight.setAxisMaxValue(HeartRateUtils.MAX_HEART_RATE_VALUE); - yAxisRight.setAxisMinValue(HeartRateUtils.MIN_HEART_RATE_VALUE); + yAxisRight.setAxisMaximum(HeartRateUtils.MAX_HEART_RATE_VALUE); + yAxisRight.setAxisMinimum(HeartRateUtils.MIN_HEART_RATE_VALUE); // refresh immediately instead of use refreshIfVisible(), for perceived performance refresh(); @@ -118,13 +118,14 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { DefaultChartsData dcd = (DefaultChartsData) chartsData; mChart.getLegend().setTextColor(LEGEND_TEXT_COLOR); mChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317 - xIndexFormatter.setxLabels(dcd.getXLabels()); + mChart.getXAxis().setValueFormatter(dcd.getXValueFormatter()); mChart.setData(dcd.getData()); } @Override protected void renderCharts() { mChart.animateX(ANIM_TIME, Easing.EasingOption.EaseInOutQuart); +// mChart.invalidate(); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java index ecdde59d..4285951f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java @@ -1,15 +1,4 @@ package nodomain.freeyourgadget.gadgetbridge.activities.charts; -import java.util.ArrayList; - public abstract class ChartsData { - private ArrayList xLabels; - - public void setxLabels(ArrayList xLabels) { - this.xLabels = xLabels; - } - - public ArrayList getXLabels() { - return xLabels; - } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java index 543ed42e..927dab5b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java @@ -1,5 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.activities.charts; +import android.content.res.Resources; import android.view.ViewGroup; import java.util.Date; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java index fcc5df35..d56bf81f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java @@ -69,6 +69,7 @@ public class LiveActivityFragment extends AbstractChartFragment { private List heartRateValues; private LineDataSet mHeartRateSet; private int mHeartRate; + private long tsOffset = -1; private class Steps { private int initialSteps; @@ -154,12 +155,14 @@ public class LiveActivityFragment extends AbstractChartFragment { case DeviceService.ACTION_REALTIME_STEPS: { int steps = intent.getIntExtra(DeviceService.EXTRA_REALTIME_STEPS, 0); long timestamp = intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); + timestamp = adjust(timestamp); addEntries(steps, timestamp); break; } case DeviceService.ACTION_HEARTRATE_MEASUREMENT: { int heartRate = intent.getIntExtra(DeviceService.EXTRA_HEART_RATE_VALUE, 0); long timestamp = intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); + timestamp = adjust(timestamp); if (isValidHeartRateValue(heartRate)) { setCurrentHeartRate(heartRate, timestamp); } @@ -169,6 +172,14 @@ public class LiveActivityFragment extends AbstractChartFragment { } }; + private long adjust(long timestamp) { + if (tsOffset == -1) { + tsOffset = timestamp; + return 0; + } + return timestamp - tsOffset; + } + private void setCurrentHeartRate(int heartRate, long timestamp) { addHistoryDataSet(true); mHeartRate = heartRate; @@ -214,12 +225,12 @@ public class LiveActivityFragment extends AbstractChartFragment { if (stepsPerMinute < 0) { stepsPerMinute = 0; } - mHistorySet.addEntry(new Entry(stepsPerMinute, timestamp)); + mHistorySet.addEntry(new Entry(timestamp, stepsPerMinute)); int hr = getCurrentHeartRate(); if (hr < 0) { hr = 0; } - mHeartRateSet.addEntry(new Entry(hr, timestamp)); + mHeartRateSet.addEntry(new Entry(timestamp, hr)); } private boolean addHistoryDataSet(boolean force) { @@ -251,8 +262,8 @@ public class LiveActivityFragment extends AbstractChartFragment { mTotalStepsChart = (CustomBarChart) rootView.findViewById(R.id.livechart_steps_total); mStepsPerMinuteHistoryChart = (BarLineChartBase) rootView.findViewById(R.id.livechart_steps_per_minute_history); - totalStepsEntry = new BarEntry(0, 1); - stepsPerMinuteEntry = new BarEntry(0, 1); + totalStepsEntry = new BarEntry(1, 0); + stepsPerMinuteEntry = new BarEntry(1, 0); mStepsPerMinuteData = setupCurrentChart(mStepsPerMinuteCurrentChart, stepsPerMinuteEntry, getString(R.string.live_activity_current_steps_per_minute)); mTotalStepsData = setupTotalStepsChart(mTotalStepsChart, totalStepsEntry, getString(R.string.live_activity_total_steps)); @@ -304,7 +315,7 @@ public class LiveActivityFragment extends AbstractChartFragment { * Called in the UI thread. */ private void pulse() { - addEntries(System.currentTimeMillis()); + addEntries(adjust(System.currentTimeMillis())); LineData historyData = (LineData) mStepsPerMinuteHistoryChart.getData(); if (historyData == null) { @@ -378,7 +389,7 @@ public class LiveActivityFragment extends AbstractChartFragment { entries.add(new BarEntry(0, 0)); entries.add(entry); - entries.add(new BarEntry(0, 2)); + entries.add(new BarEntry(2, 0)); colors.add(akActivity.color); colors.add(akActivity.color); colors.add(akActivity.color); @@ -400,7 +411,7 @@ public class LiveActivityFragment extends AbstractChartFragment { } private BarDataSet setupTotalStepsChart(CustomBarChart chart, BarEntry entry, String label) { - mTotalStepsChart.getAxisLeft().setAxisMaxValue(5000); // TODO: use daily goal - already reached steps + mTotalStepsChart.getAxisLeft().setAxisMaximum(5000); // TODO: use daily goal - already reached steps return setupCommonChart(chart, entry, label); // at the moment, these look the same } @@ -430,7 +441,7 @@ public class LiveActivityFragment extends AbstractChartFragment { y.setDrawTopYLabelEntry(false); y.setTextColor(CHART_TEXT_COLOR); y.setEnabled(true); - y.setAxisMinValue(0); + y.setAxisMinimum(0); YAxis yAxisRight = chart.getAxisRight(); yAxisRight.setDrawGridLines(false); @@ -438,8 +449,8 @@ public class LiveActivityFragment extends AbstractChartFragment { yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(false); yAxisRight.setTextColor(CHART_TEXT_COLOR); - yAxisRight.setAxisMaxValue(HeartRateUtils.MAX_HEART_RATE_VALUE); - yAxisRight.setAxisMinValue(HeartRateUtils.MIN_HEART_RATE_VALUE); + yAxisRight.setAxisMaximum(HeartRateUtils.MAX_HEART_RATE_VALUE); + yAxisRight.setAxisMinimum(HeartRateUtils.MIN_HEART_RATE_VALUE); mHistorySet = new LineDataSet(new ArrayList(), getString(R.string.live_activity_steps_history)); mHistorySet.setAxisDependency(YAxis.AxisDependency.LEFT); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java index 1fdfcd89..5df0d587 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java @@ -101,7 +101,7 @@ public class SleepChartFragment extends AbstractChartFragment { mSleepAmountChart.setData(mcd.getPieData().getPieData()); mActivityChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317 - xIndexFormatter.setxLabels(mcd.getChartsData().getXLabels()); + mActivityChart.getXAxis().setValueFormatter(mcd.getChartsData().getXValueFormatter()); mActivityChart.setData(mcd.getChartsData().getData()); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/TimestampValueFormatter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/TimestampValueFormatter.java new file mode 100644 index 00000000..0f4c592c --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/TimestampValueFormatter.java @@ -0,0 +1,40 @@ +package nodomain.freeyourgadget.gadgetbridge.activities.charts; + +import com.github.mikephil.charting.components.AxisBase; +import com.github.mikephil.charting.formatter.IAxisValueFormatter; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +public class TimestampValueFormatter implements IAxisValueFormatter { + private final Calendar cal; + // private DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm"); + private DateFormat dateFormat; + + public TimestampValueFormatter() { + this(new SimpleDateFormat("HH:mm")); + + } + + public TimestampValueFormatter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + cal = GregorianCalendar.getInstance(); + cal.clear(); + } + + @Override + public String getFormattedValue(float value, AxisBase axis) { + cal.setTimeInMillis((int) value * 1000L); + Date date = cal.getTime(); + String dateString = dateFormat.format(date); + return dateString; + } + + @Override + public int getDecimalDigits() { + return 0; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java index fdce0f75..e20c310d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java @@ -66,7 +66,7 @@ public class WeekStepsChartFragment extends AbstractChartFragment { mWeekStepsChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317 mWeekStepsChart.setData(mcd.getWeekBeforeStepsData().getData()); mWeekStepsChart.getLegend().setEnabled(false); - xIndexFormatter.setxLabels(mcd.getWeekBeforeStepsData().getXLabels()); + mWeekStepsChart.getXAxis().setValueFormatter(mcd.getWeekBeforeStepsData().getXValueFormatter()); } @Override @@ -75,7 +75,7 @@ public class WeekStepsChartFragment extends AbstractChartFragment { mTodayStepsChart.invalidate(); } - private DefaultChartsData refreshWeekBeforeSteps(DBHandler db, BarChart barChart, Calendar day, GBDevice device) { + private DefaultChartsData refreshWeekBeforeSteps(DBHandler db, BarChart barChart, Calendar day, GBDevice device) { ActivityAnalysis analysis = new ActivityAnalysis(); @@ -100,7 +100,7 @@ public class WeekStepsChartFragment extends AbstractChartFragment { barChart.getAxisLeft().removeAllLimitLines(); barChart.getAxisLeft().addLimitLine(target); - return new DefaultChartsData(barData, labels); + return new DefaultChartsData(barData, new PreformattedXIndexLabelFormatter(labels)); } @@ -184,7 +184,6 @@ public class WeekStepsChartFragment extends AbstractChartFragment { x.setEnabled(true); x.setTextColor(CHART_TEXT_COLOR); x.setDrawLimitLinesBehindData(true); - x.setValueFormatter(xIndexFormatter); x.setPosition(XAxis.XAxisPosition.BOTTOM); YAxis y = mWeekStepsChart.getAxisLeft();