mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-10 17:11:56 +01:00
Add sleep score to sleeping tabs for supported devices
This commit is contained in:
parent
51a3b5d036
commit
c3433f55cb
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023-2024 Daniel Dakhno, José Rebelo
|
||||
/* Copyright (C) 2023-2024 Daniel Dakhno, José Rebelo, a0z
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@ -31,7 +31,6 @@ import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
@ -346,17 +345,11 @@ public abstract class AbstractActivityChartFragment<D extends ChartsData> extend
|
||||
protected LineDataSet createDataSet(List<Entry> values, Integer color, String label) {
|
||||
LineDataSet set1 = new LineDataSet(values, label);
|
||||
set1.setColor(color);
|
||||
// set1.setDrawCubic(true);
|
||||
// set1.setCubicIntensity(0.2f);
|
||||
set1.setDrawFilled(true);
|
||||
set1.setDrawCircles(false);
|
||||
// set1.setLineWidth(2f);
|
||||
// set1.setCircleSize(5f);
|
||||
set1.setFillColor(color);
|
||||
set1.setFillAlpha(255);
|
||||
set1.setDrawValues(false);
|
||||
// set1.setHighLightColor(Color.rgb(128, 0, 255));
|
||||
// set1.setColor(Color.rgb(89, 178, 44));
|
||||
set1.setValueTextColor(CHART_TEXT_COLOR);
|
||||
set1.setAxisDependency(YAxis.AxisDependency.LEFT);
|
||||
return set1;
|
||||
@ -366,17 +359,9 @@ public abstract class AbstractActivityChartFragment<D extends ChartsData> extend
|
||||
LineDataSet set1 = new LineDataSet(values, label);
|
||||
set1.setLineWidth(2.2f);
|
||||
set1.setColor(HEARTRATE_COLOR);
|
||||
// set1.setDrawCubic(true);
|
||||
set1.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
|
||||
set1.setCubicIntensity(0.1f);
|
||||
set1.setDrawCircles(false);
|
||||
// set1.setCircleRadius(2f);
|
||||
// set1.setDrawFilled(true);
|
||||
// set1.setColor(getResources().getColor(android.R.color.background_light));
|
||||
// set1.setCircleColor(HEARTRATE_COLOR);
|
||||
// set1.setFillColor(ColorTemplate.getHoloBlue());
|
||||
// set1.setHighLightColor(Color.rgb(128, 0, 255));
|
||||
// set1.setColor(Color.rgb(89, 178, 44));
|
||||
set1.setDrawValues(true);
|
||||
set1.setValueTextColor(CHART_TEXT_COLOR);
|
||||
set1.setAxisDependency(YAxis.AxisDependency.RIGHT);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Copyright (C) 2017-2024 Alberto, Andreas Shimokawa, Carsten Pfeiffer,
|
||||
Daniele Gobbetti, José Rebelo, Pavel Elagin, Petr Vaněk
|
||||
Daniele Gobbetti, José Rebelo, Pavel Elagin, Petr Vaněk, a0z
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@ -27,7 +27,6 @@ import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.mikephil.charting.charts.BarChart;
|
||||
import com.github.mikephil.charting.charts.PieChart;
|
||||
import com.github.mikephil.charting.components.LimitLine;
|
||||
import com.github.mikephil.charting.components.XAxis;
|
||||
import com.github.mikephil.charting.components.YAxis;
|
||||
@ -35,10 +34,11 @@ 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.ChartData;
|
||||
import com.github.mikephil.charting.data.PieData;
|
||||
import com.github.mikephil.charting.data.PieDataSet;
|
||||
import com.github.mikephil.charting.data.PieEntry;
|
||||
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;
|
||||
@ -51,9 +51,11 @@ import java.util.Locale;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmounts;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.SleepScoreSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||
|
||||
|
||||
@ -65,47 +67,11 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
protected Locale mLocale;
|
||||
protected int mTargetValue = 0;
|
||||
|
||||
protected PieChart mTodayPieChart;
|
||||
protected BarChart mWeekChart;
|
||||
protected TextView mBalanceView;
|
||||
|
||||
private int mOffsetHours = getOffsetHours();
|
||||
|
||||
@Override
|
||||
protected MyChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
|
||||
Calendar day = Calendar.getInstance();
|
||||
day.setTime(chartsHost.getEndDate());
|
||||
//NB: we could have omitted the day, but this way we can move things to the past easily
|
||||
DayData dayData = refreshDayPie(db, day, device);
|
||||
WeekChartsData<BarData> weekBeforeData = refreshWeekBeforeData(db, mWeekChart, day, device);
|
||||
|
||||
return new MyChartsData(dayData, weekBeforeData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChartsnUIThread(MyChartsData mcd) {
|
||||
setupLegend(mWeekChart);
|
||||
mTodayPieChart.setCenterText(mcd.getDayData().centerText);
|
||||
mTodayPieChart.setData(mcd.getDayData().data);
|
||||
//set custom renderer for 30days bar charts
|
||||
if (GBApplication.getPrefs().getBoolean("charts_range", true)) {
|
||||
mWeekChart.setRenderer(new AngledLabelsChartRenderer(mWeekChart, mWeekChart.getAnimator(), mWeekChart.getViewPortHandler()));
|
||||
}
|
||||
|
||||
mWeekChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317
|
||||
mWeekChart.setData(mcd.getWeekBeforeData().getData());
|
||||
mWeekChart.getXAxis().setValueFormatter(mcd.getWeekBeforeData().getXValueFormatter());
|
||||
|
||||
mBalanceView.setText(mcd.getWeekBeforeData().getBalanceMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderCharts() {
|
||||
mWeekChart.invalidate();
|
||||
mTodayPieChart.invalidate();
|
||||
// mBalanceView.setText(getBalanceMessage(balance));
|
||||
}
|
||||
|
||||
protected String getWeeksChartsLabel(Calendar day){
|
||||
if (TOTAL_DAYS > 7) {
|
||||
//month, show day date
|
||||
@ -125,19 +91,39 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
long balance = 0;
|
||||
long daily_balance = 0;
|
||||
TOTAL_DAYS_FOR_AVERAGE=0;
|
||||
|
||||
List<Entry> sleepScoreEntities = new ArrayList<>();
|
||||
final List<ILineDataSet> sleepScoreDataSets = new ArrayList<>();
|
||||
for (int counter = 0; counter < TOTAL_DAYS; counter++) {
|
||||
// Sleep stages
|
||||
ActivityAmounts amounts = getActivityAmountsForDay(db, day, device);
|
||||
daily_balance=calculateBalance(amounts);
|
||||
if (daily_balance > 0) {
|
||||
TOTAL_DAYS_FOR_AVERAGE++;
|
||||
}
|
||||
|
||||
balance += daily_balance;
|
||||
entries.add(new BarEntry(counter, getTotalsForActivityAmounts(amounts)));
|
||||
labels.add(getWeeksChartsLabel(day));
|
||||
// Sleep score
|
||||
if (supportsSleepScore()) {
|
||||
List<? extends SleepScoreSample> sleepScoreSamples = getSleepScoreSamples(db, device, day);
|
||||
if (!sleepScoreSamples.isEmpty() && sleepScoreSamples.get(0).getSleepScore() > 0) {
|
||||
sleepScoreEntities.add(new Entry(counter, sleepScoreSamples.get(0).getSleepScore()));
|
||||
} else {
|
||||
if (!sleepScoreEntities.isEmpty()) {
|
||||
List<Entry> clone = new ArrayList<>(sleepScoreEntities.size());
|
||||
clone.addAll(sleepScoreEntities);
|
||||
sleepScoreDataSets.add(createSleepScoreDataSet(clone));
|
||||
sleepScoreEntities.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
day.add(Calendar.DATE, 1);
|
||||
}
|
||||
if (!sleepScoreEntities.isEmpty()) {
|
||||
sleepScoreDataSets.add(createSleepScoreDataSet(sleepScoreEntities));
|
||||
}
|
||||
final LineData sleepScoreLineData = new LineData(sleepScoreDataSets);
|
||||
sleepScoreLineData.setHighlightEnabled(false);
|
||||
|
||||
BarDataSet set = new BarDataSet(entries, "");
|
||||
set.setColors(getColors());
|
||||
@ -179,49 +165,50 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsSleepScore()) {
|
||||
return new WeekChartsData(barData, new PreformattedXIndexLabelFormatter(labels), getBalanceMessage(balance, mTargetValue), sleepScoreLineData);
|
||||
}
|
||||
return new WeekChartsData(barData, new PreformattedXIndexLabelFormatter(labels), getBalanceMessage(balance, mTargetValue));
|
||||
}
|
||||
|
||||
protected DayData refreshDayPie(DBHandler db, Calendar day, GBDevice device) {
|
||||
protected List<SleepScoreSample> getSleepScoreSamples(DBHandler db, GBDevice device, Calendar day) {
|
||||
int startTs;
|
||||
int endTs;
|
||||
|
||||
PieData data = new PieData();
|
||||
List<PieEntry> entries = new ArrayList<>();
|
||||
PieDataSet set = new PieDataSet(entries, "");
|
||||
day = (Calendar) day.clone(); // do not modify the caller's argument
|
||||
day.set(Calendar.HOUR_OF_DAY, 0);
|
||||
day.set(Calendar.MINUTE, 0);
|
||||
day.set(Calendar.SECOND, 0);
|
||||
day.add(Calendar.HOUR, 0);
|
||||
startTs = (int) (day.getTimeInMillis() / 1000);
|
||||
endTs = startTs + 24 * 60 * 60 - 1;
|
||||
|
||||
ActivityAmounts amounts = getActivityAmountsForDay(db, day, device);
|
||||
float[] totalValues = getTotalsForActivityAmounts(amounts);
|
||||
String[] pieLabels = getPieLabels();
|
||||
float totalValue = 0;
|
||||
for (int i = 0; i < totalValues.length; i++) {
|
||||
float value = totalValues[i];
|
||||
totalValue += value;
|
||||
entries.add(new PieEntry(value, pieLabels[i]));
|
||||
TimeSampleProvider<? extends SleepScoreSample> provider = device.getDeviceCoordinator().getSleepScoreProvider(device, db.getDaoSession());
|
||||
return (List<SleepScoreSample>) provider.getAllSamples(startTs * 1000L, endTs * 1000L);
|
||||
}
|
||||
|
||||
set.setColors(getColors());
|
||||
|
||||
if (totalValues.length < 2) {
|
||||
if (totalValue < mTargetValue) {
|
||||
entries.add(new PieEntry((mTargetValue - totalValue)));
|
||||
set.addColor(Color.GRAY);
|
||||
}
|
||||
}
|
||||
|
||||
data.setDataSet(set);
|
||||
|
||||
if (totalValues.length < 2) {
|
||||
data.setDrawValues(false);
|
||||
}
|
||||
else {
|
||||
set.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
|
||||
set.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
|
||||
set.setValueTextColor(DESCRIPTION_COLOR);
|
||||
set.setValueTextSize(13f);
|
||||
set.setValueFormatter(getPieValueFormatter());
|
||||
}
|
||||
|
||||
return new DayData(data, formatPieValue((long) totalValue));
|
||||
protected LineDataSet createSleepScoreDataSet(final List<Entry> values) {
|
||||
final LineDataSet lineDataSet = new LineDataSet(values, getString(R.string.sleep_score));
|
||||
lineDataSet.setColor(getResources().getColor(R.color.chart_light_sleep_light));
|
||||
lineDataSet.setDrawCircles(false);
|
||||
lineDataSet.setLineWidth(2f);
|
||||
lineDataSet.setFillAlpha(255);
|
||||
lineDataSet.setCircleRadius(5f);
|
||||
lineDataSet.setDrawCircles(true);
|
||||
lineDataSet.setDrawCircleHole(true);
|
||||
lineDataSet.setCircleColor(getResources().getColor(R.color.chart_light_sleep_light));
|
||||
lineDataSet.setAxisDependency(YAxis.AxisDependency.LEFT);
|
||||
lineDataSet.setDrawValues(true);
|
||||
lineDataSet.setValueTextSize(10f);
|
||||
lineDataSet.setValueTextColor(CHART_TEXT_COLOR);
|
||||
lineDataSet.setValueFormatter(new ValueFormatter() {
|
||||
@Override
|
||||
public String getFormattedValue(float value) {
|
||||
return String.format(Locale.ROOT, "%d", (int) value);
|
||||
}
|
||||
});
|
||||
return lineDataSet;
|
||||
};
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
@ -241,12 +228,10 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
mTargetValue = goal;
|
||||
}
|
||||
|
||||
mTodayPieChart = rootView.findViewById(R.id.todaystepschart);
|
||||
mWeekChart = rootView.findViewById(R.id.weekstepschart);
|
||||
mBalanceView = rootView.findViewById(R.id.balance);
|
||||
|
||||
setupWeekChart();
|
||||
setupTodayPieChart();
|
||||
|
||||
// refresh immediately instead of use refreshIfVisible(), for perceived performance
|
||||
refresh();
|
||||
@ -254,20 +239,6 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
return rootView;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
protected void setupTodayPieChart() {
|
||||
mTodayPieChart.setBackgroundColor(BACKGROUND_COLOR);
|
||||
mTodayPieChart.getDescription().setTextColor(DESCRIPTION_COLOR);
|
||||
mTodayPieChart.setEntryLabelColor(DESCRIPTION_COLOR);
|
||||
mTodayPieChart.getDescription().setText(getPieDescription(mTargetValue));
|
||||
// mTodayPieChart.setNoDataTextDescription("");
|
||||
mTodayPieChart.setNoDataText("");
|
||||
mTodayPieChart.getLegend().setEnabled(false);
|
||||
}
|
||||
|
||||
protected void setupWeekChart() {
|
||||
mWeekChart.setBackgroundColor(BACKGROUND_COLOR);
|
||||
mWeekChart.getDescription().setTextColor(DESCRIPTION_COLOR);
|
||||
@ -323,29 +294,13 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
return super.getAllSamples(db, device, tsFrom, tsTo);
|
||||
}
|
||||
|
||||
private static class DayData {
|
||||
private final PieData data;
|
||||
private final CharSequence centerText;
|
||||
|
||||
DayData(PieData data, String centerText) {
|
||||
this.data = data;
|
||||
this.centerText = centerText;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MyChartsData extends ChartsData {
|
||||
private final WeekChartsData<BarData> weekBeforeData;
|
||||
private final DayData dayData;
|
||||
|
||||
MyChartsData(DayData dayData, WeekChartsData<BarData> weekBeforeData) {
|
||||
this.dayData = dayData;
|
||||
MyChartsData(WeekChartsData<BarData> weekBeforeData) {
|
||||
this.weekBeforeData = weekBeforeData;
|
||||
}
|
||||
|
||||
DayData getDayData() {
|
||||
return dayData;
|
||||
}
|
||||
|
||||
WeekChartsData<BarData> getWeekBeforeData() {
|
||||
return weekBeforeData;
|
||||
}
|
||||
@ -382,6 +337,11 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
}
|
||||
}
|
||||
|
||||
public boolean supportsSleepScore() {
|
||||
final GBDevice device = getChartsHost().getDevice();
|
||||
return device.getDeviceCoordinator().supportsSleepScore();
|
||||
}
|
||||
|
||||
abstract String getAverage(float value);
|
||||
|
||||
abstract int getGoal();
|
||||
@ -410,14 +370,23 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
|
||||
protected class WeekChartsData<T extends ChartData<?>> extends DefaultChartsData<T> {
|
||||
private final String balanceMessage;
|
||||
private LineData sleepScoresLineData;
|
||||
|
||||
public WeekChartsData(T data, PreformattedXIndexLabelFormatter xIndexLabelFormatter, String balanceMessage) {
|
||||
super(data, xIndexLabelFormatter);
|
||||
this.balanceMessage = balanceMessage;
|
||||
}
|
||||
|
||||
public WeekChartsData(T data, PreformattedXIndexLabelFormatter xIndexLabelFormatter, String balanceMessage, LineData sleepScores) {
|
||||
super(data, xIndexLabelFormatter);
|
||||
this.balanceMessage = balanceMessage;
|
||||
this.sleepScoresLineData = sleepScores;
|
||||
}
|
||||
|
||||
public String getBalanceMessage() {
|
||||
return balanceMessage;
|
||||
}
|
||||
|
||||
public LineData getSleepScoreData() { return sleepScoresLineData; }
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Copyright (C) 2015-2024 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||
Gobbetti, Dikay900, José Rebelo, ozkanpakdil, Pavel Elagin, Petr Vaněk, Q-er
|
||||
Gobbetti, Dikay900, José Rebelo, ozkanpakdil, Pavel Elagin, Petr Vaněk, Q-er, a0z
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@ -23,21 +23,21 @@ import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.github.mikephil.charting.animation.Easing;
|
||||
import com.github.mikephil.charting.charts.Chart;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.charts.PieChart;
|
||||
import com.github.mikephil.charting.components.*;
|
||||
import com.github.mikephil.charting.data.LineData;
|
||||
import com.github.mikephil.charting.data.PieData;
|
||||
import com.github.mikephil.charting.data.PieDataSet;
|
||||
import com.github.mikephil.charting.data.PieEntry;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
import org.slf4j.Logger;
|
||||
@ -52,10 +52,13 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.SleepAnalysis.SleepSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.GaugeDrawer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.SleepScoreSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
@ -64,7 +67,7 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(ActivitySleepChartFragment.class);
|
||||
|
||||
private LineChart mActivityChart;
|
||||
private PieChart mSleepAmountChart;
|
||||
private ImageView sleepStagesGauge;
|
||||
private TextView mSleepchartInfo;
|
||||
private TextView remSleepTimeText;
|
||||
private LinearLayout remSleepTimeTextWrapper;
|
||||
@ -106,8 +109,11 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
} else {
|
||||
samples = getSamplesofSleep(db, device);
|
||||
}
|
||||
|
||||
MySleepChartsData mySleepChartsData = refreshSleepAmounts(device, samples);
|
||||
List<? extends SleepScoreSample> sleepScoreSamples = new ArrayList<>();
|
||||
if (supportsSleepScore()) {
|
||||
sleepScoreSamples = getSleepScoreSamples(db, device, getTSStart(), getTSEnd());
|
||||
}
|
||||
MySleepChartsData mySleepChartsData = refreshSleepAmounts(device, samples, sleepScoreSamples);
|
||||
|
||||
if (!CHARTS_SLEEP_RANGE_24H) {
|
||||
if (mySleepChartsData.sleepSessions.size() > 0) {
|
||||
@ -130,58 +136,22 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
|
||||
|
||||
|
||||
private MySleepChartsData refreshSleepAmounts(GBDevice mGBDevice, List<? extends ActivitySample> samples) {
|
||||
private MySleepChartsData refreshSleepAmounts(GBDevice mGBDevice, List<? extends ActivitySample> samples, List<? extends SleepScoreSample> sleepScoreSamples) {
|
||||
SleepAnalysis sleepAnalysis = new SleepAnalysis();
|
||||
List<SleepSession> sleepSessions = sleepAnalysis.calculateSleepSessions(samples);
|
||||
|
||||
PieData data = new PieData();
|
||||
|
||||
|
||||
final long lightSleepDuration = calculateLightSleepDuration(sleepSessions);
|
||||
final long deepSleepDuration = calculateDeepSleepDuration(sleepSessions);
|
||||
final long remSleepDuration = calculateRemSleepDuration(sleepSessions);
|
||||
final long awakeSleepDuration = calculateAwakeSleepDuration(sleepSessions);
|
||||
final long totalSeconds = lightSleepDuration + deepSleepDuration + remSleepDuration;
|
||||
|
||||
final List<PieEntry> entries = new ArrayList<>();
|
||||
final List<Integer> colors = new ArrayList<>();
|
||||
|
||||
if (!sleepSessions.isEmpty()) {
|
||||
entries.add(new PieEntry(lightSleepDuration, getActivity().getString(R.string.abstract_chart_fragment_kind_light_sleep)));
|
||||
entries.add(new PieEntry(deepSleepDuration, getActivity().getString(R.string.abstract_chart_fragment_kind_deep_sleep)));
|
||||
colors.add(getColorFor(ActivityKind.LIGHT_SLEEP));
|
||||
colors.add(getColorFor(ActivityKind.DEEP_SLEEP));
|
||||
|
||||
if (supportsRemSleep(mGBDevice)) {
|
||||
entries.add(new PieEntry(remSleepDuration, getActivity().getString(R.string.abstract_chart_fragment_kind_rem_sleep)));
|
||||
colors.add(getColorFor(ActivityKind.REM_SLEEP));
|
||||
int sleepScore = 0;
|
||||
if (!sleepScoreSamples.isEmpty()) {
|
||||
sleepScore = sleepScoreSamples.get(0).getSleepScore();
|
||||
}
|
||||
|
||||
if (supportsAwakeSleep(mGBDevice)) {
|
||||
entries.add(new PieEntry(awakeSleepDuration, getActivity().getString(R.string.abstract_chart_fragment_kind_awake_sleep)));
|
||||
colors.add(getColorFor(ActivityKind.AWAKE_SLEEP));
|
||||
}
|
||||
} else {
|
||||
entries.add(new PieEntry(1));
|
||||
colors.add(getResources().getColor(R.color.gauge_line_color));
|
||||
}
|
||||
|
||||
PieDataSet set = new PieDataSet(entries, "");
|
||||
set.setSliceSpace(2f);
|
||||
set.setColors(colors);
|
||||
set.setValueTextColor(DESCRIPTION_COLOR);
|
||||
set.setValueTextSize(13f);
|
||||
set.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
|
||||
set.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
|
||||
data.setDataSet(set);
|
||||
|
||||
String totalSleep = DateTimeUtils.formatDurationHoursMinutes(totalSeconds, TimeUnit.SECONDS);
|
||||
String totalAwake = DateTimeUtils.formatDurationHoursMinutes(awakeSleepDuration, TimeUnit.SECONDS);
|
||||
String totalRem = DateTimeUtils.formatDurationHoursMinutes(remSleepDuration, TimeUnit.SECONDS);
|
||||
String totalDeep = DateTimeUtils.formatDurationHoursMinutes(deepSleepDuration, TimeUnit.SECONDS);
|
||||
String totalLight = DateTimeUtils.formatDurationHoursMinutes(lightSleepDuration, TimeUnit.SECONDS);
|
||||
//setupLegend(pieChart);
|
||||
return new MySleepChartsData(data, sleepSessions, totalSleep, totalAwake, totalRem, totalDeep, totalLight);
|
||||
return new MySleepChartsData(sleepSessions, totalSeconds, awakeSleepDuration, remSleepDuration, deepSleepDuration, lightSleepDuration, sleepScore);
|
||||
}
|
||||
|
||||
private long calculateLightSleepDuration(List<SleepSession> sleepSessions) {
|
||||
@ -216,6 +186,45 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void sleepStagesGaugeUpdate(MySleepChartsData pieData) {
|
||||
int[] colors = new int[] {
|
||||
ContextCompat.getColor(GBApplication.getContext(), R.color.chart_light_sleep_light),
|
||||
ContextCompat.getColor(GBApplication.getContext(), R.color.chart_deep_sleep_light),
|
||||
ContextCompat.getColor(GBApplication.getContext(), R.color.chart_rem_sleep_light),
|
||||
ContextCompat.getColor(GBApplication.getContext(), R.color.chart_awake_sleep_light),
|
||||
};
|
||||
long total = pieData.getTotalSleep() + pieData.getTotalAwake();
|
||||
float[] segments = new float[] {
|
||||
pieData.getTotalLight() > 0 ? (float) pieData.getTotalLight() / total : 0,
|
||||
pieData.getTotalDeep() > 0 ? (float) pieData.getTotalDeep() / total : 0,
|
||||
pieData.getTotalRem() > 0 ? (float) pieData.getTotalRem() / total : 0,
|
||||
pieData.getTotalAwake() > 0 ? (float) pieData.getTotalAwake() / total : 0,
|
||||
};
|
||||
final int width = (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
300,
|
||||
GBApplication.getContext().getResources().getDisplayMetrics()
|
||||
);
|
||||
String lowerText = "";
|
||||
if (supportsSleepScore()) {
|
||||
lowerText = GBApplication.getContext().getString(R.string.sleep_score_value, pieData.getSleepScore());
|
||||
}
|
||||
sleepStagesGauge.setImageBitmap(GaugeDrawer.drawCircleGaugeSegmented(
|
||||
width,
|
||||
width / 15,
|
||||
colors,
|
||||
segments,
|
||||
true,
|
||||
String.valueOf(timeStringFormat(pieData.getTotalSleep())),
|
||||
lowerText,
|
||||
getContext()
|
||||
));
|
||||
}
|
||||
|
||||
private String timeStringFormat(long seconds) {
|
||||
return DateTimeUtils.formatDurationHoursMinutes(seconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChartsnUIThread(MyChartsData mcd) {
|
||||
MySleepChartsData pieData = mcd.getPieData();
|
||||
@ -224,15 +233,13 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
String formattedDate = new SimpleDateFormat("E, MMM dd").format(date);
|
||||
sleepDateText.setText(formattedDate);
|
||||
|
||||
pieData.pieData.setDrawValues(false);
|
||||
mSleepAmountChart.setTouchEnabled(false);
|
||||
mSleepAmountChart.setCenterTextColor(GBApplication.getTextColor(getContext()));
|
||||
mSleepAmountChart.setCenterText(pieData.getTotalSleep());
|
||||
sleepStagesGaugeUpdate(pieData);
|
||||
|
||||
if (!pieData.sleepSessions.isEmpty()) {
|
||||
awakeSleepTimeText.setText(pieData.getTotalAwake());
|
||||
remSleepTimeText.setText(pieData.getTotalRem());
|
||||
deepSleepTimeText.setText(pieData.getTotalDeep());
|
||||
lightSleepTimeText.setText(pieData.getTotalLight());
|
||||
awakeSleepTimeText.setText(timeStringFormat(pieData.getTotalAwake()));
|
||||
remSleepTimeText.setText(timeStringFormat(pieData.getTotalRem()));
|
||||
deepSleepTimeText.setText(timeStringFormat(pieData.getTotalDeep()));
|
||||
lightSleepTimeText.setText(timeStringFormat(pieData.getTotalLight()));
|
||||
} else {
|
||||
awakeSleepTimeText.setText("-");
|
||||
remSleepTimeText.setText("-");
|
||||
@ -245,9 +252,6 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
if (!supportsAwakeSleep(getChartsHost().getDevice())) {
|
||||
awakeSleepTimeTextWrapper.setVisibility(View.GONE);
|
||||
}
|
||||
mSleepAmountChart.setCenterTextSize(18f);
|
||||
mSleepAmountChart.setHoleColor(getContext().getResources().getColor(R.color.transparent));
|
||||
mSleepAmountChart.setData(pieData.getPieData());
|
||||
mSleepchartInfo.setText(buildYouSleptText(pieData));
|
||||
mSleepchartInfo.setMovementMethod(new ScrollingMovementMethod());
|
||||
mActivityChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317
|
||||
@ -264,10 +268,6 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
movementIntensityTextWrapper.setVisibility(intensityTotal > 0 ? View.VISIBLE : View.GONE);
|
||||
dummyTile.setVisibility(intensityTotal > 0 ? View.VISIBLE : View.GONE);
|
||||
|
||||
mSleepAmountChart.setHoleRadius(85);
|
||||
mSleepAmountChart.setDrawEntryLabels(false);
|
||||
mSleepAmountChart.getLegend().setEnabled(false);
|
||||
|
||||
if (!CHARTS_SLEEP_RANGE_24H
|
||||
&& supportsHeartrate(getChartsHost().getDevice())
|
||||
&& SHOW_CHARTS_AVERAGE) {
|
||||
@ -366,6 +366,11 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public boolean supportsSleepScore() {
|
||||
final GBDevice device = getChartsHost().getDevice();
|
||||
return device.getDeviceCoordinator().supportsSleepScore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return getString(R.string.sleepchart_your_sleep);
|
||||
@ -383,7 +388,7 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
}
|
||||
|
||||
mActivityChart = rootView.findViewById(R.id.sleepchart);
|
||||
mSleepAmountChart = rootView.findViewById(R.id.sleepchart_pie_light_deep);
|
||||
sleepStagesGauge = rootView.findViewById(R.id.sleep_stages_gauge);
|
||||
mSleepchartInfo = rootView.findViewById(R.id.sleepchart_info);
|
||||
remSleepTimeText = rootView.findViewById(R.id.sleep_chart_legend_rem_time);
|
||||
remSleepTimeTextWrapper = rootView.findViewById(R.id.sleep_chart_legend_rem_time_wrapper);
|
||||
@ -401,7 +406,6 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
mSleepchartInfo.setMaxLines(sleepLinesLimit);
|
||||
|
||||
setupActivityChart();
|
||||
setupSleepAmountChart();
|
||||
|
||||
// refresh immediately instead of use refreshIfVisible(), for perceived performance
|
||||
refresh();
|
||||
@ -424,16 +428,6 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
}
|
||||
}
|
||||
|
||||
private void setupSleepAmountChart() {
|
||||
mSleepAmountChart.setBackgroundColor(BACKGROUND_COLOR);
|
||||
mSleepAmountChart.getDescription().setTextColor(DESCRIPTION_COLOR);
|
||||
mSleepAmountChart.setEntryLabelColor(DESCRIPTION_COLOR);
|
||||
mSleepAmountChart.getDescription().setText("");
|
||||
// mSleepAmountChart.getDescription().setNoDataTextDescription("");
|
||||
mSleepAmountChart.setNoDataText("");
|
||||
mSleepAmountChart.getLegend().setEnabled(false);
|
||||
}
|
||||
|
||||
private void setupActivityChart() {
|
||||
mActivityChart.setBackgroundColor(BACKGROUND_COLOR);
|
||||
mActivityChart.getDescription().setTextColor(DESCRIPTION_COLOR);
|
||||
@ -448,14 +442,10 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
|
||||
YAxis y = mActivityChart.getAxisLeft();
|
||||
y.setDrawGridLines(false);
|
||||
// y.setDrawLabels(false);
|
||||
// TODO: make fixed max value optional
|
||||
y.setAxisMaximum(1f);
|
||||
y.setAxisMinimum(0);
|
||||
y.setDrawTopYLabelEntry(false);
|
||||
y.setTextColor(CHART_TEXT_COLOR);
|
||||
|
||||
// y.setLabelCount(5);
|
||||
y.setEnabled(true);
|
||||
|
||||
YAxis yAxisRight = mActivityChart.getAxisRight();
|
||||
@ -513,59 +503,61 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
|
||||
|
||||
@Override
|
||||
protected List<? extends ActivitySample> getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
|
||||
// temporary fix for totally wrong sleep amounts
|
||||
// Temporary fix for totally wrong sleep amounts.
|
||||
return super.getAllSamples(db, device, tsFrom, tsTo);
|
||||
}
|
||||
|
||||
protected List<SleepScoreSample> getSleepScoreSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
|
||||
TimeSampleProvider<? extends SleepScoreSample> provider = device.getDeviceCoordinator().getSleepScoreProvider(device, db.getDaoSession());
|
||||
return (List<SleepScoreSample>) provider.getAllSamples(tsFrom * 1000L, tsTo * 1000L);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderCharts() {
|
||||
mActivityChart.animateX(ANIM_TIME, Easing.EaseInOutQuart);
|
||||
mSleepAmountChart.invalidate();
|
||||
}
|
||||
|
||||
private static class MySleepChartsData extends ChartsData {
|
||||
private String totalSleep;
|
||||
private String totalAwake;
|
||||
private String totalRem;
|
||||
private String totalDeep;
|
||||
private String totalLight;
|
||||
private final PieData pieData;
|
||||
private long totalSleep;
|
||||
private long totalAwake;
|
||||
private long totalRem;
|
||||
private long totalDeep;
|
||||
private long totalLight;
|
||||
private int sleepScore;
|
||||
private final List<SleepSession> sleepSessions;
|
||||
|
||||
public MySleepChartsData(PieData pieData, List<SleepSession> sleepSessions, String totalSleep, String totalAwake, String totalRem, String totalDeep, String totalLight) {
|
||||
this.pieData = pieData;
|
||||
public MySleepChartsData(List<SleepSession> sleepSessions, long totalSleep, long totalAwake, long totalRem, long totalDeep, long totalLight, int sleepScore) {
|
||||
this.sleepSessions = sleepSessions;
|
||||
this.totalAwake = totalAwake;
|
||||
this.totalSleep = totalSleep;
|
||||
this.totalRem = totalRem;
|
||||
this.totalDeep = totalDeep;
|
||||
this.totalLight = totalLight;
|
||||
this.sleepScore = sleepScore;
|
||||
}
|
||||
|
||||
public PieData getPieData() {
|
||||
return pieData;
|
||||
}
|
||||
|
||||
public CharSequence getTotalSleep() {
|
||||
public long getTotalSleep() {
|
||||
return totalSleep;
|
||||
}
|
||||
|
||||
public CharSequence getTotalAwake() {
|
||||
public long getTotalAwake() {
|
||||
return totalAwake;
|
||||
}
|
||||
|
||||
public CharSequence getTotalRem() {
|
||||
public long getTotalRem() {
|
||||
return totalRem;
|
||||
}
|
||||
|
||||
public CharSequence getTotalDeep() {
|
||||
public long getTotalDeep() {
|
||||
return totalDeep;
|
||||
}
|
||||
|
||||
public CharSequence getTotalLight() {
|
||||
public long getTotalLight() {
|
||||
return totalLight;
|
||||
}
|
||||
|
||||
public int getSleepScore() {return sleepScore;}
|
||||
|
||||
public List<SleepSession> getSleepSessions() {
|
||||
return sleepSessions;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Copyright (C) 2017-2024 Andreas Shimokawa, Carsten Pfeiffer, José Rebelo,
|
||||
Pavel Elagin, Petr Vaněk
|
||||
Pavel Elagin, Petr Vaněk, a0z
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@ -25,8 +25,11 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.mikephil.charting.charts.Chart;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.components.Legend;
|
||||
import com.github.mikephil.charting.components.LegendEntry;
|
||||
import com.github.mikephil.charting.components.XAxis;
|
||||
import com.github.mikephil.charting.components.YAxis;
|
||||
import com.github.mikephil.charting.data.BarData;
|
||||
import com.github.mikephil.charting.formatter.ValueFormatter;
|
||||
|
||||
@ -60,6 +63,8 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
|
||||
private TextView lightSleepTimeText;
|
||||
private TextView sleepDatesText;
|
||||
private MySleepWeeklyData mySleepWeeklyData;
|
||||
private LinearLayout sleepScoreWrapper;
|
||||
private LineChart sleepScoreChart;
|
||||
|
||||
public static WeekSleepChartFragment newInstance ( int totalDays ) {
|
||||
WeekSleepChartFragment fragmentFirst = new WeekSleepChartFragment();
|
||||
@ -118,6 +123,8 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
|
||||
}
|
||||
|
||||
mWeekChart = rootView.findViewById(R.id.weekstepschart);
|
||||
sleepScoreWrapper = rootView.findViewById(R.id.sleep_score_wrapper);
|
||||
sleepScoreChart = rootView.findViewById(R.id.sleep_score_chart);
|
||||
remSleepTimeText = rootView.findViewById(R.id.sleep_chart_legend_rem_time);
|
||||
remSleepTimeTextWrapper = rootView.findViewById(R.id.sleep_chart_legend_rem_time_wrapper);
|
||||
awakeSleepTimeText = rootView.findViewById(R.id.sleep_chart_legend_awake_time);
|
||||
@ -128,8 +135,13 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
|
||||
|
||||
mBalanceView = rootView.findViewById(R.id.balance);
|
||||
|
||||
setupWeekChart();
|
||||
if (!supportsSleepScore()) {
|
||||
sleepScoreWrapper.setVisibility(View.GONE);
|
||||
} else {
|
||||
setupSleepScoreChart();
|
||||
}
|
||||
|
||||
setupWeekChart();
|
||||
// refresh immediately instead of use refreshIfVisible(), for perceived performance
|
||||
refresh();
|
||||
|
||||
@ -155,6 +167,13 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
|
||||
mWeekChart.getXAxis().setValueFormatter(mcd.getWeekBeforeData().getXValueFormatter());
|
||||
mWeekChart.getBarData().setValueTextSize(10f);
|
||||
|
||||
if (supportsSleepScore()) {
|
||||
sleepScoreChart.setData(null);
|
||||
sleepScoreChart.getXAxis().setValueFormatter(mcd.getWeekBeforeData().getXValueFormatter());
|
||||
sleepScoreChart.getLegend().setTextColor(LEGEND_TEXT_COLOR);
|
||||
sleepScoreChart.setData(mcd.getWeekBeforeData().getSleepScoreData());
|
||||
}
|
||||
|
||||
// The last value is for awake time, which we do not want to include in the "total sleep time"
|
||||
final int barIgnoreLast = supportsAwakeSleep(getChartsHost().getDevice()) ? 1 : 0;
|
||||
mWeekChart.getBarData().setValueFormatter(new BarChartStackedTimeValueFormatter(false, "", 0, barIgnoreLast));
|
||||
@ -200,12 +219,48 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
|
||||
WeekChartsData<BarData> weekBeforeData = refreshWeekBeforeData(db, mWeekChart, day, device);
|
||||
mySleepWeeklyData = getMySleepWeeklyData(db, day, device);
|
||||
|
||||
return new MyChartsData(null, weekBeforeData);
|
||||
return new MyChartsData(weekBeforeData);
|
||||
}
|
||||
|
||||
private void setupSleepScoreChart() {
|
||||
final XAxis xAxisBottom = sleepScoreChart.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(TOTAL_DAYS-1);
|
||||
xAxisBottom.setGranularity(1f);
|
||||
xAxisBottom.setGranularityEnabled(true);
|
||||
|
||||
final YAxis yAxisLeft = sleepScoreChart.getAxisLeft();
|
||||
yAxisLeft.setDrawGridLines(true);
|
||||
yAxisLeft.setAxisMaximum(100);
|
||||
yAxisLeft.setAxisMinimum(0);
|
||||
yAxisLeft.setDrawTopYLabelEntry(true);
|
||||
yAxisLeft.setEnabled(true);
|
||||
yAxisLeft.setTextColor(CHART_TEXT_COLOR);
|
||||
|
||||
final YAxis yAxisRight = sleepScoreChart.getAxisRight();
|
||||
yAxisRight.setEnabled(true);
|
||||
yAxisRight.setDrawLabels(false);
|
||||
yAxisRight.setDrawGridLines(false);
|
||||
yAxisRight.setDrawAxisLine(true);
|
||||
|
||||
sleepScoreChart.setDoubleTapToZoomEnabled(false);
|
||||
sleepScoreChart.getDescription().setEnabled(false);
|
||||
if (TOTAL_DAYS <= 7) {
|
||||
sleepScoreChart.setScaleEnabled(false);
|
||||
sleepScoreChart.setTouchEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderCharts() {
|
||||
mWeekChart.invalidate();
|
||||
sleepScoreChart.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -227,6 +227,19 @@ public class GaugeDrawer {
|
||||
paint);
|
||||
paint.setStrokeWidth(barWidth);
|
||||
|
||||
float remainingAngle = 360;
|
||||
float gapDegree = 1f;
|
||||
if (gapBetweenSegments) {
|
||||
int validSegments = segments.length;
|
||||
for (int i = 0; i < segments.length; i++) {
|
||||
if (segments[i] == 0) {
|
||||
validSegments--;
|
||||
}
|
||||
}
|
||||
|
||||
remainingAngle = 360 - (validSegments * gapDegree);
|
||||
}
|
||||
|
||||
float angleSum = 0;
|
||||
for (int i = 0; i < segments.length; i++) {
|
||||
if (segments[i] == 0) {
|
||||
@ -236,12 +249,8 @@ public class GaugeDrawer {
|
||||
paint.setColor(colors[i]);
|
||||
paint.setStrokeWidth(barWidth);
|
||||
|
||||
float startAngleDegrees = 270 + angleSum * 360;
|
||||
float sweepAngleDegrees = segments[i] * 360;
|
||||
|
||||
if (gapBetweenSegments) {
|
||||
sweepAngleDegrees -= 1;
|
||||
}
|
||||
float startAngleDegrees = 270 + (angleSum * remainingAngle);
|
||||
float sweepAngleDegrees = segments[i] * remainingAngle;
|
||||
|
||||
canvas.drawArc(
|
||||
barMargin,
|
||||
@ -254,6 +263,9 @@ public class GaugeDrawer {
|
||||
paint
|
||||
);
|
||||
angleSum += segments[i];
|
||||
if (gapBetweenSegments) {
|
||||
angleSum += (gapDegree / 360f);
|
||||
}
|
||||
}
|
||||
|
||||
Paint textPaint = new Paint();
|
||||
|
@ -23,13 +23,15 @@
|
||||
android:text="@string/stats_empty_value"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<com.github.mikephil.charting.charts.PieChart
|
||||
android:id="@+id/sleepchart_pie_light_deep"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="200dp"
|
||||
<ImageView
|
||||
android:layout_weight="2"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_weight="2" />
|
||||
android:id="@+id/sleep_stages_gauge"
|
||||
android:layout_width="180dp"
|
||||
android:layout_height="180dp"
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="fitStart" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -161,6 +161,28 @@
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="350dp"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:id="@+id/sleep_score_wrapper"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<TextView
|
||||
android:layout_marginStart="18dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:textSize="20sp"
|
||||
android:text="@string/sleep_score"
|
||||
/>
|
||||
<com.github.mikephil.charting.charts.LineChart
|
||||
android:id="@+id/sleep_score_chart"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="350dp"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -1022,6 +1022,8 @@
|
||||
<string name="sleep_avg">Sleep AVG</string>
|
||||
<string name="lowest">Lowest</string>
|
||||
<string name="highest">Highest</string>
|
||||
<string name="sleep_score">Sleep score</string>
|
||||
<string name="sleep_score_value">Score: %1d</string>
|
||||
<string name="stats_empty_value">-</string>
|
||||
<string name="time_empty_value" translatable="false">--:--</string>
|
||||
<string name="date_placeholders__date__time">%1s, %1s</string>
|
||||
|
Loading…
Reference in New Issue
Block a user