1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-24 22:10:55 +02:00
Gadgetbridge/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java
Daniele Gobbetti 75d3dffb14 Migrate to androidx support libraries and bump compile SDK version
"Optimize imports" has been run on all source files, there might be
unrelated changes, but these should be harmless.
2019-01-26 16:00:56 +01:00

325 lines
13 KiB
Java

/* Copyright (C) 2015-2018 0nse, Andreas Shimokawa, Carsten Pfeiffer,
Daniele Gobbetti, Pavel Elagin
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
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.LegendEntry;
import com.github.mikephil.charting.components.XAxis;
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.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.utils.ViewPortHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import androidx.annotation.Nullable;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils;
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;
public class SleepChartFragment extends AbstractChartFragment {
protected static final Logger LOG = LoggerFactory.getLogger(ActivitySleepChartFragment.class);
private LineChart mActivityChart;
private PieChart mSleepAmountChart;
private TextView mSleepchartInfo;
private int mSmartAlarmFrom = -1;
private int mSmartAlarmTo = -1;
private int mTimestampFrom = -1;
private int mSmartAlarmGoneOff = -1;
@Override
protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
List<? extends ActivitySample> samples = getSamples(db, device);
MySleepChartsData mySleepChartsData = refreshSleepAmounts(device, samples);
DefaultChartsData chartsData = refresh(device, samples);
return new MyChartsData(mySleepChartsData, chartsData);
}
private MySleepChartsData refreshSleepAmounts(GBDevice mGBDevice, List<? extends ActivitySample> samples) {
ActivityAnalysis analysis = new ActivityAnalysis();
ActivityAmounts amounts = analysis.calculateActivityAmounts(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()));
}
}
String totalSleep = DateTimeUtils.formatDurationHoursMinutes(totalSeconds, TimeUnit.SECONDS);
PieDataSet set = new PieDataSet(entries, "");
set.setValueFormatter(new IValueFormatter() {
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return DateTimeUtils.formatDurationHoursMinutes((long) value, TimeUnit.SECONDS);
}
});
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);
//setupLegend(pieChart);
return new MySleepChartsData(totalSleep, data, startSleep, endSleep);
}
@Override
protected void updateChartsnUIThread(ChartsData chartsData) {
MyChartsData mcd = (MyChartsData) chartsData;
mSleepAmountChart.setCenterText(mcd.getPieData().getTotalSleep());
mSleepAmountChart.setData(mcd.getPieData().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())));
} else {
mSleepchartInfo.setText(getContext().getString(R.string.you_did_not_sleep));
}
}
@Override
public String getTitle() {
return getString(R.string.sleepchart_your_sleep);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_sleepchart, container, false);
mActivityChart = rootView.findViewById(R.id.sleepchart);
mSleepAmountChart = rootView.findViewById(R.id.sleepchart_pie_light_deep);
mSleepchartInfo = rootView.findViewById(R.id.sleepchart_info);
setupActivityChart();
setupSleepAmountChart();
// refresh immediately instead of use refreshIfVisible(), for perceived performance
refresh();
return rootView;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ChartsHost.REFRESH)) {
// TODO: use LimitLines to visualize smart alarms?
mSmartAlarmFrom = intent.getIntExtra("smartalarm_from", -1);
mSmartAlarmTo = intent.getIntExtra("smartalarm_to", -1);
mTimestampFrom = intent.getIntExtra("recording_base_timestamp", -1);
mSmartAlarmGoneOff = intent.getIntExtra("alarm_gone_off", -1);
refresh();
} else {
super.onReceive(context, intent);
}
}
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);
configureBarLineChartDefaults(mActivityChart);
XAxis x = mActivityChart.getXAxis();
x.setDrawLabels(true);
x.setDrawGridLines(false);
x.setEnabled(true);
x.setTextColor(CHART_TEXT_COLOR);
x.setDrawLimitLinesBehindData(true);
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();
yAxisRight.setDrawGridLines(false);
yAxisRight.setEnabled(supportsHeartrate(getChartsHost().getDevice()));
yAxisRight.setDrawLabels(true);
yAxisRight.setDrawTopYLabelEntry(true);
yAxisRight.setTextColor(CHART_TEXT_COLOR);
yAxisRight.setAxisMaxValue(HeartRateUtils.getInstance().getMaxHeartRate());
yAxisRight.setAxisMinValue(HeartRateUtils.getInstance().getMinHeartRate());
}
@Override
protected void setupLegend(Chart chart) {
List<LegendEntry> legendEntries = new ArrayList<>(3);
LegendEntry lightSleepEntry = new LegendEntry();
lightSleepEntry.label = akLightSleep.label;
lightSleepEntry.formColor = akLightSleep.color;
legendEntries.add(lightSleepEntry);
LegendEntry deepSleepEntry = new LegendEntry();
deepSleepEntry.label = akDeepSleep.label;
deepSleepEntry.formColor = akDeepSleep.color;
legendEntries.add(deepSleepEntry);
if (supportsHeartrate(getChartsHost().getDevice())) {
LegendEntry hrEntry = new LegendEntry();
hrEntry.label = HEARTRATE_LABEL;
hrEntry.formColor = HEARTRATE_COLOR;
legendEntries.add(hrEntry);
}
chart.getLegend().setCustom(legendEntries);
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.getSleepSamples(db, device, tsFrom, tsTo);
return super.getAllSamples(db, device, tsFrom, tsTo);
}
@Override
protected void renderCharts() {
mActivityChart.animateX(ANIM_TIME, Easing.EasingOption.EaseInOutQuart);
mSleepAmountChart.invalidate();
}
private static class MySleepChartsData extends ChartsData {
private String totalSleep;
private final PieData pieData;
private @Nullable Date startSleep;
private @Nullable Date endSleep;
public MySleepChartsData(String totalSleep, PieData pieData, @Nullable Date startSleep, @Nullable Date endSleep) {
this.totalSleep = totalSleep;
this.pieData = pieData;
this.startSleep = startSleep;
this.endSleep = endSleep;
}
public PieData getPieData() {
return pieData;
}
public CharSequence getTotalSleep() {
return totalSleep;
}
@Nullable
public Date getStartSleep() {
return startSleep;
}
@Nullable
public Date getEndSleep() {
return endSleep;
}
}
private static class MyChartsData extends ChartsData {
private final DefaultChartsData<LineData> chartsData;
private final MySleepChartsData pieData;
public MyChartsData(MySleepChartsData pieData, DefaultChartsData<LineData> chartsData) {
this.pieData = pieData;
this.chartsData = chartsData;
}
public MySleepChartsData getPieData() {
return pieData;
}
public DefaultChartsData<LineData> getChartsData() {
return chartsData;
}
}
}