forked from upstream-mirrors/OpenTracks
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 91b379c328 | |||
| e28a84fc88 | |||
| c2d8d06204 | |||
| 7ca871c699 | |||
| 337c50eb91 | |||
| 2ff8d21897 | |||
| 2d4e987812 | |||
| fb928ccc45 | |||
| ab8791a620 | |||
| 7c03085761 | |||
| 12a8686896 | |||
| e12bb967e6 | |||
| d56b018676 | |||
| a6fd701004 | |||
| ce26e20571 | |||
| d3ff2061c6 | |||
| aa63474114 | |||
| cf545dc17b | |||
| a542f45661 | |||
| 1eeb706330 | |||
| 01ea65742b | |||
| e9456919cb | |||
| 2a8e1c99b6 | |||
| 245854581b | |||
| e372a780f0 | |||
| 25a2f978c4 | |||
| 36c3885dce | |||
| 00be0b565c | |||
| 8b1e1cf294 | |||
| ce313ba4fd | |||
| df501bde0d | |||
| 30ed8d8ba3 | |||
| ea2127846d | |||
| ac0da5e9d1 | |||
| 47fea690c9 | |||
| a1fa95094f | |||
| c4a1fb0d98 | |||
| 57cd4b3780 | |||
| 5c645712ff | |||
| e724baaafa | |||
| f55dcd7162 | |||
| 74169cb819 | |||
| 1821f47cf1 | |||
| 925a253bbb | |||
| e89ae1c2df | |||
| 75058118e0 | |||
| 96559230f8 | |||
| f16f2cfc64 | |||
| 7f353a5d13 | |||
| 2453edaa65 | |||
| 1b1568511a | |||
| 29a36c3ea7 | |||
| 71d0c7cc92 | |||
| b09d640844 | |||
| a039f1a00c | |||
| 3df5c06c20 | |||
| 2904c65a01 | |||
| 4977789004 | |||
| 95e6448cba | |||
| a66c1b9407 | |||
| 9d55ac261f | |||
| dbd3e2fc5c | |||
| 713e454e44 | |||
| f0616fc043 | |||
| 75ed3120bd | |||
| b22e41cf66 | |||
| d1f003c0ce | |||
| 6ef80ade98 | |||
| e49d9fbd83 |
@@ -8,6 +8,7 @@
|
||||
* Polar H10
|
||||
* Polar OH1
|
||||
Has updatable firmware that requires a user account at polar.com
|
||||
* Polar Loop Gen 2
|
||||
* Wahoo Tickr (Model: WFBTHR02)
|
||||
* Mi Band 3, Amazfit Band 5, Amazfit Bip. These devices are manufactured by Huami, and other Huami devices will very likely work. Theoretically, this sensor must be enabled, but testing reveals that it works even without enabling. For details on how to enable see [Gadgetbridge wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Huami-Heartrate-measurement#bluetooth-heart-rate-sensor)
|
||||
* Amazfit Neo. But first you have to enable "Discoverable" and "Activity heart rate sharing" in the official Zepp app. (after pairing with OpenTracks you can disable them again)
|
||||
|
||||
+6
-5
@@ -6,7 +6,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:9.2.1'
|
||||
classpath 'com.android.tools.build:gradle:9.3.2'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'de.dennisguse.opentracks'
|
||||
versionCode 6682
|
||||
versionName "v4.27.2"
|
||||
versionCode 6751
|
||||
versionName "v4.28.3"
|
||||
|
||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||
|
||||
@@ -145,17 +145,18 @@ android {
|
||||
dependencies {
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.7.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.8.0'
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
implementation 'androidx.documentfile:documentfile:1.1.0'
|
||||
implementation 'androidx.gridlayout:gridlayout:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.14.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.2'
|
||||
implementation 'androidx.core:core:1.19.0'
|
||||
implementation 'androidx.core:core-splashscreen:1.2.0'
|
||||
implementation 'androidx.mediarouter:mediarouter:1.8.1'
|
||||
implementation 'androidx.core:core-location-altitude:1.0.0'
|
||||
implementation 'androidx.work:work-runtime:2.11.2'
|
||||
implementation 'androidx.health.connect:connect-client:1.1.0'
|
||||
|
||||
androidTestImplementation 'androidx.test:core:1.7.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
v4.28.0: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Support for exporting to Health Connect
|
||||
|
||||
Bugfix:
|
||||
- Dashboard API: when sharing multiple tracks, the currently recorded one wasn't updated
|
||||
- Configuration setting for announcement of lap power wasn't stored correctly (only some languages affected)
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
v4.28.1: OpenTracks
|
||||
|
||||
Changes:
|
||||
- HealthConnect: sending total distance, speed and elevation gain
|
||||
|
||||
Bugfix:
|
||||
- Gravel activity was not selectable
|
||||
|
||||
Developer:
|
||||
- Cleanup ContentProvider URLs
|
||||
@@ -0,0 +1,7 @@
|
||||
v4.28.2: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Import: ignore GPX waypoints without time
|
||||
|
||||
Bugfix:
|
||||
- Only start GPS once
|
||||
@@ -0,0 +1,10 @@
|
||||
v4.28.3: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Settings: allow to disable segment creation (max recording distance)
|
||||
- Importer: match activity type case-insensitive
|
||||
- GPX: export moving speed in summary
|
||||
|
||||
Bugfix:
|
||||
- GPX: importer must respect namespace prefixes
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
v3.1.0: OpenTracks
|
||||
|
||||
Cambios:
|
||||
- Se agregó la capacidad de mostrar rutas en la aplicación de mapas (probado con OsmAnd y Maps.ME).
|
||||
- Se ha añadido la posibilidad de visualizar las estadísticas de seguimiento sin desbloquear el dispositivo durante el mismo.
|
||||
- Se ha eliminado el modo horizontal de la vista de detalles de la pista (debido a un error).
|
||||
- El historial de sugerencias de búsqueda ha sido eliminado.
|
||||
|
||||
Corrección de errores:
|
||||
- Solicitar permisos de almacenamiento para todas las importaciones/todas las exportaciones
|
||||
|
||||
Desarrolladores:
|
||||
- Actualizar a Gradle 5.6
|
||||
- No minimice la versión de lanzamiento
|
||||
@@ -0,0 +1,16 @@
|
||||
v3.2.0: OpenTracks
|
||||
|
||||
Cambios:
|
||||
- Se ha eliminado el widget
|
||||
- Se han incorporado iconos de Material Design
|
||||
- Se han eliminado el snowboard y el esquí (se necesitan nuevos iconos)
|
||||
|
||||
Corrección de errores:
|
||||
- Se ha corregido la funcionalidad de búsqueda
|
||||
|
||||
Desarrollador:
|
||||
- Se han corregido (algunos) casos de prueba
|
||||
- Se ha eliminado la funcionalidad «parcelable» en desuso
|
||||
- Limpieza y reformateo a fondo
|
||||
- No se utiliza la difusión para la comunicación entre la aplicación y el widget
|
||||
- El archivo stats_content.xml no incluye otros archivos
|
||||
@@ -1,11 +1,22 @@
|
||||
OpenTracks é um aplicativo de rastreamento de esportes que respeita totalmente a sua privacidade.
|
||||
Um companheiro de rastreamento esportivo que respeita sua privacidade.
|
||||
|
||||
Características:
|
||||
* Rastreamento de esportes: monitore seu esporte e atividades ao ar livre
|
||||
* Fotos e marcadores: marque locais interessantes durante o rastreamento
|
||||
* Ganho e perda de altitude: via sensor barométrico
|
||||
* Altitude mostrada no EGM2008 (acima do nível médio do mar); exportado como WGS84
|
||||
* Anúncios de voz
|
||||
* Suporta sensores Bluetooth LE: frequência cardíaca, velocidade e distância (ciclismo), cadência (ciclismo) e medidor de potência (ciclismo)
|
||||
* Exportar dados: exporte trilhas como KMZ (incluindo fotos), KML, ou GPX
|
||||
* Sem acesso à Internet: a Internet não é usada
|
||||
Esportes e atividades ao ar livre garantem felicidade, habilidades e confiança.
|
||||
|
||||
Valoriza sua saúde acompanhando os seus treinos.
|
||||
Grava enquanto você corre ou caminha e te entrega um computador de bicicleta com uma tela maior para o ciclismo.
|
||||
Marca locais interessantes durante o percurso com fotos.
|
||||
Deixa estatísticas registradas em grande detalhe para analises.
|
||||
Compartilha apenas os dados que você quer que outros tenham.
|
||||
|
||||
* Anúncios por voz.
|
||||
* Suporte para sensores Bluetooth LE: frequência cardíaca, velocidade e distância (ciclismo), cadência (ciclismo) e medição de potência (ciclismo).
|
||||
* Ganhos e perdas de altitude: via sensor barométrico.
|
||||
* Altitudes exibidas em EGM2008 (acima do nível médio do mar); exportado como WGS84.
|
||||
* Exporta os dados de rastreio como KMZ (inclusive fotos), KML ou GPX.
|
||||
* Sem acesso à internet ou permissões extra.
|
||||
* Tema claro e escuro, respeitando as configurações do sistema.
|
||||
* Sem propagandas.
|
||||
|
||||
Software Livre / Código Aberto
|
||||
Significa que você pode usar, estudar, mudar e compartilhar o código.
|
||||
Licença Apache 2.0
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -5,10 +5,11 @@ import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static de.dennisguse.opentracks.util.EspressoUtils.performLongClickOnAncestor;
|
||||
import static de.dennisguse.opentracks.util.EspressoUtils.selectTabAtIndex;
|
||||
import static de.dennisguse.opentracks.util.EspressoUtils.waitUntilDisplayed;
|
||||
import static de.dennisguse.opentracks.util.EspressoUtils.waitForResumedViewCondition;
|
||||
import static de.dennisguse.opentracks.util.EspressoUtils.waitUntilDisplayed;
|
||||
import static de.dennisguse.opentracks.util.EspressoUtils.withSelectedTab;
|
||||
import static de.dennisguse.opentracks.util.EspressoUtils.withViewPagerCurrentItem;
|
||||
import static de.dennisguse.opentracks.util.TestEnvironmentUtils.resetTrackRecordingServiceAndDeleteTracks;
|
||||
@@ -16,7 +17,6 @@ import static de.dennisguse.opentracks.util.TrackUiTestUtils.finishStoppedTrack;
|
||||
import static de.dennisguse.opentracks.util.TrackUiTestUtils.resumeStoppedTrack;
|
||||
import static de.dennisguse.opentracks.util.TrackUiTestUtils.startRecordingFromTrackList;
|
||||
import static de.dennisguse.opentracks.util.TrackUiTestUtils.stopRecordingToTrackStopped;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
@@ -27,7 +27,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.rule.GrantPermissionRule;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
+3
-3
@@ -227,13 +227,13 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
private void assertCount(int trackCount, int trackPointCount, int markerCount) {
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
try (Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID)) {
|
||||
try (Cursor tracksCursor = contentResolver.query(CustomContentProvider.UrlType.TRACKS.getUri(), null, null, null, TracksColumns._ID)) {
|
||||
assertEquals(trackCount, tracksCursor.getCount());
|
||||
}
|
||||
try (Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID)) {
|
||||
try (Cursor tracksPointsCursor = contentResolver.query(CustomContentProvider.UrlType.TRACKPOINTS_BY_ID.getUri(), null, null, null, TrackPointsColumns._ID)) {
|
||||
assertEquals(trackPointCount, tracksPointsCursor.getCount());
|
||||
}
|
||||
try (Cursor markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID)) {
|
||||
try (Cursor markerCursor = contentResolver.query(CustomContentProvider.UrlType.MARKERS.getUri(), null, null, null, MarkerColumns._ID)) {
|
||||
assertEquals(markerCount, markerCursor.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ActivityTypeTest {
|
||||
|
||||
@Test
|
||||
public void findBy_id() {
|
||||
assertEquals(ActivityType.TRAIL_RUNNING, ActivityType.findBy("trail running"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_idOfEveryActivityType() {
|
||||
for (ActivityType activityType : ActivityType.values()) {
|
||||
assertEquals(activityType, ActivityType.findBy(activityType.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_synonymsOfEveryActivityType() {
|
||||
for (ActivityType activityType : ActivityType.values()) {
|
||||
for (String synonym : activityType.synonyms) {
|
||||
assertEquals(activityType, ActivityType.findBy(synonym));
|
||||
assertEquals(activityType, ActivityType.findBy(synonym.toUpperCase(Locale.ROOT).replace(' ', '_')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_ignoresCase() {
|
||||
assertEquals(ActivityType.RUNNING, ActivityType.findBy("RUNNING"));
|
||||
assertEquals(ActivityType.ATV, ActivityType.findBy("atv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_ignoresSeparators() {
|
||||
assertEquals(ActivityType.TRAIL_RUNNING, ActivityType.findBy("TRAIL_RUNNING"));
|
||||
assertEquals(ActivityType.MOUNTAIN_BIKING, ActivityType.findBy("mountain-biking"));
|
||||
assertEquals(ActivityType.CROSS_COUNTRY_SKIING, ActivityType.findBy("cross_country_skiing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_ignoresSurroundingAndRepeatedWhitespace() {
|
||||
assertEquals(ActivityType.MOUNTAIN_BIKING, ActivityType.findBy(" Mountain Biking "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_synonym() {
|
||||
assertEquals(ActivityType.RUNNING, ActivityType.findBy("treadmill"));
|
||||
assertEquals(ActivityType.TRAIL_RUNNING, ActivityType.findBy("TRAIL_RUN"));
|
||||
assertEquals(ActivityType.MOUNTAIN_BIKING, ActivityType.findBy("MOUNTAIN_BIKE"));
|
||||
assertEquals(ActivityType.SWIMMING_OPEN, ActivityType.findBy("SWIMMING_OPENWATER"));
|
||||
assertEquals(ActivityType.BIKING, ActivityType.findBy("bike"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_unknown() {
|
||||
assertEquals(ActivityType.UNKNOWN, ActivityType.findBy("hovercraft"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_null() {
|
||||
assertEquals(ActivityType.UNKNOWN, ActivityType.findBy(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_blank() {
|
||||
assertEquals(ActivityType.UNKNOWN, ActivityType.findBy(" "));
|
||||
}
|
||||
}
|
||||
+180
-2
@@ -120,6 +120,184 @@ public class GPXTrackImporterTest {
|
||||
), importedTrackPoints);
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
public void gpx_missing_time() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx11_missing_time);
|
||||
|
||||
// when
|
||||
// 1. import
|
||||
importTrackId = importer.importFile(inputStream).get(0);
|
||||
|
||||
// then
|
||||
// 2. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals("", importedTrack.activityTypeLocalized());
|
||||
assertEquals("", importedTrack.description());
|
||||
assertEquals("20210907_213924.gpx", importedTrack.name());
|
||||
assertEquals(ActivityType.UNKNOWN, importedTrack.activityType());
|
||||
|
||||
// 3. trackstatistics
|
||||
Statistics trackStatistics = importedTrack.statistics();
|
||||
assertEquals(0, trackStatistics.maxSpeed().toMPS(), 0.01);
|
||||
assertEquals(Duration.ofSeconds(0), trackStatistics.movingDuration());
|
||||
|
||||
// 4. trackpoints
|
||||
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||
assertEquals(1, importedTrackPoints.size());
|
||||
|
||||
TrackPointAssert a = new TrackPointAssert();
|
||||
a.assertEquals(List.of(
|
||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
|
||||
new Position(
|
||||
Instant.parse("2021-09-07T22:12:00Z"),
|
||||
30.14185982, -40.3863038, null,
|
||||
Altitude.WGS84.of(-5), null,
|
||||
null,
|
||||
null))
|
||||
), importedTrackPoints);
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
public void gpx_with_power_pwd() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_with_power_pwr);
|
||||
|
||||
// when
|
||||
// 1. import
|
||||
importTrackId = importer.importFile(inputStream).get(0);
|
||||
|
||||
// then
|
||||
// 2. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals("", importedTrack.activityTypeLocalized());
|
||||
assertEquals("", importedTrack.description());
|
||||
assertEquals("gpx with power", importedTrack.name());
|
||||
assertEquals(ActivityType.UNKNOWN, importedTrack.activityType());
|
||||
|
||||
// 3. trackpoints
|
||||
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||
assertEquals(3, importedTrackPoints.size());
|
||||
|
||||
TrackPointAssert a = new TrackPointAssert();
|
||||
a.assertEquals(List.of(
|
||||
new TrackPoint(null, TrackPoint.Type.SEGMENT_START_AUTOMATIC,
|
||||
new Position(
|
||||
Instant.parse("2021-09-07T22:10:19Z"),
|
||||
30.14185982, -40.3863038, null,
|
||||
Altitude.WGS84.of(-5), null,
|
||||
null,
|
||||
null),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new Power(100f),
|
||||
null
|
||||
),
|
||||
new TrackPoint(null, TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2021-09-07T22:11:07Z"),
|
||||
30.14184657, -40.38670089, null,
|
||||
Altitude.WGS84.of(-5), null,
|
||||
null,
|
||||
Speed.of(0.7976524233818054)),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new Power(110f),
|
||||
null),
|
||||
new TrackPoint(null, TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2021-09-07T22:12:00Z"),
|
||||
30.14185982, -40.3863038, null,
|
||||
Altitude.WGS84.of(-5), null,
|
||||
null,
|
||||
Speed.of(0.7224021553993225)),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new Power(150f),
|
||||
null)
|
||||
), importedTrackPoints);
|
||||
}
|
||||
@LargeTest
|
||||
@Test
|
||||
public void gpx_with_power_gpxpx() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_with_power_gpxpx);
|
||||
|
||||
// when
|
||||
// 1. import
|
||||
importTrackId = importer.importFile(inputStream).get(0);
|
||||
|
||||
// then
|
||||
// 2. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals("", importedTrack.activityTypeLocalized());
|
||||
assertEquals("", importedTrack.description());
|
||||
assertEquals("gpx with power", importedTrack.name());
|
||||
assertEquals(ActivityType.UNKNOWN, importedTrack.activityType());
|
||||
|
||||
// 3. trackpoints
|
||||
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||
assertEquals(3, importedTrackPoints.size());
|
||||
|
||||
TrackPointAssert a = new TrackPointAssert();
|
||||
a.assertEquals(List.of(
|
||||
new TrackPoint(null, TrackPoint.Type.SEGMENT_START_AUTOMATIC,
|
||||
new Position(
|
||||
Instant.parse("2021-09-07T22:10:19Z"),
|
||||
30.14185982, -40.3863038, null,
|
||||
Altitude.WGS84.of(-5), null,
|
||||
null,
|
||||
null),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new Power(100f),
|
||||
null
|
||||
),
|
||||
new TrackPoint(null, TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2021-09-07T22:11:07Z"),
|
||||
30.14184657, -40.38670089, null,
|
||||
Altitude.WGS84.of(-5), null,
|
||||
null,
|
||||
Speed.of(0.7976524233818054)),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new Power(110f),
|
||||
null),
|
||||
new TrackPoint(null, TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2021-09-07T22:12:00Z"),
|
||||
30.14185982, -40.3863038, null,
|
||||
Altitude.WGS84.of(-5), null,
|
||||
null,
|
||||
Speed.of(0.7224021553993225)),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new Power(150f),
|
||||
null)
|
||||
), importedTrackPoints);
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
public void gpx_speed_no_namespace() throws IOException {
|
||||
@@ -285,8 +463,8 @@ public class GPXTrackImporterTest {
|
||||
public void importExportTest_timezone() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone);
|
||||
try (InputStream inputStreamExpected = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone)) {
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx11_timezone);
|
||||
try (InputStream inputStreamExpected = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx11_timezone)) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
||||
// when
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
@@ -91,6 +92,7 @@ public class TrackRecordingServiceNotificationManagerTest {
|
||||
setSmallIcon(R.drawable.ic_logo_color_24dp);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public NotificationCompat.Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
|
||||
onlyAlertOnceValues.add(onlyAlertOnce);
|
||||
|
||||
+5
-5
@@ -63,8 +63,8 @@ public class RecordingLayoutTest extends TestCase {
|
||||
RecordingLayout recordingLayout = RecordingLayoutIO.fromCsvLine(csv1, resources);
|
||||
|
||||
// then layout and data fields are built correctly
|
||||
assertEquals(recordingLayout.getName(), "Default Layout");
|
||||
assertEquals(recordingLayout.getColumnsPerRow(), 2);
|
||||
assertEquals("Default Layout", recordingLayout.getName());
|
||||
assertEquals(2, recordingLayout.getColumnsPerRow());
|
||||
assertEquals(PreferencesUtils.getDefaultLayout().getFields(), recordingLayout.getFields());
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ public class RecordingLayoutTest extends TestCase {
|
||||
List<DataField> dataFieldList = recordingLayout.getFields();
|
||||
|
||||
// then layout and data fields are built correctly
|
||||
assertEquals(recordingLayout.getName(), "Default Layout");
|
||||
assertEquals(recordingLayout.getColumnsPerRow(), 2);
|
||||
assertEquals("Default Layout", recordingLayout.getName());
|
||||
assertEquals(2, recordingLayout.getColumnsPerRow());
|
||||
assertEquals(PreferencesUtils.getDefaultLayout().getFields(), recordingLayout.getFields());
|
||||
}
|
||||
|
||||
@@ -144,6 +144,6 @@ public class RecordingLayoutTest extends TestCase {
|
||||
String csv = recordingLayout.toCsv();
|
||||
|
||||
// then csv is well built
|
||||
assertEquals(csv, "Test Layout;2;key1,0,0,0;key2,0,1,0;key3,1,0,0;key4,1,1,0;key5,1,1,1;");
|
||||
assertEquals("Test Layout;2;key1,0,0,0;key2,0,1,0;key3,1,0,0;key4,1,1,0;key5,1,1,1;", csv);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
|
||||
@@ -33,7 +34,7 @@ public final class ActivityTestUtils {
|
||||
|
||||
Application.ActivityLifecycleCallbacks callbacks = new Application.ActivityLifecycleCallbacks() {
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
public void onActivityResumed(@NonNull Activity activity) {
|
||||
if (activityClass.isInstance(activity)) {
|
||||
resumedActivityRef.set(activityClass.cast(activity));
|
||||
latch.countDown();
|
||||
@@ -41,27 +42,27 @@ public final class ActivityTestUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
public void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStarted(Activity activity) {
|
||||
public void onActivityStarted(@NonNull Activity activity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
public void onActivityPaused(@NonNull Activity activity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
public void onActivityStopped(@NonNull Activity activity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
|
||||
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
public void onActivityDestroyed(@NonNull Activity activity) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package de.dennisguse.opentracks.util;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.SystemClock;
|
||||
@@ -14,11 +14,11 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.test.espresso.PerformException;
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.espresso.util.HumanReadables;
|
||||
import androidx.test.espresso.util.TreeIterables;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
import androidx.test.espresso.util.HumanReadables;
|
||||
import androidx.test.espresso.util.TreeIterables;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
@@ -33,8 +33,6 @@ import java.util.function.Predicate;
|
||||
|
||||
public class EspressoUtils {
|
||||
|
||||
private static final long VIEW_POLLING_INTERVAL_MS = 50;
|
||||
|
||||
public static Matcher<View> withRecyclerViewItemCount(final int count) {
|
||||
return new TypeSafeMatcher<>() {
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||
<gpx version="1.1" creator="Cruiser" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
|
||||
<trk>
|
||||
<name>20210907_213924.gpx</name>
|
||||
<trkseg>
|
||||
<trkpt lat="30.14185982" lon="-40.3863038">
|
||||
<ele>-5</ele>
|
||||
<hdop>4</hdop>
|
||||
</trkpt>
|
||||
<trkpt lat="30.14184657" lon="-40.38670089">
|
||||
<ele>-5</ele>
|
||||
<time/>
|
||||
<hdop>4</hdop>
|
||||
</trkpt>
|
||||
<trkpt lat="30.14185982" lon="-40.3863038">
|
||||
<ele>-5</ele>
|
||||
<time>2021-09-07T22:12:00Z</time>
|
||||
<hdop>4</hdop>
|
||||
</trkpt>
|
||||
</trkseg>
|
||||
</trk>
|
||||
</gpx>
|
||||
+2
-1
@@ -28,10 +28,11 @@ xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/
|
||||
<opentracks:typeTranslated><![CDATA[unknown]]></opentracks:typeTranslated>
|
||||
<gpxtrkx:TrackStatsExtension>
|
||||
<gpxtrkx:Distance>0.0</gpxtrkx:Distance>
|
||||
<gpxtrkx:TimerTime>0</gpxtrkx:TimerTime>
|
||||
<gpxtrkx:TotalElapsedTime>0</gpxtrkx:TotalElapsedTime>
|
||||
<gpxtrkx:MovingTime>0</gpxtrkx:MovingTime>
|
||||
<gpxtrkx:StoppedTime>0</gpxtrkx:StoppedTime>
|
||||
<gpxtrkx:MaxSpeed>0.0</gpxtrkx:MaxSpeed>
|
||||
<gpxtrkx:MovingSpeed>0.0</gpxtrkx:MovingSpeed>
|
||||
</gpxtrkx:TrackStatsExtension>
|
||||
</extensions>
|
||||
<trkseg>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||
<gpx version="1.1" creator="Cruiser" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gpxpx="http://www.garmin.com/xmlschemas/PowerExtension/v1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
|
||||
<trk>
|
||||
<name>gpx with power</name>
|
||||
<trkseg>
|
||||
<trkpt lat="30.14185982" lon="-40.3863038">
|
||||
<ele>-5</ele>
|
||||
<time>2021-09-07T22:10:19Z</time>
|
||||
<hdop>4</hdop>
|
||||
<extensions>
|
||||
<gpxpx:PowerInWatts>100</gpxpx:PowerInWatts>
|
||||
</extensions>
|
||||
</trkpt>
|
||||
<trkpt lat="30.14184657" lon="-40.38670089">
|
||||
<ele>-5</ele>
|
||||
<time>2021-09-07T22:11:07Z</time>
|
||||
<hdop>4</hdop>
|
||||
<extensions>
|
||||
<gpxpx:PowerInWatts>110</gpxpx:PowerInWatts>
|
||||
</extensions>
|
||||
</trkpt>
|
||||
<trkpt lat="30.14185982" lon="-40.3863038">
|
||||
<ele>-5</ele>
|
||||
<time>2021-09-07T22:12:00Z</time>
|
||||
<hdop>4</hdop>
|
||||
<extensions>
|
||||
<gpxpx:PowerInWatts>150</gpxpx:PowerInWatts>
|
||||
</extensions>
|
||||
</trkpt>
|
||||
</trkseg>
|
||||
</trk>
|
||||
</gpx>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||
<gpx version="1.1" creator="Cruiser" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pwr="http://www.garmin.com/xmlschemas/PowerExtension/v1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
|
||||
<trk>
|
||||
<name>gpx with power</name>
|
||||
<trkseg>
|
||||
<trkpt lat="30.14185982" lon="-40.3863038">
|
||||
<ele>-5</ele>
|
||||
<time>2021-09-07T22:10:19Z</time>
|
||||
<hdop>4</hdop>
|
||||
<extensions>
|
||||
<pwr:PowerInWatts>100</pwr:PowerInWatts>
|
||||
</extensions>
|
||||
</trkpt>
|
||||
<trkpt lat="30.14184657" lon="-40.38670089">
|
||||
<ele>-5</ele>
|
||||
<time>2021-09-07T22:11:07Z</time>
|
||||
<hdop>4</hdop>
|
||||
<extensions>
|
||||
<pwr:PowerInWatts>110</pwr:PowerInWatts>
|
||||
</extensions>
|
||||
</trkpt>
|
||||
<trkpt lat="30.14185982" lon="-40.3863038">
|
||||
<ele>-5</ele>
|
||||
<time>2021-09-07T22:12:00Z</time>
|
||||
<hdop>4</hdop>
|
||||
<extensions>
|
||||
<pwr:PowerInWatts>150</pwr:PowerInWatts>
|
||||
</extensions>
|
||||
</trkpt>
|
||||
</trkseg>
|
||||
</trk>
|
||||
</gpx>
|
||||
@@ -69,6 +69,12 @@ limitations under the License.
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"
|
||||
android:minSdkVersion="33" />
|
||||
|
||||
<uses-permission android:name="android.permission.health.WRITE_EXERCISE" />
|
||||
<uses-permission android:name="android.permission.health.WRITE_EXERCISE_ROUTE" />
|
||||
<uses-permission android:name="android.permission.health.WRITE_DISTANCE" />
|
||||
<uses-permission android:name="android.permission.health.WRITE_ELEVATION_GAINED" />
|
||||
<uses-permission android:name="android.permission.health.WRITE_SPEED" />
|
||||
|
||||
<application
|
||||
android:name=".Startup"
|
||||
android:allowBackup="true"
|
||||
@@ -126,9 +132,32 @@ limitations under the License.
|
||||
|
||||
<activity android:name=".AboutActivity" />
|
||||
|
||||
<!-- Permissions -->
|
||||
<!-- until Android 13 -->
|
||||
<activity
|
||||
android:name=".HelpActivity"
|
||||
android:label="@string/menu_help" />
|
||||
android:name=".HealthConnectPermissionsRationaleActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- for Android 14 -->
|
||||
<activity-alias
|
||||
android:name="ViewPermissionUsageActivity"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.START_VIEW_PERMISSION_USAGE"
|
||||
android:targetActivity=".HealthConnectPermissionsRationaleActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW_PERMISSION_USAGE" />
|
||||
<category android:name="android.intent.category.HEALTH_PERMISSIONS" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity android:name=".settings.HealthConnect$Settings" />
|
||||
<activity android:name=".settings.HealthConnect$ConfigurePermissions" />
|
||||
<activity android:name=".settings.HealthConnect$ExportAll" />
|
||||
|
||||
<activity android:name=".HelpActivity" />
|
||||
|
||||
<activity android:name=".io.file.importer.DirectoryChooserActivity$ImportDirectoryChooserActivity" />
|
||||
|
||||
@@ -410,5 +439,6 @@ limitations under the License.
|
||||
<intent>
|
||||
<action android:name="android.intent.action.TTS_SERVICE" />
|
||||
</intent>
|
||||
<package android:name="com.google.android.apps.healthdata" />
|
||||
</queries>
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.dennisguse.opentracks;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import de.dennisguse.opentracks.databinding.ActivityHealthConnectPermissionsRationaleBinding;
|
||||
|
||||
public class HealthConnectPermissionsRationaleActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
ActivityHealthConnectPermissionsRationaleBinding viewBinding = ActivityHealthConnectPermissionsRationaleBinding.inflate(getLayoutInflater());
|
||||
setSupportActionBar(viewBinding.healthConnectActivityToolbar);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
setContentView(viewBinding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
getOnBackPressedDispatcher().onBackPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -367,7 +367,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
}
|
||||
|
||||
if (itemId == R.id.list_context_menu_show_on_map) {
|
||||
DataProvider.showTrackOnMap(this, false, trackIds);
|
||||
DataProvider.showTrackOnMap(this, recordingStatus.isRecording(), trackIds);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import de.dennisguse.opentracks.data.models.TrackBuilder;
|
||||
import de.dennisguse.opentracks.databinding.TrackStoppedBinding;
|
||||
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
||||
import de.dennisguse.opentracks.io.file.exporter.ExportUtils;
|
||||
import de.dennisguse.opentracks.io.healthconnect.exporter.HealthConnectUtils;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.ui.aggregatedStatistics.ConfirmDeleteDialogFragment;
|
||||
@@ -93,6 +94,7 @@ public class TrackStoppedActivity extends AbstractTrackDeleteActivity implements
|
||||
viewBinding.finishButton.setOnClickListener(v -> {
|
||||
storeTrackMetaData(contentProviderUtils, track);
|
||||
ExportUtils.postWorkoutExport(this, trackId);
|
||||
HealthConnectUtils.postExportTrack(this, trackId);
|
||||
finish();
|
||||
});
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -131,7 +132,7 @@ public class ContentProviderUtils {
|
||||
@VisibleForTesting
|
||||
public void deleteAllTracks(Context context) {
|
||||
// Delete tracks last since it triggers a database vacuum call
|
||||
contentResolver.delete(TracksColumns.CONTENT_URI, null, null);
|
||||
contentResolver.delete(CustomContentProvider.UrlType.TRACKS.getUri(), null, null);
|
||||
|
||||
File dir = FileUtils.getPhotoDir(context);
|
||||
FileUtils.deleteDirectoryRecurse(dir);
|
||||
@@ -144,13 +145,13 @@ public class ContentProviderUtils {
|
||||
}
|
||||
|
||||
String whereClause = String.format(TracksColumns._ID + " IN (%s)", TextUtils.join(",", Collections.nCopies(trackIds.size(), "?")));
|
||||
contentResolver.delete(TracksColumns.CONTENT_URI, whereClause, trackIds.stream().map(trackId -> Long.toString(trackId.id())).toArray(String[]::new));
|
||||
contentResolver.delete(CustomContentProvider.UrlType.TRACKS.getUri(), whereClause, trackIds.stream().map(trackId -> Long.toString(trackId.id())).toArray(String[]::new));
|
||||
}
|
||||
|
||||
public void deleteTrack(Context context, @NonNull Track.Id trackId) {
|
||||
// Delete track folder resources.
|
||||
FileUtils.deleteDirectoryRecurse(FileUtils.getPhotoDir(context, trackId));
|
||||
contentResolver.delete(TracksColumns.CONTENT_URI, TracksColumns._ID + "=?", new String[]{Long.toString(trackId.id())});
|
||||
contentResolver.delete(CustomContentProvider.UrlType.TRACKS.getUri(), TracksColumns._ID + "=?", new String[]{Long.toString(trackId.id())});
|
||||
}
|
||||
|
||||
//TODO Only use for tests; also move to tests.
|
||||
@@ -194,7 +195,7 @@ public class ContentProviderUtils {
|
||||
selectionArgs = new String[]{"%" + searchQuery + "%", "%" + searchQuery + "%", "%" + searchQuery + "%"};
|
||||
}
|
||||
|
||||
return new TrackListIterator(contentResolver.query(TracksColumns.CONTENT_URI, PROJECTION, selection, selectionArgs, sortOrder));
|
||||
return new TrackListIterator(contentResolver.query(CustomContentProvider.UrlType.TRACKS.getUri(), PROJECTION, selection, selectionArgs, sortOrder));
|
||||
}
|
||||
|
||||
public Track getTrack(@NonNull Track.Id trackId) {
|
||||
@@ -225,7 +226,7 @@ public class ContentProviderUtils {
|
||||
* @param sortOrder the sort order. Can be null
|
||||
*/
|
||||
Cursor getTrackCursor(String selection, String[] selectionArgs, String sortOrder) {
|
||||
return contentResolver.query(TracksColumns.CONTENT_URI, null, selection, selectionArgs, sortOrder);
|
||||
return contentResolver.query(CustomContentProvider.UrlType.TRACKS.getUri(), null, selection, selectionArgs, sortOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,7 +238,7 @@ public class ContentProviderUtils {
|
||||
*/
|
||||
public Track.Id insertTrack(Track track) {
|
||||
//TODO Unset trackId
|
||||
Uri uri = contentResolver.insert(TracksColumns.CONTENT_URI, createContentValues(track));
|
||||
Uri uri = contentResolver.insert(CustomContentProvider.UrlType.TRACKS.getUri(), createContentValues(track));
|
||||
return new Track.Id(ContentUris.parseId(uri));
|
||||
}
|
||||
|
||||
@@ -248,7 +249,7 @@ public class ContentProviderUtils {
|
||||
* @param track the track
|
||||
*/
|
||||
public void updateTrack(Track track) {
|
||||
contentResolver.update(TracksColumns.CONTENT_URI, createContentValues(track), TracksColumns._ID + "=?", new String[]{Long.toString(track.id().id())});
|
||||
contentResolver.update(CustomContentProvider.UrlType.TRACKS.getUri(), createContentValues(track), TracksColumns._ID + "=?", new String[]{Long.toString(track.id().id())});
|
||||
}
|
||||
|
||||
private ContentValues createContentValues(Track track) {
|
||||
@@ -270,7 +271,7 @@ public class ContentProviderUtils {
|
||||
}
|
||||
|
||||
public void updateTrackStatistics(@NonNull Track.Id trackId, @NonNull Statistics trackStatistics) {
|
||||
contentResolver.update(TracksColumns.CONTENT_URI, createContentValues(trackStatistics), TracksColumns._ID + "=?", new String[]{Long.toString(trackId.id())});
|
||||
contentResolver.update(CustomContentProvider.UrlType.TRACKS.getUri(), createContentValues(trackStatistics), TracksColumns._ID + "=?", new String[]{Long.toString(trackId.id())});
|
||||
}
|
||||
|
||||
private ContentValues createContentValues(Statistics trackStatistics) {
|
||||
@@ -362,7 +363,7 @@ public class ContentProviderUtils {
|
||||
public void deleteMarker(Context context, Marker.Id markerId) {
|
||||
final Marker marker = getMarker(markerId);
|
||||
deleteMarkerPhoto(context, marker);
|
||||
contentResolver.delete(MarkerColumns.CONTENT_URI, MarkerColumns._ID + "=?", new String[]{Long.toString(markerId.id())});
|
||||
contentResolver.delete(CustomContentProvider.UrlType.MARKERS.getUri(), MarkerColumns._ID + "=?", new String[]{Long.toString(markerId.id())});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -422,7 +423,7 @@ public class ContentProviderUtils {
|
||||
if (updateMarker.photoUrl() == null) {
|
||||
deleteMarkerPhoto(context, savedMarker);
|
||||
}
|
||||
int rows = contentResolver.update(MarkerColumns.CONTENT_URI, createContentValues(updateMarker, updateMarker.trackId()), MarkerColumns._ID + "=?", new String[]{Long.toString(updateMarker.id().id())});
|
||||
int rows = contentResolver.update(CustomContentProvider.UrlType.MARKERS.getUri(), createContentValues(updateMarker, updateMarker.trackId()), MarkerColumns._ID + "=?", new String[]{Long.toString(updateMarker.id().id())});
|
||||
return rows == 1;
|
||||
}
|
||||
|
||||
@@ -430,7 +431,7 @@ public class ContentProviderUtils {
|
||||
assert marker.id() == null;
|
||||
assert marker.trackId() != null;
|
||||
|
||||
Uri uri = contentResolver.insert(MarkerColumns.CONTENT_URI, createContentValues(marker, marker.trackId()));
|
||||
Uri uri = contentResolver.insert(CustomContentProvider.UrlType.MARKERS.getUri(), createContentValues(marker, marker.trackId()));
|
||||
return new Marker.Id(ContentUris.parseId(uri));
|
||||
}
|
||||
|
||||
@@ -491,7 +492,7 @@ public class ContentProviderUtils {
|
||||
if (maxCount >= 0) {
|
||||
sortOrder += " LIMIT " + maxCount;
|
||||
}
|
||||
return contentResolver.query(MarkerColumns.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
|
||||
return contentResolver.query(CustomContentProvider.UrlType.MARKERS.getUri(), projection, selection, selectionArgs, sortOrder);
|
||||
}
|
||||
|
||||
public MarkerIterator searchMarkers(Track.Id trackId, String query) {
|
||||
@@ -509,7 +510,7 @@ public class ContentProviderUtils {
|
||||
MarkerColumns.DESCRIPTION + " LIKE ? OR " +
|
||||
MarkerColumns.TYPE_LOCALIZED + " LIKE ?";
|
||||
selectionArgs = new String[]{"%" + query + "%", "%" + query + "%", "%" + query + "%"};
|
||||
sortOrder = MarkerColumns.DEFAULT_SORT_ORDER + " DESC";
|
||||
sortOrder = BaseColumns._ID + " DESC";
|
||||
}
|
||||
|
||||
return new MarkerIterator(this, getMarkerCursor(null, selection, selectionArgs, sortOrder, -1));
|
||||
@@ -567,7 +568,7 @@ public class ContentProviderUtils {
|
||||
for (int i = 0; i < trackPoints.size(); i++) {
|
||||
values[i] = createContentValues(trackPoints.get(i), trackId);
|
||||
}
|
||||
return contentResolver.bulkInsert(TrackPointsColumns.CONTENT_URI_BY_ID, values);
|
||||
return contentResolver.bulkInsert(CustomContentProvider.UrlType.TRACKPOINTS_BY_ID.getUri(), values);
|
||||
}
|
||||
|
||||
//TODO Set trackId in this method.
|
||||
@@ -576,7 +577,7 @@ public class ContentProviderUtils {
|
||||
for (int i = 0; i < markers.size(); i++) {
|
||||
values[i] = createContentValues(markers.get(i), trackId);
|
||||
}
|
||||
return contentResolver.bulkInsert(MarkerColumns.CONTENT_URI, values);
|
||||
return contentResolver.bulkInsert(CustomContentProvider.UrlType.MARKERS.getUri(), values);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -597,7 +598,7 @@ public class ContentProviderUtils {
|
||||
selectionArgs = new String[]{Long.toString(trackId.id())};
|
||||
}
|
||||
|
||||
return getTrackPointCursor(null, selection, selectionArgs, TrackPointsColumns.DEFAULT_SORT_ORDER);
|
||||
return getTrackPointCursor(null, selection, selectionArgs, BaseColumns._ID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -608,7 +609,7 @@ public class ContentProviderUtils {
|
||||
* @return the content provider URI of the inserted trackPoint
|
||||
*/
|
||||
public Uri insertTrackPoint(TrackPoint trackPoint, Track.Id trackId) {
|
||||
return contentResolver.insert(TrackPointsColumns.CONTENT_URI_BY_ID, createContentValues(trackPoint, trackId));
|
||||
return contentResolver.insert(CustomContentProvider.UrlType.TRACKPOINTS_BY_ID.getUri(), createContentValues(trackPoint, trackId));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -683,7 +684,7 @@ public class ContentProviderUtils {
|
||||
* @param sortOrder the sort order
|
||||
*/
|
||||
private Cursor getTrackPointCursor(String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
return contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, projection, selection, selectionArgs, sortOrder);
|
||||
return contentResolver.query(CustomContentProvider.UrlType.TRACKPOINTS_BY_ID.getUri(), projection, selection, selectionArgs, sortOrder);
|
||||
}
|
||||
|
||||
public static String formatIdListForUri(Track.Id... trackIds) {
|
||||
@@ -718,7 +719,7 @@ public class ContentProviderUtils {
|
||||
|
||||
public SensorStatistics getSensorStats(@NonNull Track.Id trackId) {
|
||||
SensorStatistics sensorStatistics = null;
|
||||
try (Cursor cursor = contentResolver.query(ContentUris.withAppendedId(TracksColumns.CONTENT_URI_SENSOR_STATS, trackId.id()), null, null, null, null)) {
|
||||
try (Cursor cursor = contentResolver.query(ContentUris.withAppendedId(CustomContentProvider.UrlType.TRACKS_SENSOR_STATS.getUri(), trackId.id()), null, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int MAX_HR_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_MAX_HR);
|
||||
final int AVG_HR_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_HR);
|
||||
@@ -743,7 +744,7 @@ public class ContentProviderUtils {
|
||||
@NonNull
|
||||
public List<AggregatedStatistic> getAggregatedStatisticsForTracks(TrackSelection selection) {
|
||||
SelectionData data = selection.buildSelection();
|
||||
try (Cursor cursor = contentResolver.query(TracksColumns.CONTENT_URI_AGGREGATED_STATISTICS, null, data.selection(), data.getSelectionArgs(), null)) {
|
||||
try (Cursor cursor = contentResolver.query(CustomContentProvider.UrlType.TRACKS_AGGREGATED_STATISTICS.getUri(), null, data.selection(), data.getSelectionArgs(), null)) {
|
||||
ArrayList<AggregatedStatistic> aggregatedStatistics = new ArrayList<>(cursor.getCount());
|
||||
while (cursor.moveToNext()) {
|
||||
aggregatedStatistics.add(new AggregatedStatistic(
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.BaseColumns;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -73,51 +74,39 @@ public class CustomContentProvider extends ContentProvider {
|
||||
*/
|
||||
private final String SENSOR_STATS_QUERY =
|
||||
"WITH time_select AS " +
|
||||
"(SELECT t1." + TrackPointsColumns.TIME + " * (t1." + TrackPointsColumns.TYPE + " NOT IN (" + TrackPoint.Type.SEGMENT_START_MANUAL.type_db + ")) time_value " +
|
||||
"FROM " + TrackPointsColumns.TABLE_NAME + " t1 " +
|
||||
"WHERE t1." + TrackPointsColumns._ID + " > t." + TrackPointsColumns._ID + " AND t1." + TrackPointsColumns.TRACKID + " = ? ORDER BY _id LIMIT 1) " +
|
||||
"(SELECT t1." + TrackPointsColumns.TIME + " * (t1." + TrackPointsColumns.TYPE + " NOT IN (" + TrackPoint.Type.SEGMENT_START_MANUAL.type_db + ")) time_value " +
|
||||
"FROM " + TrackPointsColumns.TABLE_NAME + " t1 " +
|
||||
"WHERE t1." + TrackPointsColumns._ID + " > t." + TrackPointsColumns._ID + " AND t1." + TrackPointsColumns.TRACKID + " = ? ORDER BY _id LIMIT 1) " +
|
||||
|
||||
"SELECT " +
|
||||
"SUM(t." + TrackPointsColumns.SENSOR_HEARTRATE + " * (COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ")) " +
|
||||
"/ " +
|
||||
"SUM(COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ") " + TrackPointsColumns.ALIAS_AVG_HR + ", " +
|
||||
"SELECT " +
|
||||
"SUM(t." + TrackPointsColumns.SENSOR_HEARTRATE + " * (COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ")) " +
|
||||
"/ " +
|
||||
"SUM(COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ") " + TrackPointsColumns.ALIAS_AVG_HR + ", " +
|
||||
|
||||
"MAX(t." + TrackPointsColumns.SENSOR_HEARTRATE + ") " + TrackPointsColumns.ALIAS_MAX_HR + ", " +
|
||||
"MAX(t." + TrackPointsColumns.SENSOR_HEARTRATE + ") " + TrackPointsColumns.ALIAS_MAX_HR + ", " +
|
||||
|
||||
"SUM(t." + TrackPointsColumns.SENSOR_CADENCE + " * (COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ")) " +
|
||||
"/ " +
|
||||
"SUM(COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ") " + TrackPointsColumns.ALIAS_AVG_CADENCE + ", " +
|
||||
"SUM(t." + TrackPointsColumns.SENSOR_CADENCE + " * (COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ")) " +
|
||||
"/ " +
|
||||
"SUM(COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ") " + TrackPointsColumns.ALIAS_AVG_CADENCE + ", " +
|
||||
|
||||
"MAX(t." + TrackPointsColumns.SENSOR_CADENCE + ") " + TrackPointsColumns.ALIAS_MAX_CADENCE + ", " +
|
||||
"MAX(t." + TrackPointsColumns.SENSOR_CADENCE + ") " + TrackPointsColumns.ALIAS_MAX_CADENCE + ", " +
|
||||
|
||||
"SUM(t." + TrackPointsColumns.SENSOR_POWER + " * (COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ")) " +
|
||||
"/ " +
|
||||
"SUM(COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ") " + TrackPointsColumns.ALIAS_AVG_POWER + ", " +
|
||||
"SUM(t." + TrackPointsColumns.SENSOR_POWER + " * (COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ")) " +
|
||||
"/ " +
|
||||
"SUM(COALESCE(MAX(t." + TrackPointsColumns.TIME + ", (SELECT time_value FROM time_select)), t." + TrackPointsColumns.TIME + ") - t." + TrackPointsColumns.TIME + ") " + TrackPointsColumns.ALIAS_AVG_POWER + ", " +
|
||||
|
||||
"MAX(t." + TrackPointsColumns.SENSOR_POWER + ") " + TrackPointsColumns.ALIAS_MAX_POWER + " " +
|
||||
"MAX(t." + TrackPointsColumns.SENSOR_POWER + ") " + TrackPointsColumns.ALIAS_MAX_POWER + " " +
|
||||
|
||||
"FROM " + TrackPointsColumns.TABLE_NAME + " t " +
|
||||
"WHERE t." + TrackPointsColumns.TRACKID + " = ? " +
|
||||
"AND t." + TrackPointsColumns.TYPE + " NOT IN (" + TrackPoint.Type.SEGMENT_START_MANUAL.type_db + ")";
|
||||
"FROM " + TrackPointsColumns.TABLE_NAME + " t " +
|
||||
"WHERE t." + TrackPointsColumns.TRACKID + " = ? " +
|
||||
"AND t." + TrackPointsColumns.TYPE + " NOT IN (" + TrackPoint.Type.SEGMENT_START_MANUAL.type_db + ")";
|
||||
|
||||
public CustomContentProvider() {
|
||||
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, TrackPointsColumns.CONTENT_URI_BY_ID.getPath(), UrlType.TRACKPOINTS.ordinal());
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, TrackPointsColumns.CONTENT_URI_BY_ID.getPath() + "/#", UrlType.TRACKPOINTS_BY_ID.ordinal());
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, TrackPointsColumns.CONTENT_URI_BY_TRACKID.getPath() + "/*", UrlType.TRACKPOINTS_BY_TRACKID.ordinal());
|
||||
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, TracksColumns.CONTENT_URI.getPath(), UrlType.TRACKS.ordinal());
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, TracksColumns.CONTENT_URI_SENSOR_STATS.getPath() + "/#", UrlType.TRACKS_SENSOR_STATS.ordinal());
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, TracksColumns.CONTENT_URI_AGGREGATED_STATISTICS.getPath(), UrlType.TRACKS_AGGREGATED_STATISTICS.ordinal());
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, TracksColumns.CONTENT_URI.getPath() + "/*", UrlType.TRACKS_BY_ID.ordinal());
|
||||
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, MarkerColumns.CONTENT_URI.getPath(), UrlType.MARKERS.ordinal());
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, MarkerColumns.CONTENT_URI.getPath() + "/#", UrlType.MARKERS_BY_ID.ordinal());
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, MarkerColumns.CONTENT_URI_BY_TRACKID.getPath() + "/*", UrlType.MARKERS_BY_TRACKID.ordinal());
|
||||
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, UrlType.DASHBOARD_TRACKS_BY_IDS.getPath() + "*", UrlType.DASHBOARD_TRACKS_BY_IDS.ordinal());
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, UrlType.DASHBOARD_TRACKPOINTS_BY_TRACKIDS.getPath() + "*", UrlType.DASHBOARD_TRACKPOINTS_BY_TRACKIDS.ordinal());
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, UrlType.DASHBOARD_MARKERS_BY_TRACKIDS.getPath() + "*", UrlType.DASHBOARD_MARKERS_BY_TRACKIDS.ordinal());
|
||||
UrlType[] urlTypes = UrlType.values();
|
||||
for (int i = 0; i < urlTypes.length; i++) {
|
||||
uriMatcher.addURI(AUTHORITY_PACKAGE, urlTypes[i].getPathWithFilter(), i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -180,23 +169,7 @@ public class CustomContentProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public String getType(@NonNull Uri url) {
|
||||
String contentType = getUrlType(url).contentType;
|
||||
if (contentType != null) {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
//TODO replace with getUrlType(url).getContentType()
|
||||
return switch (getUrlType(url)) {
|
||||
case TRACKPOINTS -> TrackPointsColumns.CONTENT_TYPE;
|
||||
case TRACKPOINTS_BY_TRACKID -> TrackPointsColumns.CONTENT_ITEMTYPE;
|
||||
case TRACKS -> TracksColumns.CONTENT_TYPE;
|
||||
case MARKERS -> MarkerColumns.CONTENT_TYPE;
|
||||
case MARKERS_BY_TRACKID -> MarkerColumns.CONTENT_ITEMTYPE;
|
||||
case DASHBOARD_TRACKS_BY_IDS -> UrlType.DASHBOARD_TRACKS_BY_IDS.contentType;
|
||||
case DASHBOARD_TRACKPOINTS_BY_TRACKIDS -> UrlType.DASHBOARD_TRACKPOINTS_BY_TRACKIDS.contentType;
|
||||
case DASHBOARD_MARKERS_BY_TRACKIDS -> UrlType.DASHBOARD_MARKERS_BY_TRACKIDS.contentType;
|
||||
default -> throw new IllegalArgumentException("Unknown URL " + url);
|
||||
};
|
||||
return getUrlType(url).contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -251,7 +224,7 @@ public class CustomContentProvider extends ContentProvider {
|
||||
switch (getUrlType(url)) {
|
||||
case TRACKPOINTS -> {
|
||||
queryBuilder.setTables(TrackPointsColumns.TABLE_NAME);
|
||||
sortOrder = sort != null ? sort : TrackPointsColumns.DEFAULT_SORT_ORDER;
|
||||
sortOrder = sort != null ? sort : BaseColumns._ID;
|
||||
}
|
||||
case TRACKPOINTS_BY_ID -> {
|
||||
queryBuilder.setTables(TrackPointsColumns.TABLE_NAME);
|
||||
@@ -272,13 +245,13 @@ public class CustomContentProvider extends ContentProvider {
|
||||
} else {
|
||||
queryBuilder.setTables(TracksColumns.TABLE_NAME);
|
||||
}
|
||||
sortOrder = sort != null ? sort : TracksColumns.DEFAULT_SORT_ORDER;
|
||||
sortOrder = sort != null ? sort : BaseColumns._ID;
|
||||
}
|
||||
case TRACKS_BY_ID -> {
|
||||
queryBuilder.setTables(TracksColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere(TracksColumns._ID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")");
|
||||
}
|
||||
case DASHBOARD_TRACKS_BY_IDS -> {
|
||||
case DASHBOARD_TRACKS_BY_IDS -> {
|
||||
queryBuilder.setTables(TracksColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere(TracksColumns._ID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")");
|
||||
queryBuilder.setProjectionMap(DataProvider.DATA_PROJECTIONMAP_TRACKS);
|
||||
@@ -303,7 +276,7 @@ public class CustomContentProvider extends ContentProvider {
|
||||
}
|
||||
case MARKERS -> {
|
||||
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
||||
sortOrder = sort != null ? sort : MarkerColumns.DEFAULT_SORT_ORDER;
|
||||
sortOrder = sort != null ? sort : BaseColumns._ID;
|
||||
}
|
||||
case MARKERS_BY_ID -> {
|
||||
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
||||
@@ -414,7 +387,7 @@ public class CustomContentProvider extends ContentProvider {
|
||||
}
|
||||
long rowId = db.insert(TrackPointsColumns.TABLE_NAME, TrackPointsColumns._ID, values);
|
||||
if (rowId >= 0) {
|
||||
return ContentUris.appendId(TrackPointsColumns.CONTENT_URI_BY_ID.buildUpon(), rowId).build();
|
||||
return ContentUris.appendId(UrlType.TRACKPOINTS_BY_ID.getUri().buildUpon(), rowId).build();
|
||||
}
|
||||
throw new SQLiteException("Failed to insert a track point " + url);
|
||||
}
|
||||
@@ -422,7 +395,7 @@ public class CustomContentProvider extends ContentProvider {
|
||||
private Uri insertTrack(Uri url, ContentValues contentValues) {
|
||||
long rowId = db.insert(TracksColumns.TABLE_NAME, TracksColumns._ID, contentValues);
|
||||
if (rowId >= 0) {
|
||||
return ContentUris.appendId(TracksColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
return ContentUris.appendId(UrlType.TRACKS.getUri().buildUpon(), rowId).build();
|
||||
}
|
||||
throw new SQLException("Failed to insert a track " + url);
|
||||
}
|
||||
@@ -430,53 +403,49 @@ public class CustomContentProvider extends ContentProvider {
|
||||
private Uri insertMarker(Uri url, ContentValues contentValues) {
|
||||
long rowId = db.insert(MarkerColumns.TABLE_NAME, MarkerColumns._ID, contentValues);
|
||||
if (rowId >= 0) {
|
||||
return ContentUris.appendId(MarkerColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
return ContentUris.appendId(UrlType.MARKERS.getUri().buildUpon(), rowId).build();
|
||||
}
|
||||
throw new SQLException("Failed to insert a marker " + url);
|
||||
}
|
||||
|
||||
//TODO Add ContentType as attribute
|
||||
public enum UrlType {
|
||||
TRACKPOINTS,
|
||||
TRACKPOINTS_BY_ID,
|
||||
TRACKPOINTS("/trackpoints", "", "vnd.android.cursor.dir/vnd.de.dennisguse.trackpoint"),
|
||||
TRACKPOINTS_BY_ID("/trackpoints", "#", "vnd.android.cursor.dir/vnd.de.dennisguse.trackpoint"),
|
||||
//TODO Check if still used
|
||||
TRACKPOINTS_BY_TRACKID,
|
||||
TRACKS,
|
||||
TRACKS_BY_ID,
|
||||
TRACKS_SENSOR_STATS,
|
||||
TRACKS_AGGREGATED_STATISTICS,
|
||||
MARKERS,
|
||||
MARKERS_BY_ID,
|
||||
TRACKPOINTS_BY_TRACKID("/trackpoints/trackid", "*", "vnd.android.cursor.dir/vnd.de.dennisguse.trackpoint"),
|
||||
TRACKS("/tracks", "", "vnd.android.cursor.dir/vnd.de.dennisguse.track"),
|
||||
TRACKS_BY_ID("/tracks", "#", "vnd.android.cursor.dir/vnd.de.dennisguse.track"),
|
||||
TRACKS_SENSOR_STATS("/tracks/sensorstats", "#", "vnd.android.cursor.dir/vnd.de.dennisguse.sensorstats"),
|
||||
TRACKS_AGGREGATED_STATISTICS("/tracks/aggregated/", "", "vnd.android.cursor.dir/vnd.de.dennisguse.aggregatedstatistics"),
|
||||
MARKERS("/markers", "", "vnd.android.cursor.dir/vnd.de.dennisguse.waypoint"),
|
||||
MARKERS_BY_ID("/markers", "#", "vnd.android.cursor.dir/vnd.de.dennisguse.waypoint"),
|
||||
@Deprecated //TODO Should not be used anymore
|
||||
MARKERS_BY_TRACKID,
|
||||
MARKERS_BY_TRACKID("/markers/trackid", "*", "vnd.android.cursor.dir/vnd.de.dennisguse.waypoint"),
|
||||
|
||||
DASHBOARD_TRACKS_BY_IDS(Uri.parse(CONTENT_BASE_URI + "/dashboard/tracks/"), TracksColumns.CONTENT_TYPE),
|
||||
DASHBOARD_TRACKPOINTS_BY_TRACKIDS(Uri.parse(CONTENT_BASE_URI + "/dashboard/trackpoints/"), TrackPointsColumns.CONTENT_TYPE),
|
||||
DASHBOARD_MARKERS_BY_TRACKIDS(Uri.parse(CONTENT_BASE_URI + "/dashboard/markers/"), MarkerColumns.CONTENT_TYPE);
|
||||
DASHBOARD_TRACKS_BY_IDS("/dashboard/tracks", "*", "vnd.android.cursor.dir/vnd.de.dennisguse.track"),
|
||||
DASHBOARD_TRACKPOINTS_BY_TRACKIDS("/dashboard/trackpoints", "*", "vnd.android.cursor.dir/vnd.de.dennisguse.trackpoint"),
|
||||
DASHBOARD_MARKERS_BY_TRACKIDS("/dashboard/markers", "*", "vnd.android.cursor.dir/vnd.de.dennisguse.waypoint");
|
||||
|
||||
private final Uri uri;
|
||||
private final String path;
|
||||
|
||||
private final String filter;
|
||||
|
||||
private final String contentType;
|
||||
|
||||
//TODO Add Uri as attribute:
|
||||
//TODO Add ContentType as attribute:
|
||||
@Deprecated()
|
||||
UrlType() {
|
||||
this.uri = null;
|
||||
this.contentType = null;
|
||||
}
|
||||
|
||||
UrlType(Uri uri, String contentType) {
|
||||
this.uri = uri;
|
||||
UrlType(@NonNull String path, String filter, @NonNull String contentType) {
|
||||
this.path = path;
|
||||
this.filter = filter;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
return Uri.parse(CONTENT_BASE_URI + path);
|
||||
}
|
||||
|
||||
String getPath() {
|
||||
return uri.getPath();
|
||||
private String getPathWithFilter() {
|
||||
if (TextUtils.isEmpty(filter))
|
||||
return path;
|
||||
return path + "/" + filter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ShareContentProvider extends CustomContentProvider {
|
||||
}
|
||||
trackIdBuilder.deleteCharAt(trackIdBuilder.lastIndexOf(TRACKID_DELIMITER));
|
||||
|
||||
Uri uri = Uri.parse(TracksColumns.CONTENT_URI + "/" + trackFileFormat.getPreferenceId() + "/" + trackIdBuilder + "/" + Uri.encode(filename));
|
||||
Uri uri = Uri.parse(UrlType.TRACKS.getUri() + "/" + trackFileFormat.getPreferenceId() + "/" + trackIdBuilder + "/" + Uri.encode(filename));
|
||||
|
||||
Log.d(TAG, "Created uri " + uri + " with MIME " + trackFileFormat.getMimeType());
|
||||
|
||||
@@ -192,7 +192,7 @@ public class ShareContentProvider extends CustomContentProvider {
|
||||
String[] trackIdsString = trackIds.stream().map(id -> String.valueOf(id.id())).toArray(String[]::new);
|
||||
String whereClause = String.format(TracksColumns._ID + " IN (%s)", TextUtils.join(",", Collections.nCopies(trackIds.size(), "?")));
|
||||
|
||||
try (Cursor cursor = super.query(TracksColumns.CONTENT_URI, null, whereClause, trackIdsString, TracksColumns._ID)) {
|
||||
try (Cursor cursor = super.query(UrlType.TRACKS.getUri(), null, whereClause, trackIdsString, TracksColumns._ID)) {
|
||||
while (cursor.moveToNext()) {
|
||||
tracks.add(ContentProviderUtils.createTrack(cursor));
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@ import de.dennisguse.opentracks.data.models.Statistics;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
import de.dennisguse.opentracks.data.statistics.TrackStatisticsUpdater;
|
||||
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.data.tables.TracksColumns;
|
||||
import de.dennisguse.opentracks.services.RecordingStatus;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||
import de.dennisguse.opentracks.services.handlers.AltitudeCorrectionManager;
|
||||
@@ -120,7 +118,7 @@ public class TrackDataHub {
|
||||
notifyTracksTableUpdate(listeners);
|
||||
}
|
||||
};
|
||||
contentResolver.registerContentObserver(TracksColumns.CONTENT_URI, false, tracksTableObserver);
|
||||
contentResolver.registerContentObserver(CustomContentProvider.UrlType.TRACKS.getUri(), false, tracksTableObserver);
|
||||
|
||||
trackPointsTableObserver = new ContentObserver(handler) {
|
||||
@Override
|
||||
@@ -128,7 +126,7 @@ public class TrackDataHub {
|
||||
notifyTrackPointsTableUpdate(true, listeners);
|
||||
}
|
||||
};
|
||||
contentResolver.registerContentObserver(TrackPointsColumns.CONTENT_URI_BY_ID, false, trackPointsTableObserver);
|
||||
contentResolver.registerContentObserver(CustomContentProvider.UrlType.TRACKPOINTS_BY_ID.getUri(), false, trackPointsTableObserver);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
|
||||
@@ -14,13 +15,13 @@ public enum ActivityType {
|
||||
|
||||
AIRPLANE("airplane", R.string.activity_type_airplane, R.drawable.ic_activity_flight_24dp, true),
|
||||
ATV("ATV", R.string.activity_type_atv, R.drawable.ic_activity_drive_24dp, true),
|
||||
BIKING("biking", R.string.activity_type_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
BIKING("biking", List.of("bike", "indoor cycling"), R.string.activity_type_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
BLIMP("blimp", R.string.activity_type_blimp, ActivityIcon.ICON_UNKNOWN, true),
|
||||
BOAT("boat", R.string.activity_type_boat, R.drawable.ic_activity_boat_24dp, true),
|
||||
CLIMBING("climbing", R.string.activity_type_climbing, R.drawable.ic_activity_climbing_24dp, false),
|
||||
COMMERCIAL_AIRPLANE("commercial airplane", R.string.activity_type_commercial_airplane, R.drawable.ic_activity_flight_24dp, true),
|
||||
CROSS_COUNTRY_SKIING("cross-country skiing", R.string.activity_type_cross_country_skiing, R.drawable.ic_activity_skiing_24dp, true),
|
||||
CYCLING("cycling", R.string.activity_type_cycling, R.drawable.ic_activity_bike_24dp, true),
|
||||
CYCLING("cycling", List.of("cycle"), R.string.activity_type_cycling, R.drawable.ic_activity_bike_24dp, true),
|
||||
DIRT_BIKE("dirt bike", R.string.activity_type_dirt_bike, R.drawable.ic_activity_mtb_24dp, true),
|
||||
DONKEY_BACK_RIDING("donkey back riding", R.string.activity_type_donkey_back_riding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
DRIVING("driving", R.string.activity_type_driving, R.drawable.ic_activity_drive_24dp, true),
|
||||
@@ -30,21 +31,21 @@ public enum ActivityType {
|
||||
FERRY("ferry", R.string.activity_type_ferry, R.drawable.ic_activity_boat_24dp, true),
|
||||
FRISBEE("frisbee", R.string.activity_type_frisbee, ActivityIcon.ICON_UNKNOWN, true),
|
||||
GLIDING("gliding", R.string.activity_type_gliding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
GRAVEL_BIKING("gravel biking", R.string.activity_type_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
GRAVEL_BIKING("gravel biking", List.of("gravel bike"), R.string.activity_type_gravel_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
HANG_GLIDING("hang gliding", R.string.activity_type_hang_gliding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
HELICOPTER("helicopter", R.string.activity_type_helicopter, ActivityIcon.ICON_UNKNOWN, true),
|
||||
HIKING("hiking", R.string.activity_type_hiking, R.drawable.ic_activity_walk_24dp, false),
|
||||
HIKING("hiking", List.of("hike"), R.string.activity_type_hiking, R.drawable.ic_activity_walk_24dp, false),
|
||||
HORSE_BACK_RIDING("horse back riding", R.string.activity_type_horse_back_riding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
HOT_AIR_BALLOON("hot air balloon", R.string.activity_type_hot_air_balloon, ActivityIcon.ICON_UNKNOWN, true),
|
||||
ICE_SAILING("ice sailing", R.string.activity_type_ice_sailing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
INLINE_SKATING("inline skating", R.string.activity_type_inline_skating, R.drawable.ic_activity_inline_skating_24dp, true),
|
||||
INLINE_SKATING("inline skating", List.of("inline skate"), R.string.activity_type_inline_skating, R.drawable.ic_activity_inline_skating_24dp, true),
|
||||
KAYAKING("kayaking", R.string.activity_type_kayaking, R.drawable.ic_activity_kayaking_24dp, true),
|
||||
KITE_SURFING("kite surfing", R.string.activity_type_kite_surfing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
LAND_SAILING("land sailing", R.string.activity_type_land_sailing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
MIXED_TYPE("mixed type", R.string.activity_type_mixed_type, ActivityIcon.ICON_UNKNOWN, true),
|
||||
MOTOR_BIKE("motor bike", R.string.activity_type_motor_bike, R.drawable.ic_activity_motorbike_24dp, true),
|
||||
MOTOR_BOATING("motor boating", R.string.activity_type_motor_boating, R.drawable.ic_activity_boat_24dp, true),
|
||||
MOUNTAIN_BIKING("mountain biking", R.string.activity_type_mountain_biking, R.drawable.ic_activity_mtb_24dp, true),
|
||||
MOUNTAIN_BIKING("mountain biking", List.of("mountain bike"), R.string.activity_type_mountain_biking, R.drawable.ic_activity_mtb_24dp, true),
|
||||
OFF_TRAIL_HIKING("off trail hiking", R.string.activity_type_off_trail_hiking, R.drawable.ic_activity_walk_24dp, false),
|
||||
OTHER("other", R.string.activity_type_other, ActivityIcon.ICON_UNKNOWN, true),
|
||||
PADDLING("paddling", R.string.activity_type_paddling, ActivityIcon.ICON_UNKNOWN, true),
|
||||
@@ -53,46 +54,57 @@ public enum ActivityType {
|
||||
RC_BOAT("RC boat", R.string.activity_type_rc_boat, R.drawable.ic_activity_boat_24dp, true),
|
||||
RC_HELICOPTER("RC helicopter", R.string.activity_type_rc_helicopter, ActivityIcon.ICON_UNKNOWN, true),
|
||||
RIDING("riding", R.string.activity_type_horse_back_riding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
ROAD_BIKING("road biking", R.string.activity_type_road_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
ROAD_BIKING("road biking", List.of("road bike"), R.string.activity_type_road_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
ROLLER_SKIING("roller skiing", R.string.activity_type_roller_skiing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
ROWING("rowing", R.string.activity_type_rowing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
RUNNING("running", R.string.activity_type_running, R.drawable.ic_activity_run_24dp, false),
|
||||
RUNNING("running", List.of("run", "treadmill"), R.string.activity_type_running, R.drawable.ic_activity_run_24dp, false),
|
||||
SAILING("sailing", R.string.activity_type_sailing, R.drawable.ic_activity_sailing_24dp, true),
|
||||
KICKSCOOTER("kickscooter", R.string.activity_type_kickscooter, R.drawable.ic_activity_scooter_24dp, true),
|
||||
SEAPLANE("seaplane", R.string.activity_type_seaplane, R.drawable.ic_activity_flight_24dp, true),
|
||||
SKATE_BOARDING("skateboarding", R.string.activity_type_skate_boarding, R.drawable.ic_activity_skateboarding_24dp, true),
|
||||
SKATE_BOARDING("skateboarding", List.of("skateboard"), R.string.activity_type_skate_boarding, R.drawable.ic_activity_skateboarding_24dp, true),
|
||||
SKATING("skating", R.string.activity_type_skating, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SKIING("skiing", R.string.activity_type_skiing, R.drawable.ic_activity_skiing_24dp, true),
|
||||
SKY_JUMPING("sky jumping", R.string.activity_type_sky_jumping, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SLED("sled", R.string.activity_type_sled, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SNOW_BOARDING("snowboarding", R.string.activity_type_snow_boarding, R.drawable.ic_activity_snowboarding_24dp, true),
|
||||
SNOW_BOARDING("snowboarding", List.of("snowboard"), R.string.activity_type_snow_boarding, R.drawable.ic_activity_snowboarding_24dp, true),
|
||||
SNOW_SHOEING("snow shoeing", R.string.activity_type_snow_shoeing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SPEED_WALKING("speed walking", R.string.activity_type_speed_walking, R.drawable.ic_activity_walk_24dp, false),
|
||||
STREET_RUNNING("street running", R.string.activity_type_street_running, R.drawable.ic_activity_run_24dp, false),
|
||||
SURFING("surfing", R.string.activity_type_surfing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
TRACK_CYCLING("track cycling", R.string.activity_type_track_cycling, R.drawable.ic_activity_bike_24dp, true),
|
||||
TRACK_RUNNING("track running", R.string.activity_type_trail_running, R.drawable.ic_activity_run_24dp, false),
|
||||
TRACK_RUNNING("track running", List.of("track run"), R.string.activity_type_trail_running, R.drawable.ic_activity_run_24dp, false),
|
||||
TRAIL_HIKING("trail hiking", R.string.activity_type_trail_hiking, R.drawable.ic_activity_walk_24dp, false),
|
||||
TRAIL_RUNNING("trail running", R.string.activity_type_trail_running, R.drawable.ic_activity_run_24dp, false),
|
||||
TRAIL_RUNNING("trail running", List.of("trail run"), R.string.activity_type_trail_running, R.drawable.ic_activity_run_24dp, false),
|
||||
TRAIN("train", R.string.activity_type_train, ActivityIcon.ICON_UNKNOWN, true),
|
||||
ULTIMATE_FRISBEE("ultimate frisbee", R.string.activity_type_ultimate_frisbee, ActivityIcon.ICON_UNKNOWN, true),
|
||||
WAKEBOARDING("wakeboarding", R.string.activity_type_wakeboarding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
WALKING("walking", R.string.activity_type_walking, R.drawable.ic_activity_walk_24dp, false),
|
||||
WALKING("walking", List.of("walk"), R.string.activity_type_walking, R.drawable.ic_activity_walk_24dp, false),
|
||||
WATER_SKIING("water skiing", R.string.activity_type_water_skiing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
WIND_SURFING("wind surfing", R.string.activity_type_wind_surfing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SWIMMING("swimming", R.string.activity_type_swimming, R.drawable.ic_activity_swimming_24dp, false),
|
||||
SWIMMING_OPEN("swimming in open water", R.string.activity_type_swimming_open, R.drawable.ic_activity_swimming_open_24dp, false),
|
||||
SWIMMING("swimming", List.of("swim"), R.string.activity_type_swimming, R.drawable.ic_activity_swimming_24dp, false),
|
||||
SWIMMING_OPEN("swimming in open water", List.of("swimming openwater", "open water swimming"), R.string.activity_type_swimming_open, R.drawable.ic_activity_swimming_open_24dp, false),
|
||||
WORKOUT("workout", R.string.activity_type_workout, R.drawable.ic_activity_workout_24dp, false),
|
||||
UNKNOWN("unknown", R.string.activity_type_unknown, ActivityIcon.ICON_UNKNOWN, true);
|
||||
|
||||
final String id;
|
||||
|
||||
/**
|
||||
* Spellings used by other applications that {@link #normalize(String)} cannot map onto {@link #id}.
|
||||
* Already normalized.
|
||||
*/
|
||||
final List<String> synonyms;
|
||||
|
||||
final int iconDrawableId;
|
||||
final boolean showSpeedPreferred;
|
||||
final int localizedStringId;
|
||||
|
||||
ActivityType(String id, int localizedStringId, int iconDrawableId, boolean showSpeedPreferred) {
|
||||
this(id, List.of(), localizedStringId, iconDrawableId, showSpeedPreferred);
|
||||
}
|
||||
|
||||
ActivityType(String id, List<String> synonyms, int localizedStringId, int iconDrawableId, boolean showSpeedPreferred) {
|
||||
this.id = id;
|
||||
this.synonyms = synonyms;
|
||||
this.localizedStringId = localizedStringId;
|
||||
this.iconDrawableId = iconDrawableId;
|
||||
this.showSpeedPreferred = showSpeedPreferred;
|
||||
@@ -121,12 +133,39 @@ public enum ActivityType {
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowercases and reduces "_", "-" and whitespace runs to a single space.
|
||||
* Lowercasing is locale-independent: under a Turkish locale the I of "RUNNING" would otherwise
|
||||
* lowercase to a dotless i and stop matching "running".
|
||||
*/
|
||||
@NonNull
|
||||
private static String normalize(String activityTypeId) {
|
||||
if (activityTypeId == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return activityTypeId.toLowerCase(Locale.ROOT)
|
||||
.replaceAll("[\\s_-]+", " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an activity type as written by another application; GPX's type element is free text.
|
||||
*/
|
||||
@NonNull
|
||||
public static ActivityType findBy(String activityTypeId) {
|
||||
return Arrays.stream(ActivityType.values()).filter(
|
||||
it -> it.id.equals(activityTypeId)
|
||||
).findFirst()
|
||||
.orElse(ActivityType.UNKNOWN);
|
||||
String normalized = normalize(activityTypeId);
|
||||
if (normalized.isEmpty()) {
|
||||
return ActivityType.UNKNOWN;
|
||||
}
|
||||
|
||||
return Arrays.stream(ActivityType.values())
|
||||
.filter(it -> normalize(it.id).equals(normalized))
|
||||
.findFirst()
|
||||
.orElseGet(() -> Arrays.stream(ActivityType.values())
|
||||
.filter(it -> it.synonyms.contains(normalized))
|
||||
.findFirst()
|
||||
.orElse(ActivityType.UNKNOWN));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
@@ -50,15 +50,6 @@ public class ExtremityMonitor {
|
||||
return min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum value.
|
||||
*
|
||||
* @param min the minimum value
|
||||
*/
|
||||
public void setMin(double min) {
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum value seen.
|
||||
*/
|
||||
@@ -66,15 +57,6 @@ public class ExtremityMonitor {
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum value.
|
||||
*
|
||||
* @param max the maximum value
|
||||
*/
|
||||
public void setMax(double max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the min and the max with a new value.
|
||||
*
|
||||
|
||||
@@ -17,12 +17,10 @@
|
||||
package de.dennisguse.opentracks.data.tables;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.data.CustomContentProvider;
|
||||
|
||||
/**
|
||||
* Constants for markers table.
|
||||
@@ -32,11 +30,6 @@ import de.dennisguse.opentracks.data.CustomContentProvider;
|
||||
public interface MarkerColumns extends BaseColumns {
|
||||
|
||||
String TABLE_NAME = "markers";
|
||||
Uri CONTENT_URI = Uri.parse(CustomContentProvider.CONTENT_BASE_URI + "/" + TABLE_NAME);
|
||||
Uri CONTENT_URI_BY_TRACKID = Uri.parse(CustomContentProvider.CONTENT_BASE_URI + "/" + TABLE_NAME + "/trackid");
|
||||
String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.de.dennisguse.waypoint";
|
||||
String CONTENT_ITEMTYPE = "vnd.android.cursor.item/vnd.de.dennisguse.waypoint";
|
||||
String DEFAULT_SORT_ORDER = _ID;
|
||||
|
||||
// Columns
|
||||
String NAME = "name";
|
||||
|
||||
@@ -16,11 +16,8 @@
|
||||
|
||||
package de.dennisguse.opentracks.data.tables;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
import de.dennisguse.opentracks.data.CustomContentProvider;
|
||||
|
||||
/**
|
||||
* Constants for the track points table.
|
||||
*
|
||||
@@ -29,11 +26,6 @@ import de.dennisguse.opentracks.data.CustomContentProvider;
|
||||
public interface TrackPointsColumns extends BaseColumns {
|
||||
|
||||
String TABLE_NAME = "trackpoints";
|
||||
Uri CONTENT_URI_BY_ID = Uri.parse(CustomContentProvider.CONTENT_BASE_URI + "/" + TABLE_NAME);
|
||||
Uri CONTENT_URI_BY_TRACKID = Uri.parse(CustomContentProvider.CONTENT_BASE_URI + "/" + TABLE_NAME + "/trackid");
|
||||
String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.de.dennisguse.trackpoint";
|
||||
String CONTENT_ITEMTYPE = "vnd.android.cursor.item/vnd.de.dennisguse.trackpoint";
|
||||
String DEFAULT_SORT_ORDER = _ID;
|
||||
|
||||
// Columns
|
||||
String TRACKID = "trackid";
|
||||
|
||||
@@ -16,11 +16,8 @@
|
||||
|
||||
package de.dennisguse.opentracks.data.tables;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
import de.dennisguse.opentracks.data.CustomContentProvider;
|
||||
|
||||
/**
|
||||
* Constants for the tracks table.
|
||||
*
|
||||
@@ -29,12 +26,6 @@ import de.dennisguse.opentracks.data.CustomContentProvider;
|
||||
public interface TracksColumns extends BaseColumns {
|
||||
|
||||
String TABLE_NAME = "tracks";
|
||||
Uri CONTENT_URI = Uri.parse(CustomContentProvider.CONTENT_BASE_URI + "/" + TABLE_NAME);
|
||||
Uri CONTENT_URI_SENSOR_STATS = Uri.parse(CustomContentProvider.CONTENT_BASE_URI + "/" + TABLE_NAME + "/sensorstats");
|
||||
Uri CONTENT_URI_AGGREGATED_STATISTICS = Uri.parse(CustomContentProvider.CONTENT_BASE_URI + "/" + TABLE_NAME + "/aggregated/");
|
||||
String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.de.dennisguse.track";
|
||||
String CONTENT_ITEMTYPE = "vnd.android.cursor.item/vnd.de.dennisguse.track";
|
||||
String DEFAULT_SORT_ORDER = _ID;
|
||||
|
||||
// Columns
|
||||
String UUID = "uuid"; // identifier to make tracks globally unique (prevent re-import)
|
||||
|
||||
+2
-2
@@ -56,7 +56,7 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment implements
|
||||
ActivityType.WORKOUT
|
||||
);
|
||||
|
||||
private static int getPosition(Context context, ActivityType activityType) {
|
||||
private static int getPosition(ActivityType activityType) {
|
||||
if (activityType == null) {
|
||||
return -1;
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment implements
|
||||
}
|
||||
|
||||
final ChooseActivityTypeImageAdapter imageAdapter = new ChooseActivityTypeImageAdapter(iconDrawableIds);
|
||||
int position = getPosition(getContext(), preselectedActivityType);
|
||||
int position = getPosition(preselectedActivityType);
|
||||
if (position != -1) {
|
||||
imageAdapter.setSelected(position);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ExportUtils {
|
||||
private static final String TAG = ExportUtils.class.getSimpleName();
|
||||
|
||||
public static void postWorkoutExport(AppCompatActivity context, Track.Id trackId) {
|
||||
if (PreferencesUtils.shouldInstantExportAfterWorkout()) {
|
||||
if (PreferencesUtils.shouldInstantExportToFile()) {
|
||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat();
|
||||
DocumentFile directory = IntentUtils.toDocumentFile(context, PreferencesUtils.getDefaultExportDirectoryUri());
|
||||
|
||||
|
||||
@@ -282,10 +282,11 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
Statistics trackStatistics = track.statistics();
|
||||
printWriter.println("<gpxtrkx:TrackStatsExtension>");
|
||||
printWriter.println("<gpxtrkx:Distance>" + trackStatistics.totalDistance().toM() + "</gpxtrkx:Distance>");
|
||||
printWriter.println("<gpxtrkx:TimerTime>" + trackStatistics.totalDuration().getSeconds() + "</gpxtrkx:TimerTime>");
|
||||
printWriter.println("<gpxtrkx:TotalElapsedTime>" + trackStatistics.totalDuration().getSeconds() + "</gpxtrkx:TotalElapsedTime>");
|
||||
printWriter.println("<gpxtrkx:MovingTime>" + trackStatistics.movingDuration().getSeconds() + "</gpxtrkx:MovingTime>");
|
||||
printWriter.println("<gpxtrkx:StoppedTime>" + trackStatistics.getStoppedTime().getSeconds() + "</gpxtrkx:StoppedTime>");
|
||||
printWriter.println("<gpxtrkx:MaxSpeed>" + trackStatistics.maxSpeed().toMPS() + "</gpxtrkx:MaxSpeed>");
|
||||
printWriter.println("<gpxtrkx:MovingSpeed>" + trackStatistics.getAverageMovingSpeed().toMPS() + "</gpxtrkx:MovingSpeed>");
|
||||
if (trackStatistics.altitudeGainLoss() != null) {
|
||||
printWriter.println("<gpxtrkx:Ascent>" + trackStatistics.altitudeGainLoss().gain_m() + "</gpxtrkx:Ascent>");
|
||||
printWriter.println("<gpxtrkx:Descent>" + trackStatistics.altitudeGainLoss().loss_m() + "</gpxtrkx:Descent>");
|
||||
@@ -384,10 +385,7 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
|
||||
printWriter.println("</trkpt>");
|
||||
|
||||
if (cumulativeDistance != null) {
|
||||
return cumulativeDistance;
|
||||
}
|
||||
return Distance.ZERO;
|
||||
return Objects.requireNonNullElse(cumulativeDistance, Distance.ZERO);
|
||||
}
|
||||
|
||||
private Double cumulateSensorData(TrackPoint trackPoint, List<TrackPoint> sensorPoints, Function<TrackPoint, Double> map) {
|
||||
|
||||
@@ -18,8 +18,11 @@ package de.dennisguse.opentracks.io.file.importer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
@@ -71,28 +74,44 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
private static final String TAG_TRACK_POINT = "trkpt";
|
||||
private static final String TAG_TRACK_SEGMENT = "trkseg";
|
||||
private static final String TAG_TYPE = "type";
|
||||
private static final String TAG_TYPE_LOCALIZED = "opentracks:typeTranslated";
|
||||
private static final String TAG_MARKER = "wpt";
|
||||
private static final String TAG_ID = "opentracks:trackid";
|
||||
|
||||
private static final String ATTRIBUTE_LAT = "lat";
|
||||
private static final String ATTRIBUTE_LON = "lon";
|
||||
|
||||
private static final String TAG_EXTENSION_SPEED = "gpxtpx:speed";
|
||||
/**
|
||||
* Often speed is exported without the proper namespace.
|
||||
*/
|
||||
private static final String TAG_EXTENSION_SPEED_COMPAT = "speed";
|
||||
private static final String TAG_EXTENSION_HEARTRATE = "gpxtpx:hr";
|
||||
private static final String TAG_EXTENSION_TEMPERATURE = "gpxtpx:atemp";
|
||||
private static final String TAG_EXTENSION_CADENCE = "gpxtpx:cad";
|
||||
private static final String TAG_EXTENSION_POWER = "pwr:PowerInWatts";
|
||||
|
||||
private static final String TAG_EXTENSION_GAIN = "opentracks:gain";
|
||||
private static final String TAG_EXTENSION_LOSS = "opentracks:loss";
|
||||
private static final String TAG_EXTENSION_DISTANCE = "opentracks:distance";
|
||||
private static final String TAG_EXTENSION_ACCURACY_HORIZONTAL = "opentracks:accuracy_horizontal";
|
||||
private static final String TAG_EXTENSION_ACCURACY_VERTICAL = "opentracks:accuracy_vertical";
|
||||
/**
|
||||
* Garmin Trackpoint Extensions.
|
||||
*/
|
||||
private static final String NS_GARMIN_TRACKPOINT_EXTENSION_V1 = "http://www.garmin.com/xmlschemas/TrackPointExtension/v1";
|
||||
private static final String NS_GARMIN_TRACKPOINT_EXTENSION_V2 = "http://www.garmin.com/xmlschemas/TrackPointExtension/v2";
|
||||
private static final String TAG_GARMIN_TPX_EXTENSION_SPEED = "speed";
|
||||
private static final String TAG_GARMIN_TPX_EXTENSION_HEARTRATE = "hr";
|
||||
private static final String TAG_GARMIN_TPX_EXTENSION_TEMPERATURE = "atemp";
|
||||
private static final String TAG_GARMIN_TPX_EXTENSION_CADENCE = "cad";
|
||||
|
||||
/**
|
||||
* Garmin Trackpoint Extensions.
|
||||
*/
|
||||
private static final String NS_GARMIN_POWER_EXTENSION_V1 = "http://www.garmin.com/xmlschemas/PowerExtension/v1";
|
||||
private static final String TAG_GARMIN_PWR_EXTENSION_POWER = "PowerInWatts";
|
||||
|
||||
/**
|
||||
* OpenTracks Extensions.
|
||||
*/
|
||||
private static final String NS_OPENTRACKS = "http://opentracksapp.com/xmlschemas/v1";
|
||||
private static final String TAG_OPENTRACKS_EXTENSION_TRACK_ID = "trackid";
|
||||
private static final String TAG_OPENTRACKS_EXTENSION_TYPE_LOCALIZED = "typeTranslated";
|
||||
private static final String TAG_OPENTRACKS_EXTENSION_GAIN = "gain";
|
||||
private static final String TAG_OPENTRACKS_EXTENSION_LOSS = "loss";
|
||||
private static final String TAG_OPENTRACKS_EXTENSION_DISTANCE = "distance";
|
||||
private static final String TAG_OPENTRACKS_EXTENSION_ACCURACY_HORIZONTAL = "accuracy_horizontal";
|
||||
private static final String TAG_OPENTRACKS_EXTENSION_ACCURACY_VERTICAL = "accuracy_vertical";
|
||||
|
||||
private Locator locator;
|
||||
|
||||
private final Context context;
|
||||
@@ -142,8 +161,8 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String tag, Attributes attributes) {
|
||||
switch (tag) {
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
switch (qName) {
|
||||
case TAG_MARKER:
|
||||
onMarkerStart(attributes);
|
||||
break;
|
||||
@@ -165,105 +184,128 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String tag) {
|
||||
switch (tag) {
|
||||
case TAG_GPX -> onFileEnd();
|
||||
case TAG_MARKER -> onMarkerEnd();
|
||||
case TAG_TRACK -> {
|
||||
if (activityTypeLocalized == null) {
|
||||
// Backward compatibility: up v4.9.1 as <type> contained localized content.
|
||||
activityTypeLocalized = activityType;
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
if (NS_GARMIN_TRACKPOINT_EXTENSION_V1.equals(uri) || NS_GARMIN_TRACKPOINT_EXTENSION_V2.equals(uri)) {
|
||||
switch (localName) {
|
||||
case TAG_GARMIN_TPX_EXTENSION_SPEED -> {
|
||||
if (content != null) {
|
||||
speed = content.trim();
|
||||
}
|
||||
}
|
||||
trackImporter.setTrackData(context, name, uuid, description, activityTypeLocalized, activityType, zoneOffset);
|
||||
zoneOffset = null;
|
||||
}
|
||||
case TAG_TRACK_SEGMENT -> onTrackSegmentEnd();
|
||||
case TAG_TRACK_POINT -> currentSegment.add(createTrackPoint());
|
||||
case TAG_NAME -> {
|
||||
if (content != null) {
|
||||
name = content.trim();
|
||||
case TAG_GARMIN_TPX_EXTENSION_HEARTRATE -> {
|
||||
if (content != null) {
|
||||
heartrate = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_DESCRIPTION -> {
|
||||
if (content != null) {
|
||||
description = content.trim();
|
||||
case TAG_GARMIN_TPX_EXTENSION_TEMPERATURE -> {
|
||||
if (content != null) {
|
||||
temperature = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_TYPE -> { //Track or Marker/WPT
|
||||
if (content != null) {
|
||||
// In older version this might be localized content.
|
||||
activityType = content.trim();
|
||||
markerType = content.trim();
|
||||
case TAG_GARMIN_TPX_EXTENSION_CADENCE -> {
|
||||
if (content != null) {
|
||||
cadence = content.trim();
|
||||
}
|
||||
}
|
||||
default -> Log.w(TAG, "Unknown Garmin trackpoint extension tag " + localName);
|
||||
}
|
||||
case TAG_TYPE_LOCALIZED -> {
|
||||
if (content != null) {
|
||||
activityTypeLocalized = content.trim();
|
||||
} else if (NS_GARMIN_POWER_EXTENSION_V1.equals(uri)) {
|
||||
//noinspection SwitchStatementWithTooFewBranches
|
||||
switch (localName) {
|
||||
case TAG_GARMIN_PWR_EXTENSION_POWER -> {
|
||||
if (content != null) {
|
||||
power = content.trim();
|
||||
}
|
||||
}
|
||||
default -> Log.w(TAG, "Unknown Garmin power extension tag " + localName);
|
||||
}
|
||||
case TAG_TIME -> {
|
||||
if (content != null) {
|
||||
time = content.trim();
|
||||
} else if (NS_OPENTRACKS.equals(uri)) {
|
||||
switch (localName) {
|
||||
case TAG_OPENTRACKS_EXTENSION_TRACK_ID -> {
|
||||
if (content != null) {
|
||||
uuid = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_ALTITUDE -> {
|
||||
if (content != null) {
|
||||
altitude = content.trim();
|
||||
case TAG_OPENTRACKS_EXTENSION_TYPE_LOCALIZED -> {
|
||||
if (content != null) {
|
||||
activityTypeLocalized = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_SPEED, TAG_EXTENSION_SPEED_COMPAT -> {
|
||||
if (content != null) {
|
||||
speed = content.trim();
|
||||
case TAG_OPENTRACKS_EXTENSION_GAIN -> {
|
||||
if (content != null) {
|
||||
gain = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_HEARTRATE -> {
|
||||
if (content != null) {
|
||||
heartrate = content.trim();
|
||||
case TAG_OPENTRACKS_EXTENSION_LOSS -> {
|
||||
if (content != null) {
|
||||
loss = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_TEMPERATURE -> {
|
||||
if (content != null) {
|
||||
temperature = content.trim();
|
||||
case TAG_OPENTRACKS_EXTENSION_DISTANCE -> {
|
||||
if (content != null) {
|
||||
sensorDistance = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_CADENCE -> {
|
||||
if (content != null) {
|
||||
cadence = content.trim();
|
||||
case TAG_OPENTRACKS_EXTENSION_ACCURACY_HORIZONTAL -> {
|
||||
if (content != null) {
|
||||
accuracyHorizontal = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_POWER -> {
|
||||
if (content != null) {
|
||||
power = content.trim();
|
||||
case TAG_OPENTRACKS_EXTENSION_ACCURACY_VERTICAL -> {
|
||||
if (content != null) {
|
||||
accuracyVertical = content.trim();
|
||||
}
|
||||
}
|
||||
default -> Log.w(TAG, "Unknown OpenTracks extension tag " + localName);
|
||||
}
|
||||
case TAG_ID -> {
|
||||
if (content != null) {
|
||||
uuid = content.trim();
|
||||
} else {
|
||||
switch (qName) {
|
||||
case TAG_GPX -> onFileEnd();
|
||||
case TAG_MARKER -> onMarkerEnd();
|
||||
case TAG_TRACK -> {
|
||||
if (activityTypeLocalized == null) {
|
||||
// Backward compatibility: up v4.9.1 as <type> contained localized content.
|
||||
activityTypeLocalized = activityType;
|
||||
}
|
||||
trackImporter.setTrackData(context, name, uuid, description, activityTypeLocalized, activityType, zoneOffset);
|
||||
zoneOffset = null;
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_GAIN -> {
|
||||
if (content != null) {
|
||||
gain = content.trim();
|
||||
case TAG_TRACK_SEGMENT -> onTrackSegmentEnd();
|
||||
case TAG_TRACK_POINT -> {
|
||||
TrackPoint trackPoint = createTrackPoint();
|
||||
if (trackPoint != null) currentSegment.add(trackPoint);
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_LOSS -> {
|
||||
if (content != null) {
|
||||
loss = content.trim();
|
||||
case TAG_NAME -> {
|
||||
if (content != null) {
|
||||
name = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_DISTANCE -> {
|
||||
if (content != null) {
|
||||
sensorDistance = content.trim();
|
||||
case TAG_DESCRIPTION -> {
|
||||
if (content != null) {
|
||||
description = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_ACCURACY_HORIZONTAL -> {
|
||||
if (content != null) {
|
||||
accuracyHorizontal = content.trim();
|
||||
case TAG_TYPE -> { //Track or Marker/WPT
|
||||
if (content != null) {
|
||||
// In older version this might be localized content.
|
||||
activityType = content.trim();
|
||||
markerType = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_ACCURACY_VERTICAL -> {
|
||||
if (content != null) {
|
||||
accuracyVertical = content.trim();
|
||||
case TAG_TIME -> {
|
||||
if (content != null) {
|
||||
time = content.trim();
|
||||
}
|
||||
}
|
||||
case TAG_ALTITUDE -> {
|
||||
if (content != null) {
|
||||
altitude = content.trim();
|
||||
}
|
||||
}
|
||||
case TAG_EXTENSION_SPEED_COMPAT -> {
|
||||
if (content != null) {
|
||||
speed = content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,8 +326,10 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
currentSegment.clear();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private TrackPoint createTrackPoint() throws ParsingException {
|
||||
if (TextUtils.isEmpty(time)) return null;
|
||||
|
||||
OffsetDateTime parsedTime;
|
||||
try {
|
||||
parsedTime = StringUtils.parseTime(time);
|
||||
@@ -468,7 +512,10 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
}
|
||||
|
||||
TrackPoint trackPoint = createTrackPoint();
|
||||
|
||||
if (trackPoint == null) {
|
||||
Log.w(TAG, "Marker with no TrackPoint");
|
||||
return;
|
||||
}
|
||||
if (!trackPoint.position().hasLocation()) {
|
||||
Log.w(TAG, "Marker with invalid coordinates ignored: " + trackPoint.position());
|
||||
return;
|
||||
|
||||
@@ -146,8 +146,8 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String tag, Attributes attributes) throws SAXException {
|
||||
switch (tag) {
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
switch (qName) {
|
||||
case TAG_PLACEMARK, TAG_PHOTO_OVERLAY ->
|
||||
// Note that a track is contained in a Placemark, calling onMarkerStart will clear various track variables like name, typeLocalized, and description.
|
||||
onMarkerStart();
|
||||
@@ -168,8 +168,8 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String tag) throws SAXException {
|
||||
switch (tag) {
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
switch (qName) {
|
||||
case TAG_KML -> onFileEnd();
|
||||
case TAG_PLACEMARK, TAG_PHOTO_OVERLAY ->
|
||||
// Note that a track is contained in a Placemark, calling onMarkerEnd is save since markerType is not set for a track.
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package de.dennisguse.opentracks.io.healthconnect.exporter;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.health.connect.client.HealthConnectClient;
|
||||
import androidx.health.connect.client.PermissionController;
|
||||
import androidx.health.connect.client.permission.HealthPermission;
|
||||
import androidx.health.connect.client.records.DistanceRecord;
|
||||
import androidx.health.connect.client.records.ElevationGainedRecord;
|
||||
import androidx.health.connect.client.records.ExerciseSessionRecord;
|
||||
import androidx.health.connect.client.records.SpeedRecord;
|
||||
import androidx.work.Data;
|
||||
import androidx.work.ExistingWorkPolicy;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
import androidx.work.WorkRequest;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
import kotlin.coroutines.Continuation;
|
||||
import kotlin.jvm.JvmClassMappingKt;
|
||||
import kotlin.jvm.functions.Function2;
|
||||
import kotlinx.coroutines.BuildersKt;
|
||||
|
||||
/**
|
||||
* Exports a single track as an ExerciseSession to Health Connect.
|
||||
* Uses the Track.uuid as clientRecordId to prevent duplicates on re-export.
|
||||
*/
|
||||
public class HealthConnectUtils {
|
||||
|
||||
public static final Set<String> PERMISSIONS = Set.of(
|
||||
HealthPermission.getWritePermission(JvmClassMappingKt.getKotlinClass(ExerciseSessionRecord.class)),
|
||||
HealthPermission.getWritePermission(JvmClassMappingKt.getKotlinClass(DistanceRecord.class)),
|
||||
HealthPermission.getWritePermission(JvmClassMappingKt.getKotlinClass(ElevationGainedRecord.class)),
|
||||
HealthPermission.getWritePermission(JvmClassMappingKt.getKotlinClass(SpeedRecord.class)),
|
||||
HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE
|
||||
);
|
||||
|
||||
private HealthConnectUtils() {
|
||||
}
|
||||
|
||||
public static boolean isAvailable(Context context) {
|
||||
return HealthConnectClient.getSdkStatus(context) == HealthConnectClient.SDK_AVAILABLE;
|
||||
}
|
||||
|
||||
public static Set<String> getGrantedPermissions(Context context) {
|
||||
if (!isAvailable(context))
|
||||
return Set.of();
|
||||
|
||||
try {
|
||||
HealthConnectClient client = HealthConnectClient.getOrCreate(context);
|
||||
PermissionController controller = client.getPermissionController();
|
||||
|
||||
return (Set<String>) BuildersKt.runBlocking(
|
||||
kotlin.coroutines.EmptyCoroutineContext.INSTANCE,
|
||||
(Function2) (scope, cont) -> controller.getGrantedPermissions((Continuation) cont));
|
||||
} catch (InterruptedException e) {
|
||||
return Set.of();
|
||||
}
|
||||
}
|
||||
|
||||
static boolean hasRequiredPermissions(Context context) {
|
||||
return getGrantedPermissions(context)
|
||||
.containsAll(PERMISSIONS);
|
||||
}
|
||||
|
||||
public static void postExportTrack(Context context, Track.Id trackId) {
|
||||
if (!PreferencesUtils.shouldInstantExportToHealthConnect()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkRequest request = new OneTimeWorkRequest.Builder(HealthConnectWorker.class)
|
||||
.addTag(HealthConnectWorker.WORK_TAG)
|
||||
.setInputData(new Data.Builder()
|
||||
.putLong(HealthConnectWorker.TRACK_ID_KEY, trackId.id())
|
||||
.build())
|
||||
.build();
|
||||
WorkManager.getInstance(context).enqueue(request);
|
||||
}
|
||||
|
||||
public static void postExportAll(Context context) {
|
||||
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(HealthConnectWorker.class)
|
||||
.addTag(HealthConnectWorker.WORK_TAG)
|
||||
.build();
|
||||
|
||||
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||
HealthConnectWorker.WORK_TAG,
|
||||
ExistingWorkPolicy.REPLACE,
|
||||
request
|
||||
);
|
||||
}
|
||||
|
||||
public static void cancelHealthConnectExport(Context context) {
|
||||
WorkManager workManager = WorkManager.getInstance(context);
|
||||
workManager.cancelAllWorkByTag(HealthConnectWorker.WORK_TAG);
|
||||
}
|
||||
}
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
package de.dennisguse.opentracks.io.healthconnect.exporter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.health.connect.client.HealthConnectClient;
|
||||
import androidx.health.connect.client.records.DistanceRecord;
|
||||
import androidx.health.connect.client.records.ElevationGainedRecord;
|
||||
import androidx.health.connect.client.records.ExerciseRoute;
|
||||
import androidx.health.connect.client.records.ExerciseSessionRecord;
|
||||
import androidx.health.connect.client.records.Record;
|
||||
import androidx.health.connect.client.records.SpeedRecord;
|
||||
import androidx.health.connect.client.records.metadata.Device;
|
||||
import androidx.health.connect.client.records.metadata.Metadata;
|
||||
import androidx.health.connect.client.units.Length;
|
||||
import androidx.health.connect.client.units.Velocity;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.data.models.Position;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
import kotlin.coroutines.Continuation;
|
||||
import kotlin.jvm.functions.Function2;
|
||||
import kotlinx.coroutines.BuildersKt;
|
||||
|
||||
/**
|
||||
* Exports a single track as an ExerciseSession to Health Connect.
|
||||
* Uses the Track.uuid as clientRecordId to prevent duplicates on re-export.
|
||||
*/
|
||||
//TODO add reasons for failures (if shown in the UI: must be localized)
|
||||
//TODO Export sensor data (permissions needed)
|
||||
//TODO Show progress: like ExportActivity? Or use a notification (aka handle it as a background process)
|
||||
public class HealthConnectWorker extends Worker {
|
||||
|
||||
private static final String TAG = HealthConnectWorker.class.getSimpleName();
|
||||
static final String WORK_TAG = "HealthConnectSync";
|
||||
|
||||
static final String TRACK_ID_KEY = "trackId";
|
||||
|
||||
public HealthConnectWorker(Context context, WorkerParameters params) {
|
||||
super(context, params);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
if (!HealthConnectUtils.isAvailable(getApplicationContext())) {
|
||||
Log.w(TAG, "Health Connect SDK not available");
|
||||
return Result.failure();
|
||||
}
|
||||
|
||||
//TODO If not all permissions are granted, export the data that was granted.
|
||||
if (!HealthConnectUtils.hasRequiredPermissions(getApplicationContext())) {
|
||||
Log.w(TAG, "Health Connect required permissions not granted");
|
||||
return Result.failure();
|
||||
}
|
||||
|
||||
Track.Id trackId = new Track.Id(getInputData().getLong(TRACK_ID_KEY, -1L));
|
||||
if (trackId.id() != -1L) {
|
||||
return exportTrack(trackId);
|
||||
}
|
||||
return exportAll();
|
||||
}
|
||||
|
||||
private Result exportTrack(Track.Id trackId) {
|
||||
try {
|
||||
export(getApplicationContext(), trackId);
|
||||
return Result.success();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return Result.retry();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Health Connect export failed for track " + trackId, e);
|
||||
return Result.failure();
|
||||
}
|
||||
}
|
||||
|
||||
private Result exportAll() {
|
||||
List<Track> allTracks = new ContentProviderUtils(getApplicationContext())
|
||||
.getTracks();
|
||||
|
||||
for (Track track : allTracks) {
|
||||
if (isStopped()) {
|
||||
Log.i(TAG, "Initial Health Connect sync stopped by WorkManager");
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
try {
|
||||
export(getApplicationContext(), track.id());
|
||||
} catch (InterruptedException e) {
|
||||
return Result.retry();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Initial Health Connect sync failed for track " + track.id().id(), e);
|
||||
return Result.failure();
|
||||
}
|
||||
}
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
private static ExportResult export(Context context, Track.Id trackId) throws InterruptedException {
|
||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
if (track == null) {
|
||||
throw new RuntimeException("Track not found: " + trackId);
|
||||
}
|
||||
|
||||
HealthConnectClient client = HealthConnectClient.getOrCreate(context);
|
||||
Metadata metadata = Metadata.activelyRecorded(
|
||||
new Device(Device.TYPE_PHONE, Build.MANUFACTURER, Build.MODEL),
|
||||
track.uuid().toString()
|
||||
);
|
||||
|
||||
List<Record> records = new ArrayList<>();
|
||||
|
||||
ExerciseData exerciseData = createExerciseData(contentProviderUtils, trackId);
|
||||
|
||||
//Avoid bug in HealthConnect: data must be within ExerciseSessionRecord.startTime and ExerciseSessionRecord.stopTime
|
||||
List<ExerciseRoute.Location> locations = exerciseData.locations.stream()
|
||||
.filter(i -> track.startTime().toInstant().isBefore(i.getTime()) && track.stopTime().toInstant().isAfter(i.getTime()))
|
||||
.toList();
|
||||
|
||||
records.add(new ExerciseSessionRecord(
|
||||
track.startTime().toInstant(),
|
||||
track.startTime().getOffset(),
|
||||
track.stopTime().toInstant(),
|
||||
track.stopTime().getOffset(),
|
||||
metadata,
|
||||
toExerciseType(track.activityType()),
|
||||
track.name(),
|
||||
track.description(),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
new ExerciseRoute(locations)));
|
||||
|
||||
records.add(new DistanceRecord(
|
||||
track.startTime().toInstant(),
|
||||
track.startTime().getOffset(),
|
||||
track.stopTime().toInstant(),
|
||||
track.stopTime().getOffset(),
|
||||
Length.meters(track.statistics().totalDistance().toM()),
|
||||
metadata
|
||||
));
|
||||
|
||||
if (track.statistics().altitudeGainLoss() != null) {
|
||||
records.add(new ElevationGainedRecord(
|
||||
track.startTime().toInstant(),
|
||||
track.startTime().getOffset(),
|
||||
track.stopTime().toInstant(),
|
||||
track.stopTime().getOffset(),
|
||||
Length.meters(track.statistics().altitudeGainLoss().gain_m()),
|
||||
metadata
|
||||
));
|
||||
}
|
||||
|
||||
if (!exerciseData.speeds.isEmpty()) {
|
||||
records.add(new SpeedRecord(
|
||||
track.startTime().toInstant(),
|
||||
track.startTime().getOffset(),
|
||||
track.stopTime().toInstant(),
|
||||
track.stopTime().getOffset(),
|
||||
exerciseData.speeds,
|
||||
metadata
|
||||
));
|
||||
}
|
||||
|
||||
Object ignored = BuildersKt.runBlocking(
|
||||
kotlin.coroutines.EmptyCoroutineContext.INSTANCE,
|
||||
(Function2) (scope, cont) -> client.insertRecords(records, (Continuation) cont));
|
||||
|
||||
Log.i(TAG, "Exported track to Health Connect: " + track.name());
|
||||
return new ExportResult(track.name());
|
||||
}
|
||||
|
||||
private static ExerciseData createExerciseData(ContentProviderUtils contentProviderUtils, Track.Id trackId) {
|
||||
List<ExerciseRoute.Location> locations = new LinkedList<>();
|
||||
List<SpeedRecord.Sample> speeds = new LinkedList<>();
|
||||
|
||||
try (TrackPointIterator iterator = contentProviderUtils.getTrackPointIterator(trackId, null)) {
|
||||
while (iterator.hasNext()) { //TODO iterator.iterator.forEachRemaining()
|
||||
TrackPoint trackPoint = iterator.next();
|
||||
if (trackPoint.type() != TrackPoint.Type.TRACKPOINT) continue; //TODO Include SEGMENT_START_AUTOMATIC?
|
||||
|
||||
Position position = trackPoint.position();
|
||||
|
||||
if (position.hasLocation()) {
|
||||
//ExcerciseRoute does not allow duplicated timestamps.
|
||||
if (locations.stream().noneMatch(location -> location.getTime().equals(position.time()))) {
|
||||
locations.add(new ExerciseRoute.Location(
|
||||
trackPoint.getTime(),
|
||||
position.latitude(),
|
||||
position.longitude(),
|
||||
position.horizontalAccuracy() != null ? Length.meters(position.horizontalAccuracy().toM()) : null,
|
||||
position.verticalAccuracy() != null ? Length.meters(position.verticalAccuracy().toM()) : null,
|
||||
position.altitude() != null ? Length.meters(position.altitude().toM()) : null)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (position.hasSpeed()) {
|
||||
speeds.add(new SpeedRecord.Sample(
|
||||
trackPoint.getTime(),
|
||||
Velocity.metersPerSecond(position.speed().toMPS())
|
||||
));
|
||||
}
|
||||
|
||||
//TODO Cadence
|
||||
//TODO Power
|
||||
//TODO Heartrate
|
||||
}
|
||||
}
|
||||
|
||||
return new ExerciseData(locations, speeds);
|
||||
}
|
||||
|
||||
private record ExerciseData(
|
||||
List<ExerciseRoute.Location> locations,
|
||||
List<SpeedRecord.Sample> speeds
|
||||
) {}
|
||||
|
||||
|
||||
private static int toExerciseType(ActivityType activityType) {
|
||||
return switch (activityType) {
|
||||
case RUNNING, STREET_RUNNING, TRAIL_RUNNING, TRACK_RUNNING -> ExerciseSessionRecord.EXERCISE_TYPE_RUNNING;
|
||||
case BIKING, CYCLING, ROAD_BIKING, MOUNTAIN_BIKING, TRACK_CYCLING -> ExerciseSessionRecord.EXERCISE_TYPE_BIKING;
|
||||
case WALKING, SPEED_WALKING -> ExerciseSessionRecord.EXERCISE_TYPE_WALKING;
|
||||
case HIKING, OFF_TRAIL_HIKING, TRAIL_HIKING -> ExerciseSessionRecord.EXERCISE_TYPE_HIKING;
|
||||
case CROSS_COUNTRY_SKIING, SKIING -> ExerciseSessionRecord.EXERCISE_TYPE_SKIING;
|
||||
case SNOW_BOARDING -> ExerciseSessionRecord.EXERCISE_TYPE_SNOWBOARDING;
|
||||
case KAYAKING -> ExerciseSessionRecord.EXERCISE_TYPE_PADDLING;
|
||||
case ROWING -> ExerciseSessionRecord.EXERCISE_TYPE_ROWING_MACHINE;
|
||||
case SWIMMING -> ExerciseSessionRecord.EXERCISE_TYPE_SWIMMING_POOL;
|
||||
case SWIMMING_OPEN -> ExerciseSessionRecord.EXERCISE_TYPE_SWIMMING_OPEN_WATER;
|
||||
default -> ExerciseSessionRecord.EXERCISE_TYPE_OTHER_WORKOUT;
|
||||
};
|
||||
}
|
||||
|
||||
public record ExportResult(String trackName) {
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,9 @@ public class GpsHandler extends SensorHandler<Location, Position> {
|
||||
gpsStatusManager.onMinSamplingIntervalChanged(PreferencesUtils.getMinSamplingInterval());
|
||||
}
|
||||
|
||||
//TODO
|
||||
connect();
|
||||
if (driver != null) {
|
||||
driver.updateDriverParameters(getContext(), sensorManager.getHandler());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -20,8 +20,6 @@ import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
*/
|
||||
class GpsStatusManager {
|
||||
|
||||
private static final String TAG = GpsStatusManager.class.getSimpleName();
|
||||
|
||||
// The duration that GpsStatus waits from minimal interval to consider GPS lost.
|
||||
@VisibleForTesting
|
||||
public static final Duration SIGNAL_LOST_THRESHOLD = Duration.ofSeconds(30);
|
||||
|
||||
@@ -21,11 +21,11 @@ public abstract class SensorHandler<AggregatorInput, AggregatorOutput> implement
|
||||
|
||||
private static final String TAG = SensorHandler.class.getSimpleName();
|
||||
|
||||
private final SensorManager sensorManager;
|
||||
|
||||
@VisibleForTesting
|
||||
public Driver driver;
|
||||
|
||||
protected final SensorManager sensorManager;
|
||||
|
||||
protected Aggregator<AggregatorInput, AggregatorOutput> aggregator;
|
||||
|
||||
protected SensorHandler(SensorManager sensorManager) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
@@ -98,7 +99,7 @@ public final class BoschEbikeParser {
|
||||
.filter(BoschEbikeParser::isValidFrame)
|
||||
.filter(BoschEbikeParser::isSupportedFrame)
|
||||
.map(BoschEbikeParser::decodeFrame)
|
||||
.filter(decodedFrame -> decodedFrame != null)
|
||||
.filter(Objects::nonNull)
|
||||
.reduce(null,
|
||||
BoschEbikeParser::processMessage,
|
||||
(left, right) -> right);
|
||||
|
||||
@@ -11,5 +11,9 @@ public interface Driver {
|
||||
//TODO Remove from interface?
|
||||
boolean isConnected();
|
||||
|
||||
default void updateDriverParameters(Context context, Handler handler) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
void disconnect();
|
||||
}
|
||||
|
||||
@@ -57,16 +57,11 @@ public class GpsInternal implements Driver {
|
||||
return;
|
||||
}
|
||||
|
||||
LocationRequestCompat locationRequest = new LocationRequestCompat.Builder(PreferencesUtils.getMinSamplingInterval().toMillis())
|
||||
.setQuality(LocationRequestCompat.QUALITY_HIGH_ACCURACY)
|
||||
.setMaxUpdateDelayMillis(0)
|
||||
.build();
|
||||
|
||||
if (PermissionRequester.GPS.hasPermission(context)) {
|
||||
try {
|
||||
Log.i(TAG, "Register for location updates " + context);
|
||||
Log.i(TAG, "Register for location updates");
|
||||
driverObserver.onConnected(null, null);
|
||||
LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, locationRequest, handler::post, locationListenerCompat);
|
||||
LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, createLocationRequest(), handler::post, locationListenerCompat);
|
||||
return;
|
||||
} catch (SecurityException e) {
|
||||
Log.e(TAG, "Could not register location listener; permissions not granted.", e);
|
||||
@@ -76,6 +71,16 @@ public class GpsInternal implements Driver {
|
||||
driverObserver.onDisconnected();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"MissingPermission"})
|
||||
@Override
|
||||
public void updateDriverParameters(Context context, Handler handler) {
|
||||
if (!isConnected()) return;
|
||||
|
||||
Log.i(TAG, "Update for location updates");
|
||||
driverObserver.onConnected(null, null);
|
||||
LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, createLocationRequest(), handler::post, locationListenerCompat);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"MissingPermission"})
|
||||
@Override
|
||||
public void disconnect() {
|
||||
@@ -87,9 +92,15 @@ public class GpsInternal implements Driver {
|
||||
driverObserver.onDisconnected();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return locationManager != null;
|
||||
}
|
||||
|
||||
private LocationRequestCompat createLocationRequest() {
|
||||
return new LocationRequestCompat.Builder(PreferencesUtils.getMinSamplingInterval().toMillis())
|
||||
.setQuality(LocationRequestCompat.QUALITY_HIGH_ACCURACY)
|
||||
.setMaxUpdateDelayMillis(0)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,12 +63,13 @@ public abstract class Aggregator<InputType, OutputType> {
|
||||
*/
|
||||
protected void resetOutdated() {
|
||||
output = null;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset long-term (i.e., aggregated) values (more than derived from previous SensorData) like overall distance.
|
||||
*/
|
||||
public void resetAggregated() {};
|
||||
public void resetAggregated() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the data recent considering the current time.
|
||||
|
||||
@@ -120,6 +120,7 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
|
||||
}
|
||||
|
||||
synchronized void endCurrentTrack() {
|
||||
handler.removeCallbacks(ON_IDLE);
|
||||
TrackPoint segmentEnd = trackPointCreator.createSegmentEnd();
|
||||
insertTrackPoint(segmentEnd, true);
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package de.dennisguse.opentracks.settings;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.health.connect.client.HealthConnectClient;
|
||||
import androidx.health.connect.client.PermissionController;
|
||||
|
||||
import de.dennisguse.opentracks.io.healthconnect.exporter.HealthConnectUtils;
|
||||
|
||||
public class HealthConnect {
|
||||
|
||||
public static class Settings extends AppCompatActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
startActivity(new Intent(HealthConnectClient.getHealthConnectSettingsAction()));
|
||||
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfigurePermissions extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (!HealthConnectUtils.isAvailable(this)) {
|
||||
finish();
|
||||
}
|
||||
|
||||
registerForActivityResult(
|
||||
PermissionController.createRequestPermissionResultContract(),
|
||||
grantedPermissions -> {
|
||||
// TODO User feedback via Toast.makeText()?
|
||||
finish();
|
||||
}
|
||||
).launch(HealthConnectUtils.PERMISSIONS);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExportAll extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
HealthConnectUtils.postExportAll(this);
|
||||
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,11 @@ import java.util.Map;
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.TrackFilenameGenerator;
|
||||
import de.dennisguse.opentracks.io.healthconnect.exporter.HealthConnectUtils;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
|
||||
public class ImportExportSettingsFragment extends PreferenceFragmentCompat {
|
||||
|
||||
private static final String TAG = ImportExportSettingsFragment.class.getSimpleName();
|
||||
public class ImportExportSettingsFragment extends PreferenceFragmentCompat {
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
@@ -40,9 +40,20 @@ public class ImportExportSettingsFragment extends PreferenceFragmentCompat {
|
||||
super.onResume();
|
||||
|
||||
setExportDirectorySummary();
|
||||
findPreference(getString(R.string.post_workout_export_enabled_key)).setEnabled(PreferencesUtils.isDefaultExportDirectoryUri());
|
||||
|
||||
Preference instantExportEnabledPreference = findPreference(getString(R.string.post_workout_export_enabled_key));
|
||||
instantExportEnabledPreference.setEnabled(PreferencesUtils.isDefaultExportDirectoryUri());
|
||||
setHealthConnectPreference();
|
||||
}
|
||||
|
||||
private void setHealthConnectPreference() {
|
||||
boolean healthConnectAvailable = HealthConnectUtils.isAvailable(requireContext());
|
||||
findPreference("healthConnectCategory")
|
||||
.setEnabled(healthConnectAvailable);
|
||||
|
||||
if (!healthConnectAvailable) {
|
||||
findPreference(getString(R.string.post_workout_export_health_connect_enabled_key))
|
||||
.setSummary(R.string.health_connect_not_available);
|
||||
}
|
||||
}
|
||||
|
||||
private void setExportTrackFileFormatOptions() {
|
||||
|
||||
@@ -168,23 +168,38 @@ public class PreferencesUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static long getLong(int keyId, long defaultValue) {
|
||||
try {
|
||||
return sharedPreferences.getLong(getKey(keyId), defaultValue);
|
||||
} catch (ClassCastException e) {
|
||||
// Ignore.
|
||||
}
|
||||
|
||||
try {
|
||||
String stringValue = sharedPreferences.getString(getKey(keyId), null);
|
||||
return Long.parseLong(stringValue);
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getString(int keyId, String defaultValue) {
|
||||
return sharedPreferences.getString(getKey(keyId), defaultValue);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||
public static void setString(int keyId, String value) {
|
||||
Editor editor = sharedPreferences.edit();
|
||||
editor.putString(getKey(keyId), value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||
public static void setString(int keyId, int valueId) {
|
||||
setString(keyId, resources.getString(valueId));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||
public static void setBoolean(int keyId, Boolean value) {
|
||||
Editor editor = sharedPreferences.edit();
|
||||
editor.putBoolean(getKey(keyId), value);
|
||||
@@ -197,6 +212,12 @@ public class PreferencesUtils {
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
private static void setLong(int keyId, long value) {
|
||||
Editor editor = sharedPreferences.edit();
|
||||
editor.putLong(getKey(keyId), value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static boolean isPublicAPIenabled() {
|
||||
return getBoolean(R.string.publicapi_enabled_key, resources.getBoolean(R.bool.publicapi_enabled_default));
|
||||
}
|
||||
@@ -427,7 +448,7 @@ public class PreferencesUtils {
|
||||
}
|
||||
|
||||
public static boolean shouldVoiceAnnounceLapPower() {
|
||||
return getBoolean(R.string.voice_announce_lap_power_key, false);
|
||||
return getBoolean(R.string.voice_announce_lap_power_key, getBoolean(R.bool.voice_announce_lap_power_default, false));
|
||||
}
|
||||
|
||||
public static boolean shouldVoiceAnnounceHeartRateCurrent() {
|
||||
@@ -518,6 +539,7 @@ public class PreferencesUtils {
|
||||
String[] entries = new String[entryValues.length];
|
||||
|
||||
final int maxRecordingDistanceDefault = Integer.parseInt(resources.getString(R.string.max_recording_distance_default));
|
||||
final int maxRecordingDistanceOff = Integer.parseInt(resources.getString(R.string.max_recording_distance_off));
|
||||
UnitSystem unitSystem = getUnitSystem();
|
||||
|
||||
DistanceFormatter formatter = DistanceFormatter.Builder()
|
||||
@@ -534,6 +556,9 @@ public class PreferencesUtils {
|
||||
case METRIC, IMPERIAL_METER -> {
|
||||
if (value == maxRecordingDistanceDefault) {
|
||||
entries[i] = resources.getString(R.string.value_integer_meter_recommended, value);
|
||||
}
|
||||
if (value == maxRecordingDistanceOff) {
|
||||
entries[i] = resources.getString(R.string.value_off);
|
||||
} else {
|
||||
entries[i] = displayValue;
|
||||
}
|
||||
@@ -541,6 +566,9 @@ public class PreferencesUtils {
|
||||
case IMPERIAL_FEET, NAUTICAL_IMPERIAL -> {
|
||||
if (value == maxRecordingDistanceDefault) {
|
||||
entries[i] = resources.getString(R.string.value_integer_feet_recommended, (int) distance.toFT());
|
||||
}
|
||||
if (value == maxRecordingDistanceOff) {
|
||||
entries[i] = resources.getString(R.string.value_off);
|
||||
} else {
|
||||
entries[i] = displayValue;
|
||||
}
|
||||
@@ -660,12 +688,16 @@ public class PreferencesUtils {
|
||||
return entries;
|
||||
}
|
||||
|
||||
|
||||
public static boolean shouldInstantExportAfterWorkout() {
|
||||
public static boolean shouldInstantExportToFile() {
|
||||
final boolean INSTANT_POST_WORKOUT_EXPORT_DEFAULT = resources.getBoolean(R.bool.post_workout_export_enabled_default);
|
||||
return getBoolean(R.string.post_workout_export_enabled_key, INSTANT_POST_WORKOUT_EXPORT_DEFAULT) && isDefaultExportDirectoryUri();
|
||||
}
|
||||
|
||||
public static boolean shouldInstantExportToHealthConnect() {
|
||||
final boolean DEFAULT = resources.getBoolean(R.bool.post_workout_export_health_connect_enabled_default);
|
||||
return getBoolean(R.string.post_workout_export_health_connect_enabled_key, DEFAULT);
|
||||
}
|
||||
|
||||
public static TrackFilenameGenerator getTrackFileformatGenerator() {
|
||||
String DEFAULT = resources.getString(R.string.export_filename_format_default);
|
||||
TrackFilenameGenerator generator = new TrackFilenameGenerator(getString(R.string.export_filename_format_key, DEFAULT));
|
||||
|
||||
@@ -96,6 +96,7 @@ public class BluetoothLeAdapter extends BaseAdapter {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@@ -16,42 +16,42 @@ public class ZoneOffsetAdapter extends ArrayAdapter<ZoneOffset> {
|
||||
super(context, resource);
|
||||
|
||||
addAll(
|
||||
ZoneOffset.ofHoursMinutes(-12, 00),
|
||||
ZoneOffset.ofHoursMinutes(-11, 00),
|
||||
ZoneOffset.ofHoursMinutes(-10, 00),
|
||||
ZoneOffset.ofHoursMinutes(-12, 0),
|
||||
ZoneOffset.ofHoursMinutes(-11, 0),
|
||||
ZoneOffset.ofHoursMinutes(-10, 0),
|
||||
ZoneOffset.ofHoursMinutes(-9, -30),
|
||||
ZoneOffset.ofHoursMinutes(-8, 00),
|
||||
ZoneOffset.ofHoursMinutes(-7, 00),
|
||||
ZoneOffset.ofHoursMinutes(-6, 00),
|
||||
ZoneOffset.ofHoursMinutes(-5, 00),
|
||||
ZoneOffset.ofHoursMinutes(-4, 00),
|
||||
ZoneOffset.ofHoursMinutes(-8, 0),
|
||||
ZoneOffset.ofHoursMinutes(-7, 0),
|
||||
ZoneOffset.ofHoursMinutes(-6, 0),
|
||||
ZoneOffset.ofHoursMinutes(-5, 0),
|
||||
ZoneOffset.ofHoursMinutes(-4, 0),
|
||||
ZoneOffset.ofHoursMinutes(-3, -30),
|
||||
ZoneOffset.ofHoursMinutes(-3, 00),
|
||||
ZoneOffset.ofHoursMinutes(-2, 00),
|
||||
ZoneOffset.ofHoursMinutes(-1, 00),
|
||||
ZoneOffset.ofHoursMinutes(0, 00),
|
||||
ZoneOffset.ofHoursMinutes(1, 00),
|
||||
ZoneOffset.ofHoursMinutes(2, 00),
|
||||
ZoneOffset.ofHoursMinutes(3, 00),
|
||||
ZoneOffset.ofHoursMinutes(-3, 0),
|
||||
ZoneOffset.ofHoursMinutes(-2, 0),
|
||||
ZoneOffset.ofHoursMinutes(-1, 0),
|
||||
ZoneOffset.ofHoursMinutes(0, 0),
|
||||
ZoneOffset.ofHoursMinutes(1, 0),
|
||||
ZoneOffset.ofHoursMinutes(2, 0),
|
||||
ZoneOffset.ofHoursMinutes(3, 0),
|
||||
ZoneOffset.ofHoursMinutes(3, 30),
|
||||
ZoneOffset.ofHoursMinutes(4, 00),
|
||||
ZoneOffset.ofHoursMinutes(4, 0),
|
||||
ZoneOffset.ofHoursMinutes(4, 30),
|
||||
ZoneOffset.ofHoursMinutes(5, 30),
|
||||
ZoneOffset.ofHoursMinutes(5, 45),
|
||||
ZoneOffset.ofHoursMinutes(6, 00),
|
||||
ZoneOffset.ofHoursMinutes(6, 0),
|
||||
ZoneOffset.ofHoursMinutes(6, 30),
|
||||
ZoneOffset.ofHoursMinutes(7, 00),
|
||||
ZoneOffset.ofHoursMinutes(8, 00),
|
||||
ZoneOffset.ofHoursMinutes(7, 0),
|
||||
ZoneOffset.ofHoursMinutes(8, 0),
|
||||
ZoneOffset.ofHoursMinutes(8, 45),
|
||||
ZoneOffset.ofHoursMinutes(9, 00),
|
||||
ZoneOffset.ofHoursMinutes(9, 0),
|
||||
ZoneOffset.ofHoursMinutes(9, 30),
|
||||
ZoneOffset.ofHoursMinutes(10, 00),
|
||||
ZoneOffset.ofHoursMinutes(10, 0),
|
||||
ZoneOffset.ofHoursMinutes(10, 30),
|
||||
ZoneOffset.ofHoursMinutes(11, 00),
|
||||
ZoneOffset.ofHoursMinutes(12, 00),
|
||||
ZoneOffset.ofHoursMinutes(11, 0),
|
||||
ZoneOffset.ofHoursMinutes(12, 0),
|
||||
ZoneOffset.ofHoursMinutes(12, 45),
|
||||
ZoneOffset.ofHoursMinutes(13, 00),
|
||||
ZoneOffset.ofHoursMinutes(14, 00)
|
||||
ZoneOffset.ofHoursMinutes(13, 0),
|
||||
ZoneOffset.ofHoursMinutes(14, 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
-6
@@ -136,12 +136,6 @@ public class FilterDialogFragment extends DialogFragment {
|
||||
public final String value;
|
||||
public boolean isChecked;
|
||||
|
||||
public FilterItem(String id, String value) {
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
this.isChecked = true;
|
||||
}
|
||||
|
||||
public FilterItem(String id, String value, boolean isChecked) {
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
|
||||
@@ -17,12 +17,12 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.CustomContentProvider;
|
||||
import de.dennisguse.opentracks.data.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.Statistics;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.settings.UnitSystem;
|
||||
|
||||
/**
|
||||
@@ -85,7 +85,7 @@ public class IntervalStatisticsModel extends AndroidViewModel {
|
||||
loadIntervalStatistics(trackId);
|
||||
}
|
||||
};
|
||||
contentResolver.registerContentObserver(TrackPointsColumns.CONTENT_URI_BY_TRACKID, false, trackPointsTableObserver);
|
||||
contentResolver.registerContentObserver(CustomContentProvider.UrlType.TRACKPOINTS_BY_TRACKID.getUri(), false, trackPointsTableObserver);
|
||||
|
||||
return intervalsLiveData;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package de.dennisguse.opentracks.util;
|
||||
import android.database.Cursor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
@@ -54,7 +53,6 @@ public abstract class AutoCloseableIterator<T> implements Iterator<T>, AutoClose
|
||||
return get();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public final int getCount() {
|
||||
return cursor.getCount();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -105,10 +104,6 @@ public class FileUtils {
|
||||
return fileName.substring(index + 1);
|
||||
}
|
||||
|
||||
public static String getExtension(DocumentFile file) {
|
||||
return getExtension(file.getName());
|
||||
}
|
||||
|
||||
public static String getExtension(Uri uri) {
|
||||
return getExtension(uri.toString());
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@ public class IntentUtils {
|
||||
|
||||
private static final String TAG = IntentUtils.class.getSimpleName();
|
||||
|
||||
private static final String JPEG_EXTENSION = "jpeg";
|
||||
|
||||
private IntentUtils() {
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ public class StringUtils {
|
||||
* @param text the given text
|
||||
*/
|
||||
public static String formatCData(String text) {
|
||||
return "<![CDATA[" + text.replaceAll("]]>", "]]]]><![CDATA[>") + "]]>";
|
||||
return "<![CDATA[" + text.replace("]]>", "]]]]><![CDATA[>") + "]]>";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/health_connect_activity_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:title="@string/app_name" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="20dp"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
style="?attr/textAppearanceHeadline6"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/health_connect_permissions_rationale_heading" />
|
||||
|
||||
<TextView
|
||||
style="?attr/textAppearanceBody1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/health_connect_permissions_rationale_summary" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">في انتظار إشارة أفضل لنظام تحديد المواقع العالمي (GPS)</string>
|
||||
<string name="gps_wait_for_signal">في انتظار إشارة نظام تحديد المواقع العالمي (GPS)</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">سهم</string>
|
||||
<string name="image_marker_count">عدد العلامات</string>
|
||||
<string name="image_photo_marker">علامة الصورة</string>
|
||||
<string name="image_record">تسجيل</string>
|
||||
@@ -386,7 +385,6 @@ limitations under the License.
|
||||
<item quantity="many">اكتمل مع %1$d خطأ</item>
|
||||
<item quantity="other">اكتمل مع %1$d خطأ</item>
|
||||
</plurals>
|
||||
<string name="voice_announce_lap_power_key">الإعلان الصوتي عن قوة اللفة voiceAnnounceLapPower</string>
|
||||
<string name="settings_defaults_title">الوحدات الافتراضية والنشاط</string>
|
||||
<string name="settings_defaults_summary">الوحدات المفضلة، النشاط الافتراضي، اسم المسار الافتراضي</string>
|
||||
<string name="settings_announcements_summary">الوقت، المسافة، سرعة الصوت</string>
|
||||
@@ -457,7 +455,7 @@ limitations under the License.
|
||||
<string name="settings_recording_title">التسجيل</string>
|
||||
<string name="settings_public_api_enabled_title">واجهة برمجة التطبيقات العامة</string>
|
||||
<string name="settings_public_api_disabled_toast">واجهة برمجة التطبيقات العامة لـ المسارات المفتوحة معطلة: يمكن تفعيلها في الإعدادات.</string>
|
||||
<string name="settings_export_section">التصدير</string>
|
||||
<string name="settings_export_as_file_section">التصدير</string>
|
||||
<string name="instant_export_enabled_summary">تصدير المسار إلى التخزين بعد انتهاء التسجيل</string>
|
||||
<string name="create_marker_error">غير قادر على إنشاء علامة. حاول مرة أخرى.</string>
|
||||
<string name="sensor_state_heart_rate_avg">متوسط معدل ضربات القلب</string>
|
||||
@@ -503,7 +501,6 @@ limitations under the License.
|
||||
<string name="help_feature_content">* إنشاء مسارات GPS \n* استخدام مستشعر معدل ضربات القلب (Bluetooth LE فقط) \n* إعلانات صوتية (حسب الوقت أو المسافة) \n* إنشاء علامات (بما في ذلك الصور) \n* يعمل بدون اتصال بالإنترنت \n* عرض المسارات على خريطة (انظر أدناه)</string>
|
||||
<string name="settings_recording_fullscreen_on_while_recording_summary">أثناء التسجيل، اعرضه في وضع ملء الشاشة.</string>
|
||||
<string name="settings_gps_summary">الفاصل الزمني، فاصل المسافة، أقصى مسافة، الدقة</string>
|
||||
<string name="open_track_as_trackfileformat">فتح كـ %1$s</string>
|
||||
<string name="sensor_state_power_unit">واط</string>
|
||||
<string name="about_url">صفحة المشروع: <a href="%1$s">%1$s</a></string>
|
||||
<string name="help_data_google_play_services_title">هل يتطلب المسارات المفتوحة استخدام خدمات Google Play؟</string>
|
||||
@@ -548,7 +545,6 @@ limitations under the License.
|
||||
<string name="report_bug">الإبلاغ عن خطأ</string>
|
||||
<string name="show_on_dashboard">واجهة برمجة تطبيقات لوحة تحكم المسارات المفتوحة</string>
|
||||
<string name="show_on_dashboard_not_installed">لا يوجد تطبيق يدعم واجهة برمجة تطبيقات لوحة تحكم المسارات المفتوحة مثبت.</string>
|
||||
<string name="always">دائمًا</string>
|
||||
<string name="settings_announcements_lap_power">طاقة الدورة</string>
|
||||
<string name="power_x_watt">الطاقة {x, plural, =1 {1 واط} other {# واط} }</string>
|
||||
<string name="power">الطاقة</string>
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
<string name="gps_starting">Starting GPS</string>
|
||||
<string name="gps_wait_for_better_signal">Waiting for a better GPS signal</string>
|
||||
<string name="gps_wait_for_signal">Waiting for GPS signal</string>
|
||||
<string name="image_arrow">Arrow</string>
|
||||
<string name="image_marker_count">Marker count</string>
|
||||
<string name="image_photo_marker">Photo marker</string>
|
||||
<string name="image_record">Record</string>
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
<string name="gps_starting">Iniciando GPS</string>
|
||||
<string name="gps_wait_for_better_signal">Esperando una mejor señal de GPS</string>
|
||||
<string name="gps_wait_for_signal">Esperando señal de GPS</string>
|
||||
<string name="image_arrow">Flecha</string>
|
||||
<string name="image_marker_count">Recuento de marcadores</string>
|
||||
<string name="image_photo_marker">Marcador de foto</string>
|
||||
<string name="image_record">Grabar</string>
|
||||
@@ -262,8 +261,8 @@
|
||||
<string name="share_image_subject">Me gustaría compartir una imagen contigo</string>
|
||||
<string name="share_image_body">Creo que esta imagen podría interesarte.</string>
|
||||
<string name="about_preference_title">Acerca de OpenTracks</string>
|
||||
<string name="about_description"><i> OpenTracks </i> es una aplicación de seguimiento deportivo que respeta completamente su privacidad.</string>
|
||||
<string name="about_url">Página web del proyecto: <a href="%1$s">%1$s</a></string>
|
||||
<string name="about_description"><i> OpenTracks </i> es una aplicación de seguimiento deportivo que respeta completamente tu privacidad.</string>
|
||||
<string name="about_url">Sitio web del proyecto: <a href="%1$s">%1$s</a></string>
|
||||
<string name="about_version_name">Nombre de la versión: %1$s</string>
|
||||
<string name="bluetooth_disabled">Por favor habilite Bluetooth.</string>
|
||||
<string name="settings_default_trackfileformat">Formato para exportar/compartir</string>
|
||||
@@ -320,10 +319,7 @@
|
||||
<string name="track_distance_notification">Distancia: %1$s</string>
|
||||
<string name="aggregated_stats_empty_message">Grabe su primer recorrido para ver estadísticas agregadas</string>
|
||||
<string name="settings_default_export_uri_title">Directorio de exportación de recorrido</string>
|
||||
<string name="help_track_map_content"> Utilice el pequeño icono de mapa.
|
||||
\na) (actualizaciones en vivo) Instale <a href="https://codeberg.org/OpenTracksApp/OSMDashboard"> OSMDashboard </a>. Proporciona mapas en línea o fuera de línea a través de <a href="https://www.openstreetmap.org"> OpenStreetMap </a>.
|
||||
\nEn realidad, OSMDashboard es una aplicación separada que solo puede acceder (temporalmente) a los datos de los recorridos que se mostrarán.
|
||||
\nb) A través de una aplicación de mapas normal (p. ej., <a href="http://osmand.net/"> OsmAnd </a> y <a href="https://maps.me/"> MAPS.ME </a>). Estas aplicaciones deben admitir el formato de archivo KMZ (solo ubicaciones y marcas de tiempo). De hecho, una aplicación debe admitir <i> ACTION_VIEW </i> con MIME <i> application / vnd.google-earth.kmz</i>. </string>
|
||||
<string name="help_track_map_content">Utilice el pequeño icono de mapa. \na) (actualizaciones en vivo) Instale <a href="https://codeberg.org/OpenTracksApp/OSMDashboard"> OSMDashboard </a>. Proporciona mapas con o sin conexión a través de <a href="https://www.openstreetmap.org"> OpenStreetMap </a>. \nEn realidad, OSMDashboard es una aplicación separada que solo puede acceder (temporalmente) a los datos de los recorridos que se mostrarán. \nb) A través de una aplicación de mapas normal (p. ej., <a href="http://osmand.net/"> OsmAnd </a> y <a href="https://maps.me/"> MAPS.ME </a>). Estas aplicaciones deben admitir el formato de archivo KMZ (solo ubicaciones y marcas de tiempo). De hecho, una aplicación debe admitir <i> ACTION_VIEW </i> con MIME <i>application/vnd.google-earth.kmz</i>.</string>
|
||||
<string name="about_third_party_data">Datos de terceros</string>
|
||||
<string name="about_libraries">Bibliotecas</string>
|
||||
<string name="help_feature_title">OpenTracks tiene las siguientes características:</string>
|
||||
@@ -344,7 +340,6 @@
|
||||
<string name="help_data_storage_title">¿Cómo almacena OpenTracks los datos de los sensores\?</string>
|
||||
<string name="help_gps_troubleshooting_title">¿OpenTracks no registra ubicaciones\?</string>
|
||||
<string name="help_support_title">¿Cómo puedo ayudar a OpenTracks\?</string>
|
||||
<string name="open_track_as_trackfileformat">Abrir como %1$s</string>
|
||||
<string name="activity_type_escooter">moto</string>
|
||||
<string name="description_speed_ms">Velocidad (m/s)</string>
|
||||
<string name="description_default_speed_or_pace">Por tipo de actividad</string>
|
||||
@@ -430,7 +425,7 @@
|
||||
<string name="settings_gps_summary">Intervalo de tiempo, Intervalo de distancia, Distancia máxima, Precisión</string>
|
||||
<string name="settings_sensors_title">Sensores</string>
|
||||
<string name="settings_sensors_summary">Sensores de ciclismo, Circunferencia de la rueda, Sensores de carrera</string>
|
||||
<string name="settings_export_section">Exportar</string>
|
||||
<string name="settings_export_as_file_section">Exportar</string>
|
||||
<string name="activity_type_swimming">Natación</string>
|
||||
<string name="activity_type_swimming_open">Natación en aguas abiertas</string>
|
||||
<string name="activity_type_workout">Entrenamiento</string>
|
||||
@@ -483,4 +478,101 @@
|
||||
<string name="image_discard">Descartar</string>
|
||||
<string name="menu_export_all_one_file">Exportar todo (un archivo para todas las pistas)</string>
|
||||
<string name="permission_recording_failed">OpenTracks requiere permisos adicionales para acceder a tu ubicación y a tus dispositivos cercanos.</string>
|
||||
<string name="activity_type_gravel_biking">Ciclismo en grava</string>
|
||||
<string name="description_sensor_temperature">Temperatura (Celsius)</string>
|
||||
<string name="create_marker_error">No se pudo crear un marcador. Inténtalo nuevamente.</string>
|
||||
<string name="marker_detail_title">%1$d de %2$d: %3$s</string>
|
||||
<string name="menu_export_all_to_health_connect">Exportar todo</string>
|
||||
<string name="sensor_state_cadence_unit">rpm</string>
|
||||
<string name="sensor_state_heart_rate_unit">ppm</string>
|
||||
<string name="sensor_state_temperature">Termómetro</string>
|
||||
<string name="sensor_state_pressure">Barómetro</string>
|
||||
<string name="sensor_state_power_max">Potencia máxima</string>
|
||||
<string name="sensor_state_power_unit">W</string>
|
||||
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
|
||||
<string name="settings_announcements_idle_category_title">Anuncios de espera</string>
|
||||
<string name="settings_announcements_idle_title">Espera</string>
|
||||
<string name="settings_charts_title">Gráficas</string>
|
||||
<string name="settings_chart_display_elevation_title">Mostrar elevación</string>
|
||||
<string name="settings_chart_display_pace_or_speed_title">Mostrar ritmo o velocidad</string>
|
||||
<string name="settings_chart_display_heart_rate_title">Mostrar frecuencia cardiaca</string>
|
||||
<string name="settings_recording_title">Registro</string>
|
||||
<string name="settings_theme_switch_restart">Los cambios en el tema pueden requerir un reinicio manual.</string>
|
||||
<string name="settings_ui_dynamic_colors_title">Colores dinámicos</string>
|
||||
<string name="settings_ui_dynamic_colors_summary">Usar colores dinámicos definidos por el usuario (solo para Android 12+; requiere reiniciar manualmente)</string>
|
||||
<string name="settings_recording_show_gps_disabled_warning_title">Alerta de GPS desactivado</string>
|
||||
<string name="settings_recording_show_gps_disabled_warning_summary">Durante el registro, mostrar una advertencia si el GPS está desactivado.</string>
|
||||
<string name="settings_recording_min_required_accuracy_summary">La ubicación es ignorada si su precisión es mayor que %1$s</string>
|
||||
<string name="settings_recording_idle_timeout_title">Umbral de inactividad</string>
|
||||
<string name="settings_locale_title">Idioma</string>
|
||||
<string name="settings_locale_system_default">Predeterminado del sistema</string>
|
||||
<string name="settings_night_mode_option_system_dynamic">Sistema (DynamicColor)</string>
|
||||
<string name="settings_night_mode_option_day_dynamic">Día (DynamicColor)</string>
|
||||
<string name="settings_night_mode_option_night_dynamic">Noche (DynamicColor)</string>
|
||||
<string name="settings_night_mode_option_night_oled">Optimizado para OLED</string>
|
||||
<string name="settings_night_mode_option_night_oled_dynamic">Optimizado para OLED (DynamicColor)</string>
|
||||
<string name="settings_announcements_average_heart_rate">Frecuencia cardiaca promedio</string>
|
||||
<string name="settings_announcements_lap_heart_rate">Frecuencia cardiaca por vuelta</string>
|
||||
<string name="settings_announcements_average_speed_pace">Ritmo/velocidad promedio</string>
|
||||
<string name="settings_announcements_segment_average_speed_pace">Ritmo/velocidad promedio (segmento)</string>
|
||||
<string name="settings_announcements_lap_speed_pace">Ritmo/velocidad por vuelta</string>
|
||||
<string name="settings_announcements_unit">Unidad de distancia/velocidad</string>
|
||||
<string name="settings_sensor_bluetooth_service_filter_title">Filtrar dispositivos bluetooth</string>
|
||||
<string name="settings_sensor_bluetooth_service_filter_off">Mostrar todos los dispositivos bluetooth detectables</string>
|
||||
<string name="settings_sensor_heart_rate_max">Zonas: frecuencia cardiaca máxima (ppm)</string>
|
||||
<string name="settings_stats_units_imperial_meter">Imperial (mi, m)</string>
|
||||
<string name="settings_stats_units_nautical">Náutica (NM, ft)</string>
|
||||
<string name="settings_api_summary">Control remoto y API de estadísticas para otras aplicaciones</string>
|
||||
<string name="settings_public_api_package_title">Nombre de paquete para la API pública</string>
|
||||
<string name="settings_export_to_health_connect">Exportar a Health Connect</string>
|
||||
<string name="stats_average_segment_pace">Ritmo promedio de segmento</string>
|
||||
<string name="stats_elapsed_segment_time">Tiempo transcurrido del segmento</string>
|
||||
<string name="stats_gain_loss">Ganancia y pérdida</string>
|
||||
<string name="stats_sensors_temperature">Temperatura</string>
|
||||
<string name="track_delete_number_of_tracks">%1$d pistas</string>
|
||||
<string name="track_discarding">Pista descartada</string>
|
||||
<string name="track_edit_time_offset">Diferencia horaria</string>
|
||||
<string name="unit_nautical_mile">Milla Náutica</string>
|
||||
<string name="unit_knots">nudo</string>
|
||||
<string name="unit_minute_per_nautical_mile">minutos/nudo</string>
|
||||
<string name="value_integer_knots">%1$d nudos</string>
|
||||
<string name="value_float_knots">%1$.1f nudos</string>
|
||||
<string name="value_float_knots_recommended">%1$.1f nudos (recomendado)</string>
|
||||
<string name="value_internal_sensor">Sensor interno</string>
|
||||
<string name="value_int_seconds">%1$d segundos (recomendado)</string>
|
||||
<string name="voiceIdle">Pasando a inactivo.</string>
|
||||
<string name="voiceHoursPlural">{n, plural, =1 {1 hora} otro {{n,número} horas} }</string>
|
||||
<string name="voiceMinutesPlural">{n, plural, =1 {1 minuto} otro {{n,número} minutos} }</string>
|
||||
<string name="voiceSecondsPlural">{n, plural, =1 {1 segundo} otro {{n,número} segundos}}</string>
|
||||
<string name="voiceSpeedKilometersPerHourPlural">{n, plural, =1 {1 kilómetro por hora} otro {{n,número,#.0} kilómetros por hora}}</string>
|
||||
<string name="voiceSpeedMilesPerHourPlural">{n, plural, =1 {1 milla por hora} otro {{n,número,#.0} millas por hora}}</string>
|
||||
<string name="voiceSpeedMKnotsPlural">{n, plural, =1 {1 nudo} otro {{n,número} nudos}}</string>
|
||||
<string name="voiceSpeed">{n, plural, =1 {1} otro {{n,número,#.0}} }</string>
|
||||
<string name="voice_on_device_speaker_title">Usar el altavoz del dispositivo</string>
|
||||
<string name="voice_per_nautical_mile">por milla náutica</string>
|
||||
<string name="voiceDistanceKilometersPlural">{n, plural, =1 {1 kilómetro} otro {{n,número,#.0} kilómetros} }</string>
|
||||
<string name="voiceDistanceMilesPlural">{n, plural, =1 {1 milla} otro {{n,número,#.0} millas} }</string>
|
||||
<string name="voiceDistanceNauticalMilesPlural">{n, plural, =1 {1 milla náutica} otro {{n,número,#.0} millas náuticas} }</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1} otro {{n,número#.0}} }</string>
|
||||
<string name="lap_heart_rate">Frecuencia cardiaca por vuelta</string>
|
||||
<string name="health_connect_export_enabled_summary">Exportar actividad a Health Connect después de finalizar el registro</string>
|
||||
<string name="health_connect_not_available">Health Connect no está disponible en este dispositivo</string>
|
||||
<string name="health_connect_open_settings_title">Ajustes de Health Connect</string>
|
||||
<string name="health_connect_open_settings_summary">Abrir los ajustes de Health Connect</string>
|
||||
<string name="health_connect_permissions_rationale_title">Permisos de Health Connect</string>
|
||||
<string name="health_connect_permissions_rationale_heading">Como OpenTracks usa Health Connect</string>
|
||||
<string name="health_connect_permissions_rationale_summary">Si está activado en la configuración, OpenTracks registrará la actividad en Health Connect. OpenTracks no obtiene ningún dato de Health Connect.</string>
|
||||
<string name="no_compatible_camera_installed">No hay alguna aplicación de cámara compatible instalada</string>
|
||||
<string name="no_compatible_gallery_installed">No hay alguna aplicación compatible de galería de imágenes instalada</string>
|
||||
<string name="error_crash_title">%1$s se cerró inesperadamente</string>
|
||||
<string name="share_crash_report">Compartir informe de errores</string>
|
||||
<string name="report_bug">Reportar fallo</string>
|
||||
<string name="show_on_dashboard">API del panel de control de OpenTracks</string>
|
||||
<string name="show_on_dashboard_not_installed">No se encontró instalada alguna aplicación que soporte la API del panel de control de OpenTracks.</string>
|
||||
<string name="introduction_osm_dashboard">OpenTracks no provee mapas por sí mismo. Instala OSMDashboard para ver tus registros en un mapa.</string>
|
||||
<string name="settings_recording_min_sampling_interval_title">Intervalo de tiempo de muestreo</string>
|
||||
<string name="settings_recording_location_distance_summary">%1$s entre ubicaciones registradas</string>
|
||||
<string name="settings_announcements_lap_power">Potencia por vuelta</string>
|
||||
<string name="power_x_watt">Potencia {x, plural, =1 {1 vatio} other {# vatios} }</string>
|
||||
<string name="power">Potencia</string>
|
||||
</resources>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Изчаква се по-добър сигнал за GPS</string>
|
||||
<string name="gps_wait_for_signal">Изчаква се сигнал за GPS</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Стрелка</string>
|
||||
<string name="image_marker_count">Брой маркери</string>
|
||||
<string name="image_photo_marker">Маркер за снимки</string>
|
||||
<string name="image_record">Запис</string>
|
||||
@@ -344,7 +343,6 @@ limitations under the License.
|
||||
\n б) Чрез нормално приложение за карти (напр. чрез <a href="http://osmand.net/">OsmAnd</a> и <a href="https://maps.me/">MAPS.ME</a>). Тези приложения трябва да поддържат файловия формат KMZ (само местоположения и времеви марки). Всъщност едно приложение трябва да поддържа <i>ACTION_VIEW</i> с MIME <i>application/vnd.google-earth.kmz</i>. </string>
|
||||
<string name="help_data_storage_title">Как OpenTracks съхранява данните от сензорите\?</string>
|
||||
<string name="help_data_storage_content"> Данните от сензора се съхраняват за всяко записано място. По отношение на сензора за сърдечен ритъм това означава, че само <i>едно</i> измерване на сърдечния ритъм се съхранява за всяко местоположение. Ако стоите неподвижно или се намирате на закрито, няма да бъдат записани данни от сензора (но те ще бъдат </string>
|
||||
<string name="open_track_as_trackfileformat">Отворете като %1$s</string>
|
||||
<string name="description_altitude_loss">Загуба на височина: %1$d m (%2$d ft)</string>
|
||||
<string name="help_recording_content">OpenTracks използва GPS сензора на устройството, за да записва непрекъснато местоположението. Ако GPS устройството съобщи неточни данни (напр. местоположение, скорост, надморска височина), OpenTracks не може да направи нищо по въпроса.</string>
|
||||
<string name="track_distance_notification">Отстояние: %1$s</string>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Esperant un millor senyal GPS</string>
|
||||
<string name="gps_wait_for_signal">Esperant el senyal GPS</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Fletxa</string>
|
||||
<string name="image_marker_count">Recompte de marcadors</string>
|
||||
<string name="image_photo_marker">Marcador de fotos</string>
|
||||
<string name="image_record">Enregistra</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="help_recording_title">Cumu OpenTracks arregistreghja i dati ?</string>
|
||||
<string name="help_gps_troubleshooting_title">OpenTracks ùn arregistreghja micca e pusizioni ?</string>
|
||||
<string name="help_support_title">Cumu possu sustene OpenTracks ?</string>
|
||||
<string name="open_track_as_trackfileformat">Apre cum’è %1$s</string>
|
||||
<string name="activity_type_airplane">aviò</string>
|
||||
<string name="activity_type_atv">fora di strada</string>
|
||||
<string name="activity_type_biking">bicicletta</string>
|
||||
@@ -123,7 +122,6 @@
|
||||
<string name="gps_disabled_msg">GPS disattivatu</string>
|
||||
<string name="gps_fixed_and_ready">GPS fissu è prontu</string>
|
||||
<string name="gps_recording_status">%1$s : %2$s</string>
|
||||
<string name="image_arrow">Freccia</string>
|
||||
<string name="image_marker_count">Numeru di stantelle</string>
|
||||
<string name="image_stop">Piantà</string>
|
||||
<string name="image_discard">Scartà</string>
|
||||
@@ -456,7 +454,7 @@
|
||||
<string name="settings_stats_units_imperial_meter">Imperiale (mi, m)</string>
|
||||
<string name="settings_stats_units_metric">Metrica (km, m)</string>
|
||||
<string name="settings_import_section">Impurtà</string>
|
||||
<string name="settings_export_section">Espurtà</string>
|
||||
<string name="settings_export_as_file_section">Espurtà</string>
|
||||
<string name="settings_public_api_package_title">Nome di u pacchettu per l’API publica</string>
|
||||
<string name="settings_public_api_enabled_summary_off">Solu OpenTracks pò lancià è piantà l’arregistramenti.</string>
|
||||
<string name="settings_public_api_enabled_summary_on">D’altre appiecazioni installate ponu lancià o piantà l’arregistramenti.</string>
|
||||
@@ -524,7 +522,6 @@
|
||||
<string name="field_set_secondary">Secundariu</string>
|
||||
<string name="field_remove_from_layout">Caccià</string>
|
||||
<string name="no_compatible_gallery_installed">Nisuna appiecazione cumpatibile di galleria di fiure ùn hè installata</string>
|
||||
<string name="always">Sempre</string>
|
||||
<string name="share_crash_report">Sparte u raportu d’accidente</string>
|
||||
<string name="settings_announcements_lap_power">Putenza à u giru</string>
|
||||
<string name="introduction_osm_dashboard">OpenTracks ùn pruvede micca carta da per ellu. Ci vole à installà OSMDashboard per vede i vostri arregistramenti nant’à una carta.</string>
|
||||
@@ -534,7 +531,6 @@
|
||||
<string name="settings_locale_title">Lingua</string>
|
||||
<string name="settings_locale_system_default">Predefinizione di u sistema</string>
|
||||
<string name="stats_gain_loss">Guadagnu è perdita</string>
|
||||
<string name="voice_announce_lap_power_key">AnnunziamentuVucalePutenzaÀUGiru</string>
|
||||
<string name="lap_heart_rate">Frequenza cardiaca à u giru</string>
|
||||
<string name="settings_charts_title">Grafici</string>
|
||||
<string name="settings_chart_display_elevation_title">Affissà l’altitudine</string>
|
||||
|
||||
@@ -158,7 +158,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Čekání na lepší signál GPS</string>
|
||||
<string name="gps_wait_for_signal">Čekání na signál GPS</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Šipka</string>
|
||||
<string name="image_marker_count">Počet značek</string>
|
||||
<string name="image_photo_marker">Fotografická značka</string>
|
||||
<string name="image_record">Zaznamenat</string>
|
||||
@@ -353,7 +352,6 @@ limitations under the License.
|
||||
<!-- Share image -->
|
||||
<string name="share_image_subject">Chtěl bych s vámi sdílet obrázek</string>
|
||||
<string name="share_image_body">Myslím, že by vás mohl tento obrázek zajímat.</string>
|
||||
<string name="open_track_as_trackfileformat">Otevřít jako %1$s</string>
|
||||
<string name="export_all_do_it_for_all">provést pro všechny konflikty</string>
|
||||
<string name="export_track_errors">Soubory nebyly exportovány</string>
|
||||
<string name="generic_separator_done_total">/</string>
|
||||
@@ -444,7 +442,7 @@ limitations under the License.
|
||||
<string name="settings_cycling_sensor">Cyklistika</string>
|
||||
<string name="settings_running_sensor">Běh</string>
|
||||
<string name="settings_import_section">Importovat</string>
|
||||
<string name="settings_export_section">Exportovat</string>
|
||||
<string name="settings_export_as_file_section">Exportovat</string>
|
||||
<string name="stats_sensors_power">Napájení</string>
|
||||
<string name="permission_bluetooth_failed_rejected">V nastavení systému je třeba ručně povolit aplikaci OpenTracks přístup k blízkým zařízením.</string>
|
||||
<string name="value_float_mile_hour">%1$.1f mi/h</string>
|
||||
@@ -525,7 +523,6 @@ limitations under the License.
|
||||
<string name="report_bug">Nahlásit chybu</string>
|
||||
<string name="settings_announcements_lap_heart_rate">Srdeční tep kola</string>
|
||||
<string name="introduction_osm_dashboard">OpenTracks sám o sobě mapu neposkytuje. Pro zobrazení záznamů na mapě si nainstalujte OSMDashboard.</string>
|
||||
<string name="always">Vždy</string>
|
||||
<string name="help_data_google_play_services_content">Ne</string>
|
||||
<string name="description_speed_nautical">Rychlost (uzly)</string>
|
||||
<string name="settings_export_filename_title">Formát názvu souboru</string>
|
||||
@@ -580,7 +577,6 @@ limitations under the License.
|
||||
<string name="settings_announcements_unit">Jednotka vzdálenosti/rychlosti</string>
|
||||
<string name="voiceSpeed">{n, plural, =1 {1} few {{n,number}} other {{n,number,#.0}} }</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } few {{n,number}} other {{n,number,#.0}} }</string>
|
||||
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
|
||||
<string name="power">Výkon</string>
|
||||
<string name="settings_announcements_lap_power">Výkon kola</string>
|
||||
<string name="power_x_watt">Výkon {x, plural, =1 {1 watt} few {# watty} other {# wattů} }</string>
|
||||
|
||||
@@ -174,7 +174,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Venter på et bedre GPS-signal</string>
|
||||
<string name="gps_wait_for_signal">Venter på GPS-signal</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Pil</string>
|
||||
<string name="image_marker_count">Antal markører</string>
|
||||
<string name="image_photo_marker">Billedmarkør</string>
|
||||
<string name="image_record">Registrer</string>
|
||||
@@ -369,7 +368,6 @@ limitations under the License.
|
||||
<!-- Share image -->
|
||||
<string name="share_image_subject">Jeg vil gerne dele et billede med dig</string>
|
||||
<string name="share_image_body">Jeg tror, du måske er interesseret i dette billede.</string>
|
||||
<string name="open_track_as_trackfileformat">Åbn som %1$s</string>
|
||||
<string name="activity_type_escooter">elløbehjulskørsel</string>
|
||||
<string name="generic_click_twice_cancel">Stryg tilbage igen for at annullere</string>
|
||||
<string name="import_unable_to_import_file">Kunne ikke importere filen:%1$s</string>
|
||||
@@ -471,7 +469,7 @@ limitations under the License.
|
||||
<string name="custom_layout_select_layout">Vælg layout</string>
|
||||
<string name="settings_running_sensor">Kører</string>
|
||||
<string name="settings_import_section">Importere</string>
|
||||
<string name="settings_export_section">Eksport</string>
|
||||
<string name="settings_export_as_file_section">Eksport</string>
|
||||
<string name="stats_clock">Ur</string>
|
||||
<string name="value_float_mile_hour_recommended">%1$.1f mi/h (anbefalet)</string>
|
||||
<string name="value_float_mile_hour">%1$.1f mi/h</string>
|
||||
@@ -561,7 +559,6 @@ limitations under the License.
|
||||
<string name="settings_recording_min_sampling_interval_title">Tidsinterval mellem samplinger</string>
|
||||
<string name="settings_night_mode_option_day_dynamic">Dag (DynamicColor)</string>
|
||||
<string name="voiceSpeedKilometersPerHourPlural">{n, plural, =1 {1 kilometer i timen} other {{n,number,#.0} kilometre i timen} }</string>
|
||||
<string name="empty">tom</string>
|
||||
<string name="settings_chart_display_elevation_title">Vis højde</string>
|
||||
<string name="settings_chart_display_pace_or_speed_title">Vis tempo eller hastighed</string>
|
||||
<string name="settings_chart_display_heart_rate_title">Vis puls</string>
|
||||
@@ -597,7 +594,6 @@ limitations under the License.
|
||||
<string name="error_crash_title">%1$s gik ned</string>
|
||||
<string name="share_crash_report">Del fejlrapport</string>
|
||||
<string name="report_bug">Rapporter fejl</string>
|
||||
<string name="always">Altid</string>
|
||||
<string name="introduction_osm_dashboard">OpenTracks indeholder ikke selv et kort. Installer venligst OSMDashboard for at se registreringer på et kort.</string>
|
||||
<string name="settings_recording_location_distance_summary">%1$s mellem registrerede lokationer</string>
|
||||
<string name="settings_announcements_lap_power">Omgangseffekt</string>
|
||||
|
||||
@@ -61,7 +61,6 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
|
||||
\ne) es im <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a> kaufen,
|
||||
\nf) spenden, und
|
||||
\ng) das tun, was OpenTracks Deiner Meinung nach hilft. \u0020</string>
|
||||
<string name="open_track_as_trackfileformat">Als %1$s öffnen</string>
|
||||
<!-- Activity Type -->
|
||||
<string name="activity_type_airplane">Flugzeug</string>
|
||||
<string name="activity_type_atv">Quad</string>
|
||||
@@ -176,7 +175,6 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
|
||||
<string name="gps_wait_for_better_signal">Warte auf besseres GPS-Signal</string>
|
||||
<string name="gps_wait_for_signal">Warte auf GPS-Signal</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Pfeil</string>
|
||||
<string name="image_marker_count">Anzahl der Markierungen</string>
|
||||
<string name="image_photo_marker">Fotomarkierung</string>
|
||||
<string name="image_record">Aufzeichnen</string>
|
||||
@@ -511,7 +509,7 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
|
||||
<string name="settings_sensor_bluetooth_service_filter_on">Zeige nur Bluetooth-Geräte, die benötigte Dienste bekanntmachen</string>
|
||||
<string name="settings_public_api_enabled_summary_on">Andere installierte Anwendungen können Aufzeichnungen starten oder stoppen.</string>
|
||||
<string name="settings_public_api_disabled_toast">OpenTracks öffentliche API ist deaktiviert: es kann in den Einstellungen aktiviert werden.</string>
|
||||
<string name="settings_export_section">Export</string>
|
||||
<string name="settings_export_as_file_section">Export</string>
|
||||
<string name="settings_public_api_enabled_summary_off">Nur OpenTracks kann Aufzeichnungen starten und stoppen.</string>
|
||||
<string name="settings_import_section">Import</string>
|
||||
<string name="settings_api_title">Öffentliche API</string>
|
||||
@@ -566,7 +564,6 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
|
||||
<string name="field_remove_from_layout">Entfernen</string>
|
||||
<string name="error_crash_title">%1$s ist abgestürzt</string>
|
||||
<string name="share_crash_report">Absturzbericht teilen</string>
|
||||
<string name="always">Immer</string>
|
||||
<string name="settings_layout_reset_confirm_message">Alle Layout-Einstellungen werden auf die Standardwerte zurückgesetzt. Aufzeichnungen werden nicht vom Gerät gelöscht.</string>
|
||||
<string name="report_bug">Fehler melden</string>
|
||||
<string name="settings_ui_summary">Erscheinungsbild, Aufzeichnungslayout, Theme</string>
|
||||
@@ -635,7 +632,6 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } other {{n,number,#.0}} }</string>
|
||||
<string name="settings_recording_min_sampling_interval_title">Abtastzeitintervall</string>
|
||||
<string name="voiceIdle">Untätig werden.</string>
|
||||
<string name="voice_announce_lap_power_key">StimmeAnkündigungLapPower</string>
|
||||
<string name="settings_announcements_lap_power">Rundenleistung</string>
|
||||
<string name="create_marker_error">Die Markierung konnte nicht erstellt werden. Versuchen Sie es erneut.</string>
|
||||
<string name="settings_locale_title">Sprache</string>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Αναμονή για καλύτερο σήμα GPS</string>
|
||||
<string name="gps_wait_for_signal">Αναμονή για σήμα GPS</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Βέλος</string>
|
||||
<string name="image_marker_count">Αριθμός δείκτη</string>
|
||||
<string name="image_photo_marker">Δείκτης φωτογραφίας</string>
|
||||
<string name="image_record">Εγγραφή</string>
|
||||
@@ -195,7 +194,7 @@ limitations under the License.
|
||||
<string name="settings_stats_units_metric">Μετρικό (χλμ, μέτρα)</string>
|
||||
<string name="settings_stats_units_title">Προτιμώμενες μονάδες</string>
|
||||
<!-- Share Track -->
|
||||
<string name="share_track_share_file_body">Νομίζω ότι μπορεί να σε ενδιαφέρει αυτό το ίχνος.\n\nΓια να δεις αυτό το ίχνος, χρησιμοποίησε το Google Earth ή άλλο λογισμικό χαρτογράφησης.\n\n%1$s</string>
|
||||
<string name="share_track_share_file_body">Νομίζω ότι μπορεί να σε ενδιαφέρει αυτό το ίχνος.\n\n%1$s</string>
|
||||
<string name="share_track_subject">Θα ήθελα να μοιραστώ μία διαδρομή μαζί σου</string>
|
||||
<!-- Stats -->
|
||||
<string name="stats_average_moving_pace">Μέσος ρυθμός κίνησης</string>
|
||||
@@ -303,7 +302,7 @@ limitations under the License.
|
||||
<string name="waypoint_type_water_fountain">συντριβάνι</string>
|
||||
<string name="waypoint_type_waypoint">σημείο διαδρομής</string>
|
||||
<string name="about_preference_title">Σχετικά</string>
|
||||
<string name="about_url">Ιστότοπους εγχειρήματος: <a href="%1$s">%1$s</a></string>
|
||||
<string name="about_url">Ιστότοπος εγχειρήματος: <a href="%1$s">%1$s</a></string>
|
||||
<string name="about_version_name">Όνομα έκδοσης: %1$s</string>
|
||||
<string name="about_version_code">Κωδικός έκδοσης: %1$d</string>
|
||||
<string name="about_third_party_data">Δεδομένα από τρίτους</string>
|
||||
@@ -315,13 +314,11 @@ limitations under the License.
|
||||
<string name="help_track_map_title">Πώς να εμφανιστεί ένα ίχνος στον χάρτη;</string>
|
||||
<string name="help_gps_troubleshooting_title">Το OpenTracks δεν καταγράφει τοποθεσίες;</string>
|
||||
<string name="help_support_title">Πώς να υποστηρίξω το OpenTracks;</string>
|
||||
<string name="open_track_as_trackfileformat">Ανοίγμα ως %1$s</string>
|
||||
<string name="activity_type_escooter">ηλεκτρικό πατίνι</string>
|
||||
<string name="activity_type_kickscooter">πατίνι</string>
|
||||
<string name="power_x_watt">Ισχύς {x, plural, =1 {1 watt} other {# watts} }</string>
|
||||
<string name="power">Ισχύς</string>
|
||||
<string name="report_bug">Αναφορά προβλήματος</string>
|
||||
<string name="always">Πάντα</string>
|
||||
<string name="settings_recording_min_sampling_interval_title">Χρονικό μεσοδιάστημα δειγματοληψίας</string>
|
||||
<string name="settings_recording_location_distance_summary">%1$s μεταξύ καταγεγραμμένων τοποθεσιών</string>
|
||||
<string name="field_remove_from_layout">Αφαίρεση</string>
|
||||
@@ -348,7 +345,6 @@ limitations under the License.
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } other {{n,number,#.0}} }</string>
|
||||
<string name="voiceHoursPlural">{n, plural, =1 {1 ώρα} other {{n,number} ώρες} }</string>
|
||||
<string name="settings_import_section">Εισαγωγή</string>
|
||||
<string name="settings_export_section">Εξαγωγή</string>
|
||||
<string name="settings_api_title">Δημόσιο API</string>
|
||||
<string name="settings_public_api_enabled_title">Δημόσιο API</string>
|
||||
<string name="settings_public_api_package_title">Όνομα πακέτου για Δημόσιο API</string>
|
||||
|
||||
@@ -174,7 +174,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Esperando una mejor señal de GPS</string>
|
||||
<string name="gps_wait_for_signal">Esperando señal de GPS</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Flecha</string>
|
||||
<string name="image_marker_count">Recuento de marcadores</string>
|
||||
<string name="image_photo_marker">Marcador de foto</string>
|
||||
<string name="image_record">Grabar</string>
|
||||
@@ -405,7 +404,6 @@ limitations under the License.
|
||||
<!-- Share image -->
|
||||
<string name="share_image_subject">Me gustaría compartir una imagen contigo</string>
|
||||
<string name="share_image_body">Creo que esta imagen podría interesarte.</string>
|
||||
<string name="open_track_as_trackfileformat">Abrir como %1$s</string>
|
||||
<string name="activity_type_escooter">moto</string>
|
||||
<string name="export_all_do_it_for_all">hacerlo para todos los conflictos</string>
|
||||
<string name="export_track_errors">Archivos no exportados</string>
|
||||
@@ -503,7 +501,7 @@ limitations under the License.
|
||||
<string name="permission_bluetooth_failed_rejected">Es necesario conceder manualmente a OpenTracks el acceso a los Dispositivos Cercanos en la configuración del sistema.</string>
|
||||
<string name="settings_running_sensor">Correr</string>
|
||||
<string name="settings_import_section">Importar</string>
|
||||
<string name="settings_export_section">Exportar</string>
|
||||
<string name="settings_export_as_file_section">Exportar</string>
|
||||
<string name="generic_today">Hoy</string>
|
||||
<string name="generic_yesterday">Ayer</string>
|
||||
<string name="menu_add_custom_layout">Nuevo diseño</string>
|
||||
@@ -597,7 +595,6 @@ limitations under the License.
|
||||
<string name="report_bug">Reportar error</string>
|
||||
<string name="show_on_dashboard">Panel de control del API de OpenTracks</string>
|
||||
<string name="show_on_dashboard_not_installed">No se ha instalado ninguna aplicación compatible con el panel de control del API de OpenTracks.</string>
|
||||
<string name="always">Siempre</string>
|
||||
<string name="settings_announcements_lap_heart_rate">Frecuencia cardiaca por vuelta</string>
|
||||
<string name="settings_public_api_package_title">Nombre del paquete para el API público</string>
|
||||
<string name="unit_knots">Nudo</string>
|
||||
@@ -654,7 +651,6 @@ limitations under the License.
|
||||
<string name="settings_announcements_lap_power">Potencia por vuelta</string>
|
||||
<string name="power_x_watt">Potencia {x, plural, =1 {1 vatio} otros {# vatios} }</string>
|
||||
<string name="create_marker_error">No se ha podido crear un marcador. Inténtelo de nuevo.</string>
|
||||
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
|
||||
<string name="power">Potencia</string>
|
||||
<string name="settings_locale_title">Idioma</string>
|
||||
<string name="settings_locale_system_default">Predeterminado del sistema</string>
|
||||
|
||||
@@ -153,7 +153,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Ootan paremat GPS-signaali</string>
|
||||
<string name="gps_wait_for_signal">Ootan GPS-signaali</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Nool</string>
|
||||
<string name="image_marker_count">Markerite arv</string>
|
||||
<string name="image_photo_marker">Fotomarker</string>
|
||||
<string name="image_record">Salvesta</string>
|
||||
@@ -346,7 +345,6 @@ limitations under the License.
|
||||
<!-- Share image -->
|
||||
<string name="share_image_subject">Tahaksin sinuga pilti jagada</string>
|
||||
<string name="share_image_body">Ma arvan, et see pilt võiks sind huvitada.</string>
|
||||
<string name="open_track_as_trackfileformat">Ava kui %1$s</string>
|
||||
<string name="activity_type_escooter">elektritõukeratas</string>
|
||||
<string name="description_altitude_loss">Kõrguse langus: %1$d m (%2$d jalga)</string>
|
||||
<string name="export_all_do_it_for_all">tee seda iga konfilkti puhul</string>
|
||||
@@ -442,7 +440,7 @@ limitations under the License.
|
||||
<string name="settings_reset_summary">Lähtesta seadistused vaikeväärtusteks</string>
|
||||
<string name="settings_recording_customize_layout_title">Kohanda oma salvestuse paigutust</string>
|
||||
<string name="settings_recording_customize_layout_select_columns">Andmeväljad rea kohta</string>
|
||||
<string name="settings_export_section">Eksport</string>
|
||||
<string name="settings_export_as_file_section">Eksport</string>
|
||||
<string name="settings_announcements_totaltime_frequency">Ajavahemik</string>
|
||||
<string name="settings_layout_reset">Lähtesta kohandatud paigutus</string>
|
||||
<string name="settings_layout_reset_confirm_title">Kas lähtestad oma paigutused?</string>
|
||||
@@ -544,7 +542,6 @@ limitations under the License.
|
||||
<string name="voiceSpeedKilometersPerHourPlural">{n, plural, =1 {1 kilomeeter tunnis} other {{n,number,#.0} kilomeetrit tunnis} }</string>
|
||||
<string name="voiceSpeedMilesPerHourPlural">{n, plural, =1 {1 miil tunnis} other {{n,number,#.0} miili tunnis} }</string>
|
||||
<string name="voiceSpeedMKnotsPlural">{n, plural, =1 {1 sõlm} other {{n,number,#.0} sõlme} }</string>
|
||||
<string name="always">Alati</string>
|
||||
<string name="power">Võimsus</string>
|
||||
<string name="power_x_watt">Võimsus {x, plural, =1 {1 vatt} other {# vatti} }</string>
|
||||
<string name="settings_announcements_lap_power">Ringi võimsus</string>
|
||||
@@ -595,9 +592,17 @@ limitations under the License.
|
||||
<string name="show_on_dashboard_not_installed">Pole paigaldatud ühtegi rakendust, mis toetaks OpenTracksi juhtpaneeli API-t.</string>
|
||||
<string name="introduction_osm_dashboard">Kaardi kuvamine pole OpenTracks-i automaatselt lisatud. Oma salvestiste kaardil vaatamiseks palun paigalda OSMDashboard.</string>
|
||||
<string name="settings_recording_min_sampling_interval_title">Proovivõtu ajavahemik</string>
|
||||
<string name="voice_announce_lap_power_key">RingiVõimsuseHäälteade</string>
|
||||
<string name="description_sensor_temperature">Temperatuur (Celsius)</string>
|
||||
<string name="sensor_state_temperature">Termomeeter</string>
|
||||
<string name="stats_sensors_temperature">Temperatuur</string>
|
||||
<string name="activity_type_gravel_biking">rattasõit kruusateedel</string>
|
||||
<string name="menu_export_all_to_health_connect">Ekspordi kõik</string>
|
||||
<string name="settings_export_to_health_connect">Ekspordi „Health Connect“ liidesesse</string>
|
||||
<string name="health_connect_export_enabled_summary">Peale salvestamise lõppemist ekspordi tegevus „Health Connect“ taustateenusesse</string>
|
||||
<string name="health_connect_not_available">„Health Connect“ taustateenus pole selles seadmes saadaval</string>
|
||||
<string name="health_connect_open_settings_title">„Health Connect“ taustateenuse seadistused</string>
|
||||
<string name="health_connect_open_settings_summary">Ava „Health Connect“ taustateenuse seadistused</string>
|
||||
<string name="health_connect_permissions_rationale_title">„Health Connect“ taustateenuse õigused</string>
|
||||
<string name="health_connect_permissions_rationale_heading">Kuidas OpenTracks kasutab „Health Connect“ taustateenust</string>
|
||||
<string name="health_connect_permissions_rationale_summary">Kui see on seadistustest lubatud, siis OpenTracks salvestab treeningute andmed ka „Health Connect“ taustateenusesse. OpenTracks ei loe andmeid „Health Connect“ taustateenusest.</string>
|
||||
</resources>
|
||||
|
||||
@@ -176,7 +176,6 @@ GPS gailuak datu okerrak salatzen baditu (adibidez, kokapena, abiadura, kota), O
|
||||
<string name="gps_wait_for_better_signal">GPS seinale hobearen zain</string>
|
||||
<string name="gps_wait_for_signal">GPS seinalearen zain</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Gezia</string>
|
||||
<string name="image_marker_count">Markatzaile kopurua</string>
|
||||
<string name="image_photo_marker">Argazki-markatzailea</string>
|
||||
<string name="image_record">Grabatu</string>
|
||||
@@ -371,7 +370,6 @@ GPS gailuak datu okerrak salatzen baditu (adibidez, kokapena, abiadura, kota), O
|
||||
<!-- Share image -->
|
||||
<string name="share_image_subject">Irudi bat zurekin partekatu nahi nuke</string>
|
||||
<string name="share_image_body">Irudi hau interesatuko zaizuela uste dut.</string>
|
||||
<string name="open_track_as_trackfileformat">Ireki gisa %1$s</string>
|
||||
<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>
|
||||
@@ -458,7 +456,7 @@ GPS gailuak datu okerrak salatzen baditu (adibidez, kokapena, abiadura, kota), O
|
||||
<string name="settings_layout_reset_done">Diseinuaren ezarpen guztiak balio lehenetsietara itzuli dira</string>
|
||||
<string name="settings_all_reset">Berrezarri</string>
|
||||
<string name="settings_import_section">Inportatu</string>
|
||||
<string name="settings_export_section">Esportatu</string>
|
||||
<string name="settings_export_as_file_section">Esportatu</string>
|
||||
<string name="stats_coordinates">Latitudea /Longitudea</string>
|
||||
<string name="stats_clock">Erlojua</string>
|
||||
<string name="value_float_mile_hour">%1$.1f mi/h</string>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">در انتظار سیگنال GPS بهتر</string>
|
||||
<string name="gps_wait_for_signal">در انتظار سیگنال GPS</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">پیکان</string>
|
||||
<string name="image_marker_count">تعداد نشانگر</string>
|
||||
<string name="image_photo_marker">نشانگر عکس</string>
|
||||
<string name="image_record">ضبط</string>
|
||||
|
||||
@@ -62,7 +62,6 @@ limitations under the License.
|
||||
\ne) osta <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore"> Google Play -kaupasta </a>,
|
||||
\nf) lahjoittaa ja
|
||||
\ng) tee mitä tahansa mielestäsi auttaa OpenTracksia. </string>
|
||||
<string name="open_track_as_trackfileformat">Avaa %1$s-muodossa</string>
|
||||
<!-- Activity Type -->
|
||||
<string name="activity_type_airplane">lentokone</string>
|
||||
<string name="activity_type_atv">mönkijä</string>
|
||||
@@ -177,7 +176,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Odotetaan parempaa GPS-signaalia</string>
|
||||
<string name="gps_wait_for_signal">Odotetaan GPS-signaalia</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Nuoli</string>
|
||||
<string name="image_marker_count">Merkkien määrä</string>
|
||||
<string name="image_photo_marker">Kuvamerkki</string>
|
||||
<string name="image_record">Tallenna</string>
|
||||
@@ -490,7 +488,7 @@ limitations under the License.
|
||||
<string name="stats_sensors_power">Teho</string>
|
||||
<string name="no_compatible_file_manager_installed">Yhteensopiva tiedostojen hallinta puuttuu</string>
|
||||
<string name="settings_export_filename_title">Tiedostonimen muoto</string>
|
||||
<string name="settings_export_section">Vienti</string>
|
||||
<string name="settings_export_as_file_section">Vienti</string>
|
||||
<string name="settings_recording_customize_layout_title">Muokkaa tallennuksen asettelua</string>
|
||||
<string name="settings_sensor_bluetooth_service_filter_on">Näytä vain Bluetooth-laitteet, jotka ilmoittavat tarvittavat palvelut</string>
|
||||
<string name="settings_public_api_dashboard_enabled_summary_off">Tallennettuja tietoja ei jaeta automaattisesti muiden sovellusten kanssa.</string>
|
||||
@@ -514,7 +512,6 @@ limitations under the License.
|
||||
<string name="speed">Nopeus</string>
|
||||
<string name="lap_speed">Kierrosnopeus</string>
|
||||
<string name="total_distance">Kokonaismatka</string>
|
||||
<string name="always">Aina</string>
|
||||
<string name="error_crash_title">%1$s kaatui</string>
|
||||
<string name="share_crash_report">Jaa kaatumisraportti</string>
|
||||
<string name="report_bug">Ilmoita virheestä</string>
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
<string name="gps_starting">Lancement du GPS en cours…</string>
|
||||
<string name="gps_wait_for_better_signal">En attente d\'un signal GPS de meilleure qualité…</string>
|
||||
<string name="gps_wait_for_signal">En attente du signal GPS…</string>
|
||||
<string name="image_arrow">Flèche</string>
|
||||
<string name="image_marker_count">Nombre de repères</string>
|
||||
<string name="image_photo_marker">Repère de photo</string>
|
||||
<string name="image_record">Enregistrer</string>
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
<string name="gps_starting">Lancement du GPS en cours…</string>
|
||||
<string name="gps_wait_for_better_signal">En attente d\'un signal GPS de meilleure qualité…</string>
|
||||
<string name="gps_wait_for_signal">En attente du signal GPS…</string>
|
||||
<string name="image_arrow">Flèche</string>
|
||||
<string name="image_marker_count">Nombre de repères</string>
|
||||
<string name="image_photo_marker">Repère de photo</string>
|
||||
<string name="image_record">Enregistrer</string>
|
||||
|
||||
@@ -176,7 +176,6 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
|
||||
<string name="gps_wait_for_better_signal">En attente d\'un signal GPS de meilleure qualité</string>
|
||||
<string name="gps_wait_for_signal">En attente du signal GPS</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Flèche</string>
|
||||
<string name="image_marker_count">Nombre de repères</string>
|
||||
<string name="image_photo_marker">Repère de photo</string>
|
||||
<string name="image_record">Enregistrer</string>
|
||||
@@ -423,7 +422,6 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
|
||||
<string name="instant_export_enabled_summary">Exportation du tracé dans le stockage à la fin de l\'enregistrement</string>
|
||||
<string name="hold_to_stop">Maintenir pour arrêter</string>
|
||||
<string name="track_distance_notification">Distance : %1$s</string>
|
||||
<string name="open_track_as_trackfileformat">Ouvrir comme %1$s</string>
|
||||
<string name="activity_type_escooter">éscooter</string>
|
||||
<string name="settings_sensor_wheel_circumference">Circonférence de la roue (mm)</string>
|
||||
<string name="export_error_post_workout">L\'exportation du post-travail a échoué, veuillez vérifier le répertoire d\'exportation.</string>
|
||||
@@ -505,7 +503,7 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
|
||||
<string name="settings_cycling_sensor">Cyclisme</string>
|
||||
<string name="settings_running_sensor">Course à pied</string>
|
||||
<string name="settings_import_section">Importer</string>
|
||||
<string name="settings_export_section">Exporter</string>
|
||||
<string name="settings_export_as_file_section">Exporter</string>
|
||||
<string name="settings_reset_summary">Réinitialiser les paramètres aux valeurs par défaut</string>
|
||||
<string name="settings_activity_defaults_category">Valeurs par défaut de l\'activité</string>
|
||||
<string name="settings_sensors_summary">Capteurs de cyclisme, Circonférence de roue, Capteurs de course à pied</string>
|
||||
@@ -576,7 +574,6 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
|
||||
<string name="pace">Rythme</string>
|
||||
<string name="lap_speed">Vitesse par tour</string>
|
||||
<string name="show_on_dashboard">Tableau de bord de l\'API OpenTracks</string>
|
||||
<string name="always">Toujours</string>
|
||||
<string name="share_crash_report">Partager le rapport de crash</string>
|
||||
<string name="report_bug">Signaler un problème</string>
|
||||
<string name="error_crash_title">%1$s a crashé</string>
|
||||
@@ -660,7 +657,6 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
|
||||
<string name="settings_locale_system_default">Paramètres par défaut du système</string>
|
||||
<string name="settings_locale_title">Langue</string>
|
||||
<string name="stats_gain_loss">Gain et perte</string>
|
||||
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
|
||||
<string name="settings_chart_display_pace_or_speed_title">Afficher le pas ou la vitesse</string>
|
||||
<string name="settings_chart_display_elevation_title">Afficher l\'altitude</string>
|
||||
<string name="settings_chart_display_heart_rate_title">Afficher la fréquence cardiaque</string>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
<string name="help_data_storage_title">Conas a stórálann OpenTracks sonraí braiteora\?</string>
|
||||
<string name="help_recording_content">OpenTracks úsáideann an braiteoir GPS an fheiste chun an suíomh a thaifeadadh go leanúnach. Má thuairiscíonn an gléas GPS sonraí míchruinne (m.sh., suíomh, luas, ingearchló), Ní féidir Le OpenTracks aon rud a dhéanamh faoi.</string>
|
||||
<string name="help_gps_troubleshooting_content">Cad is féidir leat a dhéanamh: \n a) seiceáil an bhfuil GPS cumasaithe, \n b) feabhas a chur ar fáiltiú GPS (e.g., dul amuigh faoin AER), \n c) seiceáil le <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">gpstest</a> app, agus \n d) díchumasaigh coigilt cumhachta. \n \nMura gcabhraíonn gach rud le do thoil tuairiscigh fabht.</string>
|
||||
<string name="open_track_as_trackfileformat">Oscail mar %1$s</string>
|
||||
<string name="activity_type_airplane">eitleán</string>
|
||||
<string name="activity_type_biking">rothaíocht</string>
|
||||
<string name="activity_type_blimp">blimpname</string>
|
||||
@@ -140,7 +139,6 @@
|
||||
<string name="generic_yesterday">Inné</string>
|
||||
<string name="generic_dismiss">Díbhe</string>
|
||||
<string name="gps_starting">Ag tosú GPS</string>
|
||||
<string name="image_arrow">Saighead</string>
|
||||
<string name="image_marker_count">Comhaireamh marcóra</string>
|
||||
<string name="image_photo_marker">Marcóir grianghraf</string>
|
||||
<string name="image_record">Taifead</string>
|
||||
@@ -257,7 +255,7 @@
|
||||
<string name="settings_public_api_enabled_summary_off">Ní féidir ach le OpenTracks taifeadtaí a thosú agus a stopadh.</string>
|
||||
<string name="settings_public_api_dashboard_enabled_summary_off">Ní dhéanfar sonraí taifeadta a roinnt go huathoibríoch le feidhmchláir eile.</string>
|
||||
<string name="settings_import_section">Iompórtáil</string>
|
||||
<string name="settings_export_section">Easpórtáil</string>
|
||||
<string name="settings_export_as_file_section">Easpórtáil</string>
|
||||
<string name="share_track_share_file_body">Sílim go mb\'fhéidir go mbeadh suim agat sa rian seo.
|
||||
\n
|
||||
\n%1$s</string>
|
||||
@@ -347,7 +345,6 @@
|
||||
<string name="settings_prevent_reimport_tracks_title">Cosc a chur ar ath-allmhairiú rianta</string>
|
||||
<string name="stats_average_pace">Meánluas</string>
|
||||
<string name="track_delete_multiple_confirm_message">Scriosfar na rianta roghnaithe agus a gcuid marcóirí go buan ón bhfeiste.</string>
|
||||
<string name="always">I gcónaí</string>
|
||||
<string name="show_on_dashboard_not_installed">Níl aon fheidhmchlár a thacaíonn le OpenTracks Dashboard API suiteáilte.</string>
|
||||
<string name="share_image_body">Sílim go mb\'fhéidir go mbeadh suim agat san íomhá seo.</string>
|
||||
<string name="help_support_content">You can: \n a) spread the word about OpenTracks, \n b) <a href="https://codeberg.org/OpenTracksApp/OpenTracks/issues">propose features</a>, \nc) <a href="https://codeberg.org/OpenTracksApp/OpenTracks/issues">report bugs</a>, \n d) help in software development, \n e) buy in <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>, \n f) donate, and \n g) do whatever you think helps OpenTracks.</string>
|
||||
@@ -510,7 +507,6 @@
|
||||
<string name="sensor_state_cadence_unit">rpm</string>
|
||||
<string name="sensor_state_heart_rate_unit">bpm</string>
|
||||
<string name="settings_night_mode_option_night_oled">OLED-chairdiúil</string>
|
||||
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
|
||||
<string name="power">Cumhacht</string>
|
||||
<string name="value_int_seconds">%1$d s (molta)</string>
|
||||
<string name="menu_export_all_one_file">Easpórtáil gach ceann (comhad amháin do gach traic)</string>
|
||||
|
||||
@@ -44,7 +44,6 @@ limitations under the License.
|
||||
<string name="help_gps_troubleshooting_content">Podes intentar: \n a) comproba que o GPS esté activado, \n b) mellora a recepción GPS (ex. sae ao exterior), \n c) comprobaa coa app <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a>, e \n d) desactiva o aforro de enerxía. \n \n Se isto non axuda, infórmanos do problema.</string>
|
||||
<string name="help_support_title">Como podo axudar a OpenTracks\?</string>
|
||||
<string name="help_support_content">Podes: \n a) falar de OpenTracks coas túas amizades, \n b) <a href="https://codeberg.org/OpenTracksApp/OpenTracks/issues">propoñer novas funcións</a>, \n c) <a href="https://codeberg.org/OpenTracksApp/OpenTracks/issues">informar de fallos</a>, \n d) axudar no desenvolvemento, \n e) mercar a app na <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>, \n f) facer unha doazón, e \n g) calquera cousa que estimes axuda a OpenTracks.</string>
|
||||
<string name="open_track_as_trackfileformat">Abrir como %1$s</string>
|
||||
<!-- Activity Type -->
|
||||
<string name="activity_type_airplane">avión</string>
|
||||
<string name="activity_type_atv">Quad</string>
|
||||
@@ -162,7 +161,6 @@ limitations under the License.
|
||||
<string name="gps_disabled_msg">GPS desactivado</string>
|
||||
<string name="gps_fixed_and_ready">GPS fixado e preparado</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Frecha</string>
|
||||
<string name="image_marker_count">Reconto de marcadores</string>
|
||||
<string name="image_photo_marker">Marcador de fotos</string>
|
||||
<string name="image_record">Gravar</string>
|
||||
@@ -443,7 +441,7 @@ limitations under the License.
|
||||
<string name="settings_cycling_sensor">Ciclismo</string>
|
||||
<string name="settings_running_sensor">Correr</string>
|
||||
<string name="settings_import_section">Importar</string>
|
||||
<string name="settings_export_section">Exportar</string>
|
||||
<string name="settings_export_as_file_section">Exportar</string>
|
||||
<string name="settings_announcements_distance_frequency">Lonxitude da volta</string>
|
||||
<string name="permission_bluetooth_failed">OpenTracks require permiso para usar o Bluetooth.</string>
|
||||
<string name="permission_bluetooth_failed_rejected">Tes que permitirlle a OpenTracks nos axustes do sistema que acceda a Dispositivos Próximos.</string>
|
||||
@@ -529,7 +527,6 @@ limitations under the License.
|
||||
<string name="value_float_knots_recommended">%1$.1f nós (recomendado)</string>
|
||||
<string name="voice_per_nautical_mile">por milla náutica</string>
|
||||
<string name="show_on_dashboard_not_installed">Non hai ningunha aplicación instalada compatible coa API de OpenTracks.</string>
|
||||
<string name="always">Sempre</string>
|
||||
<string name="error_crash_title">%1$s fallou</string>
|
||||
<string name="report_bug">Informar do problema</string>
|
||||
<string name="settings_public_api_package_title">Nome do paquete para Public API</string>
|
||||
@@ -600,7 +597,6 @@ limitations under the License.
|
||||
<string name="settings_night_mode_option_day_dynamic">Día (Cores Dinámicas)</string>
|
||||
<string name="settings_night_mode_option_night_dynamic">Noite (Cores Dinámicas)</string>
|
||||
<string name="settings_night_mode_option_night_oled_dynamic">para OLED (Cores Dinámicas)</string>
|
||||
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
|
||||
<string name="settings_announcements_segment_average_speed_pace">Velocidade/Ritmo medios (Tramo)</string>
|
||||
<string name="stats_average_segment_pace">Ritmo medio no Tramo</string>
|
||||
<string name="stats_elapsed_segment_time">Tempo transcurrido no tramo</string>
|
||||
@@ -608,4 +604,13 @@ limitations under the License.
|
||||
<string name="description_sensor_temperature">Temperatura (Celsius)</string>
|
||||
<string name="sensor_state_temperature">Termómetro</string>
|
||||
<string name="activity_type_gravel_biking">ciclismo por grava</string>
|
||||
<string name="menu_export_all_to_health_connect">Exportar todo</string>
|
||||
<string name="settings_export_to_health_connect">Exportar a Saúde conectada</string>
|
||||
<string name="health_connect_export_enabled_summary">Exportar a actividade a Saúde conectada unha vez finaliza a gravación</string>
|
||||
<string name="health_connect_not_available">Este dispositivo non é compatible con Saúde conectada</string>
|
||||
<string name="health_connect_open_settings_title">Axustes de Saúde conectada</string>
|
||||
<string name="health_connect_open_settings_summary">Abrir os axustes de Saúde conectada</string>
|
||||
<string name="health_connect_permissions_rationale_title">Permisos para Saúde conectada</string>
|
||||
<string name="health_connect_permissions_rationale_heading">De que xeito utiliza OpenTracks a Saúde conectada</string>
|
||||
<string name="health_connect_permissions_rationale_summary">Se o activas nos axustes, OpenTracks rexistra a actividade en Saúde conectada. OpenTracks non le os datos de Saúde conectada.</string>
|
||||
</resources>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">बेहतर GPS सिग्नल की प्रतीक्षा की जा रही है</string>
|
||||
<string name="gps_wait_for_signal">GPS सिग्नल की प्रतीक्षा की जा रही है</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">तीर</string>
|
||||
<string name="image_marker_count">मार्कर गणना</string>
|
||||
<string name="image_photo_marker">फ़ोटो मार्कर</string>
|
||||
<string name="image_record">रिकॉर्ड करें</string>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Čeka se bolji GPS signal</string>
|
||||
<string name="gps_wait_for_signal">Čeka se GPS signal</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Strelica</string>
|
||||
<string name="image_marker_count">Broj oznaka</string>
|
||||
<string name="image_photo_marker">Oznaka fotografije</string>
|
||||
<string name="image_record">Snimi</string>
|
||||
@@ -305,7 +304,7 @@ limitations under the License.
|
||||
<string name="waypoint_type_water_fountain">fontana</string>
|
||||
<string name="waypoint_type_waypoint">točka na ruti</string>
|
||||
<string name="settings_import_section">Uvoz</string>
|
||||
<string name="settings_export_section">Izvoz</string>
|
||||
<string name="settings_export_as_file_section">Izvoz</string>
|
||||
<string name="settings_prevent_reimport_tracks_title">Spriječi ponovni uvoz ruta</string>
|
||||
<string name="menu_export_all_one_file">Izvezi sve (jedna datoteka za sve rute)</string>
|
||||
<string name="menu_select_layout">Odaberi raspored</string>
|
||||
@@ -453,7 +452,6 @@ limitations under the License.
|
||||
<string name="custom_layout_select_layout">Odaberi raspored</string>
|
||||
<string name="settings_activity_defaults_category">Standardne vrijednosti aktivnosti</string>
|
||||
<string name="settings_sensor_bluetooth_service_filter_on">Prikaži samo Bluetooth uređaje koji najavljuju potrebne usluge</string>
|
||||
<string name="open_track_as_trackfileformat">Otvori kao %1$s</string>
|
||||
<string name="settings_api_title">Javni API</string>
|
||||
<string name="settings_announcements_distance_frequency">Duljina runde</string>
|
||||
<string name="unit_nautical_mile">NM</string>
|
||||
@@ -473,7 +471,6 @@ limitations under the License.
|
||||
<string name="value_float_kilometer_hour_recommended">%1$.1f km/h (preporučeno)</string>
|
||||
<string name="import_parser_error">Greška u obradi: %1$s</string>
|
||||
<string name="lap_speed">Brzina runde</string>
|
||||
<string name="always">Uvijek</string>
|
||||
<string name="settings_sensor_wheel_circumference">Opseg kotača (mm)</string>
|
||||
<string name="lap_time">Vrijeme runde</string>
|
||||
<string name="help_track_map_title">Kako prikazati rutu na karti\?</string>
|
||||
@@ -594,7 +591,6 @@ limitations under the License.
|
||||
<string name="create_marker_error">Nije moguće stvoriti oznaku. Pokušaj ponovo.</string>
|
||||
<string name="settings_night_mode_option_night_oled">Noć (pogodno za OLED)</string>
|
||||
<string name="power_x_watt">Snaga {x, plural, =1 {1 watt} few {# watta} other {# watta} }</string>
|
||||
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
|
||||
<string name="settings_announcements_lap_power">Snaga runde</string>
|
||||
<string name="power">Snaga</string>
|
||||
</resources>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Várakozás jobb GPS-jelre</string>
|
||||
<string name="gps_wait_for_signal">Várakozás GPS-jelre</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Nyíl</string>
|
||||
<string name="image_marker_count">Jelölőszámláló</string>
|
||||
<string name="image_photo_marker">Fényképjelölő</string>
|
||||
<string name="image_record">Felvétel</string>
|
||||
@@ -320,7 +319,6 @@ limitations under the License.
|
||||
<string name="help_track_map_title">Hogyan jelenítsünk meg egy nyomvonalat a térképen?</string>
|
||||
<string name="help_gps_troubleshooting_title">Az OpenTracks nem veszi fel a helyeket?</string>
|
||||
<string name="help_support_title">Hogyan tudom támogatni az OpenTracks-et?</string>
|
||||
<string name="open_track_as_trackfileformat">Megnyitás mint %1$s</string>
|
||||
<string name="activity_type_escooter">elektromos roller</string>
|
||||
<string name="help_recording_content">Az OpenTracks az eszköz GPS-érzékelőjét használja a hely folyamatos rögzítésére. Ha a GPS-eszköz pontatlan adatokat (pl. hely, sebesség, magasság) jelent, az OpenTracks semmit sem tehet ellene.</string>
|
||||
<string name="help_data_storage_title">Hogyan tárolja az OpenTracks az érzékelőadatokat\?</string>
|
||||
@@ -467,7 +465,7 @@ limitations under the License.
|
||||
<string name="average_heart_rate">Átlagos pulzusszám</string>
|
||||
<string name="settings_sensor_bluetooth_service_filter_on">Csak azokat a Bluetooth-eszközöket jelenítse meg, amelyek szükséges szolgáltatásokat kérnek</string>
|
||||
<string name="settings_import_section">Importálás</string>
|
||||
<string name="settings_export_section">Exportálás</string>
|
||||
<string name="settings_export_as_file_section">Exportálás</string>
|
||||
<string name="settings_layout_reset_confirm_title">Az elrendezések visszaállítása?</string>
|
||||
<string name="settings_layout_reset_done">Az összes elrendezési beállítás visszaállt az alapértelmezett értékekre</string>
|
||||
<string name="custom_layout_list_layout_removed">Az elrendezést eltávolították</string>
|
||||
@@ -477,7 +475,6 @@ limitations under the License.
|
||||
<string name="stats_custom_layout_default_layout">Alapértelmezett elrendezés</string>
|
||||
<string name="settings_layout_reset">Egyéni elrendezés visszaállítása</string>
|
||||
<string name="settings_cycling_sensor">Kerékpározás</string>
|
||||
<string name="always">Mindig</string>
|
||||
<string name="error_crash_title">Az %1$s összeomlott</string>
|
||||
<string name="settings_announcements_summary">Idő, távolság, beszédhang sebessége</string>
|
||||
<string name="settings_units_category">Egységek</string>
|
||||
@@ -578,7 +575,6 @@ limitations under the License.
|
||||
<string name="settings_announcements_lap_power">Kör teljesítmény</string>
|
||||
<string name="create_marker_error">Nem sikerült jelölőt létrehozni. Próbálja újra.</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } other {{n,number,#.0}} }</string>
|
||||
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
|
||||
<string name="power_x_watt">Teljesítmény {x, plural, =1 {1 watt} other {# watts} }</string>
|
||||
<string name="settings_locale_title">Nyelv</string>
|
||||
<string name="settings_locale_system_default">Rendszer alapértelmezett</string>
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
@@ -103,7 +103,6 @@
|
||||
<string name="gps_starting">Memulai GPS</string>
|
||||
<string name="gps_wait_for_better_signal">Menunggu sinyal GPS yang lebih baik</string>
|
||||
<string name="gps_wait_for_signal">Menunggu sinyal GPS</string>
|
||||
<string name="image_arrow">Panah</string>
|
||||
<string name="image_marker_count">Hitungan penanda</string>
|
||||
<string name="image_photo_marker">Penanda foto</string>
|
||||
<string name="image_record">Rekam</string>
|
||||
@@ -264,13 +263,12 @@
|
||||
<string name="import_progress_summary_errors_msg">Kesalahan</string>
|
||||
<string name="track_speed_notification">Kecepatan: %1$s</string>
|
||||
<string name="import_unable_to_import_file">Tidak bisa mengimpor berkas: %1$s</string>
|
||||
<string name="open_track_as_trackfileformat">Buka sebagai %1$s</string>
|
||||
<string name="track_distance_notification">Jarak: %1$s</string>
|
||||
<string name="settings_recording_show_on_lockscreen_while_recording_summary">Ketika merekam, Tampilkan statistik tanpa membuka perangkat.</string>
|
||||
<string name="about_libraries">Pustaka</string>
|
||||
<string name="help_feature_title">OpenTracks memiliki fitur-fitur berikut:</string>
|
||||
<string name="about_version_name">Nama Versi: %1$s</string>
|
||||
<string name="help_track_map_content">" Gunakan ikon peta kecil.\n\n a) (pembaruan langsung) Instal <a href=\"https://codeberg.org/OpenTracksApp/OSMDashboard\">OSMDashboard</a>. Ini menyediakan peta online atau offline melalui <a href=\"https://www.openstreetmap.org\">OpenStreetMap</a>.\n\n Sebenarnya, OSMDashboard adalah aplikasi terpisah yang hanya dapat mengakses (sementara) data trek yang akan ditampilkan.\n\n b) Melalui aplikasi peta biasa (misalnya, <a href=\"http://osmand.net/\">OsmAnd</a> dan <a href=\"https://maps.me/\">MAPS.ME< /a>). Aplikasi ini harus mendukung format file KMZ (hanya lokasi dan stempel waktu). Bahkan, aplikasi perlu mendukung <i>ACTION_VIEW</i> dengan MIME <i>application/vnd.google-earth.kmz</i>. "</string>
|
||||
<string name="help_track_map_content">" Gunakan ikon peta kecil.\n\n a) (pembaruan langsung) Instal <a href="https://codeberg.org/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Ini menyediakan peta online atau offline melalui <a href="https://www.openstreetmap.org\">OpenStreetMap</a>.\n\n Sebenarnya, OSMDashboard adalah aplikasi terpisah yang hanya dapat mengakses (sementara) data trek yang akan ditampilkan.\n\n b) Melalui aplikasi peta biasa (misalnya, <a href="http://osmand.net/">OsmAnd</a> dan <a href="https://maps.me/">MAPS.ME</a>). Aplikasi ini harus mendukung format file KMZ (hanya lokasi dan stempel waktu). Bahkan, aplikasi perlu mendukung <i>ACTION_VIEW</i>; dengan MIME <i>>application/vnd.google-earth.kmz</i>.</string>
|
||||
<string name="help_feature_content">* Buat trek GPS
|
||||
\n* Gunakan sensor denyut jantung (satu-satunya le Bluetooth)
|
||||
\n* suara pengumuman (oleh waktu atau jarak)
|
||||
|
||||
@@ -46,7 +46,6 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
||||
<string name="help_data_storage_title">In che modo OpenTracks memorizza i dati dei sensori?</string>
|
||||
<string name="help_gps_troubleshooting_title">OpenTracks non registra la posizione\?</string>
|
||||
<string name="help_support_title">Come posso supportare OpenTracks?</string>
|
||||
<string name="open_track_as_trackfileformat">Apri come %1$s</string>
|
||||
<!-- Activity Type -->
|
||||
<string name="activity_type_airplane">aereo</string>
|
||||
<string name="activity_type_atv">fuoristrada</string>
|
||||
@@ -158,7 +157,6 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
||||
<string name="gps_wait_for_better_signal">In attesa di un miglior segnale GPS</string>
|
||||
<string name="gps_wait_for_signal">In attesa del segnale GPS</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Freccia</string>
|
||||
<string name="image_marker_count">Contatore indicatori</string>
|
||||
<string name="image_photo_marker">Indicatore fotografico</string>
|
||||
<string name="image_record">Registra</string>
|
||||
@@ -448,7 +446,7 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
||||
<string name="settings_cycling_sensor">Ciclismo</string>
|
||||
<string name="settings_running_sensor">Corsa</string>
|
||||
<string name="settings_import_section">Importa</string>
|
||||
<string name="settings_export_section">Esporta</string>
|
||||
<string name="settings_export_as_file_section">Esporta</string>
|
||||
<string name="stats_coordinates">Latitudine/Longitudine</string>
|
||||
<string name="field_remove_from_layout">Rimuovi</string>
|
||||
<string name="field_set_primary">Primario</string>
|
||||
@@ -549,7 +547,6 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
||||
<string name="voiceDistanceMilesPlural">{n, plural, =1 {un miglio} other {{n,number,#.0} miglia} }</string>
|
||||
<string name="no_compatible_gallery_installed">Nessuna delle applicazioni galleria (foto) installate è compatibile</string>
|
||||
<string name="no_compatible_camera_installed">Nessuna delle applicazioni telecamera installate è compatibile</string>
|
||||
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
|
||||
<string name="settings_announcements_idle_category_title">Annunci di inattività</string>
|
||||
<string name="settings_announcements_idle_title">Inattività</string>
|
||||
<string name="settings_recording_title">Registrazione</string>
|
||||
@@ -584,7 +581,6 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
||||
<string name="unit_nautical_mile">MN</string>
|
||||
<string name="help_data_google_play_services_content">No</string>
|
||||
<string name="generic_dismiss">Ignora</string>
|
||||
<string name="always">Sempre</string>
|
||||
<string name="activity_type_swimming">nuoto</string>
|
||||
<string name="gps_recording_status">%1$s: %2$s</string>
|
||||
<string name="activity_type_swimming_open">nuoto in mare</string>
|
||||
@@ -604,7 +600,6 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
||||
<string name="voiceSpeed">{n, plural, =1 {1} other {{n,number,#.0}} }</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } other {{n,number,#.0}} }</string>
|
||||
<string name="lap_heart_rate">Frequenza cardiaca del giro</string>
|
||||
<string name="empty">vuoto</string>
|
||||
<string name="settings_recording_show_gps_disabled_warning_summary">Durante la registrazione, mostra un avviso se il GPS è disabilitato.</string>
|
||||
<string name="settings_night_mode_option_day_dynamic">Giorno (colore dinamico)</string>
|
||||
<string name="track_edit_time_offset">Compensazione fuso orario</string>
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
<string name="gps_starting">מפעיל את ה-GPS</string>
|
||||
<string name="gps_wait_for_better_signal">ממתין לאות GPS טוב יותר</string>
|
||||
<string name="gps_wait_for_signal">ממתין לאות GPS</string>
|
||||
<string name="image_arrow">חץ</string>
|
||||
<string name="image_marker_count">ספירת סמן</string>
|
||||
<string name="image_photo_marker">סמן תמונות</string>
|
||||
<string name="image_record">הקלט</string>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">GPS信号の精度が上がるまで待機しています</string>
|
||||
<string name="gps_wait_for_signal">GPS信号を待機しています</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">矢印</string>
|
||||
<string name="image_marker_count">マーカー数</string>
|
||||
<string name="image_photo_marker">写真マーカー</string>
|
||||
<string name="image_record">記録</string>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<string name="about_version_name">ಆವೃತ್ತಿಯ ಹೆಸರು: %1$s</string>
|
||||
<string name="help_storage_pictures_content">ಇವುಗಳನ್ನು ಅಪ್ಲಿಕೇಶನ್ನ ಆಂತರಿಕ ಸಂಗ್ರಹಣೆಯಲ್ಲಿ ಸಂಗ್ರಹಿಸಲಾಗಿದೆ (ಅಂದರೆ, OpenTracks ನಲ್ಲಿ ಮಾತ್ರ ಪ್ರವೇಶಿಸಬಹುದಾಗಿದೆ).</string>
|
||||
<string name="about_preference_title">OpenTracks ಕುರಿತು</string>
|
||||
<string name="help_track_map_content">" ಸಣ್ಣ ನಕ್ಷೆ ಐಕಾನ್ ಬಳಸಿ.\n\n a) (ಲೈವ್ ಅಪ್ಡೇಟ್ಗಳು) <a href=\"https://codeberg.org/OpenTracksApp/OSMDashboard\">OSMDashboard</a> ಅನ್ನು ಸ್ಥಾಪಿಸಿ. ಇದು ಆನ್ಲೈನ್ ಅಥವಾ ಆಫ್ಲೈನ್ ನಕ್ಷೆಗಳನ್ನು <a href=\"https://www.openstreetmap.org\">OpenStreetMap</a> ಮೂಲಕ ಒದಗಿಸುತ್ತದೆ.\n\n ವಾಸ್ತವವಾಗಿ, OSMDashboard ಒಂದು ಪ್ರತ್ಯೇಕ ಅಪ್ಲಿಕೇಶನ್ ಆಗಿದ್ದು ಅದು ತೋರಿಸಲಿರುವ ಟ್ರ್ಯಾಕ್(ಗಳ) ಡೇಟಾವನ್ನು ಮಾತ್ರ ಪ್ರವೇಶಿಸಬಹುದು (ತಾತ್ಕಾಲಿಕವಾಗಿ).\n\n ಬಿ) ಸಾಮಾನ್ಯ ನಕ್ಷೆ ಅಪ್ಲಿಕೇಶನ್ ಮೂಲಕ (ಉದಾ., <a href=\"http://osmand.net/\">OsmAnd</a> ಮತ್ತು <a href=\"https://maps.me/\">MAPS.ME< /a>). ಈ ಅಪ್ಲಿಕೇಶನ್ಗಳು KMZ ಫೈಲ್ ಫಾರ್ಮ್ಯಾಟ್ ಅನ್ನು ಬೆಂಬಲಿಸುವ ಅಗತ್ಯವಿದೆ (ಸ್ಥಳಗಳು ಮತ್ತು ಸಮಯಸ್ಟ್ಯಾಂಪ್ಗಳು ಮಾತ್ರ). ವಾಸ್ತವವಾಗಿ, ಒಂದು ಅಪ್ಲಿಕೇಶನ್ MIME <i>application/vnd.google-earth.kmz</i> ಜೊತೆಗೆ <i>ACTION_VIEW</i> ಅನ್ನು ಬೆಂಬಲಿಸುವ ಅಗತ್ಯವಿದೆ. "</string>
|
||||
<string name="help_track_map_content">" ಸಣ್ಣ ನಕ್ಷೆ ಐಕಾನ್ ಬಳಸಿ.\n\n a) (ಲೈವ್ ಅಪ್ಡೇಟ್ಗಳು) <a href="https://codeberg.org/OpenTracksApp/OSMDashboard">OSMDashboard</a> ಅನ್ನು ಸ್ಥಾಪಿಸಿ. ಇದು ಆನ್ಲೈನ್ ಅಥವಾ ಆಫ್ಲೈನ್ ನಕ್ಷೆಗಳನ್ನು <a href="https://www.openstreetmap.org">OpenStreetMap</a> ಮೂಲಕ ಒದಗಿಸುತ್ತದೆ.\n\n ವಾಸ್ತವವಾಗಿ, OSMDashboard ಒಂದು ಪ್ರತ್ಯೇಕ ಅಪ್ಲಿಕೇಶನ್ ಆಗಿದ್ದು ಅದು ತೋರಿಸಲಿರುವ ಟ್ರ್ಯಾಕ್(ಗಳ) ಡೇಟಾವನ್ನು ಮಾತ್ರ ಪ್ರವೇಶಿಸಬಹುದು (ತಾತ್ಕಾಲಿಕವಾಗಿ).\n\n ಬಿ) ಸಾಮಾನ್ಯ ನಕ್ಷೆ ಅಪ್ಲಿಕೇಶನ್ ಮೂಲಕ (ಉದಾ., <a href="http://osmand.net/">OsmAnd</a> ಮತ್ತು <a href="https://maps.me/">MAPS.ME</a>). ಈ ಅಪ್ಲಿಕೇಶನ್ಗಳು KMZ ಫೈಲ್ ಫಾರ್ಮ್ಯಾಟ್ ಅನ್ನು ಬೆಂಬಲಿಸುವ ಅಗತ್ಯವಿದೆ (ಸ್ಥಳಗಳು ಮತ್ತು ಸಮಯಸ್ಟ್ಯಾಂಪ್ಗಳು ಮಾತ್ರ). ವಾಸ್ತವವಾಗಿ, ಒಂದು ಅಪ್ಲಿಕೇಶನ್ MIME <i>application/vnd.google-earth.kmz</i> ಜೊತೆಗೆ <i>ACTION_VIEW</i> ಅನ್ನು ಬೆಂಬಲಿಸುವ ಅಗತ್ಯವಿದೆ.</string>
|
||||
<string name="about_url">ಪ್ರಾಜೆಕ್ಟ್ ವೆಬ್ ಪುಟ: <a href="%1$s">%1$s</a></string>
|
||||
<string name="help_track_export_title">ರೆಕಾರ್ಡ್ ಮಾಡಿದ ಟ್ರ್ಯಾಕ್ಗಳನ್ನು ನಾನು ಹೇಗೆ ರಫ್ತು ಮಾಡುವುದು/ಹಂಚಿಕೊಳ್ಳಬಹುದು?</string>
|
||||
<string name="help_storage_pictures_title">ಮಾರ್ಕರ್ಗಳಾಗಿ ತೆಗೆದ ಚಿತ್ರಗಳನ್ನು OpenTracks ಹೇಗೆ ಸಂಗ್ರಹಿಸುತ್ತದೆ?</string>
|
||||
@@ -33,7 +33,6 @@
|
||||
\n
|
||||
\n \u0020 ಎಲ್ಲವೂ ಸಹಾಯ ಮಾಡದಿದ್ದರೆ ದಯವಿಟ್ಟು ದೋಷವನ್ನು ವರದಿ ಮಾಡಿ. \u0020</string>
|
||||
<string name="help_support_title">ನಾನು OpenTracks ಅನ್ನು ಹೇಗೆ ಬೆಂಬಲಿಸಬಹುದು?</string>
|
||||
<string name="open_track_as_trackfileformat">%1$s ನಂತೆ ತೆರೆಯಿರಿ</string>
|
||||
<string name="activity_type_airplane">ವಿಮಾನ</string>
|
||||
<string name="activity_type_atv">ATV</string>
|
||||
<string name="activity_type_biking">ಬೈಕಿಂಗ್</string>
|
||||
@@ -180,7 +179,6 @@
|
||||
<string name="gps_fixed_and_ready">GPS ಸ್ಥಿರವಾಗಿದೆ ಮತ್ತು ಸಿದ್ಧವಾಗಿದೆ</string>
|
||||
<string name="gps_recording_status">%1$s: %2$s</string>
|
||||
<string name="gps_recording_without_signal">OpenTracks GPS ಡೇಟಾ ಇಲ್ಲದೆ ರೆಕಾರ್ಡಿಂಗ್ ಮಾಡುತ್ತಿದೆ.</string>
|
||||
<string name="image_arrow">ಬಾಣ</string>
|
||||
<string name="image_marker_count">ಮಾರ್ಕರ್ ಎಣಿಕೆ</string>
|
||||
<string name="image_photo_marker">ಚಿತ್ರ ಮಾರ್ಕರ್</string>
|
||||
<string name="image_record">ರೆಕಾರ್ಡ್ ಮಾಡಿ</string>
|
||||
@@ -333,7 +331,7 @@
|
||||
<string name="settings_public_api_dashboard_enabled_summary_on">ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಿದ ಅಪ್ಲಿಕೇಶನ್ ರೆಕಾರ್ಡ್ ಮಾಡಿದ ಡೇಟಾವನ್ನು ಸಹ ಪ್ರವೇಶಿಸಬಹುದು.</string>
|
||||
<string name="settings_public_api_dashboard_enabled_summary_off">ರೆಕಾರ್ಡ್ ಮಾಡಲಾದ ಡೇಟಾವನ್ನು ಇತರ ಅಪ್ಲಿಕೇಶನ್ಗಳೊಂದಿಗೆ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಹಂಚಿಕೊಳ್ಳಲಾಗುವುದಿಲ್ಲ.</string>
|
||||
<string name="settings_import_section">ಆಮದು</string>
|
||||
<string name="settings_export_section">ರಫ್ತು</string>
|
||||
<string name="settings_export_as_file_section">ರಫ್ತು</string>
|
||||
<string name="settings_prevent_reimport_tracks_title">ಟ್ರ್ಯಾಕ್ಗಳ ಮರು-ಆಮದು ತಡೆಯಿರಿ</string>
|
||||
<string name="share_track_share_file_body">ನೀವು ಈ ಟ್ರ್ಯಾಕ್ನಲ್ಲಿ ಆಸಕ್ತಿ ಹೊಂದಿರಬಹುದು ಎಂದು ನಾನು ಭಾವಿಸುತ್ತೇನೆ.
|
||||
\n
|
||||
@@ -493,7 +491,6 @@
|
||||
<string name="report_bug">ದೋಷವನ್ನು ವರದಿ ಮಾಡಿ</string>
|
||||
<string name="show_on_dashboard">OpenTracks ಡ್ಯಾಶ್ಬೋರ್ಡ್ API</string>
|
||||
<string name="show_on_dashboard_not_installed">OpenTracks ಡ್ಯಾಶ್ಬೋರ್ಡ್ API ಅನ್ನು ಬೆಂಬಲಿಸುವ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ.</string>
|
||||
<string name="always">ಯಾವಾಗಲೂ</string>
|
||||
<string name="settings_announcements_distance_frequency">ಲ್ಯಾಪ್ ಉದ್ದ</string>
|
||||
<string name="help_track_export_content"> \u0020ಟ್ರ್ಯಾಕ್ಗಳನ್ನು ಸೆಟ್ಟಿಂಗ್ಗಳಿಂದ KMZ, KML ಅಥವಾ GPX ಆಗಿ ರಫ್ತು ಮಾಡಬಹುದು. KMZ/KML ಎಲ್ಲಾ ಡೇಟಾ; GPX ಮಾತ್ರ ಸ್ಥಳಗಳು. <i>ಹಂಚಿಕೆ ಐಕಾನ್</i> ಮೂಲಕ ಹಂಚಲಾದ ಟ್ರ್ಯಾಕ್ಗಳನ್ನು KMZ ನಂತೆ ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತದೆ. \u0020</string>
|
||||
<string name="help_recording_content">ಸ್ಥಳವನ್ನು ನಿರಂತರವಾಗಿ ರೆಕಾರ್ಡ್ ಮಾಡಲು OpenTracks ಸಾಧನದ GPS ಸಂವೇದಕವನ್ನು ಬಳಸುತ್ತದೆ. GPS ಸಾಧನವು ತಪ್ಪಾದ ಡೇಟಾವನ್ನು ವರದಿ ಮಾಡಿದರೆ (ಉದಾ., ಸ್ಥಳ, ವೇಗ, ಎತ್ತರ), OpenTracks ಅದರ ಬಗ್ಗೆ ಏನನ್ನೂ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ.</string>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">더 나은 GPS 신호 대기 중</string>
|
||||
<string name="gps_wait_for_signal">GPS 신호 대기 중</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">화살표</string>
|
||||
<string name="image_marker_count">마커 수</string>
|
||||
<string name="image_photo_marker">사진 마커</string>
|
||||
<string name="image_record">기록</string>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Laukiama geresnio GPS signalo</string>
|
||||
<string name="gps_wait_for_signal">Laukiama GPS signalo</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Rodyklė</string>
|
||||
<string name="image_marker_count">Žymeklių skaičius</string>
|
||||
<string name="image_photo_marker">Nuotraukos žymeklis</string>
|
||||
<string name="image_record">Įrašyti</string>
|
||||
@@ -346,7 +345,6 @@ limitations under the License.
|
||||
<string name="help_track_map_title">Kaip parodyti takelį žemėlapyje\?</string>
|
||||
<string name="settings_default_export_uri_title">Sekti eksporto katalogą</string>
|
||||
<string name="sensor_state_cadence_avg">Vidutinis Kadencija</string>
|
||||
<string name="open_track_as_trackfileformat">Atidaryti kaip %1$s</string>
|
||||
<string name="help_feature_content">* sukurti GPS takelius
|
||||
\n * naudokite širdies ritmo jutiklį (tik „Bluetooth LE“)
|
||||
\n * balso pranešimai (pagal laiką ar atstumą)
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Gaida spēcīgāku GPS signālu</string>
|
||||
<string name="gps_wait_for_signal">Gaida GPS signālu</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Bultiņa</string>
|
||||
<string name="image_marker_count">Atzīmju numerācija</string>
|
||||
<string name="image_photo_marker">Fotoattēlu atzīme</string>
|
||||
<string name="image_record">Ierakstīt</string>
|
||||
@@ -392,7 +391,6 @@ limitations under the License.
|
||||
<string name="import_error_list_dialog_title">Faili nav importēti</string>
|
||||
<string name="settings_recording_fullscreen_on_while_recording_title">Pilna ekrāna</string>
|
||||
<string name="generic_skip">Izlaist .</string>
|
||||
<string name="open_track_as_trackfileformat">Atvērts kā %1$s</string>
|
||||
<string name="settings_recording_keep_screen_on_while_recording_title">Ekrāna ieslēgšana</string>
|
||||
<string name="share_image_body">Domāju, ka jūs varētu ieinteresēt šis attēls.</string>
|
||||
<string name="export_progress_summary_overwrite_msg">Pārrakstītās dziesmas</string>
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
<string name="gps_starting">Se pornește GPS</string>
|
||||
<string name="gps_wait_for_better_signal">Se așteaptă un semnal GPS mai bun</string>
|
||||
<string name="gps_wait_for_signal">Se așteaptă semnal GPS</string>
|
||||
<string name="image_arrow">Săgeată</string>
|
||||
<string name="image_marker_count">Număr marcator</string>
|
||||
<string name="image_photo_marker">Marcator fotografie</string>
|
||||
<string name="image_record">Înregistrați</string>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Menunggu isyarat GPS yang lebih baik</string>
|
||||
<string name="gps_wait_for_signal">Menunggu isyarat GPS</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Anak panah</string>
|
||||
<string name="image_marker_count">Kiraan penanda</string>
|
||||
<string name="image_photo_marker">Penanda foto</string>
|
||||
<string name="image_record">Rakam</string>
|
||||
|
||||
@@ -125,7 +125,6 @@ limitations under the License.
|
||||
<string name="gps_wait_for_better_signal">Venter på bedre GPS-signal</string>
|
||||
<string name="gps_wait_for_signal">Venter på GPS-signal</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Pil</string>
|
||||
<string name="image_marker_count">Markørantall</string>
|
||||
<string name="image_photo_marker">Bildemarkør</string>
|
||||
<string name="image_record">Ta opp</string>
|
||||
@@ -342,7 +341,6 @@ limitations under the License.
|
||||
<string name="settings_default_export_uri_title">Mappe for sporeksport</string>
|
||||
<string name="share_image_body">Jeg tror du kan være interessert i dette bildet.</string>
|
||||
<string name="about_preference_title">Om</string>
|
||||
<string name="open_track_as_trackfileformat">Åpne som %1$s</string>
|
||||
<string name="export_with_photos">med bilder</string>
|
||||
<string name="export_track_already_exists_msg">Filen %1$s finnes allerede i målmappen.</string>
|
||||
<string name="import_unsupported_format">Filformatet støttes ikke</string>
|
||||
@@ -437,7 +435,7 @@ limitations under the License.
|
||||
<string name="settings_cycling_sensor">Sykling</string>
|
||||
<string name="settings_running_sensor">Løping</string>
|
||||
<string name="settings_import_section">Import</string>
|
||||
<string name="settings_export_section">Eksport</string>
|
||||
<string name="settings_export_as_file_section">Eksport</string>
|
||||
<string name="value_float_kilometer_hour">%1$.1f km/t</string>
|
||||
<string name="value_float_kilometer_hour_recommended">%1$.1f km/t (anbefales)</string>
|
||||
<string name="value_float_mile_hour">%1$.1f mi/h</string>
|
||||
@@ -505,7 +503,6 @@ limitations under the License.
|
||||
<string name="share_crash_report">Del krasjrapport</string>
|
||||
<string name="report_bug">Rapporter feil</string>
|
||||
<string name="show_on_dashboard">OpenTracks dashbord API</string>
|
||||
<string name="always">Alltid</string>
|
||||
<string name="settings_announcements_average_heart_rate">Gjennomsnittlig puls</string>
|
||||
<string name="settings_announcements_lap_heart_rate">Runde-puls</string>
|
||||
<string name="settings_announcements_average_speed_pace">Gjen. hastighet/tempo</string>
|
||||
|
||||
@@ -160,7 +160,6 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
|
||||
<string name="gps_wait_for_better_signal">Wachten op een beter GPS-signaal</string>
|
||||
<string name="gps_wait_for_signal">Wachten op GPS-signaal</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Pijl</string>
|
||||
<string name="image_marker_count">Aantal markeringen</string>
|
||||
<string name="image_photo_marker">Fotomarkering</string>
|
||||
<string name="image_record">Opnemen</string>
|
||||
@@ -359,7 +358,6 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
|
||||
<string name="export_track_errors">Bestanden niet geëxporteerd</string>
|
||||
<string name="description_altitude_loss">Hoogteverlies: %1$d m (%2$d ft)</string>
|
||||
<string name="export_error_post_workout">Uitvoer na de training mislukt, controleer de uitvoermap.</string>
|
||||
<string name="open_track_as_trackfileformat">Als %1$s openen</string>
|
||||
<string name="activity_type_escooter">scooter</string>
|
||||
<string name="export_all_do_it_for_all">doe het voor alle conflicten</string>
|
||||
<string name="export_progress_summary_new_msg">Nieuwe bestanden geëxporteerd</string>
|
||||
@@ -465,7 +463,7 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
|
||||
<string name="settings_cycling_sensor">Fietsen</string>
|
||||
<string name="settings_running_sensor">Hardlopen</string>
|
||||
<string name="settings_import_section">Invoer</string>
|
||||
<string name="settings_export_section">Uitvoer</string>
|
||||
<string name="settings_export_as_file_section">Uitvoer</string>
|
||||
<string name="settings_generic_sensor">Generiek</string>
|
||||
<string name="export_dir_not_writable">" (geen schrijfrecht!)"</string>
|
||||
<string name="value_float_kilometer_hour_recommended">%1$.1f km/u (aanbevolen)</string>
|
||||
@@ -521,7 +519,6 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
|
||||
<string name="track_discarding">Track weggooien</string>
|
||||
<string name="settings_announcements_lap_speed_pace">Snelheid/tred per ronde</string>
|
||||
<string name="show_on_dashboard">OpenTracks Dashboard API</string>
|
||||
<string name="always">Altijd</string>
|
||||
<string name="show_on_dashboard_not_installed">Er is geen app geïnstalleerd die OpenTracks Dashboard API ondersteunt.</string>
|
||||
<string name="help_data_google_play_services_content">Nee</string>
|
||||
<string name="introduction_osm_dashboard">OpenTracks zelf biedt geen kaart. Installeer OSMDashboard om uw opnames op een kaart te bekijken.</string>
|
||||
@@ -581,7 +578,6 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
|
||||
<string name="settings_announcements_unit">Afstand-/snelheidseenheid</string>
|
||||
<string name="voiceSpeed">{n, plural, =1 {1} other {{n,number,#.0}} }</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } other {{n,number,#.0}} }</string>
|
||||
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
|
||||
<string name="power">Power</string>
|
||||
<string name="settings_announcements_lap_power">Lap power</string>
|
||||
<string name="power_x_watt">Power {x, plural, =1 {1 watt} other {# watt} }</string>
|
||||
|
||||
@@ -135,7 +135,6 @@ limitations under the License.
|
||||
<string name="gps_disabled_msg">GPS niedostępny</string>
|
||||
<string name="gps_fixed_and_ready">Pozycja GPS ustalona</string>
|
||||
<!-- Image -->
|
||||
<string name="image_arrow">Strzałka</string>
|
||||
<string name="image_marker_count">Liczba znaczników</string>
|
||||
<string name="image_photo_marker">Znacznik zdjęcia</string>
|
||||
<string name="image_record">Rejestruj</string>
|
||||
@@ -343,7 +342,6 @@ limitations under the License.
|
||||
<string name="about_libraries">Biblioteki</string>
|
||||
<string name="help_feature_title">OpenTracks posiada następujące funkcje:</string>
|
||||
<string name="help_track_map_title">Jak pokazywać trasę na mapie\?</string>
|
||||
<string name="open_track_as_trackfileformat">Otwórz jako %1$s</string>
|
||||
<string name="about_description"><i>OpenTracks</i> to aplikacja do śledzenia aktywności sportowej która całkowicie respektuje Twoją prywatność.</string>
|
||||
<string name="hold_to_stop">Przytrzymaj, aby zatrzymać</string>
|
||||
<string name="instant_export_enabled_title">Automatyczny eksport po ćwiczeniu</string>
|
||||
@@ -450,7 +448,7 @@ limitations under the License.
|
||||
<string name="settings_cycling_sensor">Kolarstwo</string>
|
||||
<string name="settings_running_sensor">Bieganie</string>
|
||||
<string name="settings_import_section">Import</string>
|
||||
<string name="settings_export_section">Eksport</string>
|
||||
<string name="settings_export_as_file_section">Eksport</string>
|
||||
<string name="settings_generic_sensor">Domyślny</string>
|
||||
<string name="description_speed_source_gps">GPS</string>
|
||||
<string name="permission_bluetooth_failed">OpenTracks wymaga uprawnień do urzycia Bluetooth.</string>
|
||||
@@ -572,7 +570,6 @@ limitations under the License.
|
||||
<string name="settings_public_api_enabled_title">Publiczne API</string>
|
||||
<string name="settings_announcements_idle_category_title">Powiadomienia o przerwach</string>
|
||||
<string name="pace">Tempo</string>
|
||||
<string name="always">Zawsze</string>
|
||||
<string name="settings_night_mode_option_system_dynamic">Systemowy (dynamiczne kolory)</string>
|
||||
<string name="settings_night_mode_option_day_dynamic">Dzień (dynamiczne kolory)</string>
|
||||
<string name="settings_night_mode_option_night_dynamic">Noc (dynamiczne kolory)</string>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<string name="activity_type_train">treino</string>
|
||||
<string name="activity_type_ultimate_frisbee">frisbee definitivo</string>
|
||||
<string name="activity_type_unknown">desconhecida</string>
|
||||
<string name="activity_type_wakeboarding">esqui aquático</string>
|
||||
<string name="activity_type_wakeboarding">wakeboarding</string>
|
||||
<string name="activity_type_walking">caminhada</string>
|
||||
<string name="activity_type_water_skiing">esqui aquático</string>
|
||||
<string name="activity_type_wind_surfing">windsurfe</string>
|
||||
@@ -103,7 +103,6 @@
|
||||
<string name="gps_starting">Iniciando GPS</string>
|
||||
<string name="gps_wait_for_better_signal">Aguardando sinal de GPS melhor</string>
|
||||
<string name="gps_wait_for_signal">Aguardando sinal de GPS</string>
|
||||
<string name="image_arrow">Seta</string>
|
||||
<string name="image_marker_count">Contagem do marcador</string>
|
||||
<string name="image_photo_marker">Marcador de foto</string>
|
||||
<string name="image_record">Gravar</string>
|
||||
@@ -136,7 +135,7 @@
|
||||
<string name="recording_service">Serviço de gravação</string>
|
||||
<string name="sensor_state_heart_rate">Frequência cardíaca</string>
|
||||
<string name="sensor_state_heart_rate_value">%1$d bom</string>
|
||||
<string name="sensor_state_power">Alimentação</string>
|
||||
<string name="sensor_state_power">Potência</string>
|
||||
<string name="settings_advanced">Avançado</string>
|
||||
<string name="settings_chart_by_distance">Por distância</string>
|
||||
<string name="settings_chart_by_time">Por tempo</string>
|
||||
@@ -280,7 +279,7 @@
|
||||
<string name="settings_default_export_uri_title">Diretório de exportação de trilhas</string>
|
||||
<string name="stats_split_interval">Intervalo de divisão</string>
|
||||
<string name="track_recording_notification_accuracy">Precisão da localização: %1$s</string>
|
||||
<string name="about_preference_title">Sobre OpenTracks</string>
|
||||
<string name="about_preference_title">Sobre</string>
|
||||
<string name="about_description"><i>OpenTracks</i> é um aplicativo de rastreamento de esportes que respeita totalmente a sua privacidade.</string>
|
||||
<string name="help_feature_content">* criar trilhas de GPS
|
||||
\n* use um sensor de frequência cardíaca (apenas Bluetooth LE)
|
||||
@@ -288,10 +287,7 @@
|
||||
\n* criar marcadores (incluindo imagens)
|
||||
\n* funciona completamente offline
|
||||
\n* mostrar trilhas em um mapa (veja abaixo)</string>
|
||||
<string name="help_track_map_content"> Use o pequeno ícone do mapa.
|
||||
\n a) (atualizações ao vivo) Instale <a href="https://codeberg.org/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Ele fornece mapas online ou offline via <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
|
||||
\n Na verdade, OSMDashboard é um aplicativo separado que só pode acessar (temporariamente) os dados da(s) trilha(s) que serão mostradas.
|
||||
\n b) Por meio de um aplicativo de mapa normal (por exemplo, <a href="http://osmand.net/">OsmAn </a> e <a href="https://maps.me/">MAPS.ME</a>). Esses aplicativos precisam ser compatíveis com o formato de arquivo KMZ (apenas locais e marcações de data/hora). Na verdade, um aplicativo precisa ser compatível com<i>ACTION_VIEW</i> com MIME<i> application/vnd.google-earth.kmz</i>. </string>
|
||||
<string name="help_track_map_content">Use o pequeno ícone no mapa.\n a) (atualizações ao vivo) Instale <a href="https://codeberg.org/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Ele fornece mapas online ou offline via <a href="https://www.openstreetmap.org">OpenStreetMap</a>.\n Na verdade, OSMDashboard é um aplicativo separado que só pode acessar (temporariamente) os dados da(s) trilha(s) que serão mostradas. \n b) Por meio de um aplicativo de mapa normal (por exemplo:, <a href="http://osmand.net/">OsmAnd</a> e <a href="https://maps.me/">MAPS.ME</a>). Esses aplicativos precisam ser compatíveis com o formato de arquivo KMZ (apenas locais e marcações de data/hora). Na verdade, um aplicativo precisa ser compatível com <i>ACTION_VIEW</i> com MIME <i>application/vnd.google-earth.kmz</i>.</string>
|
||||
<string name="help_data_storage_content"> Os dados do sensor são armazenados por local registrado. Em termos de sensor de frequência cardíaca, isso significa que apenas <i>uma</i> medição de frequência cardíaca é armazenada por local. Se você estiver parado ou dentro de casa, nenhum dado do sensor será registrado (mas será mostrado). </string>
|
||||
<string name="help_support_content"> Você pode:
|
||||
\n a) espalhe a palavra sobre OpenTracks,
|
||||
@@ -304,6 +300,7 @@
|
||||
<string name="activity_type_escooter">escolta</string>
|
||||
<plurals name="generic_completed_with_errors">
|
||||
<item quantity="one">Concluído com %1$d erro</item>
|
||||
<item quantity="many">Concluído com %1$d erros</item>
|
||||
<item quantity="other">Concluído com %1$d erros</item>
|
||||
</plurals>
|
||||
<string name="import_unsupported_format">Formato de arquivo não suportado</string>
|
||||
@@ -337,7 +334,6 @@
|
||||
\n
|
||||
\n Se tudo não ajudar, por favor relate um bug. </string>
|
||||
<string name="help_support_title">Como posso oferecer suporte a OpenTracks\?</string>
|
||||
<string name="open_track_as_trackfileformat">Abrir como %1$s</string>
|
||||
<string name="help_track_export_title">Como posso exportar/compartilhar trilhas gravadas\?</string>
|
||||
<string name="description_speed_ms">Velocidade (m/s)</string>
|
||||
<string name="description_default_speed_or_pace">Por tipo de atividade</string>
|
||||
@@ -372,7 +368,7 @@
|
||||
<string name="import_progress_summary_exists_msg">Já existe</string>
|
||||
<string name="import_progress_summary_errors_msg">Erros</string>
|
||||
<string name="sensor_state_heart_rate_max">Freqüência cardíaca máxima</string>
|
||||
<string name="sensor_state_power_avg">Energia Avg</string>
|
||||
<string name="sensor_state_power_avg">Potência Média</string>
|
||||
<string name="sensor_state_heart_rate_avg">Ritmo cardíaco Avg</string>
|
||||
<string name="sensor_state_cadence_max">Ritmo cardíaco médio</string>
|
||||
<string name="sensor_state_cadence_avg">Avg Cadência</string>
|
||||
@@ -396,7 +392,7 @@
|
||||
<string name="settings_layout_reset_done">Todas as configurações de layout foram revertidas para os valores padrão</string>
|
||||
<string name="settings_all_reset">Redefinir</string>
|
||||
<string name="stats_coordinates">Latitude/Longitude</string>
|
||||
<string name="stats_sensors_power">Poder</string>
|
||||
<string name="stats_sensors_power">Potência</string>
|
||||
<string name="field_set_primary">Primário</string>
|
||||
<string name="field_set_secondary">Secundário</string>
|
||||
<string name="field_remove_from_layout">Remover</string>
|
||||
@@ -412,7 +408,7 @@
|
||||
<string name="settings_cycling_sensor">Ciclismo</string>
|
||||
<string name="settings_running_sensor">Correndo</string>
|
||||
<string name="settings_import_section">Importar</string>
|
||||
<string name="settings_export_section">Exportar</string>
|
||||
<string name="settings_export_as_file_section">Exportar</string>
|
||||
<string name="value_float_kilometer_hour">%1$.1f km/h</string>
|
||||
<string name="value_float_kilometer_hour_recommended">%1$.1f km/h (Recomendado)</string>
|
||||
<string name="stats_clock">Relógio</string>
|
||||
@@ -498,6 +494,76 @@
|
||||
<string name="error_crash_title">%1$s falharam</string>
|
||||
<string name="share_crash_report">Compartilhar relatório de falha</string>
|
||||
<string name="show_on_dashboard">Painel API do OpenTracks</string>
|
||||
<string name="always">Sempre</string>
|
||||
<string name="description_speed_nautical">Velocidade (nós)</string>
|
||||
</resources>
|
||||
<string name="help_data_google_play_services_content">Não</string>
|
||||
<string name="activity_type_gravel_biking">ciclismo de gravel</string>
|
||||
<string name="activity_type_kickscooter">patinete</string>
|
||||
<string name="description_sensor_temperature">Temperatura (Celsius)</string>
|
||||
<string name="create_marker_error">Incapaz de criar um marcador. Tente outra vez.</string>
|
||||
<string name="marker_detail_title">%1$d de %2$d: %3$s</string>
|
||||
<string name="menu_export_all_one_file">Exportar tudo (Um arquivo para todas as trilhas)</string>
|
||||
<string name="permission_recording_failed">OpenTracks precisa de permissão para acessar a sua localização e dispositivos próximos.</string>
|
||||
<string name="sensor_state_cadence_unit">rpm</string>
|
||||
<string name="sensor_state_heart_rate_unit">bpm</string>
|
||||
<string name="sensor_state_temperature">Termômetro</string>
|
||||
<string name="sensor_state_pressure">Barômetro</string>
|
||||
<string name="sensor_state_power_max">Potência Máxima</string>
|
||||
<string name="sensor_state_power_unit">W</string>
|
||||
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
|
||||
<string name="settings_announcements_idle_category_title">Anúncios de Inatividade</string>
|
||||
<string name="settings_announcements_idle_title">Inativo</string>
|
||||
<string name="settings_charts_title">Gráficos</string>
|
||||
<string name="settings_chart_display_elevation_title">Mostrar elevação</string>
|
||||
<string name="settings_chart_display_pace_or_speed_title">Mostrar ritmo ou velocidade</string>
|
||||
<string name="settings_chart_display_heart_rate_title">Mostrar frequência cardíaca</string>
|
||||
<string name="settings_recording_title">Gravação</string>
|
||||
<string name="settings_theme_switch_restart">Mudanças de tema podem exigir uma reinicialização manual.</string>
|
||||
<string name="settings_ui_dynamic_colors_title">Cores Dinâmicas</string>
|
||||
<string name="settings_ui_dynamic_colors_summary">Utilizar Cores Dinâmicas definidas pelo usuário (Android 12+ apenas; necessita de reinicialização manual.)</string>
|
||||
<string name="settings_recording_show_gps_disabled_warning_title">Aviso de GPS desabilitado</string>
|
||||
<string name="settings_recording_show_gps_disabled_warning_summary">Ao gravar, exibir um aviso se o GPS estiver desabilitado.</string>
|
||||
<string name="settings_recording_min_required_accuracy_summary">Localização é ignorada se sua precisão for maior que %1$s</string>
|
||||
<string name="settings_recording_idle_timeout_title">Limiar inativo</string>
|
||||
<string name="settings_locale_title">Língua</string>
|
||||
<string name="settings_locale_system_default">Padrão do sistema</string>
|
||||
<string name="settings_night_mode_option_system_dynamic">Sistema (Cores Dinâmicas)</string>
|
||||
<string name="settings_night_mode_option_day_dynamic">Dia (Cores Dinâmicas)</string>
|
||||
<string name="settings_night_mode_option_night_dynamic">Noite (Cores Dinâmicas)</string>
|
||||
<string name="settings_night_mode_option_night_oled">OLED compatível</string>
|
||||
<string name="settings_night_mode_option_night_oled_dynamic">Compatível OLED (Cores Dinâmicas)</string>
|
||||
<string name="settings_announcements_segment_average_speed_pace">Velocidade/ritmo médio (Segmento)</string>
|
||||
<string name="settings_announcements_unit">Unidade de distância/velocidade</string>
|
||||
<string name="settings_sensor_bluetooth_service_filter_title">Filtrar Dispositivos Bluetooth</string>
|
||||
<string name="settings_sensor_bluetooth_service_filter_off">Mostrar todos os dispositivos Bluetooth detectáveis</string>
|
||||
<string name="settings_sensor_heart_rate_max">Zonas: Frequência cardíaca máxima (bpm)</string>
|
||||
<string name="settings_stats_units_imperial_meter">Imperial (mi, m)</string>
|
||||
<string name="settings_api_summary">API de controle remoto e estatísticas para outros apps</string>
|
||||
<string name="stats_average_segment_pace">Ritmo médio no segmento</string>
|
||||
<string name="stats_elapsed_segment_time">Tempo decorrido no segmento</string>
|
||||
<string name="stats_gain_loss">Ganhos e Perdas</string>
|
||||
<string name="stats_sensors_temperature">Temperatura</string>
|
||||
<string name="track_edit_time_offset">Deslocamento de fuso horário</string>
|
||||
<string name="value_internal_sensor">Sensor interno</string>
|
||||
<string name="value_int_seconds">%1$d s (recomendado)</string>
|
||||
<string name="voiceIdle">Ficando inativo.</string>
|
||||
<string name="voiceHoursPlural">{n, plural, =1 {1 hora} other {{n,number} horas} }</string>
|
||||
<string name="voiceMinutesPlural">{n, plural, =1 {1 minuto} other {{n,number} minutos} }</string>
|
||||
<string name="voiceSecondsPlural">{n, plural, =1 {1 segundo} other {{n,number} segundos} }</string>
|
||||
<string name="voiceSpeedKilometersPerHourPlural">{n, plural, =1 {1 quilômetro por hora} other {{n,number,#.0} quilômetros por hora} }</string>
|
||||
<string name="voiceSpeedMilesPerHourPlural">{n, plural, =1 {1 milha por hora} other {{n,number,#.0} milhas por hora} }</string>
|
||||
<string name="voiceSpeedMKnotsPlural">{n, plural, =1 {1 nó} other {{n,number,#.0} nós} }</string>
|
||||
<string name="voiceSpeed">{n, plural, =1 {1} other {{n,number,#.0}} }</string>
|
||||
<string name="voice_on_device_speaker_title">Use o alto-falante do dispositivo</string>
|
||||
<string name="voiceDistanceKilometersPlural">{n, plural, =1 {1 quilômetro} other {{n,number,#.0} quilômetros} }</string>
|
||||
<string name="voiceDistanceMilesPlural">{n, plural, =1 {1 milha} other {{n,number,#.0} milhas} }</string>
|
||||
<string name="voiceDistanceNauticalMilesPlural">{n, plural, =1 {1 milha náutica} other {{n,number,#.0} milhas náuticas} }</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } other {{n,number,#.0}} }</string>
|
||||
<string name="lap_heart_rate">Frequência cardíaca na volta</string>
|
||||
<string name="no_compatible_camera_installed">Nenhum aplicativo compatível de câmera instalado</string>
|
||||
<string name="no_compatible_gallery_installed">Nenhum aplicativo compatível de galeria de imagens instalado</string>
|
||||
<string name="settings_recording_min_sampling_interval_title">Intervalo de tempo de amostragem</string>
|
||||
<string name="settings_recording_location_distance_summary">%1$s entre localizações gravadas</string>
|
||||
<string name="settings_announcements_lap_power">Potência por volta</string>
|
||||
<string name="power_x_watt">Potência {x, plural, =1 {1 watt} other {# watts} }</string>
|
||||
<string name="power">Potência</string>
|
||||
</resources>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user