From 8e3f010629d6994398cc588453e0247411928741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Tue, 27 Aug 2024 19:38:10 +0100 Subject: [PATCH] Add daily steps progress chart --- .../activities/charts/StepsDailyFragment.java | 136 +++++++++++++++++- .../activities/charts/StepsFragment.java | 30 +--- .../charts/StepsPeriodFragment.java | 38 ++++- app/src/main/res/layout/fragment_steps.xml | 17 +-- 4 files changed, 174 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsDailyFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsDailyFragment.java index 8c4326ad9..5e7526893 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsDailyFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsDailyFragment.java @@ -2,6 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities.charts; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.os.Build; import android.os.Bundle; @@ -16,21 +17,36 @@ import androidx.annotation.ColorInt; import androidx.fragment.app.FragmentManager; 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.LimitLine; +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.LineDataSet; +import com.github.mikephil.charting.formatter.ValueFormatter; +import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; import java.util.List; +import java.util.Locale; +import java.util.TimeZone; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; -public class StepsDailyFragment extends StepsFragment { +public class StepsDailyFragment extends StepsFragment { protected static final Logger LOG = LoggerFactory.getLogger(BodyEnergyFragment.class); private TextView mDateView; @@ -38,10 +54,9 @@ public class StepsDailyFragment extends StepsFragment { private TextView steps; private TextView distance; ImageView stepsStreaksButton; + private LineChart stepsChart; protected int STEPS_GOAL; - protected int TOTAL_DAYS = 1; - @Override public void onResume() { @@ -62,6 +77,9 @@ public class StepsDailyFragment extends StepsFragment { stepsGauge = rootView.findViewById(R.id.steps_gauge); steps = rootView.findViewById(R.id.steps_count); distance = rootView.findViewById(R.id.steps_distance); + stepsChart = rootView.findViewById(R.id.steps_daily_chart); + setupStepsChart(); + STEPS_GOAL = GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_STEPS_GOAL, ActivityUser.defaultUserStepsGoal); refresh(); @@ -89,8 +107,16 @@ public class StepsDailyFragment extends StepsFragment { day.setTime(chartsHost.getEndDate()); String formattedDate = new SimpleDateFormat("E, MMM dd").format(chartsHost.getEndDate()); mDateView.setText(formattedDate); - List stepsDaysData = getMyStepsDaysData(db, day, device); - return new StepsDailyFragment.StepsData(stepsDaysData); + List stepsDayList = getMyStepsDaysData(db, day, device); + final StepsDay stepsDay; + if (stepsDayList.isEmpty()) { + LOG.error("Failed to get StepsDay for {}", day); + stepsDay = new StepsDay(day, 0, 0); + } else { + stepsDay = stepsDayList.get(0); + } + List samplesOfDay = getSamplesOfDay(db, day, 0, device); + return new StepsDailyFragment.StepsData(stepsDay, samplesOfDay); } @Override @@ -111,13 +137,101 @@ public class StepsDailyFragment extends StepsFragment { steps.setText(String.format(String.valueOf(stepsData.todayStepsDay.steps))); distance.setText(getString(R.string.steps_distance_unit, stepsData.todayStepsDay.distance)); + + // Chart + final List legendEntries = new ArrayList<>(1); + final LegendEntry stepsEntry = new LegendEntry(); + stepsEntry.label = getString(R.string.steps); + stepsEntry.formColor = getResources().getColor(R.color.steps_color); + legendEntries.add(stepsEntry); + final LegendEntry goalEntry = new LegendEntry(); + goalEntry.label = getString(R.string.miband_prefs_fitness_goal); + goalEntry.formColor = Color.GRAY; + legendEntries.add(goalEntry); + stepsChart.getLegend().setTextColor(TEXT_COLOR); + stepsChart.getLegend().setCustom(legendEntries); + + final List lineEntries = new ArrayList<>(); + final TimestampTranslation tsTranslation = new TimestampTranslation(); + int sum = 0; + for (final ActivitySample sample : stepsData.samples) { + if (sample.getSteps() > 0) { + sum += sample.getSteps(); + } + lineEntries.add(new Entry(tsTranslation.shorten(sample.getTimestamp()), sum)); + } + + stepsChart.getXAxis().setValueFormatter(new SampleXLabelFormatter(tsTranslation)); + + if (sum < STEPS_GOAL) { + stepsChart.getAxisLeft().setAxisMaximum(STEPS_GOAL); + } else { + stepsChart.getAxisLeft().resetAxisMaximum(); + } + + final LineDataSet lineDataSet = new LineDataSet(lineEntries, getString(R.string.steps)); + lineDataSet.setColor(getResources().getColor(R.color.steps_color)); + lineDataSet.setDrawCircles(false); + lineDataSet.setLineWidth(2f); + lineDataSet.setFillAlpha(255); + lineDataSet.setDrawCircles(false); + lineDataSet.setCircleColor(getResources().getColor(R.color.steps_color)); + lineDataSet.setAxisDependency(YAxis.AxisDependency.LEFT); + lineDataSet.setDrawValues(false); + lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER); + lineDataSet.setDrawFilled(true); + lineDataSet.setFillAlpha(60); + lineDataSet.setFillColor(getResources().getColor(R.color.steps_color )); + + final LimitLine goalLine = new LimitLine(STEPS_GOAL); + goalLine.setLineColor(Color.GRAY); + goalLine.setLineWidth(1.5f); + goalLine.enableDashedLine(10f, 10f, 0f); + stepsChart.getAxisLeft().removeAllLimitLines(); + stepsChart.getAxisLeft().addLimitLine(goalLine); + + final List lineDataSets = new ArrayList<>(); + lineDataSets.add(lineDataSet); + final LineData lineData = new LineData(lineDataSets); + stepsChart.setData(lineData); } @Override - protected void renderCharts() {} + protected void renderCharts() { + stepsChart.invalidate(); + } protected void setupLegend(Chart chart) {} + private void setupStepsChart() { + stepsChart.getDescription().setEnabled(false); + stepsChart.setDoubleTapToZoomEnabled(false); + + final XAxis xAxisBottom = stepsChart.getXAxis(); + xAxisBottom.setPosition(XAxis.XAxisPosition.BOTTOM); + xAxisBottom.setDrawLabels(true); + xAxisBottom.setDrawGridLines(false); + xAxisBottom.setEnabled(true); + xAxisBottom.setDrawLimitLinesBehindData(true); + xAxisBottom.setTextColor(CHART_TEXT_COLOR); + xAxisBottom.setAxisMinimum(0f); + xAxisBottom.setAxisMaximum(86400f); + //xAxisBottom.setLabelCount(7, true); + + final YAxis yAxisLeft = stepsChart.getAxisLeft(); + yAxisLeft.setDrawGridLines(true); + yAxisLeft.setAxisMinimum(0); + yAxisLeft.setDrawTopYLabelEntry(true); + yAxisLeft.setEnabled(true); + yAxisLeft.setTextColor(CHART_TEXT_COLOR); + + final YAxis yAxisRight = stepsChart.getAxisRight(); + yAxisRight.setEnabled(true); + yAxisRight.setDrawLabels(false); + yAxisRight.setDrawGridLines(false); + yAxisRight.setDrawAxisLine(true); + } + Bitmap drawGauge(int width, int barWidth, @ColorInt int filledColor, int value, int maxValue) { int height = width; int barMargin = (int) Math.ceil(barWidth / 2f); @@ -170,4 +284,14 @@ public class StepsDailyFragment extends StepsFragment { return bitmap; } + + protected static class StepsData extends ChartsData { + StepsDay todayStepsDay; + List samples; + + public StepsData(final StepsDay todayStepsDay, final List samplesOfDay) { + this.todayStepsDay = todayStepsDay; + this.samples = samplesOfDay; + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsFragment.java index 322d1e501..bc73a8e38 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsFragment.java @@ -1,7 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.activities.charts; import android.app.Activity; -import android.os.Bundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +20,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue; -abstract class StepsFragment extends AbstractChartFragment { +abstract class StepsFragment extends AbstractChartFragment { protected static final Logger LOG = LoggerFactory.getLogger(StepsDailyFragment.class); protected int CHART_TEXT_COLOR; @@ -93,7 +92,7 @@ abstract class StepsFragment extends AbstractChartFragment getSamplesOfDay(DBHandler db, Calendar day, int offsetHours, GBDevice device) { + protected List getSamplesOfDay(DBHandler db, Calendar day, int offsetHours, GBDevice device) { int startTs; int endTs; @@ -126,28 +125,5 @@ abstract class StepsFragment extends AbstractChartFragment days; - long stepsDailyAvg = 0; - double distanceDailyAvg = 0; - long totalSteps = 0; - double totalDistance = 0; - StepsDay todayStepsDay; - protected StepsData(List days) { - this.days = days; - int daysCounter = 0; - for(StepsDay day : days) { - this.totalSteps += day.steps; - this.totalDistance += day.distance; - if (day.steps > 0) { - daysCounter++; - } - } - if (daysCounter > 0) { - this.stepsDailyAvg = this.totalSteps / daysCounter; - this.distanceDailyAvg = this.totalDistance / daysCounter; - } - this.todayStepsDay = days.get(days.size() - 1); - } - } + } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsPeriodFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsPeriodFragment.java index e79c25469..d5c54d8ff 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsPeriodFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsPeriodFragment.java @@ -34,9 +34,8 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; -import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.DayStartHourSetting; -public class StepsPeriodFragment extends StepsFragment { +public class StepsPeriodFragment extends StepsFragment { protected static final Logger LOG = LoggerFactory.getLogger(BodyEnergyFragment.class); private TextView mDateView; @@ -113,7 +112,9 @@ public class StepsPeriodFragment extends StepsFragment { yAxisLeft.setEnabled(true); yAxisLeft.setTextColor(CHART_TEXT_COLOR); yAxisLeft.setAxisMinimum(0f); - LimitLine target = new LimitLine(STEPS_GOAL); + final LimitLine target = new LimitLine(STEPS_GOAL); + target.setLineColor(Color.GRAY); + target.enableDashedLine(10f, 10f, 0f); yAxisLeft.addLimitLine(target); final YAxis yAxisRight = stepsChart.getAxisRight(); @@ -138,7 +139,7 @@ public class StepsPeriodFragment extends StepsFragment { } @Override - protected StepsFragment.StepsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { + protected StepsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { Calendar day = Calendar.getInstance(); Date to = new Date((long) this.getTSEnd() * 1000); Date from = DateUtils.addDays(to,-(TOTAL_DAYS - 1)); @@ -147,11 +148,11 @@ public class StepsPeriodFragment extends StepsFragment { mDateView.setText(fromFormattedDate + " - " + toFormattedDate); day.setTime(to); List stepsDaysData = getMyStepsDaysData(db, day, device); - return new StepsFragment.StepsData(stepsDaysData); + return new StepsData(stepsDaysData); } @Override - protected void updateChartsnUIThread(StepsPeriodFragment.StepsData stepsData) { + protected void updateChartsnUIThread(StepsData stepsData) { stepsChart.setData(null); List entries = new ArrayList<>(); @@ -197,4 +198,29 @@ public class StepsPeriodFragment extends StepsFragment { } protected void setupLegend(Chart chart) {} + + protected static class StepsData extends ChartsData { + List days; + long stepsDailyAvg = 0; + double distanceDailyAvg = 0; + long totalSteps = 0; + double totalDistance = 0; + StepsDay todayStepsDay; + protected StepsData(List days) { + this.days = days; + int daysCounter = 0; + for(StepsDay day : days) { + this.totalSteps += day.steps; + this.totalDistance += day.distance; + if (day.steps > 0) { + daysCounter++; + } + } + if (daysCounter > 0) { + this.stepsDailyAvg = this.totalSteps / daysCounter; + this.distanceDailyAvg = this.totalDistance / daysCounter; + } + this.todayStepsDay = days.get(days.size() - 1); + } + } } diff --git a/app/src/main/res/layout/fragment_steps.xml b/app/src/main/res/layout/fragment_steps.xml index 2bed946a0..753e1eea5 100644 --- a/app/src/main/res/layout/fragment_steps.xml +++ b/app/src/main/res/layout/fragment_steps.xml @@ -123,14 +123,15 @@ - + + + \ No newline at end of file