IntervalStatisticsUpdater exposes Statistics (instead of Interval).

This commit is contained in:
Dennis Guse
2025-10-31 18:35:45 +01:00
parent 95b27f66fb
commit 53240c3d1a
9 changed files with 74 additions and 74 deletions
@@ -165,7 +165,7 @@ public class VoiceAnnouncementUtilsTest {
@Test @Test
public void getAnnouncement_withInterval_metric_speed() { public void getAnnouncement_withInterval_metric_speed() {
// given // given
Pair<Track, IntervalStatisticsUpdater.Interval> data = buildTrackWithTrackPoints(); Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -205,7 +205,7 @@ public class VoiceAnnouncementUtilsTest {
@Test @Test
public void getAnnouncement_withInterval_metric_pace() { public void getAnnouncement_withInterval_metric_pace() {
// given // given
Pair<Track, IntervalStatisticsUpdater.Interval> data = buildTrackWithTrackPoints(); Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -320,7 +320,7 @@ public class VoiceAnnouncementUtilsTest {
@Test @Test
public void getAnnouncement_withInterval_imperial_speed() { public void getAnnouncement_withInterval_imperial_speed() {
// given // given
Pair<Track, IntervalStatisticsUpdater.Interval> data = buildTrackWithTrackPoints(); Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -360,7 +360,7 @@ public class VoiceAnnouncementUtilsTest {
@Test @Test
public void getAnnouncement_withInterval_imperial_pace() { public void getAnnouncement_withInterval_imperial_pace() {
// given // given
Pair<Track, IntervalStatisticsUpdater.Interval> data = buildTrackWithTrackPoints(); Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -378,7 +378,7 @@ public class VoiceAnnouncementUtilsTest {
PreferencesUtils.setVoiceAnnounceAverageHeartRate(true); PreferencesUtils.setVoiceAnnounceAverageHeartRate(true);
PreferencesUtils.setVoiceAnnounceLapHeartRate(true); PreferencesUtils.setVoiceAnnounceLapHeartRate(true);
Pair<Track, IntervalStatisticsUpdater.Interval> data = buildTrackWithTrackPoints(); Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null, null); SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null, null);
@@ -404,7 +404,7 @@ public class VoiceAnnouncementUtilsTest {
PreferencesUtils.setVoiceAnnounceAverageSpeedPace(false); PreferencesUtils.setVoiceAnnounceAverageSpeedPace(false);
PreferencesUtils.setVoiceAnnounceLapSpeedPace(false); PreferencesUtils.setVoiceAnnounceLapSpeedPace(false);
Pair<Track, IntervalStatisticsUpdater.Interval> data = buildTrackWithTrackPoints(); Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null, null); SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null, null);
@@ -433,7 +433,7 @@ public class VoiceAnnouncementUtilsTest {
assertEquals("1.2 miles", MessageFormat.format(template, Map.of("n", 1.18))); assertEquals("1.2 miles", MessageFormat.format(template, Map.of("n", 1.18)));
} }
private static Pair<Track, IntervalStatisticsUpdater.Interval> buildTrackWithTrackPoints() { private static Pair<Track, Statistics> buildTrackWithTrackPoints() {
int numberOfPoints = 1000; int numberOfPoints = 1000;
ArrayList<TrackPoint> trackPoints = new ArrayList<>(); ArrayList<TrackPoint> trackPoints = new ArrayList<>();
@@ -443,7 +443,7 @@ public class VoiceAnnouncementUtilsTest {
IntervalStatisticsUpdater intervalStatistics = new IntervalStatisticsUpdater(Distance.of(1000)); IntervalStatisticsUpdater intervalStatistics = new IntervalStatisticsUpdater(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPoints.iterator()); intervalStatistics.addTrackPoints(trackPoints.iterator());
IntervalStatisticsUpdater.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); Statistics lastInterval = intervalStatistics.getLastInterval();
Track track = new Track(new Statistics( Track track = new Track(new Statistics(
Instant.EPOCH, Instant.EPOCH,
@@ -14,6 +14,7 @@ import java.util.List;
import de.dennisguse.opentracks.content.data.TestDataUtil; import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater; import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
@@ -126,25 +127,25 @@ public class IntervalStatisticsUpdaterTest {
intervalStatistics.addTrackPoints(trackPoints.iterator()); intervalStatistics.addTrackPoints(trackPoints.iterator());
List<IntervalStatisticsUpdater.Interval> intervalList = intervalStatistics.getIntervalList(); List<Statistics> intervalList = intervalStatistics.getIntervalList();
Distance totalDistance = Distance.of(0); Distance totalDistance = Distance.of(0);
float totalTime = 0L; float totalTime = 0L;
Float totalGain = null; Float totalGain = null;
Float totalLoss = null; Float totalLoss = null;
for (IntervalStatisticsUpdater.Interval i : intervalList) { for (Statistics i : intervalList) {
totalDistance = totalDistance.plus(i.getDistance()); totalDistance = totalDistance.plus(i.totalDistance());
totalTime += i.getDistance().toM() / i.getSpeed().toMPS(); totalTime += i.totalDistance().toM() / i.getAverageSpeed().toMPS();
if (totalGain == null) { if (totalGain == null) {
totalGain = i.getGain_m(); totalGain = i.altitudeGainLoss() != null ? i.altitudeGainLoss().gain_m() : null;
} else if (i.getGain_m() != null) { } else if (i.altitudeGainLoss() != null) {
totalGain += i.getGain_m(); totalGain += i.altitudeGainLoss().gain_m();
} }
if (totalLoss == null) { if (totalLoss == null) {
totalLoss = i.getLoss_m(); totalLoss = i.altitudeGainLoss() != null ? i.altitudeGainLoss().loss_m() : null;
} else if (i.getLoss_m() != null) { } else if (i.altitudeGainLoss() != null) {
totalLoss += i.getLoss_m(); totalLoss += i.altitudeGainLoss().loss_m();
} }
} }
@@ -152,22 +153,19 @@ public class IntervalStatisticsUpdaterTest {
assertEquals(track.getStatistics().totalTime().toSeconds(), totalTime, 0.01); assertEquals(track.getStatistics().totalTime().toSeconds(), totalTime, 0.01);
assertEquals(track.getStatistics().totalDistance().toM(), totalDistance.toM(), 0.01); assertEquals(track.getStatistics().totalDistance().toM(), totalDistance.toM(), 0.01);
assertEquals(intervalList.size(), (int) Math.ceil(track.getStatistics().totalDistance().toM() / distanceInterval)); assertEquals(intervalList.size(), (int) Math.ceil(track.getStatistics().totalDistance().toM() / distanceInterval));
if (totalGain != null) { if (totalGain != null && totalLoss != null) {
assertEquals(totalGain, numberOfPoints * TestDataUtil.ALTITUDE_GAIN, 0.1); assertEquals(totalGain, numberOfPoints * TestDataUtil.ALTITUDE_GAIN, 0.1);
} else {
assertTrue(intervalStatistics.getIntervalList().stream().noneMatch(IntervalStatisticsUpdater.Interval::hasGain));
}
if (totalLoss != null) {
assertEquals(totalLoss, numberOfPoints * TestDataUtil.ALTITUDE_LOSS, 0.1); assertEquals(totalLoss, numberOfPoints * TestDataUtil.ALTITUDE_LOSS, 0.1);
} else { } else {
assertTrue(intervalStatistics.getIntervalList().stream().noneMatch(IntervalStatisticsUpdater.Interval::hasLoss)); assertTrue(intervalStatistics.getIntervalList().stream().noneMatch(i -> i.altitudeGainLoss() != null));
} }
for (int i = 0; i < intervalList.size() - 1; i++) { for (int i = 0; i < intervalList.size() - 1; i++) {
assertEquals(intervalList.get(i).getDistance().toM(), distanceInterval, 0.001); assertEquals(intervalList.get(i).totalDistance().toM(), distanceInterval, 0.001);
totalDistance = totalDistance.minus(intervalList.get(i).getDistance()); totalDistance = totalDistance.minus(intervalList.get(i).totalDistance());
} }
assertEquals(intervalList.get(intervalList.size() - 1).getDistance().toM(), totalDistance.toM(), 0.01); assertEquals(intervalList.get(intervalList.size() - 1).totalDistance().toM(), totalDistance.toM(), 0.01);
} }
private static Pair<Track, List<TrackPoint>> buildTrackWithTrackPoints(int numberOfPoints) { private static Pair<Track, List<TrackPoint>> buildTrackWithTrackPoints(int numberOfPoints) {
@@ -11,8 +11,7 @@ import de.dennisguse.opentracks.stats.SegmentStatisticUpdater;
/** /**
* {@link Track} and {@link TrackPoint} must be immutable (i.e., their content does not change). * {@link Track} and {@link TrackPoint} must be immutable (i.e., their content does not change).
*/ */
public record RecordingData(Track track, TrackPoint latestTrackPoint, SensorDataSet sensorDataSet, public record RecordingData(Track track, TrackPoint latestTrackPoint, SensorDataSet sensorDataSet, Statistics currentSegment) {
Statistics currentSegment) {
public String getTrackCategory() { public String getTrackCategory() {
if (track == null) { if (track == null) {
return ""; return "";
@@ -149,9 +149,10 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
startTrackPointId = null; startTrackPointId = null;
} }
//TODO Avoid reloading (some) TrackPoints just to announce the last interval.
try (AutoCloseableIterator<TrackPoint> trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), startTrackPointId)) { try (AutoCloseableIterator<TrackPoint> trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), startTrackPointId)) {
startTrackPointId = intervalStatistics.addTrackPoints(trackPointIterator); startTrackPointId = intervalStatistics.addTrackPoints(trackPointIterator);
IntervalStatisticsUpdater.Interval lastInterval = intervalStatistics.getLastInterval(); Statistics lastInterval = intervalStatistics.getLastInterval();
SensorStatistics sensorStatistics = null; SensorStatistics sensorStatistics = null;
if (track.getId() != null) { if (track.getId() != null) {
sensorStatistics = contentProviderUtils.getSensorStats(track.getId()); sensorStatistics = contentProviderUtils.getSensorStats(track.getId());
@@ -38,7 +38,6 @@ import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.settings.UnitSystem;
import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.ui.intervals.IntervalStatisticsUpdater;
import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.StringUtils;
class VoiceAnnouncementUtils { class VoiceAnnouncementUtils {
@@ -51,7 +50,7 @@ class VoiceAnnouncementUtils {
.append(context.getString(R.string.voiceIdle)); .append(context.getString(R.string.voiceIdle));
} }
static Spannable createStatistics(Context context, Track track, SensorDataSet sensorDataSet, UnitSystem unitSystem, boolean isReportSpeed, @Nullable IntervalStatisticsUpdater.Interval currentInterval, @Nullable SensorStatistics sensorStatistics) { static Spannable createStatistics(Context context, Track track, SensorDataSet sensorDataSet, UnitSystem unitSystem, boolean isReportSpeed, @Nullable Statistics currentInterval, @Nullable SensorStatistics sensorStatistics) {
Statistics trackStatistics = track.getStatistics(); Statistics trackStatistics = track.getStatistics();
SpannableStringBuilder builder = new SpannableStringBuilder(); SpannableStringBuilder builder = new SpannableStringBuilder();
@@ -62,7 +61,7 @@ class VoiceAnnouncementUtils {
Distance totalDistance = trackStatistics.totalDistance(); Distance totalDistance = trackStatistics.totalDistance();
Speed averageMovingSpeed = trackStatistics.getAverageMovingSpeed(); Speed averageMovingSpeed = trackStatistics.getAverageMovingSpeed();
Speed currentDistancePerTime = currentInterval != null ? currentInterval.getSpeed() : null; Speed currentDistancePerTime = currentInterval != null ? currentInterval.getAverageSpeed() : null;
int perUnitStringId = R.string.empty; int perUnitStringId = R.string.empty;
int distanceId = R.string.voiceDistance; int distanceId = R.string.voiceDistance;
@@ -179,8 +178,8 @@ class VoiceAnnouncementUtils {
appendCardinal(builder, context.getString(R.string.sensor_state_heart_rate_value, averageHeartRate), averageHeartRate); appendCardinal(builder, context.getString(R.string.sensor_state_heart_rate_value, averageHeartRate), averageHeartRate);
builder.append("."); builder.append(".");
} }
if (shouldVoiceAnnounceLapHeartRate() && currentInterval != null && currentInterval.hasAverageHeartRate()) { if (shouldVoiceAnnounceLapHeartRate() && currentInterval != null && currentInterval.avgHeartRate() != null) {
int currentHeartRate = Math.round(currentInterval.getAverageHeartRate().getBPM()); int currentHeartRate = Math.round(currentInterval.avgHeartRate().getBPM());
builder.append(" ") builder.append(" ")
.append(context.getString(R.string.lap_heart_rate)); .append(context.getString(R.string.lap_heart_rate));
@@ -188,8 +187,8 @@ class VoiceAnnouncementUtils {
builder.append("."); builder.append(".");
} }
if (shouldVoiceAnnounceLapPower() && currentInterval != null && currentInterval.hasAveragePower()) { if (shouldVoiceAnnounceLapPower() && currentInterval != null && currentInterval.avgPower() != null) {
int currentPower = Math.round(currentInterval.getAveragePower().getW()); int currentPower = Math.round(currentInterval.avgPower().getW());
if (shouldVoiceAnnounceUnit()) { if (shouldVoiceAnnounceUnit()) {
String template = context.getResources().getString(R.string.power_x_watt); String template = context.getResources().getString(R.string.power_x_watt);
builder.append(" ") builder.append(" ")
@@ -7,18 +7,20 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.DistanceFormatter; import de.dennisguse.opentracks.data.models.DistanceFormatter;
import de.dennisguse.opentracks.data.models.SpeedFormatter; import de.dennisguse.opentracks.data.models.SpeedFormatter;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.databinding.IntervalStatsListItemBinding; import de.dennisguse.opentracks.databinding.IntervalStatsListItemBinding;
import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.settings.UnitSystem;
import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.StringUtils;
public class IntervalStatisticsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { public class IntervalStatisticsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<IntervalStatisticsUpdater.Interval> intervalList; private List<Statistics> intervalList = new ArrayList<>();
private final Context context; private final Context context;
private final StackMode stackMode; private final StackMode stackMode;
private UnitSystem unitSystem; private UnitSystem unitSystem;
@@ -43,46 +45,39 @@ public class IntervalStatisticsAdapter extends RecyclerView.Adapter<RecyclerView
int nextPosition = actualPosition + 1; int nextPosition = actualPosition + 1;
boolean isLast = actualPosition == getItemCount() - 1; boolean isLast = actualPosition == getItemCount() - 1;
IntervalStatisticsAdapter.ViewHolder viewHolder = (IntervalStatisticsAdapter.ViewHolder) holder; IntervalStatisticsAdapter.ViewHolder viewHolder = (IntervalStatisticsAdapter.ViewHolder) holder;
IntervalStatisticsUpdater.Interval interval = intervalList.get(actualPosition); Statistics interval = intervalList.get(actualPosition);
viewHolder.itemView.setTag(actualPosition); viewHolder.itemView.setTag(actualPosition);
Distance sumDistance; Distance sumDistance;
if (isLast && actualPosition > 0) { if (isLast && actualPosition > 0) {
sumDistance = intervalList.get(actualPosition - 1).getDistance() sumDistance = intervalList.get(actualPosition - 1).totalDistance()
.multipliedBy(actualPosition) .multipliedBy(actualPosition)
.plus(interval.getDistance()); .plus(interval.totalDistance());
} else { } else {
sumDistance = interval.getDistance().multipliedBy(nextPosition); sumDistance = interval.totalDistance().multipliedBy(nextPosition);
} }
viewHolder.viewBinding.intervalItemDistance.setText(DistanceFormatter.Builder() viewHolder.viewBinding.intervalItemDistance.setText(DistanceFormatter.Builder()
.setUnit(unitSystem) .setUnit(unitSystem)
.build(context).formatDistance(sumDistance)); .build(context).formatDistance(sumDistance));
SpeedFormatter formatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(isReportSpeed).build(context); SpeedFormatter formatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(isReportSpeed).build(context);
viewHolder.viewBinding.intervalItemRate.setText(formatter.formatSpeed(interval.getSpeed())); viewHolder.viewBinding.intervalItemRate.setText(formatter.formatSpeed(interval.getAverageSpeed()));
viewHolder.viewBinding.intervalItemGain.setText(StringUtils.formatAltitude(context, interval.getGain_m(), unitSystem)); viewHolder.viewBinding.intervalItemGain.setText(StringUtils.formatAltitude(context, interval.altitudeGainLoss() != null ? interval.altitudeGainLoss().gain_m() : null, unitSystem));
viewHolder.viewBinding.intervalItemLoss.setText(StringUtils.formatAltitude(context, interval.getLoss_m(), unitSystem)); viewHolder.viewBinding.intervalItemLoss.setText(StringUtils.formatAltitude(context, interval.altitudeGainLoss() != null ? interval.altitudeGainLoss().loss_m() : null, unitSystem));
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
if (intervalList == null) {
return 0;
}
return intervalList.size(); return intervalList.size();
} }
public List<IntervalStatisticsUpdater.Interval> swapData(List<IntervalStatisticsUpdater.Interval> data, UnitSystem unitSystem, boolean isReportSpeed) { public void swapData(@NonNull List<Statistics> data, UnitSystem unitSystem, boolean isReportSpeed) {
this.unitSystem = unitSystem; this.unitSystem = unitSystem;
this.isReportSpeed = isReportSpeed; this.isReportSpeed = isReportSpeed;
intervalList = data; intervalList = data;
if (data != null) { this.notifyDataSetChanged();
this.notifyDataSetChanged();
}
return data;
} }
/** /**
@@ -18,6 +18,7 @@ import java.util.concurrent.Executors;
import de.dennisguse.opentracks.data.ContentProviderUtils; import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns; import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
@@ -32,7 +33,7 @@ public class IntervalStatisticsModel extends AndroidViewModel {
private static final String TAG = IntervalStatisticsModel.class.getSimpleName(); private static final String TAG = IntervalStatisticsModel.class.getSimpleName();
private MutableLiveData<List<IntervalStatisticsUpdater.Interval>> intervalsLiveData; private MutableLiveData<List<Statistics>> intervalsLiveData;
private IntervalStatisticsUpdater intervalStatistics; private IntervalStatisticsUpdater intervalStatistics;
private Distance distanceInterval; private Distance distanceInterval;
private final ContentResolver contentResolver; private final ContentResolver contentResolver;
@@ -65,7 +66,7 @@ public class IntervalStatisticsModel extends AndroidViewModel {
handler = null; handler = null;
} }
public MutableLiveData<List<IntervalStatisticsUpdater.Interval>> getIntervalStats(Track.Id trackId, UnitSystem unitSystem, @Nullable IntervalOption interval) { public MutableLiveData<List<Statistics>> getIntervalStats(Track.Id trackId, UnitSystem unitSystem, @Nullable IntervalOption interval) {
if (intervalsLiveData == null) { if (intervalsLiveData == null) {
if (interval == null) { if (interval == null) {
interval = IntervalOption.OPTION_1; interval = IntervalOption.OPTION_1;
@@ -7,6 +7,7 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.data.models.Power;
@@ -74,8 +75,8 @@ public class IntervalStatisticsUpdater {
return trackPoint != null ? trackPoint.getId() : null; return trackPoint != null ? trackPoint.getId() : null;
} }
public List<Interval> getIntervalList() { public List<Statistics> getIntervalList() {
return intervalList; return intervalList.stream().map(Interval::toStatistics).toList();
} }
/** /**
@@ -84,14 +85,15 @@ public class IntervalStatisticsUpdater {
* *
* @return the interval object or null if any interval is completed. * @return the interval object or null if any interval is completed.
*/ */
public Interval getLastInterval() { @Nullable
public Statistics getLastInterval() {
if (intervalList.size() == 1 && intervalList.get(0).getDistance().lessThan(distanceInterval)) { if (intervalList.size() == 1 && intervalList.get(0).getDistance().lessThan(distanceInterval)) {
return null; return null;
} }
for (int i = intervalList.size() - 1; i >= 0; i--) { for (int i = intervalList.size() - 1; i >= 0; i--) {
if (intervalList.get(i).getDistance().greaterOrEqualThan(distanceInterval)) { if (intervalList.get(i).getDistance().greaterOrEqualThan(distanceInterval)) {
return this.intervalList.get(i); return this.intervalList.get(i).toStatistics();
} }
} }
@@ -99,7 +101,8 @@ public class IntervalStatisticsUpdater {
} }
//TODO Could be replaced with Statistics? //TODO Could be replaced with Statistics?
public static class Interval { @Deprecated
private static class Interval {
private Distance distance = Distance.of(0); private Distance distance = Distance.of(0);
private Duration time = Duration.ofSeconds(0); private Duration time = Duration.ofSeconds(0);
private Float gain_m; private Float gain_m;
@@ -145,18 +148,6 @@ public class IntervalStatisticsUpdater {
return gain_m != null; return gain_m != null;
} }
public Float getGain_m() {
return gain_m;
}
public boolean hasLoss() {
return loss_m != null;
}
public Float getLoss_m() {
return loss_m;
}
public boolean hasAverageHeartRate() { public boolean hasAverageHeartRate() {
return avgHeartRate != null; return avgHeartRate != null;
} }
@@ -201,5 +192,20 @@ public class IntervalStatisticsUpdater {
avgHeartRate = trackStatistics.avgHeartRate(); avgHeartRate = trackStatistics.avgHeartRate();
avgPower = trackStatistics.avgPower(); avgPower = trackStatistics.avgPower();
} }
private Statistics toStatistics() {
return new Statistics(
null,
null,
time,
null,
distance,
null,
null,
gain_m != null ? new AltitudeGainLoss(gain_m, loss_m) : null,
avgHeartRate,
avgPower
);
}
} }
} }
@@ -21,6 +21,7 @@ import java.util.Objects;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.ContentProviderUtils; import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.DistanceFormatter; import de.dennisguse.opentracks.data.models.DistanceFormatter;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.databinding.IntervalListViewBinding; import de.dennisguse.opentracks.databinding.IntervalListViewBinding;
import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.PreferencesUtils;
@@ -192,7 +193,7 @@ public class IntervalsFragment extends Fragment {
} }
viewBinding.intervalRate.setText(isReportSpeed ? getString(R.string.stats_speed) : getString(R.string.stats_pace)); viewBinding.intervalRate.setText(isReportSpeed ? getString(R.string.stats_speed) : getString(R.string.stats_pace));
LiveData<List<IntervalStatisticsUpdater.Interval>> liveData = viewModel.getIntervalStats(trackId, unitSystem, selectedInterval); LiveData<List<Statistics>> liveData = viewModel.getIntervalStats(trackId, unitSystem, selectedInterval);
liveData.observe(getActivity(), intervalList -> adapter.swapData(intervalList, unitSystem, isReportSpeed)); liveData.observe(getActivity(), intervalList -> adapter.swapData(intervalList, unitSystem, isReportSpeed));
setIntervalsDropdownText(); setIntervalsDropdownText();