diff --git a/android_app/app/build.gradle b/android_app/app/build.gradle index b17899ec..4af00ae1 100644 --- a/android_app/app/build.gradle +++ b/android_app/app/build.gradle @@ -64,7 +64,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.recyclerview:recyclerview:1.0.0' // MPAndroidChart - implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0-alpha' + implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' // Simple CSV implementation 'com.j256.simplecsv:simplecsv:2.3' // RxAndroidBle diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java index 274f3f35..a3d8b0a4 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java @@ -33,6 +33,8 @@ import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; +import androidx.fragment.app.Fragment; + import com.github.mikephil.charting.charts.BarChart; import com.github.mikephil.charting.components.AxisBase; import com.github.mikephil.charting.components.XAxis; @@ -40,8 +42,8 @@ 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.Entry; -import com.github.mikephil.charting.formatter.IAxisValueFormatter; import com.github.mikephil.charting.formatter.StackedValueFormatter; +import com.github.mikephil.charting.formatter.ValueFormatter; import com.github.mikephil.charting.highlight.Highlight; import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; import com.github.mikephil.charting.listener.OnChartValueSelectedListener; @@ -60,8 +62,6 @@ import java.util.Calendar; import java.util.List; import java.util.Locale; -import androidx.fragment.app.Fragment; - public class GraphFragment extends Fragment implements FragmentUpdateListener { private View graphView; private ChartMeasurementView chartView; @@ -128,12 +128,12 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { chartTopxAxis.setPosition(XAxis.XAxisPosition.BOTTOM); chartTopxAxis.setDrawGridLines(false); chartTopxAxis.setTextColor(ColorUtil.getTextColor(graphView.getContext())); - chartTopxAxis.setValueFormatter(new IAxisValueFormatter() { + chartTopxAxis.setValueFormatter(new ValueFormatter() { private final SimpleDateFormat mFormat = new SimpleDateFormat("MMM", Locale.getDefault()); @Override - public String getFormattedValue(float value, AxisBase axis) { + public String getAxisLabel(float value, AxisBase axis) { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.MONTH, (int)value); return mFormat.format(calendar.getTime()); diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/StatisticsFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/StatisticsFragment.java index a83b6dcf..cbf562a9 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/StatisticsFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/StatisticsFragment.java @@ -25,17 +25,17 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import androidx.fragment.app.Fragment; + 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.Entry; 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.IValueFormatter; +import com.github.mikephil.charting.formatter.ValueFormatter; import com.github.mikephil.charting.interfaces.datasets.IRadarDataSet; -import com.github.mikephil.charting.utils.ViewPortHandler; import com.health.openscale.R; import com.health.openscale.core.OpenScale; import com.health.openscale.core.datatypes.ScaleMeasurement; @@ -59,8 +59,6 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.List; -import androidx.fragment.app.Fragment; - public class StatisticsFragment extends Fragment implements FragmentUpdateListener { private View statisticsView; @@ -321,10 +319,10 @@ public class StatisticsFragment extends Fragment implements FragmentUpdateListen RadarData dataAvgWeek = new RadarData(setsAvgWeek); dataAvgWeek.setValueTextSize(8f); dataAvgWeek.setDrawValues(false); - dataAvgWeek.setValueFormatter(new IValueFormatter() { + dataAvgWeek.setValueFormatter(new ValueFormatter() { @Override - public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { - FloatMeasurementView measurementView = (FloatMeasurementView) entry.getData(); + public String getRadarLabel(RadarEntry radarEntry) { + FloatMeasurementView measurementView = (FloatMeasurementView) radarEntry.getData(); return measurementView.getValueAsString(true); } @@ -333,10 +331,10 @@ public class StatisticsFragment extends Fragment implements FragmentUpdateListen RadarData dataAvgMonth = new RadarData(setsAvgMonth); dataAvgMonth.setValueTextSize(8f); dataAvgMonth.setDrawValues(false); - dataAvgMonth.setValueFormatter(new IValueFormatter() { + dataAvgMonth.setValueFormatter(new ValueFormatter() { @Override - public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { - FloatMeasurementView measurementView = (FloatMeasurementView) entry.getData(); + public String getRadarLabel(RadarEntry radarEntry) { + FloatMeasurementView measurementView = (FloatMeasurementView) radarEntry.getData(); return measurementView.getValueAsString(true); } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/ChartMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/ChartMeasurementView.java index e5848efb..e7b234e5 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/ChartMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/ChartMeasurementView.java @@ -19,6 +19,7 @@ package com.health.openscale.gui.views; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Color; +import android.graphics.RectF; import android.preference.PreferenceManager; import android.util.AttributeSet; import android.widget.Toast; @@ -31,10 +32,9 @@ 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.IAxisValueFormatter; -import com.github.mikephil.charting.formatter.IValueFormatter; +import com.github.mikephil.charting.formatter.ValueFormatter; import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; -import com.github.mikephil.charting.utils.ViewPortHandler; +import com.github.mikephil.charting.utils.Utils; import com.health.openscale.R; import com.health.openscale.core.OpenScale; import com.health.openscale.core.datatypes.ScaleMeasurement; @@ -227,6 +227,62 @@ public class ChartMeasurementView extends LineChart { return (int)(shortDate.getTime().getTime() / 1000000L); } + private void setCustomViewPortOffsets() { + float offsetLeft = 0f, offsetRight = 0f, offsetTop = 0f, offsetBottom = 0f; + + RectF mOffsetsBuffer = new RectF(); + calculateLegendOffsets(mOffsetsBuffer); + + offsetLeft += mOffsetsBuffer.left; + offsetTop += mOffsetsBuffer.top; + offsetRight += mOffsetsBuffer.right; + offsetBottom += Math.max(70f, mOffsetsBuffer.bottom); + + // offsets for y-labels + if (mAxisLeft.needsOffset()) { + offsetLeft += mAxisLeft.getRequiredWidthSpace(mAxisRendererLeft + .getPaintAxisLabels()); + } + + if (mAxisRight.needsOffset()) { + offsetRight += mAxisRight.getRequiredWidthSpace(mAxisRendererRight + .getPaintAxisLabels()); + } + + if (mXAxis.isEnabled() && mXAxis.isDrawLabelsEnabled()) { + + float xLabelHeight = mXAxis.mLabelRotatedHeight + mXAxis.getYOffset(); + + // offsets for x-labels + if (mXAxis.getPosition() == XAxis.XAxisPosition.BOTTOM) { + + offsetBottom += xLabelHeight; + + } else if (mXAxis.getPosition() == XAxis.XAxisPosition.TOP) { + + offsetTop += xLabelHeight; + + } else if (mXAxis.getPosition() == XAxis.XAxisPosition.BOTH_SIDED) { + + offsetBottom += xLabelHeight; + offsetTop += xLabelHeight; + } + } + + offsetTop += getExtraTopOffset(); + offsetRight += getExtraRightOffset(); + offsetBottom += getExtraBottomOffset(); + offsetLeft += getExtraLeftOffset(); + + float minOffset = Utils.convertDpToPixel(mMinOffset); + + setViewPortOffsets( + Math.max(minOffset, offsetLeft), + Math.max(minOffset, offsetTop), + Math.max(minOffset, offsetRight), + Math.max(minOffset, offsetBottom)); + } + private Date convertShortInDate(int shortDate) { return new Date(shortDate * 1000000L); } @@ -291,19 +347,23 @@ public class ChartMeasurementView extends LineChart { throw new IllegalArgumentException("view mode not implemented"); } + setAutoScaleMinMaxEnabled(true); + setCustomViewPortOffsets(); // set custom viewPortOffsets to avoid jitter on translating while auto scale is on + getXAxis().setGranularity(granularity); setVisibleXRangeMaximum(range); + moveViewToX(getBinNr(lastMeasurement)); } } private void setXValueFormat(final ViewMode mode) { - getXAxis().setValueFormatter(new IAxisValueFormatter() { + getXAxis().setValueFormatter(new ValueFormatter() { private final SimpleDateFormat xValueFormat = new SimpleDateFormat(); private final Calendar calendar = Calendar.getInstance(); @Override - public String getFormattedValue(float value, AxisBase axis) { + public String getAxisLabel(float value, AxisBase axis) { calendar.setTime(new Date(0)); switch (mode) { @@ -476,7 +536,7 @@ public class ChartMeasurementView extends LineChart { private void addMeasurementLine(List lineDataSets, List lineEntries, FloatMeasurementView measurementView) { LineDataSet measurementLine = new LineDataSet(lineEntries, measurementView.getName().toString()); measurementLine.setLineWidth(1.5f); - measurementLine.setValueTextSize(8.0f); + measurementLine.setValueTextSize(10.0f); measurementLine.setColor(measurementView.getColor()); measurementLine.setValueTextColor(ColorUtil.getTextColor(getContext())); measurementLine.setCircleColor(measurementView.getColor()); @@ -488,9 +548,9 @@ public class ChartMeasurementView extends LineChart { measurementLine.setHighLightColor(Color.RED); measurementLine.setDrawCircles(prefs.getBoolean("pointsEnable", true)); measurementLine.setDrawValues(prefs.getBoolean("labelsEnable", true)); - measurementLine.setValueFormatter(new IValueFormatter() { + measurementLine.setValueFormatter(new ValueFormatter() { @Override - public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { + public String getPointLabel(Entry entry) { String prefix = new String(); Object[] extraData = (Object[])entry.getData();