mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2025-01-17 21:27:31 +01:00
Allow multiple sleep sessions per day
This commit is contained in:
parent
744848fae7
commit
371ac276a5
@ -0,0 +1,102 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
|
||||
public class SleepAnalysis {
|
||||
|
||||
public static final long MIN_SESSION_LENGTH = 5 * 60;
|
||||
public static final long MAX_WAKE_PHASE_LENGTH = 2 * 60 * 60;
|
||||
|
||||
public List<SleepSession> calculateSleepSessions(List<? extends ActivitySample> samples) {
|
||||
List<SleepSession> result = new ArrayList<>();
|
||||
|
||||
ActivitySample previousSample = null;
|
||||
Date sleepStart = null;
|
||||
Date sleepEnd = null;
|
||||
long lightSleepDuration = 0;
|
||||
long deepSleepDuration = 0;
|
||||
long durationSinceLastSleep = 0;
|
||||
|
||||
for (ActivitySample sample : samples) {
|
||||
if (isSleep(sample)) {
|
||||
if (sleepStart == null)
|
||||
sleepStart = getDateFromSample(sample);
|
||||
sleepEnd = getDateFromSample(sample);
|
||||
|
||||
durationSinceLastSleep = 0;
|
||||
}
|
||||
|
||||
if (previousSample != null) {
|
||||
long durationSinceLastSample = sample.getTimestamp() - previousSample.getTimestamp();
|
||||
if (sample.getKind() == ActivityKind.TYPE_LIGHT_SLEEP) {
|
||||
lightSleepDuration += durationSinceLastSample;
|
||||
} else if (sample.getKind() == ActivityKind.TYPE_DEEP_SLEEP) {
|
||||
deepSleepDuration += durationSinceLastSample;
|
||||
} else {
|
||||
durationSinceLastSleep += durationSinceLastSample;
|
||||
if (sleepStart != null && durationSinceLastSleep > MAX_WAKE_PHASE_LENGTH) {
|
||||
if (lightSleepDuration + deepSleepDuration > MIN_SESSION_LENGTH)
|
||||
result.add(new SleepSession(sleepStart, sleepEnd, lightSleepDuration, deepSleepDuration));
|
||||
sleepStart = null;
|
||||
sleepEnd = null;
|
||||
lightSleepDuration = 0;
|
||||
deepSleepDuration = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
previousSample = sample;
|
||||
}
|
||||
if (lightSleepDuration + deepSleepDuration > MIN_SESSION_LENGTH) {
|
||||
result.add(new SleepSession(sleepStart, sleepEnd, lightSleepDuration, deepSleepDuration));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isSleep(ActivitySample sample) {
|
||||
return sample.getKind() == ActivityKind.TYPE_DEEP_SLEEP || sample.getKind() == ActivityKind.TYPE_LIGHT_SLEEP;
|
||||
}
|
||||
|
||||
private Date getDateFromSample(ActivitySample sample) {
|
||||
return new Date(sample.getTimestamp() * 1000L);
|
||||
}
|
||||
|
||||
|
||||
public static class SleepSession {
|
||||
private final Date sleepStart;
|
||||
private final Date sleepEnd;
|
||||
private final long lightSleepDuration;
|
||||
private final long deepSleepDuration;
|
||||
|
||||
private SleepSession(Date sleepStart,
|
||||
Date sleepEnd,
|
||||
long lightSleepDuration,
|
||||
long deepSleepDuration) {
|
||||
this.sleepStart = sleepStart;
|
||||
this.sleepEnd = sleepEnd;
|
||||
this.lightSleepDuration = lightSleepDuration;
|
||||
this.deepSleepDuration = deepSleepDuration;
|
||||
}
|
||||
|
||||
public Date getSleepStart() {
|
||||
return sleepStart;
|
||||
}
|
||||
|
||||
public Date getSleepEnd() {
|
||||
return sleepEnd;
|
||||
}
|
||||
|
||||
public long getLightSleepDuration() {
|
||||
return lightSleepDuration;
|
||||
}
|
||||
|
||||
public long getDeepSleepDuration() {
|
||||
return deepSleepDuration;
|
||||
}
|
||||
}
|
||||
}
|
@ -25,8 +25,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.github.mikephil.charting.animation.Easing;
|
||||
import com.github.mikephil.charting.charts.Chart;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
@ -44,16 +42,17 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.SleepAnalysis.SleepSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
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.util.DateTimeUtils;
|
||||
@ -82,39 +81,35 @@ public class SleepChartFragment extends AbstractChartFragment {
|
||||
}
|
||||
|
||||
private MySleepChartsData refreshSleepAmounts(GBDevice mGBDevice, List<? extends ActivitySample> samples) {
|
||||
ActivityAnalysis analysis = new ActivityAnalysis();
|
||||
ActivityAmounts amounts = analysis.calculateActivityAmounts(samples);
|
||||
SleepAnalysis sleepAnalysis = new SleepAnalysis();
|
||||
List<SleepSession> sleepSessions = sleepAnalysis.calculateSleepSessions(samples);
|
||||
|
||||
PieData data = new PieData();
|
||||
List<PieEntry> entries = new ArrayList<>();
|
||||
List<Integer> colors = new ArrayList<>();
|
||||
// int index = 0;
|
||||
long totalSeconds = 0;
|
||||
|
||||
Date startSleep = null;
|
||||
Date endSleep = null;
|
||||
|
||||
for (ActivityAmount amount : amounts.getAmounts()) {
|
||||
if ((amount.getActivityKind() & ActivityKind.TYPE_SLEEP) != 0) {
|
||||
long value = amount.getTotalSeconds();
|
||||
if(startSleep == null){
|
||||
startSleep = amount.getStartDate();
|
||||
} else {
|
||||
if(startSleep.after(amount.getStartDate()))
|
||||
startSleep = amount.getStartDate();
|
||||
}
|
||||
if(endSleep == null){
|
||||
endSleep = amount.getEndDate();
|
||||
} else {
|
||||
if(endSleep.before(amount.getEndDate()))
|
||||
endSleep = amount.getEndDate();
|
||||
}
|
||||
totalSeconds += value;
|
||||
// entries.add(new PieEntry(value, index++));
|
||||
entries.add(new PieEntry(value, amount.getName(getActivity())));
|
||||
colors.add(getColorFor(amount.getActivityKind()));
|
||||
// data.addXValue(amount.getName(getActivity()));
|
||||
}
|
||||
final long lightSleepDuration = calculateLightSleepDuration(sleepSessions);
|
||||
final long deepSleepDuration = calculateDeepSleepDuration(sleepSessions);
|
||||
|
||||
final long totalSeconds = lightSleepDuration + deepSleepDuration;
|
||||
|
||||
final List<PieEntry> entries;
|
||||
final List<Integer> colors;
|
||||
|
||||
if (sleepSessions.isEmpty()) {
|
||||
entries = Collections.emptyList();
|
||||
colors = Collections.emptyList();
|
||||
} else {
|
||||
entries = Arrays.asList(
|
||||
new PieEntry(lightSleepDuration, getActivity().getString(R.string.abstract_chart_fragment_kind_light_sleep)),
|
||||
new PieEntry(deepSleepDuration, getActivity().getString(R.string.abstract_chart_fragment_kind_deep_sleep))
|
||||
);
|
||||
colors = Arrays.asList(
|
||||
getColorFor(ActivityKind.TYPE_LIGHT_SLEEP),
|
||||
getColorFor(ActivityKind.TYPE_DEEP_SLEEP)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
String totalSleep = DateTimeUtils.formatDurationHoursMinutes(totalSeconds, TimeUnit.SECONDS);
|
||||
PieDataSet set = new PieDataSet(entries, "");
|
||||
set.setValueFormatter(new ValueFormatter() {
|
||||
@ -131,27 +126,54 @@ public class SleepChartFragment extends AbstractChartFragment {
|
||||
data.setDataSet(set);
|
||||
|
||||
//setupLegend(pieChart);
|
||||
return new MySleepChartsData(totalSleep, data, startSleep, endSleep);
|
||||
return new MySleepChartsData(totalSleep, data, sleepSessions);
|
||||
}
|
||||
|
||||
private long calculateLightSleepDuration(List<SleepSession> sleepSessions) {
|
||||
long result = 0;
|
||||
for (SleepSession sleepSession : sleepSessions) {
|
||||
result += sleepSession.getLightSleepDuration();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private long calculateDeepSleepDuration(List<SleepSession> sleepSessions) {
|
||||
long result = 0;
|
||||
for (SleepSession sleepSession : sleepSessions) {
|
||||
result += sleepSession.getDeepSleepDuration();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChartsnUIThread(ChartsData chartsData) {
|
||||
MyChartsData mcd = (MyChartsData) chartsData;
|
||||
mSleepAmountChart.setCenterText(mcd.getPieData().getTotalSleep());
|
||||
mSleepAmountChart.setData(mcd.getPieData().getPieData());
|
||||
MySleepChartsData pieData = mcd.getPieData();
|
||||
mSleepAmountChart.setCenterText(pieData.getTotalSleep());
|
||||
mSleepAmountChart.setData(pieData.getPieData());
|
||||
|
||||
mActivityChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317
|
||||
mActivityChart.getXAxis().setValueFormatter(mcd.getChartsData().getXValueFormatter());
|
||||
mActivityChart.setData(mcd.getChartsData().getData());
|
||||
|
||||
if (mcd.getPieData().getStartSleep() != null && mcd.getPieData().getEndSleep() != null) {
|
||||
mSleepchartInfo.setText(getContext().getString(
|
||||
R.string.you_slept,
|
||||
DateTimeUtils.timeToString(mcd.getPieData().getStartSleep()),
|
||||
DateTimeUtils.timeToString(mcd.getPieData().getEndSleep())));
|
||||
|
||||
mSleepchartInfo.setText(buildYouSleptText(pieData));
|
||||
}
|
||||
|
||||
private String buildYouSleptText(MySleepChartsData pieData) {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
if (pieData.getSleepSessions().isEmpty()) {
|
||||
result.append(getContext().getString(R.string.you_did_not_sleep));
|
||||
} else {
|
||||
mSleepchartInfo.setText(getContext().getString(R.string.you_did_not_sleep));
|
||||
for (SleepSession sleepSession : pieData.getSleepSessions()) {
|
||||
result.append(getContext().getString(
|
||||
R.string.you_slept,
|
||||
DateTimeUtils.timeToString(sleepSession.getSleepStart()),
|
||||
DateTimeUtils.timeToString(sleepSession.getSleepEnd())));
|
||||
result.append('\n');
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -275,14 +297,12 @@ public class SleepChartFragment extends AbstractChartFragment {
|
||||
private static class MySleepChartsData extends ChartsData {
|
||||
private String totalSleep;
|
||||
private final PieData pieData;
|
||||
private @Nullable Date startSleep;
|
||||
private @Nullable Date endSleep;
|
||||
private final List<SleepSession> sleepSessions;
|
||||
|
||||
public MySleepChartsData(String totalSleep, PieData pieData, @Nullable Date startSleep, @Nullable Date endSleep) {
|
||||
public MySleepChartsData(String totalSleep, PieData pieData, List<SleepSession> sleepSessions) {
|
||||
this.totalSleep = totalSleep;
|
||||
this.pieData = pieData;
|
||||
this.startSleep = startSleep;
|
||||
this.endSleep = endSleep;
|
||||
this.sleepSessions = sleepSessions;
|
||||
}
|
||||
|
||||
public PieData getPieData() {
|
||||
@ -293,14 +313,8 @@ public class SleepChartFragment extends AbstractChartFragment {
|
||||
return totalSleep;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Date getStartSleep() {
|
||||
return startSleep;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Date getEndSleep() {
|
||||
return endSleep;
|
||||
public List<SleepSession> getSleepSessions() {
|
||||
return sleepSessions;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user