mirror of
https://github.com/russok/FitoTrack.git
synced 2025-10-28 16:22:12 -07:00
Merge branch '2.0'
This commit is contained in:
commit
c090479d26
@ -35,8 +35,8 @@ android {
|
||||
applicationId "de.tadris.fitness"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 111
|
||||
versionName "1.1.1"
|
||||
versionCode 200
|
||||
versionName "2.0"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
|
||||
@ -22,13 +22,14 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
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" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
@ -36,8 +37,13 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:appCategory="productivity"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity android:name=".activity.SettingsActivity"></activity>
|
||||
<activity android:name=".activity.ShowWorkoutMapActivity"
|
||||
android:screenOrientation="portrait"></activity>
|
||||
<activity android:name=".activity.ShowWorkoutMapDiagramActivity"
|
||||
android:screenOrientation="portrait"></activity>
|
||||
<activity android:name=".activity.SettingsActivity" />
|
||||
<activity
|
||||
android:name=".activity.ShowWorkoutActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -56,15 +62,17 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="de.tadris.fitness.fileprovider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/filepaths" />
|
||||
</provider>
|
||||
|
||||
<service android:name=".recording.LocationListener" />
|
||||
<service android:name=".recording.PressureService" />
|
||||
</application>
|
||||
|
||||
@ -37,6 +37,7 @@ import com.github.clans.fab.FloatingActionMenu;
|
||||
import de.tadris.fitness.Instance;
|
||||
import de.tadris.fitness.R;
|
||||
import de.tadris.fitness.data.Workout;
|
||||
import de.tadris.fitness.util.DialogUtils;
|
||||
import de.tadris.fitness.view.WorkoutAdapter;
|
||||
|
||||
public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.WorkoutAdapterListener {
|
||||
@ -73,8 +74,13 @@ public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.Wor
|
||||
findViewById(R.id.workoutListRecordHiking) .setOnClickListener(v -> startRecording(Workout.WORKOUT_TYPE_HIKING));
|
||||
findViewById(R.id.workoutListRecordCycling).setOnClickListener(v -> startRecording(Workout.WORKOUT_TYPE_CYCLING));
|
||||
|
||||
loadData();
|
||||
|
||||
checkFirstStart();
|
||||
|
||||
adapter= new WorkoutAdapter(workouts, this);
|
||||
listView.setAdapter(adapter);
|
||||
|
||||
}
|
||||
|
||||
private void checkFirstStart(){
|
||||
@ -101,9 +107,8 @@ public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.Wor
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
workouts= Instance.getInstance(this).db.workoutDao().getWorkouts();
|
||||
adapter= new WorkoutAdapter(workouts, this);
|
||||
listView.setAdapter(adapter);
|
||||
loadData();
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -112,6 +117,19 @@ public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.Wor
|
||||
startActivity(new Intent(this, ShowWorkoutActivity.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemLongClick(int pos, Workout workout) {
|
||||
DialogUtils.showDeleteWorkoutDialog(this, () -> {
|
||||
Instance.getInstance(ListWorkoutsActivity.this).db.workoutDao().deleteWorkout(workout);
|
||||
loadData();
|
||||
adapter.notifyItemRemoved(pos);
|
||||
});
|
||||
}
|
||||
|
||||
private void loadData(){
|
||||
workouts= Instance.getInstance(this).db.workoutDao().getWorkouts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
@ -131,6 +149,4 @@ public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.Wor
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
package de.tadris.fitness.activity;
|
||||
|
||||
import android.Manifest;
|
||||
import android.animation.Animator;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -32,6 +33,7 @@ import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
@ -71,6 +73,8 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
|
||||
List<LatLong> latLongList= new ArrayList<>();
|
||||
InfoViewHolder[] infoViews= new InfoViewHolder[4];
|
||||
TextView timeView, gpsStatusView;
|
||||
View waitingForGPSOverlay;
|
||||
boolean gpsFound= false;
|
||||
boolean isResumed= false;
|
||||
private Handler mHandler= new Handler();
|
||||
PowerManager.WakeLock wakeLock;
|
||||
@ -89,6 +93,8 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
|
||||
setupMap();
|
||||
|
||||
((ViewGroup)findViewById(R.id.recordMapViewrRoot)).addView(mapView);
|
||||
waitingForGPSOverlay= findViewById(R.id.recorderWaitingOverlay);
|
||||
waitingForGPSOverlay.setVisibility(View.VISIBLE);
|
||||
|
||||
checkPermissions();
|
||||
|
||||
@ -119,6 +125,20 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
|
||||
wakeLock.acquire(1000*60*120);
|
||||
}
|
||||
|
||||
private void hideWaitOverlay(){
|
||||
waitingForGPSOverlay.clearAnimation();
|
||||
waitingForGPSOverlay.animate().alpha(0f).setDuration(1000).setListener(new Animator.AnimatorListener() {
|
||||
@Override public void onAnimationStart(Animator animator) { }
|
||||
@Override public void onAnimationCancel(Animator animator) { }
|
||||
@Override public void onAnimationRepeat(Animator animator) { }
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
waitingForGPSOverlay.setVisibility(View.GONE);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void setupMap(){
|
||||
this.mapView= new MapView(this);
|
||||
TileSources.Purpose purpose;
|
||||
@ -336,7 +356,13 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
|
||||
|
||||
@Override
|
||||
public void onGPSStateChanged(WorkoutRecorder.GpsState oldState, WorkoutRecorder.GpsState state) {
|
||||
mHandler.post(() -> gpsStatusView.setTextColor(state.color));
|
||||
mHandler.post(() -> {
|
||||
gpsStatusView.setTextColor(state.color);
|
||||
if(!gpsFound && (state != WorkoutRecorder.GpsState.SIGNAL_LOST)){
|
||||
gpsFound= true;
|
||||
hideWaitOverlay();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static class InfoViewHolder{
|
||||
|
||||
@ -22,7 +22,6 @@ package de.tadris.fitness.activity;
|
||||
import android.Manifest;
|
||||
import android.app.ActionBar;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -44,7 +43,6 @@ import android.widget.NumberPicker;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NavUtils;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
@ -53,7 +51,6 @@ import java.io.FileNotFoundException;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
import de.tadris.fitness.util.export.Exporter;
|
||||
import de.tadris.fitness.util.gpx.GpxExporter;
|
||||
import de.tadris.fitness.util.unit.UnitUtils;
|
||||
import de.tadris.fitness.view.ProgressDialogController;
|
||||
|
||||
@ -160,6 +157,7 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
addPreferencesFromResource(R.xml.preferences_main);
|
||||
|
||||
bindPreferenceSummaryToValue(findPreference("unitSystem"));
|
||||
bindPreferenceSummaryToValue(findPreference("mapStyle"));
|
||||
|
||||
findPreference("weight").setOnPreferenceClickListener(preference -> showWeightPicker());
|
||||
findPreference("import").setOnPreferenceClickListener(preference -> showImportDialog());
|
||||
@ -259,10 +257,8 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
Exporter.importData(getBaseContext(), uri,
|
||||
(progress, action) -> mHandler.post(() -> dialogController.setProgress(progress, action)));
|
||||
|
||||
mHandler.post(() -> {
|
||||
// DO on backup finished
|
||||
dialogController.cancel();
|
||||
});
|
||||
mHandler.post(dialogController::cancel);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
mHandler.post(() -> {
|
||||
|
||||
@ -20,88 +20,44 @@
|
||||
package de.tadris.fitness.activity;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
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.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.components.Description;
|
||||
import com.github.mikephil.charting.data.Entry;
|
||||
import com.github.mikephil.charting.data.LineData;
|
||||
import com.github.mikephil.charting.data.LineDataSet;
|
||||
import com.github.mikephil.charting.highlight.Highlight;
|
||||
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
|
||||
|
||||
import org.mapsforge.core.graphics.Paint;
|
||||
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 org.mapsforge.map.layer.overlay.FixedPixelCircle;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
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.WorkoutManager;
|
||||
import de.tadris.fitness.data.WorkoutSample;
|
||||
import de.tadris.fitness.map.MapManager;
|
||||
import de.tadris.fitness.map.WorkoutLayer;
|
||||
import de.tadris.fitness.map.tilesource.TileSources;
|
||||
import de.tadris.fitness.util.ThemeManager;
|
||||
import de.tadris.fitness.util.WorkoutTypeCalculator;
|
||||
import de.tadris.fitness.util.DialogUtils;
|
||||
import de.tadris.fitness.util.gpx.GpxExporter;
|
||||
import de.tadris.fitness.util.unit.UnitUtils;
|
||||
import de.tadris.fitness.view.ProgressDialogController;
|
||||
|
||||
public class ShowWorkoutActivity extends FitoTrackActivity {
|
||||
static Workout selectedWorkout;
|
||||
public class ShowWorkoutActivity extends WorkoutActivity implements DialogUtils.WorkoutDeleter {
|
||||
|
||||
List<WorkoutSample> samples;
|
||||
Workout workout;
|
||||
ViewGroup root;
|
||||
Resources.Theme theme;
|
||||
MapView map;
|
||||
TileDownloadLayer downloadLayer;
|
||||
FixedPixelCircle highlightingCircle;
|
||||
Handler mHandler= new Handler();
|
||||
|
||||
@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));
|
||||
initBeforeContent();
|
||||
|
||||
setContentView(R.layout.activity_show_workout);
|
||||
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setTitle(WorkoutTypeCalculator.getType(workout));
|
||||
|
||||
theme= getTheme();
|
||||
|
||||
root= findViewById(R.id.showWorkoutRoot);
|
||||
|
||||
initAfterContent();
|
||||
|
||||
addText(getString(R.string.comment) + ": " + workout.comment).setOnClickListener(v -> {
|
||||
TextView textView= (TextView)v;
|
||||
openEditCommentDialog(textView);
|
||||
@ -120,6 +76,9 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
||||
|
||||
addMap();
|
||||
|
||||
map.setClickable(false);
|
||||
mapRoot.setOnClickListener(v -> startActivity(new Intent(ShowWorkoutActivity.this, ShowWorkoutMapActivity.class)));
|
||||
|
||||
addTitle(getString(R.string.workoutSpeed));
|
||||
|
||||
addKeyValue(getString(R.string.workoutAvgSpeed), UnitUtils.getSpeed(workout.avgSpeed),
|
||||
@ -127,6 +86,8 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
||||
|
||||
addSpeedDiagram();
|
||||
|
||||
speedDiagram.setOnClickListener(v -> startDiagramActivity(ShowWorkoutMapDiagramActivity.DIAGRAM_TYPE_SPEED));
|
||||
|
||||
addTitle(getString(R.string.workoutBurnedEnergy));
|
||||
addKeyValue(getString(R.string.workoutTotalEnergy), workout.calorie + " kcal",
|
||||
getString(R.string.workoutEnergyConsumption), UnitUtils.getRelativeEnergyConsumption((double)workout.calorie / ((double)workout.length / 1000)));
|
||||
@ -138,9 +99,17 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
||||
|
||||
addHeightDiagram();
|
||||
|
||||
heightDiagram.setOnClickListener(v -> startDiagramActivity(ShowWorkoutMapDiagramActivity.DIAGRAM_TYPE_HEIGHT));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void startDiagramActivity(String diagramType){
|
||||
ShowWorkoutMapDiagramActivity.DIAGRAM_TYPE= diagramType;
|
||||
startActivity(new Intent(ShowWorkoutActivity.this, ShowWorkoutMapDiagramActivity.class));
|
||||
}
|
||||
|
||||
|
||||
void openEditCommentDialog(final TextView change){
|
||||
final EditText editText= new EditText(this);
|
||||
editText.setText(workout.comment);
|
||||
@ -206,186 +175,6 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
||||
root.addView(v);
|
||||
}
|
||||
|
||||
void addDiagram(SampleConverter converter){
|
||||
LineChart chart= new LineChart(this);
|
||||
|
||||
converter.onCreate();
|
||||
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (WorkoutSample sample : samples) {
|
||||
// turn your data into Entry objects
|
||||
Entry e= new Entry((float)(sample.relativeTime) / 1000f / 60f, converter.getValue(sample));
|
||||
entries.add(e);
|
||||
converter.sampleGetsEntry(sample, e);
|
||||
}
|
||||
|
||||
LineDataSet dataSet = new LineDataSet(entries, converter.getName()); // add entries to dataset
|
||||
dataSet.setColor(getThemePrimaryColor());
|
||||
dataSet.setValueTextColor(getThemePrimaryColor());
|
||||
dataSet.setDrawCircles(false);
|
||||
dataSet.setLineWidth(4);
|
||||
dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
||||
|
||||
Description description= new Description();
|
||||
description.setText(converter.getDescription());
|
||||
|
||||
LineData lineData = new LineData(dataSet);
|
||||
chart.setData(lineData);
|
||||
chart.setScaleXEnabled(true);
|
||||
chart.setScaleYEnabled(false);
|
||||
chart.setDescription(description);
|
||||
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
|
||||
@Override
|
||||
public void onValueSelected(Entry e, Highlight h) {
|
||||
onNothingSelected();
|
||||
Paint p= AndroidGraphicFactory.INSTANCE.createPaint();
|
||||
p.setColor(Color.BLUE);
|
||||
highlightingCircle= new FixedPixelCircle(findSample(converter, e).toLatLong(), 10, p, null);
|
||||
map.addLayer(highlightingCircle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected() {
|
||||
if(highlightingCircle != null){
|
||||
map.getLayerManager().getLayers().remove(highlightingCircle);
|
||||
}
|
||||
}
|
||||
});
|
||||
chart.invalidate();
|
||||
|
||||
root.addView(chart, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getWindowManager().getDefaultDisplay().getWidth()*3/4));
|
||||
}
|
||||
|
||||
interface SampleConverter{
|
||||
void onCreate();
|
||||
float getValue(WorkoutSample sample);
|
||||
void sampleGetsEntry(WorkoutSample sample, Entry entry);
|
||||
String getName();
|
||||
String getDescription();
|
||||
boolean compare(WorkoutSample sample, Entry entry);
|
||||
}
|
||||
|
||||
void addHeightDiagram(){
|
||||
addDiagram(new SampleConverter() {
|
||||
@Override
|
||||
public void onCreate() { }
|
||||
|
||||
@Override
|
||||
public float getValue(WorkoutSample sample) {
|
||||
return (float)UnitUtils.CHOSEN_SYSTEM.getDistanceFromMeters(sample.elevation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sampleGetsEntry(WorkoutSample sample, Entry entry) {
|
||||
sample.tmpHeightEntry= entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getString(R.string.height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "min - " + UnitUtils.CHOSEN_SYSTEM.getShortDistanceUnit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compare(WorkoutSample sample, Entry entry) {
|
||||
return sample.tmpHeightEntry.equalTo(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void addSpeedDiagram(){
|
||||
addDiagram(new SampleConverter() {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
WorkoutManager.roundSpeedValues(samples);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getValue(WorkoutSample sample) {
|
||||
return (float)UnitUtils.CHOSEN_SYSTEM.getSpeedFromMeterPerSecond(sample.tmpRoundedSpeed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sampleGetsEntry(WorkoutSample sample, Entry entry) {
|
||||
sample.tmpSpeedEntry= entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getString(R.string.workoutSpeed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "min - " + UnitUtils.CHOSEN_SYSTEM.getSpeedUnit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compare(WorkoutSample sample, Entry entry) {
|
||||
return sample.tmpSpeedEntry.equalTo(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
WorkoutSample findSample(SampleConverter converter, Entry entry){
|
||||
for(WorkoutSample sample : samples){
|
||||
if(converter.compare(sample, entry)){
|
||||
return sample;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void addMap(){
|
||||
map= new MapView(this);
|
||||
downloadLayer= MapManager.setupMap(map, TileSources.Purpose.DEFAULT);
|
||||
|
||||
WorkoutLayer workoutLayer= new WorkoutLayer(samples, getThemePrimaryColor());
|
||||
map.addLayer(workoutLayer);
|
||||
|
||||
final BoundingBox bounds= new BoundingBox(workoutLayer.getLatLongs()).extendMeters(50);
|
||||
mHandler.postDelayed(() -> {
|
||||
map.getModel().mapViewPosition.setMapPosition(new MapPosition(bounds.getCenterPoint(),
|
||||
(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);
|
||||
|
||||
|
||||
Paint pGreen= AndroidGraphicFactory.INSTANCE.createPaint();
|
||||
pGreen.setColor(Color.GREEN);
|
||||
map.addLayer(new FixedPixelCircle(samples.get(0).toLatLong(), 20, pGreen, null));
|
||||
Paint pRed= AndroidGraphicFactory.INSTANCE.createPaint();
|
||||
pRed.setColor(Color.RED);
|
||||
map.addLayer(new FixedPixelCircle(samples.get(samples.size()-1).toLatLong(), 20, pRed, null));
|
||||
}
|
||||
|
||||
@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) {
|
||||
@ -394,17 +183,13 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void deleteWorkout(){
|
||||
public void deleteWorkout(){
|
||||
Instance.getInstance(this).db.workoutDao().deleteWorkout(workout);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void showDeleteDialog(){
|
||||
new AlertDialog.Builder(this).setTitle(R.string.deleteWorkout)
|
||||
.setMessage(R.string.deleteWorkoutMessage)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setPositiveButton(R.string.delete, (dialog, which) -> deleteWorkout())
|
||||
.create().show();
|
||||
DialogUtils.showDeleteWorkoutDialog(this, this);
|
||||
}
|
||||
|
||||
private void exportToGpx(){
|
||||
@ -438,9 +223,6 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
|
||||
case R.id.actionExportGpx:
|
||||
exportToGpx();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@ -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.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
|
||||
public class ShowWorkoutMapActivity extends WorkoutActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
initBeforeContent();
|
||||
|
||||
setContentView(R.layout.activity_show_workout_map);
|
||||
root= findViewById(R.id.showWorkoutMapParent);
|
||||
|
||||
initAfterContent();
|
||||
|
||||
fullScreenItems = true;
|
||||
addMap();
|
||||
|
||||
map.setClickable(true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.os.Bundle;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
|
||||
public class ShowWorkoutMapDiagramActivity extends WorkoutActivity {
|
||||
|
||||
public static final String DIAGRAM_TYPE_HEIGHT= "height";
|
||||
public static final String DIAGRAM_TYPE_SPEED= "speed";
|
||||
|
||||
static String DIAGRAM_TYPE;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
initBeforeContent();
|
||||
|
||||
setContentView(R.layout.activity_show_workout_map_diagram);
|
||||
root= findViewById(R.id.showWorkoutMapParent);
|
||||
|
||||
initAfterContent();
|
||||
|
||||
fullScreenItems = true;
|
||||
addMap();
|
||||
map.setClickable(true);
|
||||
|
||||
diagramsInteractive= true;
|
||||
root= findViewById(R.id.showWorkoutDiagramParent);
|
||||
switch (DIAGRAM_TYPE){
|
||||
case DIAGRAM_TYPE_HEIGHT: addHeightDiagram(); break;
|
||||
case DIAGRAM_TYPE_SPEED: addSpeedDiagram(); break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* 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.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.os.Handler;
|
||||
import android.view.MenuItem;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.components.Description;
|
||||
import com.github.mikephil.charting.data.Entry;
|
||||
import com.github.mikephil.charting.data.LineData;
|
||||
import com.github.mikephil.charting.data.LineDataSet;
|
||||
import com.github.mikephil.charting.highlight.Highlight;
|
||||
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
|
||||
|
||||
import org.mapsforge.core.graphics.Paint;
|
||||
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 org.mapsforge.map.layer.overlay.FixedPixelCircle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
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.WorkoutManager;
|
||||
import de.tadris.fitness.data.WorkoutSample;
|
||||
import de.tadris.fitness.map.MapManager;
|
||||
import de.tadris.fitness.map.WorkoutLayer;
|
||||
import de.tadris.fitness.map.tilesource.TileSources;
|
||||
import de.tadris.fitness.util.ThemeManager;
|
||||
import de.tadris.fitness.util.WorkoutTypeCalculator;
|
||||
import de.tadris.fitness.util.unit.UnitUtils;
|
||||
|
||||
public abstract class WorkoutActivity extends FitoTrackActivity {
|
||||
|
||||
public static Workout selectedWorkout;
|
||||
|
||||
protected List<WorkoutSample> samples;
|
||||
protected Workout workout;
|
||||
protected ViewGroup root;
|
||||
protected Resources.Theme theme;
|
||||
protected MapView map;
|
||||
protected TileDownloadLayer downloadLayer;
|
||||
protected FixedPixelCircle highlightingCircle;
|
||||
protected Handler mHandler= new Handler();
|
||||
|
||||
protected LineChart speedDiagram, heightDiagram;
|
||||
|
||||
protected void initBeforeContent(){
|
||||
workout= selectedWorkout;
|
||||
samples= Arrays.asList(Instance.getInstance(this).db.workoutDao().getAllSamplesOfWorkout(workout.id));
|
||||
setTheme(ThemeManager.getThemeByWorkout(workout));
|
||||
}
|
||||
|
||||
protected void initAfterContent(){
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setTitle(WorkoutTypeCalculator.getType(workout));
|
||||
|
||||
theme= getTheme();
|
||||
}
|
||||
|
||||
void addDiagram(SampleConverter converter){
|
||||
root.addView(getDiagram(converter), new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, fullScreenItems ? ViewGroup.LayoutParams.MATCH_PARENT : getWindowManager().getDefaultDisplay().getWidth()*3/4));
|
||||
}
|
||||
|
||||
protected boolean diagramsInteractive= false;
|
||||
|
||||
LineChart getDiagram(SampleConverter converter){
|
||||
LineChart chart= new LineChart(this);
|
||||
|
||||
converter.onCreate();
|
||||
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (WorkoutSample sample : samples) {
|
||||
// turn your data into Entry objects
|
||||
Entry e= new Entry((float)(sample.relativeTime) / 1000f / 60f, converter.getValue(sample));
|
||||
entries.add(e);
|
||||
converter.sampleGetsEntry(sample, e);
|
||||
}
|
||||
|
||||
LineDataSet dataSet = new LineDataSet(entries, converter.getName()); // add entries to dataset
|
||||
dataSet.setColor(getThemePrimaryColor());
|
||||
dataSet.setValueTextColor(getThemePrimaryColor());
|
||||
dataSet.setDrawCircles(false);
|
||||
dataSet.setLineWidth(4);
|
||||
dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
||||
|
||||
Description description= new Description();
|
||||
description.setText(converter.getDescription());
|
||||
|
||||
LineData lineData = new LineData(dataSet);
|
||||
chart.setData(lineData);
|
||||
chart.setScaleXEnabled(diagramsInteractive);
|
||||
chart.setScaleYEnabled(false);
|
||||
chart.setDescription(description);
|
||||
if(diagramsInteractive){
|
||||
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
|
||||
@Override
|
||||
public void onValueSelected(Entry e, Highlight h) {
|
||||
onNothingSelected();
|
||||
Paint p= AndroidGraphicFactory.INSTANCE.createPaint();
|
||||
p.setColor(0xff693cff);
|
||||
highlightingCircle= new FixedPixelCircle(findSample(converter, e).toLatLong(), 20, p, null);
|
||||
map.addLayer(highlightingCircle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected() {
|
||||
if(highlightingCircle != null){
|
||||
map.getLayerManager().getLayers().remove(highlightingCircle);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
chart.invalidate();
|
||||
|
||||
converter.afterAdd(chart);
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
interface SampleConverter{
|
||||
void onCreate();
|
||||
float getValue(WorkoutSample sample);
|
||||
void sampleGetsEntry(WorkoutSample sample, Entry entry);
|
||||
String getName();
|
||||
String getDescription();
|
||||
boolean compare(WorkoutSample sample, Entry entry);
|
||||
void afterAdd(LineChart chart);
|
||||
}
|
||||
|
||||
WorkoutSample findSample(SampleConverter converter, Entry entry){
|
||||
for(WorkoutSample sample : samples){
|
||||
if(converter.compare(sample, entry)){
|
||||
return sample;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void addHeightDiagram(){
|
||||
addDiagram(new SampleConverter() {
|
||||
@Override
|
||||
public void onCreate() { }
|
||||
|
||||
@Override
|
||||
public float getValue(WorkoutSample sample) {
|
||||
return (float) UnitUtils.CHOSEN_SYSTEM.getDistanceFromMeters(sample.elevation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sampleGetsEntry(WorkoutSample sample, Entry entry) {
|
||||
sample.tmpHeightEntry= entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getString(R.string.height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "min - " + UnitUtils.CHOSEN_SYSTEM.getShortDistanceUnit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compare(WorkoutSample sample, Entry entry) {
|
||||
return sample.tmpHeightEntry.equalTo(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAdd(LineChart chart) {
|
||||
heightDiagram= chart;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void addSpeedDiagram(){
|
||||
addDiagram(new SampleConverter() {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
WorkoutManager.roundSpeedValues(samples);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getValue(WorkoutSample sample) {
|
||||
return (float)UnitUtils.CHOSEN_SYSTEM.getSpeedFromMeterPerSecond(sample.tmpRoundedSpeed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sampleGetsEntry(WorkoutSample sample, Entry entry) {
|
||||
sample.tmpSpeedEntry= entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getString(R.string.workoutSpeed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "min - " + UnitUtils.CHOSEN_SYSTEM.getSpeedUnit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compare(WorkoutSample sample, Entry entry) {
|
||||
return sample.tmpSpeedEntry.equalTo(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAdd(LineChart chart) {
|
||||
speedDiagram= chart;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected boolean fullScreenItems = false;
|
||||
protected LinearLayout mapRoot;
|
||||
|
||||
void addMap(){
|
||||
map= new MapView(this);
|
||||
downloadLayer= MapManager.setupMap(map, TileSources.Purpose.DEFAULT);
|
||||
|
||||
WorkoutLayer workoutLayer= new WorkoutLayer(samples, getThemePrimaryColor());
|
||||
map.addLayer(workoutLayer);
|
||||
|
||||
final BoundingBox bounds= new BoundingBox(workoutLayer.getLatLongs()).extendMeters(50);
|
||||
mHandler.postDelayed(() -> {
|
||||
map.getModel().mapViewPosition.setMapPosition(new MapPosition(bounds.getCenterPoint(),
|
||||
(LatLongUtils.zoomForBounds(map.getDimension(), bounds, map.getModel().displayModel.getTileSize()))));
|
||||
map.animate().alpha(1f).setDuration(1000).start();
|
||||
}, 1000);
|
||||
|
||||
map.getModel().mapViewPosition.setMapLimit(bounds);
|
||||
|
||||
mapRoot= new LinearLayout(this);
|
||||
mapRoot.setOrientation(LinearLayout.VERTICAL);
|
||||
mapRoot.addView(map);
|
||||
|
||||
root.addView(mapRoot, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, fullScreenItems ? ViewGroup.LayoutParams.MATCH_PARENT : getMapHeight()));
|
||||
map.setAlpha(0);
|
||||
|
||||
|
||||
Paint pGreen= AndroidGraphicFactory.INSTANCE.createPaint();
|
||||
pGreen.setColor(Color.GREEN);
|
||||
map.addLayer(new FixedPixelCircle(samples.get(0).toLatLong(), 20, pGreen, null));
|
||||
Paint pRed= AndroidGraphicFactory.INSTANCE.createPaint();
|
||||
pRed.setColor(Color.RED);
|
||||
|
||||
map.addLayer(new FixedPixelCircle(samples.get(samples.size()-1).toLatLong(), 20, pRed, null));
|
||||
|
||||
map.setClickable(false);
|
||||
|
||||
}
|
||||
|
||||
int getMapHeight(){
|
||||
return getWindowManager().getDefaultDisplay().getWidth()*3/4;
|
||||
}
|
||||
|
||||
@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 onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if (id == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
}
|
||||
@ -35,4 +35,8 @@ public class UserPreferences {
|
||||
return preferences.getInt("weight", 80);
|
||||
}
|
||||
|
||||
public String getMapStyle(){
|
||||
return preferences.getString("mapStyle", "osm.mapnik");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -26,21 +26,24 @@ import org.mapsforge.map.android.view.MapView;
|
||||
import org.mapsforge.map.layer.cache.TileCache;
|
||||
import org.mapsforge.map.layer.download.TileDownloadLayer;
|
||||
|
||||
import de.tadris.fitness.Instance;
|
||||
import de.tadris.fitness.map.tilesource.FitoTrackTileSource;
|
||||
import de.tadris.fitness.map.tilesource.HumanitarianTileSource;
|
||||
import de.tadris.fitness.map.tilesource.MapnikTileSource;
|
||||
import de.tadris.fitness.map.tilesource.ThunderforestTileSource;
|
||||
import de.tadris.fitness.map.tilesource.TileSources;
|
||||
|
||||
public class MapManager {
|
||||
|
||||
public static TileDownloadLayer setupMap(MapView mapView, TileSources.Purpose purpose){
|
||||
FitoTrackTileSource tileSource;
|
||||
switch (purpose){
|
||||
/*case OUTDOOR: tileSource= ThunderforestTileSource.OUTDOORS; break;
|
||||
case CYCLING: tileSource= ThunderforestTileSource.CYLE_MAP; break;*/
|
||||
|
||||
case DEFAULT:
|
||||
default:
|
||||
tileSource= MapnikTileSource.INSTANCE; break;
|
||||
String chosenTileLayer= Instance.getInstance(mapView.getContext()).userPreferences.getMapStyle();
|
||||
switch (chosenTileLayer){
|
||||
case "osm.humanitarian": tileSource= HumanitarianTileSource.INSTANCE; break;
|
||||
case "thunderforest.outdoors": tileSource= ThunderforestTileSource.OUTDOORS; break;
|
||||
case "thunderforest.cycle": tileSource= ThunderforestTileSource.CYLE_MAP; break;
|
||||
default: tileSource= MapnikTileSource.INSTANCE; break; // Inclusive "osm.mapnik"
|
||||
}
|
||||
tileSource.setUserAgent("mapsforge-android");
|
||||
|
||||
|
||||
22
app/src/main/java/de/tadris/fitness/util/DialogUtils.java
Normal file
22
app/src/main/java/de/tadris/fitness/util/DialogUtils.java
Normal file
@ -0,0 +1,22 @@
|
||||
package de.tadris.fitness.util;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
|
||||
public class DialogUtils {
|
||||
|
||||
public static void showDeleteWorkoutDialog(Context context, WorkoutDeleter deleter){
|
||||
new AlertDialog.Builder(context).setTitle(R.string.deleteWorkout)
|
||||
.setMessage(R.string.deleteWorkoutMessage)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setPositiveButton(R.string.delete, (dialog, which) -> deleter.deleteWorkout())
|
||||
.create().show();
|
||||
}
|
||||
|
||||
public interface WorkoutDeleter{
|
||||
void deleteWorkout();
|
||||
}
|
||||
|
||||
}
|
||||
@ -29,7 +29,6 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
@ -59,6 +58,7 @@ public class Exporter {
|
||||
listener.onStatusChanged(10, context.getString(R.string.preferences));
|
||||
FitoTrackSettings settings= new FitoTrackSettings();
|
||||
settings.weight= preferences.getUserWeight();
|
||||
settings.mapStyle= preferences.getMapStyle();
|
||||
settings.preferredUnitSystem= String.valueOf(UnitUtils.CHOSEN_SYSTEM.getId());
|
||||
container.settings= settings;
|
||||
|
||||
@ -76,14 +76,14 @@ public class Exporter {
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
public static void importData(Context context, Uri input, ExportStatusListener listener) throws IOException{
|
||||
public static void importData(Context context, Uri input, ExportStatusListener listener) throws IOException, UnsupportedVersionException {
|
||||
listener.onStatusChanged(0, context.getString(R.string.loadingFile));
|
||||
XmlMapper xmlMapper = new XmlMapper();
|
||||
xmlMapper.configure(JsonParser.Feature.IGNORE_UNDEFINED, true);
|
||||
FitoTrackDataContainer container = xmlMapper.readValue(context.getContentResolver().openInputStream(input), FitoTrackDataContainer.class);
|
||||
|
||||
if(container.version != 1){
|
||||
throw new UnsupportedEncodingException("Version Code" + container.version + " is unsupported!");
|
||||
throw new UnsupportedVersionException("Version Code" + container.version + " is unsupported!");
|
||||
}
|
||||
|
||||
listener.onStatusChanged(40, context.getString(R.string.preferences));
|
||||
@ -91,10 +91,12 @@ public class Exporter {
|
||||
.edit().clear()
|
||||
.putInt("weight", container.settings.weight)
|
||||
.putString("unitSystem", container.settings.preferredUnitSystem)
|
||||
.putBoolean("firstStart", false)
|
||||
.putBoolean("firstStart", false).putString("mapStyle", container.settings.mapStyle)
|
||||
.commit();
|
||||
|
||||
AppDatabase database= Instance.getInstance(context).db;
|
||||
|
||||
database.runInTransaction(() -> {
|
||||
database.clearAllTables();
|
||||
|
||||
listener.onStatusChanged(60, context.getString(R.string.workouts));
|
||||
@ -110,6 +112,8 @@ public class Exporter {
|
||||
database.workoutDao().insertSample(sample);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
listener.onStatusChanged(100, context.getString(R.string.finished));
|
||||
}
|
||||
|
||||
@ -1,15 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
* FitoTrack is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FitoTrack is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.util.export;
|
||||
|
||||
public class FitoTrackSettings {
|
||||
|
||||
String preferredUnitSystem;
|
||||
int weight;
|
||||
String mapStyle;
|
||||
|
||||
public FitoTrackSettings(){}
|
||||
|
||||
public FitoTrackSettings(String preferredUnitSystem, int weight) {
|
||||
public FitoTrackSettings(String preferredUnitSystem, int weight, String mapStyle) {
|
||||
this.preferredUnitSystem = preferredUnitSystem;
|
||||
this.weight = weight;
|
||||
this.mapStyle = mapStyle;
|
||||
}
|
||||
|
||||
public String getPreferredUnitSystem() {
|
||||
@ -27,4 +48,12 @@ public class FitoTrackSettings {
|
||||
public void setWeight(int weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public String getMapStyle() {
|
||||
return mapStyle;
|
||||
}
|
||||
|
||||
public void setMapStyle(String mapStyle) {
|
||||
this.mapStyle = mapStyle;
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,6 +87,10 @@ public class WorkoutAdapter extends RecyclerView.Adapter<WorkoutAdapter.WorkoutV
|
||||
holder.lengthText.setText(UnitUtils.getDistance(workout.length));
|
||||
holder.timeText.setText(UnitUtils.getHourMinuteTime(workout.duration));
|
||||
holder.root.setOnClickListener(v -> listener.onItemClick(workout));
|
||||
holder.root.setOnLongClickListener(v -> {
|
||||
listener.onItemLongClick(position, workout);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// Return the size of your dataset (invoked by the layout manager)
|
||||
@ -97,6 +101,7 @@ public class WorkoutAdapter extends RecyclerView.Adapter<WorkoutAdapter.WorkoutV
|
||||
|
||||
public interface WorkoutAdapterListener{
|
||||
void onItemClick(Workout workout);
|
||||
void onItemLongClick(int pos, Workout workout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
11
app/src/main/res/drawable-anydpi/ic_gps_no_fix.xml
Normal file
11
app/src/main/res/drawable-anydpi/ic_gps_no_fix.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFF"
|
||||
android:alpha="0.8">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94V1h-2v2.06C6.83,3.52 3.52,6.83 3.06,11H1v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94V23h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94H23v-2h-2.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
|
||||
</vector>
|
||||
BIN
app/src/main/res/drawable-hdpi/ic_gps_no_fix.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_gps_no_fix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 358 B |
BIN
app/src/main/res/drawable-mdpi/ic_gps_no_fix.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_gps_no_fix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 247 B |
BIN
app/src/main/res/drawable-xhdpi/ic_gps_no_fix.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_gps_no_fix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 439 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_gps_no_fix.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_gps_no_fix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 670 B |
@ -197,4 +197,34 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/recorderWaitingOverlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/holo_red_light">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
android:src="@drawable/ic_gps_no_fix" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="20dp"
|
||||
android:text="@string/waiting_gps"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/background_light"
|
||||
android:textSize="30sp" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
@ -18,16 +18,25 @@
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/showWorkoutSceneRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activity.ShowWorkoutActivity">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/showWorkoutDefaultSceneRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/showWorkoutRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="20dp"></LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
37
app/src/main/res/layout/activity_show_workout_map.xml
Normal file
37
app/src/main/res/layout/activity_show_workout_map.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/showWorkoutMapRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".activity.ShowWorkoutMapActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/showWorkoutMapParent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,63 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/showWorkoutMapRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".activity.ShowWorkoutMapActivity" >
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline4"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintGuide_percent="0.6"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/showWorkoutMapParent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline4"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/showWorkoutDiagramParent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline4"></LinearLayout>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
30
app/src/main/res/values-de/map_layers.xml
Normal file
30
app/src/main/res/values-de/map_layers.xml
Normal file
@ -0,0 +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/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<string-array name="pref_map_layers">
|
||||
<item>Mapnik\nStandard OSM Kartenstil</item>
|
||||
<item>Humanitarian\nSchöne Karte, aber manchmal nicht verfügbar</item>
|
||||
<item>Outdoors\nLimitierter Zugriff</item>
|
||||
<item>Cyclemap\nLimitierter Zugriff</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
@ -94,4 +94,6 @@
|
||||
<string name="noGpsMessage">Bitte aktiviere GPS, damit dein Workout aufgezeichnet werden kann.</string>
|
||||
<string name="workoutAscent">Aufstieg</string>
|
||||
<string name="workoutDescent">Abstieg</string>
|
||||
<string name="data">Daten</string>
|
||||
<string name="mapStyle">Kartenstil</string>
|
||||
</resources>
|
||||
37
app/src/main/res/values/map_layers.xml
Normal file
37
app/src/main/res/values/map_layers.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?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>
|
||||
|
||||
<string-array name="pref_map_layers">
|
||||
<item>Mapnik\nDefault OSM Mapstyle</item>
|
||||
<item>Humanitarian\nClean map but sometimes not available</item>
|
||||
<item>Outdoors\nLimited access</item>
|
||||
<item>Cyclemap\nLimited access</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_map_layers_values">
|
||||
<item>osm.mapnik</item>
|
||||
<item>osm.humanitarian</item>
|
||||
<item>thunderforest.outdoors</item>
|
||||
<item>thunderforest.cycle</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
@ -112,4 +112,7 @@
|
||||
<string name="importBackup">Import Data Backup</string>
|
||||
<string name="importBackupSummary">Restore a taken backup</string>
|
||||
<string name="gps">GPS</string>
|
||||
<string name="data">Data</string>
|
||||
<string name="mapStyle">Map Style</string>
|
||||
<string name="waiting_gps">Waiting for GPS</string>
|
||||
</resources>
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
|
||||
<string-array name="pref_unit_systems">
|
||||
<item>Metric</item>
|
||||
<item>Metric Physical (m/s)</item>
|
||||
<item>Metric with m/s</item>
|
||||
<item>Imperial</item>
|
||||
<item>Imperial with meters</item>
|
||||
</string-array>
|
||||
|
||||
@ -1,11 +1,31 @@
|
||||
<?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/>.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/pref_unit_systems"
|
||||
android:entryValues="@array/pref_unit_system_values"
|
||||
android:key="unitSystem"
|
||||
android:title="@string/pref_unit_system" />
|
||||
android:title="@string/pref_unit_system"
|
||||
android:defaultValue="1" />
|
||||
|
||||
<Preference
|
||||
android:key="weight"
|
||||
@ -14,6 +34,16 @@
|
||||
android:summary="@string/pref_weight_summary"
|
||||
android:title="@string/pref_weight" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="osm.mapnik"
|
||||
android:entries="@array/pref_map_layers"
|
||||
android:entryValues="@array/pref_map_layers_values"
|
||||
android:key="mapStyle"
|
||||
android:title="@string/mapStyle" />
|
||||
|
||||
|
||||
<PreferenceCategory android:title="@string/data">
|
||||
|
||||
<Preference
|
||||
android:key="import"
|
||||
android:summary="@string/importBackupSummary"
|
||||
@ -22,6 +52,7 @@
|
||||
android:key="export"
|
||||
android:summary="@string/exportDataSummary"
|
||||
android:title="@string/exportData" />
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
</PreferenceScreen>
|
||||
6
metadata/en-US/changelogs/200.txt
Normal file
6
metadata/en-US/changelogs/200.txt
Normal file
@ -0,0 +1,6 @@
|
||||
**2.0:**
|
||||
- Screen to compare height/elevation diagram and the map
|
||||
- Show overlay if GPS signal wasn't found yet
|
||||
- Set preferred map layer (#15)
|
||||
|
||||
- Speed up data import
|
||||
Loading…
x
Reference in New Issue
Block a user