mirror of
https://github.com/russok/FitoTrack.git
synced 2025-10-29 08:42:12 -07:00
Show workouts
This commit is contained in:
parent
4aa8a5c6aa
commit
7e406db592
@ -63,4 +63,5 @@ dependencies {
|
|||||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,9 +32,10 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<activity android:name=".RecordWorkoutActivity"></activity>
|
<activity android:name=".activity.ShowWorkoutActivity"></activity>
|
||||||
<activity android:name=".ListWorkoutsActivity" />
|
<activity android:name=".activity.RecordWorkoutActivity" />
|
||||||
<activity android:name=".LauncherActivity">
|
<activity android:name=".activity.ListWorkoutsActivity" />
|
||||||
|
<activity android:name=".activity.LauncherActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,10 @@ 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 de.tadris.fitness.data.AppDatabase;
|
import de.tadris.fitness.data.AppDatabase;
|
||||||
import de.tadris.fitness.location.LocationListener;
|
import de.tadris.fitness.location.LocationListener;
|
||||||
@ -45,6 +48,12 @@ public class Instance {
|
|||||||
private Instance(Context context) {
|
private Instance(Context context) {
|
||||||
db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
|
db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
|
||||||
.allowMainThreadQueries()
|
.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();
|
.build();
|
||||||
locationListener= new LocationListener(context);
|
locationListener= new LocationListener(context);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,7 @@ public class WorkoutAdapter extends RecyclerView.Adapter<WorkoutAdapter.WorkoutV
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(WorkoutViewHolder holder, final int position) {
|
public void onBindViewHolder(WorkoutViewHolder holder, final int position) {
|
||||||
holder.lengthText.setText(UnitUtils.getDistance(workouts[position].length));
|
holder.lengthText.setText(UnitUtils.getDistance(workouts[position].length));
|
||||||
holder.timeText.setText(UnitUtils.getHourMinuteTime(workouts[position].getTime()));
|
holder.timeText.setText(UnitUtils.getHourMinuteTime(workouts[position].getDuration()));
|
||||||
holder.root.setOnClickListener(new View.OnClickListener() {
|
holder.root.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -80,7 +80,7 @@ public class WorkoutAdapter extends RecyclerView.Adapter<WorkoutAdapter.WorkoutV
|
|||||||
return workouts.length;
|
return workouts.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WorkoutAdapterListener{
|
public interface WorkoutAdapterListener{
|
||||||
void onItemClick(Workout workout);
|
void onItemClick(Workout workout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,12 +17,14 @@
|
|||||||
* 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;
|
package de.tadris.fitness.activity;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import de.tadris.fitness.R;
|
||||||
|
|
||||||
public class LauncherActivity extends Activity {
|
public class LauncherActivity extends Activity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -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;
|
package de.tadris.fitness.activity;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@ -28,6 +28,9 @@ import android.view.MenuItem;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
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;
|
import de.tadris.fitness.data.Workout;
|
||||||
|
|
||||||
public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.WorkoutAdapterListener {
|
public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.WorkoutAdapterListener {
|
||||||
@ -62,7 +65,8 @@ public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.Wor
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(Workout workout) {
|
public void onItemClick(Workout workout) {
|
||||||
// TODO: open detail View
|
ShowWorkoutActivity.selectedWorkout= workout;
|
||||||
|
startActivity(new Intent(this, ShowWorkoutActivity.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -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;
|
package de.tadris.fitness.activity;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@ -30,23 +30,20 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
|
|
||||||
import org.mapsforge.core.model.LatLong;
|
|
||||||
import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
|
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.android.view.MapView;
|
||||||
import org.mapsforge.map.layer.cache.TileCache;
|
|
||||||
import org.mapsforge.map.layer.download.TileDownloadLayer;
|
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.data.Workout;
|
||||||
import de.tadris.fitness.location.LocationListener;
|
import de.tadris.fitness.location.LocationListener;
|
||||||
import de.tadris.fitness.location.MyLocationOverlay;
|
|
||||||
import de.tadris.fitness.location.WorkoutRecorder;
|
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 {
|
public class RecordWorkoutActivity extends Activity implements LocationListener.LocationChangeListener {
|
||||||
|
|
||||||
MapView mapView;
|
MapView mapView;
|
||||||
MyLocationOverlay locationOverlay;
|
|
||||||
TileDownloadLayer downloadLayer;
|
TileDownloadLayer downloadLayer;
|
||||||
WorkoutRecorder recorder;
|
WorkoutRecorder recorder;
|
||||||
|
|
||||||
@ -57,24 +54,7 @@ public class RecordWorkoutActivity extends Activity implements LocationListener.
|
|||||||
|
|
||||||
this.mapView= new MapView(this);
|
this.mapView= new MapView(this);
|
||||||
|
|
||||||
mapView.setZoomLevelMin((byte) 18);
|
downloadLayer= MapManager.setupMap(mapView);
|
||||||
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));
|
|
||||||
|
|
||||||
((ViewGroup)findViewById(R.id.recordMapViewrRoot)).addView(mapView);
|
((ViewGroup)findViewById(R.id.recordMapViewrRoot)).addView(mapView);
|
||||||
|
|
||||||
@ -113,7 +93,6 @@ public class RecordWorkoutActivity extends Activity implements LocationListener.
|
|||||||
@Override
|
@Override
|
||||||
public void onLocationChange(Location location) {
|
public void onLocationChange(Location location) {
|
||||||
mapView.getModel().mapViewPosition.animateTo(LocationListener.locationToLatLong(location));
|
mapView.getModel().mapViewPosition.animateTo(LocationListener.locationToLatLong(location));
|
||||||
locationOverlay.setPosition(location.getLatitude(), location.getLongitude(), location.getAccuracy());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* 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.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<WorkoutSample> 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();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
@ -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 = 3, 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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,8 @@ import androidx.room.PrimaryKey;
|
|||||||
public class Workout{
|
public class Workout{
|
||||||
|
|
||||||
public static final String WORKOUT_TYPE_RUNNING= "running";
|
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";
|
public static final String WORKOUT_TYPE_CYCLING= "cycling";
|
||||||
|
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@ -44,6 +46,11 @@ public class Workout{
|
|||||||
*/
|
*/
|
||||||
public double avgSpeed;
|
public double avgSpeed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Top speed in m/s
|
||||||
|
*/
|
||||||
|
public double topSpeed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Average pace of workout in km/min
|
* Average pace of workout in km/min
|
||||||
*/
|
*/
|
||||||
@ -51,11 +58,9 @@ public class Workout{
|
|||||||
|
|
||||||
public String workoutType;
|
public String workoutType;
|
||||||
|
|
||||||
/**
|
public int calorie;
|
||||||
* Gets time of workout
|
|
||||||
* @return time in milliseconds
|
public long getDuration(){
|
||||||
*/
|
|
||||||
public long getTime(){
|
|
||||||
return end - start;
|
return end - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,13 +19,19 @@
|
|||||||
|
|
||||||
package de.tadris.fitness.data;
|
package de.tadris.fitness.data;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.tadris.fitness.Instance;
|
import de.tadris.fitness.Instance;
|
||||||
|
import de.tadris.fitness.util.CalorieCalculator;
|
||||||
|
|
||||||
public class WorkoutManager {
|
public class WorkoutManager {
|
||||||
|
|
||||||
public static void insertWorkout(Instance instance, Workout workout, List<WorkoutSample> samples){
|
public static void insertWorkout(Context context, Workout workout, List<WorkoutSample> samples){
|
||||||
|
AppDatabase db= Instance.getInstance(context).db;
|
||||||
|
|
||||||
|
|
||||||
workout.id= System.currentTimeMillis();
|
workout.id= System.currentTimeMillis();
|
||||||
|
|
||||||
// Calculating values
|
// Calculating values
|
||||||
@ -34,19 +40,28 @@ public class WorkoutManager {
|
|||||||
length+= samples.get(i - 1).toLatLong().sphericalDistance(samples.get(i).toLatLong());
|
length+= samples.get(i - 1).toLatLong().sphericalDistance(samples.get(i).toLatLong());
|
||||||
}
|
}
|
||||||
workout.length= (int)length;
|
workout.length= (int)length;
|
||||||
workout.avgSpeed= ((double) workout.length / 1000) / ((double) workout.getTime() / 1000);
|
workout.avgSpeed= ((double) workout.length) / ((double) workout.getDuration() / 1000);
|
||||||
workout.avgPace= (double)(workout.getTime() / 1000 / 60) / ((double) workout.length / 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
|
// Setting workoutId in the samples
|
||||||
int i= 0;
|
int i= 0;
|
||||||
|
double topSpeed= 0;
|
||||||
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;
|
||||||
|
if(sample.speed > topSpeed){
|
||||||
|
topSpeed= sample.speed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
workout.topSpeed= topSpeed;
|
||||||
|
|
||||||
|
|
||||||
// Saving workout and samples
|
// Saving workout and samples
|
||||||
instance.db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0]));
|
db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0]));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -88,7 +88,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
|||||||
if(state != RecordingState.STOPPED){
|
if(state != RecordingState.STOPPED){
|
||||||
throw new IllegalStateException("Cannot save recording, recorder was not stopped. state = " + state);
|
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(){
|
public int getSampleCount(){
|
||||||
|
|||||||
54
app/src/main/java/de/tadris/fitness/map/MapManager.java
Normal file
54
app/src/main/java/de/tadris/fitness/map/MapManager.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
58
app/src/main/java/de/tadris/fitness/map/WorkoutLayer.java
Normal file
58
app/src/main/java/de/tadris/fitness/map/WorkoutLayer.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.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<WorkoutSample> samples;
|
||||||
|
|
||||||
|
public WorkoutLayer(List<WorkoutSample> samples, int color) {
|
||||||
|
this(getDEFAULT_PAINT_STROKE(color), samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkoutLayer(Paint paintStroke, List<WorkoutSample> samples) {
|
||||||
|
super(paintStroke, AndroidGraphicFactory.INSTANCE);
|
||||||
|
this.samples = samples;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(){
|
||||||
|
for(WorkoutSample sample : samples){
|
||||||
|
addPoint(sample.toLatLong());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
app/src/main/java/de/tadris/fitness/util/ThemeManager.java
Normal file
39
app/src/main/java/de/tadris/fitness/util/ThemeManager.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -28,9 +28,9 @@ public class UnitUtils {
|
|||||||
int remainingMinutes= (int)mins % 60;
|
int remainingMinutes= (int)mins % 60;
|
||||||
|
|
||||||
if(hours > 0){
|
if(hours > 0){
|
||||||
return hours + "h " + remainingMinutes + "m";
|
return hours + " h " + remainingMinutes + " m";
|
||||||
}else{
|
}else{
|
||||||
return remainingMinutes + "min";
|
return remainingMinutes + " min";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +40,7 @@ public class UnitUtils {
|
|||||||
* @return String in preferred unit
|
* @return String in preferred unit
|
||||||
*/
|
*/
|
||||||
public static String getDistance(int distance){
|
public static String getDistance(int distance){
|
||||||
|
// TODO: use preferred unit by user
|
||||||
if(distance >= 1000){
|
if(distance >= 1000){
|
||||||
return getDistanceInKilometers((double)distance);
|
return getDistanceInKilometers((double)distance);
|
||||||
}else{
|
}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){
|
public static String getDistanceInMeters(int distance){
|
||||||
return distance + "m";
|
return distance + " m";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDistanceInKilometers(double distance){
|
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){
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,10 +1,28 @@
|
|||||||
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ListWorkoutsActivity">
|
tools:context=".activity.ListWorkoutsActivity">
|
||||||
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
|||||||
@ -1,7 +1,25 @@
|
|||||||
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".LauncherActivity"/>
|
tools:context=".activity.LauncherActivity" />
|
||||||
@ -22,7 +22,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".RecordWorkoutActivity">
|
tools:context=".activity.RecordWorkoutActivity">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -30,6 +30,13 @@
|
|||||||
android:layout_above="@id/recordInfoRoot">
|
android:layout_above="@id/recordInfoRoot">
|
||||||
|
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/location_marker" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/recordMapViewrRoot"
|
android:id="@+id/recordMapViewrRoot"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
33
app/src/main/res/layout/activity_show_workout.xml
Normal file
33
app/src/main/res/layout/activity_show_workout.xml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".activity.ShowWorkoutActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/showWorkoutRoot"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp"></LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
103
app/src/main/res/layout/show_entry.xml
Normal file
103
app/src/main/res/layout/show_entry.xml
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/v1"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/v1title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif-black"
|
||||||
|
android:text=""
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="@color/textColorLight"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/v1value"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif-black"
|
||||||
|
android:text=""
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/textLighterBlack"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/v2"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/guideline"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/v2title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif-black"
|
||||||
|
android:text=""
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="@color/textColorLight"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/v2value"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif-black"
|
||||||
|
android:text=""
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/textLighterBlack"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline
|
||||||
|
android:id="@+id/guideline"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="204dp"
|
||||||
|
android:layout_marginEnd="207dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintGuide_begin="204dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
</android.support.constraint.ConstraintLayout>
|
||||||
@ -1,34 +1,69 @@
|
|||||||
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal">
|
android:orientation="vertical"
|
||||||
|
android:background="?android:selectableItemBackground">
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/workoutLength"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="8km"
|
|
||||||
android:textSize="36sp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/workoutTime"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="27min"
|
|
||||||
android:textColor="@color/textLighterBlack"
|
|
||||||
android:textSize="30sp" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_margin="15dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/workoutLength"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="8km"
|
||||||
|
android:textSize="36sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/workoutTime"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="27min"
|
||||||
|
android:textColor="@color/textLighterBlack"
|
||||||
|
android:textSize="30sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/workoutPreviewRoot"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@android:color/darker_gray"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
27
app/src/main/res/menu/show_workout_menu.xml
Normal file
27
app/src/main/res/menu/show_workout_menu.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/actionDeleteWorkout"
|
||||||
|
android:showAsAction="ifRoom"
|
||||||
|
android:title="@string/deleteWorkout" />
|
||||||
|
</menu>
|
||||||
@ -1,7 +1,34 @@
|
|||||||
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<color name="colorPrimary">#008577</color>
|
<color name="colorPrimary">#FB8C00</color>
|
||||||
<color name="colorPrimaryDark">#00574B</color>
|
<color name="colorPrimaryDark">#EF6C00</color>
|
||||||
<color name="colorAccent">#D81B60</color>
|
|
||||||
|
<color name="colorPrimaryRunning">#43A047</color>
|
||||||
|
<color name="colorPrimaryDarkRunning">#2E7D32</color>
|
||||||
|
|
||||||
|
<color name="colorPrimaryBicycling">#523220</color>
|
||||||
|
<color name="colorPrimaryDarkBicycling">#462A1D</color>
|
||||||
|
|
||||||
|
<color name="colorAccent">#4CAF50</color>
|
||||||
<color name="textLighterBlack">#C8000000</color>
|
<color name="textLighterBlack">#C8000000</color>
|
||||||
|
<color name="textColorLight">#C8414141</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@ -21,4 +21,5 @@
|
|||||||
<string name="app_name">FitoTrack</string>
|
<string name="app_name">FitoTrack</string>
|
||||||
<string name="workout_add">Add</string>
|
<string name="workout_add">Add</string>
|
||||||
<string name="workoutStopRecording">Stop</string>
|
<string name="workoutStopRecording">Stop</string>
|
||||||
|
<string name="deleteWorkout">Delete</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@ -1,11 +1,45 @@
|
|||||||
|
<!--
|
||||||
|
~ 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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!-- Base application theme. -->
|
<!-- Base application theme. -->
|
||||||
<style name="AppTheme" parent="android:Theme.Material.Light">
|
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
<item name="android:colorPrimary">@color/colorPrimary</item>
|
<item name="android:colorPrimary">@color/colorPrimary</item>
|
||||||
<item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
|
<item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
<item name="android:colorAccent">@color/colorAccent</item>
|
<item name="android:colorAccent">@color/colorAccent</item>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="Running" parent="AppTheme">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
<item name="android:colorPrimary">@color/colorPrimaryRunning</item>
|
||||||
|
<item name="android:colorPrimaryDark">@color/colorPrimaryDarkRunning</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="Bicycling" parent="AppTheme">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
<item name="android:colorPrimary">@color/colorPrimaryBicycling</item>
|
||||||
|
<item name="android:colorPrimaryDark">@color/colorPrimaryDarkBicycling</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user