mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 01:23:06 +02:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c7738b1cb2 | |||
| 713f5c7708 | |||
| b9a36d1b3c | |||
| 34e89ea3f9 | |||
| 50a0e37086 | |||
| 11ac6b7279 | |||
| aadb79bf7d | |||
| da6b26644e | |||
| b264655d75 | |||
| 1ea9c0b216 | |||
| 8040edac7a | |||
| 037c79a1c5 | |||
| bc46f7447e | |||
| 6e88a448b1 | |||
| 2dac8d3ea6 | |||
| 0844c48d25 | |||
| 9607fda962 | |||
| 77ed28a8e2 | |||
| 4283e6d316 | |||
| ee030f32f5 | |||
| fb25055f3e | |||
| 9cdf87b998 | |||
| e9217b5327 | |||
| b4cb606499 | |||
| d1975685bc | |||
| 8cd9dda1f5 | |||
| c072967dd1 | |||
| 94e91d2063 | |||
| 796fa216f6 |
@@ -13,7 +13,7 @@ jobs:
|
||||
image: 'ubuntu:android-24.04'
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
image: 'ubuntu:android-24.04'
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
|
||||
@@ -123,4 +123,5 @@ Tested with:
|
||||
|
||||
Currently supported measurements:
|
||||
|
||||
* Human power
|
||||
* Human power
|
||||
* Cadence
|
||||
|
||||
+7
-7
@@ -33,7 +33,7 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
compileSdk = 36
|
||||
compileSdk = 37
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
@@ -47,13 +47,13 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'de.dennisguse.opentracks'
|
||||
versionCode 6653
|
||||
versionName "v4.27.0"
|
||||
versionCode 6682
|
||||
versionName "v4.27.2"
|
||||
|
||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||
|
||||
minSdk = 26
|
||||
targetSdk = 36
|
||||
targetSdk = 37
|
||||
|
||||
testInstrumentationRunner 'de.dennisguse.opentracks.TestRunner'
|
||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||
@@ -149,12 +149,12 @@ dependencies {
|
||||
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.13.0'
|
||||
implementation 'com.google.android.material:material:1.14.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
|
||||
implementation 'androidx.core:core:1.18.0'
|
||||
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-rc01'
|
||||
implementation 'androidx.core:core-location-altitude:1.0.0'
|
||||
implementation 'androidx.work:work-runtime:2.11.2'
|
||||
|
||||
androidTestImplementation 'androidx.test:core:1.7.0'
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
v4.27.1: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Support for Bosch Smart System eBikes (cadence, human power)
|
||||
- Add activity "gravel biking"
|
||||
|
||||
Bugfix:
|
||||
- While recording: TrackRecordingService would not restart correctly if killed by Android
|
||||
|
||||
Developer:
|
||||
- TargetSDK 37
|
||||
@@ -0,0 +1,5 @@
|
||||
v4.27.2: OpenTracks
|
||||
|
||||
Bugfix:
|
||||
- Not all valid timezone offsets could be set
|
||||
- Fixed race condition for IDLE trackpoints
|
||||
@@ -0,0 +1,17 @@
|
||||
v3.0.1: OpenTracks
|
||||
|
||||
Cambios:
|
||||
- Compartir marcadores
|
||||
- Configuración reestructurada
|
||||
- Se ha eliminado el botón «Atrás» de la barra de acciones
|
||||
- Exportación: se ha eliminado la opción de configuración del tamaño de las fotos
|
||||
- Exportación: ahora se puede seleccionar el formato KML
|
||||
|
||||
Correcciones de errores:
|
||||
- El directorio de exportación es ahora /OpenTracks/
|
||||
- El modo horizontal ya no provoca fallos
|
||||
- Se ha corregido la exportación a KML/KMZ
|
||||
|
||||
Desarrollador:
|
||||
- Las pruebas son ejecutables (pero muchas fallan)
|
||||
- Se ha habilitado la integración continua con TravisCI (sin pruebas)
|
||||
@@ -0,0 +1,14 @@
|
||||
v4.27.0: OpenTracks
|
||||
|
||||
Cambios:
|
||||
- Sensor: potencia de la bicicleta eléctrica Bosch
|
||||
- Sensores: se incluyen los dispositivos Bluetooth ya emparejados (como la bicicleta eléctrica Bosch)
|
||||
- Barómetro: se aplica la frecuencia de muestreo
|
||||
|
||||
Corrección de errores:
|
||||
- API del panel de control: no se proporcionaba la actualización
|
||||
- No se podía activar el GPS con el Bluetooth desactivado
|
||||
|
||||
Desarrollador:
|
||||
- Se ha eliminado Mockito
|
||||
- Pruebas de la interfaz de usuario: menos inestables
|
||||
@@ -0,0 +1,5 @@
|
||||
v4.26.2: OpenTracks
|
||||
|
||||
Correzioni:
|
||||
- Il GPS via Bluetooth non è (ancora) supportato
|
||||
- Il tipo di altitudine (EGM2008) non viene mostrato
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>OpenTracks: Privacy Policy</h1>
|
||||
|
||||
<p>
|
||||
OpenTracks does only store data on the local device that is relevant for tracking your sport exercise.
|
||||
Stored data is not transmitted from the app itself to a third party.
|
||||
|
||||
Data is stored by OpenTracks until:
|
||||
1. the user deletes the recorded track or
|
||||
2. the user uninstalls OpenTracks
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
+19
@@ -96,6 +96,25 @@ public class SensorDataCyclingTest {
|
||||
assertNull(current.getAggregatedValue(Instant.MIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compute_cadence_directCadence_withoutPrevious() {
|
||||
AggregatorCyclingCadence current = new AggregatorCyclingCadence("", "");
|
||||
|
||||
current.add(Instant.MIN, new CyclingCadenceBluetooth.DirectCadenceData(Cadence.of(92)));
|
||||
|
||||
assertEquals(92, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compute_cadence_directCadence_winsOverCrankData() {
|
||||
AggregatorCyclingCadence current = new AggregatorCyclingCadence("", "");
|
||||
|
||||
current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(1L, 1024));
|
||||
current.add(Instant.MIN, new CyclingCadenceBluetooth.DirectCadenceData(Cadence.of(92)));
|
||||
|
||||
assertEquals(92, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compute_speed() {
|
||||
AggregatorCyclingDistanceSpeed current = new AggregatorCyclingDistanceSpeed("", "");
|
||||
|
||||
+36
@@ -2,6 +2,7 @@ package de.dennisguse.opentracks.services;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -93,6 +94,41 @@ public class TrackRecordingServiceRecordingTest {
|
||||
service = startService();
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@Test
|
||||
public void reCreate_not_recording() {
|
||||
// given
|
||||
TrackIdStorage.unset(context);
|
||||
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
// when
|
||||
service.onStartCommand(null, 0, 1);
|
||||
|
||||
// then
|
||||
assertFalse(service.isRecording());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@Test
|
||||
public void reCreate_recording() {
|
||||
// given
|
||||
assertFalse(service.isRecording());
|
||||
Track.Id trackId = service.startNewTrack();
|
||||
assertTrue(service.isRecording());
|
||||
|
||||
// when (crash and restart)
|
||||
service.onDestroy();
|
||||
service.onCreate();
|
||||
service.onStartCommand(null, 0, 1);
|
||||
|
||||
// then
|
||||
assertTrue(service.isRecording());
|
||||
assertEquals(trackId, service.getRecordingStatusObservable().getValue().trackId());
|
||||
|
||||
service.endCurrentTrack();
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@Test
|
||||
public void recording_startStop() {
|
||||
|
||||
+43
@@ -52,6 +52,7 @@ public class VoiceAnnouncementUtilsTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
PreferencesUtils.setVoiceAnnounceUnit(true);
|
||||
PreferencesUtils.setVoiceAnnounceHeartRateCurrent(false);
|
||||
PreferencesUtils.setVoiceAnnounceLapHeartRate(false);
|
||||
PreferencesUtils.setVoiceAnnounceAverageHeartRate(false);
|
||||
@@ -221,6 +222,48 @@ public class VoiceAnnouncementUtilsTest {
|
||||
assertEquals("12:00 AM. Total distance 19.9 kilometers. 1 hour. Average moving speed 19.9 kilometers per hour.", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnouncement_metric_distance_without_unit() {
|
||||
PreferencesUtils.setVoiceAnnounceUnit(false);
|
||||
|
||||
Track track = new Track(
|
||||
null,
|
||||
null,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
ActivityType.AIRPLANE,
|
||||
ZoneOffset.UTC,
|
||||
new Statistics(
|
||||
Instant.EPOCH,
|
||||
Instant.EPOCH,
|
||||
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
|
||||
Duration.ofHours(1),
|
||||
Distance.of(19900),
|
||||
Speed.of(100),
|
||||
null,
|
||||
new AltitudeGainLoss(6000, 6000),
|
||||
null,
|
||||
null
|
||||
));
|
||||
|
||||
SensorDataSet dataSet = new SensorDataSet(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new SensorData<>(HeartRate.of(60), "unused"),
|
||||
null, null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 19.9. 1 hour. Average moving speed 19.9.", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnouncement_withInterval_metric_speed() {
|
||||
// given
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.StrictMode;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -27,6 +28,11 @@ public class Startup extends Application {
|
||||
|
||||
// Include version information into stack traces.
|
||||
Log.i(TAG, BuildConfig.APPLICATION_ID + "; BuildType: " + BuildConfig.BUILD_TYPE + "; VersionName: " + BuildConfig.VERSION_NAME + "/" + BuildConfig.VERSION_NAME_FULL + " VersionCode: " + BuildConfig.VERSION_CODE);
|
||||
// In debug builds: show thread and VM warnings.
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, "Enabling strict mode");
|
||||
StrictMode.enableDefaults();
|
||||
}
|
||||
|
||||
PreferencesUtils.initPreferences(this);
|
||||
// Set default values of preferences on first start.
|
||||
|
||||
@@ -30,6 +30,7 @@ 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),
|
||||
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),
|
||||
|
||||
@@ -9,7 +9,7 @@ import de.dennisguse.opentracks.sensors.driver.CyclingCadenceBluetooth;
|
||||
import de.dennisguse.opentracks.sensors.driver.Driver;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
|
||||
|
||||
public class CyclingCadenceHandler extends SensorHandler<CyclingCadenceBluetooth.CrankData, Cadence> {
|
||||
public class CyclingCadenceHandler extends SensorHandler<CyclingCadenceBluetooth.CyclingCadenceMeasurement, Cadence> {
|
||||
|
||||
protected CyclingCadenceHandler(SensorManager sensorManager) {
|
||||
super(sensorManager);
|
||||
|
||||
@@ -6,23 +6,25 @@ import android.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID;
|
||||
|
||||
public class CyclingCadenceBluetooth implements BluetoothDriver.BluetoothParser<CyclingCadenceBluetooth.CrankData> {
|
||||
public class CyclingCadenceBluetooth implements BluetoothDriver.BluetoothParser<CyclingCadenceBluetooth.CyclingCadenceMeasurement> {
|
||||
private static final String TAG = CyclingCadenceBluetooth.class.getSimpleName();
|
||||
|
||||
public static final List<ServiceMeasurementUUID> CYCLING_CADENCE = List.of(
|
||||
public static final List<ServiceMeasurementUUID> SUPPORTED_SERVICES = List.of(
|
||||
CyclingPowerBluetooth.CYCLING_POWER,
|
||||
CyclingDistanceSpeedBluetooth.CYCLING_SPEED_CADENCE
|
||||
CyclingDistanceSpeedBluetooth.CYCLING_SPEED_CADENCE,
|
||||
BoschEbikeParser.BOSCH_EBIKE
|
||||
);
|
||||
|
||||
@Override
|
||||
public List<ServiceMeasurementUUID> getServices() {
|
||||
return CYCLING_CADENCE;
|
||||
return SUPPORTED_SERVICES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CrankData parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic) {
|
||||
public CyclingCadenceMeasurement parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic) {
|
||||
if (serviceMeasurementUUID.equals(CyclingPowerBluetooth.CYCLING_POWER)) {
|
||||
CyclingPowerBluetooth.Data data = CyclingPowerBluetooth.parseCyclingPower(characteristic);
|
||||
if (data != null && data.crank() != null) {
|
||||
@@ -38,12 +40,28 @@ public class CyclingCadenceBluetooth implements BluetoothDriver.BluetoothParser<
|
||||
}
|
||||
}
|
||||
|
||||
if (serviceMeasurementUUID.equals(BoschEbikeParser.BOSCH_EBIKE)) {
|
||||
BoschEbikeParser.Data boschData = BoschEbikeParser.parse(characteristic.getValue());
|
||||
if (boschData != null && boschData.cadence() != null) {
|
||||
return new DirectCadenceData(boschData.cadence());
|
||||
}
|
||||
}
|
||||
|
||||
Log.e(TAG, "Don't know how to decode this payload.");
|
||||
return null;
|
||||
}
|
||||
|
||||
public sealed interface CyclingCadenceMeasurement permits CrankData, DirectCadenceData {
|
||||
}
|
||||
|
||||
public record CrankData(
|
||||
long crankRevolutionsCount, // UINT32
|
||||
int crankRevolutionsTime // UINT16; 1/1024s
|
||||
) {}
|
||||
) implements CyclingCadenceMeasurement {
|
||||
}
|
||||
|
||||
public record DirectCadenceData(
|
||||
Cadence cadence
|
||||
) implements CyclingCadenceMeasurement {
|
||||
}
|
||||
}
|
||||
|
||||
+22
-6
@@ -10,7 +10,7 @@ import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.sensors.UintUtils;
|
||||
import de.dennisguse.opentracks.sensors.driver.CyclingCadenceBluetooth;
|
||||
|
||||
public class AggregatorCyclingCadence extends Aggregator<CyclingCadenceBluetooth.CrankData, Cadence> {
|
||||
public class AggregatorCyclingCadence extends Aggregator<CyclingCadenceBluetooth.CyclingCadenceMeasurement, Cadence> {
|
||||
|
||||
private final String TAG = AggregatorCyclingCadence.class.getSimpleName();
|
||||
|
||||
@@ -19,12 +19,20 @@ public class AggregatorCyclingCadence extends Aggregator<CyclingCadenceBluetooth
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeValue(@NonNull Raw<CyclingCadenceBluetooth.CrankData> current) {
|
||||
if (previous == null) {
|
||||
protected void computeValue(@NonNull Raw<CyclingCadenceBluetooth.CyclingCadenceMeasurement> current) {
|
||||
if (current.value() instanceof CyclingCadenceBluetooth.DirectCadenceData directCadenceData) {
|
||||
output = directCadenceData.cadence();
|
||||
return;
|
||||
}
|
||||
|
||||
float timeDiff_ms = UintUtils.diff(current.value().crankRevolutionsTime(), previous.value().crankRevolutionsTime(), UintUtils.UINT16_MAX) / 1024f * 1000;
|
||||
computeRawCadence((CyclingCadenceBluetooth.CrankData) current.value());
|
||||
}
|
||||
|
||||
private void computeRawCadence(@NonNull CyclingCadenceBluetooth.CrankData currentRaw) {
|
||||
CyclingCadenceBluetooth.CrankData previousRaw = getPreviousRaw();
|
||||
if (previousRaw == null) return;
|
||||
|
||||
float timeDiff_ms = UintUtils.diff(currentRaw.crankRevolutionsTime(), previousRaw.crankRevolutionsTime(), UintUtils.UINT16_MAX) / 1024f * 1000;
|
||||
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);
|
||||
|
||||
if (timeDiff.isZero()) {
|
||||
@@ -37,13 +45,21 @@ public class AggregatorCyclingCadence extends Aggregator<CyclingCadenceBluetooth
|
||||
}
|
||||
|
||||
// TODO We have to treat with overflow according to the documentation: read https://codeberg.org/OpenTracksApp/OpenTracks/pulls/953#issuecomment-6466930
|
||||
if (current.value().crankRevolutionsCount() < previous.value().crankRevolutionsCount()) {
|
||||
if (currentRaw.crankRevolutionsCount() < previousRaw.crankRevolutionsCount()) {
|
||||
Log.e(TAG, "Crank revolutions count difference is invalid: cannot compute cadence.");
|
||||
output = null;
|
||||
return;
|
||||
}
|
||||
|
||||
long crankDiff = UintUtils.diff(current.value().crankRevolutionsCount(), previous.value().crankRevolutionsCount(), UintUtils.UINT32_MAX);
|
||||
long crankDiff = UintUtils.diff(currentRaw.crankRevolutionsCount(), previousRaw.crankRevolutionsCount(), UintUtils.UINT32_MAX);
|
||||
output = Cadence.of(crankDiff, timeDiff);
|
||||
}
|
||||
|
||||
private CyclingCadenceBluetooth.CrankData getPreviousRaw() {
|
||||
if (previous == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return previous.value() instanceof CyclingCadenceBluetooth.CrankData raw ? raw : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package de.dennisguse.opentracks.services;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
|
||||
/**
|
||||
* For handling restarts of TrackRecordingService: while recording, stores the {@link de.dennisguse.opentracks.data.models.Track.Id}.
|
||||
*/
|
||||
class TrackIdStorage {
|
||||
|
||||
private final static String SHARED_PREFERENCE_NAME = "TrackRecordingService_pref";
|
||||
|
||||
private final static String KEY = "trackId_key";
|
||||
|
||||
private static SharedPreferences sharedPreferences;
|
||||
|
||||
private static void init(Context context) {
|
||||
if (sharedPreferences == null) {
|
||||
sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Track.Id get(Context context) {
|
||||
TrackIdStorage.init(context);
|
||||
|
||||
long value = sharedPreferences.getLong(KEY, -1);
|
||||
if (value < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Track.Id(value);
|
||||
}
|
||||
|
||||
public static void set(Context context, @NonNull Track.Id trackId) {
|
||||
TrackIdStorage.init(context);
|
||||
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putLong(KEY, trackId.id());
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public static void unset(Context context) {
|
||||
TrackIdStorage.init(context);
|
||||
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.remove(KEY);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
|
||||
contentProviderUtils = new ContentProviderUtils(context);
|
||||
}
|
||||
|
||||
Track.Id startNewTrack() {
|
||||
synchronized Track.Id startNewTrack() {
|
||||
TrackPoint segmentStartTrackPoint = trackPointCreator.createSegmentStartManual();
|
||||
|
||||
ZoneOffset zoneOffset = ZoneOffset.systemDefault().getRules().getOffset(segmentStartTrackPoint.getTime());
|
||||
@@ -103,7 +103,7 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
|
||||
/**
|
||||
* @return if the recording could be started.
|
||||
*/
|
||||
boolean resumeExistingTrack(@NonNull Track.Id resumeTrackId) {
|
||||
synchronized boolean resumeExistingTrack(@NonNull Track.Id resumeTrackId) {
|
||||
trackId = resumeTrackId;
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
if (track == null) {
|
||||
@@ -119,7 +119,7 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
|
||||
return true;
|
||||
}
|
||||
|
||||
void endCurrentTrack() {
|
||||
synchronized void endCurrentTrack() {
|
||||
TrackPoint segmentEnd = trackPointCreator.createSegmentEnd();
|
||||
insertTrackPoint(segmentEnd, true);
|
||||
|
||||
@@ -149,7 +149,7 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||
public void onIdle() {
|
||||
public synchronized void onIdle() {
|
||||
Log.d(TAG, "Becoming idle");
|
||||
onNewTrackPoint(trackPointCreator.createIdle());
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
||||
private MutableLiveData<GpsStatusValue> gpsStatusObservable;
|
||||
private MutableLiveData<RecordingData> recordingDataObservable;
|
||||
|
||||
// The following variables are set when recording:
|
||||
private Handler handler;
|
||||
|
||||
private TrackPointCreator trackPointCreator;
|
||||
@@ -119,9 +118,6 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log.d(TAG, "Destroying");
|
||||
if (isRecording()) {
|
||||
endCurrentTrack();
|
||||
}
|
||||
if (trackPointCreator != null && trackPointCreator.isStarted()) {
|
||||
stopSensors();
|
||||
}
|
||||
@@ -150,6 +146,16 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (intent == null) {
|
||||
Log.i(TAG, "Service got killed and is restarting");
|
||||
|
||||
//Best guess: do we need to resume a recording?
|
||||
Track.Id trackId = TrackIdStorage.get(this);
|
||||
if (trackId != null) {
|
||||
Log.i(TAG, "After restart: resuming recording for " + trackId);
|
||||
resumeTrack(trackId);
|
||||
}
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@@ -167,9 +173,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
||||
|
||||
// Set recording status
|
||||
Track.Id trackId = trackRecordingManager.startNewTrack();
|
||||
updateRecordingStatus(RecordingStatus.record(trackId));
|
||||
|
||||
startRecording();
|
||||
startRecording(trackId);
|
||||
return trackId;
|
||||
}
|
||||
|
||||
@@ -180,12 +184,13 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
||||
}
|
||||
Log.i(TAG, "resumeTrack");
|
||||
|
||||
updateRecordingStatus(RecordingStatus.record(trackId));
|
||||
|
||||
startRecording();
|
||||
startRecording(trackId);
|
||||
}
|
||||
|
||||
private void startRecording() {
|
||||
private void startRecording(Track.Id trackId) {
|
||||
updateRecordingStatus(RecordingStatus.record(trackId));
|
||||
TrackIdStorage.set(this, trackId);
|
||||
|
||||
startSensors();
|
||||
|
||||
voiceAnnouncementManager.start(trackRecordingManager.getTrackStatistics());
|
||||
@@ -226,6 +231,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
||||
updateRecordingStatus(STATUS_DEFAULT);
|
||||
|
||||
trackRecordingManager.endCurrentTrack();
|
||||
TrackIdStorage.unset(this);
|
||||
|
||||
stopUpdateRecordingData();
|
||||
|
||||
|
||||
@@ -328,6 +328,11 @@ public class PreferencesUtils {
|
||||
return getBoolean(R.string.voice_announce_unit_key, true);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void setVoiceAnnounceUnit(boolean value) {
|
||||
setBoolean(R.string.voice_announce_unit_key, value);
|
||||
}
|
||||
|
||||
public static Duration getVoiceAnnouncementFrequency() {
|
||||
final int DEFAULT = Integer.parseInt(resources.getString(R.string.voice_announcement_frequency_default));
|
||||
int value = getInt(R.string.voice_announcement_frequency_key, DEFAULT);
|
||||
@@ -748,11 +753,13 @@ public class PreferencesUtils {
|
||||
sharedPreferences.edit().clear().commit();
|
||||
}
|
||||
|
||||
// Each setting file must be mentioned here.
|
||||
// Each setting file must be mentioned here: see xml/settings.xml
|
||||
PreferenceManager.setDefaultValues(context, R.xml.settings, readAgain);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.settings_defaults, readAgain);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.settings_user_interface, readAgain);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.settings_recording, readAgain);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.settings_sensors, readAgain);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.settings_announcements, readAgain);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.settings_import_export, readAgain);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.settings_public_api, readAgain);
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class BluetoothLeCyclingCadencePreference extends BluetoothLeSensorPrefer
|
||||
|
||||
@Override
|
||||
public PreferenceDialogFragmentCompat createInstance() {
|
||||
return BluetoothLeSensorPreferenceDialog.newInstance(getKey(), CyclingCadenceBluetooth.CYCLING_CADENCE);
|
||||
return BluetoothLeSensorPreferenceDialog.newInstance(getKey(), CyclingCadenceBluetooth.SUPPORTED_SERVICES);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,51 @@ import android.widget.ArrayAdapter;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* <a href="Data source for UTC Offsets">https://en.wikipedia.org/wiki/List_of_UTC_offsets</a>
|
||||
*/
|
||||
public class ZoneOffsetAdapter extends ArrayAdapter<ZoneOffset> {
|
||||
public ZoneOffsetAdapter(@NonNull Context context, int resource) {
|
||||
super(context, resource, IntStream.range(-12, +12)
|
||||
.boxed()
|
||||
.map(ZoneOffset::ofHours)
|
||||
.toList());
|
||||
super(context, resource);
|
||||
|
||||
addAll(
|
||||
ZoneOffset.ofHoursMinutes(-12, 00),
|
||||
ZoneOffset.ofHoursMinutes(-11, 00),
|
||||
ZoneOffset.ofHoursMinutes(-10, 00),
|
||||
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(-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, 30),
|
||||
ZoneOffset.ofHoursMinutes(4, 00),
|
||||
ZoneOffset.ofHoursMinutes(4, 30),
|
||||
ZoneOffset.ofHoursMinutes(5, 30),
|
||||
ZoneOffset.ofHoursMinutes(5, 45),
|
||||
ZoneOffset.ofHoursMinutes(6, 00),
|
||||
ZoneOffset.ofHoursMinutes(6, 30),
|
||||
ZoneOffset.ofHoursMinutes(7, 00),
|
||||
ZoneOffset.ofHoursMinutes(8, 00),
|
||||
ZoneOffset.ofHoursMinutes(8, 45),
|
||||
ZoneOffset.ofHoursMinutes(9, 00),
|
||||
ZoneOffset.ofHoursMinutes(9, 30),
|
||||
ZoneOffset.ofHoursMinutes(10, 00),
|
||||
ZoneOffset.ofHoursMinutes(10, 30),
|
||||
ZoneOffset.ofHoursMinutes(11, 00),
|
||||
ZoneOffset.ofHoursMinutes(12, 00),
|
||||
ZoneOffset.ofHoursMinutes(12, 45),
|
||||
ZoneOffset.ofHoursMinutes(13, 00),
|
||||
ZoneOffset.ofHoursMinutes(14, 00)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
package de.dennisguse.opentracks.ui.customRecordingLayout;
|
||||
|
||||
public enum CustomLayoutFieldType {
|
||||
GENERIC(1),
|
||||
CLOCK(2);
|
||||
|
||||
private final int value;
|
||||
|
||||
CustomLayoutFieldType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ limitations under the License.
|
||||
<string name="description_max_altitude">Μέγιστη ανύψωση: %1$d μέτρα (%2$d πόδια)</string>
|
||||
<string name="description_max_speed">Μέγιστη ταχύτητα: %1$.2f χλμ/ώρα (%2$.1f μίλια/ώρα)</string>
|
||||
<string name="description_min_altitude">Ελάχιστη ανύψωση: %1$d μέτρα (%2$d πόδια)</string>
|
||||
<string name="description_moving_time">Χρόνος μεταφοράς: %1$s</string>
|
||||
<string name="description_moving_time">Χρόνος κίνησης: %1$s</string>
|
||||
<string name="description_pace_imperial">Ρυθμός (λεπτά/μίλι)</string>
|
||||
<string name="description_pace_metric">Ρυθμός (λεπτά/χλμ)</string>
|
||||
<string name="description_recorded_time">Εγγραφή: %1$s</string>
|
||||
@@ -230,22 +230,22 @@ limitations under the License.
|
||||
<!-- Tracks -->
|
||||
<!-- Unit -->
|
||||
<string name="unit_feet">πόδια</string>
|
||||
<string name="unit_kilometer">χλμ.</string>
|
||||
<string name="unit_kilometer">χλμ</string>
|
||||
<string name="unit_kilometer_per_hour">χλμ/ώρα</string>
|
||||
<string name="unit_meter">μέτρα</string>
|
||||
<string name="unit_mile">μίλι</string>
|
||||
<string name="unit_mile_per_hour">μίλια/ώρα</string>
|
||||
<string name="unit_minute_per_kilometer">λεπτά / χιλ.</string>
|
||||
<string name="unit_minute_per_kilometer">λεπτά/χλμ</string>
|
||||
<string name="unit_minute_per_mile">λεπτά/μίλι</string>
|
||||
<!-- Value -->
|
||||
<string name="value_integer_feet_excellent_gps">%1$d πόδια (τέλειο σήμα GPS)</string>
|
||||
<string name="value_integer_feet_recommended">%1$d ft (συνιστάται)</string>
|
||||
<string name="value_integer_feet_recommended">%1$d πόδια (συνιστάται)</string>
|
||||
<string name="value_integer_kilometer_hour">%1$d χλμ/ώρα</string>
|
||||
<string name="value_integer_meter_excellent_gps">%1$d μέτρα (τέλειο σήμα GPS)</string>
|
||||
<string name="value_integer_meter_poor_gps">%1$d μέτρα (χαμηλό σήμα GPS)</string>
|
||||
<string name="value_integer_meter_recommended">%1$d m (συνιστάται)</string>
|
||||
<string name="value_integer_mile_hour">%1$d μίλια/ώρα</string>
|
||||
<string name="value_integer_minute">%1$d λεπ.</string>
|
||||
<string name="value_integer_minute">%1$d λεπ</string>
|
||||
<string name="value_integer_second">%1$d δευτ</string>
|
||||
<string name="value_none">Καμία</string>
|
||||
<string name="value_off">Απενεργοποιημένο</string>
|
||||
@@ -325,4 +325,120 @@ limitations under the License.
|
||||
<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>
|
||||
<string name="value_float_kilometer_hour">%1$.1f χλμ/ώρα</string>
|
||||
<string name="value_float_kilometer_hour_recommended">%1$.1f χλμ/ώρα (συνιστάται)</string>
|
||||
<string name="value_integer_knots">%1$d κόμβοι</string>
|
||||
<string name="value_float_mile_hour">%1$.1f μίλια/ώρα</string>
|
||||
<string name="value_float_knots">%1$.1f κόμβοι</string>
|
||||
<string name="value_float_mile_hour_recommended">%1$.1f μίλια/ώρα (συνιστάται)</string>
|
||||
<string name="value_float_knots_recommended">%1$.1f κόμβοι (συνιστάται)</string>
|
||||
<string name="value_internal_sensor">Εσωτερικός αισθητήρας</string>
|
||||
<string name="value_int_seconds">%1$d δευτ (συνιστάται)</string>
|
||||
<string name="voice_per_kilometer">ανά χιλιόμετρο</string>
|
||||
<string name="voice_per_mile">ανά μίλι</string>
|
||||
<string name="voice_per_nautical_mile">ανά ναυτικό μίλι</string>
|
||||
<string name="lap_time">Χρόνος γύρου</string>
|
||||
<string name="pace">Ρυθμός</string>
|
||||
<string name="lap_speed">Ταχύτητα γύρου</string>
|
||||
<string name="speed">Μέση ταχύτητα κίνησης</string>
|
||||
<string name="total_distance">Συνολική απόσταση</string>
|
||||
<string name="voiceDistanceKilometersPlural">{n, plural, =1 {1 χιλιόμετρο} other {{n,number,#.0} χιλιόμετρα} }</string>
|
||||
<string name="voiceDistanceMilesPlural">{n, plural, =1 {1 μίλι} other {{n,number,#.0} μίλια} }</string>
|
||||
<string name="voiceDistanceNauticalMilesPlural">{n, plural, =1 {1 ναυτικό μίλι} other {{n,number,#.0} ναυτικά μίλια} }</string>
|
||||
<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>
|
||||
<string name="settings_api_summary">API απομακρυσμένου ελέγχου και στατιστικών για άλλες εφαρμογές</string>
|
||||
<string name="voiceMinutesPlural">{n, plural, =1 {1 λεπτό} other {{n,number} λεπτά} }</string>
|
||||
<string name="voiceSecondsPlural">{n, plural, =1 {1 δευτερόλεπτο} other {{n,number} δευτερόλεπτα} }</string>
|
||||
<string name="voiceSpeedKilometersPerHourPlural">{n, plural, =1 {1 χιλιόμετρο ανά ώρα} other {{n,number,#.0} χιλιόμετρα ανά ώρα} }</string>
|
||||
<string name="voiceSpeedMilesPerHourPlural">{n, plural, =1 {1 μίλι ανά ώρα} other {{n,number,#.0} μίλια ανά ώρα} }</string>
|
||||
<string name="voiceSpeedMKnotsPlural">{n, plural, =1 {1 κόμβος} other {{n,number,#.0} κόμβοι} }</string>
|
||||
<string name="voiceSpeed">{n, plural, =1 {1} other {{n,number,#.0}} }</string>
|
||||
<string name="description_speed_nautical">Ταχύτητα (κόμβοι)</string>
|
||||
<string name="description_sensor_temperature">Θερμοκρασία (Κελσίου)</string>
|
||||
<string name="export_with_photos">με φωτογραφίες</string>
|
||||
<string name="export_without_photos">χωρίς φωτογραφίες</string>
|
||||
<string name="export_progress_summary_errors_msg">Σφάλματα</string>
|
||||
<string name="import_progress_summary_errors_msg">Σφάλματα</string>
|
||||
<string name="import_progress_summary_exists_msg">Υπάρχει ήδη</string>
|
||||
<string name="import_error_info">%1$s: %2$s</string>
|
||||
<string name="gps_recording_status">%1$s: %2$s</string>
|
||||
<string name="generic_undo">Αναίρεση</string>
|
||||
<string name="generic_filter">Φίλτρο</string>
|
||||
<string name="menu_filter">Φίλτρο</string>
|
||||
<string name="menu_voice_rate">Ταχύτητα φωνής</string>
|
||||
<string name="sensor_state_cadence_avg">Μέσο πεταλάρισμα</string>
|
||||
<string name="sensor_state_cadence_max">Μέγιστο πεταλάρισμα</string>
|
||||
<string name="sensor_state_temperature">Θερμόμετρο</string>
|
||||
<string name="sensor_state_pressure">Βαρόμετρο</string>
|
||||
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
|
||||
<string name="bluetooth_disabled">Παρακαλούμε ενεργοποιήστε το Bluetooth.</string>
|
||||
<string name="settings_ui_title">Διεπαφή Χρήστη</string>
|
||||
<string name="settings_ui_summary">Εμφάνιση, Διάταξη Εγγραφής, Θέμα</string>
|
||||
<string name="settings_gps_sensor">GPS</string>
|
||||
<string name="description_speed_source_gps">GPS</string>
|
||||
<string name="settings_sensors_title">Αισθητήρες</string>
|
||||
<string name="settings_sensors_summary">Αισθητήρες Ποδηλασίας, Περιφέρεια Ρόδας, Αισθητήρες Τρεξίματος</string>
|
||||
<string name="settings_defaults_title">Προεπιλεγμένες Μονάδες και Δραστηριότητα</string>
|
||||
<string name="settings_announcements_summary">Χρόνος, Απόσταση, Ταχύτητα Φωνής</string>
|
||||
<string name="settings_import_export_title">Εισαγωγή και Εξαγωγή</string>
|
||||
<string name="settings_import_export_summary">Εισαγωγή, Εξαγωγή, Αυτόματη Εξαγωγή</string>
|
||||
<string name="settings_units_category">Μονάδες</string>
|
||||
<string name="settings_activity_defaults_category">Προεπιλογές Δραστηριότητας</string>
|
||||
<string name="settings_reset_summary">Επαναφορά Ρυθμίσεων στις Προεπιλεγμένες Τιμές</string>
|
||||
<string name="generic_from">Από</string>
|
||||
<string name="generic_to">Μέχρι</string>
|
||||
<string name="generic_today">Σήμερα</string>
|
||||
<string name="generic_yesterday">Χθες</string>
|
||||
<string name="generic_dismiss">Παράβλεψη</string>
|
||||
<string name="generic_completed">Ολοκληρώθηκε</string>
|
||||
<string name="generic_click_twice_cancel">Πατήστε ξανά πίσω για ακύρωση</string>
|
||||
<string name="generic_choose_an_option">Επιλέξτε μια επιλογή</string>
|
||||
<string name="generic_skip">Παράλειψη</string>
|
||||
<string name="generic_separator_done_total">/</string>
|
||||
<string name="generic_show_errors">Εμφάνιση σφαλμάτων</string>
|
||||
<plurals name="generic_completed_with_errors">
|
||||
<item quantity="one">Ολοκληρώθηκε με ένα σφάλμα</item>
|
||||
<item quantity="other">Ολοκληρώθηκε με %1$d σφάλματα</item>
|
||||
</plurals>
|
||||
<string name="generic_overwrite">Αντικατάσταση</string>
|
||||
<string name="gps_disabled_msg">GPS απενεργοποιημένο</string>
|
||||
<string name="gps_fixed_and_ready">GPS σταθερό και έτοιμο</string>
|
||||
<string name="image_discard">Απόρριψη</string>
|
||||
<string name="menu_select_layout">Επιλογή διάταξης</string>
|
||||
<string name="custom_layout_select_layout">Επιλογή διάταξης</string>
|
||||
<string name="settings_announcements_distance_frequency">Μήκος γύρου</string>
|
||||
<string name="settings_locale_title">Γλώσσα</string>
|
||||
<string name="settings_locale_system_default">Προεπιλογή συστήματος</string>
|
||||
<string name="settings_night_mode_option_system">Σύστημα</string>
|
||||
<string name="settings_night_mode_option_day">Μέρα</string>
|
||||
<string name="settings_night_mode_option_night">Νύχτα</string>
|
||||
<string name="custom_layout_list_title">Διατάξεις</string>
|
||||
<string name="stats_custom_layout_default_layout">Προεπιλεγμένη διάταξη</string>
|
||||
<string name="settings_all_reset">Επαναφορά</string>
|
||||
<string name="settings_recording_fullscreen_on_while_recording_title">Πλήρης οθόνη</string>
|
||||
<string name="settings_recording_show_gps_disabled_warning_title">Προειδοποίηση απενεργοποιημένου GPS</string>
|
||||
<string name="settings_recording_keep_screen_on_while_recording_title">Διατήρηση της οθόνης ενεργοποιημένης</string>
|
||||
<string name="settings_recording_show_on_lockscreen_while_recording_title">Εμφάνιση στατιστικών στο κλείδωμα οθόνης</string>
|
||||
<string name="settings_ui_dynamic_colors_title">Δυναμικά Χρώματα</string>
|
||||
<string name="settings_recording_customize_layout_title">Προσαρμόστε τη διάταξη εγγραφής</string>
|
||||
<string name="settings_sensor_cycling_cadence">Πεταλάρισμα</string>
|
||||
<string name="stats_sensors_cadence">Πεταλάρισμα</string>
|
||||
<string name="stats_sensors_temperature">Θερμοκρασία</string>
|
||||
<string name="stats_clock">Ρολόι</string>
|
||||
<string name="track_recording_notification_accuracy">Ακρίβεια τοποθεσίας: %1$s</string>
|
||||
<string name="track_distance_notification">Απόσταση: %1$s</string>
|
||||
<string name="track_speed_notification">Ταχύτητα: %1$s</string>
|
||||
<string name="track_pace_notification">Ρυθμός: %1$s</string>
|
||||
<string name="stats_coordinates">Γεωγραφικό πλάτος/Γεωγραφικό μήκος</string>
|
||||
<string name="settings_sensor_running_speed_and_cadence">Απόσταση, Ταχύτητα και Πεταλάρισμα</string>
|
||||
<string name="settings_sensor_cycling_distance_speed">Απόσταση και Ταχύτητα</string>
|
||||
<string name="settings_sensor_bluetooth_service_filter_title">Φιλτράτισμα Συσκευών Bluetooth</string>
|
||||
<string name="settings_sensor_wheel_circumference">Περιφέρεια Ρόδας (mm)</string>
|
||||
<string name="settings_public_api_dashboard_enabled_title">Αυτόματη μεταφορά δεδομένων</string>
|
||||
</resources>
|
||||
|
||||
@@ -599,4 +599,5 @@ limitations under the License.
|
||||
<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>
|
||||
</resources>
|
||||
|
||||
@@ -607,4 +607,5 @@ limitations under the License.
|
||||
<string name="stats_sensors_temperature">Temperatura</string>
|
||||
<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>
|
||||
</resources>
|
||||
|
||||
@@ -150,7 +150,7 @@ limitations under the License.
|
||||
<string name="menu_aggregated_statistics">集計統計</string>
|
||||
<string name="menu_delete">削除</string>
|
||||
<string name="menu_edit">編集</string>
|
||||
<string name="menu_export_all">すべてエクスポート</string>
|
||||
<string name="menu_export_all">すべてエクスポート(トラックごとに別ファイル)</string>
|
||||
<string name="menu_help">ヘルプ</string>
|
||||
<string name="menu_import_all">すべてインポート</string>
|
||||
<string name="menu_insert_marker">マーカーを追加</string>
|
||||
@@ -313,4 +313,24 @@ limitations under the License.
|
||||
<string name="import_progress_summary_ok_msg">インポート完了</string>
|
||||
<string name="import_progress_summary_exists_msg">既に存在しています</string>
|
||||
<string name="help_track_map_content">小さな地図のアイコンを使います.\n a) (live updates) <a href="https://codeberg.org/OpenTracksApp/OSMDashboard">OSMDashboard</a>をインストールして下さい。 <a href="https://www.openstreetmap.org">OpenStreetMap</a> を利用したオンラインまたはオフラインの地図を使用できるようになります。\n実際、OSMDashbordは (一時的に保存された) 表示するトラッキングデータにだけアクセスする独立したアプリケーションです。\n b) 一般的な地図アプリケーションを使用 (e.g., <a href="http://osmand.net/">OsmAnd</a> and <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_storage_pictures_title">マーカーとして撮影した写真の保存場所</string>
|
||||
<string name="help_storage_pictures_content">アプリケーションの内部ストレージ(つまり、OpenTracks内部からのみアクセス可能な場所)に保存されます。</string>
|
||||
<string name="help_track_export_title">記録したトラックのエクスポート/共有方法</string>
|
||||
<string name="stats_sensors_temperature">温度</string>
|
||||
<string name="settings_announcements_average_heart_rate">平均心拍数</string>
|
||||
<string name="description_speed_source_gps">GPS</string>
|
||||
<string name="export_dir_not_writable">" (書き込み失敗!)"</string>
|
||||
<string name="export_progress_summary_overwrite_msg">上書きされたファイル</string>
|
||||
<string name="export_progress_summary_skip_msg">スキップされたファイル</string>
|
||||
<string name="export_progress_summary_errors_msg">エラー</string>
|
||||
<string name="generic_separator_done_total">/</string>
|
||||
<string name="generic_today">今日</string>
|
||||
<string name="generic_yesterday">昨日</string>
|
||||
<string name="gps_disabled_msg">GPSが無効化されています</string>
|
||||
<string name="import_no_kml_file_found">KMZ中にkmlファイルが見つかりませんでした</string>
|
||||
<string name="import_error_info">%1$s: %2$s</string>
|
||||
<string name="create_marker_error">マーカーを作成することができませんでした。もう一度やり直して下さい。</string>
|
||||
<string name="menu_export_all_one_file">すべてエクスポート(全てのトラックを1つのファイルに)</string>
|
||||
<string name="menu_select_layout">レイアウトを選択</string>
|
||||
<string name="permission_gps_failed">OpenTracksはGPSにアクセスする権限が必要です。</string>
|
||||
</resources>
|
||||
|
||||
@@ -588,4 +588,8 @@ limitations under the License.
|
||||
<string name="stats_sensors_temperature">Temperatur</string>
|
||||
<string name="sensor_state_temperature">Termometer</string>
|
||||
<string name="description_sensor_temperature">Temperatur (Celsius)</string>
|
||||
<string name="activity_type_gravel_biking">gravelsykling</string>
|
||||
<string name="settings_night_mode_option_day_dynamic">Dag (DynamicColor)</string>
|
||||
<string name="settings_night_mode_option_night_dynamic">Natt (DynamicColor)</string>
|
||||
<string name="settings_night_mode_option_night_oled_dynamic">OLED-vennlig (DynamicColor)</string>
|
||||
</resources>
|
||||
|
||||
@@ -603,4 +603,5 @@ limitations under the License.
|
||||
<string name="description_sensor_temperature">Температура (Цельсій)</string>
|
||||
<string name="sensor_state_temperature">Термометр</string>
|
||||
<string name="stats_sensors_temperature">Температура</string>
|
||||
<string name="activity_type_gravel_biking">гравійний велосипед</string>
|
||||
</resources>
|
||||
|
||||
@@ -17,7 +17,7 @@ limitations under the License.
|
||||
<!-- Activity Type -->
|
||||
<string name="activity_type_airplane">坐飞机</string>
|
||||
<string name="activity_type_atv">全地形越野</string>
|
||||
<string name="activity_type_biking">自行车</string>
|
||||
<string name="activity_type_biking">骑行</string>
|
||||
<string name="activity_type_blimp">小型飞艇游览</string>
|
||||
<string name="activity_type_boat">船</string>
|
||||
<string name="activity_type_climbing">攀岩</string>
|
||||
@@ -633,4 +633,5 @@ limitations under the License.
|
||||
<string name="description_sensor_temperature">温度(摄氏度)</string>
|
||||
<string name="sensor_state_temperature">温度计</string>
|
||||
<string name="stats_sensors_temperature">温度</string>
|
||||
<string name="activity_type_gravel_biking">砾石骑行</string>
|
||||
</resources>
|
||||
|
||||
@@ -83,6 +83,7 @@ limitations under the License.
|
||||
<string name="activity_type_airplane">airplane</string>
|
||||
<string name="activity_type_atv">ATV</string>
|
||||
<string name="activity_type_biking">biking</string>
|
||||
<string name="activity_type_gravel_biking">gravel biking</string>
|
||||
<string name="activity_type_blimp">blimp</string>
|
||||
<string name="activity_type_boat">boat</string>
|
||||
<string name="activity_type_climbing">climbing</string>
|
||||
|
||||
Reference in New Issue
Block a user