diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9130196 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build +/app/build +/app/release + +# misc +.* +*.properties +*.iml +!.gitignore + diff --git a/app/build.gradle b/app/build.gradle index c204660..f490654 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,12 @@ android { sourceCompatibility = '1.8' targetCompatibility = '1.8' } + lintOptions { + checkReleaseBuilds false + // Or, if you prefer, you can continue to check for errors in release builds, + // but continue the build even when errors are found: +// abortOnError false + } } dependencies { diff --git a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java index 5edd3c6..2121c5e 100644 --- a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java +++ b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java @@ -38,6 +38,8 @@ import android.view.ViewGroup; import android.widget.EditText; import android.widget.TextView; +import android.speech.tts.TextToSpeech; + import androidx.core.app.ActivityCompat; import org.mapsforge.core.graphics.Paint; @@ -50,9 +52,11 @@ import org.mapsforge.map.layer.overlay.Polyline; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import de.tadris.fitness.Instance; import de.tadris.fitness.R; +import de.tadris.fitness.data.UserPreferences; import de.tadris.fitness.data.Workout; import de.tadris.fitness.map.MapManager; import de.tadris.fitness.map.tilesource.TileSources; @@ -82,6 +86,8 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location private Intent locationListener; private Intent pressureService; private boolean saved= false; + TextToSpeech tts; + boolean ttsReady = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -102,6 +108,9 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location recorder= new WorkoutRecorder(this, ACTIVITY, this); recorder.start(); + tts = new TextToSpeech(this, (int status) -> { + ttsReady = status == TextToSpeech.SUCCESS && tts.setLanguage(Locale.getDefault())>=0; + }); infoViews[0]= new InfoViewHolder(findViewById(R.id.recordInfo1Title), findViewById(R.id.recordInfo1Value)); infoViews[1]= new InfoViewHolder(findViewById(R.id.recordInfo2Title), findViewById(R.id.recordInfo2Value)); infoViews[2]= new InfoViewHolder(findViewById(R.id.recordInfo3Title), findViewById(R.id.recordInfo3Value)); @@ -169,9 +178,7 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location try{ while (recorder.isActive()){ Thread.sleep(1000); - if(isResumed){ - mHandler.post(this::updateDescription); - } + mHandler.post(this::updateDescription); } }catch (InterruptedException e){ e.printStackTrace(); @@ -179,15 +186,38 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location }).start(); } - private int i = 0; + long lastSpokenUpdateTime = 0; + int lastSpokenUpdateDistance = 0; - private void updateDescription(){ - i++; - timeView.setText(UnitUtils.getHourMinuteSecondTime(recorder.getDuration())); - infoViews[0].setText(getString(R.string.workoutDistance), UnitUtils.getDistance(recorder.getDistance())); - infoViews[1].setText(getString(R.string.workoutBurnedEnergy), recorder.getCalories() + " kcal"); - infoViews[2].setText(getString(R.string.workoutAvgSpeed), UnitUtils.getSpeed(Math.min(100d, recorder.getAvgSpeed()))); - infoViews[3].setText(getString(R.string.workoutPauseDuration), UnitUtils.getHourMinuteSecondTime(recorder.getPauseDuration())); + private void updateDescription() { + long duration = recorder.getDuration(); + int distanceInMeters = recorder.getDistance(); + final String distanceCaption = getString(R.string.workoutDistance); + final String distance = UnitUtils.getDistance(distanceInMeters); + final String avgSpeedCaption = getString(R.string.workoutAvgSpeed); + final String avgSpeed = UnitUtils.getSpeed(Math.min(100d, recorder.getAvgSpeed())); + if (isResumed) { + timeView.setText(UnitUtils.getHourMinuteSecondTime(duration)); + infoViews[0].setText(distanceCaption, distance); + infoViews[1].setText(getString(R.string.workoutBurnedEnergy), recorder.getCalories() + " kcal"); + infoViews[2].setText(avgSpeedCaption, avgSpeed); + infoViews[3].setText(getString(R.string.workoutPauseDuration), UnitUtils.getHourMinuteSecondTime(recorder.getPauseDuration())); + } + + final UserPreferences prefs = Instance.getInstance(this).userPreferences; + final long intervalT = 60 * 1000 * prefs.getSpokenUpdateTimePeriod(); + final int intervalInMeters = (int) (1000.0 / UnitUtils.CHOSEN_SYSTEM.getDistanceFromKilometers(1) * prefs.getSpokenUpdateDistancePeriod()); + if (!ttsReady || + (intervalT == 0 || duration / intervalT == lastSpokenUpdateTime / intervalT) + && (intervalInMeters == 0 || distanceInMeters / intervalInMeters == lastSpokenUpdateDistance / intervalInMeters) + ) return; + + final String text = distanceCaption + ": " + distance + ". " + + avgSpeedCaption + ": " + avgSpeed; + tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, "updateDescription" + duration); + + lastSpokenUpdateTime = duration; + lastSpokenUpdateDistance = distanceInMeters; } private void stop(){ diff --git a/app/src/main/java/de/tadris/fitness/activity/SettingsActivity.java b/app/src/main/java/de/tadris/fitness/activity/SettingsActivity.java index 9d0befb..e17c687 100644 --- a/app/src/main/java/de/tadris/fitness/activity/SettingsActivity.java +++ b/app/src/main/java/de/tadris/fitness/activity/SettingsActivity.java @@ -165,6 +165,10 @@ public class SettingsActivity extends PreferenceActivity { showWeightPicker(); return true; }); + findPreference("speech").setOnPreferenceClickListener(preference -> { + showSpeechConfig(); + return true; + }); findPreference("import").setOnPreferenceClickListener(preference -> { showImportDialog(); return true; @@ -285,7 +289,8 @@ public class SettingsActivity extends PreferenceActivity { np.setMaxValue((int) UnitUtils.CHOSEN_SYSTEM.getWeightFromKilogram(150)); np.setMinValue((int) UnitUtils.CHOSEN_SYSTEM.getWeightFromKilogram(20)); np.setFormatter(value -> value + " " + UnitUtils.CHOSEN_SYSTEM.getWeightUnit()); - np.setValue((int)Math.round(UnitUtils.CHOSEN_SYSTEM.getWeightFromKilogram(preferences.getInt("weight", 80)))); + final String preferenceVariable = "weight"; + np.setValue((int)Math.round(UnitUtils.CHOSEN_SYSTEM.getWeightFromKilogram(preferences.getInt(preferenceVariable, 80)))); np.setWrapSelectorWheel(false); d.setView(v); @@ -294,7 +299,47 @@ public class SettingsActivity extends PreferenceActivity { d.setPositiveButton(R.string.okay, (dialog, which) -> { int unitValue= np.getValue(); int kilograms= (int)Math.round(UnitUtils.CHOSEN_SYSTEM.getKilogramFromUnit(unitValue)); - preferences.edit().putInt("weight", kilograms).apply(); + preferences.edit().putInt(preferenceVariable, kilograms).apply(); + }); + + d.create().show(); + + return true; + } + + private boolean showSpeechConfig() { + UnitUtils.setUnit(this); // Maybe the user changed unit system + + final AlertDialog.Builder d = new AlertDialog.Builder(this); + final SharedPreferences preferences= PreferenceManager.getDefaultSharedPreferences(this); + d.setTitle(getString(R.string.pref_spoken_updates_summary)); + View v= getLayoutInflater().inflate(R.layout.dialog_spoken_updates_picker, null); + + NumberPicker npT = v.findViewById(R.id.spokenUpdatesTimePicker); + npT.setMaxValue(60); + npT.setMinValue(0); + npT.setFormatter(value -> value == 0 ? "No speech" : value + " min"); + final String updateTimeVariable = "spokenUpdateTimePeriod"; + npT.setValue(preferences.getInt(updateTimeVariable, 0)); + npT.setWrapSelectorWheel(false); + + final String distanceUnit = " " + UnitUtils.CHOSEN_SYSTEM.getLongDistanceUnit(); + NumberPicker npD = v.findViewById(R.id.spokenUpdatesDistancePicker); + npD.setMaxValue(10); + npD.setMinValue(0); + npD.setFormatter(value -> value == 0 ? "No speech" : value + distanceUnit); + final String updateDistanceVariable = "spokenUpdateDistancePeriod"; + npD.setValue(preferences.getInt(updateDistanceVariable, 0)); + npD.setWrapSelectorWheel(false); + + d.setView(v); + + d.setNegativeButton(R.string.cancel, null); + d.setPositiveButton(R.string.okay, (dialog, which) -> { + preferences.edit() + .putInt(updateTimeVariable, npT.getValue()) + .putInt(updateDistanceVariable, npD.getValue()) + .apply(); }); d.create().show(); diff --git a/app/src/main/java/de/tadris/fitness/data/UserPreferences.java b/app/src/main/java/de/tadris/fitness/data/UserPreferences.java index 7fdb1f4..f9882c5 100644 --- a/app/src/main/java/de/tadris/fitness/data/UserPreferences.java +++ b/app/src/main/java/de/tadris/fitness/data/UserPreferences.java @@ -35,6 +35,14 @@ public class UserPreferences { return preferences.getInt("weight", 80); } + public int getSpokenUpdateTimePeriod(){ + return preferences.getInt("spokenUpdateTimePeriod", 5); + } + + public int getSpokenUpdateDistancePeriod(){ + return preferences.getInt("spokenUpdateDistancePeriod", 1); + } + public String getMapStyle(){ return preferences.getString("mapStyle", "osm.mapnik"); } diff --git a/app/src/main/java/de/tadris/fitness/map/MapManager.java b/app/src/main/java/de/tadris/fitness/map/MapManager.java index caa54c7..23efa99 100644 --- a/app/src/main/java/de/tadris/fitness/map/MapManager.java +++ b/app/src/main/java/de/tadris/fitness/map/MapManager.java @@ -62,7 +62,6 @@ public class MapManager { mapView.getLayerManager().redrawLayers(); mapView.setZoomLevel((byte) 18); - mapView.setCenter(new LatLong(52, 13)); return downloadLayer; } diff --git a/app/src/main/java/de/tadris/fitness/map/tilesource/MapnikTileSource.java b/app/src/main/java/de/tadris/fitness/map/tilesource/MapnikTileSource.java index 30dab49..d9ab541 100644 --- a/app/src/main/java/de/tadris/fitness/map/tilesource/MapnikTileSource.java +++ b/app/src/main/java/de/tadris/fitness/map/tilesource/MapnikTileSource.java @@ -30,7 +30,7 @@ public class MapnikTileSource extends FitoTrackTileSource { "a.tile.openstreetmap.org", "b.tile.openstreetmap.org", "c.tile.openstreetmap.org"}, 443); private static final int PARALLEL_REQUESTS_LIMIT = 8; private static final String PROTOCOL = "https"; - private static final int ZOOM_LEVEL_MAX = 18; + private static final int ZOOM_LEVEL_MAX = 19; private static final int ZOOM_LEVEL_MIN = 0; private static final String NAME = "OSM Mapnik"; diff --git a/app/src/main/java/de/tadris/fitness/recording/WorkoutRecorder.java b/app/src/main/java/de/tadris/fitness/recording/WorkoutRecorder.java index 07b25a3..856166a 100644 --- a/app/src/main/java/de/tadris/fitness/recording/WorkoutRecorder.java +++ b/app/src/main/java/de/tadris/fitness/recording/WorkoutRecorder.java @@ -47,7 +47,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener } } - private static final int PAUSE_TIME= 10000; + private static final int PAUSE_TIME= 1000*1000; /** * Time after which the workout is stopped and saved automatically because there is no activity anymore diff --git a/app/src/main/res/layout/dialog_spoken_updates_picker.xml b/app/src/main/res/layout/dialog_spoken_updates_picker.xml new file mode 100644 index 0000000..3df099f --- /dev/null +++ b/app/src/main/res/layout/dialog_spoken_updates_picker.xml @@ -0,0 +1,40 @@ + + + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index b0cde6c..4459871 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -50,6 +50,11 @@ Bevorzugtes Einheitensystem Dein Gewicht Dein Gewicht ist zur Kalorienberechnung wichtig + + + Spoken Updates + Choose the time and distance between spoken updates + Einstellungen Workout aufzeichnen Wiederherstellen @@ -107,4 +112,4 @@ Upload fehlgeschlagen Upload erfolgreich Nicht autorisiert, nocheinmal versuchen - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index da6a17b..522bf2d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -57,7 +57,7 @@ Pace Route Speed - Avg. Speed + Average Speed Top Speed Burned Energy Total Energy @@ -112,6 +112,8 @@ Export as GPX-File Your Weight Your weight is needed to calculate the burned calories + Spoken Updates + Choose the time and distance between spoken updates Preferred system of units Settings Export Data diff --git a/app/src/main/res/xml/preferences_main.xml b/app/src/main/res/xml/preferences_main.xml index 8757058..3342d39 100644 --- a/app/src/main/res/xml/preferences_main.xml +++ b/app/src/main/res/xml/preferences_main.xml @@ -40,6 +40,13 @@ android:key="mapStyle" android:title="@string/mapStyle" /> + + @@ -54,4 +61,4 @@ - \ No newline at end of file + diff --git a/build.gradle b/build.gradle index 608be65..820a5ba 100644 --- a/build.gradle +++ b/build.gradle @@ -23,11 +23,11 @@ buildscript { repositories { google() jcenter() - + } dependencies { classpath 'com.android.tools.build:gradle:3.5.3' - + // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -37,7 +37,7 @@ allprojects { repositories { google() jcenter() - + } }