1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-09-18 12:16:36 +02:00

Replace dummy values with actual data

This commit is contained in:
Arjan Schrijver 2023-12-27 23:01:35 +01:00
parent fbe1d18709
commit 2f0e9871c6
7 changed files with 259 additions and 45 deletions

View File

@ -0,0 +1,75 @@
/* Copyright (C) 2023 Arjan Schrijver
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.dashboard;
import androidx.fragment.app.Fragment;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.StepAnalysis;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession;
import nodomain.freeyourgadget.gadgetbridge.model.DailyTotals;
public abstract class AbstractDashboardWidget extends Fragment {
protected long getSteps(GBDevice device, DBHandler db) {
Calendar day = GregorianCalendar.getInstance();
DailyTotals ds = new DailyTotals();
return ds.getDailyTotalsForDevice(device, day, db)[0];
}
protected long getSleep(GBDevice device, DBHandler db) {
Calendar day = GregorianCalendar.getInstance();
DailyTotals ds = new DailyTotals();
return ds.getDailyTotalsForDevice(device, day, db)[1];
}
protected long getActiveMinutes(GBDevice gbDevice, DBHandler db, int timeFrom, int timeTo) {
ActivitySession stepSessionsSummary = new ActivitySession();
List<ActivitySession> stepSessions;
List<? extends ActivitySample> activitySamples = getAllSamples(db, gbDevice, timeFrom, timeTo);
StepAnalysis stepAnalysis = new StepAnalysis();
boolean isEmptySummary = false;
if (activitySamples != null) {
stepSessions = stepAnalysis.calculateStepSessions(activitySamples);
if (stepSessions.toArray().length == 0) {
isEmptySummary = true;
}
stepSessionsSummary = stepAnalysis.calculateSummary(stepSessions, isEmptySummary);
}
long duration = stepSessionsSummary.getEndTime().getTime() - stepSessionsSummary.getStartTime().getTime();
return duration / 1000 / 60;
}
protected List<? extends ActivitySample> getAllSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
SampleProvider<? extends ActivitySample> provider = getProvider(db, device);
return provider.getAllActivitySamples(tsFrom, tsTo);
}
SampleProvider<? extends AbstractActivitySample> getProvider(DBHandler db, GBDevice device) {
DeviceCoordinator coordinator = device.getDeviceCoordinator();
return coordinator.getSampleProvider(device, db.getDaoSession());
}
}

View File

@ -24,14 +24,26 @@ import android.widget.TextView;
import androidx.fragment.app.Fragment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DashboardActiveTimeWidget#newInstance} factory method to
* create an instance of this fragment.
*/
public class DashboardActiveTimeWidget extends Fragment {
public class DashboardActiveTimeWidget extends AbstractDashboardWidget {
private static final Logger LOG = LoggerFactory.getLogger(DashboardActiveTimeWidget.class);
public DashboardActiveTimeWidget() {
// Required empty public constructor
@ -41,8 +53,25 @@ public class DashboardActiveTimeWidget extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.dashboard_widget_active_time, container, false);
Calendar day = Calendar.getInstance();
day.set(Calendar.HOUR_OF_DAY, 23);
day.set(Calendar.MINUTE, 59);
day.set(Calendar.SECOND, 59);
int timeTo = (int) (day.getTimeInMillis() / 1000);
int timeFrom = DateTimeUtils.shiftDays(timeTo, -1);
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
long totalActiveMinutes = 0;
try (DBHandler dbHandler = GBApplication.acquireDB()) {
for (GBDevice dev : devices) {
if (dev.getDeviceCoordinator().supportsActivityTracking()) {
totalActiveMinutes += getActiveMinutes(dev, dbHandler, timeFrom, timeTo);
}
}
} catch (Exception e) {
LOG.warn("Could not calculate total amount of sleep: ", e);
}
TextView activeTime = fragmentView.findViewById(R.id.active_time);
activeTime.setText("1h 15min");
activeTime.setText(DateTimeUtils.formatDurationHoursMinutes(totalActiveMinutes, TimeUnit.MINUTES));
return fragmentView;
}
}

