Introduced Statistics as a value object.

This commit is contained in:
Dennis Guse
2025-10-26 20:23:39 +01:00
parent fba08fe8dd
commit 920ad5129a
8 changed files with 105 additions and 29 deletions
@@ -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);
@@ -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;
}
}
@@ -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)
@@ -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;
}
@@ -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);
}
}
@@ -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<TrackPoint> trackPoints) {
@@ -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<Recycl
private static final RecordingData demoData;
static {
SegmentStatisticUpdater trackStatistics = new SegmentStatisticUpdater();
trackStatistics.setStartTime(Instant.ofEpochMilli(0));
trackStatistics.setMovingTime(Duration.ofMinutes(0));
trackStatistics.setTotalTime(Duration.ofMinutes(0));
Statistics statistics = new Statistics(
Instant.ofEpochMilli(0),
Instant.ofEpochMilli(0),
Duration.ofMinutes(0),
Duration.ofMinutes(0),
trackStatistics.setTotalDistance(Distance.of(0));
Distance.of(0),
false,
Speed.of(0),
null,
null,
trackStatistics.setTotalAltitudeGain(0f);
trackStatistics.setTotalAltitudeLoss(0f);
Track track = new Track(ZoneOffset.UTC);
track.setTrackStatistics(trackStatistics);
new AltitudeGainLoss(0f, 0f),
null,
null
);
Track track = new Track(ZoneOffset.UTC); //TODO Pass statistics as well
Position position = new Position(
Instant.ofEpochMilli(0),
@@ -61,7 +69,7 @@ public class SettingsCustomLayoutEditAdapter extends RecyclerView.Adapter<Recycl
Speed.zero()
);
demoData = new RecordingData(track, new TrackPoint(TrackPoint.Type.TRACKPOINT, position), null, trackStatistics) ;
demoData = new RecordingData(track, new TrackPoint(TrackPoint.Type.TRACKPOINT, position), null, statistics);
}
private RecordingLayout recordingLayout;
@@ -208,7 +208,7 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
.setReportSpeedOrPace(false)
.build(getContext());
Pair<String, String> valueAndUnit = speedFormatterSpeed.getSpeedParts(data.getStatisticsCurrentSegment().getAverageMovingSpeed());
Pair<String, String> 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<St
@Override
public void onChanged(UnitSystem unitSystem, RecordingData data) {
String value = StringUtils.formatElapsedTime(data.getStatisticsCurrentSegment().getTotalTime());
String value = StringUtils.formatElapsedTime(data.currentSegment().totalTime());
getBinding().statsValue.setText(value);
getBinding().statsDescriptionMain.setText(getContext().getString(R.string.stats_elapsed_segment_time));