Garmin: add dedicated lap summary format for stop watch activities

This commit is contained in:
Thomas Kuehne
2026-05-08 09:38:32 +00:00
parent 0ccbda5e62
commit 6fab1ef852
4 changed files with 51 additions and 2 deletions
@@ -1,7 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.activities.workouts;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.DISTANCE_METERS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_CM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_EPOC_TIME;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KILOMETERS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KMPH;
@@ -19,6 +19,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS_PER_100_YARDS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS_PER_KM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS_PER_M;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS_SPORT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -210,6 +211,11 @@ public class WorkoutValueFormatter {
if (unit.equals("seconds") && !show_raw_data && showUnit) { //rather then plain seconds, show formatted duration
return DateTimeUtils.formatDurationHoursMinutes((long) value, TimeUnit.SECONDS);
}else if (unit.equals(UNIT_SECONDS_SPORT) && !show_raw_data && showUnit) {
return DateTimeUtils.formatSportsDuration(Math.round(1000L * (double) value), TimeUnit.MILLISECONDS);
} else if (UNIT_EPOC_TIME.equals(unit) && !show_raw_data) {
long epoc = ((Number) rawValue).longValue();
return DateTimeUtils.formatLocalTime(epoc * 1000L);
} else if (unit.equals("minutes_km") || unit.equals("minutes_mi") || unit.equals("minutes_100m") || unit.equals("minutes_100yd")) {
// Format pace
String format = showUnit ? "%d:%02d %s" : "%d:%02d";
@@ -1036,7 +1036,35 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
final boolean anySwimmingLaps = laps.stream()
.anyMatch(lap -> lap.getSwimStyle() != null);
if (anyValidLaps && diveLaps.isEmpty()) {
if (activityKind == ActivityKind.STOP_WATCH) {
// The start value encoded in the FIT file is shifted to a later time if the stop watch was paused.
// There is not enough information in the FIT file to fix this so display the values as they
// were encoded.
// The duration / active seconds are accurate.
final ActivitySummaryTableBuilder tableBuilder = new ActivitySummaryTableBuilder(GROUP_INTERVALS, "intervals_header", Arrays.asList(
"#",
"start",
"stop",
ACTIVE_SECONDS
));
for (int lapIndex = 0; lapIndex < laps.size(); lapIndex++) {
FitLap lap = laps.get(lapIndex);
Integer index = lap.getMessageIndex();
if (index != null) {
index = index + 1;
} else {
index = lapIndex + 1;
}
final List<ActivitySummaryValue> row = new ArrayList<>();
row.add(new ActivitySummaryValue(index, UNIT_NONE));
row.add(new ActivitySummaryValue(lap.getStartTime(), UNIT_EPOC_TIME));
row.add(new ActivitySummaryValue(lap.getTimestamp(), UNIT_EPOC_TIME));
row.add(new ActivitySummaryValue(lap.getTotalTimerTime(), UNIT_SECONDS_SPORT));
tableBuilder.addRow("interval_" + lapIndex, row);
}
tableBuilder.addToSummaryData(summaryData);
} else if (anyValidLaps && diveLaps.isEmpty()) {
// Unfortunately our tables do not yet scroll horizontally, so can't always add all possible columns
final List<String> header = new ArrayList<>();
header.add("#");
@@ -267,6 +267,10 @@ public class ActivitySummaryEntries {
public static final String UNIT_KG_PER_M3 = "unit_kg_per_m3";
public static final String UNIT_BAR = "unit_bar";
public static final String UNIT_LITER = "unit_liter";
/// UNIX epoc seconds to be formated in local time without showing date
public static final String UNIT_EPOC_TIME = "unit_epoc_time";
/// display time including milli seconds if any
public static final String UNIT_SECONDS_SPORT = "unit_sports_seconds";
public static final String GROUP_PACE = "Pace";
public static final String GROUP_ACTIVITY = "Activity";
@@ -339,6 +339,17 @@ public class DateTimeUtils {
return format.format(date);
}
/// format duration day - milli seconds with max 3 units shown
public static String formatSportsDuration(long duration, TimeUnit unit) {
DurationFormatter df = DurationFormatter.Builder.SYMBOLS
.maximum(TimeUnit.HOURS)
.minimum(TimeUnit.MILLISECONDS)
.suppressZeros(DurationFormatter.SuppressZeros.LEADING, DurationFormatter.SuppressZeros.TRAILING)
.maximumAmountOfUnitsToShow(3)
.build();
return df.format(duration, unit);
}
/// number of seconds since UTC epoch of 1970-01-01T00:00:00Z
public static long getEpochSeconds() {
final long epoc;