diff --git a/app/build.gradle b/app/build.gradle
index 62da33b..86b19a8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -63,4 +63,5 @@ dependencies {
implementation 'androidx.recyclerview:recyclerview:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1a01d55..81062b7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -32,9 +32,10 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
-
-
-
+
+
+
+
diff --git a/app/src/main/java/de/tadris/fitness/Instance.java b/app/src/main/java/de/tadris/fitness/Instance.java
index 5b3e6b7..25c8edd 100644
--- a/app/src/main/java/de/tadris/fitness/Instance.java
+++ b/app/src/main/java/de/tadris/fitness/Instance.java
@@ -21,7 +21,10 @@ package de.tadris.fitness;
import android.content.Context;
+import androidx.annotation.NonNull;
import androidx.room.Room;
+import androidx.room.migration.Migration;
+import androidx.sqlite.db.SupportSQLiteDatabase;
import de.tadris.fitness.data.AppDatabase;
import de.tadris.fitness.location.LocationListener;
@@ -45,6 +48,12 @@ public class Instance {
private Instance(Context context) {
db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
.allowMainThreadQueries()
+ .addMigrations(new Migration(2, 3) {
+ @Override
+ public void migrate(@NonNull SupportSQLiteDatabase database) {
+ database.execSQL("ALTER TABLE workout add topSpeed DOUBLE not null default 0.0");
+ }
+ })
.build();
locationListener= new LocationListener(context);
}
diff --git a/app/src/main/java/de/tadris/fitness/WorkoutAdapter.java b/app/src/main/java/de/tadris/fitness/WorkoutAdapter.java
index e1fc4df..0d96d45 100644
--- a/app/src/main/java/de/tadris/fitness/WorkoutAdapter.java
+++ b/app/src/main/java/de/tadris/fitness/WorkoutAdapter.java
@@ -65,7 +65,7 @@ public class WorkoutAdapter extends RecyclerView.Adapter.
*/
-package de.tadris.fitness;
+package de.tadris.fitness.activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
+import de.tadris.fitness.R;
+
public class LauncherActivity extends Activity {
@Override
diff --git a/app/src/main/java/de/tadris/fitness/ListWorkoutsActivity.java b/app/src/main/java/de/tadris/fitness/activity/ListWorkoutsActivity.java
similarity index 90%
rename from app/src/main/java/de/tadris/fitness/ListWorkoutsActivity.java
rename to app/src/main/java/de/tadris/fitness/activity/ListWorkoutsActivity.java
index 3e7c892..dd39942 100644
--- a/app/src/main/java/de/tadris/fitness/ListWorkoutsActivity.java
+++ b/app/src/main/java/de/tadris/fitness/activity/ListWorkoutsActivity.java
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-package de.tadris.fitness;
+package de.tadris.fitness.activity;
import android.app.Activity;
import android.content.Intent;
@@ -28,6 +28,9 @@ import android.view.MenuItem;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import de.tadris.fitness.Instance;
+import de.tadris.fitness.R;
+import de.tadris.fitness.WorkoutAdapter;
import de.tadris.fitness.data.Workout;
public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.WorkoutAdapterListener {
@@ -62,7 +65,8 @@ public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.Wor
@Override
public void onItemClick(Workout workout) {
- // TODO: open detail View
+ ShowWorkoutActivity.selectedWorkout= workout;
+ startActivity(new Intent(this, ShowWorkoutActivity.class));
}
@Override
diff --git a/app/src/main/java/de/tadris/fitness/RecordWorkoutActivity.java b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java
similarity index 75%
rename from app/src/main/java/de/tadris/fitness/RecordWorkoutActivity.java
rename to app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java
index 147e0e7..7e4cd49 100644
--- a/app/src/main/java/de/tadris/fitness/RecordWorkoutActivity.java
+++ b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-package de.tadris.fitness;
+package de.tadris.fitness.activity;
import android.Manifest;
import android.app.Activity;
@@ -30,23 +30,20 @@ import android.view.ViewGroup;
import androidx.core.app.ActivityCompat;
-import org.mapsforge.core.model.LatLong;
import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
-import org.mapsforge.map.android.util.AndroidUtil;
import org.mapsforge.map.android.view.MapView;
-import org.mapsforge.map.layer.cache.TileCache;
import org.mapsforge.map.layer.download.TileDownloadLayer;
+import de.tadris.fitness.Instance;
+import de.tadris.fitness.R;
import de.tadris.fitness.data.Workout;
import de.tadris.fitness.location.LocationListener;
-import de.tadris.fitness.location.MyLocationOverlay;
import de.tadris.fitness.location.WorkoutRecorder;
-import de.tadris.fitness.map.HumanitarianTileSource;
+import de.tadris.fitness.map.MapManager;
public class RecordWorkoutActivity extends Activity implements LocationListener.LocationChangeListener {
MapView mapView;
- MyLocationOverlay locationOverlay;
TileDownloadLayer downloadLayer;
WorkoutRecorder recorder;
@@ -57,24 +54,7 @@ public class RecordWorkoutActivity extends Activity implements LocationListener.
this.mapView= new MapView(this);
- mapView.setZoomLevelMin((byte) 18);
- mapView.setZoomLevelMax((byte) 18);
- mapView.setBuiltInZoomControls(false);
-
- TileCache tileCache = AndroidUtil.createTileCache(this, "mapcache", mapView.getModel().displayModel.getTileSize(), 1f, this.mapView.getModel().frameBufferModel.getOverdrawFactor(), true);
-
- HumanitarianTileSource tileSource = HumanitarianTileSource.INSTANCE;
- tileSource.setUserAgent("mapsforge-android");
- downloadLayer = new TileDownloadLayer(tileCache, mapView.getModel().mapViewPosition, tileSource, AndroidGraphicFactory.INSTANCE);
-
- mapView.getLayerManager().getLayers().add(downloadLayer);
-
- locationOverlay= new MyLocationOverlay(Instance.getInstance(this).locationListener, getDrawable(R.drawable.location_marker));
-
- mapView.getLayerManager().redrawLayers();
-
- mapView.setZoomLevel((byte) 18);
- mapView.setCenter(new LatLong(52, 13));
+ downloadLayer= MapManager.setupMap(mapView);
((ViewGroup)findViewById(R.id.recordMapViewrRoot)).addView(mapView);
@@ -113,7 +93,6 @@ public class RecordWorkoutActivity extends Activity implements LocationListener.
@Override
public void onLocationChange(Location location) {
mapView.getModel().mapViewPosition.animateTo(LocationListener.locationToLatLong(location));
- locationOverlay.setPosition(location.getLatitude(), location.getLongitude(), location.getAccuracy());
}
@Override
diff --git a/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java b/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java
new file mode 100644
index 0000000..d121a47
--- /dev/null
+++ b/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java
@@ -0,0 +1,228 @@
+/*
+ * 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.activity;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.TypedValue;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.mapsforge.core.model.BoundingBox;
+import org.mapsforge.core.model.MapPosition;
+import org.mapsforge.core.util.LatLongUtils;
+import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
+import org.mapsforge.map.android.view.MapView;
+import org.mapsforge.map.layer.download.TileDownloadLayer;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import de.tadris.fitness.Instance;
+import de.tadris.fitness.R;
+import de.tadris.fitness.data.Workout;
+import de.tadris.fitness.data.WorkoutSample;
+import de.tadris.fitness.map.MapManager;
+import de.tadris.fitness.map.WorkoutLayer;
+import de.tadris.fitness.util.ThemeManager;
+import de.tadris.fitness.util.UnitUtils;
+
+public class ShowWorkoutActivity extends Activity {
+ static Workout selectedWorkout;
+
+ List samples;
+ Workout workout;
+ ViewGroup root;
+ Resources.Theme theme;
+ MapView map;
+ TileDownloadLayer downloadLayer;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ workout= selectedWorkout;
+ samples= Arrays.asList(Instance.getInstance(this).db.workoutDao().getAllSamplesOfWorkout(workout.id));
+ setTheme(ThemeManager.getThemeByWorkout(workout, this));
+ setContentView(R.layout.activity_show_workout);
+
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+
+ theme= getTheme();
+
+ root= findViewById(R.id.showWorkoutRoot);
+
+ addTitle("Zeit");
+ addKeyValue("Datum", getDate(), "Dauer", UnitUtils.getHourMinuteTime(workout.getDuration()));
+ addKeyValue("Startzeit", SimpleDateFormat.getTimeInstance().format(new Date(workout.start)),
+ "Endzeit", SimpleDateFormat.getTimeInstance().format(new Date(workout.end)));
+
+ addKeyValue("Distanz", UnitUtils.getDistance(workout.length), "Pace", UnitUtils.round(workout.avgPace, 1) + " min/km");
+
+ addTitle("Geschwindigkeit");
+
+ addKeyValue("Durchschnittsgeschw.", UnitUtils.getSpeed(workout.avgSpeed),
+ "Top Geschw.", UnitUtils.round(workout.topSpeed, 1) + " km/h");
+
+ // TODO: add speed diagram
+
+ addTitle("Verbrauchte Energie");
+ addKeyValue("Gesamtverbrauch", workout.calorie + " kcal",
+ "Relativverbrauch", UnitUtils.round(((double)workout.calorie / workout.length / 1000), 2) + " kcal/km");
+
+ addTitle("Route");
+
+ addMap();
+
+ }
+
+ String getDate(){
+ return SimpleDateFormat.getDateInstance().format(new Date(workout.start));
+ }
+
+
+ void addTitle(String title){
+ TextView textView= new TextView(this);
+ textView.setText(title);
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
+ textView.setTextColor(getThemePrimaryColor());
+ textView.setTypeface(Typeface.DEFAULT_BOLD);
+ textView.setAllCaps(true);
+
+ root.addView(textView);
+ }
+
+ void addKeyValue(String key1, String value1){
+ addKeyValue(key1, value1, "", "");
+ }
+
+ void addKeyValue(String key1, String value1, String key2, String value2){
+ View v= getLayoutInflater().inflate(R.layout.show_entry, root, false);
+
+ TextView title1= v.findViewById(R.id.v1title);
+ TextView title2= v.findViewById(R.id.v2title);
+ TextView v1= v.findViewById(R.id.v1value);
+ TextView v2= v.findViewById(R.id.v2value);
+
+ title1.setText(key1);
+ title2.setText(key2);
+ v1.setText(value1);
+ v2.setText(value2);
+
+ root.addView(v);
+ }
+
+ void addDiagram(){
+
+ }
+
+ void addMap(){
+ map= new MapView(this);
+ downloadLayer= MapManager.setupMap(map);
+ map.setZoomLevelMin((byte)2);
+ map.setZoomLevelMax((byte)18);
+
+ WorkoutLayer workoutLayer= new WorkoutLayer(samples, getThemePrimaryColor());
+ map.addLayer(workoutLayer);
+
+ final BoundingBox bounds= new BoundingBox(workoutLayer.getLatLongs()).extendMeters(50);
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ map.getModel().mapViewPosition.setMapPosition(new MapPosition(bounds.getCenterPoint(),
+ (byte)(LatLongUtils.zoomForBounds(map.getDimension(), bounds, map.getModel().displayModel.getTileSize()))));
+ map.animate().alpha(1f).setDuration(1000).start();
+ }
+ }, 1000);
+
+ map.getModel().mapViewPosition.setMapLimit(bounds);
+
+
+ root.addView(map, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getWindowManager().getDefaultDisplay().getWidth()*3/4));
+ map.setAlpha(0);
+ }
+
+ private int getThemePrimaryColor() {
+ final TypedValue value = new TypedValue ();
+ getTheme().resolveAttribute (android.R.attr.colorPrimary, value, true);
+ return value.data;
+ }
+
+ @Override
+ protected void onDestroy() {
+ map.destroyAll();
+ AndroidGraphicFactory.clearResourceMemoryCache();
+ super.onDestroy();
+ }
+
+ @Override
+ public void onPause(){
+ super.onPause();
+ downloadLayer.onPause();
+ }
+
+ public void onResume(){
+ super.onResume();
+ downloadLayer.onResume();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.show_workout_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+ if(id == R.id.actionDeleteWorkout){
+ // TODO: delete workout
+ return true;
+ }else if(id == android.R.id.home){
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /*private int zoomToBounds(BoundingBox boundingBox) {
+ int TILE_SIZE= map.getModel().displayModel.getTileSize();
+ Dimension mapViewDimension = map.getModel().mapViewDimension.getDimension();
+ if(mapViewDimension == null)
+ return 0;
+ double dxMax = longitudeToPixelX(boundingBox.maxLongitude, (byte) 0) / TILE_SIZE;
+ double dxMin = longitudeToPixelX(boundingBox.minLongitude, (byte) 0) / TILE_SIZE;
+ double zoomX = floor(-log(3.8) * log(abs(dxMax-dxMin)) + mapViewDimension.width / TILE_SIZE);
+ double dyMax = latitudeToPixelY(boundingBox.maxLatitude, (byte) 0) / TILE_SIZE;
+ double dyMin = latitudeToPixelY(boundingBox.minLatitude, (byte) 0) / TILE_SIZE;
+ double zoomY = floor(-log(3.8) * log(abs(dyMax-dyMin)) + mapViewDimension.height / TILE_SIZE);
+ return Double.valueOf(min(zoomX, zoomY)).intValue();
+ }*/
+
+}
diff --git a/app/src/main/java/de/tadris/fitness/data/AppDatabase.java b/app/src/main/java/de/tadris/fitness/data/AppDatabase.java
index cd1fc75..e1ce9ed 100644
--- a/app/src/main/java/de/tadris/fitness/data/AppDatabase.java
+++ b/app/src/main/java/de/tadris/fitness/data/AppDatabase.java
@@ -22,7 +22,7 @@ package de.tadris.fitness.data;
import androidx.room.Database;
import androidx.room.RoomDatabase;
-@Database(version = 1, entities = {Workout.class, WorkoutSample.class})
+@Database(version = 3, entities = {Workout.class, WorkoutSample.class})
public abstract class AppDatabase extends RoomDatabase {
public abstract WorkoutDao workoutDao();
}
diff --git a/app/src/main/java/de/tadris/fitness/data/Workout.java b/app/src/main/java/de/tadris/fitness/data/Workout.java
index d553397..4c87a23 100644
--- a/app/src/main/java/de/tadris/fitness/data/Workout.java
+++ b/app/src/main/java/de/tadris/fitness/data/Workout.java
@@ -26,6 +26,8 @@ import androidx.room.PrimaryKey;
public class Workout{
public static final String WORKOUT_TYPE_RUNNING= "running";
+ public static final String WORKOUT_TYPE_WALKING= "running";
+ public static final String WORKOUT_TYPE_HIKING= "hiking";
public static final String WORKOUT_TYPE_CYCLING= "cycling";
@PrimaryKey
@@ -44,6 +46,11 @@ public class Workout{
*/
public double avgSpeed;
+ /**
+ * Top speed in m/s
+ */
+ public double topSpeed;
+
/**
* Average pace of workout in km/min
*/
@@ -51,11 +58,9 @@ public class Workout{
public String workoutType;
- /**
- * Gets time of workout
- * @return time in milliseconds
- */
- public long getTime(){
+ public int calorie;
+
+ public long getDuration(){
return end - start;
}
diff --git a/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java b/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java
index 7ae63f6..1f1e83f 100644
--- a/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java
+++ b/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java
@@ -19,13 +19,19 @@
package de.tadris.fitness.data;
+import android.content.Context;
+
import java.util.List;
import de.tadris.fitness.Instance;
+import de.tadris.fitness.util.CalorieCalculator;
public class WorkoutManager {
- public static void insertWorkout(Instance instance, Workout workout, List samples){
+ public static void insertWorkout(Context context, Workout workout, List samples){
+ AppDatabase db= Instance.getInstance(context).db;
+
+
workout.id= System.currentTimeMillis();
// Calculating values
@@ -34,19 +40,28 @@ public class WorkoutManager {
length+= samples.get(i - 1).toLatLong().sphericalDistance(samples.get(i).toLatLong());
}
workout.length= (int)length;
- workout.avgSpeed= ((double) workout.length / 1000) / ((double) workout.getTime() / 1000);
- workout.avgPace= (double)(workout.getTime() / 1000 / 60) / ((double) workout.length / 1000);
+ workout.avgSpeed= ((double) workout.length) / ((double) workout.getDuration() / 1000);
+ workout.avgPace= (double)(workout.getDuration() / 1000 / 60) / ((double) workout.length / 1000);
+ workout.calorie= CalorieCalculator.calculateCalories(workout, 80);
+ // TODO: use user weight
// Setting workoutId in the samples
int i= 0;
+ double topSpeed= 0;
for(WorkoutSample sample : samples){
i++;
sample.id= workout.id + i;
sample.workoutId= workout.id;
+ if(sample.speed > topSpeed){
+ topSpeed= sample.speed;
+ }
}
+ workout.topSpeed= topSpeed;
+
+
// Saving workout and samples
- instance.db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0]));
+ db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0]));
}
diff --git a/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java b/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java
index 23de5a9..8822822 100644
--- a/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java
+++ b/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java
@@ -88,7 +88,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
if(state != RecordingState.STOPPED){
throw new IllegalStateException("Cannot save recording, recorder was not stopped. state = " + state);
}
- WorkoutManager.insertWorkout(Instance.getInstance(context), workout, samples);
+ WorkoutManager.insertWorkout(context, workout, samples);
}
public int getSampleCount(){
diff --git a/app/src/main/java/de/tadris/fitness/map/MapManager.java b/app/src/main/java/de/tadris/fitness/map/MapManager.java
new file mode 100644
index 0000000..367e8da
--- /dev/null
+++ b/app/src/main/java/de/tadris/fitness/map/MapManager.java
@@ -0,0 +1,54 @@
+/*
+ * 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.map;
+
+import org.mapsforge.core.model.LatLong;
+import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
+import org.mapsforge.map.android.util.AndroidUtil;
+import org.mapsforge.map.android.view.MapView;
+import org.mapsforge.map.layer.cache.TileCache;
+import org.mapsforge.map.layer.download.TileDownloadLayer;
+
+public class MapManager {
+
+ public static TileDownloadLayer setupMap(MapView mapView){
+ mapView.setZoomLevelMin((byte) 18);
+ mapView.setZoomLevelMax((byte) 18);
+ mapView.setBuiltInZoomControls(false);
+
+ TileCache tileCache = AndroidUtil.createTileCache(mapView.getContext(), "mapcache",
+ mapView.getModel().displayModel.getTileSize(), 1f,
+ mapView.getModel().frameBufferModel.getOverdrawFactor(), true);
+
+ HumanitarianTileSource tileSource = HumanitarianTileSource.INSTANCE;
+ tileSource.setUserAgent("mapsforge-android");
+ TileDownloadLayer downloadLayer = new TileDownloadLayer(tileCache, mapView.getModel().mapViewPosition, tileSource, AndroidGraphicFactory.INSTANCE);
+
+ mapView.getLayerManager().getLayers().add(downloadLayer);
+
+ 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/WorkoutLayer.java b/app/src/main/java/de/tadris/fitness/map/WorkoutLayer.java
new file mode 100644
index 0000000..8afa936
--- /dev/null
+++ b/app/src/main/java/de/tadris/fitness/map/WorkoutLayer.java
@@ -0,0 +1,58 @@
+/*
+ * 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.map;
+
+import org.mapsforge.core.graphics.Paint;
+import org.mapsforge.core.graphics.Style;
+import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
+import org.mapsforge.map.layer.overlay.Polyline;
+
+import java.util.List;
+
+import de.tadris.fitness.data.WorkoutSample;
+
+public class WorkoutLayer extends Polyline {
+
+ public static Paint getDEFAULT_PAINT_STROKE(int color){
+ Paint paint= AndroidGraphicFactory.INSTANCE.createPaint();
+ paint.setStyle(Style.STROKE);
+ paint.setColor(color);
+ paint.setStrokeWidth(14f);
+ return paint;
+ }
+
+ List samples;
+
+ public WorkoutLayer(List samples, int color) {
+ this(getDEFAULT_PAINT_STROKE(color), samples);
+ }
+
+ public WorkoutLayer(Paint paintStroke, List samples) {
+ super(paintStroke, AndroidGraphicFactory.INSTANCE);
+ this.samples = samples;
+ init();
+ }
+
+ private void init(){
+ for(WorkoutSample sample : samples){
+ addPoint(sample.toLatLong());
+ }
+ }
+}
diff --git a/app/src/main/java/de/tadris/fitness/util/CalorieCalculator.java b/app/src/main/java/de/tadris/fitness/util/CalorieCalculator.java
new file mode 100644
index 0000000..5f50d92
--- /dev/null
+++ b/app/src/main/java/de/tadris/fitness/util/CalorieCalculator.java
@@ -0,0 +1,74 @@
+/*
+ * 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.util;
+
+import de.tadris.fitness.data.Workout;
+
+public class CalorieCalculator {
+
+ /**
+ *
+ * @param workout the workout
+ * @param weight the weight of the person in kilogram
+ * @return calories burned
+ */
+ public static int calculateCalories(Workout workout, double weight){
+ int mins= (int)(workout.getDuration() / 1000 / 60);
+ return (int)(mins * (getMET(workout) * 3.5 * weight) / 200);
+ }
+
+ /**
+ * calorie calculation based on @link { https://www.topendsports.com/weight-loss/energy-met.htm }
+ *
+ * @param workout
+ * @return MET
+ */
+ public static double getMET(Workout workout){
+ if(workout.workoutType.equals(Workout.WORKOUT_TYPE_RUNNING)){
+ if(workout.avgSpeed < 3.2){
+ return 1.5;
+ }else if(workout.avgSpeed < 4.0){
+ return 2.5;
+ }else if(workout.avgSpeed < 4.8){
+ return 3.25;
+ }else if(workout.avgSpeed < 5.9){
+ return 4.0;
+ }else if(workout.avgSpeed < 7.0){
+ return 5.0;
+ }else if(workout.avgSpeed < 8.0){
+ return 7.0;
+ }else if(workout.avgSpeed < 9.6){
+ return 9.0;
+ }else if(workout.avgSpeed < 12.8){
+ return 12.0;
+ }else{
+ return 16;
+ }
+ }
+ if(workout.workoutType.equals(Workout.WORKOUT_TYPE_HIKING)){
+ return 6.3;
+ }
+ if(workout.workoutType.equals(Workout.WORKOUT_TYPE_CYCLING)){
+ return Math.max(3, (workout.avgSpeed-10) / 1.5);
+ }
+ return -1;
+ }
+
+}
diff --git a/app/src/main/java/de/tadris/fitness/util/ThemeManager.java b/app/src/main/java/de/tadris/fitness/util/ThemeManager.java
new file mode 100644
index 0000000..5510c22
--- /dev/null
+++ b/app/src/main/java/de/tadris/fitness/util/ThemeManager.java
@@ -0,0 +1,39 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+
+import de.tadris.fitness.R;
+import de.tadris.fitness.data.Workout;
+
+public class ThemeManager {
+
+
+ public static int getThemeByWorkout(Workout workout, Context context){
+ switch (workout.workoutType){
+ case Workout.WORKOUT_TYPE_RUNNING: return R.style.Running;
+ case Workout.WORKOUT_TYPE_CYCLING: return R.style.Bicycling;
+ default: return R.style.AppTheme;
+ }
+ }
+
+}
+
diff --git a/app/src/main/java/de/tadris/fitness/util/UnitUtils.java b/app/src/main/java/de/tadris/fitness/util/UnitUtils.java
index d13752a..d8a5dad 100644
--- a/app/src/main/java/de/tadris/fitness/util/UnitUtils.java
+++ b/app/src/main/java/de/tadris/fitness/util/UnitUtils.java
@@ -28,9 +28,9 @@ public class UnitUtils {
int remainingMinutes= (int)mins % 60;
if(hours > 0){
- return hours + "h " + remainingMinutes + "m";
+ return hours + " h " + remainingMinutes + " m";
}else{
- return remainingMinutes + "min";
+ return remainingMinutes + " min";
}
}
@@ -40,6 +40,7 @@ public class UnitUtils {
* @return String in preferred unit
*/
public static String getDistance(int distance){
+ // TODO: use preferred unit by user
if(distance >= 1000){
return getDistanceInKilometers((double)distance);
}else{
@@ -47,16 +48,26 @@ public class UnitUtils {
}
}
+ /**
+ *
+ * @param speed speed in m/s
+ * @return speed in km/h
+ */
+ public static String getSpeed(double speed){
+ // TODO: use preferred unit by user
+ return round(speed*3.6, 1) + " km/h";
+ }
+
public static String getDistanceInMeters(int distance){
- return distance + "m";
+ return distance + " m";
}
public static String getDistanceInKilometers(double distance){
- return round(distance / 1000, 1) + "km";
+ return round(distance / 1000, 1) + " km";
}
public static double round(double d, int count){
- return (double)Math.round(d * Math.pow(10, count)) / count;
+ return (double)Math.round(d * Math.pow(10, count)) / Math.pow(10, count);
}
diff --git a/app/src/main/java/de/tadris/fitness/util/WorkoutTypeCalculator.java b/app/src/main/java/de/tadris/fitness/util/WorkoutTypeCalculator.java
new file mode 100644
index 0000000..5382925
--- /dev/null
+++ b/app/src/main/java/de/tadris/fitness/util/WorkoutTypeCalculator.java
@@ -0,0 +1,46 @@
+/*
+ * 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.util;
+
+import de.tadris.fitness.data.Workout;
+
+public class WorkoutTypeCalculator {
+
+ public static String getType(Workout workout){
+ // TODO: use localisation
+ if(workout.workoutType.equals(Workout.WORKOUT_TYPE_RUNNING)){
+ if(workout.avgSpeed < 7){
+ return "Walking";
+ }else if(workout.avgSpeed < 9.6){
+ return "Jogging";
+ }else{
+ return "Running";
+ }
+ }
+ if(workout.workoutType.equals(Workout.WORKOUT_TYPE_CYCLING)){
+ return "Cycling";
+ }
+ if(workout.workoutType.equals(Workout.WORKOUT_TYPE_HIKING)){
+ return "Hiking";
+ }
+ return "Unknown";
+ }
+
+}
diff --git a/app/src/main/res/layout/activity_list_workouts.xml b/app/src/main/res/layout/activity_list_workouts.xml
index c43a178..ce1cc41 100644
--- a/app/src/main/res/layout/activity_list_workouts.xml
+++ b/app/src/main/res/layout/activity_list_workouts.xml
@@ -1,10 +1,28 @@
+
+
+ tools:context=".activity.ListWorkoutsActivity">
+
+
\ No newline at end of file
+ tools:context=".activity.LauncherActivity" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_record_workout.xml b/app/src/main/res/layout/activity_record_workout.xml
index 6088777..b581b3c 100644
--- a/app/src/main/res/layout/activity_record_workout.xml
+++ b/app/src/main/res/layout/activity_record_workout.xml
@@ -22,7 +22,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".RecordWorkoutActivity">
+ tools:context=".activity.RecordWorkoutActivity">
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/show_entry.xml b/app/src/main/res/layout/show_entry.xml
new file mode 100644
index 0000000..8076af6
--- /dev/null
+++ b/app/src/main/res/layout/show_entry.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_workout.xml b/app/src/main/res/layout/view_workout.xml
index d4675ae..17e7c86 100644
--- a/app/src/main/res/layout/view_workout.xml
+++ b/app/src/main/res/layout/view_workout.xml
@@ -1,34 +1,69 @@
+
+
-
-
-
-
-
-
-
+ android:orientation="vertical"
+ android:background="?android:selectableItemBackground">
+ android:orientation="horizontal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/show_workout_menu.xml b/app/src/main/res/menu/show_workout_menu.xml
new file mode 100644
index 0000000..da4a8a4
--- /dev/null
+++ b/app/src/main/res/menu/show_workout_menu.xml
@@ -0,0 +1,27 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index ef5e1fc..2df259c 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,7 +1,34 @@
+
+
- #008577
- #00574B
- #D81B60
+ #FB8C00
+ #EF6C00
+
+ #43A047
+ #2E7D32
+
+ #523220
+ #462A1D
+
+ #4CAF50
#C8000000
+ #C8414141
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index eed3063..21d86c7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -21,4 +21,5 @@
FitoTrack
Add
Stop
+ Delete
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index e82a4c3..4b3749b 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,11 +1,45 @@
+
+
-
+
+
+
+
+
+