diff --git a/app/build.gradle b/app/build.gradle index 96cfdac..c967b2e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -82,6 +82,9 @@ dependencies { implementation 'stax:stax-api:1.0.1' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.8' + // File Utils + implementation 'commons-io:commons-io:2.6' + // Upload to OSM implementation('de.westnordost:osmapi-traces:1.0') configurations { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6c3c40..79648e4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,6 +27,7 @@ + { try{ String file= getFilesDir().getAbsolutePath() + "/shared/backup.ftb"; - if (!new File(file).getParentFile().mkdirs()) { + File parent = new File(file).getParentFile(); + if (!parent.exists() && !parent.mkdirs()) { throw new IOException("Cannot write"); } Uri uri= FileProvider.getUriForFile(getBaseContext(), "de.tadris.fitness.fileprovider", new File(file)); @@ -125,7 +131,7 @@ public class SettingsActivity extends FitoTrackSettingsActivity { mHandler.post(() -> { dialogController.cancel(); - shareFile(uri); + FileUtils.saveOrShareFile(this, uri, "ftb"); }); }catch (Exception e){ e.printStackTrace(); diff --git a/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java b/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java index 02cdb4a..d336847 100644 --- a/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java +++ b/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java @@ -48,6 +48,7 @@ import de.tadris.fitness.data.WorkoutSample; import de.tadris.fitness.osm.OAuthAuthentication; import de.tadris.fitness.osm.OsmTraceUploader; import de.tadris.fitness.util.DialogUtils; +import de.tadris.fitness.util.FileUtils; import de.tadris.fitness.util.gpx.GpxExporter; import de.tadris.fitness.util.unit.UnitUtils; import de.tadris.fitness.view.ProgressDialogController; @@ -202,20 +203,25 @@ public class ShowWorkoutActivity extends WorkoutActivity implements DialogUtils. } private void exportToGpx(){ + if (!hasStoragePermission()) { + requestStoragePermissions(); + return; + } ProgressDialogController dialogController= new ProgressDialogController(this, getString(R.string.exporting)); dialogController.setIndeterminate(true); dialogController.show(); new Thread(() -> { try{ String file= getFilesDir().getAbsolutePath() + "/shared/workout.gpx"; - if (!new File(file).getParentFile().mkdirs()) { + File parent = new File(file).getParentFile(); + if (!parent.exists() && !parent.mkdirs()) { throw new IOException("Cannot write to " + file); } Uri uri= FileProvider.getUriForFile(getBaseContext(), "de.tadris.fitness.fileprovider", new File(file)); GpxExporter.exportWorkout(getBaseContext(), workout, new File(file)); dialogController.cancel(); - mHandler.post(() -> shareFile(uri)); + mHandler.post(() -> FileUtils.saveOrShareFile(this, uri, "gpx")); }catch (Exception e){ e.printStackTrace(); mHandler.post(() -> showErrorDialog(e, R.string.error, R.string.errorGpxExportFailed)); diff --git a/app/src/main/java/de/tadris/fitness/export/BackupController.java b/app/src/main/java/de/tadris/fitness/export/BackupController.java index dd7b7c1..546ffe3 100644 --- a/app/src/main/java/de/tadris/fitness/export/BackupController.java +++ b/app/src/main/java/de/tadris/fitness/export/BackupController.java @@ -31,7 +31,6 @@ import java.util.Arrays; import de.tadris.fitness.Instance; import de.tadris.fitness.R; import de.tadris.fitness.data.AppDatabase; -import de.tadris.fitness.data.UserPreferences; import de.tadris.fitness.util.unit.UnitUtils; public class BackupController { @@ -41,7 +40,6 @@ public class BackupController { private final Context context; private final File output; private final ExportStatusListener listener; - private UserPreferences preferences; private AppDatabase database; private FitoTrackDataContainer dataContainer; @@ -55,10 +53,6 @@ public class BackupController { public void exportData() throws IOException { listener.onStatusChanged(0, context.getString(R.string.initialising)); init(); - listener.onStatusChanged(10, context.getString(R.string.preferences)); - newContainer(); - - saveSettingsToContainer(); listener.onStatusChanged(20, context.getString(R.string.workouts)); saveWorkoutsToContainer(); listener.onStatusChanged(40, context.getString(R.string.locationData)); @@ -69,32 +63,24 @@ public class BackupController { } private void init(){ - preferences= Instance.getInstance(context).userPreferences; database= Instance.getInstance(context).db; UnitUtils.setUnit(context); // Ensure unit system is correct + newContainer(); } private void newContainer(){ dataContainer= new FitoTrackDataContainer(); - dataContainer.version= VERSION; - dataContainer.workouts= new ArrayList<>(); - dataContainer.samples= new ArrayList<>(); - } - - private void saveSettingsToContainer(){ - FitoTrackSettings settings= new FitoTrackSettings(); - settings.weight= preferences.getUserWeight(); - settings.mapStyle= preferences.getMapStyle(); - settings.preferredUnitSystem= String.valueOf(UnitUtils.CHOSEN_SYSTEM.getId()); - dataContainer.settings= settings; + dataContainer.setVersion(VERSION); + dataContainer.setWorkouts(new ArrayList<>()); + dataContainer.setSamples(new ArrayList<>()); } private void saveWorkoutsToContainer(){ - dataContainer.workouts.addAll(Arrays.asList(database.workoutDao().getWorkouts())); + dataContainer.getWorkouts().addAll(Arrays.asList(database.workoutDao().getWorkouts())); } private void saveSamplesToContainer(){ - dataContainer.samples.addAll(Arrays.asList(database.workoutDao().getSamples())); + dataContainer.getSamples().addAll(Arrays.asList(database.workoutDao().getSamples())); } private void writeContainerToOutputFile() throws IOException { diff --git a/app/src/main/java/de/tadris/fitness/export/FitoTrackDataContainer.java b/app/src/main/java/de/tadris/fitness/export/FitoTrackDataContainer.java index 2e25eac..fad4d84 100644 --- a/app/src/main/java/de/tadris/fitness/export/FitoTrackDataContainer.java +++ b/app/src/main/java/de/tadris/fitness/export/FitoTrackDataContainer.java @@ -31,18 +31,16 @@ import de.tadris.fitness.data.WorkoutSample; @JsonIgnoreProperties(ignoreUnknown = true) class FitoTrackDataContainer { - int version; - List workouts; - List samples; - FitoTrackSettings settings; + private int version; + private List workouts; + private List samples; public FitoTrackDataContainer(){} - public FitoTrackDataContainer(int version, List workouts, List samples, FitoTrackSettings settings) { + public FitoTrackDataContainer(int version, List workouts, List samples) { this.version = version; this.workouts = workouts; this.samples = samples; - this.settings = settings; } public int getVersion() { @@ -69,11 +67,5 @@ class FitoTrackDataContainer { this.samples = samples; } - public FitoTrackSettings getSettings() { - return settings; - } - public void setSettings(FitoTrackSettings settings) { - this.settings = settings; - } } diff --git a/app/src/main/java/de/tadris/fitness/export/FitoTrackSettings.java b/app/src/main/java/de/tadris/fitness/export/FitoTrackSettings.java deleted file mode 100644 index 44b50b2..0000000 --- a/app/src/main/java/de/tadris/fitness/export/FitoTrackSettings.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2019 Jannis Scheibe - * - * This file is part of FitoTrack - * - * FitoTrack is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * FitoTrack is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package de.tadris.fitness.export; - -public class FitoTrackSettings { - - String preferredUnitSystem; - int weight; - String mapStyle; - - public FitoTrackSettings(){} - - public FitoTrackSettings(String preferredUnitSystem, int weight, String mapStyle) { - this.preferredUnitSystem = preferredUnitSystem; - this.weight = weight; - this.mapStyle = mapStyle; - } - - public String getPreferredUnitSystem() { - return preferredUnitSystem; - } - - public void setPreferredUnitSystem(String preferredUnitSystem) { - this.preferredUnitSystem = preferredUnitSystem; - } - - public int getWeight() { - return weight; - } - - public void setWeight(int weight) { - this.weight = weight; - } - - public String getMapStyle() { - return mapStyle; - } - - public void setMapStyle(String mapStyle) { - this.mapStyle = mapStyle; - } -} diff --git a/app/src/main/java/de/tadris/fitness/export/RestoreController.java b/app/src/main/java/de/tadris/fitness/export/RestoreController.java index 1ca0bda..49828ce 100644 --- a/app/src/main/java/de/tadris/fitness/export/RestoreController.java +++ b/app/src/main/java/de/tadris/fitness/export/RestoreController.java @@ -19,10 +19,8 @@ package de.tadris.fitness.export; -import android.annotation.SuppressLint; import android.content.Context; import android.net.Uri; -import android.preference.PreferenceManager; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.dataformat.xml.XmlMapper; @@ -54,9 +52,6 @@ public class RestoreController { listener.onStatusChanged(0, context.getString(R.string.loadingFile)); loadDataFromFile(); checkVersion(); - listener.onStatusChanged(40, context.getString(R.string.preferences)); - restoreSettings(); - restoreDatabase(); listener.onStatusChanged(100, context.getString(R.string.finished)); } @@ -68,21 +63,11 @@ public class RestoreController { } private void checkVersion() throws UnsupportedVersionException { - if(dataContainer.version != 1){ - throw new UnsupportedVersionException("Version Code" + dataContainer.version + " is unsupported!"); + if (dataContainer.getVersion() != 1) { + throw new UnsupportedVersionException("Version Code" + dataContainer.getVersion() + " is unsupported!"); } } - @SuppressLint("ApplySharedPref") - private void restoreSettings(){ - PreferenceManager.getDefaultSharedPreferences(context) - .edit().clear() - .putInt("weight", dataContainer.settings.weight) - .putString("unitSystem", dataContainer.settings.preferredUnitSystem) - .putBoolean("firstStart", false).putString("mapStyle", dataContainer.settings.mapStyle) - .commit(); - } - private void restoreDatabase(){ database.runInTransaction(() -> { resetDatabase(); @@ -97,8 +82,8 @@ public class RestoreController { private void restoreWorkouts(){ listener.onStatusChanged(60, context.getString(R.string.workouts)); - if(dataContainer.workouts != null){ - for(Workout workout : dataContainer.workouts){ + if (dataContainer.getWorkouts() != null) { + for (Workout workout : dataContainer.getWorkouts()) { database.workoutDao().insertWorkout(workout); } } @@ -106,8 +91,8 @@ public class RestoreController { private void restoreSamples(){ listener.onStatusChanged(80, context.getString(R.string.locationData)); - if(dataContainer.samples != null){ - for(WorkoutSample sample : dataContainer.samples){ + if (dataContainer.getSamples() != null) { + for (WorkoutSample sample : dataContainer.getSamples()) { database.workoutDao().insertSample(sample); } } diff --git a/app/src/main/java/de/tadris/fitness/util/FileUtils.java b/app/src/main/java/de/tadris/fitness/util/FileUtils.java new file mode 100644 index 0000000..f541e25 --- /dev/null +++ b/app/src/main/java/de/tadris/fitness/util/FileUtils.java @@ -0,0 +1,78 @@ +package de.tadris.fitness.util; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Intent; +import android.net.Uri; +import android.os.Environment; +import android.util.Log; +import android.widget.Toast; + +import org.apache.commons.io.IOUtils; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import de.tadris.fitness.R; + +public class FileUtils { + + public static void saveOrShareFile(Activity activity, Uri uri, String suffix) { + String[] colors = {activity.getString(R.string.share), activity.getString(R.string.save)}; + + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setItems(colors, (dialog, which) -> { + if (which == 0) { + shareFile(activity, uri); + } else { + try { + saveFile(activity, uri, suffix); + Toast.makeText(activity, R.string.savedToDownloads, Toast.LENGTH_LONG).show(); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, R.string.savingFailed, Toast.LENGTH_LONG).show(); + } + } + }); + builder.show(); + } + + private static void saveFile(Activity activity, Uri fileUri, String suffix) throws IOException { + File target = new File(Environment.getExternalStorageDirectory(), "Download/fitotrack" + System.currentTimeMillis() + "." + suffix); + if (!target.createNewFile()) { + throw new IOException("Cannot write to file " + target); + } + copyFile(activity, fileUri, Uri.fromFile(target)); + } + + private static void copyFile(Activity activity, Uri sourceUri, Uri targetUri) throws IOException { + InputStream input = activity.getContentResolver().openInputStream(sourceUri); + if (input == null) { + throw new IOException("Source file not found"); + } + OutputStream output = activity.getContentResolver().openOutputStream(targetUri); + IOUtils.copy(input, output); + } + + private static void shareFile(Activity activity, Uri uri) { + Intent intentShareFile = new Intent(Intent.ACTION_SEND); + intentShareFile.setDataAndType(uri, activity.getContentResolver().getType(uri)); + intentShareFile.putExtra(Intent.EXTRA_STREAM, uri); + intentShareFile.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + activity.startActivity(Intent.createChooser(intentShareFile, activity.getString(R.string.shareFile))); + + Log.d("Export", uri.toString()); + Log.d("Export", activity.getContentResolver().getType(uri)); + try { + Log.d("Export", new BufferedInputStream(activity.getContentResolver().openInputStream(uri)).toString()); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + +} diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9222344..dbe1905 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -35,7 +35,7 @@ Der Datenimport ist fehlgeschlagen. Als GPX-Datei exportieren Daten exportieren - Erstellt ein Backup von all deinen Einstellungen und deiner Workoutdaten + Erstellt ein Backup von all deinern Workoutdaten Exportieren Fertig GPS diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 2405657..66bc27f 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -115,7 +115,6 @@ Sistema preferido de unidades Ajustes Datos de exportación - Esto toma una copia de seguridad de todas sus preferencias y datos de entrenamiento Importar copia de seguridad Restaurar una copia de seguridad GPS diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1f751b4..a55932e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -136,7 +136,7 @@ Preferred system of units Settings Export Data - This takes a backup of all your preferences and workout data + This takes a backup of all your workout data Import Data Backup Restore a taken backup GPS @@ -150,4 +150,9 @@ TextToSpeech is not available Edit Comment Announcement Mode + + Save + Share + Saved to Downloads + Saving failed