1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-24 05:50:47 +02:00

Allow multiple sleep sessions per day

This commit is contained in:
Q-er 2019-09-17 00:47:10 +02:00 committed by Andreas Shimokawa
parent 744848fae7
commit 371ac276a5
2 changed files with 171 additions and 55 deletions

View File

@ -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;
}
}
}

View File

@ -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;
}
}