/* Copyright (C) 2015-2024 Andreas Shimokawa, Carsten Pfeiffer, Daniele Gobbetti, Dikay900, José Rebelo, 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 . */ 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 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.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.LineData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; 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.ActivitySample; public class ActivitySleepChartFragment extends AbstractActivityChartFragment> { protected static final Logger LOG = LoggerFactory.getLogger(ActivitySleepChartFragment.class); private LineChart mChart; private int mSmartAlarmFrom = -1; private int mSmartAlarmTo = -1; private int mTimestampFrom = -1; private int mSmartAlarmGoneOff = -1; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_charts, container, false); mChart = (LineChart) rootView.findViewById(R.id.activitysleepchart); setupChart(); return rootView; } @Override public String getTitle() { return getString(R.string.activity_sleepchart_activity_and_sleep); } private void setupChart() { mChart.setBackgroundColor(BACKGROUND_COLOR); mChart.getDescription().setTextColor(DESCRIPTION_COLOR); configureBarLineChartDefaults(mChart); XAxis x = mChart.getXAxis(); x.setDrawLabels(true); x.setDrawGridLines(false); x.setEnabled(true); x.setTextColor(CHART_TEXT_COLOR); x.setDrawLimitLinesBehindData(true); YAxis y = mChart.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 = mChart.getAxisRight(); yAxisRight.setDrawGridLines(false); yAxisRight.setEnabled(supportsHeartrate(getChartsHost().getDevice())); yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setTextColor(CHART_TEXT_COLOR); yAxisRight.setAxisMaximum(HeartRateUtils.getInstance().getMaxHeartRate()); yAxisRight.setAxisMinimum(HeartRateUtils.getInstance().getMinHeartRate()); // refresh immediately instead of use refreshIfVisible(), for perceived performance refresh(); } @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); } } @Override protected DefaultChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { List samples = getSamples(db, device); return refresh(device, samples); } @Override protected void updateChartsnUIThread(DefaultChartsData dcd) { mChart.getLegend().setTextColor(LEGEND_TEXT_COLOR); mChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317 mChart.getXAxis().setValueFormatter(dcd.getXValueFormatter()); mChart.setData((LineData) dcd.getData()); } @Override protected void renderCharts() { mChart.animateX(ANIM_TIME, Easing.EaseInOutQuart); // mChart.invalidate(); } @Override protected void setupLegend(Chart chart) { List legendEntries = new ArrayList<>(5); LegendEntry activityEntry = new LegendEntry(); activityEntry.label = akActivity.label; activityEntry.formColor = akActivity.color; legendEntries.add(activityEntry); 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 (supportsRemSleep(getChartsHost().getDevice())) { LegendEntry remSleepEntry = new LegendEntry(); remSleepEntry.label = akRemSleep.label; remSleepEntry.formColor = akRemSleep.color; legendEntries.add(remSleepEntry); } LegendEntry notWornEntry = new LegendEntry(); notWornEntry.label = akNotWorn.label; notWornEntry.formColor = akNotWorn.color; legendEntries.add(notWornEntry); 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().setWordWrapEnabled(true); chart.getLegend().setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER); } @Override protected List getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) { return getAllSamples(db, device, tsFrom, tsTo); } }