forked from upstream-mirrors/OpenTracks
AggregatedStatistics: compute without SegmentStatisticUpdater.
This commit is contained in:
+18
-28
@@ -23,7 +23,6 @@ import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.Statistics;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class AggregatedStatisticsTest {
|
||||
@@ -65,9 +64,8 @@ public class AggregatedStatisticsTest {
|
||||
assertNotNull(aggregatedStatistics.get(biking));
|
||||
assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
||||
|
||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, aggregatedStatistics.get(biking).totalDistance);
|
||||
assertEquals(totalTime, aggregatedStatistics.get(biking).totalMovingTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,9 +117,8 @@ public class AggregatedStatisticsTest {
|
||||
assertNotNull(aggregatedStatistics.get(biking));
|
||||
assertEquals(2, aggregatedStatistics.get(biking).getCountTracks());
|
||||
|
||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||
assertEquals(totalDistance.multipliedBy(2), statistics2.getTotalDistance());
|
||||
assertEquals(totalTime.multipliedBy(2), statistics2.getMovingTime());
|
||||
assertEquals(totalDistance.multipliedBy(2), aggregatedStatistics.get(biking).totalDistance);
|
||||
assertEquals(totalTime.multipliedBy(2), aggregatedStatistics.get(biking).totalMovingTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -153,21 +150,18 @@ public class AggregatedStatisticsTest {
|
||||
assertEquals(1, aggregatedStatistics.get(walking).getCountTracks());
|
||||
|
||||
{
|
||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, aggregatedStatistics.get(biking).totalDistance);
|
||||
assertEquals(totalTime, aggregatedStatistics.get(biking).totalMovingTime);
|
||||
}
|
||||
|
||||
{
|
||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, aggregatedStatistics.get(running).totalDistance);
|
||||
assertEquals(totalTime, aggregatedStatistics.get(running).totalMovingTime);
|
||||
}
|
||||
|
||||
{
|
||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, aggregatedStatistics.get(walking).totalDistance);
|
||||
assertEquals(totalTime, aggregatedStatistics.get(walking).totalMovingTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,30 +210,26 @@ public class AggregatedStatisticsTest {
|
||||
|
||||
// Biking.
|
||||
{
|
||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||
assertEquals(totalDistance.multipliedBy(5), statistics2.getTotalDistance());
|
||||
assertEquals(totalTime.multipliedBy(5), statistics2.getMovingTime());
|
||||
assertEquals(totalDistance.multipliedBy(5), aggregatedStatistics.get(biking).totalDistance);
|
||||
assertEquals(totalTime.multipliedBy(5), aggregatedStatistics.get(biking).totalMovingTime);
|
||||
}
|
||||
|
||||
// Running.
|
||||
{
|
||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
||||
assertEquals(totalDistance.multipliedBy(2), statistics2.getTotalDistance());
|
||||
assertEquals(totalTime.multipliedBy(2), statistics2.getMovingTime());
|
||||
assertEquals(totalDistance.multipliedBy(2), aggregatedStatistics.get(running).totalDistance);
|
||||
assertEquals(totalTime.multipliedBy(2), aggregatedStatistics.get(running).totalMovingTime);
|
||||
}
|
||||
|
||||
// Walking.
|
||||
{
|
||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
||||
assertEquals(totalDistance.multipliedBy(2), statistics2.getTotalDistance());
|
||||
assertEquals(totalTime.multipliedBy(2), statistics2.getMovingTime());
|
||||
assertEquals(totalDistance.multipliedBy(2), aggregatedStatistics.get(walking).totalDistance);
|
||||
assertEquals(totalTime.multipliedBy(2), aggregatedStatistics.get(walking).totalMovingTime);
|
||||
}
|
||||
|
||||
// Driving.
|
||||
{
|
||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(driving).getTrackStatistics();
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, aggregatedStatistics.get(driving).totalDistance);
|
||||
assertEquals(totalTime, aggregatedStatistics.get(driving).totalMovingTime);
|
||||
}
|
||||
|
||||
// Check order
|
||||
|
||||
@@ -108,7 +108,7 @@ public class SegmentStatisticUpdater {
|
||||
*
|
||||
* @param other another statistics data object
|
||||
*/
|
||||
//TODO Should be refactored to append only [mainly due to isIdle] (NOTE: This requires to use a custom value object for AggregatedStatistics; this is anyhow recommended).
|
||||
//TODO Should be refactored to append only [mainly due to isIdle]
|
||||
public void merge(SegmentStatisticUpdater other) {
|
||||
if (startTime == null) {
|
||||
startTime = other.startTime;
|
||||
|
||||
+39
-42
@@ -1,53 +1,47 @@
|
||||
package de.dennisguse.opentracks.ui.aggregatedStatistics;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Statistics;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater;
|
||||
|
||||
public class AggregatedStatistics {
|
||||
|
||||
private final Map<String, AggregatedStatistic> dataMap = new HashMap<>();
|
||||
|
||||
private final List<AggregatedStatistic> dataList = new ArrayList<>();
|
||||
private final List<AggregatedStatistic> dataList;
|
||||
|
||||
public AggregatedStatistics(@NonNull List<Track> tracks) {
|
||||
for (Track track : tracks) {
|
||||
aggregate(track);
|
||||
}
|
||||
Map<String, List<Track>> groupedByActivityType = tracks.stream().collect(Collectors.groupingBy(Track::getActivityTypeLocalized));
|
||||
|
||||
dataList.addAll(dataMap.values());
|
||||
dataList.sort((o1, o2) -> {
|
||||
if (o1.getCountTracks() == o2.getCountTracks()) {
|
||||
return o1.getActivityTypeLocalized().compareTo(o2.getActivityTypeLocalized());
|
||||
}
|
||||
return (o1.getCountTracks() < o2.getCountTracks() ? 1 : -1);
|
||||
});
|
||||
}
|
||||
List<Pair<String, List<Track>>> groupedByActivityTypeList = new ArrayList<>();
|
||||
groupedByActivityType.forEach((activityTypeLocalized, trackList) -> groupedByActivityTypeList.add(new Pair<>(activityTypeLocalized, trackList)));
|
||||
|
||||
@VisibleForTesting
|
||||
public void aggregate(@NonNull Track track) {
|
||||
String activityTypeLocalized = track.getActivityTypeLocalized();
|
||||
if (dataMap.containsKey(activityTypeLocalized)) {
|
||||
dataMap.get(activityTypeLocalized).add(track.getStatistics());
|
||||
} else {
|
||||
dataMap.put(activityTypeLocalized, new AggregatedStatistic(activityTypeLocalized, track.getStatistics()));
|
||||
}
|
||||
dataList = groupedByActivityTypeList.parallelStream()
|
||||
.map(i -> new AggregatedStatistic(i.first, i.second))
|
||||
.sorted((o1, o2) -> {
|
||||
if (o1.getCountTracks() == o2.getCountTracks()) {
|
||||
return o1.getActivityTypeLocalized().compareTo(o2.getActivityTypeLocalized());
|
||||
}
|
||||
return (o1.getCountTracks() < o2.getCountTracks() ? 1 : -1);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return dataMap.size();
|
||||
return dataList.size();
|
||||
}
|
||||
|
||||
public AggregatedStatistic get(String activityType) {
|
||||
return dataMap.get(activityType);
|
||||
@VisibleForTesting
|
||||
public AggregatedStatistic get(String activityTypeLocalized) {
|
||||
return dataList.stream().filter(i -> i.getActivityTypeLocalized().equals(activityTypeLocalized)).findFirst().get();
|
||||
}
|
||||
|
||||
public AggregatedStatistic getItem(int position) {
|
||||
@@ -55,30 +49,33 @@ public class AggregatedStatistics {
|
||||
}
|
||||
|
||||
public static class AggregatedStatistic {
|
||||
private final String activityTypeLocalized;
|
||||
private final SegmentStatisticUpdater trackStatistics;
|
||||
private int countTracks = 1;
|
||||
final String activityTypeLocalized;
|
||||
final int countTracks;
|
||||
|
||||
public AggregatedStatistic(String activityTypeLocalized, Statistics trackStatistics) {
|
||||
final Duration totalMovingTime;
|
||||
|
||||
final Distance totalDistance;
|
||||
|
||||
final Speed avgMovingSpeed;
|
||||
|
||||
final Speed maxSpeed;
|
||||
|
||||
public AggregatedStatistic(String activityTypeLocalized, List<Track> tracks) {
|
||||
this.activityTypeLocalized = activityTypeLocalized;
|
||||
this.trackStatistics = new SegmentStatisticUpdater(trackStatistics);
|
||||
this.countTracks = tracks.size();
|
||||
|
||||
totalMovingTime = tracks.stream().map(t -> t.getStatistics().movingTime()).reduce(Duration.ZERO, Duration::plus);
|
||||
totalDistance = tracks.stream().map(t -> t.getStatistics().totalDistance()).reduce(Distance.of(0), Distance::plus);
|
||||
maxSpeed = tracks.stream().map(t -> t.getStatistics().maxSpeed()).max((o1, o2) -> (int) (o1.speed_mps() - o2.speed_mps())).orElse(Speed.zero());
|
||||
avgMovingSpeed = Speed.of(totalDistance, totalMovingTime);
|
||||
}
|
||||
|
||||
public String getActivityTypeLocalized() {
|
||||
return activityTypeLocalized;
|
||||
}
|
||||
|
||||
public SegmentStatisticUpdater getTrackStatistics() {
|
||||
return trackStatistics;
|
||||
}
|
||||
|
||||
public int getCountTracks() {
|
||||
return countTracks;
|
||||
}
|
||||
|
||||
void add(Statistics statistics) {
|
||||
trackStatistics.merge(new SegmentStatisticUpdater(statistics));
|
||||
countTracks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -86,14 +86,14 @@ public class AggregatedStatisticsAdapter extends RecyclerView.Adapter<RecyclerVi
|
||||
|
||||
SpeedFormatter formatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(reportSpeed).build(context);
|
||||
{
|
||||
Pair<String, String> parts = formatter.getSpeedParts(aggregatedStatistic.getTrackStatistics().getAverageMovingSpeed());
|
||||
Pair<String, String> parts = formatter.getSpeedParts(aggregatedStatistic.avgMovingSpeed);
|
||||
viewBinding.aggregatedStatsAvgRate.setText(parts.first);
|
||||
viewBinding.aggregatedStatsAvgRateUnit.setText(parts.second);
|
||||
viewBinding.aggregatedStatsAvgRateLabel.setText(context.getString(R.string.stats_average_moving_speed));
|
||||
}
|
||||
|
||||
{
|
||||
Pair<String, String> parts = formatter.getSpeedParts(aggregatedStatistic.getTrackStatistics().getMaxSpeed());
|
||||
Pair<String, String> parts = formatter.getSpeedParts(aggregatedStatistic.maxSpeed);
|
||||
viewBinding.aggregatedStatsMaxRate.setText(parts.first);
|
||||
viewBinding.aggregatedStatsMaxRateUnit.setText(parts.second);
|
||||
viewBinding.aggregatedStatsMaxRateLabel.setText(context.getString(R.string.stats_max_speed));
|
||||
@@ -105,14 +105,14 @@ public class AggregatedStatisticsAdapter extends RecyclerView.Adapter<RecyclerVi
|
||||
|
||||
SpeedFormatter formatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(reportSpeed).build(context);
|
||||
{
|
||||
Pair<String, String> parts = formatter.getSpeedParts(aggregatedStatistic.getTrackStatistics().getAverageMovingSpeed());
|
||||
Pair<String, String> parts = formatter.getSpeedParts(aggregatedStatistic.avgMovingSpeed);
|
||||
viewBinding.aggregatedStatsAvgRate.setText(parts.first);
|
||||
viewBinding.aggregatedStatsAvgRateUnit.setText(parts.second);
|
||||
viewBinding.aggregatedStatsAvgRateLabel.setText(context.getString(R.string.stats_average_moving_pace));
|
||||
}
|
||||
|
||||
{
|
||||
Pair<String, String> parts = formatter.getSpeedParts(aggregatedStatistic.getTrackStatistics().getMaxSpeed());
|
||||
Pair<String, String> parts = formatter.getSpeedParts(aggregatedStatistic.maxSpeed);
|
||||
viewBinding.aggregatedStatsMaxRate.setText(parts.first);
|
||||
viewBinding.aggregatedStatsMaxRateUnit.setText(parts.second);
|
||||
viewBinding.aggregatedStatsMaxRateLabel.setText(R.string.stats_fastest_pace);
|
||||
@@ -132,11 +132,11 @@ public class AggregatedStatisticsAdapter extends RecyclerView.Adapter<RecyclerVi
|
||||
|
||||
Pair<String, String> parts = DistanceFormatter.Builder()
|
||||
.setUnit(unitSystem)
|
||||
.build(context).getDistanceParts(aggregatedStatistic.getTrackStatistics().getTotalDistance());
|
||||
.build(context).getDistanceParts(aggregatedStatistic.totalDistance);
|
||||
viewBinding.aggregatedStatsDistance.setText(parts.first);
|
||||
viewBinding.aggregatedStatsDistanceUnit.setText(parts.second);
|
||||
|
||||
viewBinding.aggregatedStatsTime.setText(StringUtils.formatElapsedTime(aggregatedStatistic.getTrackStatistics().getMovingTime()));
|
||||
viewBinding.aggregatedStatsTime.setText(StringUtils.formatElapsedTime(aggregatedStatistic.totalMovingTime));
|
||||
}
|
||||
|
||||
private int getIcon(AggregatedStatistics.AggregatedStatistic aggregatedStatistic) {
|
||||
|
||||
Reference in New Issue
Block a user