1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2025-01-14 11:47:32 +01:00

Calories: Cleanup and fix some inconsistencies

This commit is contained in:
José Rebelo 2024-11-24 16:55:25 +00:00
parent 27c4cc95c9
commit e54b7959a4
18 changed files with 118 additions and 80 deletions

View File

@ -127,7 +127,7 @@ public class GBApplication extends Application {
private static SharedPreferences sharedPrefs;
private static final String PREFS_VERSION = "shared_preferences_version";
//if preferences have to be migrated, increment the following and add the migration logic in migratePrefs below; see http://stackoverflow.com/questions/16397848/how-can-i-migrate-android-preferences-with-a-new-version
private static final int CURRENT_PREFS_VERSION = 44;
private static final int CURRENT_PREFS_VERSION = 43;
private static final LimitedQueue<Integer, String> mIDSenderLookup = new LimitedQueue<>(16);
private static GBPrefs prefs;
@ -1853,7 +1853,7 @@ public class GBApplication extends Application {
}
final String newPrefValue;
if (!StringUtils.isBlank(chartsTabsValue)) {
if (!StringUtils.isBlank(chartsTabsValue) && !chartsTabsValue.contains("calories")) {
newPrefValue = chartsTabsValue + ",calories";
} else {
newPrefValue = "calories";
@ -1868,14 +1868,6 @@ public class GBApplication extends Application {
}
}
if (oldVersion < 44) {
// Add new dashboard calories widgets.
final String dashboardWidgetsOrder = sharedPrefs.getString("pref_dashboard_widgets_order", null);
if (!StringUtils.isBlank(dashboardWidgetsOrder) && !dashboardWidgetsOrder.contains("calories")) {
editor.putString("pref_dashboard_widgets_order", dashboardWidgetsOrder + ",calories,calories_active,calories_segmented");
}
}
editor.putString(PREFS_VERSION, Integer.toString(CURRENT_PREFS_VERSION));
editor.apply();
}

View File

@ -395,6 +395,7 @@ public class DashboardFragment extends Fragment implements MenuProvider {
public void clear() {
restingCaloriesTotal = 0;
activeCaloriesTotal = 0;
activeCaloriesGoalFactor = 0;
caloriesTotal = 0;
stepsTotal = 0;
stepsGoalFactor = 0;
@ -413,6 +414,7 @@ public class DashboardFragment extends Fragment implements MenuProvider {
stepsGoalFactor == 0 &&
restingCaloriesTotal == 0 &&
activeCaloriesTotal == 0 &&
activeCaloriesGoalFactor == 0 &&
caloriesTotal == 0 &&
sleepTotalMinutes == 0 &&
sleepGoalFactor == 0 &&

View File

@ -134,7 +134,7 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
if (!coordinator.supportsVO2Max()) {
tabList.remove("vo2max");
}
if (!coordinator.supportsActiveCalories() && !coordinator.supportsRestingCalories()) {
if (!coordinator.supportsActiveCalories()) {
tabList.remove("calories");
}
return tabList;

View File

@ -26,6 +26,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.GaugeDrawer;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.DefaultRestingMetabolicRateProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
@ -114,7 +115,12 @@ public class CaloriesDailyFragment extends AbstractChartFragment<CaloriesDailyFr
protected RestingMetabolicRateSample getRestingMetabolicRate(DBHandler db, GBDevice device) {
TimeSampleProvider<? extends RestingMetabolicRateSample> provider = device.getDeviceCoordinator().getRestingMetabolicRateProvider(device, db.getDaoSession());
return provider.getLatestSample();
RestingMetabolicRateSample latestSample = provider.getLatestSample();
if (latestSample != null) {
return latestSample;
}
DefaultRestingMetabolicRateProvider defaultProvider = new DefaultRestingMetabolicRateProvider(device, db.getDaoSession());
return defaultProvider.getLatestSample();
}
protected List<? extends AbstractActivitySample> getActivitySamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
@ -201,7 +207,7 @@ public class CaloriesDailyFragment extends AbstractChartFragment<CaloriesDailyFr
segments,
true,
String.valueOf(totalCalories),
getContext().getString(R.string.total_burnt),
getContext().getString(R.string.total_calories_burnt),
getContext()
));
} else {

View File

@ -36,6 +36,11 @@ public class DashboardCaloriesTotalSegmentedWidget extends AbstractGaugeWidget {
return fragment;
}
@Override
protected boolean isSupportedBy(final GBDevice device) {
return device.getDeviceCoordinator().supportsActiveCalories();
}
@Override
protected void populateData(final DashboardFragment.DashboardData dashboardData) {
dashboardData.getActiveCaloriesTotal();

View File

@ -196,7 +196,14 @@ public class GaugeDrawer {
gaugeBar.setImageBitmap(bitmap);
}
public static Bitmap drawCircleGaugeSegmented(int width, int barWidth, final int[] colors, final float[] segments, final boolean gapBetweenSegments, String text, String lowerText, Context context) {
public static Bitmap drawCircleGaugeSegmented(int width,
int barWidth,
final int[] colors,
final float[] segments,
final boolean gapBetweenSegments,
String text,
String lowerText,
Context context) {
int TEXT_COLOR = GBApplication.getTextColor(context);
int height = width;
int barMargin = (int) Math.ceil(barWidth / 2f);
@ -267,7 +274,12 @@ public class GaugeDrawer {
return bitmap;
}
public static Bitmap drawCircleGauge(int width, int barWidth, @ColorInt int filledColor, int value, int maxValue, Context context) {
public static Bitmap drawCircleGauge(int width,
int barWidth,
@ColorInt int filledColor,
int value,
int maxValue,
Context context) {
int TEXT_COLOR = GBApplication.getTextColor(context);
int height = width;
int barMargin = (int) Math.ceil(barWidth / 2f);

View File

@ -501,11 +501,6 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
return false;
}
@Override
public boolean supportsRestingCalories() {
return false;
}
@Override
public boolean supportsActivityTabs() {
return supportsActivityTracking();

View File

@ -100,6 +100,7 @@ public abstract class AbstractTimeSampleProvider<T extends AbstractTimeSample> i
return samples.get(0);
}
@Nullable
public T getLastSampleBefore(final long timestampTo) {
final Device dbDevice = DBHelper.findDevice(getDevice(), getSession());
if (dbDevice == null) {
@ -119,6 +120,7 @@ public abstract class AbstractTimeSampleProvider<T extends AbstractTimeSample> i
return !samples.isEmpty() ? samples.get(0) : null;
}
@Nullable
public T getNextSampleAfter(final long timestampFrom) {
final Device dbDevice = DBHelper.findDevice(getDevice(), getSession());
if (dbDevice == null) {

View File

@ -22,6 +22,8 @@ import androidx.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import de.greenrobot.dao.AbstractDao;
import de.greenrobot.dao.Property;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
@ -29,13 +31,16 @@ import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
/**
* Provides a default resting metabolic rate, for devices that do not provide it. Currently it uses the
* Mifflin St Jeor equation. TODO: use the user data at that timestamp, and make the algorithm configurable.
* Mifflin St Jeor equation.
* TODO: use the user data at that timestamp, and make the algorithm configurable.
* TODO: maybe let the user also configure their own static value
*/
public class DefaultRestingMetabolicRateProvider implements TimeSampleProvider<RestingMetabolicRateSample> {
public class DefaultRestingMetabolicRateProvider extends AbstractTimeSampleProvider<RestingMetabolicRateSample> {
private final DaoSession mSession;
private final GBDevice mDevice;
protected DefaultRestingMetabolicRateProvider(final GBDevice device, final DaoSession session) {
public DefaultRestingMetabolicRateProvider(final GBDevice device, final DaoSession session) {
super(device, session);
mDevice = device;
mSession = session;
}
@ -66,13 +71,41 @@ public class DefaultRestingMetabolicRateProvider implements TimeSampleProvider<R
@Override
public RestingMetabolicRateSample createSample() {
throw new UnsupportedOperationException("createSample not supported");
return new DefaultRestingMetabolicRateSample(System.currentTimeMillis());
}
@NonNull
@Override
public AbstractDao<RestingMetabolicRateSample, ?> getSampleDao() {
throw new UnsupportedOperationException("getSampleDao not supported");
}
@NonNull
@Override
protected Property getTimestampSampleProperty() {
throw new UnsupportedOperationException("getTimestampSampleProperty not supported");
}
@NonNull
@Override
protected Property getDeviceIdentifierSampleProperty() {
throw new UnsupportedOperationException("getDeviceIdentifierSampleProperty not supported");
}
@Nullable
@Override
public RestingMetabolicRateSample getLatestSample() {
return new DefaultRestingMetabolicRateSample();
return new DefaultRestingMetabolicRateSample(System.currentTimeMillis());
}
@Nullable
public RestingMetabolicRateSample getLastSampleBefore(final long timestampTo) {
return new DefaultRestingMetabolicRateSample(timestampTo);
}
@Nullable
public RestingMetabolicRateSample getNextSampleAfter(final long timestampFrom) {
return new DefaultRestingMetabolicRateSample(timestampFrom);
}
@Nullable
@ -81,12 +114,12 @@ public class DefaultRestingMetabolicRateProvider implements TimeSampleProvider<R
return getLatestSample();
}
private static class DefaultRestingMetabolicRateSample extends RestingMetabolicRateSample {
public static class DefaultRestingMetabolicRateSample extends RestingMetabolicRateSample {
private long timestamp;
private final int rate;
private DefaultRestingMetabolicRateSample() {
this.timestamp = System.currentTimeMillis();
public DefaultRestingMetabolicRateSample(final long timestamp) {
this.timestamp = timestamp;
ActivityUser activityUser = new ActivityUser();
final int weightKg = activityUser.getWeightKg();
final int heightCm = activityUser.getHeightCm();

View File

@ -227,7 +227,6 @@ public interface DeviceCoordinator {
boolean supportsStepCounter();
boolean supportsSpeedzones();
boolean supportsActivityTabs();
boolean supportsRestingCalories();
boolean supportsActiveCalories();
/**

View File

@ -255,11 +255,6 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return true;
}
@Override
public boolean supportsRestingCalories() {
return true;
}
@Override
public int[] getStressRanges() {
// 1-25 = relaxed

View File

@ -44,7 +44,6 @@ public class ActivityUser {
private int activityUserSleepDurationGoal;
private int activityUserStepsGoal;
private int activityUserCaloriesBurntGoal;
private int activityUserActiveCaloriesBurntGoal;
private int activityUserDistanceGoalMeters;
private int activityUserActiveTimeGoalMinutes;
private int activityUserStandingTimeGoalHours;

View File

@ -17,9 +17,6 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.model;
import android.content.Context;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -30,9 +27,10 @@ import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ActivityAnalysis;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractTimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.DefaultRestingMetabolicRateProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
@ -160,8 +158,9 @@ public class DailyTotals implements Serializable {
day.set(Calendar.MINUTE, 0);
day.set(Calendar.SECOND, 0);
day.add(Calendar.HOUR, 0);
RestingMetabolicRateSample metabolicRate = getRestingMetabolicRate(db, device);
RestingMetabolicRateSample metabolicRate = getRestingMetabolicRate(db, day, device);
if (metabolicRate == null) {
// should never happen
return 0;
}
double passedDayProportion = 1;
@ -177,9 +176,17 @@ public class DailyTotals implements Serializable {
return getAllSamples(db, device, tsFrom, tsTo);
}
protected static RestingMetabolicRateSample getRestingMetabolicRate(DBHandler db, GBDevice device) {
TimeSampleProvider<? extends RestingMetabolicRateSample> provider = device.getDeviceCoordinator().getRestingMetabolicRateProvider(device, db.getDaoSession());
return provider.getLatestSample();
protected static RestingMetabolicRateSample getRestingMetabolicRate(DBHandler db, Calendar day, GBDevice device) {
// FIXME this cast is ugly and might lead to issues
AbstractTimeSampleProvider<? extends RestingMetabolicRateSample> provider = (AbstractTimeSampleProvider<? extends RestingMetabolicRateSample>)
device.getDeviceCoordinator().getRestingMetabolicRateProvider(device, db.getDaoSession());
final long endOfDayTimestamp = day.getTimeInMillis() + 86_400_000L;
final RestingMetabolicRateSample latestSample = provider.getLastSampleBefore(endOfDayTimestamp);
if (latestSample != null) {
return latestSample;
}
DefaultRestingMetabolicRateProvider defaultProvider = new DefaultRestingMetabolicRateProvider(device, db.getDaoSession());
return defaultProvider.getLastSampleBefore(endOfDayTimestamp);
}
protected static SampleProvider<? extends AbstractActivitySample> getProvider(DBHandler db, GBDevice device) {

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2024 Severin von Wnuck-Lipinski
/* Copyright (C) 2024 José Rebelo
This file is part of Gadgetbridge.

View File

@ -68,7 +68,7 @@ public class DashboardUtils {
int totalActiveCalories = 0;
try (DBHandler dbHandler = GBApplication.acquireDB()) {
for (GBDevice dev : devices) {
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsActivityTracking()) {
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsActiveCalories()) {
totalActiveCalories += (int) getDailyTotals(dev, dbHandler, dashboardData.timeTo).getActiveCalories();
}
}
@ -83,7 +83,7 @@ public class DashboardUtils {
int totalRestingCalories = 0;
try (DBHandler dbHandler = GBApplication.acquireDB()) {
for (GBDevice dev : devices) {
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsActivityTracking()) {
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsActiveCalories()) {
totalRestingCalories += (int) getDailyTotals(dev, dbHandler, dashboardData.timeTo).getRestingCalories();
}
}

View File

@ -19,26 +19,26 @@
android:textSize="20sp" />
<ImageView
android:id="@+id/calories_gauge"
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_gravity="center"
android:scaleType="fitStart"
android:id="@+id/calories_gauge" />
android:scaleType="fitStart" />
<GridLayout
android:id="@+id/calories_types_wrapper"
android:background="@color/gauge_line_color"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:layout_marginTop="15dp"
>
android:background="@color/gauge_line_color"
android:columnCount="2">
<LinearLayout
android:id="@+id/calories_active_wrapper"
style="@style/GridTile"
android:layout_marginEnd="1dp"
android:layout_marginTop="2dp"
>
android:layout_marginEnd="1dp">
<TextView
android:id="@+id/calories_active"
android:layout_width="wrap_content"
@ -49,14 +49,16 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/active"
android:text="@string/active_calories_short"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/calories_resting_wrapper"
style="@style/GridTile"
android:layout_marginEnd="1dp"
>
android:layout_marginStart="1dp"
android:layout_marginTop="2dp">
<TextView
android:id="@+id/calories_resting"
android:layout_width="wrap_content"
@ -70,12 +72,12 @@
android:text="@string/hr_resting"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/calories_active_goal_wrapper"
style="@style/GridTile"
android:layout_marginStart="1dp"
android:layout_marginTop="2dp"
>
android:layout_marginEnd="1dp">
<TextView
android:id="@+id/calories_active_goal"
android:layout_width="wrap_content"
@ -86,24 +88,15 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/active_goal"
android:text="@string/active_calories_goal"
android:textSize="12sp" />
</LinearLayout>
<!-- empty tile -->
<LinearLayout
style="@style/GridTile"
android:layout_marginEnd="1dp"
>
</LinearLayout>
android:layout_marginStart="1dp" />
</GridLayout>
<TextView
android:id="@+id/steps_chart_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:paddingLeft="20dip"
android:text=""
android:textSize="20sp" />
</LinearLayout>
</ScrollView>

View File

@ -3113,7 +3113,7 @@
<item>@string/pref_header_spo2</item>
<item>@string/menuitem_temperature</item>
<item>@string/menuitem_weight</item>
<item>@string/menuitem_calories</item>
<item>@string/watchface_widget_type_calories</item>
</string-array>
<string-array name="pref_charts_tabs_values">

View File

@ -936,10 +936,9 @@
<string name="hr_maximum">Maximum</string>
<string name="hr_minimum">Minimum</string>
<string name="hr_average">Average</string>
<string name="active">Active</string>
<string name="active_goal">Active goal</string>
<string name="total_burnt">Total burnt</string>
<string name="goal">Goal</string>
<string name="active_calories_short">Active</string>
<string name="active_calories_goal">Active goal</string>
<string name="total_calories_burnt">Total burnt</string>
<string name="blood_pressure">Blood pressure</string>
<string name="getting_heart_rate">Measuring</string>
<string name="heart_rate_result">Measurement results</string>
@ -1945,8 +1944,8 @@
<string name="menuitem_stress_simple">Stress (simple)</string>
<string name="menuitem_stress_segmented">Stress (segmented)</string>
<string name="menuitem_stress_breakdown">Stress (breakdown)</string>
<string name="menuitem_calories_segmented">Calories(segmented)</string>
<string name="menuitem_calories_active_goal">Calories goal(active)</string>
<string name="menuitem_calories_segmented">Calories (segmented)</string>
<string name="menuitem_calories_active_goal">Calories goal (active)</string>
<string name="menuitem_pai">PAI</string>
<string name="menuitem_hr">Heart Rate</string>
<string name="menuitem_spo2">SpO2</string>
@ -1967,7 +1966,6 @@
<string name="menuitem_widgets">Widgets</string>
<string name="menuitem_temperature">Temperature</string>
<string name="menuitem_weight">Weight</string>
<string name="menuitem_calories">Calories</string>
<string name="menuitem_barometer">Barometer</string>
<string name="menuitem_flashlight">Flashlight</string>
<string name='menuitem_email'>E-mail</string>