Better layout for workout map and diagrams

This commit is contained in:
jannis 2019-09-02 20:37:23 +02:00
parent ec73699411
commit b8a0012f7d
7 changed files with 547 additions and 297 deletions

View File

@ -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>

View File

@ -20,101 +20,42 @@
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.transition.Scene;
import android.transition.TransitionManager;
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.LinearLayout;
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.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 {
List<WorkoutSample> samples;
Workout workout;
ViewGroup root;
Resources.Theme theme;
MapView map;
TileDownloadLayer downloadLayer;
FixedPixelCircle highlightingCircle;
Handler mHandler= new Handler();
Scene sceneOverview;
Scene speedDiagramScene;
Scene heightDiagramScene;
Scene mapScene;
LineChart speedDiagram;
LineChart heightDiagram;
ViewGroup sceneRoot;
@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);
sceneRoot= findViewById(R.id.showWorkoutSceneRoot);
ViewGroup sceneLayout= findViewById(R.id.showWorkoutDefaultSceneRoot);
sceneOverview= new Scene(sceneRoot, sceneLayout);
initAfterContent();
addText(getString(R.string.comment) + ": " + workout.comment).setOnClickListener(v -> {
TextView textView= (TextView)v;
@ -134,6 +75,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),
@ -141,6 +85,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)));
@ -152,23 +98,16 @@ public class ShowWorkoutActivity extends FitoTrackActivity {
addHeightDiagram();
createScenes();
heightDiagram.setOnClickListener(v -> startDiagramActivity(ShowWorkoutMapDiagramActivity.DIAGRAM_TYPE_HEIGHT));
}
void createScenes(){
speedDiagramScene= createDiagramScene(speedDiagram);
heightDiagramScene= createDiagramScene(heightDiagram);
mapScene= new Scene(sceneRoot, map);
void startDiagramActivity(String diagramType){
ShowWorkoutMapDiagramActivity.DIAGRAM_TYPE= diagramType;
startActivity(new Intent(ShowWorkoutActivity.this, ShowWorkoutMapDiagramActivity.class));
}
Scene createDiagramScene(LineChart chart){
LinearLayout layout= new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(map, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getMapHeight()));
layout.addView(chart, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return new Scene(sceneRoot, layout);
}
void openEditCommentDialog(final TextView change){
final EditText editText= new EditText(this);
@ -235,219 +174,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();
converter.afterAdd(chart);
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 afterAdd(LineChart chart);
}
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;
heightDiagram.setOnClickListener(v -> TransitionManager.go(heightDiagramScene));
}
});
}
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;
heightDiagram.setOnClickListener(v -> TransitionManager.go(speedDiagramScene));
}
});
}
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, 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.setOnClickListener(v -> goToMapScene());
goToMapScene();
}
private void goToMapScene(){
TransitionManager.go(mapScene);
map.setOnClickListener(null);
}
private void leaveMapScene(){
TransitionManager.go(sceneOverview);
map.setOnClickListener(v -> goToMapScene());
}
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 onCreateOptionsMenu(Menu menu) {
@ -500,9 +226,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);
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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(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();
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);
}
}

View 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>

View File

@ -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>