mirror of
https://github.com/russok/FitoTrack.git
synced 2025-10-29 08:42:12 -07:00
Merge branch '1.1'
This commit is contained in:
commit
9c17d19308
@ -35,8 +35,8 @@ android {
|
|||||||
applicationId "de.tadris.fitness"
|
applicationId "de.tadris.fitness"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 103
|
versionCode 110
|
||||||
versionName "1.0.3"
|
versionName "1.1.0"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@ -1,4 +1,23 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||||
|
~
|
||||||
|
~ 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 <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="de.tadris.fitness">
|
package="de.tadris.fitness">
|
||||||
@ -46,7 +65,8 @@
|
|||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/filepaths" />
|
android:resource="@xml/filepaths" />
|
||||||
</provider>
|
</provider>
|
||||||
<service android:name=".location.LocationListener"></service>
|
<service android:name=".recording.LocationListener" />
|
||||||
|
<service android:name=".recording.PressureService" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@ -21,14 +21,17 @@ package de.tadris.fitness;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.room.Room;
|
import androidx.room.Room;
|
||||||
|
import androidx.room.migration.Migration;
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.tadris.fitness.data.AppDatabase;
|
import de.tadris.fitness.data.AppDatabase;
|
||||||
import de.tadris.fitness.data.UserPreferences;
|
import de.tadris.fitness.data.UserPreferences;
|
||||||
import de.tadris.fitness.location.LocationListener;
|
import de.tadris.fitness.recording.LocationListener;
|
||||||
import de.tadris.fitness.util.unit.UnitUtils;
|
import de.tadris.fitness.util.unit.UnitUtils;
|
||||||
|
|
||||||
public class Instance {
|
public class Instance {
|
||||||
@ -48,9 +51,45 @@ public class Instance {
|
|||||||
public List<LocationListener.LocationChangeListener> locationChangeListeners= new ArrayList<>();
|
public List<LocationListener.LocationChangeListener> locationChangeListeners= new ArrayList<>();
|
||||||
public UserPreferences userPreferences;
|
public UserPreferences userPreferences;
|
||||||
|
|
||||||
|
public boolean pressureAvailable= false;
|
||||||
|
public float lastPressure= 0;
|
||||||
|
|
||||||
private Instance(Context context) {
|
private Instance(Context context) {
|
||||||
userPreferences= new UserPreferences(context);
|
userPreferences= new UserPreferences(context);
|
||||||
db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
|
db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
|
||||||
|
.addMigrations(new Migration(1, 2) {
|
||||||
|
@Override
|
||||||
|
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||||
|
try{
|
||||||
|
database.beginTransaction();
|
||||||
|
|
||||||
|
database.execSQL("ALTER table workout add descent REAL NOT NULL DEFAULT 0;");
|
||||||
|
database.execSQL("ALTER table workout add ascent REAL NOT NULL DEFAULT 0");
|
||||||
|
|
||||||
|
database.execSQL("ALTER TABLE workout_sample RENAME TO workout_sample2;");
|
||||||
|
|
||||||
|
database.execSQL("CREATE TABLE workout_sample (" +
|
||||||
|
"id INTEGER NOT NULL DEFAULT NULL PRIMARY KEY," +
|
||||||
|
"relativeTime INTEGER NOT NULL DEFAULT NULL," +
|
||||||
|
"elevation REAL NOT NULL DEFAULT NULL," +
|
||||||
|
"absoluteTime INTEGER NOT NULL DEFAULT NULL," +
|
||||||
|
"lat REAL NOT NULL DEFAULT NULL," +
|
||||||
|
"lon REAL NOT NULL DEFAULT NULL," +
|
||||||
|
"speed REAL NOT NULL DEFAULT NULL," +
|
||||||
|
"workout_id INTEGER NOT NULL DEFAULT NULL," +
|
||||||
|
"FOREIGN KEY (workout_id) REFERENCES workout(id) ON DELETE CASCADE);");
|
||||||
|
|
||||||
|
database.execSQL("INSERT INTO workout_sample (id, relativeTime, elevation, absoluteTime, lat, lon, speed, workout_id) " +
|
||||||
|
"SELECT id, relativeTime, elevation, absoluteTime, lat, lon, speed, workout_id FROM workout_sample2");
|
||||||
|
|
||||||
|
database.execSQL("DROP TABLE workout_sample2");
|
||||||
|
|
||||||
|
database.setTransactionSuccessful();
|
||||||
|
}finally {
|
||||||
|
database.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.allowMainThreadQueries()
|
.allowMainThreadQueries()
|
||||||
.build();
|
.build();
|
||||||
UnitUtils.setUnit(context);
|
UnitUtils.setUnit(context);
|
||||||
|
|||||||
@ -21,9 +21,11 @@ package de.tadris.fitness.activity;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
import android.location.LocationManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@ -50,10 +52,11 @@ import java.util.List;
|
|||||||
import de.tadris.fitness.Instance;
|
import de.tadris.fitness.Instance;
|
||||||
import de.tadris.fitness.R;
|
import de.tadris.fitness.R;
|
||||||
import de.tadris.fitness.data.Workout;
|
import de.tadris.fitness.data.Workout;
|
||||||
import de.tadris.fitness.location.LocationListener;
|
|
||||||
import de.tadris.fitness.location.WorkoutRecorder;
|
|
||||||
import de.tadris.fitness.map.MapManager;
|
import de.tadris.fitness.map.MapManager;
|
||||||
import de.tadris.fitness.map.tilesource.TileSources;
|
import de.tadris.fitness.map.tilesource.TileSources;
|
||||||
|
import de.tadris.fitness.recording.LocationListener;
|
||||||
|
import de.tadris.fitness.recording.PressureService;
|
||||||
|
import de.tadris.fitness.recording.WorkoutRecorder;
|
||||||
import de.tadris.fitness.util.ThemeManager;
|
import de.tadris.fitness.util.ThemeManager;
|
||||||
import de.tadris.fitness.util.unit.UnitUtils;
|
import de.tadris.fitness.util.unit.UnitUtils;
|
||||||
|
|
||||||
@ -72,6 +75,7 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
|
|||||||
private Handler mHandler= new Handler();
|
private Handler mHandler= new Handler();
|
||||||
PowerManager.WakeLock wakeLock;
|
PowerManager.WakeLock wakeLock;
|
||||||
Intent locationListener;
|
Intent locationListener;
|
||||||
|
Intent pressureService;
|
||||||
private boolean saved= false;
|
private boolean saved= false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -154,7 +158,10 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
|
|||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i= 0;
|
||||||
|
|
||||||
private void updateDescription(){
|
private void updateDescription(){
|
||||||
|
i++;
|
||||||
timeView.setText(UnitUtils.getHourMinuteSecondTime(recorder.getDuration()));
|
timeView.setText(UnitUtils.getHourMinuteSecondTime(recorder.getDuration()));
|
||||||
infoViews[0].setText(getString(R.string.workoutDistance), UnitUtils.getDistance(recorder.getDistance()));
|
infoViews[0].setText(getString(R.string.workoutDistance), UnitUtils.getDistance(recorder.getDistance()));
|
||||||
infoViews[1].setText(getString(R.string.workoutBurnedEnergy), recorder.getCalories() + " kcal");
|
infoViews[1].setText(getString(R.string.workoutBurnedEnergy), recorder.getCalories() + " kcal");
|
||||||
@ -228,19 +235,42 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
|
|||||||
|
|
||||||
public void stopListener(){
|
public void stopListener(){
|
||||||
stopService(locationListener);
|
stopService(locationListener);
|
||||||
|
stopService(pressureService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startListener(){
|
public void startListener(){
|
||||||
if(locationListener == null){
|
if(locationListener == null){
|
||||||
locationListener= new Intent(this, LocationListener.class);
|
locationListener= new Intent(this, LocationListener.class);
|
||||||
|
pressureService= new Intent(this, PressureService.class);
|
||||||
}else{
|
}else{
|
||||||
stopListener();
|
stopListener();
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
startForegroundService(locationListener);
|
startForegroundService(locationListener);
|
||||||
|
startService(pressureService);
|
||||||
}else{
|
}else{
|
||||||
startService(locationListener);
|
startService(locationListener);
|
||||||
|
startService(pressureService);
|
||||||
}
|
}
|
||||||
|
checkGpsStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkGpsStatus(){
|
||||||
|
final LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||||
|
|
||||||
|
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
|
||||||
|
openDialogNoGps();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openDialogNoGps(){
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.noGpsTitle)
|
||||||
|
.setMessage(R.string.noGpsMessage)
|
||||||
|
.setNegativeButton(R.string.cancel, (dialog, which) -> finish())
|
||||||
|
.setPositiveButton(R.string.enable, (dialog, which) -> startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)))
|
||||||
|
.setCancelable(false)
|
||||||
|
.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -325,9 +325,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||||
int id = item.getItemId();
|
int id = item.getItemId();
|
||||||
if (id == android.R.id.home) {
|
if (id == android.R.id.home) {
|
||||||
if (!super.onMenuItemSelected(featureId, item)) {
|
finish();
|
||||||
NavUtils.navigateUpFromSameTask(this);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return super.onMenuItemSelected(featureId, item);
|
return super.onMenuItemSelected(featureId, item);
|
||||||
|
|||||||
@ -131,6 +131,13 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
|||||||
addKeyValue(getString(R.string.workoutTotalEnergy), workout.calorie + " kcal",
|
addKeyValue(getString(R.string.workoutTotalEnergy), workout.calorie + " kcal",
|
||||||
getString(R.string.workoutEnergyConsumption), UnitUtils.getRelativeEnergyConsumption((double)workout.calorie / ((double)workout.length / 1000)));
|
getString(R.string.workoutEnergyConsumption), UnitUtils.getRelativeEnergyConsumption((double)workout.calorie / ((double)workout.length / 1000)));
|
||||||
|
|
||||||
|
addTitle(getString(R.string.height));
|
||||||
|
|
||||||
|
addKeyValue(getString(R.string.workoutAscent), UnitUtils.getDistance((int)workout.ascent),
|
||||||
|
getString(R.string.workoutDescent), UnitUtils.getDistance((int)workout.descent));
|
||||||
|
|
||||||
|
addHeightDiagram();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,20 +206,20 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
|||||||
root.addView(v);
|
root.addView(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSpeedDiagram(){
|
void addDiagram(SampleConverter converter){
|
||||||
LineChart chart= new LineChart(this);
|
LineChart chart= new LineChart(this);
|
||||||
|
|
||||||
WorkoutManager.roundSpeedValues(samples);
|
converter.onCreate();
|
||||||
|
|
||||||
List<Entry> entries = new ArrayList<>();
|
List<Entry> entries = new ArrayList<>();
|
||||||
for (WorkoutSample sample : samples) {
|
for (WorkoutSample sample : samples) {
|
||||||
// turn your data into Entry objects
|
// turn your data into Entry objects
|
||||||
Entry e= new Entry((float)(sample.relativeTime) / 1000f / 60f, (float)sample.tmpRoundedSpeed*3.6f);
|
Entry e= new Entry((float)(sample.relativeTime) / 1000f / 60f, converter.getValue(sample));
|
||||||
entries.add(e);
|
entries.add(e);
|
||||||
sample.tmpEntry= e;
|
converter.sampleGetsEntry(sample, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
LineDataSet dataSet = new LineDataSet(entries, "Speed"); // add entries to dataset // TODO: localisatoin
|
LineDataSet dataSet = new LineDataSet(entries, converter.getName()); // add entries to dataset
|
||||||
dataSet.setColor(getThemePrimaryColor());
|
dataSet.setColor(getThemePrimaryColor());
|
||||||
dataSet.setValueTextColor(getThemePrimaryColor());
|
dataSet.setValueTextColor(getThemePrimaryColor());
|
||||||
dataSet.setDrawCircles(false);
|
dataSet.setDrawCircles(false);
|
||||||
@ -220,11 +227,12 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
|||||||
dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
||||||
|
|
||||||
Description description= new Description();
|
Description description= new Description();
|
||||||
description.setText("min - km/h");
|
description.setText(converter.getDescription());
|
||||||
|
|
||||||
LineData lineData = new LineData(dataSet);
|
LineData lineData = new LineData(dataSet);
|
||||||
chart.setData(lineData);
|
chart.setData(lineData);
|
||||||
chart.setScaleEnabled(false);
|
chart.setScaleXEnabled(true);
|
||||||
|
chart.setScaleYEnabled(false);
|
||||||
chart.setDescription(description);
|
chart.setDescription(description);
|
||||||
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
|
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -232,7 +240,7 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
|||||||
onNothingSelected();
|
onNothingSelected();
|
||||||
Paint p= AndroidGraphicFactory.INSTANCE.createPaint();
|
Paint p= AndroidGraphicFactory.INSTANCE.createPaint();
|
||||||
p.setColor(Color.BLUE);
|
p.setColor(Color.BLUE);
|
||||||
highlightingCircle= new FixedPixelCircle(getSamplebyTime(e).toLatLong(), 10, p, null);
|
highlightingCircle= new FixedPixelCircle(findSample(converter, e).toLatLong(), 10, p, null);
|
||||||
map.addLayer(highlightingCircle);
|
map.addLayer(highlightingCircle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,9 +256,84 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
|||||||
root.addView(chart, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getWindowManager().getDefaultDisplay().getWidth()*3/4));
|
root.addView(chart, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getWindowManager().getDefaultDisplay().getWidth()*3/4));
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkoutSample getSamplebyTime(Entry entry){
|
interface SampleConverter{
|
||||||
|
void onCreate();
|
||||||
|
float getValue(WorkoutSample sample);
|
||||||
|
void sampleGetsEntry(WorkoutSample sample, Entry entry);
|
||||||
|
String getName();
|
||||||
|
String getDescription();
|
||||||
|
boolean compare(WorkoutSample sample, Entry entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addHeightDiagram(){
|
||||||
|
addDiagram(new SampleConverter() {
|
||||||
|
@Override
|
||||||
|
public void onCreate() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getValue(WorkoutSample sample) {
|
||||||
|
return (float)UnitUtils.CHOSEN_SYSTEM.getDistanceFromMeters(sample.elevation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sampleGetsEntry(WorkoutSample sample, Entry entry) {
|
||||||
|
sample.tmpHeightEntry= entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return getString(R.string.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "min - " + UnitUtils.CHOSEN_SYSTEM.getShortDistanceUnit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean compare(WorkoutSample sample, Entry entry) {
|
||||||
|
return sample.tmpHeightEntry.equalTo(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void addSpeedDiagram(){
|
||||||
|
addDiagram(new SampleConverter() {
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
WorkoutManager.roundSpeedValues(samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getValue(WorkoutSample sample) {
|
||||||
|
return (float)UnitUtils.CHOSEN_SYSTEM.getSpeedFromMeterPerSecond(sample.tmpRoundedSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sampleGetsEntry(WorkoutSample sample, Entry entry) {
|
||||||
|
sample.tmpSpeedEntry= entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return getString(R.string.workoutSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "min - " + UnitUtils.CHOSEN_SYSTEM.getSpeedUnit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean compare(WorkoutSample sample, Entry entry) {
|
||||||
|
return sample.tmpSpeedEntry.equalTo(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkoutSample findSample(SampleConverter converter, Entry entry){
|
||||||
for(WorkoutSample sample : samples){
|
for(WorkoutSample sample : samples){
|
||||||
if(sample.tmpEntry.equalTo(entry)){
|
if(converter.compare(sample, entry)){
|
||||||
return sample;
|
return sample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ package de.tadris.fitness.data;
|
|||||||
import androidx.room.Database;
|
import androidx.room.Database;
|
||||||
import androidx.room.RoomDatabase;
|
import androidx.room.RoomDatabase;
|
||||||
|
|
||||||
@Database(version = 1, entities = {Workout.class, WorkoutSample.class})
|
@Database(version = 2, entities = {Workout.class, WorkoutSample.class})
|
||||||
public abstract class AppDatabase extends RoomDatabase {
|
public abstract class AppDatabase extends RoomDatabase {
|
||||||
public abstract WorkoutDao workoutDao();
|
public abstract WorkoutDao workoutDao();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,10 +22,13 @@ package de.tadris.fitness.data;
|
|||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.PrimaryKey;
|
import androidx.room.PrimaryKey;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@Entity(tableName = "workout")
|
@Entity(tableName = "workout")
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class Workout{
|
public class Workout{
|
||||||
|
|
||||||
public static final String WORKOUT_TYPE_RUNNING= "running";
|
public static final String WORKOUT_TYPE_RUNNING= "running";
|
||||||
@ -66,6 +69,11 @@ public class Workout{
|
|||||||
|
|
||||||
public String workoutType;
|
public String workoutType;
|
||||||
|
|
||||||
|
|
||||||
|
public float ascent;
|
||||||
|
|
||||||
|
public float descent;
|
||||||
|
|
||||||
public int calorie;
|
public int calorie;
|
||||||
|
|
||||||
public String toString(){
|
public String toString(){
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
package de.tadris.fitness.data;
|
package de.tadris.fitness.data;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -61,10 +62,14 @@ public class WorkoutManager {
|
|||||||
// Setting workoutId in the samples
|
// Setting workoutId in the samples
|
||||||
int i= 0;
|
int i= 0;
|
||||||
double topSpeed= 0;
|
double topSpeed= 0;
|
||||||
|
double elevationSum= 0; // Sum of elevation
|
||||||
|
double pressureSum= 0; // Sum of elevation
|
||||||
for(WorkoutSample sample : samples){
|
for(WorkoutSample sample : samples){
|
||||||
i++;
|
i++;
|
||||||
sample.id= workout.id + i;
|
sample.id= workout.id + i;
|
||||||
sample.workoutId= workout.id;
|
sample.workoutId= workout.id;
|
||||||
|
elevationSum+= sample.elevation;
|
||||||
|
pressureSum+= sample.tmpPressure;
|
||||||
if(sample.speed > topSpeed){
|
if(sample.speed > topSpeed){
|
||||||
topSpeed= sample.speed;
|
topSpeed= sample.speed;
|
||||||
}
|
}
|
||||||
@ -72,6 +77,36 @@ public class WorkoutManager {
|
|||||||
|
|
||||||
workout.topSpeed= topSpeed;
|
workout.topSpeed= topSpeed;
|
||||||
|
|
||||||
|
// Calculating height data
|
||||||
|
boolean pressureDataAvailable= samples.get(0).tmpPressure != -1;
|
||||||
|
double avgElevation= elevationSum / samples.size();
|
||||||
|
double avgPressure= pressureSum / samples.size();
|
||||||
|
|
||||||
|
workout.ascent = 0;
|
||||||
|
workout.descent = 0;
|
||||||
|
|
||||||
|
for(i= 0; i < samples.size(); i++){
|
||||||
|
WorkoutSample sample= samples.get(i);
|
||||||
|
|
||||||
|
if(pressureDataAvailable){
|
||||||
|
// Altitude Difference to Average Elevation in meters
|
||||||
|
float altitude_difference =
|
||||||
|
SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, sample.tmpPressure) -
|
||||||
|
SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, (float) avgPressure);
|
||||||
|
sample.elevation= avgElevation + altitude_difference;
|
||||||
|
} // Else: use already set GPS elevation in WorkoutSample.elevation
|
||||||
|
|
||||||
|
if(i >= 1){
|
||||||
|
WorkoutSample lastSample= samples.get(i-1);
|
||||||
|
double diff= sample.elevation - lastSample.elevation;
|
||||||
|
if(diff > 0){
|
||||||
|
workout.ascent += diff;
|
||||||
|
}else{
|
||||||
|
workout.descent += Math.abs(diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Saving workout and samples
|
// Saving workout and samples
|
||||||
db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0]));
|
db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0]));
|
||||||
@ -91,4 +126,15 @@ public class WorkoutManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void calculateInclination(List<WorkoutSample> samples){
|
||||||
|
samples.get(0).tmpInclination= 0;
|
||||||
|
for(int i= 1; i < samples.size(); i++){
|
||||||
|
WorkoutSample sample= samples.get(i);
|
||||||
|
WorkoutSample lastSample= samples.get(i);
|
||||||
|
double elevationDifference= sample.elevation - sample.elevation;
|
||||||
|
double distance= sample.toLatLong().sphericalDistance(lastSample.toLatLong());
|
||||||
|
sample.tmpInclination= (float)(elevationDifference*100/distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import androidx.room.Ignore;
|
|||||||
import androidx.room.PrimaryKey;
|
import androidx.room.PrimaryKey;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.github.mikephil.charting.data.Entry;
|
import com.github.mikephil.charting.data.Entry;
|
||||||
|
|
||||||
import org.mapsforge.core.model.LatLong;
|
import org.mapsforge.core.model.LatLong;
|
||||||
@ -38,6 +39,7 @@ import static androidx.room.ForeignKey.CASCADE;
|
|||||||
parentColumns = "id",
|
parentColumns = "id",
|
||||||
childColumns = "workout_id",
|
childColumns = "workout_id",
|
||||||
onDelete = CASCADE))
|
onDelete = CASCADE))
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class WorkoutSample{
|
public class WorkoutSample{
|
||||||
|
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@ -56,18 +58,28 @@ public class WorkoutSample{
|
|||||||
|
|
||||||
public double elevation;
|
public double elevation;
|
||||||
|
|
||||||
public double relativeElevation;
|
|
||||||
|
|
||||||
public double speed;
|
public double speed;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@Ignore
|
@Ignore
|
||||||
public Entry tmpEntry;
|
public Entry tmpHeightEntry;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@Ignore
|
||||||
|
public Entry tmpSpeedEntry;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@Ignore
|
@Ignore
|
||||||
public double tmpRoundedSpeed;
|
public double tmpRoundedSpeed;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@Ignore
|
||||||
|
public float tmpPressure;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@Ignore
|
||||||
|
public float tmpInclination;
|
||||||
|
|
||||||
public LatLong toLatLong(){
|
public LatLong toLatLong(){
|
||||||
return new LatLong(lat, lon);
|
return new LatLong(lat, lon);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.tadris.fitness.location;
|
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
|
|
||||||
import org.mapsforge.core.graphics.Canvas;
|
|
||||||
import org.mapsforge.core.graphics.Paint;
|
|
||||||
import org.mapsforge.core.graphics.Style;
|
|
||||||
import org.mapsforge.core.model.BoundingBox;
|
|
||||||
import org.mapsforge.core.model.LatLong;
|
|
||||||
import org.mapsforge.core.model.Point;
|
|
||||||
import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
|
|
||||||
import org.mapsforge.map.layer.Layer;
|
|
||||||
import org.mapsforge.map.layer.overlay.Circle;
|
|
||||||
import org.mapsforge.map.layer.overlay.Marker;
|
|
||||||
|
|
||||||
public class MyLocationOverlay extends Layer {
|
|
||||||
|
|
||||||
private final Circle circle;
|
|
||||||
private final Marker marker;
|
|
||||||
private final LocationListener locationListener;
|
|
||||||
|
|
||||||
private static Paint getDefaultFixedPixelCircleFill() {
|
|
||||||
return getPaint(AndroidGraphicFactory.INSTANCE.createColor(255, 0, 0, 255), 0, Style.FILL);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Paint getDefaultOuterFixedPixelCircleFill(){
|
|
||||||
return getPaint(AndroidGraphicFactory.INSTANCE.createColor(30, 30, 30, 255), 0, Style.FILL);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Paint getDefaultFixedPixelCircleStroke() {
|
|
||||||
return getPaint(AndroidGraphicFactory.INSTANCE.createColor(255, 255, 255, 255), 7, Style.STROKE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Paint getPaint(int color, int strokeWidth, Style style) {
|
|
||||||
Paint paint = AndroidGraphicFactory.INSTANCE.createPaint();
|
|
||||||
paint.setColor(color);
|
|
||||||
paint.setStrokeWidth(strokeWidth);
|
|
||||||
paint.setStyle(style);
|
|
||||||
return paint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MyLocationOverlay(LocationListener locationListener, Drawable icon) {
|
|
||||||
this.locationListener= locationListener;
|
|
||||||
this.circle= new Circle(null, 0f, getDefaultFixedPixelCircleFill(), null);
|
|
||||||
this.marker= new Marker(null, AndroidGraphicFactory.convertToBitmap(icon), 26, 26);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void draw(BoundingBox boundingBox, byte zoomLevel, Canvas canvas, Point topLeftPoint) {
|
|
||||||
if (this.circle != null) {
|
|
||||||
this.circle.draw(boundingBox, zoomLevel, canvas, topLeftPoint);
|
|
||||||
}
|
|
||||||
this.marker.draw(boundingBox, zoomLevel, canvas, topLeftPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onAdd() {
|
|
||||||
this.circle.setDisplayModel(this.displayModel);
|
|
||||||
this.marker.setDisplayModel(this.displayModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
this.marker.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPosition(double latitude, double longitude, float accuracy) {
|
|
||||||
synchronized (this) {
|
|
||||||
LatLong latLong = new LatLong(latitude, longitude);
|
|
||||||
this.marker.setLatLong(latLong);
|
|
||||||
if (this.circle != null) {
|
|
||||||
this.circle.setLatLong(latLong);
|
|
||||||
this.circle.setRadius(accuracy);
|
|
||||||
}
|
|
||||||
requestRedraw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.tadris.fitness.location;
|
package de.tadris.fitness.recording;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.tadris.fitness.recording;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEvent;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import de.tadris.fitness.Instance;
|
||||||
|
|
||||||
|
public class PressureService extends Service {
|
||||||
|
|
||||||
|
private static final String TAG = "PressureService";
|
||||||
|
|
||||||
|
private SensorManager sensorManager;
|
||||||
|
private Instance instance;
|
||||||
|
private Sensor pressureSensor;
|
||||||
|
private PressureListener pressureListener;
|
||||||
|
|
||||||
|
private class PressureListener implements SensorEventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSensorChanged(SensorEvent event) {
|
||||||
|
instance.lastPressure= event.values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
Log.d(TAG, "onCreate");
|
||||||
|
super.onCreate();
|
||||||
|
instance= Instance.getInstance(this);
|
||||||
|
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
|
||||||
|
|
||||||
|
pressureSensor= sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
|
||||||
|
|
||||||
|
pressureListener= new PressureListener();
|
||||||
|
|
||||||
|
if (pressureSensor != null){
|
||||||
|
instance.pressureAvailable= true;
|
||||||
|
sensorManager.registerListener(pressureListener, pressureSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||||
|
} else {
|
||||||
|
instance.pressureAvailable= false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
Log.d(TAG, "onStartCommand");
|
||||||
|
return super.onStartCommand(intent, flags, startId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
Log.d(TAG, "onDestroy");
|
||||||
|
super.onDestroy();
|
||||||
|
sensorManager.unregisterListener(pressureListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable @Override public IBinder onBind(Intent intent) { return null; }
|
||||||
|
}
|
||||||
@ -17,7 +17,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.tadris.fitness.location;
|
package de.tadris.fitness.recording;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@ -224,10 +224,14 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
|||||||
sample.lat= location.getLatitude();
|
sample.lat= location.getLatitude();
|
||||||
sample.lon= location.getLongitude();
|
sample.lon= location.getLongitude();
|
||||||
sample.elevation= location.getAltitude();
|
sample.elevation= location.getAltitude();
|
||||||
sample.relativeElevation= 0.0;
|
|
||||||
sample.speed= location.getSpeed();
|
sample.speed= location.getSpeed();
|
||||||
sample.relativeTime= location.getTime() - workout.start - pauseTime;
|
sample.relativeTime= location.getTime() - workout.start - pauseTime;
|
||||||
sample.absoluteTime= location.getTime();
|
sample.absoluteTime= location.getTime();
|
||||||
|
if(Instance.getInstance(context).pressureAvailable){
|
||||||
|
sample.tmpPressure= Instance.getInstance(context).lastPressure;
|
||||||
|
}else{
|
||||||
|
sample.tmpPressure= -1;
|
||||||
|
}
|
||||||
synchronized (samples){
|
synchronized (samples){
|
||||||
samples.add(sample);
|
samples.add(sample);
|
||||||
}
|
}
|
||||||
@ -282,6 +286,10 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
|||||||
workout.comment= comment;
|
workout.comment= comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPaused(){
|
||||||
|
return state == RecordingState.PAUSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum RecordingState{
|
enum RecordingState{
|
||||||
IDLE, RUNNING, PAUSED, STOPPED
|
IDLE, RUNNING, PAUSED, STOPPED
|
||||||
@ -48,14 +48,10 @@ public class CalorieCalculator {
|
|||||||
*/
|
*/
|
||||||
public static double getMET(Workout workout){
|
public static double getMET(Workout workout){
|
||||||
double speedInKmh= workout.avgSpeed * 3.6;
|
double speedInKmh= workout.avgSpeed * 3.6;
|
||||||
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_RUNNING)){
|
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_RUNNING) || workout.workoutType.equals(Workout.WORKOUT_TYPE_HIKING)){
|
||||||
// This is a linear graph based on the website linked above
|
// This is a linear graph based on the website linked above
|
||||||
return Math.max(1.5, speedInKmh*1.117 - 2.1906);
|
return Math.max(1.5, speedInKmh*1.117 - 2.1906);
|
||||||
}
|
}
|
||||||
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_HIKING)){
|
|
||||||
// Use fixed MET because no more precise calculation was found
|
|
||||||
return 6.0;
|
|
||||||
}
|
|
||||||
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_CYCLING)){
|
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_CYCLING)){
|
||||||
// This is a linear graph based on the website linked above
|
// This is a linear graph based on the website linked above
|
||||||
return Math.max(3, (speedInKmh-10) / 1.5);
|
return Math.max(3, (speedInKmh-10) / 1.5);
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import android.content.Context;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -78,6 +79,7 @@ public class Exporter {
|
|||||||
public static void importData(Context context, Uri input, ExportStatusListener listener) throws IOException{
|
public static void importData(Context context, Uri input, ExportStatusListener listener) throws IOException{
|
||||||
listener.onStatusChanged(0, context.getString(R.string.loadingFile));
|
listener.onStatusChanged(0, context.getString(R.string.loadingFile));
|
||||||
XmlMapper xmlMapper = new XmlMapper();
|
XmlMapper xmlMapper = new XmlMapper();
|
||||||
|
xmlMapper.configure(JsonParser.Feature.IGNORE_UNDEFINED, true);
|
||||||
FitoTrackDataContainer container = xmlMapper.readValue(context.getContentResolver().openInputStream(input), FitoTrackDataContainer.class);
|
FitoTrackDataContainer container = xmlMapper.readValue(context.getContentResolver().openInputStream(input), FitoTrackDataContainer.class);
|
||||||
|
|
||||||
if(container.version != 1){
|
if(container.version != 1){
|
||||||
@ -89,6 +91,7 @@ public class Exporter {
|
|||||||
.edit().clear()
|
.edit().clear()
|
||||||
.putInt("weight", container.settings.weight)
|
.putInt("weight", container.settings.weight)
|
||||||
.putString("unitSystem", container.settings.preferredUnitSystem)
|
.putString("unitSystem", container.settings.preferredUnitSystem)
|
||||||
|
.putBoolean("firstStart", false)
|
||||||
.commit();
|
.commit();
|
||||||
|
|
||||||
AppDatabase database= Instance.getInstance(context).db;
|
AppDatabase database= Instance.getInstance(context).db;
|
||||||
|
|||||||
@ -1,5 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package de.tadris.fitness.util.export;
|
package de.tadris.fitness.util.export;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -8,6 +28,7 @@ import de.tadris.fitness.data.Workout;
|
|||||||
import de.tadris.fitness.data.WorkoutSample;
|
import de.tadris.fitness.data.WorkoutSample;
|
||||||
|
|
||||||
@JacksonXmlRootElement(localName = "fito-track")
|
@JacksonXmlRootElement(localName = "fito-track")
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class FitoTrackDataContainer {
|
public class FitoTrackDataContainer {
|
||||||
|
|
||||||
int version;
|
int version;
|
||||||
|
|||||||
@ -11,13 +11,9 @@ public class ImperialWithMeters extends Imperial {
|
|||||||
public double getDistanceFromMeters(double meters) {
|
public double getDistanceFromMeters(double meters) {
|
||||||
return meters;
|
return meters;
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
public String getLongDistanceUnit() {
|
|
||||||
return "m";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getShortDistanceUnit() {
|
public String getShortDistanceUnit() {
|
||||||
return "yd";
|
return "m";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
<string name="errorImportFailed">Der Datenimport ist fehlgeschlagen.</string>
|
<string name="errorImportFailed">Der Datenimport ist fehlgeschlagen.</string>
|
||||||
<string name="exportAsGpxFile">Als GPX-Datei exportieren</string>
|
<string name="exportAsGpxFile">Als GPX-Datei exportieren</string>
|
||||||
<string name="exportData">Daten exportieren</string>
|
<string name="exportData">Daten exportieren</string>
|
||||||
<string name="exportDataSummary">"Es wird ein Backup von all deinen Einstallungen und "</string>
|
<string name="exportDataSummary">Erstellt ein Backup von all deinen Einstellungen und deiner Workoutdaten</string>
|
||||||
<string name="exporting">Exportieren</string>
|
<string name="exporting">Exportieren</string>
|
||||||
<string name="finished">Fertig</string>
|
<string name="finished">Fertig</string>
|
||||||
<string name="gps">GPS</string>
|
<string name="gps">GPS</string>
|
||||||
@ -88,4 +88,10 @@
|
|||||||
<string name="workoutTypeWalking">Gehen</string>
|
<string name="workoutTypeWalking">Gehen</string>
|
||||||
<string name="workout_add">Hinzufügen</string>
|
<string name="workout_add">Hinzufügen</string>
|
||||||
<string name="workouts">Workouts</string>
|
<string name="workouts">Workouts</string>
|
||||||
|
<string name="enable">Aktivieren</string>
|
||||||
|
<string name="height">Höhe</string>
|
||||||
|
<string name="noGpsTitle">GPS deaktiviert</string>
|
||||||
|
<string name="noGpsMessage">Bitte aktiviere GPS, damit dein Workout aufgezeichnet werden kann.</string>
|
||||||
|
<string name="workoutAscent">Aufstieg</string>
|
||||||
|
<string name="workoutDescent">Abstieg</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -63,6 +63,12 @@
|
|||||||
<string name="workoutTotalEnergy">Total Energy</string>
|
<string name="workoutTotalEnergy">Total Energy</string>
|
||||||
<string name="workoutEnergyConsumption">Energy Consumption</string>
|
<string name="workoutEnergyConsumption">Energy Consumption</string>
|
||||||
|
|
||||||
|
<string name="workoutAscent">Ascent</string>
|
||||||
|
<string name="workoutDescent">Descent</string>
|
||||||
|
|
||||||
|
<string name="height">Height</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="workoutTypeRunning">Running</string>
|
<string name="workoutTypeRunning">Running</string>
|
||||||
<string name="workoutTypeWalking">Walking</string>
|
<string name="workoutTypeWalking">Walking</string>
|
||||||
<string name="workoutTypeJogging">Jogging</string>
|
<string name="workoutTypeJogging">Jogging</string>
|
||||||
@ -72,6 +78,10 @@
|
|||||||
|
|
||||||
<string name="recordWorkout">Record Workout</string>
|
<string name="recordWorkout">Record Workout</string>
|
||||||
|
|
||||||
|
<string name="noGpsTitle">GPS disabled</string>
|
||||||
|
<string name="noGpsMessage">Please enable GPS for tracking your workout.</string>
|
||||||
|
<string name="enable">Enable</string>
|
||||||
|
|
||||||
<string name="comment">Comment</string>
|
<string name="comment">Comment</string>
|
||||||
<string name="enterComment">Enter Comment</string>
|
<string name="enterComment">Enter Comment</string>
|
||||||
<string name="okay">Okay</string>
|
<string name="okay">Okay</string>
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package de.tadris.fitness;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import de.tadris.fitness.data.Workout;
|
||||||
|
import de.tadris.fitness.util.CalorieCalculator;
|
||||||
|
|
||||||
|
public class CalorieCalculatorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCalculation(){
|
||||||
|
Workout workout= new Workout();
|
||||||
|
workout.avgSpeed= 2.7d;
|
||||||
|
workout.workoutType= Workout.WORKOUT_TYPE_RUNNING;
|
||||||
|
workout.duration= 1000L * 60 * 10;
|
||||||
|
int calorie= CalorieCalculator.calculateCalories(workout, 80);
|
||||||
|
System.out.println("Calories: " + calorie);
|
||||||
|
Assert.assertEquals(120, calorie, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.tadris.fitness;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
public class ExampleUnitTest {
|
|
||||||
@Test
|
|
||||||
public void addition_isCorrect() {
|
|
||||||
assertEquals(4, 2 + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
8
metadata/en-US/changelogs/110.txt
Normal file
8
metadata/en-US/changelogs/110.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
New:
|
||||||
|
- Height measurement via GPS and pressure sensor
|
||||||
|
- Show height diagram
|
||||||
|
- Show dialog if GPS is disabled
|
||||||
|
|
||||||
|
Fix:
|
||||||
|
- Back-Button in Settings crashes on earlier Android versions (#20)
|
||||||
|
- Fix Unit system "Imperial with meters"
|
||||||
Loading…
x
Reference in New Issue
Block a user