View File

@ -24,14 +24,28 @@ import android.widget.TextView;
import androidx.fragment.app.Fragment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.DailyTotals;
import nodomain.freeyourgadget.gadgetbridge.util.FormatUtils;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DashboardDistanceWidget#newInstance} factory method to
* create an instance of this fragment.
*/
public class DashboardDistanceWidget extends Fragment {
public class DashboardDistanceWidget extends AbstractDashboardWidget {
private static final Logger LOG = LoggerFactory.getLogger(DashboardDistanceWidget.class);
public DashboardDistanceWidget() {
// Required empty public constructor
@ -41,8 +55,23 @@ public class DashboardDistanceWidget extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.dashboard_widget_distance, container, false);
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
long totalSteps = 0;
try (DBHandler dbHandler = GBApplication.acquireDB()) {
for (GBDevice dev : devices) {
if (dev.getDeviceCoordinator().supportsActivityTracking()) {
totalSteps += getSteps(dev, dbHandler);
}
}
} catch (Exception e) {
LOG.warn("Could not calculate total amount of steps: ", e);
}
ActivityUser activityUser = new ActivityUser();
int stepLength = activityUser.getStepLengthCm();
double distanceMeters = totalSteps * stepLength * 0.01;
String distanceFormatted = FormatUtils.getFormattedDistanceLabel(distanceMeters);
TextView distance = fragmentView.findViewById(R.id.distance);
distance.setText("2700m");
distance.setText(distanceFormatted);
return fragmentView;
}
}

View File

@ -24,14 +24,25 @@ import android.widget.TextView;
import androidx.fragment.app.Fragment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DashboardSleepWidget#newInstance} factory method to
* create an instance of this fragment.
*/
public class DashboardSleepWidget extends Fragment {
public class DashboardSleepWidget extends AbstractDashboardWidget {
private static final Logger LOG = LoggerFactory.getLogger(DashboardSleepWidget.class);
public DashboardSleepWidget() {
// Required empty public constructor
@ -41,8 +52,19 @@ public class DashboardSleepWidget extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.dashboard_widget_sleep, container, false);
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
long totalSleepMinutes = 0;
try (DBHandler dbHandler = GBApplication.acquireDB()) {
for (GBDevice dev : devices) {
if (dev.getDeviceCoordinator().supportsActivityTracking()) {
totalSleepMinutes += getSleep(dev, dbHandler);
}
}
} catch (Exception e) {
LOG.warn("Could not calculate total amount of sleep: ", e);
}
TextView sleepAmount = fragmentView.findViewById(R.id.sleep_amount);
sleepAmount.setText("7h 35min");
sleepAmount.setText(DateTimeUtils.formatDurationHoursMinutes(totalSleepMinutes, TimeUnit.MINUTES));
return fragmentView;
}
}

View File

@ -24,14 +24,23 @@ import android.widget.TextView;
import androidx.fragment.app.Fragment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DashboardStepsWidget#newInstance} factory method to
* create an instance of this fragment.
*/
public class DashboardStepsWidget extends Fragment {
public class DashboardStepsWidget extends AbstractDashboardWidget {
private static final Logger LOG = LoggerFactory.getLogger(DashboardStepsWidget.class);
public DashboardStepsWidget() {
// Required empty public constructor
@ -41,8 +50,19 @@ public class DashboardStepsWidget extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.dashboard_widget_steps, container, false);
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
long totalSteps = 0;
try (DBHandler dbHandler = GBApplication.acquireDB()) {
for (GBDevice dev : devices) {
if (dev.getDeviceCoordinator().supportsActivityTracking()) {
totalSteps += getSteps(dev, dbHandler);
}
}
} catch (Exception e) {
LOG.warn("Could not calculate total amount of steps: ", e);
}
TextView stepsCount = fragmentView.findViewById(R.id.steps_count);
stepsCount.setText("5500");
stepsCount.setText(String.valueOf(totalSteps));
return fragmentView;
}
}

