mirror of
https://github.com/russok/FitoTrack.git
synced 2025-10-28 16:22:12 -07:00
Record workout, List workouts
This commit is contained in:
parent
cdcf2ddce2
commit
4aa8a5c6aa
@ -1,5 +1,32 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
allprojects {
|
||||
dependencies {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "29.0.1"
|
||||
@ -20,9 +47,19 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
def room_version = "2.2.0-alpha02"
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||
implementation "androidx.room:room-runtime:2.2.0-alpha02"
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
implementation 'org.mapsforge:mapsforge-core:0.11.0'
|
||||
implementation 'org.mapsforge:mapsforge-map:0.11.0'
|
||||
implementation 'org.mapsforge:mapsforge-map-reader:0.11.0'
|
||||
implementation 'org.mapsforge:mapsforge-themes:0.11.0'
|
||||
implementation 'org.mapsforge:mapsforge-map-android:0.11.0'
|
||||
implementation 'com.caverock:androidsvg:1.3'
|
||||
implementation 'net.sf.kxml:kxml2:2.3.0'
|
||||
annotationProcessor "androidx.room:room-compiler:$room_version"
|
||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
|
||||
@ -1,7 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
~
|
||||
~ This file is part of FitoTrack
|
||||
~
|
||||
~ FitoTrack is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ FitoTrack is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="de.tadris.fitness">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
|
||||
@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import androidx.room.Room;
|
||||
|
||||
import de.tadris.fitness.data.AppDatabase;
|
||||
import de.tadris.fitness.location.LocationListener;
|
||||
|
||||
public class Instance {
|
||||
|
||||
@ -39,8 +40,12 @@ public class Instance {
|
||||
}
|
||||
|
||||
public AppDatabase db;
|
||||
public LocationListener locationListener;
|
||||
|
||||
private Instance(Context context) {
|
||||
db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME).allowMainThreadQueries().build();
|
||||
db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
|
||||
.allowMainThreadQueries()
|
||||
.build();
|
||||
locationListener= new LocationListener(context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,21 +20,20 @@
|
||||
package de.tadris.fitness;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.tadris.fitness.data.Workout;
|
||||
|
||||
public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.WorkoutAdapterListener {
|
||||
|
||||
private RecyclerView listView;
|
||||
private RecyclerView.Adapter mAdapter;
|
||||
private RecyclerView.Adapter adapter;
|
||||
private RecyclerView.LayoutManager layoutManager;
|
||||
Workout[] workouts;
|
||||
|
||||
@ -50,12 +49,38 @@ public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.Wor
|
||||
layoutManager= new LinearLayoutManager(this);
|
||||
listView.setLayoutManager(layoutManager);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
workouts= Instance.getInstance(this).db.workoutDao().getWorkouts();
|
||||
listView.setAdapter(new WorkoutAdapter(workouts, this));
|
||||
adapter= new WorkoutAdapter(workouts, this);
|
||||
listView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(Workout workout) {
|
||||
// TODO: open detail View
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.list_workout_menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if(id == R.id.action_workout_add){
|
||||
startActivity(new Intent(this, RecordWorkoutActivity.class));
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,19 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
* FitoTrack is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FitoTrack is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class RecordWorkoutActivity extends Activity {
|
||||
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.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;
|
||||
|
||||
public class RecordWorkoutActivity extends Activity implements LocationListener.LocationChangeListener {
|
||||
|
||||
MapView mapView;
|
||||
MyLocationOverlay locationOverlay;
|
||||
TileDownloadLayer downloadLayer;
|
||||
WorkoutRecorder recorder;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_record_workout);
|
||||
|
||||
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));
|
||||
|
||||
((ViewGroup)findViewById(R.id.recordMapViewrRoot)).addView(mapView);
|
||||
|
||||
checkPermissions();
|
||||
|
||||
recorder= new WorkoutRecorder(this, Workout.WORKOUT_TYPE_RUNNING);
|
||||
recorder.start();
|
||||
}
|
||||
|
||||
private void stopAndSave(){
|
||||
recorder.stop();
|
||||
if(recorder.getSampleCount() > 3){
|
||||
recorder.save();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
void checkPermissions(){
|
||||
if (!hasPermission()) {
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 10);
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 10);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasPermission(){
|
||||
return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
|| ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (hasPermission()) {
|
||||
Instance.getInstance(this).locationListener.enableMyLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChange(Location location) {
|
||||
mapView.getModel().mapViewPosition.animateTo(LocationListener.locationToLatLong(location));
|
||||
locationOverlay.setPosition(location.getLatitude(), location.getLongitude(), location.getAccuracy());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
recorder.stop();
|
||||
mapView.destroyAll();
|
||||
AndroidGraphicFactory.clearResourceMemoryCache();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause(){
|
||||
super.onPause();
|
||||
downloadLayer.onPause();
|
||||
Instance.getInstance(this).locationListener.unregisterLocationChangeListeners(this);
|
||||
}
|
||||
|
||||
public void onResume(){
|
||||
super.onResume();
|
||||
downloadLayer.onResume();
|
||||
Instance.getInstance(this).locationListener.registerLocationChangeListeners(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.record_menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if(id == R.id.actionRecordingStop){
|
||||
stopAndSave();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void onMenuCreate(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
* FitoTrack is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FitoTrack is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
@ -45,7 +64,7 @@ public class WorkoutAdapter extends RecyclerView.Adapter<WorkoutAdapter.WorkoutV
|
||||
// Replace the contents of a view (invoked by the layout manager)
|
||||
@Override
|
||||
public void onBindViewHolder(WorkoutViewHolder holder, final int position) {
|
||||
holder.lengthText.setText(workouts[position].length + "km");
|
||||
holder.lengthText.setText(UnitUtils.getDistance(workouts[position].length));
|
||||
holder.timeText.setText(UnitUtils.getHourMinuteTime(workouts[position].getTime()));
|
||||
holder.root.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
|
||||
@ -22,7 +22,7 @@ package de.tadris.fitness.data;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
@Database(entities = {Workout.class, WorkoutSample.class}, version = 1)
|
||||
@Database(version = 1, entities = {Workout.class, WorkoutSample.class})
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
public abstract WorkoutDao workoutDao();
|
||||
}
|
||||
|
||||
@ -33,11 +33,28 @@ public class Workout{
|
||||
|
||||
public long start;
|
||||
public long end;
|
||||
public double length;
|
||||
|
||||
/**
|
||||
* Length of workout in meters
|
||||
*/
|
||||
public int length;
|
||||
|
||||
/**
|
||||
* Average speed of workout in m/s
|
||||
*/
|
||||
public double avgSpeed;
|
||||
|
||||
/**
|
||||
* Average pace of workout in km/min
|
||||
*/
|
||||
public double avgPace;
|
||||
|
||||
public String workoutType;
|
||||
|
||||
/**
|
||||
* Gets time of workout
|
||||
* @return time in milliseconds
|
||||
*/
|
||||
public long getTime(){
|
||||
return end - start;
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
package de.tadris.fitness.data;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
|
||||
@Dao
|
||||
@ -31,4 +32,13 @@ public interface WorkoutDao {
|
||||
@Query("SELECT * FROM workout")
|
||||
Workout[] getWorkouts();
|
||||
|
||||
@Insert
|
||||
void insertWorkoutAndSamples(Workout workout, WorkoutSample[] samples);
|
||||
|
||||
@Insert
|
||||
void insertWorkout(Workout workout);
|
||||
|
||||
@Query("SELECT * FROM workout ORDER BY start DESC LIMIT 1")
|
||||
Workout findLastWorkout();
|
||||
|
||||
}
|
||||
|
||||
53
app/src/main/java/de/tadris/fitness/data/WorkoutManager.java
Normal file
53
app/src/main/java/de/tadris/fitness/data/WorkoutManager.java
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.tadris.fitness.Instance;
|
||||
|
||||
public class WorkoutManager {
|
||||
|
||||
public static void insertWorkout(Instance instance, Workout workout, List<WorkoutSample> samples){
|
||||
workout.id= System.currentTimeMillis();
|
||||
|
||||
// Calculating values
|
||||
double length= 0;
|
||||
for(int i= 1; i < samples.size(); i++){
|
||||
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);
|
||||
|
||||
// Setting workoutId in the samples
|
||||
int i= 0;
|
||||
for(WorkoutSample sample : samples){
|
||||
i++;
|
||||
sample.id= workout.id + i;
|
||||
sample.workoutId= workout.id;
|
||||
}
|
||||
|
||||
// Saving workout and samples
|
||||
instance.db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0]));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -24,6 +24,8 @@ import androidx.room.Entity;
|
||||
import androidx.room.ForeignKey;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.mapsforge.core.model.LatLong;
|
||||
|
||||
import static androidx.room.ForeignKey.CASCADE;
|
||||
|
||||
@Entity(tableName = "workout_sample",
|
||||
@ -48,5 +50,9 @@ public class WorkoutSample{
|
||||
|
||||
public double speed;
|
||||
|
||||
public LatLong toLatLong(){
|
||||
return new LatLong(lat, lon);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
* FitoTrack is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FitoTrack is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.location;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import org.mapsforge.core.model.LatLong;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LocationListener implements android.location.LocationListener {
|
||||
|
||||
public static LatLong static_lastLocation;
|
||||
|
||||
/**
|
||||
* @param location the location whose geographical coordinates should be converted.
|
||||
* @return a new LatLong with the geographical coordinates taken from the given location.
|
||||
*/
|
||||
public static LatLong locationToLatLong(Location location) {
|
||||
return new LatLong(location.getLatitude(), location.getLongitude());
|
||||
}
|
||||
|
||||
private Context activity;
|
||||
private Location lastLocation;
|
||||
private final LocationManager locationManager;
|
||||
private boolean myLocationEnabled;
|
||||
|
||||
public LocationListener(Context context) {
|
||||
super();
|
||||
this.activity= context;
|
||||
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stops the receiving of location updates. Has no effect if location updates are already disabled.
|
||||
*/
|
||||
public synchronized void disableMyLocation() {
|
||||
if (this.myLocationEnabled) {
|
||||
this.myLocationEnabled = false;
|
||||
try {
|
||||
this.locationManager.removeUpdates(this);
|
||||
} catch (RuntimeException runtimeException) {
|
||||
// do we need to catch security exceptions for this call on Android 6?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void enableMyLocation() {
|
||||
enableBestAvailableProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the most-recently received location fix (might be null).
|
||||
*/
|
||||
public synchronized Location getLastLocation() {
|
||||
return this.lastLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the receiving of location updates is currently enabled, false otherwise.
|
||||
*/
|
||||
public synchronized boolean isMyLocationEnabled() {
|
||||
return this.myLocationEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
|
||||
synchronized (this) {
|
||||
this.lastLocation = location;
|
||||
|
||||
LatLong latLong = locationToLatLong(location);
|
||||
static_lastLocation= latLong;
|
||||
|
||||
for(LocationChangeListener listener : this.locationChangeListeners){
|
||||
listener.onLocationChange(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
enableBestAvailableProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {
|
||||
enableBestAvailableProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
private void enableBestAvailableProvider() {
|
||||
disableMyLocation();
|
||||
|
||||
boolean result = false;
|
||||
for (String provider : this.locationManager.getProviders(true)) {
|
||||
if (LocationManager.GPS_PROVIDER.equals(provider) || LocationManager.NETWORK_PROVIDER.equals(provider)) {
|
||||
result = true;
|
||||
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
this.locationManager.requestLocationUpdates(provider, 0, 0, this);
|
||||
Location location= this.locationManager.getLastKnownLocation(provider);
|
||||
if(location != null){
|
||||
onLocationChanged(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.myLocationEnabled = result;
|
||||
}
|
||||
|
||||
private List<LocationChangeListener> locationChangeListeners= new ArrayList<>();
|
||||
|
||||
public void registerLocationChangeListeners(LocationChangeListener listener){
|
||||
if(locationChangeListeners.size() == 0){
|
||||
enableMyLocation();
|
||||
}
|
||||
locationChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
public void unregisterLocationChangeListeners(LocationChangeListener listener){
|
||||
locationChangeListeners.remove(listener);
|
||||
if(locationChangeListeners.size() == 0){
|
||||
disableMyLocation();
|
||||
}
|
||||
}
|
||||
|
||||
public interface LocationChangeListener{
|
||||
void onLocationChange(Location location);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
* FitoTrack is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FitoTrack is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.location;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import org.mapsforge.core.graphics.Canvas;
|
||||
import org.mapsforge.core.graphics.Paint;
|
||||
import org.mapsforge.core.graphics.Style;
|
||||
import org.mapsforge.core.model.BoundingBox;
|
||||
import org.mapsforge.core.model.LatLong;
|
||||
import org.mapsforge.core.model.Point;
|
||||
import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
|
||||
import org.mapsforge.map.layer.Layer;
|
||||
import org.mapsforge.map.layer.overlay.Circle;
|
||||
import org.mapsforge.map.layer.overlay.Marker;
|
||||
|
||||
public class MyLocationOverlay extends Layer {
|
||||
|
||||
private final Circle circle;
|
||||
private final Marker marker;
|
||||
private final LocationListener locationListener;
|
||||
|
||||
private static Paint getDefaultFixedPixelCircleFill() {
|
||||
return getPaint(AndroidGraphicFactory.INSTANCE.createColor(255, 0, 0, 255), 0, Style.FILL);
|
||||
}
|
||||
|
||||
private static Paint getDefaultOuterFixedPixelCircleFill(){
|
||||
return getPaint(AndroidGraphicFactory.INSTANCE.createColor(30, 30, 30, 255), 0, Style.FILL);
|
||||
}
|
||||
|
||||
private static Paint getDefaultFixedPixelCircleStroke() {
|
||||
return getPaint(AndroidGraphicFactory.INSTANCE.createColor(255, 255, 255, 255), 7, Style.STROKE);
|
||||
}
|
||||
|
||||
private static Paint getPaint(int color, int strokeWidth, Style style) {
|
||||
Paint paint = AndroidGraphicFactory.INSTANCE.createPaint();
|
||||
paint.setColor(color);
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
paint.setStyle(style);
|
||||
return paint;
|
||||
}
|
||||
|
||||
public MyLocationOverlay(LocationListener locationListener, Drawable icon) {
|
||||
this.locationListener= locationListener;
|
||||
this.circle= new Circle(null, 0f, getDefaultFixedPixelCircleFill(), null);
|
||||
this.marker= new Marker(null, AndroidGraphicFactory.convertToBitmap(icon), 26, 26);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void draw(BoundingBox boundingBox, byte zoomLevel, Canvas canvas, Point topLeftPoint) {
|
||||
if (this.circle != null) {
|
||||
this.circle.draw(boundingBox, zoomLevel, canvas, topLeftPoint);
|
||||
}
|
||||
this.marker.draw(boundingBox, zoomLevel, canvas, topLeftPoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAdd() {
|
||||
this.circle.setDisplayModel(this.displayModel);
|
||||
this.marker.setDisplayModel(this.displayModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
this.marker.onDestroy();
|
||||
}
|
||||
|
||||
public void setPosition(double latitude, double longitude, float accuracy) {
|
||||
synchronized (this) {
|
||||
LatLong latLong = new LatLong(latitude, longitude);
|
||||
this.marker.setLatLong(latLong);
|
||||
if (this.circle != null) {
|
||||
this.circle.setLatLong(latLong);
|
||||
this.circle.setRadius(accuracy);
|
||||
}
|
||||
requestRedraw();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
* FitoTrack is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FitoTrack is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mapsforge.core.model.LatLong;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.tadris.fitness.Instance;
|
||||
import de.tadris.fitness.data.Workout;
|
||||
import de.tadris.fitness.data.WorkoutManager;
|
||||
import de.tadris.fitness.data.WorkoutSample;
|
||||
|
||||
public class WorkoutRecorder implements LocationListener.LocationChangeListener {
|
||||
|
||||
private static final int MIN_DISTANCE= 5;
|
||||
|
||||
private Context context;
|
||||
private Workout workout;
|
||||
private RecordingState state;
|
||||
private List<WorkoutSample> samples= new ArrayList<>();
|
||||
private long time= 0;
|
||||
private long lastResume;
|
||||
|
||||
public WorkoutRecorder(Context context, String workoutType) {
|
||||
this.context= context;
|
||||
this.state= RecordingState.IDLE;
|
||||
|
||||
this.workout= new Workout();
|
||||
this.workout.workoutType= workoutType;
|
||||
}
|
||||
|
||||
public void start(){
|
||||
if(state == RecordingState.IDLE){
|
||||
Log.i("Recorder", "");
|
||||
workout.start= System.currentTimeMillis();
|
||||
resume();
|
||||
}else if(state == RecordingState.PAUSED){
|
||||
resume();
|
||||
}else if(state != RecordingState.RUNNING){
|
||||
throw new IllegalStateException("Cannot start or resume recording. state = " + state);
|
||||
}
|
||||
}
|
||||
|
||||
private void resume(){
|
||||
state= RecordingState.RUNNING;
|
||||
lastResume= System.currentTimeMillis();
|
||||
Instance.getInstance(context).locationListener.registerLocationChangeListeners(this);
|
||||
}
|
||||
|
||||
public void pause(){
|
||||
if(state == RecordingState.RUNNING){
|
||||
state= RecordingState.PAUSED;
|
||||
time+= System.currentTimeMillis() - lastResume;
|
||||
Instance.getInstance(context).locationListener.unregisterLocationChangeListeners(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
pause();
|
||||
workout.end= System.currentTimeMillis();
|
||||
state= RecordingState.STOPPED;
|
||||
}
|
||||
|
||||
public void save(){
|
||||
if(state != RecordingState.STOPPED){
|
||||
throw new IllegalStateException("Cannot save recording, recorder was not stopped. state = " + state);
|
||||
}
|
||||
WorkoutManager.insertWorkout(Instance.getInstance(context), workout, samples);
|
||||
}
|
||||
|
||||
public int getSampleCount(){
|
||||
return samples.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChange(Location location) {
|
||||
if(state == RecordingState.RUNNING){
|
||||
if(getSampleCount() > 0){
|
||||
WorkoutSample lastSample= samples.get(samples.size() - 1);
|
||||
if(LocationListener.locationToLatLong(location).sphericalDistance(new LatLong(lastSample.lat, lastSample.lon)) < MIN_DISTANCE){
|
||||
return;
|
||||
}
|
||||
}
|
||||
WorkoutSample sample= new WorkoutSample();
|
||||
sample.lat= location.getLatitude();
|
||||
sample.lon= location.getLongitude();
|
||||
sample.speed= location.getSpeed();
|
||||
sample.time= location.getTime();
|
||||
samples.add(sample);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum RecordingState{
|
||||
IDLE, RUNNING, PAUSED, STOPPED
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.Tile;
|
||||
import org.mapsforge.map.layer.download.tilesource.AbstractTileSource;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public class HumanitarianTileSource extends AbstractTileSource {
|
||||
|
||||
public static HumanitarianTileSource INSTANCE= new HumanitarianTileSource(new String[]{"tile-a.openstreetmap.fr", "tile-b.openstreetmap.fr", "tile-c.openstreetmap.fr"}, 443);
|
||||
|
||||
private static final int PARALLEL_REQUESTS_LIMIT = 8;
|
||||
private static final String PROTOCOL = "https";
|
||||
private static final int ZOOM_LEVEL_MAX = 18;
|
||||
private static final int ZOOM_LEVEL_MIN = 0;
|
||||
|
||||
public HumanitarianTileSource(String[] hostNames, int port) {
|
||||
super(hostNames, port);
|
||||
defaultTimeToLive = 864000000; // Ten days
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParallelRequestsLimit() {
|
||||
return PARALLEL_REQUESTS_LIMIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getTileUrl(Tile tile) throws MalformedURLException {
|
||||
|
||||
return new URL(PROTOCOL, getHostName(), this.port, "/hot/" + tile.zoomLevel + '/' + tile.tileX + '/' + tile.tileY + ".png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getZoomLevelMax() {
|
||||
return ZOOM_LEVEL_MAX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getZoomLevelMin() {
|
||||
return ZOOM_LEVEL_MIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAlpha() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.map.rendertheme.XmlRenderTheme;
|
||||
import org.mapsforge.map.rendertheme.XmlRenderThemeMenuCallback;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Enumeration of all internal rendering themes.
|
||||
*/
|
||||
public enum InternalRenderTheme implements XmlRenderTheme {
|
||||
|
||||
OLD("/assets/rendertheme/default.xml"),
|
||||
DEFAULT("/assets/rendertheme/osmarender.xml");
|
||||
|
||||
private final String path;
|
||||
private XmlRenderThemeMenuCallback callback;
|
||||
|
||||
InternalRenderTheme(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlRenderThemeMenuCallback getMenuCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the prefix for all relative resource paths.
|
||||
*/
|
||||
@Override
|
||||
public String getRelativePathPrefix() {
|
||||
return "/assets/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getRenderThemeAsStream() {
|
||||
return getClass().getResourceAsStream(this.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMenuCallback(XmlRenderThemeMenuCallback menuCallback) {
|
||||
callback= menuCallback;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,23 @@
|
||||
package de.tadris.fitness.util;
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
package de.tadris.fitness.util;
|
||||
|
||||
public class UnitUtils {
|
||||
|
||||
@ -17,4 +34,30 @@ public class UnitUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param distance Distance in meters
|
||||
* @return String in preferred unit
|
||||
*/
|
||||
public static String getDistance(int distance){
|
||||
if(distance >= 1000){
|
||||
return getDistanceInKilometers((double)distance);
|
||||
}else{
|
||||
return getDistanceInMeters(distance);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDistanceInMeters(int distance){
|
||||
return distance + "m";
|
||||
}
|
||||
|
||||
public static String getDistanceInKilometers(double distance){
|
||||
return round(distance / 1000, 1) + "km";
|
||||
}
|
||||
|
||||
public static double round(double d, int count){
|
||||
return (double)Math.round(d * Math.pow(10, count)) / count;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
28
app/src/main/res/drawable/ic_record_24dp.xml
Normal file
28
app/src/main/res/drawable/ic_record_24dp.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"
|
||||
android:fillColor="@android:color/white"/>
|
||||
</vector>
|
||||
BIN
app/src/main/res/drawable/location_marker.png
Normal file
BIN
app/src/main/res/drawable/location_marker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@ -1,9 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<RelativeLayout 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=".RecordWorkoutActivity">
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@id/recordInfoRoot">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/recordMapViewrRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/recordInfoRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:padding="10dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20sp"
|
||||
android:text="TextView" />
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
@ -1,7 +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/action_workout_add"
|
||||
android:showAsAction="always"
|
||||
android:title="@string/workout_add" />
|
||||
</menu>
|
||||
27
app/src/main/res/menu/record_menu.xml
Normal file
27
app/src/main/res/menu/record_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/actionRecordingStop"
|
||||
android:showAsAction="ifRoom"
|
||||
android:title="@string/workoutStopRecording" />
|
||||
</menu>
|
||||
@ -1,4 +1,24 @@
|
||||
<!--
|
||||
~ 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>
|
||||
<string name="app_name">FitoTrack</string>
|
||||
<string name="workout_add">Add</string>
|
||||
<string name="workoutStopRecording">Stop</string>
|
||||
</resources>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user