mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-03 01:53:05 +02:00
TrackDataHub computes TrackStatistics and passes it to listeners.
Part of #719.
This commit is contained in:
@@ -3,9 +3,10 @@ package de.dennisguse.opentracks.chart;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Distance;
|
||||
import de.dennisguse.opentracks.content.data.Speed;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||
import de.dennisguse.opentracks.util.UnitConversions;
|
||||
|
||||
public class ChartPoint {
|
||||
@@ -13,44 +14,38 @@ public class ChartPoint {
|
||||
private double timeOrDistance;
|
||||
|
||||
//Y-axis
|
||||
private double altitude;
|
||||
private final double altitude;
|
||||
private Double speed;
|
||||
private Double pace;
|
||||
private Double heartRate;
|
||||
private Double cadence;
|
||||
private Double power;
|
||||
|
||||
@Deprecated
|
||||
@VisibleForTesting
|
||||
ChartPoint(double altitude) {
|
||||
this.altitude = altitude;
|
||||
}
|
||||
|
||||
public ChartPoint(@NonNull TrackStatisticsUpdater trackStatisticsUpdater, TrackPoint trackPoint, boolean chartByDistance, boolean metricUnits) {
|
||||
TrackStatistics trackStatistics = trackStatisticsUpdater.getTrackStatistics();
|
||||
|
||||
public ChartPoint(@NonNull TrackStatistics trackStatistics, @NonNull TrackPoint trackPoint, Speed smoothedSpeed, double smoothedAltitude_m, boolean chartByDistance, boolean metricUnits) {
|
||||
if (chartByDistance) {
|
||||
timeOrDistance = trackStatistics.getTotalDistance().to(metricUnits);
|
||||
} else {
|
||||
timeOrDistance = trackStatistics.getTotalTime().toMillis();
|
||||
}
|
||||
|
||||
altitude = trackStatisticsUpdater.getSmoothedAltitude();
|
||||
if (!metricUnits) {
|
||||
altitude *= UnitConversions.M_TO_FT;
|
||||
}
|
||||
altitude = Distance.of(smoothedAltitude_m).to(metricUnits);
|
||||
|
||||
speed = trackStatisticsUpdater.getSmoothedSpeed().to(metricUnits);
|
||||
pace = trackStatisticsUpdater.getSmoothedSpeed().toPace(metricUnits).toMillis() * UnitConversions.MS_TO_S * UnitConversions.S_TO_MIN;
|
||||
if (trackPoint != null) {
|
||||
if (trackPoint.hasHeartRate()) {
|
||||
heartRate = (double) trackPoint.getHeartRate_bpm();
|
||||
}
|
||||
if (trackPoint.hasCyclingCadence()) {
|
||||
cadence = (double) trackPoint.getCyclingCadence_rpm();
|
||||
}
|
||||
if (trackPoint.hasPower()) {
|
||||
power = (double) trackPoint.getPower();
|
||||
}
|
||||
speed = smoothedSpeed.to(metricUnits);
|
||||
pace = smoothedSpeed.toPace(metricUnits).toMillis() * UnitConversions.MS_TO_S * UnitConversions.S_TO_MIN;
|
||||
if (trackPoint.hasHeartRate()) {
|
||||
heartRate = (double) trackPoint.getHeartRate_bpm();
|
||||
}
|
||||
if (trackPoint.hasCyclingCadence()) {
|
||||
cadence = (double) trackPoint.getCyclingCadence_rpm();
|
||||
}
|
||||
if (trackPoint.hasPower()) {
|
||||
power = (double) trackPoint.getPower();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Distance;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
@@ -38,6 +39,7 @@ import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||
|
||||
/**
|
||||
* Track data hub.
|
||||
@@ -349,6 +351,8 @@ public class TrackDataHub {
|
||||
next = new TrackPoint.Id(localLastSeenTrackPointIdId.getId() + 1); //TODO startTrackPointId + 1 is an assumption assumption; should be derived from the DB.
|
||||
}
|
||||
|
||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
|
||||
TrackPoint trackPoint = null;
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(selectedTrackId, next)) {
|
||||
|
||||
@@ -370,15 +374,16 @@ public class TrackDataHub {
|
||||
samplingFrequency = 1 + (int) (numTotalPoints / targetNumPoints);
|
||||
}
|
||||
|
||||
trackStatisticsUpdater.addTrackPoint(trackPoint, Distance.of(50)); //TODO
|
||||
|
||||
// Also include the last point if the selected track is not recording.
|
||||
if ((localNumLoadedTrackPoints % samplingFrequency == 0) || (trackPointId == lastTrackPointId && !isSelectedTrackRecording())) {
|
||||
for (TrackDataListener trackDataListener : sampledInListeners) {
|
||||
trackDataListener.onSampledInTrackPoint(trackPoint);
|
||||
trackDataListener.onSampledInTrackPoint(trackPoint, trackStatisticsUpdater.getTrackStatistics(), trackStatisticsUpdater.getSmoothedSpeed(), trackStatisticsUpdater.getSmoothedAltitude());
|
||||
}
|
||||
} else {
|
||||
for (TrackDataListener trackDataListener : sampledOutListeners) {
|
||||
trackDataListener.onSampledOutTrackPoint(trackPoint);
|
||||
trackDataListener.onSampledOutTrackPoint(trackPoint, trackStatisticsUpdater.getTrackStatistics());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,7 +403,7 @@ public class TrackDataHub {
|
||||
|
||||
if (trackPoint != null) {
|
||||
for (TrackDataListener listener : sampledInListeners) {
|
||||
listener.onNewTrackPointsDone(trackPoint);
|
||||
listener.onNewTrackPointsDone(trackPoint, trackStatisticsUpdater.getTrackStatistics());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@ package de.dennisguse.opentracks.content;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Speed;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
|
||||
/**
|
||||
* Listener for track data changes.
|
||||
@@ -47,20 +49,23 @@ public interface TrackDataListener {
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
*/
|
||||
void onSampledInTrackPoint(@NonNull TrackPoint trackPoint);
|
||||
default void onSampledInTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics trackStatistics, Speed smoothedSpeed, double smoothedAltitude_m) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a sampled out track point is read.
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
*/
|
||||
void onSampledOutTrackPoint(@NonNull TrackPoint trackPoint);
|
||||
default void onSampledOutTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics trackStatistics) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when finish sending new track points.
|
||||
* This gets called after every batch of calls to {@link #onSampledInTrackPoint(TrackPoint)} and {@link #onSampledOutTrackPoint(TrackPoint)}.
|
||||
* This gets called after every batch of calls to {@link #onSampledInTrackPoint(TrackPoint, TrackStatistics, Speed, double)} and {@link #onSampledOutTrackPoint(TrackPoint, TrackStatistics)}.
|
||||
*/
|
||||
void onNewTrackPointsDone(@NonNull TrackPoint lastTrackPoint);
|
||||
default void onNewTrackPointsDone(@NonNull TrackPoint lastTrackPoint, @NonNull TrackStatistics trackStatistics) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to clear previously sent markers.
|
||||
|
||||
@@ -39,6 +39,7 @@ import de.dennisguse.opentracks.content.TrackDataHub;
|
||||
import de.dennisguse.opentracks.content.TrackDataListener;
|
||||
import de.dennisguse.opentracks.content.data.Distance;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Speed;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.databinding.ChartBinding;
|
||||
@@ -72,7 +73,6 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
private TrackDataHub trackDataHub;
|
||||
|
||||
// Stats gathered from the received data
|
||||
private TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
private final List<ChartPoint> pendingPoints = new ArrayList<>();
|
||||
private String category = "";
|
||||
|
||||
@@ -217,7 +217,6 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
@Override
|
||||
public void clearTrackPoints() {
|
||||
if (isResumed()) {
|
||||
trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
pendingPoints.clear();
|
||||
chartView.reset();
|
||||
runOnUiThread(() -> {
|
||||
@@ -228,24 +227,15 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledInTrackPoint(@NonNull TrackPoint trackPoint) {
|
||||
public void onSampledInTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics trackStatistics, Speed smoothedSpeed, double smoothedAltitude_m) {
|
||||
if (isResumed()) {
|
||||
pendingPoints.add(createPendingPoint(trackPoint));
|
||||
ChartPoint point = new ChartPoint(trackStatistics, trackPoint, smoothedSpeed, smoothedAltitude_m, chartByDistance, chartView.getMetricUnits());
|
||||
pendingPoints.add(point);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledOutTrackPoint(@NonNull TrackPoint trackPoint) {
|
||||
if (isResumed()) {
|
||||
if (trackStatisticsUpdater != null) {
|
||||
trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTrackPointsDone(@NonNull TrackPoint unused) {
|
||||
public void onNewTrackPointsDone(@NonNull TrackPoint unused, @NonNull TrackStatistics alsoUnused) {
|
||||
if (isResumed()) {
|
||||
chartView.addChartPoints(pendingPoints);
|
||||
pendingPoints.clear();
|
||||
@@ -324,12 +314,6 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
ChartPoint createPendingPoint(@NonNull TrackPoint trackPoint) {
|
||||
trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
||||
return new ChartPoint(trackStatisticsUpdater, trackPoint, chartByDistance, chartView.getMetricUnits());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setChartView(ChartView view) {
|
||||
chartView = view;
|
||||
|
||||
@@ -25,9 +25,11 @@ import de.dennisguse.opentracks.adapters.IntervalStatisticsAdapter;
|
||||
import de.dennisguse.opentracks.content.TrackDataHub;
|
||||
import de.dennisguse.opentracks.content.TrackDataListener;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Speed;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.databinding.IntervalListViewBinding;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||
import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel;
|
||||
@@ -229,21 +231,21 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledInTrackPoint(@NonNull TrackPoint trackPoint) {
|
||||
public void onSampledInTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics unused, Speed unused2, double unused3) {
|
||||
if (isResumed()) {
|
||||
viewModel.add(trackPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledOutTrackPoint(@NonNull TrackPoint trackPoint) {
|
||||
public void onSampledOutTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics unused) {
|
||||
if (isResumed()) {
|
||||
viewModel.add(trackPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTrackPointsDone(@NonNull TrackPoint unused) {
|
||||
public void onNewTrackPointsDone(@NonNull TrackPoint unused, @NonNull TrackStatistics alsoUnused) {
|
||||
if (isResumed()) {
|
||||
runOnUiThread(viewModel::onNewTrackPoints);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||
import de.dennisguse.opentracks.databinding.StatisticsRecordingBinding;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
@@ -211,17 +212,7 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledInTrackPoint(@NonNull TrackPoint trackPoint) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledOutTrackPoint(@NonNull TrackPoint trackPoint) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTrackPointsDone(@NonNull TrackPoint newLastTrackPoint) {
|
||||
public void onNewTrackPointsDone(@NonNull TrackPoint newLastTrackPoint, @NonNull TrackStatistics trackStatistics) {
|
||||
if (isResumed()) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
if (isResumed()) {
|
||||
@@ -388,7 +379,7 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
}
|
||||
|
||||
// Set time
|
||||
if (track != null && track.getTrackStatistics() != null) {
|
||||
if (track != null) {
|
||||
viewBinding.statsMovingTimeValue.setText(StringUtils.formatElapsedTime(track.getTrackStatistics().getMovingTime()));
|
||||
updateTotalTime();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package de.dennisguse.opentracks.stats;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
@@ -193,6 +194,7 @@ public class TrackStatistics {
|
||||
this.movingTime = movingTime;
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||
public void addMovingTime(Duration time) {
|
||||
movingTime = movingTime.plus(time);
|
||||
}
|
||||
@@ -265,6 +267,7 @@ public class TrackStatistics {
|
||||
this.totalAltitudeGain_m = totalAltitudeGain_m;
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||
public void addTotalAltitudeGain(float gain_m) {
|
||||
if (totalAltitudeGain_m == null) {
|
||||
totalAltitudeGain_m = 0f;
|
||||
@@ -285,6 +288,7 @@ public class TrackStatistics {
|
||||
this.totalAltitudeLoss_m = totalAltitudeLoss_m;
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||
public void addTotalAltitudeLoss(float loss_m) {
|
||||
if (totalAltitudeLoss_m == null) {
|
||||
totalAltitudeLoss_m = 0f;
|
||||
|
||||
Reference in New Issue
Block a user