mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Merge pull request 'Garmin: enhance activity summaries' (#5996)
Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/5996
This commit is contained in:
+33
@@ -100,6 +100,9 @@ object ActivitySummaryGroup {
|
||||
ActivitySummaryEntries.HR_AVG,
|
||||
ActivitySummaryEntries.HR_MAX,
|
||||
ActivitySummaryEntries.HR_MIN,
|
||||
ActivitySummaryEntries.RECOVERY_HR,
|
||||
ActivitySummaryEntries.HR_USER_RESTING,
|
||||
ActivitySummaryEntries.HR_USER_MAX,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -180,6 +183,7 @@ object ActivitySummaryGroup {
|
||||
ActivitySummaryEntries.AVG_RIGHT_POWER_PHASE_PEAK,
|
||||
ActivitySummaryEntries.AVG_POWER_SEATING,
|
||||
ActivitySummaryEntries.AVG_POWER_STANDING,
|
||||
ActivitySummaryEntries.TOTAL_WORK,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -240,6 +244,10 @@ object ActivitySummaryGroup {
|
||||
ActivitySummaryEntries.MAX_CADENCE_SEATING,
|
||||
ActivitySummaryEntries.FRONT_GEAR_SHIFTS,
|
||||
ActivitySummaryEntries.REAR_GEAR_SHIFTS,
|
||||
ActivitySummaryEntries.BATTERY_LEVEL_EBIKE_START,
|
||||
ActivitySummaryEntries.BATTERY_LEVEL_EBIKE_END,
|
||||
ActivitySummaryEntries.MOUNTAIN_BIKE_GRIT_SCORE,
|
||||
ActivitySummaryEntries.MOUNTAIN_BIKE_FLOW_SCORE,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -248,13 +256,19 @@ object ActivitySummaryGroup {
|
||||
ActivitySummaryEntries.GROUP_TRAINING_EFFECT, listOf<String>(
|
||||
ActivitySummaryEntries.TRAINING_EFFECT_AEROBIC,
|
||||
ActivitySummaryEntries.TRAINING_EFFECT_ANAEROBIC,
|
||||
ActivitySummaryEntries.TRAINING_EFFECT_TOTAL,
|
||||
ActivitySummaryEntries.WORKOUT_LOAD,
|
||||
ActivitySummaryEntries.TRAINING_LOAD,
|
||||
ActivitySummaryEntries.INTENSITY_FACTOR,
|
||||
ActivitySummaryEntries.TRAINING_STRESS_SCORE,
|
||||
ActivitySummaryEntries.MAXIMUM_OXYGEN_UPTAKE,
|
||||
ActivitySummaryEntries.RECOVERY_TIME_REMAINING_AT_START,
|
||||
ActivitySummaryEntries.RECOVERY_TIME,
|
||||
ActivitySummaryEntries.BODY_ENERGY_AT_START,
|
||||
ActivitySummaryEntries.BODY_ENERGY_AT_END,
|
||||
ActivitySummaryEntries.LACTATE_THRESHOLD_HR,
|
||||
ActivitySummaryEntries.RATING_OF_PERCEIVED_EXERTION,
|
||||
ActivitySummaryEntries.WORKOUT_FEEL,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -298,9 +312,14 @@ object ActivitySummaryGroup {
|
||||
ActivitySummaryEntries.BOTTOM_TIME,
|
||||
ActivitySummaryEntries.OXYGEN_TOXICITY,
|
||||
ActivitySummaryEntries.SURFACE_INTERVAL,
|
||||
ActivitySummaryEntries.PRESSURE_SAC_AVG,
|
||||
ActivitySummaryEntries.WATER_TYPE
|
||||
)
|
||||
)
|
||||
|
||||
// Diving Gas
|
||||
put(ActivitySummaryEntries.GROUP_GAS, listOf())
|
||||
|
||||
// Recovery Heart Rate
|
||||
put(ActivitySummaryEntries.GROUP_RECOVERY_HEART_RATE, listOf<String>())
|
||||
|
||||
@@ -359,6 +378,16 @@ object ActivitySummaryGroup {
|
||||
ActivitySummaryEntries.STRIDE_TOTAL,
|
||||
))
|
||||
|
||||
|
||||
// Gear Info - e.g. last battery level
|
||||
put(
|
||||
ActivitySummaryEntries.GROUP_GEAR_INFO, listOf(
|
||||
ActivitySummaryEntries.BATTERY_LEVEL_START,
|
||||
ActivitySummaryEntries.BATTERY_LEVEL_END,
|
||||
ActivitySummaryEntries.BATTERY_GAIN
|
||||
)
|
||||
)
|
||||
|
||||
// Other
|
||||
put(
|
||||
ActivitySummaryEntries.GROUP_OTHER, listOf<String>(
|
||||
@@ -367,6 +396,10 @@ object ActivitySummaryGroup {
|
||||
ActivitySummaryEntries.CALORIES_BURNT,
|
||||
ActivitySummaryEntries.CALORIES_TOTAL,
|
||||
ActivitySummaryEntries.CALORIES_RESTING,
|
||||
ActivitySummaryEntries.CALORIES_CONSUMED,
|
||||
ActivitySummaryEntries.SPO2_AVG,
|
||||
ActivitySummaryEntries.STRESS_AVG,
|
||||
ActivitySummaryEntries.SOLAR_INTENSITY,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+4
@@ -27,6 +27,10 @@ public class ActivitySummaryTableBuilder {
|
||||
rows.put(rowId, row);
|
||||
}
|
||||
|
||||
public boolean hasRows() {
|
||||
return !rows.isEmpty();
|
||||
}
|
||||
|
||||
public void addToSummaryData(final ActivitySummaryData summaryData) {
|
||||
final int numColumns = headerColumns.size();
|
||||
final boolean[] anyNonNullOrZero = new boolean[numColumns];
|
||||
|
||||
+288
-104
@@ -32,7 +32,9 @@ import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.charts.DefaultWorkoutCharts;
|
||||
@@ -51,9 +53,14 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitFile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.enums.GarminSport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.exception.FitParseException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBatteryStatus.BatteryStatus;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionExerciseCategory.ExerciseCategory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionMeasurementSystem;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWaterType.WaterType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDeviceInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDeviceStatus;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDiveGas;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDiveSettings;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDiveSummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitLap;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitPhysiologicalMetrics;
|
||||
@@ -62,7 +69,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitSet;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitSport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitTimeInZone;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitUserMetrics;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitUserProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitWorkout;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
@@ -76,12 +85,25 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
private List<ActivityPoint> sessionActivityPoints;
|
||||
private FitSession session = null;
|
||||
private FitSport sport = null;
|
||||
private FitUserMetrics userMetrics = null;
|
||||
private FitUserProfile userProfile = null;
|
||||
private FitPhysiologicalMetrics physiologicalMetrics = null;
|
||||
private FitDiveSettings diveSettings = null;
|
||||
private FitDiveSummary diveSummary = null;
|
||||
private final List<FitDiveGas> diveGases = new ArrayList<>();
|
||||
private final List<FitSet> sets = new ArrayList<>();
|
||||
private final List<FitLap> laps = new ArrayList<>();
|
||||
private final Map<Integer, FitDeviceInfo> deviceInfos = new TreeMap<>();
|
||||
@Nullable
|
||||
private FitDeviceStatus deviceStatusStart = null;
|
||||
@Nullable
|
||||
private FitDeviceStatus deviceStatusEnd = null;
|
||||
@Nullable
|
||||
private Number ebikeBatteryStart = null;
|
||||
@Nullable
|
||||
private Number ebikeBatteryEnd = null;
|
||||
@Nullable
|
||||
private FitWorkout workout = null;
|
||||
|
||||
public GarminWorkoutParser(final Context context) {
|
||||
this.context = context;
|
||||
@@ -161,17 +183,33 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
activityPoints.clear();
|
||||
session = null;
|
||||
sport = null;
|
||||
userMetrics = null;
|
||||
userProfile = null;
|
||||
physiologicalMetrics = null;
|
||||
diveSettings = null;
|
||||
diveSummary = null;
|
||||
diveGases.clear();
|
||||
sets.clear();
|
||||
laps.clear();
|
||||
deviceInfos.clear();
|
||||
deviceStatusStart = null;
|
||||
deviceStatusEnd = null;
|
||||
ebikeBatteryStart = null;
|
||||
ebikeBatteryEnd = null;
|
||||
workout = null;
|
||||
}
|
||||
|
||||
public boolean handleRecord(final RecordData record) {
|
||||
if (record instanceof FitRecord) {
|
||||
activityPoints.add(((FitRecord) record).toActivityPoint());
|
||||
if (record instanceof FitRecord fitRecord) {
|
||||
activityPoints.add(fitRecord.toActivityPoint());
|
||||
final Integer ebikeBattery = fitRecord.getEbikeBatteryLevel();
|
||||
if (ebikeBattery != null) {
|
||||
if (ebikeBatteryStart == null) {
|
||||
ebikeBatteryStart = ebikeBattery;
|
||||
} else {
|
||||
ebikeBatteryEnd = ebikeBattery;
|
||||
}
|
||||
}
|
||||
} else if (record instanceof FitSession) {
|
||||
LOG.debug("Session: {}", record);
|
||||
if (session != null) {
|
||||
@@ -209,6 +247,12 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
// We only support 1 user profile
|
||||
userProfile = (FitUserProfile) record;
|
||||
}
|
||||
} else if (record instanceof FitUserMetrics metrics) {
|
||||
if (userMetrics != null) {
|
||||
LOG.warn("Got multiple user metrics - NOT SUPPORTED: {}", record);
|
||||
} else {
|
||||
userMetrics = metrics;
|
||||
}
|
||||
} else if (record instanceof FitDiveSummary newDiveSummary) {
|
||||
LOG.trace("Dive summary: {}", record);
|
||||
if (diveSummary != null) {
|
||||
@@ -229,6 +273,53 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
} else if (record instanceof FitDiveGas) {
|
||||
LOG.trace("Dive gas: {}", record);
|
||||
diveGases.add((FitDiveGas) record);
|
||||
}else if(record instanceof FitDiveSettings settings){
|
||||
if (diveSettings != null) {
|
||||
LOG.warn("Got multiple dive settings - NOT SUPPORTED: {}", record);
|
||||
} else {
|
||||
diveSettings = settings;
|
||||
}
|
||||
} else if (record instanceof FitDeviceInfo deviceInfo) {
|
||||
Integer deviceIndex = deviceInfo.getDeviceIndex();
|
||||
if (deviceIndex == null) {
|
||||
// Suunto quirk
|
||||
deviceIndex = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
boolean relevant = false;
|
||||
// extract the latest battery related information
|
||||
final Integer level = deviceInfo.getBatteryLevel();
|
||||
if (level != null && level != 0) {
|
||||
relevant = true;
|
||||
} else {
|
||||
final Float volt = deviceInfo.getBatteryVoltage();
|
||||
if (volt != null && volt != 0) {
|
||||
relevant = true;
|
||||
} else {
|
||||
BatteryStatus batteryStatus = deviceInfo.getBatteryStatus();
|
||||
if (batteryStatus != null && batteryStatus != BatteryStatus.Unknown) {
|
||||
relevant = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (relevant) {
|
||||
deviceInfos.put(deviceIndex, deviceInfo);
|
||||
}
|
||||
} else if (record instanceof FitDeviceStatus deviceStatus) {
|
||||
if (deviceStatusStart == null) {
|
||||
deviceStatusStart = deviceStatus;
|
||||
} else {
|
||||
deviceStatusEnd = deviceStatus;
|
||||
}
|
||||
// FitImporter implements the main processing for these records
|
||||
return false;
|
||||
} else if (record instanceof FitWorkout fitWorkout) {
|
||||
if (workout != null) {
|
||||
LOG.warn("Got multiple workout - NOT SUPPORTED: {}", record);
|
||||
} else {
|
||||
workout = fitWorkout;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -245,13 +336,28 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
}
|
||||
|
||||
final ActivityKind activityKind;
|
||||
if (sport != null) {
|
||||
if (StringUtils.isNullOrEmpty(summary.getName())) {
|
||||
summary.setName(sport.getName());
|
||||
|
||||
// prioritize names: FitWorkout > FitSession > FitSport
|
||||
if (StringUtils.isNullOrEmpty(summary.getName())) {
|
||||
String workoutName = null;
|
||||
if (workout != null) {
|
||||
workoutName = workout.getName();
|
||||
}
|
||||
activityKind = getActivityKind(sport.getSport(), sport.getSubSport());
|
||||
} else {
|
||||
if (StringUtils.isNullOrEmpty(workoutName)) {
|
||||
workoutName = session.getSportProfileName();
|
||||
}
|
||||
if (StringUtils.isNullOrEmpty(workoutName) && sport != null) {
|
||||
workoutName = sport.getName();
|
||||
}
|
||||
if (!StringUtils.isNullOrEmpty(workoutName)) {
|
||||
summary.setName(workoutName);
|
||||
}
|
||||
}
|
||||
|
||||
if (sport == null || session.getSport() != null) {
|
||||
activityKind = getActivityKind(session.getSport(), session.getSubSport());
|
||||
} else {
|
||||
activityKind = getActivityKind(sport.getSport(), sport.getSubSport());
|
||||
}
|
||||
final ActivityKind.CycleUnit cycleUnit = ActivityKind.getCycleUnit(activityKind);
|
||||
|
||||
@@ -274,12 +380,8 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
if (session.getTotalDistance() != null) {
|
||||
summaryData.add(DISTANCE_METERS, session.getTotalDistance() / 100f, UNIT_METERS);
|
||||
}
|
||||
if (session.getPoolLength() != null) {
|
||||
summaryData.add(POOL_LENGTH, session.getPoolLength(), UNIT_METERS);
|
||||
}
|
||||
if (session.getAvgSwolf() != null) {
|
||||
summaryData.add(SWOLF_AVG, session.getAvgSwolf(), UNIT_NONE);
|
||||
}
|
||||
summaryData.add(POOL_LENGTH, session.getPoolLength(), UNIT_METERS);
|
||||
summaryData.add(SWOLF_AVG, session.getAvgSwolf(), UNIT_NONE);
|
||||
if (session.getTotalCycles() != null && cycleUnit != ActivityKind.CycleUnit.NONE) {
|
||||
if (cycleUnit == ActivityKind.CycleUnit.STEPS) {
|
||||
summaryData.addTotal(session.getTotalCycles() * 2, cycleUnit);
|
||||
@@ -297,39 +399,30 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
summaryData.add(CALORIES_RESTING, session.getRestingCalories(), UNIT_KCAL);
|
||||
}
|
||||
}
|
||||
if (session.getFluidConsumed() != null) {
|
||||
summaryData.add(FLUID_CONSUMED, session.getFluidConsumed(), UNIT_ML);
|
||||
}
|
||||
if (session.getEstimatedSweatLoss() != null) {
|
||||
summaryData.add(ESTIMATED_SWEAT_LOSS, session.getEstimatedSweatLoss(), UNIT_ML);
|
||||
}
|
||||
if (session.getAverageHeartRate() != null) {
|
||||
summaryData.add(HR_AVG, session.getAverageHeartRate(), UNIT_BPM);
|
||||
}
|
||||
if (session.getMaxHeartRate() != null) {
|
||||
summaryData.add(HR_MAX, session.getMaxHeartRate(), UNIT_BPM);
|
||||
}
|
||||
if (session.getHrvSdrr() != null) {
|
||||
summaryData.add(HRV_SDRR, session.getHrvSdrr(), UNIT_MILLISECONDS);
|
||||
}
|
||||
if (session.getHrvRmssd() != null) {
|
||||
summaryData.add(HRV_RMSSD, session.getHrvRmssd(), UNIT_MILLISECONDS);
|
||||
}
|
||||
if (session.getAvgSpo2() != null) {
|
||||
summaryData.add(SPO2_AVG, session.getAvgSpo2(), UNIT_PERCENTAGE);
|
||||
}
|
||||
if (session.getEnhancedMinRespirationRate() != null) {
|
||||
summaryData.add(RESPIRATION_MIN, session.getEnhancedMinRespirationRate(), UNIT_BREATHS_PER_MIN);
|
||||
}
|
||||
if (session.getEnhancedMaxRespirationRate() != null) {
|
||||
summaryData.add(RESPIRATION_MAX, session.getEnhancedMaxRespirationRate(), UNIT_BREATHS_PER_MIN);
|
||||
}
|
||||
if (session.getEnhancedAvgRespirationRate() != null) {
|
||||
summaryData.add(RESPIRATION_AVG, session.getEnhancedAvgRespirationRate(), UNIT_BREATHS_PER_MIN);
|
||||
}
|
||||
if (session.getAvgStress() != null) {
|
||||
summaryData.add(STRESS_AVG, session.getAvgStress(), UNIT_NONE);
|
||||
}
|
||||
summaryData.add(FLUID_CONSUMED, session.getFluidConsumed(), UNIT_ML);
|
||||
summaryData.add(ESTIMATED_SWEAT_LOSS, session.getEstimatedSweatLoss(), UNIT_ML);
|
||||
summaryData.add(HR_MIN, session.getMinHeartRate(), UNIT_BPM);
|
||||
summaryData.add(HR_AVG, session.getAverageHeartRate(), UNIT_BPM);
|
||||
summaryData.add(HR_MAX, session.getMaxHeartRate(), UNIT_BPM);
|
||||
summaryData.add(HRV_SDRR, session.getHrvSdrr(), UNIT_MILLISECONDS);
|
||||
summaryData.add(HRV_RMSSD, session.getHrvRmssd(), UNIT_MILLISECONDS);
|
||||
summaryData.add(SPO2_AVG, session.getAvgSpo2(), UNIT_PERCENTAGE);
|
||||
|
||||
summaryData.add(RESPIRATION_MIN, UNIT_BREATHS_PER_MIN,
|
||||
session.getEnhancedMinRespirationRate(), session.getMinRespirationRate());
|
||||
summaryData.add(RESPIRATION_MAX, UNIT_BREATHS_PER_MIN,
|
||||
session.getEnhancedMaxRespirationRate(), session.getMaxRespirationRate());
|
||||
summaryData.add(RESPIRATION_AVG, UNIT_BREATHS_PER_MIN,
|
||||
session.getEnhancedAvgRespirationRate(), session.getAvgRespirationRate());
|
||||
|
||||
summaryData.add(ALTITUDE_MIN, UNIT_METERS,
|
||||
session.getEnhancedMinAltitude(), session.getMinAltitude());
|
||||
summaryData.add(ALTITUDE_MAX, UNIT_METERS,
|
||||
session.getEnhancedMaxAltitude(), session.getMaxAltitude());
|
||||
summaryData.add(ALTITUDE_AVG, UNIT_METERS,
|
||||
session.getEnhancedAvgAltitude(), session.getAvgAltitude());
|
||||
|
||||
summaryData.add(STRESS_AVG, session.getAvgStress(), UNIT_NONE);
|
||||
if (session.getAvgCadence() != null) {
|
||||
if (cycleUnit == ActivityKind.CycleUnit.STEPS) {
|
||||
summaryData.addCadenceAvg(session.getAvgCadence() * 2, cycleUnit);
|
||||
@@ -346,46 +439,51 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
summaryData.addCadenceMax(session.getMaxCadence(), cycleUnit);
|
||||
}
|
||||
}
|
||||
if (session.getTotalAscent() != null && !ActivityKind.isDiving(activityKind)) {
|
||||
if (!ActivityKind.isDiving(activityKind)) {
|
||||
summaryData.add(TOTAL_ASCENT, session.getTotalAscent(), UNIT_METERS);
|
||||
}
|
||||
if (session.getTotalDescent() != null && !ActivityKind.isDiving(activityKind)) {
|
||||
summaryData.add(TOTAL_DESCENT, session.getTotalDescent(), UNIT_METERS);
|
||||
if (session.getAvgVam() != null) {
|
||||
summaryData.add(AVERAGE_ASCENT_VELOCITY, session.getAvgVam() * 3600, UNIT_METERS_PER_HOUR);
|
||||
}
|
||||
}
|
||||
if (session.getAvgVam() != null && !ActivityKind.isDiving(activityKind)) {
|
||||
summaryData.add(AVERAGE_ASCENT_VELOCITY, session.getAvgVam() * 3600, UNIT_METERS_PER_HOUR);
|
||||
}
|
||||
if (session.getAvgSwimCadence() != null) {
|
||||
summaryData.add(SWIM_AVG_CADENCE, session.getAvgSwimCadence(), UNIT_STROKES_PER_LENGTH);
|
||||
}
|
||||
summaryData.add(SWIM_AVG_CADENCE, session.getAvgSwimCadence(), UNIT_STROKES_PER_LENGTH);
|
||||
|
||||
if (session.getEnhancedAvgSpeed() != null) {
|
||||
Number speedAvg = session.getEnhancedAvgSpeed();
|
||||
if(speedAvg == null){
|
||||
speedAvg = session.getAvgSpeed();
|
||||
}
|
||||
if (speedAvg != null) {
|
||||
if (ActivityKind.isPaceActivity(activityKind)) {
|
||||
summaryData.add(PACE_AVG_SECONDS_KM, Math.round((60 / (session.getEnhancedAvgSpeed() * 3.6)) * 60), UNIT_SECONDS);
|
||||
summaryData.add(PACE_AVG_SECONDS_KM, Math.round((60 / (speedAvg.doubleValue() * 3.6)) * 60), UNIT_SECONDS);
|
||||
} else if (ActivityKind.isDiving(activityKind)) {
|
||||
// Hide speed for diving activities
|
||||
} else {
|
||||
summaryData.add(SPEED_AVG, Math.round((session.getEnhancedAvgSpeed() * 3600 / 1000) * 100.0) / 100.0, UNIT_KMPH);
|
||||
summaryData.add(SPEED_AVG, speedAvg.doubleValue() * 3600 / 1000, UNIT_KMPH);
|
||||
}
|
||||
}
|
||||
|
||||
if (session.getEnhancedMaxSpeed() != null) {
|
||||
Number speedMax = session.getEnhancedMaxSpeed();
|
||||
if(speedMax == null){
|
||||
speedMax = session.getMaxSpeed();
|
||||
}
|
||||
if (speedMax != null) {
|
||||
if (ActivityKind.isPaceActivity(activityKind)) {
|
||||
summaryData.add(PACE_MAX, Math.round((60 / (session.getEnhancedMaxSpeed() * 3.6)) * 60), UNIT_SECONDS);
|
||||
} else if (ActivityKind.isDiving(activityKind)) { // Hide average speed for diving activities
|
||||
summaryData.add(PACE_MAX, Math.round((60 / (speedMax.doubleValue() * 3.6)) * 60), UNIT_SECONDS);
|
||||
} else if (ActivityKind.isDiving(activityKind)) {
|
||||
// Hide speed for diving activities
|
||||
} else {
|
||||
summaryData.add(SPEED_MAX, Math.round((session.getEnhancedMaxSpeed() * 3600 / 1000) * 100.0) / 100.0, UNIT_KMPH);
|
||||
summaryData.add(SPEED_MAX, speedMax.doubleValue() * 3600 / 1000, UNIT_KMPH);
|
||||
}
|
||||
}
|
||||
|
||||
if (session.getRecoveryHeartRate() != null){
|
||||
summaryData.add(RECOVERY_HR, session.getRecoveryHeartRate(), UNIT_BPM);
|
||||
}
|
||||
if (session.getWorkoutRpe() != null){
|
||||
summaryData.add(RATING_OF_PERCEIVED_EXERTION, session.getWorkoutRpe(), UNIT_PERCENTAGE);
|
||||
}
|
||||
summaryData.add(RECOVERY_HR, session.getRecoveryHeartRate(), UNIT_BPM);
|
||||
summaryData.add(RATING_OF_PERCEIVED_EXERTION, session.getWorkoutRpe(), UNIT_PERCENTAGE);
|
||||
summaryData.add(WORKOUT_FEEL, session.getWorkoutFeel(), UNIT_PERCENTAGE);
|
||||
|
||||
summaryData.add(AVG_POWER, session.getAvgPower(), UNIT_WATT);
|
||||
summaryData.add(MAX_POWER, session.getMaxPower(), UNIT_WATT);
|
||||
summaryData.add(NORMALIZED_POWER, session.getNormalizedPower(), UNIT_WATT);
|
||||
summaryData.add(TOTAL_WORK, session.getTotalWork(), UNIT_JOULE);
|
||||
|
||||
if (session.getStandTime() != null) {
|
||||
summaryData.add(STANDING_TIME, session.getStandTime() / 1000, UNIT_SECONDS);
|
||||
@@ -596,63 +694,61 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
if (physiologicalMetrics.getRecoveryTime() != null) {
|
||||
summaryData.add(RECOVERY_TIME, physiologicalMetrics.getRecoveryTime() * 60, UNIT_SECONDS);
|
||||
}
|
||||
if (physiologicalMetrics.getLactateThresholdHeartRate() != null) {
|
||||
summaryData.add(LACTATE_THRESHOLD_HR, physiologicalMetrics.getLactateThresholdHeartRate(), UNIT_BPM);
|
||||
}
|
||||
summaryData.add(LACTATE_THRESHOLD_HR, physiologicalMetrics.getLactateThresholdHeartRate(), UNIT_BPM);
|
||||
}
|
||||
summaryData.add(TRAINING_LOAD, safeRound(session.getTrainingLoadPeak()), UNIT_NONE);
|
||||
|
||||
if (diveSummary != null) {
|
||||
if (diveSummary.getDiveNumber() != null) {
|
||||
summaryData.add(DIVE_NUMBER, diveSummary.getDiveNumber(), UNIT_NONE);
|
||||
}
|
||||
if (diveSummary.getBottomTime() != null) {
|
||||
summaryData.add(BOTTOM_TIME, diveSummary.getBottomTime(), UNIT_SECONDS);
|
||||
}
|
||||
if (diveSummary.getAvgDepth() != null) {
|
||||
summaryData.add(AVG_DEPTH, diveSummary.getAvgDepth(), UNIT_METERS);
|
||||
}
|
||||
if (diveSummary.getMaxDepth() != null) {
|
||||
summaryData.add(MAX_DEPTH, diveSummary.getMaxDepth(), UNIT_METERS);
|
||||
}
|
||||
summaryData.add(DIVE_NUMBER, diveSummary.getDiveNumber(), UNIT_NONE);
|
||||
summaryData.add(BOTTOM_TIME, diveSummary.getBottomTime(), UNIT_SECONDS);
|
||||
summaryData.add(AVG_DEPTH, diveSummary.getAvgDepth(), UNIT_METERS);
|
||||
summaryData.add(MAX_DEPTH, diveSummary.getMaxDepth(), UNIT_METERS);
|
||||
if (diveSummary.getStartCns() != null) {
|
||||
summaryData.add(START_CNS, diveSummary.getStartCns(), UNIT_PERCENTAGE, true);
|
||||
}
|
||||
if (diveSummary.getEndCns() != null) {
|
||||
summaryData.add(END_CNS, diveSummary.getEndCns(), UNIT_PERCENTAGE);
|
||||
}
|
||||
summaryData.add(END_CNS, diveSummary.getEndCns(), UNIT_PERCENTAGE);
|
||||
if (diveSummary.getStartN2() != null) {
|
||||
summaryData.add(START_N2, diveSummary.getStartN2(), UNIT_PERCENTAGE, true);
|
||||
}
|
||||
if (diveSummary.getEndN2() != null) {
|
||||
summaryData.add(END_N2, diveSummary.getEndN2(), UNIT_PERCENTAGE);
|
||||
}
|
||||
if (diveSummary.getO2Toxicity() != null) {
|
||||
summaryData.add(OXYGEN_TOXICITY, diveSummary.getO2Toxicity(), UNIT_OXYGEN_TOXICITY_UNITs);
|
||||
}
|
||||
if (diveSummary.getSurfaceInterval() != null) {
|
||||
summaryData.add(SURFACE_INTERVAL, diveSummary.getSurfaceInterval(), UNIT_SECONDS);
|
||||
summaryData.add(END_N2, diveSummary.getEndN2(), UNIT_PERCENTAGE);
|
||||
summaryData.add(OXYGEN_TOXICITY, diveSummary.getO2Toxicity(), UNIT_OXYGEN_TOXICITY_UNITs);
|
||||
summaryData.add(SURFACE_INTERVAL, diveSummary.getSurfaceInterval(), UNIT_SECONDS);
|
||||
summaryData.add(PRESSURE_SAC_AVG, diveSummary.getAvgPressureSac(), UNIT_BAR_PER_MINUTE);
|
||||
}
|
||||
|
||||
if (diveSettings != null) {
|
||||
if (diveSettings.getWaterDensity() != null) {
|
||||
summaryData.add(WATER_TYPE, diveSettings.getWaterDensity(), UNIT_KG_PER_M3);
|
||||
} else {
|
||||
WaterType waterType = diveSettings.getWaterType();
|
||||
if (waterType != null) {
|
||||
summaryData.add(WATER_TYPE, waterType.toString(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
summaryData.add(TEMPERATURE_MIN, session.getMinTemperature(), UNIT_CELSIUS);
|
||||
summaryData.add(TEMPERATURE_MAX, session.getMaxTemperature(), UNIT_CELSIUS);
|
||||
summaryData.add(TEMPERATURE_AVG, session.getAvgTemperature(), UNIT_CELSIUS);
|
||||
|
||||
// MTB-specific metrics
|
||||
summaryData.add("activity_type_mountain_bike", MOUNTAIN_BIKE_GRIT_SCORE, session.getTotalGrit(), UNIT_NONE);
|
||||
summaryData.add("activity_type_mountain_bike", MOUNTAIN_BIKE_FLOW_SCORE, session.getAvgFlow(), UNIT_NONE);
|
||||
summaryData.add(BATTERY_LEVEL_EBIKE_START, ebikeBatteryStart, UNIT_PERCENTAGE);
|
||||
summaryData.add(BATTERY_LEVEL_EBIKE_END, ebikeBatteryEnd, UNIT_PERCENTAGE);
|
||||
|
||||
summaryData.add(TRAINING_LOAD, safeRound(session.getTrainingLoadPeak()), UNIT_NONE);
|
||||
// MTB-specific metrics
|
||||
summaryData.add(MOUNTAIN_BIKE_GRIT_SCORE, session.getTotalGrit(), UNIT_NONE);
|
||||
summaryData.add(MOUNTAIN_BIKE_FLOW_SCORE, session.getAvgFlow(), UNIT_NONE);
|
||||
|
||||
summaryData.add(TRAINING_LOAD, session.getTrainingLoadPeak(), UNIT_NONE);
|
||||
summaryData.add(INTENSITY_FACTOR, session.getIntensityFactor(), UNIT_NONE);
|
||||
summaryData.add(TRAINING_STRESS_SCORE, session.getTrainingStressScore(), UNIT_NONE);
|
||||
summaryData.add(TRAINING_EFFECT_TOTAL, session.getTotalTrainingEffect(), UNIT_NONE);
|
||||
summaryData.add(BODY_ENERGY_AT_START, session.getBeginningBodyBattery(), UNIT_PERCENTAGE);
|
||||
summaryData.add(BODY_ENERGY_AT_END, session.getEndingBodyBattery(), UNIT_PERCENTAGE);
|
||||
|
||||
summaryData.add(SOLAR_INTENSITY, safeRound(session.getSolarIntensity()), UNIT_PERCENTAGE);
|
||||
if (session.getBatteryGain() != null) {
|
||||
summaryData.add(BATTERY_GAIN, session.getBatteryGain(), UNIT_SECONDS);
|
||||
}
|
||||
summaryData.add(BATTERY_GAIN, session.getBatteryGain(), UNIT_SECONDS);
|
||||
|
||||
if (!diveGases.isEmpty()) {
|
||||
final ActivitySummaryTableBuilder tableBuilder = new ActivitySummaryTableBuilder(GAS, "gases_header", Arrays.asList(
|
||||
final ActivitySummaryTableBuilder tableBuilder = new ActivitySummaryTableBuilder(GROUP_GAS, "gases_header", Arrays.asList(
|
||||
"diving_gas",
|
||||
"helium_content",
|
||||
"oxygen_content",
|
||||
@@ -661,6 +757,12 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
|
||||
int i = 1;
|
||||
for (final FitDiveGas gas : diveGases) {
|
||||
final Integer gasStatus = gas.getStatus();
|
||||
if (gasStatus != null && gasStatus == 0) {
|
||||
// ignore disabled gasses
|
||||
continue;
|
||||
}
|
||||
|
||||
int helium = gas.getHeliumContent() != null ? gas.getHeliumContent() : 0;
|
||||
int oxygen = gas.getOxygenContent() != null ? gas.getOxygenContent() : 0;
|
||||
int nitrogen = 100 - helium - oxygen;
|
||||
@@ -676,7 +778,89 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
i++;
|
||||
}
|
||||
|
||||
tableBuilder.addToSummaryData(summaryData);
|
||||
if (tableBuilder.hasRows()) {
|
||||
tableBuilder.addToSummaryData(summaryData);
|
||||
}
|
||||
}
|
||||
|
||||
if (userProfile != null) {
|
||||
summaryData.add(HR_USER_RESTING, userProfile.getRestingHeartRate(), UNIT_BPM);
|
||||
}
|
||||
|
||||
if (userMetrics != null) {
|
||||
final Integer remainingRecoveryTime = userMetrics.getRemainingRecoveryTime();
|
||||
if (remainingRecoveryTime != null && remainingRecoveryTime > 1) {
|
||||
summaryData.add(RECOVERY_TIME_REMAINING_AT_START, userMetrics.getRemainingRecoveryTime() * 60, UNIT_SECONDS);
|
||||
}
|
||||
summaryData.add(HR_USER_MAX, userMetrics.getMaxHr(), UNIT_BPM);
|
||||
}
|
||||
|
||||
if (!deviceInfos.isEmpty()) {
|
||||
final ActivitySummaryTableBuilder tableBuilder = new ActivitySummaryTableBuilder(GROUP_GEAR_INFO, "gear_info_header", Arrays.asList(
|
||||
"device",
|
||||
"battery_status",
|
||||
"battery_level"
|
||||
));
|
||||
|
||||
for (final Map.Entry<Integer, FitDeviceInfo> entry : deviceInfos.entrySet()) {
|
||||
final Integer deviceIndex = entry.getKey();
|
||||
final FitDeviceInfo deviceInfo = entry.getValue();
|
||||
Object device = deviceInfo.getProductName();
|
||||
if (device == null) {
|
||||
device = deviceInfo.getSerialNumber();
|
||||
if (device == null) {
|
||||
device = deviceIndex;
|
||||
}
|
||||
}
|
||||
|
||||
BatteryStatus rawStatus = deviceInfo.getBatteryStatus();
|
||||
@Nullable final String status;
|
||||
if (rawStatus != null) {
|
||||
status = rawStatus.toString(context);
|
||||
} else {
|
||||
status = null;
|
||||
}
|
||||
|
||||
Number level = deviceInfo.getBatteryLevel();
|
||||
String level_uom = UNIT_PERCENTAGE;
|
||||
if (level == null) {
|
||||
level = deviceInfo.getBatteryVoltage();
|
||||
level_uom = UNIT_VOLT;
|
||||
}
|
||||
|
||||
tableBuilder.addRow(
|
||||
"device_info_" + deviceIndex,
|
||||
Arrays.asList(
|
||||
new ActivitySummaryValue(device, UNIT_NONE),
|
||||
new ActivitySummaryValue(status),
|
||||
new ActivitySummaryValue(level, level_uom)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (tableBuilder.hasRows()) {
|
||||
tableBuilder.addToSummaryData(summaryData);
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceStatusStart != null) {
|
||||
Number batteryLevel = deviceStatusStart.getBatteryLevel();
|
||||
String batteryUom = UNIT_PERCENTAGE;
|
||||
if (batteryLevel == null) {
|
||||
batteryLevel = deviceStatusStart.getBatteryVoltage();
|
||||
batteryUom = UNIT_VOLT;
|
||||
}
|
||||
summaryData.add(BATTERY_LEVEL_START, batteryLevel, batteryUom);
|
||||
}
|
||||
|
||||
if (deviceStatusEnd != null) {
|
||||
Number batteryLevel = deviceStatusEnd.getBatteryLevel();
|
||||
String batteryUom = UNIT_PERCENTAGE;
|
||||
if (batteryLevel == null) {
|
||||
batteryLevel = deviceStatusEnd.getBatteryVoltage();
|
||||
batteryUom = UNIT_VOLT;
|
||||
}
|
||||
summaryData.add(BATTERY_LEVEL_END, batteryLevel, batteryUom);
|
||||
}
|
||||
|
||||
if (!sets.isEmpty()) {
|
||||
|
||||
@@ -112,7 +112,7 @@ public class ActivityPoint {
|
||||
/// nitrogen (N2) tissue load (e.g. Diving)
|
||||
/// @see ActivitySummaryEntries#UNIT_PERCENTAGE
|
||||
public float getN2Load() {
|
||||
return cnsToxicity;
|
||||
return n2Load;
|
||||
}
|
||||
|
||||
/// @see ActivitySummaryEntries#UNIT_METERS
|
||||
|
||||
@@ -66,6 +66,14 @@ public class ActivitySummaryData {
|
||||
add(null, key, value, unit, false);
|
||||
}
|
||||
|
||||
public void add(final String key, final String unit, final Number value, final Number valueFallback) {
|
||||
if (value != null) {
|
||||
add(null, key, value, unit, false);
|
||||
} else {
|
||||
add(null, key, valueFallback, unit, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(final String key, final Number value, final String unit, boolean forceDisplay) {
|
||||
add(null, key, value, unit, forceDisplay);
|
||||
}
|
||||
|
||||
+19
-2
@@ -123,6 +123,8 @@ public class ActivitySummaryEntries {
|
||||
public static final String HR_AVG = "averageHR";
|
||||
public static final String HR_MAX = "maxHR";
|
||||
public static final String HR_MIN = "minHR";
|
||||
public static final String HR_USER_RESTING = "hr_user_resting";
|
||||
public static final String HR_USER_MAX = "hr_user_max";
|
||||
public static final String HR_ZONE_NA = "hrZoneNa";
|
||||
public static final String HR_ZONE_WARM_UP = "hrZoneWarmUp";
|
||||
public static final String HR_ZONE_EASY = "hrZoneEasy";
|
||||
@@ -182,6 +184,7 @@ public class ActivitySummaryEntries {
|
||||
public static final String CALORIES_RESTING = "restingCalories";
|
||||
public static final String TRAINING_EFFECT_AEROBIC = "aerobicTrainingEffect";
|
||||
public static final String TRAINING_EFFECT_ANAEROBIC = "anaerobicTrainingEffect";
|
||||
public static final String TRAINING_EFFECT_TOTAL = "training_effect_total";
|
||||
public static final String WORKOUT_LOAD = "currentWorkoutLoad";
|
||||
public static final String MAXIMUM_OXYGEN_UPTAKE = "maximumOxygenUptake";
|
||||
public static final String RECOVERY_TIME = "recoveryTime";
|
||||
@@ -190,6 +193,7 @@ public class ActivitySummaryEntries {
|
||||
public static final String ESTIMATED_SWEAT_LOSS = "estimatedSweatLoss";
|
||||
public static final String LACTATE_THRESHOLD_HR = "lactateThresholdHeartRate";
|
||||
public static final String RATING_OF_PERCEIVED_EXERTION = "ratingOfPerceivedExertion";
|
||||
public static final String WORKOUT_FEEL = "workout_feel";
|
||||
|
||||
public static final String CYCLING_POWER_AVERAGE = "cyclingPowerAverage";
|
||||
public static final String CYCLING_POWER_MIN = "cyclingPowerMin";
|
||||
@@ -258,6 +262,9 @@ public class ActivitySummaryEntries {
|
||||
public static final String UNIT_KNOTS = "knots";
|
||||
public static final String UNIT_CELSIUS = "unit_celsius";
|
||||
public static final String UNIT_OXYGEN_TOXICITY_UNITs = "unit_oxygen_toxicity_units";
|
||||
public static final String UNIT_BAR_PER_MINUTE = "unit_bar_per_minute";
|
||||
public static final String UNIT_VOLT = "unit_volt";
|
||||
public static final String UNIT_KG_PER_M3 = "unit_kg_per_m3";
|
||||
|
||||
public static final String GROUP_PACE = "Pace";
|
||||
public static final String GROUP_ACTIVITY = "Activity";
|
||||
@@ -283,6 +290,8 @@ public class ActivitySummaryEntries {
|
||||
public static final String GROUP_MOVEMENT_EVALUATION = "movement_evaluation";
|
||||
public static final String GROUP_DISTANCE = "Distance";
|
||||
public static final String GROUP_STEPS = "Steps";
|
||||
public static final String GROUP_BIKE = "activity_type_biking";
|
||||
public static final String GROUP_GEAR_INFO = "Gear";
|
||||
public static final String AVG_DEPTH = "diving_avg_depth";
|
||||
public static final String START_CNS = "diving_start_cns";
|
||||
public static final String END_CNS = "diving_end_cns";
|
||||
@@ -292,11 +301,19 @@ public class ActivitySummaryEntries {
|
||||
public static final String BOTTOM_TIME = "diving_bottom_time";
|
||||
public static final String OXYGEN_TOXICITY = "diving_oxygen_toxicity";
|
||||
public static final String SURFACE_INTERVAL = "diving_surface_interval";
|
||||
|
||||
public static final String PRESSURE_SAC_AVG = "diving_pressure_sac_avg";
|
||||
public static final String RECOVERY_TIME_REMAINING_AT_START = "recovery_time_remaining_at_start";
|
||||
public static final String BODY_ENERGY_AT_START = "body_energy_at_start";
|
||||
public static final String BODY_ENERGY_AT_END = "body_energy_at_end";
|
||||
public static final String TOTAL_WORK = "total_work";
|
||||
public static final String BATTERY_LEVEL_START = "battery_level_start";
|
||||
public static final String BATTERY_LEVEL_END = "battery_level_end";
|
||||
public static final String BATTERY_LEVEL_EBIKE_START = "battery_level_ebike_start";
|
||||
public static final String BATTERY_LEVEL_EBIKE_END = "battery_level_ebike_end";
|
||||
// DIVING parameters
|
||||
public static final String MAX_DEPTH = "diving_maximum_diving_depth";
|
||||
public static final String WATER_TYPE = "diving_water_type";
|
||||
public static final String GAS = "diving_gas";
|
||||
public static final String GROUP_GAS = "diving_gas";
|
||||
|
||||
/**
|
||||
* Used to signal that this activity has a gps track. This is currently used by ActivitySummaryDetail
|
||||
|
||||
+6
@@ -4,6 +4,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionAlarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionAlarmLabel;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionArray;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBatteryStatus;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBoolean;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionCoordinate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionCoursePoint;
|
||||
@@ -12,6 +13,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefi
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionFileType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalSource;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWaterType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWeatherReport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrTimeInZone;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrZoneHighBoundary;
|
||||
@@ -56,6 +58,8 @@ public class FieldDefinitionFactory {
|
||||
case LOCATION_SYMBOL -> new FieldDefinitionLocationSymbol(localNumber, size, baseType, name, scale, offset);
|
||||
case COURSE_POINT -> new FieldDefinitionCoursePoint(localNumber, size, baseType, name, scale, offset);
|
||||
case WEATHER_REPORT -> new FieldDefinitionWeatherReport(localNumber, size, baseType, name);
|
||||
case BATTERY_STATUS -> new FieldDefinitionBatteryStatus(localNumber, size, baseType, name, scale, offset);
|
||||
case WATER_TYPE -> new FieldDefinitionWaterType(localNumber, size, baseType, name, scale, offset);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -84,5 +88,7 @@ public class FieldDefinitionFactory {
|
||||
LOCATION_SYMBOL,
|
||||
COURSE_POINT,
|
||||
WEATHER_REPORT,
|
||||
BATTERY_STATUS,
|
||||
WATER_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
+34
-7
@@ -281,6 +281,7 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(69, BaseType.UINT32, "avg_lap_time", 1000, 0), // s
|
||||
new FieldDefinitionPrimitive(70, BaseType.UINT16, "best_lap_index"),
|
||||
new FieldDefinitionPrimitive(71, BaseType.UINT16, "min_altitude", 5, 500), // m
|
||||
new FieldDefinitionPrimitive(78, BaseType.UINT32, "work_time"), // ms
|
||||
new FieldDefinitionPrimitive(79, BaseType.UINT16, "avg_swim_cadence", 10, 0), // rpm
|
||||
new FieldDefinitionPrimitive(80, BaseType.UINT16, "avg_swolf"),
|
||||
new FieldDefinitionPrimitive(82, BaseType.UINT16, "player_score"),
|
||||
@@ -347,6 +348,8 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(148, BaseType.UINT8, "max_respiration_rate"),
|
||||
new FieldDefinitionPrimitive(149, BaseType.UINT8, "min_respiration_rate"),
|
||||
new FieldDefinitionPrimitive(150, BaseType.SINT8, "min_temperature"), // C
|
||||
new FieldDefinitionPrimitive(151, BaseType.UINT16, "total_sets"),
|
||||
new FieldDefinitionPrimitive(152, BaseType.UINT32, "volume", 100, 0), // kg
|
||||
new FieldDefinitionPrimitive(155, BaseType.UINT16, "o2_toxicity"), // OTUs
|
||||
new FieldDefinitionPrimitive(156, BaseType.UINT32, "dive_number"),
|
||||
new FieldDefinitionPrimitive(168, BaseType.SINT32, "training_load_peak", 65536, 0),
|
||||
@@ -359,6 +362,7 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(181, BaseType.FLOAT32, "total_grit"),
|
||||
new FieldDefinitionPrimitive(182, BaseType.FLOAT32, "total_flow"),
|
||||
new FieldDefinitionPrimitive(183, BaseType.UINT16, "jump_count"),
|
||||
new FieldDefinitionPrimitive(185, BaseType.UINT8, "execution_score"), // %
|
||||
new FieldDefinitionPrimitive(186, BaseType.FLOAT32, "avg_grit"),
|
||||
new FieldDefinitionPrimitive(187, BaseType.FLOAT32, "avg_flow"),
|
||||
new FieldDefinitionPrimitive(188, BaseType.ENUM, "primary_benefit"), // 1 recovery
|
||||
@@ -380,8 +384,16 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(208, BaseType.UINT16, "avg_core_temperature", 100, 0), // °C
|
||||
new FieldDefinitionPrimitive(209, BaseType.UINT16, "min_core_temperature", 100, 0), // °C
|
||||
new FieldDefinitionPrimitive(210, BaseType.UINT16, "max_core_temperature", 100, 0), // °C
|
||||
new FieldDefinitionPrimitive(211, BaseType.UINT32, "grade_adjusted_speed", 1000, 0), // m/s
|
||||
new FieldDefinitionPrimitive(212, BaseType.ENUM, "wind_data"),
|
||||
new FieldDefinitionPrimitive(215, BaseType.UINT8, "beginning_body_battery"),
|
||||
new FieldDefinitionPrimitive(216, BaseType.UINT8, "ending_body_battery"),
|
||||
new FieldDefinitionPrimitive(220, BaseType.UINT16, "pack_weight", 10, 0), // kg
|
||||
new FieldDefinitionPrimitive(222, BaseType.UINT16, "step_speed_loss", 100, 0),
|
||||
new FieldDefinitionPrimitive(223, BaseType.UINT16, "step_speed_loss_percentage", 100, 0),
|
||||
new FieldDefinitionPrimitive(224, BaseType.SINT32, "avg_force", 1000, 0), // N
|
||||
new FieldDefinitionPrimitive(225, BaseType.SINT32, "max_force", 1000, 0), // N
|
||||
new FieldDefinitionPrimitive(226, BaseType.SINT32, "normalized_force", 1000, 0), // N
|
||||
new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP),
|
||||
new FieldDefinitionPrimitive(254, BaseType.UINT16, "message_index")
|
||||
));
|
||||
@@ -414,6 +426,10 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(24, BaseType.ENUM, "lap_trigger"), // 0 manual
|
||||
new FieldDefinitionPrimitive(25, BaseType.ENUM, "sport"), // 5 swimming
|
||||
new FieldDefinitionPrimitive(26, BaseType.UINT8, "event_group"),
|
||||
new FieldDefinitionPrimitive(25, BaseType.SINT32, "nec_lat", FieldDefinitionFactory.FIELD.COORDINATE),
|
||||
new FieldDefinitionPrimitive(26, BaseType.SINT32, "nec_long", FieldDefinitionFactory.FIELD.COORDINATE),
|
||||
new FieldDefinitionPrimitive(27, BaseType.SINT32, "swc_lat", FieldDefinitionFactory.FIELD.COORDINATE),
|
||||
new FieldDefinitionPrimitive(28, BaseType.SINT32, "swc_long", FieldDefinitionFactory.FIELD.COORDINATE),
|
||||
new FieldDefinitionPrimitive(32, BaseType.UINT16, "num_lengths"),
|
||||
new FieldDefinitionPrimitive(33, BaseType.UINT16, "normalized_power"), // watt
|
||||
new FieldDefinitionPrimitive(34, BaseType.UINT16, "left_right_balance"),
|
||||
@@ -497,11 +513,13 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(124, BaseType.SINT8, "min_temperature"), // °C
|
||||
new FieldDefinitionPrimitive(136, BaseType.UINT16, "enhanced_avg_respiration_rate", 100, 0), // breath / min
|
||||
new FieldDefinitionPrimitive(137, BaseType.UINT16, "enhanced_max_respiration_rate", 100, 0), // breath / min
|
||||
new FieldDefinitionPrimitive(145, BaseType.UINT16, "est_sweat_loss"),
|
||||
new FieldDefinitionPrimitive(147, BaseType.UINT8, "avg_respiration_rate"),
|
||||
new FieldDefinitionPrimitive(148, BaseType.UINT8, "max_respiration_rate"),
|
||||
new FieldDefinitionPrimitive(149, BaseType.FLOAT32, "total_grit"),
|
||||
new FieldDefinitionPrimitive(150, BaseType.FLOAT32, "total_flow"),
|
||||
new FieldDefinitionPrimitive(151, BaseType.UINT16, "jump_count"),
|
||||
new FieldDefinitionPrimitive(152, BaseType.UINT8, "execution_score"),
|
||||
new FieldDefinitionPrimitive(153, BaseType.FLOAT32, "avg_grit"),
|
||||
new FieldDefinitionPrimitive(154, BaseType.FLOAT32, "avg_flow"),
|
||||
new FieldDefinitionPrimitive(156, BaseType.UINT8, "total_fractional_ascent", 100, 0), // m
|
||||
@@ -573,6 +591,7 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(84, BaseType.UINT16, "stance_time_balance", 100, 0), // %
|
||||
new FieldDefinitionPrimitive(85, BaseType.UINT16, "step_length", 10, 0), // mm
|
||||
new FieldDefinitionPrimitive(87, BaseType.UINT16, "cycle_length16", 100, 0), // m
|
||||
new FieldDefinitionPrimitive(90, BaseType.SINT8, "performance_condition"),
|
||||
new FieldDefinitionPrimitive(91, BaseType.UINT32, "absolute_pressure", 1, 0), // Pa
|
||||
new FieldDefinitionPrimitive(92, BaseType.UINT32, "depth", 1000, 0), // m
|
||||
new FieldDefinitionPrimitive(93, BaseType.UINT32, "next_stop_depth", 1000, 0), // m
|
||||
@@ -590,17 +609,23 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(118, BaseType.UINT8, "ebike_battery_level"), // %
|
||||
new FieldDefinitionPrimitive(119, BaseType.UINT8, "ebike_assist_mode"),
|
||||
new FieldDefinitionPrimitive(120, BaseType.UINT8, "ebike_assist_level_percent"), // %
|
||||
new FieldDefinitionPrimitive(121, BaseType.UINT16, "total_ascent"), // m
|
||||
new FieldDefinitionPrimitive(123, BaseType.UINT32, "air_time_remaining"), // s
|
||||
new FieldDefinitionPrimitive(124, BaseType.UINT16, "pressure_sac", 100, 0), // bar / min
|
||||
new FieldDefinitionPrimitive(125, BaseType.UINT16, "volume_sac", 100, 0), // liter / min
|
||||
new FieldDefinitionPrimitive(126, BaseType.UINT16, "rmv", 100, 0), // liter / min
|
||||
new FieldDefinitionPrimitive(127, BaseType.SINT32, "ascent_rate", 1000, 0), // m/s
|
||||
new FieldDefinitionPrimitive(129, BaseType.UINT8, "po2", 100, 0), // %
|
||||
new FieldDefinitionPrimitive(136, BaseType.UINT8, "wrist_heart_rate"),
|
||||
new FieldDefinitionPrimitive(136, BaseType.UINT8, "wrist_heart_rate"), // BPM
|
||||
new FieldDefinitionPrimitive(137, BaseType.UINT8, "stamina_potential"), // %
|
||||
new FieldDefinitionPrimitive(138, BaseType.UINT8, "stamina"), // %
|
||||
new FieldDefinitionPrimitive(139, BaseType.UINT16, "core_temperature", 100, 0), // °C
|
||||
new FieldDefinitionPrimitive(140, BaseType.UINT32, "grade_adjusted_speed", 1000, 0), // m/s
|
||||
new FieldDefinitionPrimitive(143, BaseType.UINT8, "body_battery"),
|
||||
new FieldDefinitionPrimitive(144, BaseType.UINT8, "external_heart_rate"), // BPM
|
||||
new FieldDefinitionPrimitive(146, BaseType.UINT16, "step_speed_loss_distance", 100, 0), // cm/s
|
||||
new FieldDefinitionPrimitive(147, BaseType.UINT16, "step_speed_loss_percentage", 100, 0), // %
|
||||
new FieldDefinitionPrimitive(148, BaseType.SINT32, "force", 1000, 0), // N
|
||||
new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP)
|
||||
));
|
||||
|
||||
@@ -646,7 +671,7 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(6, BaseType.UINT8, "hardware_version"),
|
||||
new FieldDefinitionPrimitive(7, BaseType.UINT32, "cum_operating_time"), // s
|
||||
new FieldDefinitionPrimitive(10, BaseType.UINT16, "battery_voltage", 256, 0), // V
|
||||
new FieldDefinitionPrimitive(11, BaseType.UINT8, "battery_status"),
|
||||
new FieldDefinitionPrimitive(11, BaseType.UINT8, "battery_status", FieldDefinitionFactory.FIELD.BATTERY_STATUS),
|
||||
new FieldDefinitionPrimitive(18, BaseType.ENUM, "sensor_position"),
|
||||
new FieldDefinitionPrimitive(19, BaseType.STRING, "descriptor"),
|
||||
new FieldDefinitionPrimitive(20, BaseType.UINT8Z, "ant_transmission_type"),
|
||||
@@ -861,6 +886,8 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(32, BaseType.UINT32, "descent", 1000, 0), // m
|
||||
new FieldDefinitionPrimitive(33, BaseType.UINT16, "moderate_activity_minutes"),
|
||||
new FieldDefinitionPrimitive(34, BaseType.UINT16, "vigorous_activity_minutes"),
|
||||
new FieldDefinitionPrimitive(35, BaseType.UINT32, "total_ascent", 1000, 0), // m
|
||||
new FieldDefinitionPrimitive(36, BaseType.UINT32, "total_descent", 1000, 0), // m
|
||||
new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP)
|
||||
));
|
||||
|
||||
@@ -1519,7 +1546,7 @@ public class NativeFITMessage {
|
||||
new FieldDefinitionPrimitive(1, BaseType.ENUM, "model"),
|
||||
new FieldDefinitionPrimitive(2, BaseType.UINT8, "gf_low"), // %
|
||||
new FieldDefinitionPrimitive(3, BaseType.UINT8, "gf_high"), // %
|
||||
new FieldDefinitionPrimitive(4, BaseType.ENUM, "water_type"), // %
|
||||
new FieldDefinitionPrimitive(4, BaseType.ENUM, "water_type", FieldDefinitionFactory.FIELD.WATER_TYPE),
|
||||
new FieldDefinitionPrimitive(5, BaseType.FLOAT32, "water_density"), // kg/m^3
|
||||
new FieldDefinitionPrimitive(6, BaseType.UINT8, "po2_warn", 100, 0), // %
|
||||
new FieldDefinitionPrimitive(7, BaseType.UINT8, "po2_critical", 100, 0), // %
|
||||
@@ -1811,15 +1838,15 @@ public class NativeFITMessage {
|
||||
public static NativeFITMessage ECG_SUMMARY = new NativeFITMessage(336, "ECG_SUMMARY", Arrays.asList(
|
||||
new FieldDefinitionPrimitive(0, BaseType.UINT16, "unknown_0"), // 10103
|
||||
new FieldDefinitionPrimitive(1, BaseType.ENUM, "unknown_1"), // 3
|
||||
new FieldDefinitionPrimitive(2, BaseType.FLOAT32, "unknown_2"), // 512
|
||||
new FieldDefinitionPrimitive(3, BaseType.FLOAT32, "unknown_3"), // 128
|
||||
new FieldDefinitionPrimitive(2, BaseType.FLOAT32, "raw_sample_rate"), // 512
|
||||
new FieldDefinitionPrimitive(3, BaseType.FLOAT32, "smooth_sample_rate"), // 128
|
||||
new FieldDefinitionPrimitive(4, BaseType.UINT32, "ecg_timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP),
|
||||
new FieldDefinitionPrimitive(5, BaseType.UINT32, "local_timestamp"), // garmin timestamp, but in user timezone
|
||||
new FieldDefinitionPrimitive(6, BaseType.ENUM, "unknown_6"), // 1
|
||||
new FieldDefinitionPrimitive(7, BaseType.FLOAT32, "average_heart_rate"), // bpm
|
||||
new FieldDefinitionPrimitive(10, BaseType.STRING, "unknown_10"), // ?
|
||||
new FieldDefinitionPrimitive(11, BaseType.UINT16, "unknown_11"), // 30
|
||||
new FieldDefinitionPrimitive(12, BaseType.UINT8, "unknown_12") // 39
|
||||
new FieldDefinitionPrimitive(11, BaseType.UINT16, "sample_time"), // s
|
||||
new FieldDefinitionPrimitive(12, BaseType.UINT8, "sdrr_hrv") // ms
|
||||
));
|
||||
|
||||
public static NativeFITMessage ECG_RAW_SAMPLE = new NativeFITMessage(337, "ECG_RAW_SAMPLE", Arrays.asList(
|
||||
|
||||
+4
@@ -29,10 +29,12 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDef
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionAlarmLabel;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBatteryStatus;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionCoursePoint;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionExerciseCategory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalSource;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWaterType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWeatherReport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrvStatus;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionLanguage;
|
||||
@@ -366,6 +368,8 @@ public class FitCodeGen {
|
||||
case LOCATION_SYMBOL -> FieldDefinitionLocationSymbol.LocationSymbol.class;
|
||||
case COURSE_POINT -> FieldDefinitionCoursePoint.CoursePoint.class;
|
||||
case WEATHER_REPORT -> FieldDefinitionWeatherReport.Type.class;
|
||||
case BATTERY_STATUS -> FieldDefinitionBatteryStatus.BatteryStatus.class;
|
||||
case WATER_TYPE -> FieldDefinitionWaterType.WaterType.class;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -120,6 +120,7 @@ public enum GarminSport {
|
||||
SOFTBALL(50, 0, ActivityKind.SOFTBALL),
|
||||
SOFTBALL_SLOW_PITCH(51, 0, ActivityKind.SOFTBALL_SLOW_PITCH),
|
||||
STOPWATCH(52, 0, ActivityKind.STOP_WATCH),
|
||||
DIVING(53, 0, ActivityKind.DIVING),
|
||||
SINGLE_GAS_DIVING(53, 53, ActivityKind.SCUBA_DIVING),
|
||||
MULTI_GAS_DIVING(53, 54, ActivityKind.SCUBA_DIVING),
|
||||
GAUGE_DIVING(53, 55, ActivityKind.DIVING),
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
|
||||
|
||||
public class FieldDefinitionBatteryStatus extends FieldDefinition {
|
||||
|
||||
public FieldDefinitionBatteryStatus(int localNumber, int size, BaseType baseType, String name, int scale, int offset) {
|
||||
super(localNumber, size, baseType, name, scale, offset);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object decode(ByteBuffer byteBuffer) {
|
||||
final Object rawObj = baseType.decode(byteBuffer, scale, offset);
|
||||
if (rawObj != null) {
|
||||
final int raw = (int) rawObj;
|
||||
return BatteryStatus.fromId(raw);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuffer byteBuffer, Object o) {
|
||||
if (o instanceof BatteryStatus) {
|
||||
baseType.encode(byteBuffer, (((BatteryStatus) o).getId()), scale, offset);
|
||||
return;
|
||||
}
|
||||
baseType.encode(byteBuffer, o, scale, offset);
|
||||
}
|
||||
|
||||
public enum BatteryStatus {
|
||||
New(1, R.string.battery_status_new),
|
||||
Good(2, R.string.battery_status_good),
|
||||
Ok(3, R.string.battery_status_ok),
|
||||
Low(4, R.string.battery_status_low),
|
||||
Critical(5, R.string.battery_status_critical),
|
||||
Charging(6, R.string.battery_status_charging),
|
||||
Unknown(7, R.string.battery_status_unknown),
|
||||
;
|
||||
|
||||
private final int id;
|
||||
@StringRes
|
||||
private final int stringRes;
|
||||
|
||||
BatteryStatus(int i, @StringRes int text) {
|
||||
id = i;
|
||||
stringRes = text;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static BatteryStatus fromId(int id) {
|
||||
for (BatteryStatus batteryStatus : values()) {
|
||||
if (id == batteryStatus.id) {
|
||||
return batteryStatus;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String toString(@NonNull Context context) {
|
||||
return context.getString(stringRes);
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
|
||||
|
||||
public class FieldDefinitionWaterType extends FieldDefinition {
|
||||
|
||||
public FieldDefinitionWaterType(int localNumber, int size, BaseType baseType, String name, int scale, int offset) {
|
||||
super(localNumber, size, baseType, name, scale, offset);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object decode(ByteBuffer byteBuffer) {
|
||||
final Object rawObj = baseType.decode(byteBuffer, scale, offset);
|
||||
if (rawObj != null) {
|
||||
final int raw = (int) rawObj;
|
||||
return WaterType.fromId(raw);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuffer byteBuffer, Object o) {
|
||||
if (o instanceof WaterType) {
|
||||
baseType.encode(byteBuffer, (((WaterType) o).getId()), scale, offset);
|
||||
return;
|
||||
}
|
||||
baseType.encode(byteBuffer, o, scale, offset);
|
||||
}
|
||||
|
||||
public enum WaterType {
|
||||
Fresh(0, R.string.water_type_fresh),
|
||||
Salt(1, R.string.water_type_salt),
|
||||
En13319(2, R.string.water_type_en13319),
|
||||
Custom(3, R.string.water_type_custom),
|
||||
;
|
||||
|
||||
private final int id;
|
||||
@StringRes
|
||||
private final int stringRes;
|
||||
|
||||
WaterType(int i, @StringRes int text) {
|
||||
id = i;
|
||||
stringRes = text;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static WaterType fromId(int id) {
|
||||
for (WaterType waterType : values()) {
|
||||
if (id == waterType.id) {
|
||||
return waterType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String toString(@NonNull Context context) {
|
||||
return context.getString(stringRes);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -22,6 +22,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitRecord
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBatteryStatus.BatteryStatus;
|
||||
|
||||
/**
|
||||
* WARNING: This class was auto-generated, please avoid modifying it directly.
|
||||
@@ -85,8 +86,8 @@ public class FitDeviceInfo extends RecordData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getBatteryStatus() {
|
||||
return getFieldByNumber(11, Integer.class);
|
||||
public BatteryStatus getBatteryStatus() {
|
||||
return getFieldByNumber(11, BatteryStatus.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -192,7 +193,7 @@ public class FitDeviceInfo extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBatteryStatus(final Integer value) {
|
||||
public Builder setBatteryStatus(final BatteryStatus value) {
|
||||
setFieldByNumber(11, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
+4
-3
@@ -22,6 +22,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitRecord
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWaterType.WaterType;
|
||||
|
||||
/**
|
||||
* WARNING: This class was auto-generated, please avoid modifying it directly.
|
||||
@@ -60,8 +61,8 @@ public class FitDiveSettings extends RecordData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getWaterType() {
|
||||
return getFieldByNumber(4, Integer.class);
|
||||
public WaterType getWaterType() {
|
||||
return getFieldByNumber(4, WaterType.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -242,7 +243,7 @@ public class FitDiveSettings extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setWaterType(final Integer value) {
|
||||
public Builder setWaterType(final WaterType value) {
|
||||
setFieldByNumber(4, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
+8
-8
@@ -50,12 +50,12 @@ public class FitEcgSummary extends RecordData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getUnknown2() {
|
||||
public Float getRawSampleRate() {
|
||||
return getFieldByNumber(2, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getUnknown3() {
|
||||
public Float getSmoothSampleRate() {
|
||||
return getFieldByNumber(3, Float.class);
|
||||
}
|
||||
|
||||
@@ -85,12 +85,12 @@ public class FitEcgSummary extends RecordData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getUnknown11() {
|
||||
public Integer getSampleTime() {
|
||||
return getFieldByNumber(11, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getUnknown12() {
|
||||
public Integer getSdrrHrv() {
|
||||
return getFieldByNumber(12, Integer.class);
|
||||
}
|
||||
|
||||
@@ -112,12 +112,12 @@ public class FitEcgSummary extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUnknown2(final Float value) {
|
||||
public Builder setRawSampleRate(final Float value) {
|
||||
setFieldByNumber(2, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUnknown3(final Float value) {
|
||||
public Builder setSmoothSampleRate(final Float value) {
|
||||
setFieldByNumber(3, value);
|
||||
return this;
|
||||
}
|
||||
@@ -147,12 +147,12 @@ public class FitEcgSummary extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUnknown11(final Integer value) {
|
||||
public Builder setSampleTime(final Integer value) {
|
||||
setFieldByNumber(11, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUnknown12(final Integer value) {
|
||||
public Builder setSdrrHrv(final Integer value) {
|
||||
setFieldByNumber(12, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
+60
@@ -175,6 +175,26 @@ public class FitLap extends RecordData {
|
||||
return getFieldByNumber(26, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getNecLat() {
|
||||
return getFieldByNumber(25, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getNecLong() {
|
||||
return getFieldByNumber(26, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getSwcLat() {
|
||||
return getFieldByNumber(27, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getSwcLong() {
|
||||
return getFieldByNumber(28, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getNumLengths() {
|
||||
return getFieldByNumber(32, Integer.class);
|
||||
@@ -590,6 +610,11 @@ public class FitLap extends RecordData {
|
||||
return getFieldByNumber(137, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getEstSweatLoss() {
|
||||
return getFieldByNumber(145, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getAvgRespirationRate() {
|
||||
return getFieldByNumber(147, Integer.class);
|
||||
@@ -615,6 +640,11 @@ public class FitLap extends RecordData {
|
||||
return getFieldByNumber(151, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getExecutionScore() {
|
||||
return getFieldByNumber(152, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getAvgGrit() {
|
||||
return getFieldByNumber(153, Float.class);
|
||||
@@ -803,6 +833,26 @@ public class FitLap extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNecLat(final Double value) {
|
||||
setFieldByNumber(25, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNecLong(final Double value) {
|
||||
setFieldByNumber(26, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSwcLat(final Double value) {
|
||||
setFieldByNumber(27, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSwcLong(final Double value) {
|
||||
setFieldByNumber(28, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNumLengths(final Integer value) {
|
||||
setFieldByNumber(32, value);
|
||||
return this;
|
||||
@@ -1218,6 +1268,11 @@ public class FitLap extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEstSweatLoss(final Integer value) {
|
||||
setFieldByNumber(145, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgRespirationRate(final Integer value) {
|
||||
setFieldByNumber(147, value);
|
||||
return this;
|
||||
@@ -1243,6 +1298,11 @@ public class FitLap extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setExecutionScore(final Integer value) {
|
||||
setFieldByNumber(152, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgGrit(final Float value) {
|
||||
setFieldByNumber(153, value);
|
||||
return this;
|
||||
|
||||
+20
@@ -182,6 +182,16 @@ public class FitMonitoring extends RecordData {
|
||||
return getFieldByNumber(34, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getTotalAscent() {
|
||||
return getFieldByNumber(35, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getTotalDescent() {
|
||||
return getFieldByNumber(36, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getTimestamp() {
|
||||
return getFieldByNumber(253, Long.class);
|
||||
@@ -335,6 +345,16 @@ public class FitMonitoring extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTotalAscent(final Double value) {
|
||||
setFieldByNumber(35, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTotalDescent(final Double value) {
|
||||
setFieldByNumber(36, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTimestamp(final Long value) {
|
||||
setFieldByNumber(253, value);
|
||||
return this;
|
||||
|
||||
+70
@@ -335,6 +335,11 @@ public class FitRecord extends RecordData {
|
||||
return getFieldByNumber(87, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getPerformanceCondition() {
|
||||
return getFieldByNumber(90, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getAbsolutePressure() {
|
||||
return getFieldByNumber(91, Long.class);
|
||||
@@ -420,6 +425,11 @@ public class FitRecord extends RecordData {
|
||||
return getFieldByNumber(120, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getTotalAscent() {
|
||||
return getFieldByNumber(121, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getAirTimeRemaining() {
|
||||
return getFieldByNumber(123, Long.class);
|
||||
@@ -470,11 +480,36 @@ public class FitRecord extends RecordData {
|
||||
return getFieldByNumber(139, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getGradeAdjustedSpeed() {
|
||||
return getFieldByNumber(140, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getBodyBattery() {
|
||||
return getFieldByNumber(143, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getExternalHeartRate() {
|
||||
return getFieldByNumber(144, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getStepSpeedLossDistance() {
|
||||
return getFieldByNumber(146, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getStepSpeedLossPercentage() {
|
||||
return getFieldByNumber(147, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getForce() {
|
||||
return getFieldByNumber(148, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getTimestamp() {
|
||||
return getFieldByNumber(253, Long.class);
|
||||
@@ -783,6 +818,11 @@ public class FitRecord extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPerformanceCondition(final Integer value) {
|
||||
setFieldByNumber(90, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAbsolutePressure(final Long value) {
|
||||
setFieldByNumber(91, value);
|
||||
return this;
|
||||
@@ -868,6 +908,11 @@ public class FitRecord extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTotalAscent(final Integer value) {
|
||||
setFieldByNumber(121, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAirTimeRemaining(final Long value) {
|
||||
setFieldByNumber(123, value);
|
||||
return this;
|
||||
@@ -918,11 +963,36 @@ public class FitRecord extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setGradeAdjustedSpeed(final Double value) {
|
||||
setFieldByNumber(140, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBodyBattery(final Integer value) {
|
||||
setFieldByNumber(143, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setExternalHeartRate(final Integer value) {
|
||||
setFieldByNumber(144, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setStepSpeedLossDistance(final Float value) {
|
||||
setFieldByNumber(146, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setStepSpeedLossPercentage(final Float value) {
|
||||
setFieldByNumber(147, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setForce(final Double value) {
|
||||
setFieldByNumber(148, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTimestamp(final Long value) {
|
||||
setFieldByNumber(253, value);
|
||||
return this;
|
||||
|
||||
+120
@@ -395,6 +395,11 @@ public class FitSession extends RecordData {
|
||||
return getFieldByNumber(71, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getWorkTime() {
|
||||
return getFieldByNumber(78, Long.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getAvgSwimCadence() {
|
||||
return getFieldByNumber(79, Float.class);
|
||||
@@ -725,6 +730,16 @@ public class FitSession extends RecordData {
|
||||
return getFieldByNumber(150, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getTotalSets() {
|
||||
return getFieldByNumber(151, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getVolume() {
|
||||
return getFieldByNumber(152, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getO2Toxicity() {
|
||||
return getFieldByNumber(155, Integer.class);
|
||||
@@ -785,6 +800,11 @@ public class FitSession extends RecordData {
|
||||
return getFieldByNumber(183, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getExecutionScore() {
|
||||
return getFieldByNumber(185, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getAvgGrit() {
|
||||
return getFieldByNumber(186, Float.class);
|
||||
@@ -890,6 +910,31 @@ public class FitSession extends RecordData {
|
||||
return getFieldByNumber(210, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getGradeAdjustedSpeed() {
|
||||
return getFieldByNumber(211, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getWindData() {
|
||||
return getFieldByNumber(212, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getBeginningBodyBattery() {
|
||||
return getFieldByNumber(215, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getEndingBodyBattery() {
|
||||
return getFieldByNumber(216, Integer.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getPackWeight() {
|
||||
return getFieldByNumber(220, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getStepSpeedLoss() {
|
||||
return getFieldByNumber(222, Float.class);
|
||||
@@ -900,6 +945,21 @@ public class FitSession extends RecordData {
|
||||
return getFieldByNumber(223, Float.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getAvgForce() {
|
||||
return getFieldByNumber(224, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getMaxForce() {
|
||||
return getFieldByNumber(225, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getNormalizedForce() {
|
||||
return getFieldByNumber(226, Double.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getTimestamp() {
|
||||
return getFieldByNumber(253, Long.class);
|
||||
@@ -1268,6 +1328,11 @@ public class FitSession extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setWorkTime(final Long value) {
|
||||
setFieldByNumber(78, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgSwimCadence(final Float value) {
|
||||
setFieldByNumber(79, value);
|
||||
return this;
|
||||
@@ -1598,6 +1663,16 @@ public class FitSession extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTotalSets(final Integer value) {
|
||||
setFieldByNumber(151, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setVolume(final Double value) {
|
||||
setFieldByNumber(152, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setO2Toxicity(final Integer value) {
|
||||
setFieldByNumber(155, value);
|
||||
return this;
|
||||
@@ -1658,6 +1733,11 @@ public class FitSession extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setExecutionScore(final Integer value) {
|
||||
setFieldByNumber(185, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgGrit(final Float value) {
|
||||
setFieldByNumber(186, value);
|
||||
return this;
|
||||
@@ -1763,6 +1843,31 @@ public class FitSession extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setGradeAdjustedSpeed(final Double value) {
|
||||
setFieldByNumber(211, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setWindData(final Integer value) {
|
||||
setFieldByNumber(212, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBeginningBodyBattery(final Integer value) {
|
||||
setFieldByNumber(215, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEndingBodyBattery(final Integer value) {
|
||||
setFieldByNumber(216, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPackWeight(final Float value) {
|
||||
setFieldByNumber(220, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setStepSpeedLoss(final Float value) {
|
||||
setFieldByNumber(222, value);
|
||||
return this;
|
||||
@@ -1773,6 +1878,21 @@ public class FitSession extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgForce(final Double value) {
|
||||
setFieldByNumber(224, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMaxForce(final Double value) {
|
||||
setFieldByNumber(225, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNormalizedForce(final Double value) {
|
||||
setFieldByNumber(226, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTimestamp(final Long value) {
|
||||
setFieldByNumber(253, value);
|
||||
return this;
|
||||
|
||||
@@ -2703,6 +2703,36 @@
|
||||
<string name="cycling">Cycling</string>
|
||||
<string name="aerobicTrainingEffect">Aerobic Effect</string>
|
||||
<string name="anaerobicTrainingEffect">Anaerobic Effect</string>
|
||||
<string name="battery_level_ebike_end">Final Battery Level</string>
|
||||
<string name="battery_level_ebike_start">Initial Battery Level</string>
|
||||
<string name="battery_level_end">Final Battery Level</string>
|
||||
<string name="battery_level_start">Initial Battery Level</string>
|
||||
<string name="battery_status">Battery Status</string>
|
||||
<string name="battery_status_charging">Charging</string>
|
||||
<string name="battery_status_critical">Critical</string>
|
||||
<string name="battery_status_good">Good</string>
|
||||
<string name="battery_status_invalid">Invalid</string>
|
||||
<string name="battery_status_low">Low</string>
|
||||
<string name="battery_status_new">New</string>
|
||||
<string name="battery_status_ok">Ok</string>
|
||||
<string name="battery_status_unknown">Unknown</string>
|
||||
<string name="body_energy_at_end">Finishing body energy</string>
|
||||
<string name="body_energy_at_start">Initial body energy</string>
|
||||
<string name="device">Device</string>
|
||||
<string name="diving_pressure_sac_avg">Surface air consumption</string>
|
||||
<string name="hr_user_max">User Max Heart Rate</string>
|
||||
<string name="hr_user_resting">Resting Heart Rate</string>
|
||||
<string name="recovery_time_remaining_at_start">Initial recovery time</string>
|
||||
<string name="total_work">Total Work</string>
|
||||
<string name="training_effect_total">Total Effect</string>
|
||||
<string name="unit_bar_per_minute">bar/min</string>
|
||||
<string name="unit_kg_per_m3">kg/m³</string>
|
||||
<string name="unit_volt">V</string>
|
||||
<string name="water_type_custom">Custom</string>
|
||||
<string name="water_type_en13319">EN13319</string>
|
||||
<string name="water_type_fresh">Fresh</string>
|
||||
<string name="water_type_salt">Salt</string>
|
||||
<string name="workout_feel">Workout Feel</string>
|
||||
<string name="currentWorkoutLoad">Workout Load</string>
|
||||
<string name="maximumOxygenUptake">Maximum Oxygen Uptake</string>
|
||||
<string name="fluid_consumed">Fluid consumed</string>
|
||||
|
||||
Reference in New Issue
Block a user