From da1449b58397fd47dc1b0dbf493e20e5b8e1591c Mon Sep 17 00:00:00 2001 From: oliexdev Date: Sat, 11 Feb 2023 18:33:54 +0100 Subject: [PATCH] - redesign statistic fragment to show the differences between a range of measurements --- .../com/health/openscale/core/OpenScale.java | 13 + .../gui/measurement/FloatMeasurementView.java | 2 +- .../gui/overview/OverviewFragment.java | 2 + .../gui/statistic/StatisticAdapter.java | 173 ++++++++ .../gui/statistic/StatisticsFragment.java | 404 +++++------------- .../app/src/main/res/drawable/ic_calendar.xml | 5 + .../app/src/main/res/layout/activity_main.xml | 4 +- .../res/layout/activity_slidetonavigation.xml | 2 +- .../src/main/res/layout/float_input_view.xml | 4 +- .../src/main/res/layout/fragment_graph.xml | 1 + .../main/res/layout/fragment_statistics.xml | 299 +++---------- .../src/main/res/layout/item_statistic.xml | 87 ++++ .../app/src/main/res/values/colors.xml | 4 +- .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 10 +- 15 files changed, 471 insertions(+), 542 deletions(-) create mode 100644 android_app/app/src/main/java/com/health/openscale/gui/statistic/StatisticAdapter.java create mode 100644 android_app/app/src/main/res/drawable/ic_calendar.xml create mode 100644 android_app/app/src/main/res/layout/item_statistic.xml diff --git a/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java b/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java index 2944bc1a..dc2914cc 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java +++ b/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java @@ -576,6 +576,19 @@ public class OpenScale { return measurementDAO.getAllInRange(startCalender.getTime(), endCalender.getTime(), selectedUserId); } + public List getScaleMeasurementOfRangeDates(int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay) { + int selectedUserId = getSelectedScaleUserId(); + + Calendar startCalender = Calendar.getInstance(); + Calendar endCalender = Calendar.getInstance(); + + startCalender.set(startYear, startMonth, startDay, 0, 0, 0); + endCalender.set(endYear, endMonth, endDay, 0, 0, 0); + endCalender.add(Calendar.DAY_OF_MONTH, 1); + + return measurementDAO.getAllInRange(startCalender.getTime(), endCalender.getTime(), selectedUserId); + } + public List getScaleMeasurementOfDay(int year, int month, int day) { int selectedUserId = getSelectedScaleUserId(); diff --git a/android_app/app/src/main/java/com/health/openscale/gui/measurement/FloatMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/measurement/FloatMeasurementView.java index 0704b5c2..808c01d8 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/measurement/FloatMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/measurement/FloatMeasurementView.java @@ -228,7 +228,7 @@ public abstract class FloatMeasurementView extends MeasurementView { setValue(clampValue(value - INC_DEC_DELTA), previousValue, true); } - private String formatValue(float value, boolean withUnit) { + public String formatValue(float value, boolean withUnit) { final String format = String.format(Locale.getDefault(), "%%.%df%s", getDecimalPlaces(), withUnit && !getUnit().isEmpty() ? " %s" : ""); return String.format(Locale.getDefault(), format, value, getUnit()); diff --git a/android_app/app/src/main/java/com/health/openscale/gui/overview/OverviewFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/overview/OverviewFragment.java index 336033d7..ceff9f95 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/overview/OverviewFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/overview/OverviewFragment.java @@ -103,8 +103,10 @@ public class OverviewFragment extends Fragment { chartView.getLegend().setEnabled(false); chartView.getAxisRight().setDrawLabels(false); chartView.getAxisRight().setDrawGridLines(false); + chartView.getAxisRight().setDrawAxisLine(false); chartView.getAxisLeft().setDrawGridLines(false); chartView.getAxisLeft().setDrawLabels(false); + chartView.getAxisLeft().setDrawAxisLine(false); chartView.getXAxis().setDrawGridLines(false); chartActionBarView = overviewView.findViewById(R.id.chartActionBar); diff --git a/android_app/app/src/main/java/com/health/openscale/gui/statistic/StatisticAdapter.java b/android_app/app/src/main/java/com/health/openscale/gui/statistic/StatisticAdapter.java new file mode 100644 index 00000000..496a3e23 --- /dev/null +++ b/android_app/app/src/main/java/com/health/openscale/gui/statistic/StatisticAdapter.java @@ -0,0 +1,173 @@ +package com.health.openscale.gui.statistic; + +import android.app.Activity; +import android.content.res.ColorStateList; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.RelativeSizeSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.github.mikephil.charting.charts.LineChart; +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.interfaces.datasets.ILineDataSet; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.health.openscale.R; +import com.health.openscale.core.datatypes.ScaleMeasurement; +import com.health.openscale.gui.measurement.FloatMeasurementView; +import com.health.openscale.gui.measurement.MeasurementView; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +class StatisticAdapter extends RecyclerView.Adapter { + private Activity activity; + private List scaleMeasurementList; + private ScaleMeasurement firstMeasurement; + private ScaleMeasurement lastMeasurement; + private List measurementViewList; + + public StatisticAdapter(Activity activity, List scaleMeasurementList) { + this.activity = activity; + this.scaleMeasurementList = scaleMeasurementList; + + if (scaleMeasurementList.isEmpty()) { + this.firstMeasurement = new ScaleMeasurement(); + this.lastMeasurement = new ScaleMeasurement(); + } else if (scaleMeasurementList.size() == 1) { + this.firstMeasurement = scaleMeasurementList.get(0); + this.lastMeasurement = scaleMeasurementList.get(0); + } else { + this.firstMeasurement = scaleMeasurementList.get(scaleMeasurementList.size()-1); + this.lastMeasurement = scaleMeasurementList.get(0); + } + + List fullMeasurementViewList = MeasurementView.getMeasurementList(activity, MeasurementView.DateTimeOrder.LAST); + measurementViewList = new ArrayList<>(); + + for (MeasurementView measurementView : fullMeasurementViewList) { + if (measurementView instanceof FloatMeasurementView && measurementView.isVisible()) { + measurementViewList.add((FloatMeasurementView)measurementView); + } + } + } + + @Override + public StatisticAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_statistic, parent, false); + + ViewHolder viewHolder = new ViewHolder(view); + + return viewHolder; + } + + @Override + public void onBindViewHolder(@NonNull StatisticAdapter.ViewHolder holder, int position) { + FloatMeasurementView measurementView = measurementViewList.get(position); + List lineEntries = new ArrayList<>(); + + Collections.reverse(scaleMeasurementList); + + int i=0; + float sumValue = 0; + for (ScaleMeasurement scaleMeasurement : scaleMeasurementList) { + measurementView.loadFrom(scaleMeasurement, null); + sumValue += measurementView.getValue(); + lineEntries.add(new Entry(i, measurementView.getValue())); + i++; + } + + Collections.reverse(scaleMeasurementList); + + LineDataSet lineDataSet = new LineDataSet(lineEntries, holder.measurementName.getText().toString()); + lineDataSet.setColor(measurementView.getColor()); + lineDataSet.setDrawCircles(false); + lineDataSet.setFillColor(measurementView.getColor()); + lineDataSet.setDrawFilled(true); + lineDataSet.setDrawValues(false); + lineDataSet.setHighlightEnabled(false); + + List dataSets = new ArrayList<>(); + dataSets.add(lineDataSet); + + LineData data = new LineData(dataSets); + holder.diffChartView.setData(data); + holder.diffChartView.invalidate(); + + measurementView.loadFrom(lastMeasurement, firstMeasurement); + + holder.measurementName.setText(measurementView.getName()); + SpannableStringBuilder diffValueText = new SpannableStringBuilder(); + float avgValue = sumValue / scaleMeasurementList.size(); + diffValueText.append("(\u00d8 " + measurementView.formatValue(avgValue, true) + ") "); + diffValueText.setSpan(new RelativeSizeSpan(0.8f), 0, diffValueText.length(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + measurementView.appendDiffValue(diffValueText, false); + holder.diffValueView.setText(diffValueText); + holder.endValueView.setText(measurementView.getValueAsString(true)); + holder.iconView.setImageDrawable(measurementView.getIcon()); + holder.iconView.setBackgroundTintList(ColorStateList.valueOf(measurementView.getColor())); + + measurementView.loadFrom(firstMeasurement, null); + holder.startValueView.setText(measurementView.getValueAsString(true)); + } + + private int convertDateToInt(Date date) { + LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + return (int)localDate.toEpochDay(); + } + + @Override + public long getItemId(int position) { + return measurementViewList.get(position).getId(); + } + + @Override + public int getItemCount() { + return measurementViewList.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + TextView measurementName; + TextView diffValueView; + TextView startValueView; + FloatingActionButton iconView; + LineChart diffChartView; + TextView endValueView; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + + measurementName = itemView.findViewById(R.id.measurementName); + diffValueView = itemView.findViewById(R.id.diffValueView); + startValueView = itemView.findViewById(R.id.startValueView); + iconView = itemView.findViewById(R.id.iconView); + diffChartView = itemView.findViewById(R.id.diffChartView); + endValueView = itemView.findViewById(R.id.endValueView); + + diffChartView.getLegend().setEnabled(false); + diffChartView.getDescription().setEnabled(false); + diffChartView.getAxisRight().setDrawLabels(false); + diffChartView.getAxisRight().setDrawGridLines(false); + diffChartView.getAxisRight().setDrawAxisLine(false); + diffChartView.getAxisLeft().setDrawGridLines(false); + diffChartView.getAxisLeft().setDrawLabels(false); + diffChartView.getAxisLeft().setDrawAxisLine(false); + diffChartView.getXAxis().setDrawGridLines(false); + diffChartView.getXAxis().setDrawLabels(false); + diffChartView.getXAxis().setDrawAxisLine(false); + diffChartView.setMinOffset(0); + } + } +} diff --git a/android_app/app/src/main/java/com/health/openscale/gui/statistic/StatisticsFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/statistic/StatisticsFragment.java index 78f58fb5..32b4d62d 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/statistic/StatisticsFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/statistic/StatisticsFragment.java @@ -16,141 +16,120 @@ package com.health.openscale.gui.statistic; +import android.content.SharedPreferences; import android.os.Bundle; +import android.os.Parcel; import android.preference.PreferenceManager; -import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; import androidx.activity.OnBackPressedCallback; +import androidx.annotation.NonNull; +import androidx.core.util.Pair; import androidx.fragment.app.Fragment; import androidx.lifecycle.Observer; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; -import com.github.mikephil.charting.charts.RadarChart; -import com.github.mikephil.charting.components.Legend; -import com.github.mikephil.charting.components.LegendEntry; -import com.github.mikephil.charting.components.MarkerView; -import com.github.mikephil.charting.data.RadarData; -import com.github.mikephil.charting.data.RadarDataSet; -import com.github.mikephil.charting.data.RadarEntry; -import com.github.mikephil.charting.formatter.ValueFormatter; -import com.github.mikephil.charting.interfaces.datasets.IRadarDataSet; +import com.google.android.material.datepicker.CalendarConstraints; +import com.google.android.material.datepicker.CompositeDateValidator; +import com.google.android.material.datepicker.DateValidatorPointBackward; +import com.google.android.material.datepicker.DateValidatorPointForward; +import com.google.android.material.datepicker.MaterialDatePicker; +import com.google.android.material.datepicker.MaterialPickerOnPositiveButtonClickListener; import com.health.openscale.R; import com.health.openscale.core.OpenScale; import com.health.openscale.core.datatypes.ScaleMeasurement; -import com.health.openscale.core.datatypes.ScaleUser; -import com.health.openscale.core.utils.Converters; -import com.health.openscale.core.utils.DateTimeHelpers; -import com.health.openscale.gui.measurement.BMIMeasurementView; -import com.health.openscale.gui.measurement.BoneMeasurementView; -import com.health.openscale.gui.measurement.ChartMarkerView; -import com.health.openscale.gui.measurement.FatMeasurementView; -import com.health.openscale.gui.measurement.FloatMeasurementView; -import com.health.openscale.gui.measurement.MeasurementView; -import com.health.openscale.gui.measurement.MeasurementViewSettings; -import com.health.openscale.gui.measurement.MuscleMeasurementView; -import com.health.openscale.gui.measurement.WaterMeasurementView; -import com.health.openscale.gui.measurement.WeightMeasurementView; -import com.health.openscale.gui.utils.ColorUtil; import java.text.DateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; import java.util.List; public class StatisticsFragment extends Fragment { - - private View statisticsView; - - private TextView txtGoalWeight; - private TextView txtGoalDiff; - private TextView txtGoalDayLeft; - private TextView txtTotalWeightLost; - - private TextView txtLabelGoalWeight; - private TextView txtLabelGoalDiff; - private TextView txtLabelDayLeft; - private TextView txtLabelTotalWeightLost; - - private RadarChart radarChartWeek; - private RadarChart radarChartMonth; - - private ScaleUser currentScaleUser; - private ScaleMeasurement firstScaleMeasurement; - private ScaleMeasurement lastScaleMeasurement; - - private ArrayList viewMeasurementsStatistics; + private RecyclerView compareRecyclerView; + private TextView diffDateTextView; + private TextView countMeasurementTextView; + private ImageView datePickerView; + private StatisticAdapter statisticAdapter; + private List scaleMeasurementList; + private SharedPreferences prefs; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - statisticsView = inflater.inflate(R.layout.fragment_statistics, container, false); + View statisticsView = inflater.inflate(R.layout.fragment_statistics, container, false); - txtGoalWeight = statisticsView.findViewById(R.id.txtGoalWeight); - txtGoalWeight.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - txtGoalDiff = statisticsView.findViewById(R.id.txtGoalDiff); - txtGoalDiff.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - txtGoalDayLeft = statisticsView.findViewById(R.id.txtGoalDayLeft); - txtGoalDayLeft.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - txtTotalWeightLost = statisticsView.findViewById(R.id.txtTotalWeightLost); - txtTotalWeightLost.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); + prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + compareRecyclerView = statisticsView.findViewById(R.id.compareRecyclerView); + diffDateTextView = statisticsView.findViewById(R.id.diffDateTextView); + countMeasurementTextView = statisticsView.findViewById(R.id.countMeasurementTextView); + datePickerView = statisticsView.findViewById(R.id.datePickerView); - txtLabelGoalWeight = statisticsView.findViewById(R.id.txtLabelGoalWeight); - txtLabelGoalWeight.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - txtLabelGoalDiff = statisticsView.findViewById(R.id.txtLabelGoalDiff); - txtLabelGoalDiff.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - txtLabelDayLeft = statisticsView.findViewById(R.id.txtLabelDayLeft); - txtLabelDayLeft.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - txtLabelTotalWeightLost = statisticsView.findViewById(R.id.txtLabelTotalWeightLost); - txtLabelTotalWeightLost.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); + datePickerView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + List dateValidatorList = new ArrayList<>(); - viewMeasurementsStatistics = new ArrayList<>(); + CalendarConstraints.DateValidator selectedDateValidator = new CalendarConstraints.DateValidator() { + @Override + public boolean isValid(long date) { + Calendar dateCalendar = Calendar.getInstance(); + dateCalendar.setTime(new Date(date)); - viewMeasurementsStatistics.add(new WeightMeasurementView(statisticsView.getContext())); - viewMeasurementsStatistics.add(new WaterMeasurementView(statisticsView.getContext())); - viewMeasurementsStatistics.add(new MuscleMeasurementView(statisticsView.getContext())); - viewMeasurementsStatistics.add(new FatMeasurementView(statisticsView.getContext())); - viewMeasurementsStatistics.add(new BoneMeasurementView(statisticsView.getContext())); - viewMeasurementsStatistics.add(new BMIMeasurementView(statisticsView.getContext())); + List dateScaleMeasurementList = OpenScale.getInstance().getScaleMeasurementOfDay(dateCalendar.get(Calendar.YEAR), dateCalendar.get(Calendar.MONTH), dateCalendar.get(Calendar.DAY_OF_MONTH)); - ArrayList legendEntriesWeek = new ArrayList<>(); + if (!dateScaleMeasurementList.isEmpty()) { + return true; + } - for (int i = 0; i< viewMeasurementsStatistics.size(); i++) { - LegendEntry legendEntry = new LegendEntry(); - legendEntry.label = i + " - " + viewMeasurementsStatistics.get(i).getName().toString(); - legendEntriesWeek.add(legendEntry); - } + return false; + } - MarkerView mv = new ChartMarkerView(statisticsView.getContext(), R.layout.chart_markerview); + @Override + public int describeContents() { + return 0; + } - radarChartWeek = statisticsView.findViewById(R.id.radarPastWeek); - radarChartWeek.getXAxis().setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - radarChartWeek.getDescription().setEnabled(false); - radarChartWeek.getYAxis().setEnabled(false); - radarChartWeek.setExtraTopOffset(10); - radarChartWeek.setRotationEnabled(false); - Legend weekLegend = radarChartWeek.getLegend(); - weekLegend.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - weekLegend.setWordWrapEnabled(true); - weekLegend.setExtra(legendEntriesWeek); - weekLegend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER); - mv.setChartView(radarChartWeek); - radarChartWeek.setMarker(mv); + @Override + public void writeToParcel(@NonNull Parcel parcel, int i) { - radarChartMonth = statisticsView.findViewById(R.id.radarPastMonth); - radarChartMonth.getXAxis().setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - radarChartMonth.getDescription().setEnabled(false); - radarChartMonth.getYAxis().setEnabled(false); - radarChartMonth.setExtraTopOffset(10); - radarChartMonth.setRotationEnabled(false); - Legend monthLegend = radarChartMonth.getLegend(); - monthLegend.setTextColor(ColorUtil.getTintColor(statisticsView.getContext())); - monthLegend.setWordWrapEnabled(true); - monthLegend.setExtra(legendEntriesWeek); - monthLegend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER); - mv.setChartView(radarChartMonth); - radarChartMonth.setMarker(mv); + } + }; + dateValidatorList.add(DateValidatorPointForward.from(scaleMeasurementList.get(scaleMeasurementList.size()-1).getDateTime().getTime())); + dateValidatorList.add(DateValidatorPointBackward.before(scaleMeasurementList.get(0).getDateTime().getTime())); + dateValidatorList.add(selectedDateValidator); + + CalendarConstraints constraintsBuilderRange = new CalendarConstraints.Builder().setValidator(CompositeDateValidator.allOf(dateValidatorList)).build(); + + MaterialDatePicker> materialDate = MaterialDatePicker.Builder.dateRangePicker().setCalendarConstraints(constraintsBuilderRange).build(); + materialDate.show(getActivity().getSupportFragmentManager(), "MATERIAL_DATE_PICKER"); + + materialDate.addOnPositiveButtonClickListener(new MaterialPickerOnPositiveButtonClickListener>() { + @Override public void onPositiveButtonClick(Pair selection) { + Calendar startCalendar = Calendar.getInstance(); + startCalendar.setTime(new Date(selection.first)); + Calendar endCalendar = Calendar.getInstance(); + endCalendar.setTime(new Date(selection.second)); + + setDiffDateText(startCalendar.getTime(), endCalendar.getTime()); + + List rangeScaleMeasurementList = OpenScale.getInstance().getScaleMeasurementOfRangeDates(startCalendar.get(Calendar.YEAR), startCalendar.get(Calendar.MONTH), startCalendar.get(Calendar.DAY_OF_MONTH), + endCalendar.get(Calendar.YEAR), endCalendar.get(Calendar.MONTH), endCalendar.get(Calendar.DAY_OF_MONTH)); + + prefs.edit().putLong("statistic_range_start_date", startCalendar.getTime().getTime()).commit(); + + updateStatistic(rangeScaleMeasurementList); + } + }); + } + }); + + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()); + compareRecyclerView.setLayoutManager(layoutManager); OpenScale.getInstance().getScaleMeasurementsLiveData().observe(getViewLifecycleOwner(), new Observer>() { @Override @@ -171,206 +150,57 @@ public class StatisticsFragment extends Fragment { return statisticsView; } - public void updateOnView(List scaleMeasurementList) { - currentScaleUser = OpenScale.getInstance().getSelectedScaleUser(); + public void updateStatistic(List rangeScaleMeasurementList) { + compareRecyclerView.setVisibility(View.VISIBLE); + statisticAdapter = new StatisticAdapter(getActivity(), rangeScaleMeasurementList); + compareRecyclerView.setAdapter(statisticAdapter); - if (scaleMeasurementList.isEmpty()) { - lastScaleMeasurement = new ScaleMeasurement(); - lastScaleMeasurement.setUserId(currentScaleUser.getId()); - lastScaleMeasurement.setWeight(currentScaleUser.getInitialWeight()); - firstScaleMeasurement = lastScaleMeasurement; + countMeasurementTextView.setText(rangeScaleMeasurementList.size() + " " + getResources().getString(R.string.label_measurements)); + + ScaleMeasurement firstMeasurement; + ScaleMeasurement lastMeasurement; + + if (rangeScaleMeasurementList.isEmpty()) { + firstMeasurement = new ScaleMeasurement(); + lastMeasurement = new ScaleMeasurement(); + } else if (rangeScaleMeasurementList.size() == 1) { + firstMeasurement = rangeScaleMeasurementList.get(0); + lastMeasurement = rangeScaleMeasurementList.get(0); } else { - lastScaleMeasurement = scaleMeasurementList.get(0); - firstScaleMeasurement = scaleMeasurementList.get(scaleMeasurementList.size() - 1); + firstMeasurement = rangeScaleMeasurementList.get(rangeScaleMeasurementList.size() - 1); + lastMeasurement = rangeScaleMeasurementList.get(0); } - updateStatistics(scaleMeasurementList); - updateGoal(); + setDiffDateText(firstMeasurement.getDateTime(), lastMeasurement.getDateTime()); } - private void updateGoal() { - final Converters.WeightUnit unit = currentScaleUser.getScaleUnit(); + public void setDiffDateText(Date firstDate, Date secondDate) { + String diffDateText = DateFormat.getDateInstance(DateFormat.MEDIUM).format(firstDate) + " - " + + DateFormat.getDateInstance(DateFormat.MEDIUM).format(secondDate); - ScaleMeasurement goalScaleMeasurement = new ScaleMeasurement(); - goalScaleMeasurement.setUserId(currentScaleUser.getId()); - goalScaleMeasurement.setWeight(currentScaleUser.getGoalWeight()); - - txtGoalWeight.setText(String.format("%.1f %s", - Converters.fromKilogram(goalScaleMeasurement.getWeight(), unit), - unit.toString())); - - txtGoalDiff.setText(String.format("%.1f %s", - Converters.fromKilogram(goalScaleMeasurement.getWeight() - lastScaleMeasurement.getWeight(), unit), - unit.toString())); - - txtTotalWeightLost.setText(String.format("%.1f %s", - Converters.fromKilogram(firstScaleMeasurement.getWeight() - lastScaleMeasurement.getWeight(), unit), - unit.toString())); - - Calendar goalCalendar = Calendar.getInstance(); - goalCalendar.setTime(currentScaleUser.getGoalDate()); - int days = Math.max(0, DateTimeHelpers.daysBetween(Calendar.getInstance(), goalCalendar)); - txtGoalDayLeft.setText(getResources().getQuantityString(R.plurals.label_days, days, days)); - - boolean isBmiEnabled = new MeasurementViewSettings( - PreferenceManager.getDefaultSharedPreferences(getActivity()), BMIMeasurementView.KEY) - .isEnabled(); - final float goalBmi = goalScaleMeasurement.getBMI(currentScaleUser.getBodyHeight()); - - txtLabelGoalWeight.setText( - isBmiEnabled - ? Html.fromHtml(String.format( - "%s
%s: %.1f", - getResources().getString(R.string.label_goal_weight), - getResources().getString(R.string.label_bmi), - goalBmi)) - : getResources().getString(R.string.label_goal_weight)); - - txtLabelGoalDiff.setText( - isBmiEnabled - ? Html.fromHtml(String.format( - "%s
%s: %.1f", - getResources().getString(R.string.label_weight_difference), - getResources().getString(R.string.label_bmi), - lastScaleMeasurement.getBMI(currentScaleUser.getBodyHeight()) - goalBmi)) - : getResources().getString(R.string.label_weight_difference)); - - txtLabelDayLeft.setText( - Html.fromHtml(String.format( - "%s
%s %s", - getResources().getString(R.string.label_days_left), - getResources().getString(R.string.label_goal_date_is), - DateFormat.getDateInstance(DateFormat.LONG).format(currentScaleUser.getGoalDate())))); - - txtLabelTotalWeightLost.setText( - Html.fromHtml(String.format( - "%s
%s %.1f %s", - getResources().getString(R.string.label_total_weight_lost), - getResources().getString(R.string.label_total_weight_lost_weight_reference), - Converters.fromKilogram(firstScaleMeasurement.getWeight(), unit), - unit.toString()))); + diffDateTextView.setText(diffDateText); } - private void updateStatistics(List scaleMeasurementList) { - radarChartWeek.clear(); - radarChartMonth.clear(); + public void updateOnView(List scaleMeasurementList) { + this.scaleMeasurementList = scaleMeasurementList; - Calendar histDate = Calendar.getInstance(); - Calendar weekPastDate = Calendar.getInstance(); - Calendar monthPastDate = Calendar.getInstance(); + Long prefDate = prefs.getLong("statistic_range_start_date", 0); - weekPastDate.setTime(lastScaleMeasurement.getDateTime()); - weekPastDate.add(Calendar.DATE, -7); + if (prefDate != 0) { + Calendar startCalendar = Calendar.getInstance(); + startCalendar.setTime(new Date(prefDate)); + Calendar endCalendar = Calendar.getInstance(); + endCalendar.setTime(new Date()); - monthPastDate.setTime(lastScaleMeasurement.getDateTime()); - monthPastDate.add(Calendar.DATE, -30); + setDiffDateText(startCalendar.getTime(), endCalendar.getTime()); - ScaleMeasurement averageWeek = new ScaleMeasurement(); - ScaleMeasurement averageMonth = new ScaleMeasurement(); + List rangeScaleMeasurementList = OpenScale.getInstance().getScaleMeasurementOfRangeDates(startCalendar.get(Calendar.YEAR), startCalendar.get(Calendar.MONTH), startCalendar.get(Calendar.DAY_OF_MONTH), + endCalendar.get(Calendar.YEAR), endCalendar.get(Calendar.MONTH), endCalendar.get(Calendar.DAY_OF_MONTH)); - ArrayList entriesLastMeasurement = new ArrayList<>(); - ArrayList entriesAvgWeek = new ArrayList<>(); - ArrayList entriesAvgMonth = new ArrayList<>(); - - for (ScaleMeasurement measurement : scaleMeasurementList) { - histDate.setTime(measurement.getDateTime()); - - if (weekPastDate.before(histDate)) { - averageWeek.add(measurement); - } - - if (monthPastDate.before(histDate)) { - averageMonth.add(measurement); - } + updateStatistic(rangeScaleMeasurementList); + } else { + updateStatistic(scaleMeasurementList); } - averageWeek.divide(averageWeek.count()); - averageMonth.divide(averageMonth.count()); - - for (MeasurementView view : viewMeasurementsStatistics) { - final FloatMeasurementView measurementView = (FloatMeasurementView) view; - - Object[] extraData = new Object[3]; - extraData[0] = null; // not needed - extraData[1] = null; // not needed - extraData[2] = measurementView; - - measurementView.loadFrom(averageMonth, null); - entriesAvgMonth.add(new RadarEntry(measurementView.getValue(), extraData)); - - measurementView.loadFrom(averageWeek, null); - entriesAvgWeek.add(new RadarEntry(measurementView.getValue(), extraData)); - - measurementView.loadFrom(lastScaleMeasurement, null); - entriesLastMeasurement.add(new RadarEntry(measurementView.getValue(), extraData)); - } - - RadarDataSet setLastMeasurement = new RadarDataSet(entriesLastMeasurement, getString(R.string.label_title_last_measurement)); - setLastMeasurement.setColor(ColorUtil.COLOR_BLUE); - setLastMeasurement.setFillColor(ColorUtil.COLOR_BLUE); - setLastMeasurement.setDrawFilled(true); - setLastMeasurement.setFillAlpha(180); - setLastMeasurement.setLineWidth(2f); - setLastMeasurement.setDrawHighlightCircleEnabled(true); - setLastMeasurement.setDrawHighlightIndicators(false); - - RadarDataSet setAvgWeek = new RadarDataSet(entriesAvgWeek, getString(R.string.label_last_week)); - setAvgWeek.setColor(ColorUtil.COLOR_GREEN); - setAvgWeek.setFillColor(ColorUtil.COLOR_GREEN); - setAvgWeek.setDrawFilled(true); - setAvgWeek.setFillAlpha(180); - setAvgWeek.setLineWidth(2f); - setAvgWeek.setDrawHighlightCircleEnabled(true); - setAvgWeek.setDrawHighlightIndicators(false); - - RadarDataSet setAvgMonth = new RadarDataSet(entriesAvgMonth, getString(R.string.label_last_month)); - setAvgMonth.setColor(ColorUtil.COLOR_GREEN); - setAvgMonth.setFillColor(ColorUtil.COLOR_GREEN); - setAvgMonth.setDrawFilled(true); - setAvgMonth.setFillAlpha(180); - setAvgMonth.setLineWidth(2f); - setAvgMonth.setDrawHighlightCircleEnabled(true); - setAvgMonth.setDrawHighlightIndicators(false); - - ArrayList setsAvgWeek = new ArrayList<>(); - setsAvgWeek.add(setAvgWeek); - setsAvgWeek.add(setLastMeasurement); - - ArrayList setsAvgMonth = new ArrayList<>(); - setsAvgMonth.add(setAvgMonth); - setsAvgMonth.add(setLastMeasurement); - - RadarData dataAvgWeek = new RadarData(setsAvgWeek); - dataAvgWeek.setValueTextSize(8f); - dataAvgWeek.setDrawValues(false); - dataAvgWeek.setValueFormatter(new ValueFormatter() { - @Override - public String getRadarLabel(RadarEntry radarEntry) { - FloatMeasurementView measurementView = (FloatMeasurementView) radarEntry.getData(); - - return measurementView.getValueAsString(true); - } - }); - - RadarData dataAvgMonth = new RadarData(setsAvgMonth); - dataAvgMonth.setValueTextSize(8f); - dataAvgMonth.setDrawValues(false); - dataAvgMonth.setValueFormatter(new ValueFormatter() { - @Override - public String getRadarLabel(RadarEntry radarEntry) { - FloatMeasurementView measurementView = (FloatMeasurementView) radarEntry.getData(); - - return measurementView.getValueAsString(true); - } - }); - - radarChartWeek.setData(dataAvgWeek); - radarChartMonth.setData(dataAvgMonth); - - radarChartWeek.animateXY(1000, 1000); - radarChartMonth.animateXY(1000, 1000); - - radarChartWeek.invalidate(); - radarChartMonth.invalidate(); } } diff --git a/android_app/app/src/main/res/drawable/ic_calendar.xml b/android_app/app/src/main/res/drawable/ic_calendar.xml new file mode 100644 index 00000000..a1b22763 --- /dev/null +++ b/android_app/app/src/main/res/drawable/ic_calendar.xml @@ -0,0 +1,5 @@ + + + diff --git a/android_app/app/src/main/res/layout/activity_main.xml b/android_app/app/src/main/res/layout/activity_main.xml index ae8928dc..6368ca95 100644 --- a/android_app/app/src/main/res/layout/activity_main.xml +++ b/android_app/app/src/main/res/layout/activity_main.xml @@ -18,14 +18,14 @@ + android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"> + app:popupTheme="@style/ThemeOverlay.MaterialComponents.Dark" /> diff --git a/android_app/app/src/main/res/layout/activity_slidetonavigation.xml b/android_app/app/src/main/res/layout/activity_slidetonavigation.xml index cf99056c..58971b36 100644 --- a/android_app/app/src/main/res/layout/activity_slidetonavigation.xml +++ b/android_app/app/src/main/res/layout/activity_slidetonavigation.xml @@ -12,7 +12,7 @@ android:layout_height="wrap_content" android:fitsSystemWindows="true" android:minHeight="?attr/actionBarSize" - app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" + app:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar" android:background="?attr/colorPrimaryDark"> diff --git a/android_app/app/src/main/res/layout/float_input_view.xml b/android_app/app/src/main/res/layout/float_input_view.xml index 1fc3cc16..32dceea2 100644 --- a/android_app/app/src/main/res/layout/float_input_view.xml +++ b/android_app/app/src/main/res/layout/float_input_view.xml @@ -6,7 +6,7 @@