From 920ad5129a16469973cbcd9111f0b3718649bcd5 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sun, 26 Oct 2025 20:23:39 +0100 Subject: [PATCH] Introduced Statistics as a value object. --- .../opentracks/data/models/Track.java | 15 +++++++ .../opentracks/services/RecordingData.java | 14 ++---- .../services/TrackRecordingManager.java | 3 +- .../stats/SegmentStatisticUpdater.java | 19 ++++++++ .../opentracks/stats/Statistics.java | 43 +++++++++++++++++++ .../stats/TrackStatisticsUpdater.java | 6 +-- .../SettingsCustomLayoutEditAdapter.java | 30 ++++++++----- .../GenericStatisticsViewHolder.java | 4 +- 8 files changed, 105 insertions(+), 29 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/stats/Statistics.java diff --git a/src/main/java/de/dennisguse/opentracks/data/models/Track.java b/src/main/java/de/dennisguse/opentracks/data/models/Track.java index 5b9138659..7057762bb 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/Track.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/Track.java @@ -30,6 +30,7 @@ import java.util.Objects; import java.util.UUID; import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; +import de.dennisguse.opentracks.stats.Statistics; /** * A track. @@ -51,6 +52,7 @@ public class Track { private ZoneOffset zoneOffset; + @Deprecated // TODO Replace with Statistic private SegmentStatisticUpdater trackStatistics = new SegmentStatisticUpdater(); @VisibleForTesting @@ -137,15 +139,26 @@ public class Track { .getStopTime().atOffset(zoneOffset); } + public Statistics getStatistics() { + return trackStatistics.getStatistics(); + } + + public Statistics setStatistics() { + throw new RuntimeException("TODO"); + } + + @Deprecated @NonNull public SegmentStatisticUpdater getTrackStatistics() { return trackStatistics; } + @Deprecated public void setTrackStatistics(@NonNull SegmentStatisticUpdater trackStatistics) { this.trackStatistics = trackStatistics; } + @NonNull @Override public String toString() { return "Track{" + @@ -156,6 +169,7 @@ public class Track { '}'; } + @Deprecated //TODO Remove: should not be used. @Override public boolean equals(Object o) { if (this == o) return true; @@ -164,6 +178,7 @@ public class Track { return id.equals(track.id); } + @Deprecated //TODO Remove: should not be used. @Override public int hashCode() { return Objects.hash(id); diff --git a/src/main/java/de/dennisguse/opentracks/services/RecordingData.java b/src/main/java/de/dennisguse/opentracks/services/RecordingData.java index 04fd36150..49383afe5 100644 --- a/src/main/java/de/dennisguse/opentracks/services/RecordingData.java +++ b/src/main/java/de/dennisguse/opentracks/services/RecordingData.java @@ -6,11 +6,13 @@ import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; +import de.dennisguse.opentracks.stats.Statistics; /** * {@link Track} and {@link TrackPoint} must be immutable (i.e., their content does not change). */ -public record RecordingData(Track track, TrackPoint latestTrackPoint, SensorDataSet sensorDataSet, SegmentStatisticUpdater currentSegment) { +public record RecordingData(Track track, TrackPoint latestTrackPoint, SensorDataSet sensorDataSet, + Statistics currentSegment) { public String getTrackCategory() { if (track == null) { return ""; @@ -26,14 +28,4 @@ public record RecordingData(Track track, TrackPoint latestTrackPoint, SensorData return track.getTrackStatistics(); } - - @NonNull - public SegmentStatisticUpdater getStatisticsCurrentSegment() { - if (currentSegment == null) { - return new SegmentStatisticUpdater(); - } - - return currentSegment; - } - } diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java index 663a16596..87ab306e4 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java @@ -131,9 +131,8 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen } track.setTrackStatistics(tmpTrackStatisticsUpdater.getTrackStatistics()); - SegmentStatisticUpdater currentSegment = tmpTrackStatisticsUpdater.getCurrentSegment(); - return new RecordingData(track, current.first, current.second, currentSegment); + return new RecordingData(track, current.first, current.second, tmpTrackStatisticsUpdater.getCurrentSegment()); } @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) diff --git a/src/main/java/de/dennisguse/opentracks/stats/SegmentStatisticUpdater.java b/src/main/java/de/dennisguse/opentracks/stats/SegmentStatisticUpdater.java index 5b1d7fc1a..9fb1ef587 100644 --- a/src/main/java/de/dennisguse/opentracks/stats/SegmentStatisticUpdater.java +++ b/src/main/java/de/dennisguse/opentracks/stats/SegmentStatisticUpdater.java @@ -24,6 +24,7 @@ import java.time.Duration; import java.time.Instant; import de.dennisguse.opentracks.data.models.Altitude; +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Power; @@ -198,6 +199,24 @@ public class SegmentStatisticUpdater { setStartTime(startTime); } + public Statistics getStatistics() { + return new Statistics( + startTime, + stopTime, + totalTime, + movingTime, + + totalDistance, + isIdle, + getMaxSpeed(), + altitudeExtremities.hasData() ? altitudeExtremities.getMin() : null, + altitudeExtremities.hasData() ? altitudeExtremities.getMax() : null, + totalAltitudeGain_m != null && totalAltitudeLoss_m != null ? new AltitudeGainLoss(totalAltitudeGain_m, totalAltitudeLoss_m) : null, + avgHeartRate, + avgPower + ); + } + public Instant getStartTime() { return startTime; } diff --git a/src/main/java/de/dennisguse/opentracks/stats/Statistics.java b/src/main/java/de/dennisguse/opentracks/stats/Statistics.java new file mode 100644 index 000000000..b27ddd716 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/stats/Statistics.java @@ -0,0 +1,43 @@ +package de.dennisguse.opentracks.stats; + +import androidx.annotation.Nullable; + +import java.time.Duration; +import java.time.Instant; + +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; +import de.dennisguse.opentracks.data.models.Distance; +import de.dennisguse.opentracks.data.models.HeartRate; +import de.dennisguse.opentracks.data.models.Power; +import de.dennisguse.opentracks.data.models.Speed; + +public record Statistics( + Instant startTime, + Instant stopTime, + //TODO Rename to totalDuration + Duration totalTime, + //TODO Rename to movingDuration + Duration movingTime, // Based on when we believe the user is traveling + + Distance totalDistance, + boolean isIdle, //TODO Check if this is persisted; if not: remove + Speed maxSpeed, + + //TODO Create record for min/max altitude + @Nullable + Double altitudeMin_m, + @Nullable + Double altitudeMax_m, + + @Nullable + AltitudeGainLoss altitudeGainLoss, + @Nullable + HeartRate avgHeartRate, + @Nullable + Power avgPower +) { + + public Speed getAverageMovingSpeed() { + return Speed.of(totalDistance, movingTime); + } +} diff --git a/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java b/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java index f0558e06d..f1b075b53 100644 --- a/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java +++ b/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java @@ -78,9 +78,9 @@ public class TrackStatisticsUpdater { stats.merge(currentSegment); return stats; } - public SegmentStatisticUpdater getCurrentSegment() { - // Take a snapshot - we don't want anyone messing with our currentSegment - return new SegmentStatisticUpdater(currentSegment); + + public Statistics getCurrentSegment() { + return currentSegment.getStatistics(); } public void addTrackPoints(List trackPoints) { diff --git a/src/main/java/de/dennisguse/opentracks/ui/customRecordingLayout/SettingsCustomLayoutEditAdapter.java b/src/main/java/de/dennisguse/opentracks/ui/customRecordingLayout/SettingsCustomLayoutEditAdapter.java index 0c8a12fe3..438d0b4f0 100644 --- a/src/main/java/de/dennisguse/opentracks/ui/customRecordingLayout/SettingsCustomLayoutEditAdapter.java +++ b/src/main/java/de/dennisguse/opentracks/ui/customRecordingLayout/SettingsCustomLayoutEditAdapter.java @@ -19,6 +19,7 @@ import java.util.concurrent.Callable; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Altitude; +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Position; import de.dennisguse.opentracks.data.models.Speed; @@ -27,7 +28,7 @@ import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.databinding.CustomStatsItemBinding; import de.dennisguse.opentracks.services.RecordingData; import de.dennisguse.opentracks.settings.UnitSystem; -import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; +import de.dennisguse.opentracks.stats.Statistics; import de.dennisguse.opentracks.viewmodels.Mapping; import de.dennisguse.opentracks.viewmodels.StatisticViewHolder; @@ -38,17 +39,24 @@ public class SettingsCustomLayoutEditAdapter extends RecyclerView.Adapter valueAndUnit = speedFormatterSpeed.getSpeedParts(data.getStatisticsCurrentSegment().getAverageMovingSpeed()); + Pair valueAndUnit = speedFormatterSpeed.getSpeedParts(data.currentSegment().getAverageMovingSpeed()); getBinding().statsValue.setText(valueAndUnit.first); getBinding().statsUnit.setText(valueAndUnit.second); @@ -220,7 +220,7 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder