Compare commits

...

8 Commits

Author SHA1 Message Date
Dennis Guse 9234da4957 Release: v3.18.4 2021-06-15 17:53:30 +02:00
Román Martínez 24e18347a6 IntervalsFragment doesn't use TrackDataHub anymore. This improve intervals performance. Fixes #808. 2021-06-15 17:09:24 +02:00
Román Martínez 4c68592a0c Intervals are computated through TrackStatisticsUpdater. Fixes #703. 2021-06-15 17:08:16 +02:00
Dennis Guse 47a340578f Bugfix: prevent crash when creating TRACKPOINT without location.
Introduced in 2f0449c420
2021-06-14 12:11:23 +02:00
Dennis Guse e9e48e4a79 Bugfix: cycling sensors report wheel count as UINT32 - data type must be long, int is too small.
Also forgot to fix tests.

Fixes #810.
2021-06-13 19:17:05 +02:00
Dennis Guse 40188774b1 Bugfix: cycling sensors report wheel count as UINT32.
Garmin Speed Sensor 2 actually counts forward: it was an UINT16 overflow problem (removed workaround).

Fixes #810.
2021-06-11 19:25:40 +02:00
Dennis Guse 2f0449c420 TrackRecordingService: compute temporary TrackStatistics for UI.
Fixes #810.
2021-06-11 19:25:40 +02:00
Dennis Guse 21376cd3da Speed and distance each only use one formatting rule.
Fixes #648.
2021-06-08 17:10:23 +02:00
78 changed files with 512 additions and 690 deletions
-2
View File
@@ -23,8 +23,6 @@ However, often only one value is provided.
* Has updatable firmware that requires an account for garmin.com
* This sensor reports speed data as cadence.
A workaround is in place.
* This sensor sometimes counts backwards (unknown software version).
A workaround is in place.
* Wahoo Speed (Model: WFRPMSPD)
+2 -2
View File
@@ -55,8 +55,8 @@ android {
defaultConfig {
applicationId "de.dennisguse.opentracks"
versionCode 4143
versionName "v3.18.3"
versionCode 4151
versionName "v3.18.4"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -0,0 +1,10 @@
v3.18.4: OpenTracks
Changes:
- Speed/distance are consistently formatted
- Intervals tab is now faster
Bugfix:
- Cycling speed/distance sensor:
- fixed parsing (UINT32)
- transmit data to UI properly
@@ -4,7 +4,6 @@ package de.dennisguse.opentracks;
import android.app.ActivityManager;
import android.app.Instrumentation;
import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -14,6 +14,7 @@ import java.util.List;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
import de.dennisguse.opentracks.util.FileUtils;
public class TestDataUtil {
@@ -166,4 +167,20 @@ public class TestDataUtil {
}
return trackPoints;
}
public static Pair<Track.Id, TrackStatistics> buildTrackWithTrackPoints(ContentProviderUtils contentProviderUtils, int numberOfPoints) {
Track dummyTrack = new Track();
dummyTrack.setId(new Track.Id(System.currentTimeMillis()));
dummyTrack.setName("Dummy Track");
contentProviderUtils.insertTrack(dummyTrack);
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
for (int i = 0; i < numberOfPoints; i++) {
TrackPoint tp = TestDataUtil.createTrackPoint(i);
contentProviderUtils.insertTrackPoint(tp, dummyTrack.getId());
trackStatisticsUpdater.addTrackPoint(tp, Distance.of(0));
}
dummyTrack.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
contentProviderUtils.updateTrack(dummyTrack);
return new Pair<>(dummyTrack.getId(), trackStatisticsUpdater.getTrackStatistics());
}
}
@@ -111,7 +111,7 @@ public class SensorDataCyclingTest {
@Test
public void compute_speed_rollOverCount() {
// given
SensorDataCycling.DistanceSpeed previous = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", UintUtils.UINT16_MAX - 1, 1024);
SensorDataCycling.DistanceSpeed previous = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCycling.DistanceSpeed current = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 0, 2048);
// when
@@ -1,21 +1,23 @@
package de.dennisguse.opentracks.util;
import android.content.Context;
import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Duration;
import java.util.List;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
@@ -25,6 +27,12 @@ import static org.junit.Assert.assertEquals;
public class AnnouncementUtilsTest {
private final Context context = ApplicationProvider.getApplicationContext();
private ContentProviderUtils contentProviderUtils;
@Before
public void setUp() {
contentProviderUtils = new ContentProviderUtils(context);
}
@Test
public void getAnnouncement_metric_speed() {
@@ -44,22 +52,31 @@ public class AnnouncementUtilsTest {
@Test
public void getAnnouncement_withInterval_metric_speed() {
TrackStatistics stats = new TrackStatistics();
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
List<TrackPoint> trackPoints = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second;
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, Distance.of(1000));
IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
// given
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(trackPointIterator.getCount(), numberOfPoints);
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0));
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval);
// then
assertEquals("OpenTracks total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 18.4 kilometers per hour Lap speed of 51.2 kilometers per hour", announcement);
assertEquals(
"OpenTracks total distance " +
StringUtils.getDistanceParts(context, stats.getTotalDistance(), true).first +
" kilometers in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " +
StringUtils.getSpeedParts(context, stats.getAverageMovingSpeed(), true, true).first +
" kilometers per hour Lap speed of " +
StringUtils.getSpeedParts(context, lastInterval.getSpeed(), true, true).first +
" kilometers per hour",
announcement);
}
@Test
@@ -80,22 +97,31 @@ public class AnnouncementUtilsTest {
@Test
public void getAnnouncement_withInterval_metric_pace() {
TrackStatistics stats = new TrackStatistics();
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
List<TrackPoint> trackPoints = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second;
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, Distance.of(1000));
IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
// given
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(trackPointIterator.getCount(), numberOfPoints);
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0));
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, false, lastInterval);
// then
assertEquals("OpenTracks total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 3 minutes 15 seconds per kilometer Lap time of 1 minute 10 seconds per kilometer", announcement);
assertEquals(
"OpenTracks total distance " +
StringUtils.getDistanceParts(context, stats.getTotalDistance(), true).first +
" kilometers in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " +
buildAndGetTimeText(stats.getAverageMovingSpeed().toPace(true), true) +
" per kilometer Lap time of " +
buildAndGetTimeText(lastInterval.getSpeed().toPace(true), true) +
" per kilometer",
announcement);
}
@Test
@@ -116,22 +142,31 @@ public class AnnouncementUtilsTest {
@Test
public void getAnnouncement_withInterval_imperial_speed() {
TrackStatistics stats = new TrackStatistics();
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
List<TrackPoint> trackPoints = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second;
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, Distance.of(1000));
IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
// given
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(trackPointIterator.getCount(), numberOfPoints);
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0));
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, true, lastInterval);
// then
assertEquals("OpenTracks total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 11.4 miles per hour Lap speed of 31.8 miles per hour", announcement);
assertEquals(
"OpenTracks total distance " +
StringUtils.getDistanceParts(context, stats.getTotalDistance(), false).first +
" miles in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " +
StringUtils.getSpeedParts(context, stats.getAverageMovingSpeed(), false, true).first +
" miles per hour Lap speed of " +
StringUtils.getSpeedParts(context, lastInterval.getSpeed(), false, true).first +
" miles per hour",
announcement);
}
@Test
@@ -152,21 +187,60 @@ public class AnnouncementUtilsTest {
@Test
public void getAnnouncement_withInterval_imperial_pace() {
TrackStatistics stats = new TrackStatistics();
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
List<TrackPoint> trackPoints = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second;
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, Distance.of(1000));
IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
// given
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(trackPointIterator.getCount(), numberOfPoints);
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0));
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, false, lastInterval);
// then
assertEquals("OpenTracks total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 5 minutes 15 seconds per mile Lap time of 1 minute 53 seconds per mile", announcement);
//assertEquals("OpenTracks total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 5 minutes 15 seconds per mile Lap time of 1 minute 53 seconds per mile", announcement);
assertEquals(
"OpenTracks total distance " +
StringUtils.getDistanceParts(context, stats.getTotalDistance(), false).first +
" miles in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " +
buildAndGetTimeText(stats.getAverageMovingSpeed().toPace(false), true) +
" per mile Lap time of " +
buildAndGetTimeText(lastInterval.getSpeed().toPace(false), true) +
" per mile",
announcement);
}
/**
* Builds an returns the text representing the duration's time.
*
* @param duration Duration object.
* @param showFromMinutes show minutes tough it's 0.
* @return text representing the duratin's time.
*/
private String buildAndGetTimeText(Duration duration, boolean showFromMinutes) {
long hours = Math.abs(duration.getSeconds()) / 3600;
long minutes = (Math.abs(duration.getSeconds()) % 3600) / 60;
long seconds = Math.abs(duration.getSeconds()) % 60;
String hUnit = hours > 1 || hours == 0 ? "hours" : "hour";
String mUnit = minutes > 1 || minutes == 0 ? "minutes" : "minute";
String sUnit = seconds > 1 || seconds == 0 ? "seconds" : "second";
String res = hours > 0 ? hours + " " + hUnit : "";
if (hours > 0) {
res += minutes > 0 || showFromMinutes ? " " + minutes + " " + mUnit : "";
} else {
res += minutes > 0 || showFromMinutes ? minutes + " " + mUnit : "";
}
if (hours > 0 || minutes > 0 || showFromMinutes) {
res += " " + seconds + " " + sUnit;
} else {
res += seconds + " " + sUnit;
}
return res;
}
}
@@ -153,15 +153,15 @@ public class StringUtilsTest {
assertEquals("10", StringUtils.formatDecimal(10.1, 0));
assertEquals("-0", StringUtils.formatDecimal(-0.1, 0));
assertEquals("0", StringUtils.formatDecimal(0.0, 2));
assertEquals("0.1", StringUtils.formatDecimal(0.1, 2));
assertEquals("1.1", StringUtils.formatDecimal(1.1, 2));
assertEquals("10", StringUtils.formatDecimal(10, 2));
assertEquals("10.1", StringUtils.formatDecimal(10.1, 2));
assertEquals("0.00", StringUtils.formatDecimal(0.0, 2));
assertEquals("0.10", StringUtils.formatDecimal(0.1, 2));
assertEquals("1.10", StringUtils.formatDecimal(1.1, 2));
assertEquals("10.00", StringUtils.formatDecimal(10, 2));
assertEquals("10.10", StringUtils.formatDecimal(10.1, 2));
assertEquals("10.11", StringUtils.formatDecimal(10.111, 2));
assertEquals("-0.1", StringUtils.formatDecimal(-0.1, 2));
assertEquals("-0.10", StringUtils.formatDecimal(-0.1, 2));
assertEquals("1", StringUtils.formatDecimal(0.99, 1));
assertEquals("1.0", StringUtils.formatDecimal(0.99, 1));
}
@Test
@@ -181,7 +181,7 @@ public class StringUtilsTest {
assertEquals("4:59 min/km", StringUtils.formatSpeed(context, Speed.of(3.34), true, false));
assertEquals("8:02 min/mi", StringUtils.formatSpeed(context, Speed.of(3.34), false, false));
assertEquals("12.02 km/h", StringUtils.formatSpeed(context, Speed.of(3.34), true, true));
assertEquals("7.47 mph", StringUtils.formatSpeed(context, Speed.of(3.34), false, true));
assertEquals("12.0 km/h", StringUtils.formatSpeed(context, Speed.of(3.34), true, true));
assertEquals("7.5 mph", StringUtils.formatSpeed(context, Speed.of(3.34), false, true));
}
}
@@ -0,0 +1,23 @@
package de.dennisguse.opentracks.util;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class UintUtilsTest {
@Test
public void diff() {
assertEquals(0, UintUtils.diff(1, 1, UintUtils.UINT16_MAX));
assertEquals(1, UintUtils.diff(2, 1, UintUtils.UINT16_MAX));
assertEquals(3, UintUtils.diff(5, 2, UintUtils.UINT16_MAX));
assertEquals(65534, UintUtils.diff(1, 2, UintUtils.UINT16_MAX));
assertEquals(65530, UintUtils.diff(UintUtils.UINT16_MAX, 5, UintUtils.UINT16_MAX));
}
@Test
public void realData() {
assertEquals(1, UintUtils.diff(381616, 381615, UintUtils.UINT32_MAX));
}
}
@@ -1,5 +1,11 @@
package de.dennisguse.opentracks.viewmodels;
import android.content.Context;
import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -10,6 +16,8 @@ import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
import de.dennisguse.opentracks.util.UnitConversions;
@@ -21,8 +29,12 @@ public class IntervalStatisticsTest {
private static final String TAG = IntervalStatisticsTest.class.getSimpleName();
private List<TrackPoint> buildTrackPoints(int numberOfTrackPoints) {
return TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), numberOfTrackPoints).second;
private final Context context = ApplicationProvider.getApplicationContext();
private ContentProviderUtils contentProviderUtils;
@Before
public void setUp() {
contentProviderUtils = new ContentProviderUtils(context);
}
private TrackStatistics buildTrackStatistics(List<TrackPoint> trackPoints) {
@@ -41,12 +53,10 @@ public class IntervalStatisticsTest {
// With 50 points and interval distance of 1000m.
// given
List<TrackPoint> trackPoints = buildTrackPoints(50);
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
float distanceInterval = 1000f;
// when and then
whenAndThen(trackPoints, trackStatistics, distanceInterval);
whenAndThen(50, distanceInterval);
}
/**
@@ -57,12 +67,10 @@ public class IntervalStatisticsTest {
// With 200 points and interval distance of 1000m.
// given
List<TrackPoint> trackPoints = buildTrackPoints(200);
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
float distanceInterval = 1000f;
// when and then
whenAndThen(trackPoints, trackStatistics, distanceInterval);
whenAndThen(200, distanceInterval);
}
/**
@@ -73,12 +81,10 @@ public class IntervalStatisticsTest {
// With 200 points and interval distance of 3000m.
// given
List<TrackPoint> trackPoints = buildTrackPoints(200);
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
float distanceInterval = 3000f;
// when and then
whenAndThen(trackPoints, trackStatistics, distanceInterval);
whenAndThen(3000, distanceInterval);
}
/**
@@ -89,12 +95,10 @@ public class IntervalStatisticsTest {
// With 1000 points and interval distance of 3000m.
// given
List<TrackPoint> trackPoints = buildTrackPoints(1000);
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
float distanceInterval = 3000f;
// when and then
whenAndThen(trackPoints, trackStatistics, distanceInterval);
whenAndThen(1000, distanceInterval);
}
/**
@@ -105,16 +109,21 @@ public class IntervalStatisticsTest {
// With 10000 points and interval distance of 1000m.
// given
List<TrackPoint> trackPoints = buildTrackPoints(10000);
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
float distanceInterval = 1000f;
// when and then
whenAndThen(trackPoints, trackStatistics, distanceInterval);
whenAndThen(10000, distanceInterval);
}
private void whenAndThen(List<TrackPoint> trackPoints, TrackStatistics trackStatistics, float distanceInterval) {
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, Distance.of(distanceInterval));
private void whenAndThen(int numberOfPoints, float distanceInterval) {
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(distanceInterval), Distance.of(0));
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics trackStatistics = trackWithStats.second;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(trackPointIterator.getCount(), numberOfPoints);
intervalStatistics.addTrackPoints(trackPointIterator);
}
List<IntervalStatistics.Interval> intervalList = intervalStatistics.getIntervalList();
Distance totalDistance = Distance.of(0);
float totalTime = 0L;
@@ -129,7 +138,7 @@ public class IntervalStatisticsTest {
assertEquals(trackStatistics.getTotalDistance().toM(), totalDistance.toM(), 0.01);
assertEquals(trackStatistics.getTotalTime().toMillis(), totalTime * UnitConversions.S_TO_MS, 1);
assertEquals(intervalList.size(), (int) Math.ceil(trackStatistics.getTotalDistance().toM() / distanceInterval));
assertEquals(totalGain, trackPoints.size() * TestDataUtil.ALTITUDE_GAIN, 0.1);
assertEquals(totalGain, numberOfPoints * TestDataUtil.ALTITUDE_GAIN, 0.1);
for (int i = 0; i < intervalList.size() - 1; i++) {
assertEquals(intervalList.get(i).getDistance().toM(), distanceInterval, 0.001);
@@ -289,7 +289,7 @@ public class TrackRecordedActivity extends AbstractTrackDeleteActivity implement
case 0:
return StatisticsRecordedFragment.newInstance(trackId);
case 1:
return IntervalsFragment.newInstance(true);
return IntervalsFragment.newInstance(trackId, true);
case 2:
return ChartFragment.newInstance(false);
case 3:
@@ -360,7 +360,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
case 0:
return StatisticsRecordingFragment.newInstance();
case 1:
return IntervalsFragment.newInstance(false);
return IntervalsFragment.newInstance(trackId, false);
case 2:
return ChartFragment.newInstance(false);
case 3:
@@ -72,10 +72,6 @@ public class IntervalStatisticsAdapter extends RecyclerView.Adapter<RecyclerView
}
public List<IntervalStatistics.Interval> swapData(List<IntervalStatistics.Interval> data, boolean metricUnits, boolean isReportSpeed) {
if (intervalList == data && this.metricUnits == metricUnits && this.isReportSpeed == isReportSpeed) {
return null;
}
this.metricUnits = metricUnits;
this.isReportSpeed = isReportSpeed;
intervalList = data;
@@ -48,7 +48,9 @@ public class TrackPoint {
private TrackPoint.Id id;
@NonNull
private Instant time;
private Double latitude;
private Double longitude;
private Float accuracy;
@@ -96,10 +98,16 @@ public class TrackPoint {
public TrackPoint(@NonNull Type type) {
this.type = type;
this.time = Instant.now(); //TODO This may result in #800
}
public TrackPoint(@NonNull Type type, Instant time) {
this(type);
this.time = time;
}
public TrackPoint(@NonNull Location location) {
this(Type.TRACKPOINT, location, Instant.now());
this(Type.TRACKPOINT, location, Instant.now()); //TODO This may result in #800
}
public TrackPoint(@NonNull Type type, @NonNull Location location, @NonNull Instant time) {
@@ -116,11 +124,6 @@ public class TrackPoint {
setTime(time);
}
public TrackPoint(@NonNull Type type, Instant time) {
this(type);
this.time = time;
}
public TrackPoint(double latitude, double longitude, Altitude altitude, Instant time) {
this(Type.TRACKPOINT);
this.latitude = latitude;
@@ -37,6 +37,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.stream.StreamSupport;
import de.dennisguse.opentracks.BuildConfig;
import de.dennisguse.opentracks.content.data.Altitude;
@@ -15,8 +15,6 @@ import de.dennisguse.opentracks.util.UnitConversions;
/**
* Provides cadence in rpm and speed in milliseconds from Bluetooth LE Cycling Cadence and Speed sensors.
* <p>
* https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=261449
*/
public final class SensorDataCycling {
@@ -96,7 +94,7 @@ public final class SensorDataCycling {
public static class DistanceSpeed extends SensorData<DistanceSpeed.Data> {
private final Integer wheelRevolutionsCount; // UINT16
private final Long wheelRevolutionsCount; // UINT32
private final Integer wheelRevolutionsTime; // UINT16; 1/1024s
public DistanceSpeed(String sensorAddress) {
@@ -105,7 +103,7 @@ public final class SensorDataCycling {
this.wheelRevolutionsTime = null;
}
public DistanceSpeed(String sensorAddress, String sensorName, int wheelRevolutionsCount, int wheelRevolutionsTime) {
public DistanceSpeed(String sensorAddress, String sensorName, long wheelRevolutionsCount, int wheelRevolutionsTime) {
super(sensorAddress, sensorName);
this.wheelRevolutionsCount = wheelRevolutionsCount;
this.wheelRevolutionsTime = wheelRevolutionsTime;
@@ -115,7 +113,7 @@ public final class SensorDataCycling {
return wheelRevolutionsCount != null && wheelRevolutionsTime != null;
}
public int getWheelRevolutionsCount() {
public long getWheelRevolutionsCount() {
return wheelRevolutionsCount;
}
@@ -128,20 +126,20 @@ public final class SensorDataCycling {
float timeDiff_ms = UintUtils.diff(wheelRevolutionsTime, previous.wheelRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * UnitConversions.S_TO_MS;
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);
if (timeDiff.isZero() || timeDiff.isNegative()) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute cadence.");
Log.e(TAG, "Timestamps difference is invalid: cannot compute speed.");
value = null;
} else {
long wheelDiff = UintUtils.diff(wheelRevolutionsCount, previous.wheelRevolutionsCount, UintUtils.UINT16_MAX);
wheelDiff = Math.abs(wheelDiff); //HACK for Garmin Speed 2 as some of those seem to count backwards
Distance distance = wheelCircumference.multipliedBy(wheelDiff);
Distance distanceOverall = distance;
if (previous.hasValue()) {
distanceOverall = distance.plus(previous.getValue().distanceOverall);
}
Speed speed_mps = Speed.of(distance, timeDiff);
value = new Data(distance, distanceOverall, speed_mps);
return;
}
long wheelDiff = UintUtils.diff(wheelRevolutionsCount, previous.wheelRevolutionsCount, UintUtils.UINT32_MAX);
Distance distance = wheelCircumference.multipliedBy(wheelDiff);
Distance distanceOverall = distance;
if (previous.hasValue()) {
distanceOverall = distance.plus(previous.getValue().distanceOverall);
}
Speed speed_mps = Speed.of(distance, timeDiff);
value = new Data(distance, distanceOverall, speed_mps);
}
}
@@ -163,11 +161,11 @@ public final class SensorDataCycling {
if (!(obj instanceof DistanceSpeed)) return false;
DistanceSpeed comp = (DistanceSpeed) obj;
if (hasData() && comp.hasData() == hasData()) {
return getWheelRevolutionsCount() == comp.getWheelRevolutionsCount() && getWheelRevolutionsTime() == comp.getWheelRevolutionsTime();
} else {
if (!(hasData() && comp.hasData())) {
return false;
}
return getWheelRevolutionsCount() == comp.getWheelRevolutionsCount() && getWheelRevolutionsTime() == comp.getWheelRevolutionsTime();
}
public static class Data {
@@ -12,7 +12,6 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
@@ -20,15 +19,10 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackActivityDataHubInterface;
import de.dennisguse.opentracks.adapters.IntervalStatisticsAdapter;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.TrackDataListener;
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.content.provider.ContentProviderUtils;
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;
@@ -36,31 +30,31 @@ import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel;
/**
* A fragment to display the intervals from recorded track.
*/
public class IntervalsFragment extends Fragment implements TrackDataListener {
public class IntervalsFragment extends Fragment {
private static final String TAG = IntervalsFragment.class.getSimpleName();
private static final String FROM_TOP_TO_BOTTOM_KEY = "fromTopToBottom";
private static final String TRACK_ID_KEY = "trackId";
private IntervalStatisticsModel viewModel;
protected IntervalStatisticsAdapter.StackMode stackModeListView;
private IntervalStatisticsModel.IntervalOption selectedInterval;
private Track.Id trackId;
private boolean metricUnits;
private IntervalStatisticsAdapter adapter;
private ArrayAdapter<IntervalStatisticsModel.IntervalOption> spinnerAdapter;
private SharedPreferences sharedPreferences;
private TrackDataHub trackDataHub;
private boolean isReportSpeed;
private IntervalListViewBinding viewBinding;
protected final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> {
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
metricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, getContext());
uploadIntervals();
updateIntervals(PreferencesUtils.isMetricUnits(sharedPreferences, getContext()), selectedInterval);
if (spinnerAdapter != null) {
spinnerAdapter.notifyDataSetChanged();
}
@@ -70,12 +64,14 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
/**
* Creates an instance of this class.
*
* @param trackId
* @param fromTopToBottom If true then the intervals are shown from top to bottom (the first interval on top). Otherwise the intervals are shown from bottom to top.
* @return IntervalsFragment instance.
*/
public static Fragment newInstance(boolean fromTopToBottom) {
public static Fragment newInstance(Track.Id trackId, boolean fromTopToBottom) {
Bundle bundle = new Bundle();
bundle.putBoolean(FROM_TOP_TO_BOTTOM_KEY, fromTopToBottom);
bundle.putParcelable(TRACK_ID_KEY, trackId);
IntervalsFragment intervalsFragment = new IntervalsFragment();
intervalsFragment.setArguments(bundle);
return intervalsFragment;
@@ -85,6 +81,7 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
stackModeListView = getArguments().getBoolean(FROM_TOP_TO_BOTTOM_KEY, true) ? IntervalStatisticsAdapter.StackMode.STACK_FROM_TOP : IntervalStatisticsAdapter.StackMode.STACK_FROM_BOTTOM;
trackId = getArguments().getParcelable(TRACK_ID_KEY);
}
@Override
@@ -127,8 +124,7 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
viewBinding.spinnerIntervals.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
selectedInterval = IntervalStatisticsModel.IntervalOption.values()[i];
uploadIntervals();
updateIntervals(metricUnits, IntervalStatisticsModel.IntervalOption.values()[i]);
}
@Override
@@ -140,18 +136,25 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
@Override
public void onResume() {
super.onResume();
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(getContext());
Track track = contentProviderUtils.getTrack(trackId);
if (track != null) {
isReportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, getContext(), track.getCategory());
}
viewModel = new ViewModelProvider(getActivity()).get(IntervalStatisticsModel.class);
loadIntervals();
resumeTrackDataHub();
}
@Override
public void onPause() {
super.onPause();
pauseTrackDataHub();
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
viewModel.onPause();
}
@Override
@@ -177,88 +180,17 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
if (viewModel == null) {
return;
}
LiveData<List<IntervalStatistics.Interval>> liveData = viewModel.getIntervalStats(metricUnits, selectedInterval);
LiveData<List<IntervalStatistics.Interval>> liveData = viewModel.getIntervalStats(trackId, metricUnits, selectedInterval);
liveData.observe(getActivity(), intervalList -> adapter.swapData(intervalList, metricUnits, isReportSpeed));
}
private synchronized void uploadIntervals() {
if (viewModel == null) {
return;
}
viewModel.upload(metricUnits, selectedInterval);
}
private synchronized void updateIntervals(boolean metricUnits, IntervalStatisticsModel.IntervalOption selectedInterval) {
boolean update = metricUnits != this.metricUnits || !selectedInterval.sameMultiplier(this.selectedInterval);
this.metricUnits = metricUnits;
this.selectedInterval = selectedInterval;
/**
* Resumes the trackDataHub.
* Needs to be synchronized because trackDataHub can be accessed by multiple threads.
*/
private synchronized void resumeTrackDataHub() {
trackDataHub = ((TrackActivityDataHubInterface) getActivity()).getTrackDataHub();
trackDataHub.registerTrackDataListener(this);
}
/**
* Pauses the trackDataHub.
* Needs to be synchronized because trackDataHub can be accessed by multiple threads.
*/
private synchronized void pauseTrackDataHub() {
trackDataHub.unregisterTrackDataListener(this);
trackDataHub = null;
}
@Override
public void onTrackUpdated(Track track) {
if (isResumed()) {
getActivity().runOnUiThread(() -> {
if (isResumed()) {
// Set category.
String category = track != null ? track.getCategory() : "";
// Set rate label.
isReportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, getContext(), category);
viewBinding.intervalRate.setText(isReportSpeed ? R.string.stats_speed : R.string.stats_pace);
}
});
}
}
@Override
public void clearTrackPoints() {
if (isResumed()) {
viewModel.clear();
}
}
@Override
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, @NonNull TrackStatistics unused) {
if (isResumed()) {
viewModel.add(trackPoint);
}
}
@Override
public void onNewTrackPointsDone() {
if (isResumed()) {
runOnUiThread(viewModel::onNewTrackPoints);
}
}
/**
* Runs a runnable on the UI thread.
*
* @param runnable the runnable
*/
private void runOnUiThread(Runnable runnable) {
FragmentActivity fragmentActivity = getActivity();
if (fragmentActivity != null) {
fragmentActivity.runOnUiThread(runnable);
if (update && viewModel != null) {
viewModel.update(trackId, this.metricUnits, this.selectedInterval);
}
}
}
@@ -670,7 +670,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
return null;
}
SensorDataSet sensorData = remoteSensorManager.getSensorData();
SensorDataSet sensorData = remoteSensorManager.getSensorData(); //TODO Should return a copy of SensorDataSet
if (sensorData == null) {
return null;
}
@@ -756,10 +756,18 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
return;
}
Track track = contentProviderUtils.getTrack(recordingStatus.getTrackId());
track.getTrackStatistics().setTotalTime(TrackRecordingService.this.getTotalTime());
SensorDataSet sensorDataSet = fillWithSensorDataSet(lastTrackPoint);
recordingDataObservable.postValue(new RecordingData(track, lastTrackPoint, sensorDataSet));
// Compute temporary track statistics using sensorData and update time.
//TODO This somehow should happen in the HandlerServer as we create a new TrackPoint.
TrackStatisticsUpdater tmpTrackStatisticsUpdater = new TrackStatisticsUpdater(trackStatisticsUpdater);
TrackPoint tmpLastTrackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT);
SensorDataSet sensorDataSet = fillWithSensorDataSet(tmpLastTrackPoint);
tmpTrackStatisticsUpdater.addTrackPoint(tmpLastTrackPoint, recordingDistanceInterval);
track.setTrackStatistics(tmpTrackStatisticsUpdater.getTrackStatistics());
recordingDataObservable.postValue(new RecordingData(track, tmpLastTrackPoint, sensorDataSet));
}
public LiveData<RecordingStatus> getRecordingStatusObservable() {
@@ -178,17 +178,13 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
}
String category = track.getCategory();
//TODO Querying all TrackPoints all the time is inefficient; get infos from TrackRecordingService
TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null);
ArrayList<TrackPoint> trackPoints = new ArrayList<>();
while (trackPointIterator.hasNext()) {
trackPoints.add(trackPointIterator.next());
}
boolean isMetricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, context);
boolean isReportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, context, category);
Distance minGPSDistance = PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, context);
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, Distance.one(isMetricUnits));
TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null);
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.one(isMetricUnits), minGPSDistance);
intervalStatistics.addTrackPoints(trackPointIterator);
IntervalStatistics.Interval lastInterval = intervalStatistics.getLastInterval();
String announcement = AnnouncementUtils.getAnnouncement(context, trackStatistics, isMetricUnits, isReportSpeed, lastInterval);
@@ -76,16 +76,10 @@ final class PreferenceHelper {
}
} else {
int feet = (int) (value * UnitConversions.M_TO_FT);
if (feet < 2000) {
displayValue = context.getString(R.string.value_integer_feet, feet);
if (value == maxRecordingDistanceDefault) {
entries[i] = context.getString(R.string.value_integer_feet_recommended, feet);
} else {
entries[i] = displayValue;
}
displayValue = context.getString(R.string.value_integer_feet, feet);
if (value == maxRecordingDistanceDefault) {
entries[i] = context.getString(R.string.value_integer_feet_recommended, feet);
} else {
double mile = feet * UnitConversions.FT_TO_MI;
displayValue = context.getString(R.string.value_float_mile, mile);
entries[i] = displayValue;
}
}
@@ -118,24 +112,14 @@ final class PreferenceHelper {
}
} else {
int feet = (int) (value * UnitConversions.M_TO_FT);
if (feet < 2000) {
displayValue = context.getString(R.string.value_integer_feet, feet);
displayValue = context.getString(R.string.value_integer_feet, feet);
if (value == recordingGPSAccuracyDefault) {
entries[i] = context.getString(R.string.value_integer_feet_recommended, feet);
} else if (value == recordingGPSAccuracyExcellent) {
entries[i] = context.getString(R.string.value_integer_feet_excellent_gps, feet);
} else {
entries[i] = displayValue;
}
if (value == recordingGPSAccuracyDefault) {
entries[i] = context.getString(R.string.value_integer_feet_recommended, feet);
} else if (value == recordingGPSAccuracyExcellent) {
entries[i] = context.getString(R.string.value_integer_feet_excellent_gps, feet);
} else {
double mile = feet * UnitConversions.FT_TO_MI;
displayValue = context.getString(R.string.value_float_mile, mile);
if (value == recordingGPSAccuracyPoor) {
entries[i] = context.getString(R.string.value_float_mile_poor_gps, mile);
} else {
entries[i] = displayValue;
}
entries[i] = displayValue;
}
}
}
@@ -18,6 +18,8 @@ package de.dennisguse.opentracks.stats;
import androidx.annotation.NonNull;
import java.util.Arrays;
/**
* This class maintains a ring buffer of doubles.
* This buffer is a convenient class for storing a series of doubles and calculating information about them.
@@ -49,6 +51,12 @@ class DoubleRingBuffer {
reset();
}
DoubleRingBuffer(DoubleRingBuffer toCopy) {
this.buffer = Arrays.copyOf(toCopy.buffer, toCopy.buffer.length);
this.index = toCopy.index;
this.isFull = toCopy.isFull;
}
/**
* Resets the buffer.
*/
@@ -64,8 +64,8 @@ public class TrackStatisticsUpdater {
private final TrackStatistics trackStatistics;
private final DoubleRingBuffer altitudeBuffer_m = new DoubleRingBuffer(ALTITUDE_SMOOTHING_FACTOR);
private final DoubleRingBuffer speedBuffer_mps = new DoubleRingBuffer(SPEED_SMOOTHING_FACTOR);
private final DoubleRingBuffer altitudeBuffer_m;
private final DoubleRingBuffer speedBuffer_mps;
// The current segment's statistics
private final TrackStatistics currentSegment = new TrackStatistics();
@@ -75,7 +75,7 @@ public class TrackStatisticsUpdater {
private TrackPoint lastMovingTrackPoint;
public TrackStatisticsUpdater() {
trackStatistics = new TrackStatistics();
this(new TrackStatistics());
}
/**
@@ -86,6 +86,22 @@ public class TrackStatisticsUpdater {
public TrackStatisticsUpdater(TrackStatistics trackStatistics) {
this.trackStatistics = trackStatistics;
trackInitialized = true;
altitudeBuffer_m = new DoubleRingBuffer(ALTITUDE_SMOOTHING_FACTOR);
speedBuffer_mps = new DoubleRingBuffer(SPEED_SMOOTHING_FACTOR);
}
public TrackStatisticsUpdater(TrackStatisticsUpdater toCopy) {
this.trackInitialized = toCopy.trackInitialized;
this.segmentInitialized = toCopy.segmentInitialized;
this.altitudeBuffer_m = new DoubleRingBuffer(toCopy.altitudeBuffer_m);
this.speedBuffer_mps = new DoubleRingBuffer(toCopy.speedBuffer_mps);
this.lastTrackPoint = toCopy.lastTrackPoint;
this.lastMovingTrackPoint = toCopy.lastMovingTrackPoint;
this.trackStatistics = toCopy.getTrackStatistics();
this.currentSegment.merge(toCopy.currentSegment);
}
public TrackStatistics getTrackStatistics() {
@@ -109,11 +125,6 @@ public class TrackStatisticsUpdater {
* @param minGPSDistance the min recording distance
*/
public void addTrackPoint(TrackPoint trackPoint, Distance minGPSDistance) {
internalAddTrackPoint(trackPoint, minGPSDistance);
Log.v(TAG, this.toString());
}
private void internalAddTrackPoint(TrackPoint trackPoint, Distance minGPSDistance) {
if (!trackInitialized) {
trackStatistics.setStartTime(trackPoint.getTime());
trackInitialized = true;
@@ -161,13 +172,14 @@ public class TrackStatisticsUpdater {
return;
}
if (!trackPoint.hasSensorDistance()) {
if (!trackPoint.hasSensorDistance()
&& trackPoint.hasLocation() && lastMovingTrackPoint.hasLocation()) {
// GPS-based distance/speed
Distance movingDistance = trackPoint.distanceToPrevious(lastMovingTrackPoint);
if (movingDistance.lessThan(minGPSDistance) && !trackPoint.isMoving()) {
if (movingDistance != null && movingDistance.lessThan(minGPSDistance) && !trackPoint.isMoving()) {
speedBuffer_mps.reset();
lastTrackPoint = trackPoint;
return;
return; //TOOD Why? Is there nothing to be done afterwards?
}
// Update total distance
currentSegment.addTotalDistance(movingDistance);
@@ -33,7 +33,6 @@ import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Locale;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Distance;
@@ -96,38 +95,15 @@ public class StringUtils {
return context.getString(R.string.value_unknown);
}
if (metricUnits) {
if (distance.greaterThan(Distance.of(500))) {
return context.getString(R.string.value_float_kilometer, distance.toKM());
} else {
return context.getString(R.string.value_float_meter, distance.toM());
}
} else {
if (distance.greaterThan(Distance.ofMile(0.5))) {
return context.getString(R.string.value_float_mile, distance.toMI());
} else {
return context.getString(R.string.value_float_feet, distance.toFT());
}
}
Pair<String, String> distanceParts = getDistanceParts(context, distance, metricUnits);
return context.getString(R.string.distance_with_unit, distanceParts.first, distanceParts.second);
}
public static String formatSpeed(Context context, Speed speed, boolean metricUnits, boolean reportSpeed) {
if (reportSpeed) {
if (metricUnits) {
return context.getString(R.string.value_float_kilometer_hour, speed.toKMH());
} else {
return context.getString(R.string.value_float_mile_hour, speed.toMPH());
}
} else {
int pace = (int) speed.toPace(metricUnits).getSeconds();
int minutes = pace / 60;
int seconds = pace % 60;
if (metricUnits) {
return context.getString(R.string.value_pace_kilometer, minutes, seconds);
} else {
return context.getString(R.string.value_pace_mile, minutes, seconds);
}
}
Pair<String, String> distanceParts = getSpeedParts(context, speed, metricUnits, reportSpeed);
return context.getString(R.string.speed_with_unit, distanceParts.first, distanceParts.second);
}
private static String formatDecimal(double value) {
@@ -139,6 +115,7 @@ public class StringUtils {
*/
public static String formatDecimal(double value, int decimalPlaces) {
DecimalFormat df = new DecimalFormat();
df.setMinimumFractionDigits(decimalPlaces);
df.setMaximumFractionDigits(decimalPlaces);
df.setRoundingMode(RoundingMode.HALF_EVEN);
return df.format(value);
@@ -173,7 +150,7 @@ public class StringUtils {
return new Pair<>(formatDecimal(distance.toM()), context.getString(R.string.unit_meter));
}
} else {
if (distance.greaterThan(Distance.of(0.5 * UnitConversions.M_TO_MI))) {
if (distance.greaterThan(Distance.ofMile(0.5))) {
return new Pair<>(formatDecimal(distance.toMI()), context.getString(R.string.unit_mile));
} else {
return new Pair<>(formatDecimal(distance.toFT()), context.getString(R.string.unit_feet));
@@ -211,7 +188,7 @@ public class StringUtils {
int minutes = pace / 60;
int seconds = pace % 60;
return new Pair<>(String.format(Locale.US, "%d:%02d", minutes, seconds), unitString);
return new Pair<>(context.getString(R.string.time, minutes, seconds), unitString);
}
/**
@@ -238,7 +215,7 @@ public class StringUtils {
}
StringBuilder builder = new StringBuilder();
builder.append("[").append(category).append("]");
builder.append(getCategory(category));
if (description != null && description.length() != 0) {
builder.append(" ").append(description);
}
@@ -11,14 +11,14 @@ public class UintUtils {
/**
* Computes a - b for UINT with overflow (b < a).
*
* @return diff or -1 (invalid)
* @return diff
*/
public static long diff(long a, long b, final long UINT_MAX) {
if (a < 0 || b < 0) {
return -1;
throw new RuntimeException("a or b cannot be less than zero.");
}
if (a > UINT_MAX || b > UINT_MAX) {
return -1;
throw new RuntimeException("a or b are outside of the allowed range.");
}
if (a >= b) {
@@ -1,6 +1,6 @@
package de.dennisguse.opentracks.viewmodels;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.time.Duration;
import java.util.ArrayList;
@@ -9,45 +9,72 @@ import java.util.List;
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.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
public class IntervalStatistics {
private final List<Interval> intervalList = new ArrayList<>();
private TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
private final List<Interval> intervalList;
private final Distance distanceInterval;
private final Distance minGPSDistance;
private Interval interval, lastInterval;
public IntervalStatistics(@NonNull List<TrackPoint> trackPoints, Distance distanceInterval) {
intervalList.clear();
/**
* @param distanceInterval distance of every interval.
* @param minGPSDistance the setting value for GPS distance.
*/
public IntervalStatistics(Distance distanceInterval, Distance minGPSDistance) {
this.distanceInterval = distanceInterval;
this.minGPSDistance = minGPSDistance;
if (trackPoints.size() == 0) {
return;
}
interval = new Interval();
lastInterval = new Interval();
intervalList = new ArrayList<>();
intervalList.add(lastInterval);
}
Interval interval = new Interval();
interval.gain_m += trackPoints.get(0).hasAltitudeGain() ? trackPoints.get(0).getAltitudeGain() : 0;
interval.loss_m += trackPoints.get(0).hasAltitudeLoss() ? trackPoints.get(0).getAltitudeLoss() : 0;
for (int i = 1; i < trackPoints.size(); i++) {
TrackPoint prevTrackPoint = trackPoints.get(i - 1);
TrackPoint trackPoint = trackPoints.get(i);
/**
* Complete intervals with the tracks points from the iterator.
*
* @param trackPointIterator
* @return the last track point's id used to compute the intervals.
*/
public TrackPoint.Id addTrackPoints(TrackPointIterator trackPointIterator) {
boolean newIntervalAdded = false;
TrackPoint trackPoint = null;
if (trackPoint.hasLocation() && prevTrackPoint.hasLocation()) {
interval.distance = interval.distance.plus(prevTrackPoint.distanceToPrevious(trackPoint));
interval.time = interval.time.plus(Duration.between(prevTrackPoint.getTime(), trackPoint.getTime()));
interval.gain_m += trackPoint.hasAltitudeGain() ? trackPoint.getAltitudeGain() : 0;
interval.loss_m += trackPoint.hasAltitudeLoss() ? trackPoint.getAltitudeLoss() : 0;
while (trackPointIterator.hasNext()) {
trackPoint = trackPointIterator.next();
trackStatisticsUpdater.addTrackPoint(trackPoint, minGPSDistance);
if (interval.distance.greaterThan(distanceInterval)) {
Interval adjustedInterval = new Interval(interval, distanceInterval.dividedBy(interval.distance));
if (trackStatisticsUpdater.getTrackStatistics().getTotalDistance().plus(interval.distance).greaterOrEqualThan(distanceInterval)) {
interval.add(trackStatisticsUpdater.getTrackStatistics(), trackPoint);
intervalList.add(adjustedInterval);
double adjustFactor = distanceInterval.dividedBy(interval.distance);
Interval adjustedInterval = new Interval(interval);
adjustedInterval.adjust(adjustFactor);
interval = new Interval(interval.distance.minus(adjustedInterval.distance), interval.time.minus(adjustedInterval.time));
}
intervalList.set(intervalList.size() - 1, adjustedInterval);
interval = new Interval(interval.distance.minus(adjustedInterval.distance), interval.time.minus(adjustedInterval.time));
trackStatisticsUpdater = new TrackStatisticsUpdater();
trackStatisticsUpdater.addTrackPoint(trackPoint, minGPSDistance);
lastInterval = new Interval(interval);
intervalList.add(lastInterval);
newIntervalAdded = true;
}
}
if (interval.distance.greaterThan(Distance.of(1))) {
intervalList.add(interval);
if (newIntervalAdded) {
lastInterval.add(trackStatisticsUpdater.getTrackStatistics(), null);
} else {
lastInterval.set(trackStatisticsUpdater.getTrackStatistics());
}
return trackPoint != null ? trackPoint.getId() : null;
}
public List<Interval> getIntervalList() {
@@ -77,8 +104,8 @@ public class IntervalStatistics {
public static class Interval {
private Distance distance = Distance.of(0);
private Duration time = Duration.ofSeconds(0);
private float gain_m = 0f;
private float loss_m = 0f;
private float gain_m;
private float loss_m;
public Interval() {
}
@@ -96,6 +123,18 @@ public class IntervalStatistics {
loss_m = i.loss_m;
}
public Interval(Interval i) {
distance = i.distance;
time = i.time;
gain_m = i.gain_m;
loss_m = i.loss_m;
}
private void adjust(double adjustFactor) {
distance = distance.multipliedBy(adjustFactor);
time = Duration.ofMillis((long) (time.toMillis() * adjustFactor));
}
public Distance getDistance() {
return distance;
}
@@ -111,5 +150,23 @@ public class IntervalStatistics {
public float getLoss_m() {
return loss_m;
}
private void add(TrackStatistics trackStatistics, @Nullable TrackPoint lastTrackPoint) {
distance = distance.plus(trackStatistics.getTotalDistance());
time = time.plus(trackStatistics.getTotalTime());
gain_m = trackStatistics.hasTotalAltitudeGain() ? trackStatistics.getTotalAltitudeGain() : gain_m;
loss_m = trackStatistics.hasTotalAltitudeLoss() ? trackStatistics.getTotalAltitudeLoss() : loss_m;
if (lastTrackPoint != null) {
gain_m = lastTrackPoint.hasAltitudeGain() ? gain_m - lastTrackPoint.getAltitudeGain() : gain_m;
loss_m = lastTrackPoint.hasAltitudeLoss() ? loss_m - lastTrackPoint.getAltitudeLoss() : loss_m;
}
}
private void set(TrackStatistics trackStatistics) {
distance = trackStatistics.getTotalDistance();
time = trackStatistics.getTotalTime();
gain_m = trackStatistics.hasTotalAltitudeGain() ? trackStatistics.getTotalAltitudeGain() : gain_m;
loss_m = trackStatistics.hasTotalAltitudeLoss() ? trackStatistics.getTotalAltitudeLoss() : loss_m;
}
}
}
@@ -1,17 +1,28 @@
package de.dennisguse.opentracks.viewmodels;
import android.app.Application;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.MutableLiveData;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.util.PreferencesUtils;
/**
* This model is used to load intervals for a track.
@@ -19,63 +30,92 @@ import de.dennisguse.opentracks.content.data.TrackPoint;
*/
public class IntervalStatisticsModel extends AndroidViewModel {
private final List<TrackPoint> trackPoints = new ArrayList<>();
private static final String TAG = IntervalStatisticsModel.class.getSimpleName();
private MutableLiveData<List<IntervalStatistics.Interval>> intervalsLiveData;
private IntervalStatistics intervalStatistics;
private Distance distanceInterval;
private final Distance minGPSDistance;
private final ContentResolver contentResolver;
private ContentObserver trackPointsTableObserver;
private TrackPoint.Id lastTrackPointId;
private final Executor executor = Executors.newSingleThreadExecutor();
private HandlerThread handlerThread;
private Handler handler;
public IntervalStatisticsModel(@NonNull Application application) {
super(application);
minGPSDistance = PreferencesUtils.getRecordingDistanceInterval(PreferencesUtils.getSharedPreferences(application), application);
contentResolver = getApplication().getContentResolver();
handlerThread = new HandlerThread(TAG);
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
}
public MutableLiveData<List<IntervalStatistics.Interval>> getIntervalStats(boolean metricUnits, @Nullable IntervalOption interval) {
synchronized (trackPoints) {
if (intervalsLiveData == null) {
if (interval == null) {
interval = IntervalOption.OPTION_1;
}
intervalsLiveData = new MutableLiveData<>();
distanceInterval = interval.getDistance(metricUnits);
loadIntervalStatistics();
}
return intervalsLiveData;
@Override
protected void onCleared() {
super.onCleared();
if (trackPointsTableObserver != null) {
contentResolver.unregisterContentObserver(trackPointsTableObserver);
trackPointsTableObserver = null;
}
}
private void loadIntervalStatistics() {
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, distanceInterval);
intervalsLiveData.postValue(intervalStatistics.getIntervalList());
}
public void add(TrackPoint trackPoint) {
synchronized (trackPoints) {
trackPoints.add(trackPoint);
if (handlerThread != null) {
handlerThread.getLooper().quit();
handlerThread = null;
}
handler = null;
}
public void onNewTrackPoints() {
synchronized (trackPoints) {
if (intervalsLiveData != null) {
loadIntervalStatistics();
}
}
}
public void clear() {
synchronized (trackPoints) {
trackPoints.clear();
}
}
public void upload(boolean metricUnits, @Nullable IntervalOption interval) {
synchronized (trackPoints) {
public MutableLiveData<List<IntervalStatistics.Interval>> getIntervalStats(Track.Id trackId, boolean metricUnits, @Nullable IntervalOption interval) {
if (intervalsLiveData == null) {
if (interval == null) {
interval = IntervalOption.OPTION_1;
}
intervalsLiveData = new MutableLiveData<>();
distanceInterval = interval.getDistance(metricUnits);
loadIntervalStatistics();
intervalStatistics = new IntervalStatistics(distanceInterval, minGPSDistance);
loadIntervalStatistics(trackId);
}
trackPointsTableObserver = new ContentObserver(handler) {
@Override
public void onChange(boolean selfChange, Uri uri) {
loadIntervalStatistics(trackId);
}
};
contentResolver.registerContentObserver(TrackPointsColumns.CONTENT_URI_BY_TRACKID, false, trackPointsTableObserver);
return intervalsLiveData;
}
private void loadIntervalStatistics(Track.Id trackId) {
executor.execute(() -> {
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(getApplication());
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, lastTrackPointId)) {
lastTrackPointId = intervalStatistics.addTrackPoints(trackPointIterator);
intervalsLiveData.postValue(intervalStatistics.getIntervalList());
}
});
}
public void onPause() {
if (trackPointsTableObserver != null) {
contentResolver.unregisterContentObserver(trackPointsTableObserver);
}
}
public void update(Track.Id trackId, boolean metricUnits, @Nullable IntervalOption interval) {
if (interval == null) {
interval = IntervalOption.OPTION_1;
}
lastTrackPointId = null;
distanceInterval = interval.getDistance(metricUnits);
intervalStatistics = new IntervalStatistics(distanceInterval, minGPSDistance);
loadIntervalStatistics(trackId);
}
/**
@@ -103,6 +143,10 @@ public class IntervalStatisticsModel extends AndroidViewModel {
.multipliedBy(multiplier);
}
public boolean sameMultiplier(IntervalOption intervalOption) {
return intervalOption != null && this.multiplier == intervalOption.multiplier;
}
@Override
public String toString() {
return "" + multiplier; //TODO Somehow IntervalsFragment relies on a parsable Integer.
-5
View File
@@ -339,11 +339,6 @@ limitations under the License.
<string name="value_adapt_accuracy">تكييف من أجل الدقة</string>
<string name="value_adapt_battery_life">التكيف بحسب عمر البطارية</string>
<string name="value_always">دائمًا</string>
<string name="value_float_feet">%1$.2f‏ قدم</string>
<string name="value_float_kilometer">%1$.2f‏ كم‏</string>
<string name="value_float_meter">%1$.2f‏ م</string>
<string name="value_float_mile">%1$.2f ميل</string>
<string name="value_float_mile_poor_gps">%1$.1f ميل (إشارة نظام تحديد المواقع سيئة)</string>
<string name="value_integer_feet">%1$d قدم</string>
<string name="value_integer_feet_excellent_gps">%1$d قدم (إشارة نظام تحديد المواقع ممتازة)</string>
<string name="value_integer_feet_recommended">%1$d قدم (موصى به)</string>
-5
View File
@@ -291,11 +291,6 @@
<string name="value_adapt_accuracy">Adapt for accuracy</string>
<string name="value_adapt_battery_life">Adapt for battery life</string>
<string name="value_always">Always</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (poor GPS)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (excellent GPS)</string>
<string name="value_integer_feet_recommended">%1$d ft (recommended)</string>
-9
View File
@@ -295,11 +295,6 @@
<string name="value_adapt_accuracy">Adaptar para precisión</string>
<string name="value_adapt_battery_life">Adaptar a la duración de la batería</string>
<string name="value_always">Siempre</string>
<string name="value_float_feet">%1$.2f pies</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f millas</string>
<string name="value_float_mile_poor_gps">%1$.1f millas (señal de GPS deficiente)</string>
<string name="value_integer_feet">%1$d pies</string>
<string name="value_integer_feet_excellent_gps">%1$d pies (señal de GPS excelente)</string>
<string name="value_integer_feet_recommended">%1$d pies (recomendado)</string>
@@ -462,10 +457,6 @@
\nd) desactivar el ahorro de energía.
\n
\nSi todo no ayuda, informe un error. </string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="help_support_content"> Usted puede:
\na) haga correr la voz sobre OpenTracks,
\nb) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> proponer funciones </a>,
-5
View File
@@ -341,11 +341,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Адаптиране за точност</string>
<string name="value_adapt_battery_life">Адаптиране спрямо батерията</string>
<string name="value_always">Винаги</string>
<string name="value_float_feet">%1$.2f фт</string>
<string name="value_float_kilometer">%1$.2f км</string>
<string name="value_float_meter">%1$.2f м</string>
<string name="value_float_mile">%1$.2f мил</string>
<string name="value_float_mile_poor_gps">%1$.1f мил (слаб GPS)</string>
<string name="value_integer_feet">%1$d фт</string>
<string name="value_integer_feet_excellent_gps">%1$d фт (отличен GPS)</string>
<string name="value_integer_feet_recommended">%1$d фт (препоръчително)</string>
-5
View File
@@ -341,11 +341,6 @@ es vegi el cel. Torneu-ho a provar més tard.</string>
<string name="value_adapt_accuracy">Adapta\'n la precisió</string>
<string name="value_adapt_battery_life">Adapta a la durada de la bateria</string>
<string name="value_always">Sempre</string>
<string name="value_float_feet">%1$.2f peus</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f milles</string>
<string name="value_float_mile_poor_gps">%1$.1f milles (GPS amb poca senyal)</string>
<string name="value_integer_feet">%1$d peus</string>
<string name="value_integer_feet_excellent_gps">%1$d peus (senyal de GPS excel·lent)</string>
<string name="value_integer_feet_recommended">%1$d peus (recomanat)</string>
-9
View File
@@ -411,11 +411,6 @@ Pokud zařízení GPS hlásí nepřesná data (např. Polohu, rychlost, nadmořs
<string name="value_adapt_accuracy">Upřednostnit přesnost</string>
<string name="value_adapt_battery_life">Upřednostnit výdrži baterie</string>
<string name="value_always">Vždy</string>
<string name="value_float_feet">%1$.2f stop</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mil</string>
<string name="value_float_mile_poor_gps">%1$.1f mil (špatný signál GPS)</string>
<string name="value_integer_feet">%1$d stop</string>
<string name="value_integer_feet_excellent_gps">%1$d stop (vynikající signál GPS)</string>
<string name="value_integer_feet_recommended">%1$d stop (doporučeno)</string>
@@ -556,10 +551,6 @@ Pokud zařízení GPS hlásí nepřesná data (např. Polohu, rychlost, nadmořs
<string name="stats_intervals">Intervaly</string>
<string name="stats_split_interval">Rozdělit interval</string>
<string name="track_detail_intervals_tab">Intervaly</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="value_float_mile_hour">%1$.2f mil/h</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="voice_pace_lap">Čas na kolo %1$s</string>
<string name="hold_to_pause">Podržet pro pozastavení</string>
<string name="toast_message_instant_track_was_exported">Poslední trasa exportována</string>
-9
View File
@@ -417,11 +417,6 @@ Hvis GPS-enheden rapporterer unøjagtige data (f.eks. Placering, hastighed, høj
<string name="value_adapt_accuracy">Juster nøjagtighed</string>
<string name="value_adapt_battery_life">Tilpas til batterilevetid</string>
<string name="value_always">Altid</string>
<string name="value_float_feet">%1$.2f fod</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mil</string>
<string name="value_float_mile_poor_gps">%1$.1f mil (dårlig GPS)</string>
<string name="value_integer_feet">%1$d fod</string>
<string name="value_integer_feet_excellent_gps">%1$d fod (fremragende GPS)</string>
<string name="value_integer_feet_recommended">%1$d fod (anbefales)</string>
@@ -545,10 +540,7 @@ Hvis GPS-enheden rapporterer unøjagtige data (f.eks. Placering, hastighed, høj
<string name="open_track_as_trackfileformat">Åbn som %1$s</string>
<string name="activity_type_escooter">elektrisk scooter</string>
<string name="generic_click_twice_cancel">Klik tilbage igen for at annullere</string>
<string name="value_float_kilometer_hour">%1$.2f km/t</string>
<string name="import_unable_to_import_file">Kunne ikke importere filen:%1$s</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="import_prevent_reimport">Du har indstillet forhindre genimport af spor</string>
<string name="settings_default_export_uri_title">Spor eksportmappe</string>
<string name="instant_export_enabled_summary">Eksporter spor til lagring, når optagelsen er færdig</string>
@@ -583,7 +575,6 @@ Hvis GPS-enheden rapporterer unøjagtige data (f.eks. Placering, hastighed, høj
<string name="interval_list_empty_message">Der er ikke noget interval endnu</string>
<string name="aggregated_stats_empty_message">Optag dit første spor for at se aggregerede statistikker</string>
<string name="track_detail_intervals_tab">Intervaller</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="voice_pace_lap">Omgangstid på %1$s</string>
<string name="voice_speed_lap">Omgangshastighed på %1$s</string>
<string name="hold_to_pause">Hold nede for at holde pause</string>
-7
View File
@@ -422,11 +422,6 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<string name="value_adapt_accuracy">Genauigkeit anpassen</string>
<string name="value_adapt_battery_life">An Akkulaufzeit anpassen</string>
<string name="value_always">Immer</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f Meilen</string>
<string name="value_float_mile_poor_gps">%1$.1f Meilen (schlechtes GPS-Signal)</string>
<string name="value_integer_feet">%1$d Fuß</string>
<string name="value_integer_feet_excellent_gps">%1$d Fuß (ausgezeichnetes GPS-Signal)</string>
<string name="value_integer_feet_recommended">%1$d Fuß (empfohlen)</string>
@@ -601,6 +596,4 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<string name="track_distance_notification">Strecke: %1$s</string>
<string name="track_speed_notification">Geschwindigkeit: %1$s</string>
<string name="track_pace_notification">Tempo: %1$s</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
</resources>
-5
View File
@@ -340,11 +340,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Προσαρμογή για ακρίβεια</string>
<string name="value_adapt_battery_life">Καλύτερο για μπατ.</string>
<string name="value_always">Πάντα</string>
<string name="value_float_feet">%1$.2f πόδια</string>
<string name="value_float_kilometer">%1$.2f χιλιόμετρα</string>
<string name="value_float_meter">%1$.2f μέτρα</string>
<string name="value_float_mile">%1$.2f μίλια</string>
<string name="value_float_mile_poor_gps">%1$.1f μίλια (χαμηλό σήμα GPS)</string>
<string name="value_integer_feet">%1$d πόδια</string>
<string name="value_integer_feet_excellent_gps">%1$d πόδια (τέλειο σήμα GPS)</string>
<string name="value_integer_feet_recommended">%1$d ft (συνιστάται)</string>
-9
View File
@@ -412,11 +412,6 @@ Si el dispositivo GPS reporta datos inexactos (por ejemplo, ubicación, velocida
<string name="value_adapt_accuracy">Adaptar para obtener valores exactos</string>
<string name="value_adapt_battery_life">Adaptar a la duración de la batería</string>
<string name="value_always">Siempre</string>
<string name="value_float_feet">%1$.2f pies</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f millas</string>
<string name="value_float_mile_poor_gps">%1$.1f millas (señal de GPS débil)</string>
<string name="value_integer_feet">%1$d pies</string>
<string name="value_integer_feet_excellent_gps">%1$d pies (señal de GPS excelente)</string>
<string name="value_integer_feet_recommended">%1$d pies (recomendado)</string>
@@ -595,12 +590,8 @@ Si el dispositivo GPS reporta datos inexactos (por ejemplo, ubicación, velocida
<string name="import_progress_summary_errors_msg">Errores</string>
<string name="import_progress_summary_ok_msg">Archivos importados</string>
<string name="description_altitude_loss">Pérdida de altura: %1$d m (%2$d pies)</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="sensor_state_cadence_max">Cadencia máxima</string>
<string name="sensor_state_cadence_avg">Cadencia media</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="export_progress_summary_overwrite_msg">Pistas sobrescritas</string>
<string name="export_progress_summary_skip_msg">Pistas omitidas</string>
<string name="export_progress_summary_errors_msg">Errores</string>
-9
View File
@@ -411,11 +411,6 @@ Kui GPS-seade teatab ebatäpsetest andmetest (nt asukoht, kiirus, kõrgus), ei s
<string name="value_adapt_accuracy">Täpsuse kohandamine</string>
<string name="value_adapt_battery_life">Kohandage aku elueale</string>
<string name="value_always">Alati</string>
<string name="value_float_feet">%1$.2f jalga</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f miili</string>
<string name="value_float_mile_poor_gps">%1$.1f miili (nõrk GPS-signaal)</string>
<string name="value_integer_feet">%1$d jalga</string>
<string name="value_integer_feet_excellent_gps">%1$d jalga (tugev GPS-signaal)</string>
<string name="value_integer_feet_recommended">%1$d jalga (soovitatav)</string>
@@ -579,10 +574,6 @@ Kui GPS-seade teatab ebatäpsetest andmetest (nt asukoht, kiirus, kõrgus), ei s
<string name="stats_split_interval">Jagatud intervall</string>
<string name="stats_intervals">Intervallid</string>
<string name="interval_list_empty_message">Ei ole ühtegi intervalli veel</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="voice_speed_lap">Ringi kiirus %1$s</string>
<string name="hold_to_stop">Hoidke lõpetada</string>
<string name="hold_to_pause">Hoidke pausi</string>
-9
View File
@@ -412,11 +412,6 @@ GPS gailuak datu okerrak salatzen baditu (adibidez, kokapena, abiadura, kota), O
<string name="value_adapt_accuracy">Doitu zehaztasuna</string>
<string name="value_adapt_battery_life">Doitu bateriaren iraupenera</string>
<string name="value_always">Beti</string>
<string name="value_float_feet">%1$.2f oin</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (GPS ahula)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (GPS bikaina)</string>
<string name="value_integer_feet_recommended">%1$d oin (gomendatua)</string>
@@ -543,13 +538,9 @@ GPS gailuak datu okerrak salatzen baditu (adibidez, kokapena, abiadura, kota), O
<string name="activity_type_escooter">eskooterra</string>
<string name="settings_recording_fullscreen_on_while_recording_summary">Grabatzen ari zaren bitartean, pantaila osoan ikusi.</string>
<string name="settings_recording_fullscreen_on_while_recording_title">Pantaila osoa</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="settings_default_export_uri_title">Track esportazio-direktorioa</string>
<string name="instant_export_enabled_title">Berehalako post-entrenamendu esportatu</string>
<string name="instant_export_enabled_summary">Esportazio-pista biltegiratze ondoren grabaketa amaitu da</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="interval_list_empty_message">Ez dira edozein tarte oraindik</string>
<string name="aggregated_stats_empty_message">Grabatu zure lehen pista ikusteko batzen estatistikak</string>
<string name="open_track_as_GPX">Ireki gisa GPX</string>
-5
View File
@@ -339,11 +339,6 @@ limitations under the License.
<string name="value_adapt_accuracy">تعدیل به خاطر دقت</string>
<string name="value_adapt_battery_life">تعدیل به خاطر عمر باتری</string>
<string name="value_always">همیشه</string>
<string name="value_float_feet">%1$.2f فوت</string>
<string name="value_float_kilometer">%1$.2f کیلومتر</string>
<string name="value_float_meter">%1$.2f متر</string>
<string name="value_float_mile">%1$.2f مایل</string>
<string name="value_float_mile_poor_gps">%1$.1f مایل (GPS ضعیف)</string>
<string name="value_integer_feet">%1$d فوت</string>
<string name="value_integer_feet_excellent_gps">%1$d فوت (GPS عالی)</string>
<string name="value_integer_feet_recommended">%1$d فوت (توصیه می‌شود)</string>
-9
View File
@@ -422,11 +422,6 @@ jotta ne voidaan tuoda kohteeseen %1$s.</string>
<string name="value_adapt_accuracy">Säädä tarkkuutta</string>
<string name="value_adapt_battery_life">Sovita akun kestoon</string>
<string name="value_always">Aina</string>
<string name="value_float_feet">%1$.2f jalkaa</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mailia</string>
<string name="value_float_mile_poor_gps">%1$.1f mailia (heikko GPS)</string>
<string name="value_integer_feet">%1$d jalkaa</string>
<string name="value_integer_feet_excellent_gps">%1$d jalkaa (erinomainen GPS)</string>
<string name="value_integer_feet_recommended">%1$d jalkaa (suositus)</string>
@@ -560,7 +555,6 @@ jotta ne voidaan tuoda kohteeseen %1$s.</string>
<string name="settings_default_export_uri_title">Seuraa vientihakemistoa</string>
<string name="instant_export_enabled_summary">Vie raita varastoon tallennuksen jälkeen on valmis</string>
<string name="voice_speed_lap">Kierrosnopeus %1$s</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="settings_sensor_wheel_circumference">Pyörän ympärysmitta (mm)</string>
<string name="stats_intervals">Välein</string>
<string name="import_thread_interrupted">Lanka keskeytetty</string>
@@ -605,12 +599,9 @@ jotta ne voidaan tuoda kohteeseen %1$s.</string>
<string name="description_altitude_loss">Korkeussijaintitappio: %1$d m (%2$d ft)</string>
<string name="sensor_state_heart_rate_max">Maksimisyke</string>
<string name="sensor_state_heart_rate_avg">Avg syke</string>
<string name="value_float_kilometer_hour">%1$.2f k/t</string>
<string name="value_pace_mile">%1$d:%2$02d min/mailia</string>
<string name="activity_type_escooter">eskootteri</string>
<string name="sensor_state_cadence_avg">Keskim.Poljinnopeus</string>
<string name="sensor_state_cadence_max">Suurin Poljinnopeus</string>
<string name="value_float_mile_hour">%1$.2f mt</string>
<string name="generic_open_track">Avattu reitti</string>
<string name="track_distance_notification">Etäisyys: %1$s</string>
<string name="track_pace_notification">Vauhti: %1$s</string>
-5
View File
@@ -290,11 +290,6 @@
<string name="value_adapt_accuracy">Adapter pour la précision</string>
<string name="value_adapt_battery_life">Optimiser pour économiser la pile</string>
<string name="value_always">Toujours</string>
<string name="value_float_feet">%1$.2f pi</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (mauvaise réception GPS)</string>
<string name="value_integer_feet">%1$d pi</string>
<string name="value_integer_feet_excellent_gps">%1$d pi(s) (réception GPS excellente)</string>
<string name="value_integer_feet_recommended">%1$d pi (recommandé)</string>
+1 -6
View File
@@ -291,12 +291,7 @@
<string name="value_adapt_accuracy">Adapter pour la précision</string>
<string name="value_adapt_battery_life">Économiser la batterie</string>
<string name="value_always">Toujours</string>
<string name="value_float_feet">%1$.2f pi</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mile(s)</string>
<string name="value_float_mile_poor_gps">%1$.1f mile(s) (mauvaise réception GPS)</string>
<string name="value_integer_feet">%1$d pied(s)</string>
<string name="value_integer_feet">%1$d pied(s)</string>
<string name="value_integer_feet_excellent_gps">%1$d pied(s) (réception GPS excellente)</string>
<string name="value_integer_feet_recommended">%1$d pied(s) (recommandé)</string>
<string name="value_integer_kilometer">%1$d km</string>
-9
View File
@@ -412,11 +412,6 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
<string name="value_adapt_accuracy">Adapter pour la précision</string>
<string name="value_adapt_battery_life">Économiser la batterie</string>
<string name="value_always">Toujours</string>
<string name="value_float_feet">%1$.2f pi</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mile(s)</string>
<string name="value_float_mile_poor_gps">%1$.1f mile(s) (mauvaise réception GPS)</string>
<string name="value_integer_feet">%1$d pied(s)</string>
<string name="value_integer_feet_excellent_gps">%1$d pied(s) (réception GPS excellente)</string>
<string name="value_integer_feet_recommended">%1$d pied(s) (recommandé)</string>
@@ -542,10 +537,6 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
<string name="track_detail_intervals_tab">Intervalles</string>
<string name="interval_list_empty_message">Il n\'y a pas encore d\'intervalle</string>
<string name="aggregated_stats_empty_message">Enregistrez votre première piste pour voir les statistiques agrégées</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="voice_pace_lap">Temps au tour de %1$s</string>
<string name="voice_speed_lap">Vitesse du tour de %1$s</string>
<string name="toast_message_instant_track_was_exported">Dernière piste exportée</string>
-9
View File
@@ -429,11 +429,6 @@ Se te detés ou estás en interiores, non se gardarán datos do sensor (mais ser
<string name="value_adapt_accuracy">Adaptar para obter precisión</string>
<string name="value_adapt_battery_life">Adaptar á duración restante da batería</string>
<string name="value_always">Sempre</string>
<string name="value_float_feet">%1$.2f pés</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f km</string>
<string name="value_float_mile_poor_gps">%1$.1f km (GPS deficiente)</string>
<string name="value_integer_feet">%1$d m</string>
<string name="value_integer_feet_excellent_gps">%1$d m (GPS excelente)</string>
<string name="value_integer_feet_recommended">%1$d m (recomendado)</string>
@@ -593,12 +588,8 @@ Se te detés ou estás en interiores, non se gardarán datos do sensor (mais ser
<string name="export_progress_summary_new_msg">Exportadas as novas rutas</string>
<string name="import_no_kml_file_found">Non se atopou ficheiro doc.kml en KMZ</string>
<string name="stats_loss">Perda</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="description_altitude_loss">Perda de altitude: %1$d m (%2$d ft)</string>
<string name="export_error_post_workout">Fallou a exportación, comproba o directorio de exportación.</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="settings_prevent_reimport_tracks_title">Previr a reimportación de rutas</string>
<string name="export_progress_summary_overwrite_msg">Rutas sobrescritas</string>
<string name="export_progress_summary_skip_msg">Rutas omitidas</string>
-5
View File
@@ -339,11 +339,6 @@ limitations under the License.
<string name="value_adapt_accuracy">सटीकता के लिए ग्रहण करें</string>
<string name="value_adapt_battery_life">बैटरी जीवन के लिए ग्रहण करें</string>
<string name="value_always">हमेशा</string>
<string name="value_float_feet">%1$.2f फुट</string>
<string name="value_float_kilometer">%1$.2f किमी</string>
<string name="value_float_meter">%1$.2f मी</string>
<string name="value_float_mile">%1$.2f मी</string>
<string name="value_float_mile_poor_gps">%1$.1f मी (खराब GPS)</string>
<string name="value_integer_feet">%1$d फुट</string>
<string name="value_integer_feet_excellent_gps">%1$d फुट (उत्कृष्ट GPS)</string>
<string name="value_integer_feet_recommended">%1$d फ़ुट (अनुशंसित)</string>
-5
View File
@@ -340,11 +340,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Prilagodba radi točnosti</string>
<string name="value_adapt_battery_life">Prilagodi vijeku trajanja baterije</string>
<string name="value_always">Uvijek</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (loš GPS)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (izvrstan GPS)</string>
<string name="value_integer_feet_recommended">%1$d ft (preporučeno)</string>
-9
View File
@@ -341,11 +341,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Beállítás pontossághoz</string>
<string name="value_adapt_battery_life">Akkumulátor élettartama szerint</string>
<string name="value_always">Mindig</string>
<string name="value_float_feet">%1$.2f láb</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mérföld</string>
<string name="value_float_mile_poor_gps">%1$.1f mérföld (gyenge GPS-jel)</string>
<string name="value_integer_feet">%1$d láb</string>
<string name="value_integer_feet_excellent_gps">%1$d láb (kiváló GPS-jel)</string>
<string name="value_integer_feet_recommended">%1$d láb (ajánlott)</string>
@@ -499,15 +494,12 @@ limitations under the License.
<string name="track_detail_record_success">Most egy új szám felvétele</string>
<string name="track_detail_resume_success">Most folytatódik a pálya</string>
<string name="interval_list_empty_message">Még nincs intervallum</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="settings_default_export_uri_title">Pálya export könyvtár</string>
<string name="instant_export_enabled_summary">Sáv exportálása a tárolóba a felvétel befejezése után</string>
<string name="toast_message_instant_track_was_exported">Utolsó exportált zeneszám</string>
<string name="hold_to_pause">Tartsa a szünethez</string>
<string name="hold_to_stop">Tartsa lenyomva a leállításhoz</string>
<string name="track_distance_notification">Távolság: %1$s</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="instant_export_enabled_title">Azonnali edzés utáni export</string>
<string name="track_pace_notification">Tempó: %1$s</string>
<string name="export_with_photos">fotókkal</string>
@@ -519,7 +511,6 @@ limitations under the License.
<string name="import_unsupported_format">Nem támogatott fájlformátum</string>
<string name="description_default_speed_or_pace">Tevékenységtípus szerint</string>
<string name="export_without_photos">fotók nélkül</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="voice_speed_lap">%1$s körsebessége</string>
<string name="help_gps_troubleshooting_content"> Mit tehetsz:
\n a) ellenőrizze, hogy a GPS engedélyezve van-e,
-5
View File
@@ -291,11 +291,6 @@
<string name="value_adapt_accuracy">Sesuaikan dengan akurasi</string>
<string name="value_adapt_battery_life">Sesuaikan untuk masa pakai baterai</string>
<string name="value_always">Selalu</string>
<string name="value_float_feet">%1$.2f kaki</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mil</string>
<string name="value_float_mile_poor_gps">%1$.1f mil (GPS buruk)</string>
<string name="value_integer_feet">%1$d kaki</string>
<string name="value_integer_feet_excellent_gps">%1$d kaki (GPS sangat baik)</string>
<string name="value_integer_feet_recommended">%1$d kaki (direkomendasikan)</string>
-9
View File
@@ -385,11 +385,6 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
<string name="value_adapt_accuracy">Adatta per la precisione</string>
<string name="value_adapt_battery_life">Adatta per la massima durata della batteria</string>
<string name="value_always">Sempre</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (GPS debole)</string>
<string name="value_integer_feet">%1$d pd</string>
<string name="value_integer_feet_excellent_gps">%1$d pd (GPS forte)</string>
<string name="value_integer_feet_recommended">%1$d pd (consigliato)</string>
@@ -605,16 +600,12 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
<string name="import_progress_summary_errors_msg">Errore</string>
<string name="sensor_state_power_avg">Potenza media</string>
<string name="sensor_state_heart_rate_max">Frequenza cardiaca max</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/cm</string>
<string name="value_float_kilometer_hour">%1$.2f cp/s</string>
<string name="stats_loss">Discesa</string>
<string name="settings_sensor_wheel_circumference">Circonferenza della ruota (mm)</string>
<string name="description_altitude_loss">Perdita di quota: %1$d m (%2$d ft)</string>
<string name="sensor_state_heart_rate_avg">Tasso cardiaco medio</string>
<string name="sensor_state_cadence_max">Cadenza max</string>
<string name="sensor_state_cadence_avg">Cadenza media</string>
<string name="value_float_mile_hour">%1$.2f mpo</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="track_distance_notification">Distanza: %1$s</string>
<string name="track_speed_notification">Velocità: %1$s</string>
<string name="track_pace_notification">Ritmo: %1$s</string>
-5
View File
@@ -291,11 +291,6 @@
<string name="value_adapt_accuracy">התאם למען הדיוק</string>
<string name="value_adapt_battery_life">התאם לחיי הסוללה</string>
<string name="value_always">תמיד</string>
<string name="value_float_feet">%1$.2f רגל</string>
<string name="value_float_kilometer">%1$.2f ק\"מ</string>
<string name="value_float_meter">%1$.2f מ\'</string>
<string name="value_float_mile">%1$.2f מייל</string>
<string name="value_float_mile_poor_gps">%1$.1f מייל (GPS חלש)</string>
<string name="value_integer_feet">%1$d רגל</string>
<string name="value_integer_feet_excellent_gps">%1$d רגל (GPS מעולה)</string>
<string name="value_integer_feet_recommended">%1$d רגל (מומלץ)</string>
-5
View File
@@ -341,11 +341,6 @@ limitations under the License.
<string name="value_adapt_accuracy">精度を重視</string>
<string name="value_adapt_battery_life">電池残量を重視</string>
<string name="value_always">常に使用する</string>
<string name="value_float_feet">%1$.2fフィート</string>
<string name="value_float_kilometer">%1$.2fkm</string>
<string name="value_float_meter">%1$.2fm</string>
<string name="value_float_mile">%1$.2fmi</string>
<string name="value_float_mile_poor_gps">%1$.1fmi(GPS信号: 弱)</string>
<string name="value_integer_feet">%1$dft</string>
<string name="value_integer_feet_excellent_gps">%1$dft(GPS信号: 強)</string>
<string name="value_integer_feet_recommended">%1$dft(推奨)</string>
-5
View File
@@ -340,11 +340,6 @@ limitations under the License.
<string name="value_adapt_accuracy">정확도를 위해 조정</string>
<string name="value_adapt_battery_life">배터리 수명을 위해 조정</string>
<string name="value_always">항상</string>
<string name="value_float_feet">%1$.2f피트</string>
<string name="value_float_kilometer">%1$.2fkm</string>
<string name="value_float_meter">%1$.2fm</string>
<string name="value_float_mile">%1$.2f마일</string>
<string name="value_float_mile_poor_gps">%1$.1f마일(GPS 수신 불량)</string>
<string name="value_integer_feet">%1$d피트</string>
<string name="value_integer_feet_excellent_gps">%1$d피트(GPS 수신 원활)</string>
<string name="value_integer_feet_recommended">%1$d피트(권장)</string>
-5
View File
@@ -342,11 +342,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Pritaikyti siekiant tikslumo</string>
<string name="value_adapt_battery_life">Pritaik. taus. akum.</string>
<string name="value_always">Visada</string>
<string name="value_float_feet">%1$.2f pėd.</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f myl.</string>
<string name="value_float_mile_poor_gps">%1$.1f myl. (prastas GPS)</string>
<string name="value_integer_feet">%1$d pėd.</string>
<string name="value_integer_feet_excellent_gps">%1$d pėd. (puikus GPS)</string>
<string name="value_integer_feet_recommended">%1$d pėd. (rekomenduojama)</string>
-5
View File
@@ -340,11 +340,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Pielāgot precizitātei</string>
<string name="value_adapt_battery_life">Pielāgot akumulatora darbības ilgumam</string>
<string name="value_always">Vienmēr</string>
<string name="value_float_feet">%1$.2f pēda(-as)</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f jūdze(-es)</string>
<string name="value_float_mile_poor_gps">%1$.1f jūdze(-es) (vājš GPS)</string>
<string name="value_integer_feet">%1$d pēda(-as)</string>
<string name="value_integer_feet_excellent_gps">%1$d pēda(-as) (izcilas kvalitātes GPS)</string>
<string name="value_integer_feet_recommended">%1$d pēdas (ieteicams)</string>
-5
View File
@@ -291,11 +291,6 @@
<string name="value_adapt_accuracy">Adaptaţi pentru acurateţe</string>
<string name="value_adapt_battery_life">Economisiţi bateria</string>
<string name="value_always">Întotdeauna</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (semnal GPS slab)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (semnal GPS excelent)</string>
<string name="value_integer_feet_recommended">%1$d ft (recomandat)</string>
-5
View File
@@ -341,11 +341,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Sesuaikan untuk ketepatan</string>
<string name="value_adapt_battery_life">Sesuaikan untuk hayat bateri</string>
<string name="value_always">Sentiasa</string>
<string name="value_float_feet">%1$.2f kaki</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f batu</string>
<string name="value_float_mile_poor_gps">%1$.1f batu (GPS lemah)</string>
<string name="value_integer_feet">%1$d kaki</string>
<string name="value_integer_feet_excellent_gps">%1$d kaki (GPS bagus)</string>
<string name="value_integer_feet_recommended">%1$d kaki (disyorkan)</string>
-9
View File
@@ -342,11 +342,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Tilpass for nøyaktighet</string>
<string name="value_adapt_battery_life">Tilpass for batterilevetid</string>
<string name="value_always">Alltid</string>
<string name="value_float_feet">%1$.2f fot</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (dårlig GPS)</string>
<string name="value_integer_feet">%1$d fot</string>
<string name="value_integer_feet_excellent_gps">%1$d fot (utmerket GPS)</string>
<string name="value_integer_feet_recommended">%1$d fot (anbefales)</string>
@@ -579,10 +574,6 @@ limitations under the License.
\n e) kjøpe i <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,
\n f) donere, og
\n g) gjøre hva du tror hjelper OpenTracks. </string>
<string name="value_float_kilometer_hour">%1$.2f km/t</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="description_altitude_loss">Total nedstigning: %1$d m (%2$d ft)</string>
<string name="stats_loss">Total nedstigning</string>
<string name="import_prevent_reimport">Du har stilt inn å forhindre at spor importeres om igjen</string>
-9
View File
@@ -411,11 +411,6 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
<string name="value_adapt_accuracy">Aanpassen voor nauwkeurigheid</string>
<string name="value_adapt_battery_life">Aanpassen voor resterende accutijd</string>
<string name="value_always">Altijd</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (slecht GPS-signaal)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (uitstekend GPS-signaal)</string>
<string name="value_integer_feet_recommended">%1$d ft (aanbevolen)</string>
@@ -553,7 +548,6 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
<string name="import_no_kml_file_found">Geen doc.kml bestand gevonden in KMZ</string>
<string name="settings_recording_fullscreen_on_while_recording_title">Volledig scherm</string>
<string name="gps_fixed_and_ready">GPS vast en klaar</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="aggregated_stats_empty_message">Neem uw eerste track op om geaggregeerde statistieken te zien</string>
<string name="track_detail_intervals_tab">Intervallen</string>
<string name="settings_sensor_wheel_circumference">Wielomtrek (mm)</string>
@@ -574,12 +568,9 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
<string name="settings_night_mode_option_system">Systeem</string>
<string name="settings_night_mode_title">UI Thema</string>
<string name="stats_loss">Verlies</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="interval_list_empty_message">Er zijn nog geen intervallen</string>
<string name="stats_split_interval">Gesplitst interval</string>
<string name="stats_intervals">Intervallen</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="voice_pace_lap">Rondetijd van %1$s</string>
<string name="voice_speed_lap">Ronde snelheid van %1$s</string>
<string name="instant_export_enabled_title">Directe export na de training</string>
-9
View File
@@ -378,11 +378,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Dostosuj pod kątem dokładności</string>
<string name="value_adapt_battery_life">Dostosuj pod kątem żywotności baterii</string>
<string name="value_always">Zawsze</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (słaby sygnał GPS)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (doskonały sygnał GPS)</string>
<string name="value_integer_feet_recommended">%1$d ft (zalecane)</string>
@@ -609,10 +604,6 @@ limitations under the License.
<string name="track_pace_notification">Prędkość: %1$s</string>
<string name="track_speed_notification">Szybkość: %1$s</string>
<string name="track_distance_notification">Odległość: %1$s</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="about_third_party_data">Dane osób trzecich</string>
<string name="delete_service">Usługa usuwania</string>
<string name="track_delete_progress">%1$d/%2$d</string>
-9
View File
@@ -294,11 +294,6 @@
<string name="value_adapt_accuracy">Adaptar para fins de precisão</string>
<string name="value_adapt_battery_life">Adaptar à vida da bateria</string>
<string name="value_always">Sempre</string>
<string name="value_float_feet">%1$.2f pés</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f milhas</string>
<string name="value_float_mile_poor_gps">%1$.1f milhas (GPS com sinal baixo)</string>
<string name="value_integer_feet">%1$d pés</string>
<string name="value_integer_feet_excellent_gps">%1$d pés (GPS excelente)</string>
<string name="value_integer_feet_recommended">%1$d pés (recomendado)</string>
@@ -530,16 +525,12 @@
<string name="voice_pace_lap">Tempo da volta de %1$s</string>
<string name="share_image_subject">Eu gostaria de compartilhar uma imagem com você</string>
<string name="instant_export_enabled_summary">Exportar trilha para armazenamento depois que a gravação for concluída</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="import_prevent_reimport">Você definiu evitar reimportar a trilha</string>
<string name="stats_loss">Perda</string>
<string name="export_error_post_workout">A exportação pós-treino falhou, verifique o diretório de exportação.</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="description_altitude_loss">Perda de elevação: %1$d m (%2$d ft)</string>
<string name="export_progress_summary_new_msg">Novas trilhas exportadas</string>
<string name="import_no_kml_file_found">Nenhum arquivo doc.kml encontrado no KMZ</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="settings_prevent_reimport_tracks_title">Impedir a reimportação de trilhas</string>
<string name="export_progress_summary_overwrite_msg">Trilhas sobrescritas</string>
<string name="export_progress_summary_skip_msg">Trilhas puladas</string>
-5
View File
@@ -290,11 +290,6 @@
<string name="value_adapt_accuracy">Adaptar para precisão</string>
<string name="value_adapt_battery_life">Adaptar para a vida da bateria</string>
<string name="value_always">Sempre</string>
<string name="value_float_feet">%1$.2f pés</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (GPS fraco)</string>
<string name="value_integer_feet">%1$d pés</string>
<string name="value_integer_feet_excellent_gps">%1$d pés (GPS excelente)</string>
<string name="value_integer_feet_recommended">%1$d pés (recomendado)</string>
-5
View File
@@ -342,11 +342,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Adaptar para fins de precisão</string>
<string name="value_adapt_battery_life">Adaptar à vida da bateria</string>
<string name="value_always">Sempre</string>
<string name="value_float_feet">%1$.2f pés</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f milhas</string>
<string name="value_float_mile_poor_gps">%1$.1f milhas (GPS com sinal baixo)</string>
<string name="value_integer_feet">%1$d pés</string>
<string name="value_integer_feet_excellent_gps">%1$d pés (GPS excelente)</string>
<string name="value_integer_feet_recommended">%1$d pés (recomendado)</string>
-5
View File
@@ -340,11 +340,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Adaptaţi pentru acurateţe</string>
<string name="value_adapt_battery_life">Economisiţi bateria</string>
<string name="value_always">Întotdeauna</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (semnal GPS slab)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (semnal GPS excelent)</string>
<string name="value_integer_feet_recommended">%1$d ft (recomandat)</string>
-9
View File
@@ -340,11 +340,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Макс. точность</string>
<string name="value_adapt_battery_life">Мин. расход батареи</string>
<string name="value_always">Всегда</string>
<string name="value_float_feet">%1$.2f фт</string>
<string name="value_float_kilometer">%1$.2f км</string>
<string name="value_float_meter">%1$.2f м</string>
<string name="value_float_mile">%1$.2f мил</string>
<string name="value_float_mile_poor_gps">%1$.1f мил. (слабый сигнал)</string>
<string name="value_integer_feet">%1$d фт</string>
<string name="value_integer_feet_excellent_gps">%1$d фт (отличный сигнал)</string>
<string name="value_integer_feet_recommended">%1$d фт (рекомендуется)</string>
@@ -569,10 +564,6 @@ limitations under the License.
<string name="track_pace_notification">Темп: %1$s</string>
<string name="track_speed_notification">Скорость: %1$s</string>
<string name="track_distance_notification">Расстояние: %1$s</string>
<string name="value_pace_kilometer">%1$d:%2$02d мин/км</string>
<string name="value_pace_mile">%1$d:%2$02d мин/миль</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_float_kilometer_hour">%1$.2f км/ч</string>
<string name="interval_list_empty_message">Интервалов пока нет</string>
<string name="aggregated_stats_empty_message">Запишите свой первый трек, чтобы увидеть агрегированную статистику</string>
<string name="track_detail_resume_success">Теперь возобновляем путь</string>
-5
View File
@@ -339,11 +339,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Prispôsobiť na presnosť</string>
<string name="value_adapt_battery_life">Prispôsobiť na výdrž batérie</string>
<string name="value_always">Vždy</string>
<string name="value_float_feet">%1$.2f stopy</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi.</string>
<string name="value_float_mile_poor_gps">%1$.1f mi. (slabý signál GPS)</string>
<string name="value_integer_feet">%1$d st.</string>
<string name="value_integer_feet_excellent_gps">%1$d st. (výborný signál GPS)</string>
<string name="value_integer_feet_recommended">%1$d st. (odporúčané)</string>
-5
View File
@@ -341,11 +341,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Prilagodi za natančnost</string>
<string name="value_adapt_battery_life">Prilagodi za življenjsko dobo baterije</string>
<string name="value_always">Vedno</string>
<string name="value_float_feet">%1$.2f čevljev</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (slab signal GPS)</string>
<string name="value_integer_feet">%1$d čevljev</string>
<string name="value_integer_feet_excellent_gps">%1$d čevljev (odličen signal GPS)</string>
<string name="value_integer_feet_recommended">%1$d čevljev (priporočeno)</string>
-5
View File
@@ -339,11 +339,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Прилагоди за прецизност</string>
<string name="value_adapt_battery_life">Прилагоди трајању батерије</string>
<string name="value_always">Увек</string>
<string name="value_float_feet">%1$.2f ст</string>
<string name="value_float_kilometer">%1$.2f км</string>
<string name="value_float_meter">%1$.2f м</string>
<string name="value_float_mile">%1$.2f ми</string>
<string name="value_float_mile_poor_gps">%1$.1f ми (слаб GPS)</string>
<string name="value_integer_feet">%1$d ст</string>
<string name="value_integer_feet_excellent_gps">%1$d ст (одличан GPS)</string>
<string name="value_integer_feet_recommended">%1$d ст (препоручено)</string>
-5
View File
@@ -339,11 +339,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Anpassa för noggrannhet</string>
<string name="value_adapt_battery_life">Anpassa för batterilivslängd</string>
<string name="value_always">Alltid</string>
<string name="value_float_feet">%1$.2f fot</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mile</string>
<string name="value_float_mile_poor_gps">%1$.1f mile (dålig GPS-mottagning)</string>
<string name="value_integer_feet">%1$d fot</string>
<string name="value_integer_feet_excellent_gps">%1$d fot (utmärkt GPS-mottagning)</string>
<string name="value_integer_feet_recommended">%1$d fot (rekommenderas)</string>
-5
View File
@@ -339,11 +339,6 @@ limitations under the License.
<string name="value_adapt_accuracy">ปรับความแม่นยำ</string>
<string name="value_adapt_battery_life">ปรับเพื่อแบตเตอรี่</string>
<string name="value_always">เปิดใช้งานเสมอ</string>
<string name="value_float_feet">%1$.2f ฟุต</string>
<string name="value_float_kilometer">%1$.2f กม.</string>
<string name="value_float_meter">%1$.2f ม.</string>
<string name="value_float_mile">%1$.2f ไมล์</string>
<string name="value_float_mile_poor_gps">%1$.1f ไมล์ (สัญญาณ GPS ไม่ดี)</string>
<string name="value_integer_feet">%1$d ฟุต</string>
<string name="value_integer_feet_excellent_gps">%1$d ฟุต (สัญญาณ GPS ดี)</string>
<string name="value_integer_feet_recommended">%1$d ฟุต (แนะนำ)</string>
-5
View File
@@ -339,11 +339,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Iangkop para sa katumpakan</string>
<string name="value_adapt_battery_life">Iangkop para sa antas ng baterya</string>
<string name="value_always">Palagi</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (mahina ang GPS)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (malinaw na GPS)</string>
<string name="value_integer_feet_recommended">%1$d ft (inirerekomenda)</string>
-5
View File
@@ -340,11 +340,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Doğruluk için uyarla</string>
<string name="value_adapt_battery_life">Pil ömrü için uyarla</string>
<string name="value_always">Her zaman</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mil</string>
<string name="value_float_mile_poor_gps">%1$.1f mil (zayıf GPS)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (mükemmel GPS)</string>
<string name="value_integer_feet_recommended">%1$d ft (önerilir)</string>
-9
View File
@@ -341,11 +341,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Адаптувати для точності</string>
<string name="value_adapt_battery_life">Адаптувати до часу роботи батареї</string>
<string name="value_always">Завжди</string>
<string name="value_float_feet">%1$.2f фт</string>
<string name="value_float_kilometer">%1$.2f км</string>
<string name="value_float_meter">%1$.2f м</string>
<string name="value_float_mile">Миль: %1$.2f</string>
<string name="value_float_mile_poor_gps">Миль: %1$.1f (слабкий сигнал GPS)</string>
<string name="value_integer_feet">%1$d фут</string>
<string name="value_integer_feet_excellent_gps">%1$d фут. (відмінний сигнал GPS)</string>
<string name="value_integer_feet_recommended">%1$d фут. (рекомендовано)</string>
@@ -474,14 +469,11 @@ limitations under the License.
<string name="stats_split_interval">Розділити на</string>
<string name="track_recording_notification_accuracy">Точність місцеположення: %1$s</string>
<string name="track_detail_intervals_tab">Інтервали</string>
<string name="value_pace_mile">%1$d:%2$02d хв/милі</string>
<string name="voice_speed_lap">Швидкість кола %1$s</string>
<string name="voice_pace_lap">Час кола %1$s</string>
<string name="track_detail_record_success">Зараз записується новий трек</string>
<string name="track_detail_resume_success">Відновлюємо запис треку</string>
<string name="interval_list_empty_message">Ще немає інтервалу</string>
<string name="value_float_kilometer_hour">%1$.2f км/г</string>
<string name="value_float_mile_hour">%1$.2f миль/г</string>
<string name="share_image_body">Думаю, вам може бути цікаво це зображення.</string>
<string name="hold_to_pause">Затисніть</string>
<string name="instant_export_enabled_summary">Експорт треку в сховище після завершення запису</string>
@@ -582,7 +574,6 @@ limitations under the License.
<string name="settings_recording_show_on_lockscreen_while_recording_summary">Під час запису показувати статистику без розблокування пристрою.</string>
<string name="stats_loss">Втрачено</string>
<string name="stats_intervals">Інтервали</string>
<string name="value_pace_kilometer">%1$d:%2$02d хв/км</string>
<string name="share_image_subject">Я хотів би поділитися з вами зображенням</string>
<string name="toast_message_instant_track_was_exported">Останній трек експортовано</string>
<string name="settings_default_export_uri_title">Каталог експорту треків</string>
-5
View File
@@ -341,11 +341,6 @@ limitations under the License.
<string name="value_adapt_accuracy">Thích ứng với độ chính xác</string>
<string name="value_adapt_battery_life">Thích ứng với tuổi thọ pin</string>
<string name="value_always">Luôn luôn</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f dặm</string>
<string name="value_float_mile_poor_gps">%1$.1f dặm (tín hiệu GPS xấu)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (tín hiệu GPS tốt)</string>
<string name="value_integer_feet_recommended">%1$d ft (được đề nghị)</string>
-5
View File
@@ -292,11 +292,6 @@
<string name="value_adapt_accuracy">根據精度調整</string>
<string name="value_adapt_battery_life">根據電池壽命調整</string>
<string name="value_always">一律使用</string>
<string name="value_float_feet">%1$.2f 英尺</string>
<string name="value_float_kilometer">%1$.2f 公里</string>
<string name="value_float_meter">%1$.2f 公尺</string>
<string name="value_float_mile">%1$.2f 英里</string>
<string name="value_float_mile_poor_gps">%1$.1f 英里 (GPS 訊號差)</string>
<string name="value_integer_feet">%1$d 英尺</string>
<string name="value_integer_feet_excellent_gps">%1$d 英尺 (GPS 訊號佳)</string>
<string name="value_integer_feet_recommended">%1$d 英尺 (建議值)</string>
-5
View File
@@ -292,11 +292,6 @@
<string name="value_adapt_accuracy">根據精度調整</string>
<string name="value_adapt_battery_life">根據電池壽命調整</string>
<string name="value_always">一律使用</string>
<string name="value_float_feet">%1$.2f 英尺</string>
<string name="value_float_kilometer">%1$.2f 公里</string>
<string name="value_float_meter">%1$.2f 公尺</string>
<string name="value_float_mile">%1$.2f 英里</string>
<string name="value_float_mile_poor_gps">%1$.1f 英里 (GPS 訊號差)</string>
<string name="value_integer_feet">%1$d 英尺</string>
<string name="value_integer_feet_excellent_gps">%1$d 英尺 (GPS 訊號佳)</string>
<string name="value_integer_feet_recommended">%1$d 英尺 (建議值)</string>
-5
View File
@@ -342,11 +342,6 @@ limitations under the License.
<string name="value_adapt_accuracy">适应精度</string>
<string name="value_adapt_battery_life">视电池电量而定</string>
<string name="value_always">一律启用</string>
<string name="value_float_feet">%1$.2f 英尺</string>
<string name="value_float_kilometer">%1$.2f 公里</string>
<string name="value_float_meter">%1$.2f 米</string>
<string name="value_float_mile">%1$.2f 英里</string>
<string name="value_float_mile_poor_gps">%1$.1f 英里(GPS 信号差)</string>
<string name="value_integer_feet">%1$d 英尺</string>
<string name="value_integer_feet_excellent_gps">%1$d 英尺(GPS 信号极佳)</string>
<string name="value_integer_feet_recommended">%1$d 英尺(推荐)</string>
+5
View File
@@ -24,6 +24,11 @@ limitations under the License.
Data provided by <a href="https://geographiclib.sourceforge.io/html/geoid.html">GeographicLib</a>.
</string>
<!-- If the order depends on the language, we might need to make this translatable -->
<string name="distance_with_unit" translatable="false">%1$s %2$s</string>
<string name="speed_with_unit" translatable="false">%1$s %2$s</string>
<string name="time" translatable="false">%1$d:%2$02d</string>
<!-- List here all used libraries (will be shown in the about activity -->
<string name="third_party_libraries" translatable="false">
<a href="https://developer.android.com/topic/libraries/support-library/">Google\'s androidX support</a> (Apache License, Version 2.0) \n
+1 -10
View File
@@ -507,21 +507,14 @@ limitations under the License.
<string name="unit_kilometer_per_hour">km/h</string>
<string name="unit_meter">m</string>
<string name="unit_mile">mi</string>
<string name="unit_mile_per_hour">mi/h</string>
<string name="unit_mile_per_hour">mph</string>
<string name="unit_minute_per_kilometer">min/km</string>
<string name="unit_minute_per_mile">min/mi</string>
<!-- Value -->
<string name="value_adapt_accuracy">Adapt for accuracy</string>
<string name="value_adapt_battery_life">Adapt for battery life</string>
<string name="value_always">Always</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (poor GPS)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (excellent GPS)</string>
<string name="value_integer_feet_recommended">%1$d ft (recommended)</string>
@@ -536,8 +529,6 @@ limitations under the License.
<string name="value_integer_minute">%1$d min</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d s</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="value_none">None</string>
<string name="value_off">Off</string>
<string name="value_smallest">Smallest</string>