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.Speed;
|
||||||
import de.dennisguse.opentracks.data.models.Statistics;
|
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.stats.SegmentStatisticUpdater;
|
|
||||||
|
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class AggregatedStatisticsTest {
|
public class AggregatedStatisticsTest {
|
||||||
@@ -65,9 +64,8 @@ public class AggregatedStatisticsTest {
|
|||||||
assertNotNull(aggregatedStatistics.get(biking));
|
assertNotNull(aggregatedStatistics.get(biking));
|
||||||
assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
||||||
|
|
||||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
assertEquals(totalDistance, aggregatedStatistics.get(biking).totalDistance);
|
||||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
assertEquals(totalTime, aggregatedStatistics.get(biking).totalMovingTime);
|
||||||
assertEquals(totalTime, statistics2.getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -119,9 +117,8 @@ public class AggregatedStatisticsTest {
|
|||||||
assertNotNull(aggregatedStatistics.get(biking));
|
assertNotNull(aggregatedStatistics.get(biking));
|
||||||
assertEquals(2, aggregatedStatistics.get(biking).getCountTracks());
|
assertEquals(2, aggregatedStatistics.get(biking).getCountTracks());
|
||||||
|
|
||||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
assertEquals(totalDistance.multipliedBy(2), aggregatedStatistics.get(biking).totalDistance);
|
||||||
assertEquals(totalDistance.multipliedBy(2), statistics2.getTotalDistance());
|
assertEquals(totalTime.multipliedBy(2), aggregatedStatistics.get(biking).totalMovingTime);
|
||||||
assertEquals(totalTime.multipliedBy(2), statistics2.getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -153,21 +150,18 @@ public class AggregatedStatisticsTest {
|
|||||||
assertEquals(1, aggregatedStatistics.get(walking).getCountTracks());
|
assertEquals(1, aggregatedStatistics.get(walking).getCountTracks());
|
||||||
|
|
||||||
{
|
{
|
||||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
assertEquals(totalDistance, aggregatedStatistics.get(biking).totalDistance);
|
||||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
assertEquals(totalTime, aggregatedStatistics.get(biking).totalMovingTime);
|
||||||
assertEquals(totalTime, statistics2.getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
assertEquals(totalDistance, aggregatedStatistics.get(running).totalDistance);
|
||||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
assertEquals(totalTime, aggregatedStatistics.get(running).totalMovingTime);
|
||||||
assertEquals(totalTime, statistics2.getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
assertEquals(totalDistance, aggregatedStatistics.get(walking).totalDistance);
|
||||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
assertEquals(totalTime, aggregatedStatistics.get(walking).totalMovingTime);
|
||||||
assertEquals(totalTime, statistics2.getMovingTime());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,30 +210,26 @@ public class AggregatedStatisticsTest {
|
|||||||
|
|
||||||
// Biking.
|
// Biking.
|
||||||
{
|
{
|
||||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
assertEquals(totalDistance.multipliedBy(5), aggregatedStatistics.get(biking).totalDistance);
|
||||||
assertEquals(totalDistance.multipliedBy(5), statistics2.getTotalDistance());
|
assertEquals(totalTime.multipliedBy(5), aggregatedStatistics.get(biking).totalMovingTime);
|
||||||
assertEquals(totalTime.multipliedBy(5), statistics2.getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Running.
|
// Running.
|
||||||
{
|
{
|
||||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
assertEquals(totalDistance.multipliedBy(2), aggregatedStatistics.get(running).totalDistance);
|
||||||
assertEquals(totalDistance.multipliedBy(2), statistics2.getTotalDistance());
|
assertEquals(totalTime.multipliedBy(2), aggregatedStatistics.get(running).totalMovingTime);
|
||||||
assertEquals(totalTime.multipliedBy(2), statistics2.getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walking.
|
// Walking.
|
||||||
{
|
{
|
||||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
assertEquals(totalDistance.multipliedBy(2), aggregatedStatistics.get(walking).totalDistance);
|
||||||
assertEquals(totalDistance.multipliedBy(2), statistics2.getTotalDistance());
|
assertEquals(totalTime.multipliedBy(2), aggregatedStatistics.get(walking).totalMovingTime);
|
||||||
assertEquals(totalTime.multipliedBy(2), statistics2.getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Driving.
|
// Driving.
|
||||||
{
|
{
|
||||||
SegmentStatisticUpdater statistics2 = aggregatedStatistics.get(driving).getTrackStatistics();
|
assertEquals(totalDistance, aggregatedStatistics.get(driving).totalDistance);
|
||||||
assertEquals(totalDistance, statistics2.getTotalDistance());
|
assertEquals(totalTime, aggregatedStatistics.get(driving).totalMovingTime);
|
||||||
assertEquals(totalTime, statistics2.getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check order
|
// Check order
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class SegmentStatisticUpdater {
|
|||||||
*
|
*
|
||||||
* @param other another statistics data object
|
* @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) {
|
public void merge(SegmentStatisticUpdater other) {
|
||||||
if (startTime == null) {
|
if (startTime == null) {
|
||||||
startTime = other.startTime;
|
startTime = other.startTime;
|
||||||
|
|||||||
+39
-42
@@ -1,53 +1,47 @@
|
|||||||
package de.dennisguse.opentracks.ui.aggregatedStatistics;
|
package de.dennisguse.opentracks.ui.aggregatedStatistics;
|
||||||
|
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.data.models.Track;
|
||||||
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater;
|
|
||||||
|
|
||||||
public class AggregatedStatistics {
|
public class AggregatedStatistics {
|
||||||
|
|
||||||
private final Map<String, AggregatedStatistic> dataMap = new HashMap<>();
|
private final List<AggregatedStatistic> dataList;
|
||||||
|
|
||||||
private final List<AggregatedStatistic> dataList = new ArrayList<>();
|
|
||||||
|
|
||||||
public AggregatedStatistics(@NonNull List<Track> tracks) {
|
public AggregatedStatistics(@NonNull List<Track> tracks) {
|
||||||
for (Track track : tracks) {
|
Map<String, List<Track>> groupedByActivityType = tracks.stream().collect(Collectors.groupingBy(Track::getActivityTypeLocalized));
|
||||||
aggregate(track);
|
|
||||||
}
|
|
||||||
|
|
||||||
dataList.addAll(dataMap.values());
|
List<Pair<String, List<Track>>> groupedByActivityTypeList = new ArrayList<>();
|
||||||
dataList.sort((o1, o2) -> {
|
groupedByActivityType.forEach((activityTypeLocalized, trackList) -> groupedByActivityTypeList.add(new Pair<>(activityTypeLocalized, trackList)));
|
||||||
if (o1.getCountTracks() == o2.getCountTracks()) {
|
|
||||||
return o1.getActivityTypeLocalized().compareTo(o2.getActivityTypeLocalized());
|
|
||||||
}
|
|
||||||
return (o1.getCountTracks() < o2.getCountTracks() ? 1 : -1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
dataList = groupedByActivityTypeList.parallelStream()
|
||||||
public void aggregate(@NonNull Track track) {
|
.map(i -> new AggregatedStatistic(i.first, i.second))
|
||||||
String activityTypeLocalized = track.getActivityTypeLocalized();
|
.sorted((o1, o2) -> {
|
||||||
if (dataMap.containsKey(activityTypeLocalized)) {
|
if (o1.getCountTracks() == o2.getCountTracks()) {
|
||||||
dataMap.get(activityTypeLocalized).add(track.getStatistics());
|
return o1.getActivityTypeLocalized().compareTo(o2.getActivityTypeLocalized());
|
||||||
} else {
|
}
|
||||||
dataMap.put(activityTypeLocalized, new AggregatedStatistic(activityTypeLocalized, track.getStatistics()));
|
return (o1.getCountTracks() < o2.getCountTracks() ? 1 : -1);
|
||||||
}
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return dataMap.size();
|
return dataList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AggregatedStatistic get(String activityType) {
|
@VisibleForTesting
|
||||||
return dataMap.get(activityType);
|
public AggregatedStatistic get(String activityTypeLocalized) {
|
||||||
|
return dataList.stream().filter(i -> i.getActivityTypeLocalized().equals(activityTypeLocalized)).findFirst().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AggregatedStatistic getItem(int position) {
|
public AggregatedStatistic getItem(int position) {
|
||||||
@@ -55,30 +49,33 @@ public class AggregatedStatistics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class AggregatedStatistic {
|
public static class AggregatedStatistic {
|
||||||
private final String activityTypeLocalized;
|
final String activityTypeLocalized;
|
||||||
private final SegmentStatisticUpdater trackStatistics;
|
final int countTracks;
|
||||||
private int countTracks = 1;
|
|
||||||
|
|
||||||
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.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() {
|
public String getActivityTypeLocalized() {
|
||||||
return activityTypeLocalized;
|
return activityTypeLocalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SegmentStatisticUpdater getTrackStatistics() {
|
|
||||||
return trackStatistics;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCountTracks() {
|
public int getCountTracks() {
|
||||||
return countTracks;
|
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);
|
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.aggregatedStatsAvgRate.setText(parts.first);
|
||||||
viewBinding.aggregatedStatsAvgRateUnit.setText(parts.second);
|
viewBinding.aggregatedStatsAvgRateUnit.setText(parts.second);
|
||||||
viewBinding.aggregatedStatsAvgRateLabel.setText(context.getString(R.string.stats_average_moving_speed));
|
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.aggregatedStatsMaxRate.setText(parts.first);
|
||||||
viewBinding.aggregatedStatsMaxRateUnit.setText(parts.second);
|
viewBinding.aggregatedStatsMaxRateUnit.setText(parts.second);
|
||||||
viewBinding.aggregatedStatsMaxRateLabel.setText(context.getString(R.string.stats_max_speed));
|
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);
|
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.aggregatedStatsAvgRate.setText(parts.first);
|
||||||
viewBinding.aggregatedStatsAvgRateUnit.setText(parts.second);
|
viewBinding.aggregatedStatsAvgRateUnit.setText(parts.second);
|
||||||
viewBinding.aggregatedStatsAvgRateLabel.setText(context.getString(R.string.stats_average_moving_pace));
|
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.aggregatedStatsMaxRate.setText(parts.first);
|
||||||
viewBinding.aggregatedStatsMaxRateUnit.setText(parts.second);
|
viewBinding.aggregatedStatsMaxRateUnit.setText(parts.second);
|
||||||
viewBinding.aggregatedStatsMaxRateLabel.setText(R.string.stats_fastest_pace);
|
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()
|
Pair<String, String> parts = DistanceFormatter.Builder()
|
||||||
.setUnit(unitSystem)
|
.setUnit(unitSystem)
|
||||||
.build(context).getDistanceParts(aggregatedStatistic.getTrackStatistics().getTotalDistance());
|
.build(context).getDistanceParts(aggregatedStatistic.totalDistance);
|
||||||
viewBinding.aggregatedStatsDistance.setText(parts.first);
|
viewBinding.aggregatedStatsDistance.setText(parts.first);
|
||||||
viewBinding.aggregatedStatsDistanceUnit.setText(parts.second);
|
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) {
|
private int getIcon(AggregatedStatistics.AggregatedStatistic aggregatedStatistic) {
|
||||||
|
|||||||
Reference in New Issue
Block a user