Refactor sleep chart fragments

This commit is contained in:
trentsuzuki
2025-05-24 14:46:50 +02:00
committed by José Rebelo
parent bb2ba155cc
commit 6a88e43ac6
9 changed files with 391 additions and 107 deletions
@@ -55,6 +55,11 @@ public class CaloriesPeriodFragment extends CaloriesFragment<CaloriesPeriodFragm
protected int BACKGROUND_COLOR;
protected int DESCRIPTION_COLOR;
@Override
protected boolean isSingleDay() {
return false;
}
public static CaloriesPeriodFragment newInstance(int totalDays) {
CaloriesPeriodFragment fragmentFirst = new CaloriesPeriodFragment();
Bundle args = new Bundle();
@@ -70,6 +70,11 @@ public class HeartRatePeriodFragment extends AbstractChartFragment<HeartRatePeri
private LineChart hrLineChart;
private int TOTAL_DAYS;
@Override
protected boolean isSingleDay() {
return false;
}
public static HeartRatePeriodFragment newInstance(int totalDays) {
HeartRatePeriodFragment fragmentFirst = new HeartRatePeriodFragment();
Bundle args = new Bundle();
@@ -43,6 +43,11 @@ public class RespiratoryRatePeriodFragment extends RespiratoryRateFragment<Respi
private TextView awakeAvg;
private LineChart respiratoryRateChart;
@Override
protected boolean isSingleDay() {
return false;
}
public static RespiratoryRatePeriodFragment newInstance (int totalDays) {
RespiratoryRatePeriodFragment fragmentFirst = new RespiratoryRatePeriodFragment();
Bundle args = new Bundle();
@@ -45,7 +45,13 @@ import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
@@ -59,12 +65,13 @@ 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.service.devices.sony.wena3.protocol.packets.notification.defines.LedColor;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySleepChartFragment.MyChartsData> {
protected static final Logger LOG = LoggerFactory.getLogger(DaySleepChartFragment.class);
public class SleepDailyFragment extends SleepFragment<SleepDailyFragment.MyChartsData> {
protected static final Logger LOG = LoggerFactory.getLogger(SleepDailyFragment.class);
private LineChart mActivityChart;
private ImageView sleepStagesGauge;
@@ -134,8 +141,6 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
return new MyChartsData(mySleepChartsData, chartsData, hrData.getLeft(), hrData.getMiddle(), hrData.getRight(), intensityData.getLeft(), intensityData.getMiddle(), intensityData.getRight());
}
private MySleepChartsData refreshSleepAmounts(GBDevice mGBDevice, List<? extends ActivitySample> samples, List<? extends SleepScoreSample> sleepScoreSamples) {
SleepAnalysis sleepAnalysis = new SleepAnalysis();
List<SleepSession> sleepSessions = sleepAnalysis.calculateSleepSessions(samples);
@@ -364,15 +369,7 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
return result.toString();
}
public boolean supportsSleepScore() {
final GBDevice device = getChartsHost().getDevice();
return device.getDeviceCoordinator().supportsSleepScore(device);
}
@Override
public String getTitle() {
return getString(R.string.sleepchart_your_sleep);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -457,30 +454,7 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
@Override
protected void setupLegend(Chart<?> chart) {
List<LegendEntry> legendEntries = new ArrayList<>(4);
LegendEntry lightSleepEntry = new LegendEntry();
lightSleepEntry.label = getActivity().getString(R.string.sleep_colored_stats_light);
lightSleepEntry.formColor = akLightSleep.color;
legendEntries.add(lightSleepEntry);
LegendEntry deepSleepEntry = new LegendEntry();
deepSleepEntry.label = getActivity().getString(R.string.sleep_colored_stats_deep);
deepSleepEntry.formColor = akDeepSleep.color;
legendEntries.add(deepSleepEntry);
if (supportsRemSleep(getChartsHost().getDevice())) {
LegendEntry remSleepEntry = new LegendEntry();
remSleepEntry.label = getActivity().getString(R.string.sleep_colored_stats_rem);
remSleepEntry.formColor = akRemSleep.color;
legendEntries.add(remSleepEntry);
}
if (supportsAwakeSleep(getChartsHost().getDevice())) {
LegendEntry awakeSleepEntry = new LegendEntry();
awakeSleepEntry.label = getActivity().getString(R.string.abstract_chart_fragment_kind_awake_sleep);
awakeSleepEntry.formColor = akAwakeSleep.color;
legendEntries.add(awakeSleepEntry);
}
List<LegendEntry> legendEntries = super.createLegendEntries(chart);
if (supportsHeartrate(getChartsHost().getDevice())) {
LegendEntry hrEntry = new LegendEntry();
@@ -498,17 +472,6 @@ public class DaySleepChartFragment extends AbstractActivityChartFragment<DaySlee
chart.getLegend().setTextColor(LEGEND_TEXT_COLOR);
}
@Override
protected List<? extends ActivitySample> getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
// 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);
@@ -0,0 +1,82 @@
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.components.LegendEntry;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
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.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.SleepScoreSample;
abstract class SleepFragment<D extends ChartsData> extends AbstractActivityChartFragment<D> {
@Override
public String getTitle() {
return getString(R.string.sleepchart_your_sleep);
}
@Override
protected List<? extends ActivitySample> getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
return super.getAllSamples(db, device, tsFrom, tsTo);
}
public boolean supportsSleepScore() {
final GBDevice device = getChartsHost().getDevice();
return device.getDeviceCoordinator().supportsSleepScore(device);
}
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);
}
protected List<SleepScoreSample> getSleepScoreSamples(DBHandler db, GBDevice device, Calendar day) {
int startTs;
int endTs;
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;
TimeSampleProvider<? extends SleepScoreSample> provider = device.getDeviceCoordinator().getSleepScoreProvider(device, db.getDaoSession());
return (List<SleepScoreSample>) provider.getAllSamples(startTs * 1000L, endTs * 1000L);
}
protected List<LegendEntry> createLegendEntries(Chart<?> chart) {
List<LegendEntry> legendEntries = new ArrayList<>(4);
LegendEntry lightSleepEntry = new LegendEntry();
lightSleepEntry.label = getActivity().getString(R.string.sleep_colored_stats_light);
lightSleepEntry.formColor = akLightSleep.color;
legendEntries.add(lightSleepEntry);
LegendEntry deepSleepEntry = new LegendEntry();
deepSleepEntry.label = getActivity().getString(R.string.sleep_colored_stats_deep);
deepSleepEntry.formColor = akDeepSleep.color;
legendEntries.add(deepSleepEntry);
if (supportsRemSleep(getChartsHost().getDevice())) {
LegendEntry remSleepEntry = new LegendEntry();
remSleepEntry.label = getActivity().getString(R.string.sleep_colored_stats_rem);
remSleepEntry.formColor = akRemSleep.color;
legendEntries.add(remSleepEntry);
}
if (supportsAwakeSleep(getChartsHost().getDevice())) {
LegendEntry awakeSleepEntry = new LegendEntry();
awakeSleepEntry.label = getActivity().getString(R.string.abstract_chart_fragment_kind_awake_sleep);
awakeSleepEntry.formColor = akAwakeSleep.color;
legendEntries.add(awakeSleepEntry);
}
return legendEntries;
}
}
@@ -17,6 +17,8 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
import android.app.Activity;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -25,24 +27,35 @@ import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.github.mikephil.charting.charts.BarChart;
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.LimitLine;
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.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.ChartData;
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 nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import org.apache.commons.lang3.ArrayUtils;
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.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
@@ -50,11 +63,17 @@ import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmount;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmounts;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.SleepScoreSample;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
public class WeekSleepChartFragment extends AbstractWeekChartFragment {
public class SleepPeriodFragment extends SleepFragment<SleepPeriodFragment.MyChartsData> {
protected static final Logger LOG = LoggerFactory.getLogger(SleepPeriodFragment.class);
protected int TOTAL_DAYS = getRangeDays();
protected int TOTAL_DAYS_FOR_AVERAGE = 0;
private TextView awakeSleepTimeText;
private LinearLayout awakeSleepTimeTextWrapper;
private TextView remSleepTimeText;
@@ -67,11 +86,16 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
private LineChart sleepScoreChart;
private TextView mBalanceView;
protected Locale mLocale;
protected int mTargetValue = 0;
protected BarChart mWeekChart;
private final int mOffsetHours = getOffsetHours();
protected boolean SHOW_BALANCE;
public static WeekSleepChartFragment newInstance ( int totalDays ) {
WeekSleepChartFragment fragmentFirst = new WeekSleepChartFragment();
public static SleepPeriodFragment newInstance(int totalDays) {
SleepPeriodFragment fragmentFirst = new SleepPeriodFragment();
Bundle args = new Bundle();
args.putInt("totalDays", totalDays);
fragmentFirst.setArguments(args);
@@ -167,7 +191,38 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
}
protected void setupWeekChart() {
super.setupWeekChart();
mWeekChart.setBackgroundColor(BACKGROUND_COLOR);
mWeekChart.getDescription().setTextColor(DESCRIPTION_COLOR);
mWeekChart.getDescription().setText("");
mWeekChart.setFitBars(true);
configureBarLineChartDefaults(mWeekChart);
XAxis x = mWeekChart.getXAxis();
x.setDrawLabels(true);
x.setDrawGridLines(false);
x.setEnabled(true);
x.setTextColor(CHART_TEXT_COLOR);
x.setDrawLimitLinesBehindData(true);
x.setPosition(XAxis.XAxisPosition.BOTTOM);
YAxis y = mWeekChart.getAxisLeft();
y.setDrawGridLines(false);
y.setDrawTopYLabelEntry(false);
y.setTextColor(CHART_TEXT_COLOR);
y.setDrawZeroLine(true);
y.setSpaceBottom(0);
y.setAxisMinimum(0);
y.setValueFormatter(getYAxisFormatter());
y.setEnabled(true);
YAxis yAxisRight = mWeekChart.getAxisRight();
yAxisRight.setDrawGridLines(false);
yAxisRight.setEnabled(false);
yAxisRight.setDrawLabels(false);
yAxisRight.setDrawTopYLabelEntry(false);
yAxisRight.setTextColor(CHART_TEXT_COLOR);
if (TOTAL_DAYS > 7) {
mWeekChart.setRenderer(new AngledLabelsChartRenderer(mWeekChart, mWeekChart.getAnimator(), mWeekChart.getViewPortHandler()));
} else {
@@ -236,6 +291,129 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
return new MyChartsData(weekBeforeData);
}
protected WeekChartsData<BarData> refreshWeekBeforeData(DBHandler db, BarChart barChart, Calendar day, GBDevice device) {
day = (Calendar) day.clone(); // do not modify the caller's argument
day.add(Calendar.DATE, -TOTAL_DAYS + 1);
List<BarEntry> entries = new ArrayList<>();
ArrayList<String> labels = new ArrayList<String>();
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());
set.setValueFormatter(getBarValueFormatter());
BarData barData = new BarData(set);
barData.setValueTextColor(Color.GRAY); //prevent tearing other graph elements with the black text. Another approach would be to hide the values cmpletely with data.setDrawValues(false);
barData.setValueTextSize(10f);
barChart.getAxisLeft().setAxisMaximum(Math.max(set.getYMax(), mTargetValue) + 60);
LimitLine target = new LimitLine(mTargetValue);
target.setLineWidth(1.5f);
target.enableDashedLine(15f, 10f, 0f);
target.setLineColor(getResources().getColor(R.color.chart_deep_sleep_dark));
barChart.getAxisLeft().removeAllLimitLines();
barChart.getAxisLeft().addLimitLine(target);
float average = 0;
if (TOTAL_DAYS_FOR_AVERAGE > 0) {
average = Math.abs(balance / TOTAL_DAYS_FOR_AVERAGE);
}
LimitLine average_line = new LimitLine(average);
average_line.setLineWidth(1.5f);
average_line.enableDashedLine(15f, 10f, 0f);
average_line.setLabel(getString(R.string.average, getAverage(average)));
if (average > (mTargetValue)) {
average_line.setLineColor(Color.GREEN);
average_line.setTextColor(Color.GREEN);
}
else {
average_line.setLineColor(Color.RED);
average_line.setTextColor(Color.RED);
}
if (average > 0) {
if (GBApplication.getPrefs().getBoolean("charts_show_average", true)) {
barChart.getAxisLeft().addLimitLine(average_line);
}
}
if (supportsSleepScore()) {
return new WeekChartsData(barData, new PreformattedXIndexLabelFormatter(labels), getBalanceMessage(balance, mTargetValue), sleepScoreLineData);
}
return new WeekChartsData(barData, new PreformattedXIndexLabelFormatter(labels), getBalanceMessage(balance, mTargetValue));
}
protected String getWeeksChartsLabel(Calendar day){
if (TOTAL_DAYS > 7) {
//month, show day date
return String.valueOf(day.get(Calendar.DAY_OF_MONTH));
}
else{
//week, show short day name
return day.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, mLocale);
}
}
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;
};
private void setupSleepScoreChart() {
final XAxis xAxisBottom = sleepScoreChart.getXAxis();
xAxisBottom.setPosition(XAxis.XAxisPosition.BOTTOM);
@@ -287,23 +465,19 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
}
}
@Override
String getPieDescription(int targetValue) {
return getString(R.string.weeksleepchart_today_sleep_description, DateTimeUtils.formatDurationHoursMinutes(targetValue, TimeUnit.MINUTES));
}
@Override
int getGoal() {
return GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_SLEEP_DURATION, 8) * 60;
}
@Override
int getOffsetHours() {
return -12;
}
@Override
protected long calculateBalance(ActivityAmounts activityAmounts) {
long balance = 0;
@@ -317,7 +491,6 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
return (int) (balance / 60);
}
@Override
protected String getBalanceMessage(long balance, int targetValue) {
if (balance > 0) {
final long totalBalance = balance - ((long)targetValue * TOTAL_DAYS_FOR_AVERAGE);
@@ -329,7 +502,6 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
return getString(R.string.no_data);
}
@Override
float[] getTotalsForActivityAmounts(ActivityAmounts activityAmounts) {
long totalSecondsDeepSleep = 0;
long totalSecondsLightSleep = 0;
@@ -362,12 +534,10 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
return activityAmountsTotals;
}
@Override
protected String formatPieValue(long value) {
return DateTimeUtils.formatDurationHoursMinutes(value, TimeUnit.MINUTES);
}
@Override
String[] getPieLabels() {
String[] labels = {
getString(R.string.abstract_chart_fragment_kind_deep_sleep),
@@ -382,7 +552,6 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
return labels;
}
@Override
ValueFormatter getPieValueFormatter() {
return new ValueFormatter() {
@Override
@@ -392,7 +561,6 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
};
}
@Override
ValueFormatter getBarValueFormatter() {
return new ValueFormatter() {
@Override
@@ -402,7 +570,6 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
};
}
@Override
ValueFormatter getYAxisFormatter() {
return new ValueFormatter() {
@Override
@@ -412,7 +579,6 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
};
}
@Override
int[] getColors() {
int[] colors = {akDeepSleep.color, akLightSleep.color};
if (supportsRemSleep(getChartsHost().getDevice())) {
@@ -426,33 +592,9 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
@Override
protected void setupLegend(Chart<?> chart) {
List<LegendEntry> legendEntries = new ArrayList<>(2);
LegendEntry lightSleepEntry = new LegendEntry();
lightSleepEntry.label = getActivity().getString(R.string.sleep_colored_stats_light);
lightSleepEntry.formColor = akLightSleep.color;
legendEntries.add(lightSleepEntry);
LegendEntry deepSleepEntry = new LegendEntry();
deepSleepEntry.label = getActivity().getString(R.string.sleep_colored_stats_deep);
deepSleepEntry.formColor = akDeepSleep.color;
legendEntries.add(deepSleepEntry);
if (supportsRemSleep(getChartsHost().getDevice())) {
LegendEntry remSleepEntry = new LegendEntry();
remSleepEntry.label = getActivity().getString(R.string.sleep_colored_stats_rem);
remSleepEntry.formColor = akRemSleep.color;
legendEntries.add(remSleepEntry);
}
if (supportsAwakeSleep(getChartsHost().getDevice())) {
LegendEntry awakeSleepEntry = new LegendEntry();
awakeSleepEntry.label = getActivity().getString(R.string.abstract_chart_fragment_kind_awake_sleep);
awakeSleepEntry.formColor = akAwakeSleep.color;
legendEntries.add(awakeSleepEntry);
}
List<LegendEntry> legendEntries = super.createLegendEntries(chart);
chart.getLegend().setCustom(legendEntries);
chart.getLegend().setTextColor(LEGEND_TEXT_COLOR);
chart.getLegend().setWordWrapEnabled(true);
chart.getLegend().setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
@@ -462,17 +604,97 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
return DateTimeUtils.formatDurationHoursMinutes(value, TimeUnit.MINUTES);
}
@Override
String getAverage(float value) {
return getHM((long)value);
}
protected static class MyChartsData extends ChartsData {
private final WeekChartsData<BarData> weekBeforeData;
MyChartsData(WeekChartsData<BarData> weekBeforeData) {
this.weekBeforeData = weekBeforeData;
}
WeekChartsData<BarData> getWeekBeforeData() {
return weekBeforeData;
}
}
protected ActivityAmounts getActivityAmountsForDay(DBHandler db, Calendar day, GBDevice device) {
LimitedQueue<Integer, ActivityAmounts> activityAmountCache = null;
ActivityAmounts amounts = null;
Activity activity = getActivity();
int key = (int) (day.getTimeInMillis() / 1000) + (mOffsetHours * 3600);
if (activity != null) {
activityAmountCache = ((ActivityChartsActivity) activity).mActivityAmountCache;
amounts = activityAmountCache.lookup(key);
}
if (amounts == null) {
ActivityAnalysis analysis = new ActivityAnalysis();
amounts = analysis.calculateActivityAmounts(getSamplesOfDay(db, day, mOffsetHours, device));
if (activityAmountCache != null) {
activityAmountCache.add(key, amounts);
}
}
return amounts;
}
private List<? extends ActivitySample> getSamplesOfDay(DBHandler db, Calendar day, int offsetHours, GBDevice device) {
int startTs;
int endTs;
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, offsetHours);
startTs = (int) (day.getTimeInMillis() / 1000);
endTs = startTs + 24 * 60 * 60 - 1;
return getSamples(db, device, startTs, endTs);
}
private int getRangeDays(){
if (GBApplication.getPrefs().getBoolean("charts_range", true)) {
return 30;}
else{
return 7;
}
}
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; }
}
private static class MySleepWeeklyData {
private long totalAwake;
private long totalRem;
private long totalDeep;
private long totalLight;
private int totalDaysForAverage;
private final long totalAwake;
private final long totalRem;
private final long totalDeep;
private final long totalLight;
private final int totalDaysForAverage;
public MySleepWeeklyData(long totalAwake, long totalRem, long totalDeep, long totalLight) {
this.totalDeep = totalDeep;
@@ -57,6 +57,11 @@ public class StepsPeriodFragment extends StepsFragment<StepsPeriodFragment.Steps
protected int BACKGROUND_COLOR;
protected int DESCRIPTION_COLOR;
@Override
protected boolean isSingleDay() {
return false;
}
public static StepsPeriodFragment newInstance(int totalDays) {
StepsPeriodFragment fragmentFirst = new StepsPeriodFragment();
Bundle args = new Bundle();
@@ -4,10 +4,7 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.DaySleepChartFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.WeekSleepChartFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.HeartRatePeriodFragment;
public class HeartRateFragmentAdapter extends NestedFragmentAdapter {
@@ -6,8 +6,8 @@ import androidx.fragment.app.FragmentManager;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.DaySleepChartFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.WeekSleepChartFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.SleepDailyFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.SleepPeriodFragment;
public class SleepFragmentAdapter extends NestedFragmentAdapter {
public SleepFragmentAdapter(AbstractGBFragment fragment, FragmentManager childFragmentManager) {
@@ -19,12 +19,12 @@ public class SleepFragmentAdapter extends NestedFragmentAdapter {
public Fragment createFragment(int position) {
switch (position) {
case 0:
return new DaySleepChartFragment();
return new SleepDailyFragment();
case 1:
return WeekSleepChartFragment.newInstance(7);
return SleepPeriodFragment.newInstance(7);
case 2:
return WeekSleepChartFragment.newInstance(30);
return SleepPeriodFragment.newInstance(30);
}
return new DaySleepChartFragment();
return new SleepDailyFragment();
}
}