forked from upstream-mirrors/OpenTracks
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ca2bc6426c | |||
| 81097aac40 | |||
| a74b5fc743 | |||
| e996ad0a0c | |||
| 0f726958e0 | |||
| 3a84520819 | |||
| 8328069b9d | |||
| b2df79caf2 |
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
_OpenTracks_ is a sport tracking application that completely respects your privacy.
|
_OpenTracks_ is a sport tracking application that completely respects your privacy.
|
||||||
|
|
||||||
|
[](https://github.com/humanetech-community/awesome-humane-tech)
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Free</th>
|
<th>Free</th>
|
||||||
|
|||||||
+4
-13
@@ -51,12 +51,13 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "de.dennisguse.opentracks"
|
applicationId "de.dennisguse.opentracks"
|
||||||
versionCode 3732
|
versionCode 3740
|
||||||
versionName "v3.13.0"
|
versionName "v3.13.2"
|
||||||
|
|
||||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
|
|
||||||
@@ -67,25 +68,15 @@ android {
|
|||||||
debug {
|
debug {
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".debug"
|
||||||
versionNameSuffix "-debug"
|
versionNameSuffix "-debug"
|
||||||
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
release {
|
release {
|
||||||
shrinkResources true
|
minifyEnabled false
|
||||||
minifyEnabled true
|
|
||||||
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
releasePlayStore {
|
releasePlayStore {
|
||||||
applicationIdSuffix ".playstore"
|
applicationIdSuffix ".playstore"
|
||||||
versionNameSuffix "-PlayStore"
|
versionNameSuffix "-PlayStore"
|
||||||
|
|
||||||
shrinkResources true
|
|
||||||
minifyEnabled true
|
|
||||||
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
v3.13.1: OpenTracks
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Crash on record start: minify/shrink removed a drawable
|
||||||
|
- Automatic export failed silently (mainly remote destinations)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
v3.13.2: OpenTracks
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Crash in landscape mode
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
-dontobfuscate
|
|
||||||
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable
|
|
||||||
@@ -9,6 +9,7 @@ import androidx.test.filters.LargeTest;
|
|||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
@@ -196,6 +197,7 @@ public class ExportImportTest {
|
|||||||
assertNull(importedTrack);
|
assertNull(importedTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
public void kmz_only_track() {
|
public void kmz_only_track() {
|
||||||
@@ -203,6 +205,7 @@ public class ExportImportTest {
|
|||||||
Log.e(TAG, "Test not implemented.");
|
Log.e(TAG, "Test not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
public void kmz_with_trackdetail() {
|
public void kmz_with_trackdetail() {
|
||||||
@@ -210,6 +213,7 @@ public class ExportImportTest {
|
|||||||
Log.e(TAG, "Test not implemented.");
|
Log.e(TAG, "Test not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
public void kmz_with_trackdetail_and_sensordata() {
|
public void kmz_with_trackdetail_and_sensordata() {
|
||||||
@@ -217,6 +221,7 @@ public class ExportImportTest {
|
|||||||
Log.e(TAG, "Test not implemented.");
|
Log.e(TAG, "Test not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
public void kmz_with_trackdetail_and_sensordata_and_pictures() {
|
public void kmz_with_trackdetail_and_sensordata_and_pictures() {
|
||||||
|
|||||||
@@ -95,9 +95,7 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
|
|||||||
}
|
}
|
||||||
|
|
||||||
setActivityTypeIcon(iconValue);
|
setActivityTypeIcon(iconValue);
|
||||||
viewBinding.trackEditActivityTypeIcon.setOnClickListener(v -> {
|
viewBinding.trackEditActivityTypeIcon.setOnClickListener(v -> ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), viewBinding.trackEditActivityType.getText().toString()));
|
||||||
ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), viewBinding.trackEditActivityType.getText().toString());
|
|
||||||
});
|
|
||||||
|
|
||||||
viewBinding.trackEditDescription.setText(track.getDescription());
|
viewBinding.trackEditDescription.setText(track.getDescription());
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,10 @@ public class Track {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Id(Parcel in) {
|
||||||
|
id = in.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
//TOOD Limit visibility to TrackRecordingService / ContentProvider
|
//TOOD Limit visibility to TrackRecordingService / ContentProvider
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
|
|
||||||
private ChartBinding viewBinding;
|
private ChartBinding viewBinding;
|
||||||
|
|
||||||
//TODO Why is this needed?
|
//TODO REMOVE: Used to restore the TrackStatistics via TrackStatisticsUpdater; for the diagrams we should consider not this setting and just use all data that is in the database
|
||||||
|
@Deprecated
|
||||||
private int recordingDistanceInterval;
|
private int recordingDistanceInterval;
|
||||||
private String category = "";
|
private String category = "";
|
||||||
|
|
||||||
|
|||||||
@@ -109,9 +109,7 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
|||||||
handlerUpdateUI = new Handler();
|
handlerUpdateUI = new Handler();
|
||||||
|
|
||||||
|
|
||||||
viewBinding.statsActivityTypeIcon.setOnClickListener(v -> {
|
viewBinding.statsActivityTypeIcon.setOnClickListener(v -> ((TrackRecordingActivity) getActivity()).chooseActivityType(category));
|
||||||
((TrackRecordingActivity) getActivity()).chooseActivityType(category);
|
|
||||||
});
|
|
||||||
|
|
||||||
sensorsAdapter = new SensorsAdapter(getContext());
|
sensorsAdapter = new SensorsAdapter(getContext());
|
||||||
sensorsRecyclerView = viewBinding.statsSensorsRecyclerView;
|
sensorsRecyclerView = viewBinding.statsSensorsRecyclerView;
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import android.content.SharedPreferences;
|
|||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -46,12 +48,14 @@ import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
|||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
||||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||||
|
import de.dennisguse.opentracks.io.file.exporter.ExportServiceResultReceiver;
|
||||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||||
import de.dennisguse.opentracks.services.handlers.HandlerServer;
|
import de.dennisguse.opentracks.services.handlers.HandlerServer;
|
||||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||||
import de.dennisguse.opentracks.services.sensors.ElevationSumManager;
|
import de.dennisguse.opentracks.services.sensors.ElevationSumManager;
|
||||||
import de.dennisguse.opentracks.services.tasks.AnnouncementPeriodicTaskFactory;
|
import de.dennisguse.opentracks.services.tasks.AnnouncementPeriodicTaskFactory;
|
||||||
import de.dennisguse.opentracks.services.tasks.PeriodicTaskExecutor;
|
import de.dennisguse.opentracks.services.tasks.PeriodicTaskExecutor;
|
||||||
|
import de.dennisguse.opentracks.settings.SettingsActivity;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||||
import de.dennisguse.opentracks.util.ExportUtils;
|
import de.dennisguse.opentracks.util.ExportUtils;
|
||||||
@@ -69,7 +73,7 @@ import de.dennisguse.opentracks.util.TrackPointUtils;
|
|||||||
*
|
*
|
||||||
* @author Leif Hendrik Wilden
|
* @author Leif Hendrik Wilden
|
||||||
*/
|
*/
|
||||||
public class TrackRecordingService extends Service implements HandlerServer.HandlerServerInterface {
|
public class TrackRecordingService extends Service implements HandlerServer.HandlerServerInterface, ExportServiceResultReceiver.Receiver {
|
||||||
|
|
||||||
private static final String TAG = TrackRecordingService.class.getSimpleName();
|
private static final String TAG = TrackRecordingService.class.getSimpleName();
|
||||||
|
|
||||||
@@ -431,7 +435,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportUtils.postWorkoutExport(this, track);
|
ExportUtils.postWorkoutExport(this, track, new ExportServiceResultReceiver(new Handler(), this));
|
||||||
|
|
||||||
endRecording(true);
|
endRecording(true);
|
||||||
}
|
}
|
||||||
@@ -751,4 +755,16 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
public GpsStatusValue getGpsStatus() {
|
public GpsStatusValue getGpsStatus() {
|
||||||
return handlerServer.getGpsStatus();
|
return handlerServer.getGpsStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceiveResult(final int resultCode, final Bundle resultData) {
|
||||||
|
Log.w(TAG, "onReceiveResult: " + resultCode);
|
||||||
|
if (resultCode != ExportServiceResultReceiver.RESULT_CODE_SUCCESS) {
|
||||||
|
Intent intent = new Intent(this, SettingsActivity.class);
|
||||||
|
intent.putExtra(SettingsActivity.EXTRAS_CHECK_EXPORT_DIRECTORY, true);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,9 +95,7 @@ public class ActivityTypePreference extends DialogPreference {
|
|||||||
});
|
});
|
||||||
|
|
||||||
iconView = view.findViewById(R.id.activity_type_preference_spinner);
|
iconView = view.findViewById(R.id.activity_type_preference_spinner);
|
||||||
iconView.setOnClickListener((it) -> {
|
iconView.setOnClickListener((it) -> showIconSelectDialog());
|
||||||
showIconSelectDialog();
|
|
||||||
});
|
|
||||||
|
|
||||||
updateIcon(TrackIconUtils.getIconValue(context, category));
|
updateIcon(TrackIconUtils.getIconValue(context, category));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package de.dennisguse.opentracks.settings;
|
package de.dennisguse.opentracks.settings;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
@@ -32,8 +34,10 @@ import de.dennisguse.opentracks.util.StringUtils;
|
|||||||
public class SettingsActivity extends AppCompatActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, ResetDialogPreference.ResetCallback {
|
public class SettingsActivity extends AppCompatActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, ResetDialogPreference.ResetCallback {
|
||||||
|
|
||||||
private static final String TAG = SettingsActivity.class.getSimpleName();
|
private static final String TAG = SettingsActivity.class.getSimpleName();
|
||||||
|
public static final String EXTRAS_CHECK_EXPORT_DIRECTORY = "Check Export Directory";
|
||||||
|
|
||||||
private PrefsFragment prefsFragment;
|
private PrefsFragment prefsFragment;
|
||||||
|
private boolean checkExportDirectory = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -45,9 +49,29 @@ public class SettingsActivity extends AppCompatActivity implements ChooseActivit
|
|||||||
toolbar.setTitle(R.string.menu_settings);
|
toolbar.setTitle(R.string.menu_settings);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
if (intent != null && intent.hasExtra(EXTRAS_CHECK_EXPORT_DIRECTORY)) {
|
||||||
|
checkExportDirectory = true;
|
||||||
|
}
|
||||||
onReset();
|
onReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
if (checkExportDirectory) {
|
||||||
|
checkExportDirectory = false;
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setIcon(R.drawable.ic_logo_24dp)
|
||||||
|
.setTitle(R.string.app_name)
|
||||||
|
.setMessage(R.string.export_error_post_workout)
|
||||||
|
.setNeutralButton(R.string.generic_ok, null)
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChooseActivityTypeDone(String iconValue) {
|
public void onChooseActivityTypeDone(String iconValue) {
|
||||||
prefsFragment.setDefaultActivity(iconValue);
|
prefsFragment.setDefaultActivity(iconValue);
|
||||||
|
|||||||
@@ -17,18 +17,20 @@ import java.util.List;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
import de.dennisguse.opentracks.io.file.exporter.ExportService;
|
||||||
|
import de.dennisguse.opentracks.io.file.exporter.ExportServiceResultReceiver;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||||
|
|
||||||
public class ExportUtils {
|
public class ExportUtils {
|
||||||
|
|
||||||
private static final String TAG = ExportUtils.class.getSimpleName();
|
private static final String TAG = ExportUtils.class.getSimpleName();
|
||||||
|
|
||||||
public static void postWorkoutExport(Context context, Track track) {
|
public static void postWorkoutExport(Context context, Track track, ExportServiceResultReceiver resultReceiver) {
|
||||||
if (PreferencesUtils.shouldInstantExportAfterWorkout(context)) {
|
if (PreferencesUtils.shouldInstantExportAfterWorkout(context)) {
|
||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
||||||
DocumentFile directory = PreferencesUtils.getDefaultExportDirectoryUri(context);
|
DocumentFile directory = PreferencesUtils.getDefaultExportDirectoryUri(context);
|
||||||
|
|
||||||
exportTrack(context, trackFileFormat, directory, track);
|
ExportService.enqueue(context, resultReceiver, track.getId(), trackFileFormat, directory.getUri());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +38,10 @@ public class ExportUtils {
|
|||||||
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context);
|
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context);
|
||||||
|
|
||||||
Uri exportDocumentFileUri = getExportDocumentFileUri(context, track.getId(), trackFileFormat, directory);
|
Uri exportDocumentFileUri = getExportDocumentFileUri(context, track.getId(), trackFileFormat, directory);
|
||||||
|
if (exportDocumentFileUri == null) {
|
||||||
|
Log.e(TAG, "Couldn't create document file for export");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(exportDocumentFileUri)) {
|
try (OutputStream outputStream = context.getContentResolver().openOutputStream(exportDocumentFileUri)) {
|
||||||
if (trackExporter.writeTrack(track, outputStream)) {
|
if (trackExporter.writeTrack(track, outputStream)) {
|
||||||
@@ -80,7 +86,10 @@ public class ExportUtils {
|
|||||||
String exportFileName = getExportFileNameByTrackId(trackId, trackFileFormat.getExtension());
|
String exportFileName = getExportFileNameByTrackId(trackId, trackFileFormat.getExtension());
|
||||||
Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName);
|
Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName);
|
||||||
if (exportDocumentFileUri == null) {
|
if (exportDocumentFileUri == null) {
|
||||||
exportDocumentFileUri = directory.createFile(trackFileFormat.getMimeType(), exportFileName).getUri();
|
final DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), exportFileName);
|
||||||
|
if (file != null) {
|
||||||
|
exportDocumentFileUri = file.getUri();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return exportDocumentFileUri;
|
return exportDocumentFileUri;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ limitations under the License.
|
|||||||
android:id="@+id/track_controller_container"
|
android:id="@+id/track_controller_container"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/track_controller_background_normal"
|
android:background="@drawable/track_controller_background"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingLeft="8dp"
|
android:paddingLeft="8dp"
|
||||||
android:paddingRight="8dp">
|
android:paddingRight="8dp">
|
||||||
|
|||||||
@@ -212,6 +212,7 @@ limitations under the License.
|
|||||||
<string name="export_with_photos">with photos</string>
|
<string name="export_with_photos">with photos</string>
|
||||||
<string name="export_without_photos">without photos</string>
|
<string name="export_without_photos">without photos</string>
|
||||||
<string name="export_error">Exported %1$d of %2$s to %3$s</string>
|
<string name="export_error">Exported %1$d of %2$s to %3$s</string>
|
||||||
|
<string name="export_error_post_workout">Post-workout export failed, please check the export directory.</string>
|
||||||
<string name="export_option">as %1$s to %2$s</string>
|
<string name="export_option">as %1$s to %2$s</string>
|
||||||
<string name="export_progress_message">Exporting to %1$s…</string>
|
<string name="export_progress_message">Exporting to %1$s…</string>
|
||||||
<string name="export_success">Exported %1$s to %2$s</string>
|
<string name="export_success">Exported %1$s to %2$s</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user