View File

@ -32,17 +32,30 @@ import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.StepAnalysis;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DashboardTodayWidget#newInstance} factory method to
* create an instance of this fragment.
*/
public class DashboardTodayWidget extends Fragment {
public class DashboardTodayWidget extends AbstractDashboardWidget {
private static final Logger LOG = LoggerFactory.getLogger(DashboardTodayWidget.class);
public DashboardTodayWidget() {
// Required empty public constructor
@ -53,6 +66,7 @@ public class DashboardTodayWidget extends Fragment {
Bundle savedInstanceState) {
View todayView = inflater.inflate(R.layout.dashboard_widget_today, container, false);
// Initialize chart
PieChart chart = todayView.findViewById(R.id.dashboard_piechart_today);
chart.getDescription().setEnabled(false);
chart.setDrawHoleEnabled(true);
@ -61,55 +75,72 @@ public class DashboardTodayWidget extends Fragment {
chart.setRotationEnabled(false);
chart.setDrawEntryLabels(false);
// Initialize legend
Legend l = chart.getLegend();
l.setTextColor(GBApplication.getTextColor(getContext()));
ArrayList<LegendEntry> legendEntries = new ArrayList<>();
legendEntries.add(new LegendEntry("Deep sleep", Legend.LegendForm.SQUARE, 10f, 10f, new DashPathEffect(new float[]{10f, 5f}, 0f), Color.rgb(0, 0, 255)));
legendEntries.add(new LegendEntry("Light sleep", Legend.LegendForm.SQUARE, 10f, 10f, new DashPathEffect(new float[]{10f, 5f}, 0f), Color.rgb(150, 150, 255)));
legendEntries.add(new LegendEntry("Inactive", Legend.LegendForm.SQUARE, 10f, 10f, new DashPathEffect(new float[]{10f, 5f}, 0f), Color.rgb(200, 200, 200)));
legendEntries.add(new LegendEntry("Active", Legend.LegendForm.SQUARE, 10f, 10f, new DashPathEffect(new float[]{10f, 5f}, 0f), Color.rgb(0, 255, 0)));
legendEntries.add(new LegendEntry(getContext().getString(R.string.activity_type_deep_sleep), Legend.LegendForm.SQUARE, 10f, 10f, new DashPathEffect(new float[]{10f, 5f}, 0f), Color.rgb(0, 0, 255)));
legendEntries.add(new LegendEntry(getContext().getString(R.string.activity_type_light_sleep), Legend.LegendForm.SQUARE, 10f, 10f, new DashPathEffect(new float[]{10f, 5f}, 0f), Color.rgb(150, 150, 255)));
legendEntries.add(new LegendEntry(getContext().getString(R.string.activity_type_activity), Legend.LegendForm.SQUARE, 10f, 10f, new DashPathEffect(new float[]{10f, 5f}, 0f), Color.rgb(0, 255, 0)));
legendEntries.add(new LegendEntry(getContext().getString(R.string.activity_type_not_worn), Legend.LegendForm.SQUARE, 10f, 10f, new DashPathEffect(new float[]{10f, 5f}, 0f), Color.rgb(0, 0, 0)));
l.setCustom(legendEntries);
// Retrieve activity sessions
Calendar day = Calendar.getInstance();
day.set(Calendar.HOUR_OF_DAY, 23);
day.set(Calendar.MINUTE, 59);
day.set(Calendar.SECOND, 59);
int timeTo = (int) (day.getTimeInMillis() / 1000);
int timeFrom = DateTimeUtils.shiftDays(timeTo, -1);
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
List<ActivitySession> stepSessions = new ArrayList<>();
try (DBHandler dbHandler = GBApplication.acquireDB()) {
for (GBDevice dev : devices) {
if (dev.getDeviceCoordinator().supportsActivityTracking()) {
ActivitySession stepSessionsSummary = new ActivitySession();
List<? extends ActivitySample> activitySamples = getAllSamples(dbHandler, dev, timeFrom, timeTo);
StepAnalysis stepAnalysis = new StepAnalysis();
if (activitySamples != null) {
stepSessions.addAll(stepAnalysis.calculateStepSessions(activitySamples));
}
}
}
} catch (Exception e) {
LOG.warn("Could not calculate total amount of sleep: ", e);
}
Collections.sort(stepSessions, (o1, o2) -> o1.getStartTime().compareTo(o2.getStartTime()));
// Add pie slice entries
ArrayList<PieEntry> entries = new ArrayList<>();
ArrayList<Integer> colors = new ArrayList<>();
long secondIndex = timeFrom;
for (ActivitySession session : stepSessions) {
// Calculate start and end seconds
long startSec = session.getStartTime().getTime() / 1000;
long endSec = session.getEndTime().getTime() / 1000;
// Skip earlier sessions
if (startSec < secondIndex) continue;
// Draw inactive slice
entries.add(new PieEntry(startSec - secondIndex, "Inactive"));
colors.add(Color.rgb(128, 128, 128));
// Draw activity slice
entries.add(new PieEntry(endSec - startSec, "Active"));
colors.add(Color.rgb(0, 255, 0));
secondIndex = endSec;
}
// Fill with inactive slice up until current time
entries.add(new PieEntry(Calendar.getInstance().getTimeInMillis() / 1000 - secondIndex, "Inactive"));
colors.add(Color.rgb(128, 128, 128));
// Draw transparent slice for remaining time until midnight
entries.add(new PieEntry(timeTo - Calendar.getInstance().getTimeInMillis() / 1000, ""));
colors.add(Color.argb(0, 0, 0, 0));
entries.add(new PieEntry(120, "Deep sleep"));
colors.add(Color.rgb(0, 0, 255));
entries.add(new PieEntry(120, "Light sleep"));
colors.add(Color.rgb(150, 150, 255));
entries.add(new PieEntry(60, "Deep sleep"));
colors.add(Color.rgb(0, 0, 255));
entries.add(new PieEntry(120, "Light sleep"));
colors.add(Color.rgb(150, 150, 255));
entries.add(new PieEntry(180, "Inactive"));
colors.add(Color.rgb(200, 200, 200));
entries.add(new PieEntry(60, "Active"));
colors.add(Color.rgb(0, 255, 0));
entries.add(new PieEntry(60, "Inactive"));
colors.add(Color.rgb(200, 200, 200));
entries.add(new PieEntry(30, "Active"));
colors.add(Color.rgb(0, 255, 0));
entries.add(new PieEntry(150, "Inactive"));
colors.add(Color.rgb(200, 200, 200));
entries.add(new PieEntry(60, "Active"));
colors.add(Color.rgb(0, 255, 0));
entries.add(new PieEntry(60, "Inactive"));
colors.add(Color.rgb(200, 200, 200));
entries.add(new PieEntry(90, "Active"));
colors.add(Color.rgb(0, 255, 0));
entries.add(new PieEntry(150, "Inactive"));
colors.add(Color.rgb(200, 200, 200));
entries.add(new PieEntry(120, "Light sleep"));
colors.add(Color.rgb(150, 150, 255));
entries.add(new PieEntry(60, "Deep sleep"));
colors.add(Color.rgb(0, 0, 255));
// Draw chart
PieDataSet dataSet = new PieDataSet(entries, "Today");
dataSet.setSliceSpace(0f);
dataSet.setSelectionShift(5f);
dataSet.setDrawValues(false);
dataSet.setColors(colors);
PieData data = new PieData(dataSet);
chart.setData(data);

View File

@ -21,6 +21,14 @@
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/activity_summary_today"
android:textStyle="bold"
android:textSize="30sp" />
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"