mirror of
https://github.com/russok/FitoTrack.git
synced 2025-10-28 00:02:11 -07:00
Merge branch 'feature-manual-workouts'
# Conflicts: # app/src/main/AndroidManifest.xml
This commit is contained in:
commit
a336015818
@ -73,7 +73,7 @@ dependencies {
|
||||
implementation 'org.mapsforge:mapsforge-map-android:0.11.0'
|
||||
implementation 'com.caverock:androidsvg:1.3'
|
||||
|
||||
// Charts
|
||||
// UI
|
||||
implementation 'net.sf.kxml:kxml2:2.3.0'
|
||||
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
|
||||
implementation 'com.github.clans:fab:1.6.4'
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity android:name=".activity.VoiceAnnouncementsSettingsActivity" />
|
||||
<activity android:name=".activity.SettingsActivity" />
|
||||
<activity android:name=".activity.EnterWorkoutActivity"/>
|
||||
<activity
|
||||
android:name=".activity.ShowWorkoutMapActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
@ -60,7 +60,7 @@ public class Instance {
|
||||
.addMigrations(new Migration(1, 2) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
try{
|
||||
try {
|
||||
database.beginTransaction();
|
||||
|
||||
database.execSQL("ALTER table workout add descent REAL NOT NULL DEFAULT 0;");
|
||||
@ -85,7 +85,20 @@ public class Instance {
|
||||
database.execSQL("DROP TABLE workout_sample2");
|
||||
|
||||
database.setTransactionSuccessful();
|
||||
}finally {
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
}
|
||||
}
|
||||
}, new Migration(2, 3) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
try {
|
||||
database.beginTransaction();
|
||||
|
||||
database.execSQL("ALTER table workout add COLUMN edited INTEGER not null default 0");
|
||||
|
||||
database.setTransactionSuccessful();
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.util.TypedValue;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
import de.tadris.fitness.data.WorkoutBuilder;
|
||||
import de.tadris.fitness.data.WorkoutType;
|
||||
import de.tadris.fitness.dialog.DatePickerFragment;
|
||||
import de.tadris.fitness.dialog.DurationPickerDialogFragment;
|
||||
import de.tadris.fitness.dialog.SelectWorkoutTypeDialog;
|
||||
import de.tadris.fitness.dialog.TimePickerFragment;
|
||||
import de.tadris.fitness.util.unit.UnitUtils;
|
||||
|
||||
public class EnterWorkoutActivity extends InformationActivity implements SelectWorkoutTypeDialog.WorkoutTypeSelectListener, DatePickerFragment.DatePickerCallback, TimePickerFragment.TimePickerCallback, DurationPickerDialogFragment.DurationPickListener {
|
||||
|
||||
WorkoutBuilder workoutBuilder = new WorkoutBuilder();
|
||||
TextView typeTextView, dateTextView, timeTextView, durationTextView;
|
||||
EditText distanceEditText, commentEditText;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_enter_workout);
|
||||
|
||||
initRoot();
|
||||
|
||||
addTitle(getString(R.string.info));
|
||||
setupActionBar();
|
||||
|
||||
KeyValueLine typeLine = addKeyValueLine(getString(R.string.type));
|
||||
typeTextView = typeLine.value;
|
||||
typeLine.lineRoot.setOnClickListener(v -> showTypeSelection());
|
||||
|
||||
distanceEditText = new EditText(this);
|
||||
distanceEditText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||
distanceEditText.setSingleLine(true);
|
||||
distanceEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
|
||||
distanceEditText.setOnEditorActionListener((v, actionId, event) -> {
|
||||
// If the User clicks on the finish button on the keyboard, continue by showing the date selection
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
|
||||
actionId == EditorInfo.IME_ACTION_DONE ||
|
||||
event != null &&
|
||||
event.getAction() == KeyEvent.ACTION_DOWN &&
|
||||
event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
|
||||
if (event == null || !event.isShiftPressed()) {
|
||||
showDateSelection();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
addKeyValueLine(getString(R.string.workoutDistance), distanceEditText, UnitUtils.CHOSEN_SYSTEM.getLongDistanceUnit());
|
||||
|
||||
|
||||
KeyValueLine dateLine = addKeyValueLine(getString(R.string.workoutDate));
|
||||
dateLine.lineRoot.setOnClickListener(v -> showDateSelection());
|
||||
dateTextView = dateLine.value;
|
||||
|
||||
KeyValueLine timeLine = addKeyValueLine(getString(R.string.workoutStartTime));
|
||||
timeLine.lineRoot.setOnClickListener(v -> showTimeSelection());
|
||||
timeTextView = timeLine.value;
|
||||
|
||||
KeyValueLine durationLine = addKeyValueLine(getString(R.string.workoutDuration));
|
||||
durationLine.lineRoot.setOnClickListener(v -> showDurationSelection());
|
||||
durationTextView = durationLine.value;
|
||||
|
||||
addTitle(getString(R.string.custom));
|
||||
|
||||
commentEditText = new EditText(this);
|
||||
commentEditText.setSingleLine(true);
|
||||
root.addView(commentEditText);
|
||||
|
||||
updateTextViews();
|
||||
}
|
||||
|
||||
private void saveWorkout() {
|
||||
workoutBuilder.setComment(commentEditText.getText().toString());
|
||||
try {
|
||||
workoutBuilder.setLength((int) (Double.parseDouble(distanceEditText.getText().toString()) * 1000));
|
||||
} catch (NumberFormatException ignored) {
|
||||
distanceEditText.requestFocus();
|
||||
distanceEditText.setError(getString(R.string.errorEnterValidNumber));
|
||||
return;
|
||||
}
|
||||
if (workoutBuilder.getStart().getTimeInMillis() > System.currentTimeMillis()) {
|
||||
Toast.makeText(this, R.string.errorWorkoutAddFuture, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
if (workoutBuilder.getDuration() < 1000) {
|
||||
Toast.makeText(this, R.string.errorEnterValidDuration, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
ShowWorkoutActivity.selectedWorkout = workoutBuilder.insertWorkout(this);
|
||||
startActivity(new Intent(this, ShowWorkoutActivity.class));
|
||||
finish();
|
||||
}
|
||||
|
||||
private void updateTextViews() {
|
||||
typeTextView.setText(getString(workoutBuilder.getWorkoutType().title));
|
||||
dateTextView.setText(SimpleDateFormat.getDateInstance().format(workoutBuilder.getStart().getTime()));
|
||||
timeTextView.setText(SimpleDateFormat.getTimeInstance().format(workoutBuilder.getStart().getTime()));
|
||||
durationTextView.setText(UnitUtils.getHourMinuteTime(workoutBuilder.getDuration()));
|
||||
}
|
||||
|
||||
private void showTypeSelection() {
|
||||
new SelectWorkoutTypeDialog(this, this).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectWorkoutType(WorkoutType workoutType) {
|
||||
workoutBuilder.setWorkoutType(workoutType);
|
||||
updateTextViews();
|
||||
distanceEditText.requestFocus();
|
||||
}
|
||||
|
||||
private void showDateSelection() {
|
||||
DatePickerFragment fragment = new DatePickerFragment();
|
||||
fragment.callback = this;
|
||||
fragment.show(getFragmentManager(), "datePicker");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDatePick(int year, int month, int day) {
|
||||
workoutBuilder.getStart().set(year, month, day);
|
||||
updateTextViews();
|
||||
showTimeSelection();
|
||||
}
|
||||
|
||||
private void showTimeSelection() {
|
||||
TimePickerFragment fragment = new TimePickerFragment();
|
||||
fragment.callback = this;
|
||||
fragment.show(getFragmentManager(), "timePicker");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimePick(int hour, int minute) {
|
||||
workoutBuilder.getStart().set(Calendar.HOUR_OF_DAY, hour);
|
||||
workoutBuilder.getStart().set(Calendar.MINUTE, minute);
|
||||
workoutBuilder.getStart().set(Calendar.SECOND, 0);
|
||||
updateTextViews();
|
||||
showDurationSelection();
|
||||
}
|
||||
|
||||
private void showDurationSelection() {
|
||||
DurationPickerDialogFragment fragment = new DurationPickerDialogFragment(this, this, workoutBuilder.getDuration());
|
||||
fragment.listener = this;
|
||||
fragment.initialDuration = workoutBuilder.getDuration();
|
||||
fragment.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDurationPick(long duration) {
|
||||
workoutBuilder.setDuration(duration);
|
||||
updateTextViews();
|
||||
commentEditText.requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.enter_workout_menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
switch (id) {
|
||||
case R.id.actionEnterWorkoutAdd:
|
||||
saveWorkout();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void setupActionBar() {
|
||||
if (getActionBar() != null) {
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void initRoot() {
|
||||
root = findViewById(R.id.enterWorkoutRoot);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.graphics.Typeface;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
|
||||
public abstract class InformationActivity extends FitoTrackActivity {
|
||||
|
||||
ViewGroup root;
|
||||
|
||||
protected void addTitle(String title) {
|
||||
TextView textView = new TextView(this);
|
||||
textView.setText(title);
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||
textView.setTextColor(getThemePrimaryColor());
|
||||
textView.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
textView.setAllCaps(true);
|
||||
textView.setPadding(0, 20, 0, 0);
|
||||
|
||||
root.addView(textView);
|
||||
}
|
||||
|
||||
protected TextView addText(String text, boolean themeColor) {
|
||||
TextView textView = createTextView(text, themeColor);
|
||||
root.addView(textView);
|
||||
|
||||
return textView;
|
||||
}
|
||||
|
||||
protected TextView createTextView(String text) {
|
||||
return createTextView(text, false);
|
||||
}
|
||||
|
||||
protected TextView createTextView(String text, boolean themeColor) {
|
||||
TextView textView = new TextView(this);
|
||||
textView.setText(text);
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||
if (themeColor) {
|
||||
textView.setTextColor(getThemePrimaryColor());
|
||||
} else {
|
||||
textView.setTextColor(getResources().getColor(R.color.textLighterBlack));
|
||||
}
|
||||
textView.setPadding(0, 20, 0, 0);
|
||||
|
||||
return textView;
|
||||
}
|
||||
|
||||
protected void addKeyValue(String key1, String value1) {
|
||||
addKeyValue(key1, value1, "", "");
|
||||
}
|
||||
|
||||
protected void addKeyValue(String key1, String value1, String key2, String value2) {
|
||||
View v = getLayoutInflater().inflate(R.layout.show_entry, root, false);
|
||||
|
||||
TextView title1 = v.findViewById(R.id.v1title);
|
||||
TextView title2 = v.findViewById(R.id.v2title);
|
||||
TextView v1 = v.findViewById(R.id.v1value);
|
||||
TextView v2 = v.findViewById(R.id.v2value);
|
||||
|
||||
title1.setText(key1);
|
||||
title2.setText(key2);
|
||||
v1.setText(value1);
|
||||
v2.setText(value2);
|
||||
|
||||
root.addView(v);
|
||||
}
|
||||
|
||||
protected KeyValueLine addKeyValueLine(String key) {
|
||||
return addKeyValueLine(key, "");
|
||||
}
|
||||
|
||||
protected KeyValueLine addKeyValueLine(String key, String value) {
|
||||
return addKeyValueLine(key, null, value);
|
||||
}
|
||||
|
||||
protected KeyValueLine addKeyValueLine(String key, @Nullable View view) {
|
||||
return addKeyValueLine(key, view, "");
|
||||
}
|
||||
|
||||
protected KeyValueLine addKeyValueLine(String key, @Nullable View view, String value) {
|
||||
View v = getLayoutInflater().inflate(R.layout.enter_workout_line, root, false);
|
||||
|
||||
TextView keyView = v.findViewById(R.id.lineKey);
|
||||
TextView valueView = v.findViewById(R.id.lineValue);
|
||||
LinearLayout customViewRoot = v.findViewById(R.id.lineViewRoot);
|
||||
|
||||
keyView.setText(key);
|
||||
valueView.setText(value);
|
||||
|
||||
if (view != null) {
|
||||
customViewRoot.addView(view);
|
||||
}
|
||||
|
||||
root.addView(v);
|
||||
return new KeyValueLine(v, keyView, valueView, view);
|
||||
}
|
||||
|
||||
public static class KeyValueLine {
|
||||
public View lineRoot;
|
||||
public TextView key;
|
||||
public TextView value;
|
||||
public View customView;
|
||||
|
||||
public KeyValueLine(View lineRoot, TextView key, TextView value, View customView) {
|
||||
this.lineRoot = lineRoot;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.customView = customView;
|
||||
}
|
||||
}
|
||||
|
||||
abstract void initRoot();
|
||||
|
||||
|
||||
}
|
||||
@ -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.data.WorkoutType;
|
||||
import de.tadris.fitness.util.DialogUtils;
|
||||
import de.tadris.fitness.view.WorkoutAdapter;
|
||||
|
||||
@ -63,16 +64,17 @@ public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.Wor
|
||||
menu= findViewById(R.id.workoutListMenu);
|
||||
menu.setOnMenuButtonLongClickListener(v -> {
|
||||
if(workouts.length > 0){
|
||||
startRecording(workouts[0].workoutType);
|
||||
startRecording(workouts[0].getWorkoutType());
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.workoutListRecordRunning).setOnClickListener(v -> startRecording(Workout.WORKOUT_TYPE_RUNNING));
|
||||
findViewById(R.id.workoutListRecordHiking) .setOnClickListener(v -> startRecording(Workout.WORKOUT_TYPE_HIKING));
|
||||
findViewById(R.id.workoutListRecordCycling).setOnClickListener(v -> startRecording(Workout.WORKOUT_TYPE_CYCLING));
|
||||
findViewById(R.id.workoutListRecordRunning).setOnClickListener(v -> startRecording(WorkoutType.RUNNING));
|
||||
findViewById(R.id.workoutListRecordHiking).setOnClickListener(v -> startRecording(WorkoutType.HIKING));
|
||||
findViewById(R.id.workoutListRecordCycling).setOnClickListener(v -> startRecording(WorkoutType.CYCLING));
|
||||
findViewById(R.id.workoutListEnter).setOnClickListener(v -> startEnterWorkoutActivity());
|
||||
|
||||
checkFirstStart();
|
||||
|
||||
@ -92,7 +94,13 @@ public class ListWorkoutsActivity extends Activity implements WorkoutAdapter.Wor
|
||||
}
|
||||
}
|
||||
|
||||
private void startRecording(String activity) {
|
||||
private void startEnterWorkoutActivity() {
|
||||
menu.close(true);
|
||||
final Intent intent = new Intent(this, EnterWorkoutActivity.class);
|
||||
new Handler().postDelayed(() -> startActivity(intent), 300);
|
||||
}
|
||||
|
||||
private void startRecording(WorkoutType activity) {
|
||||
menu.close(true);
|
||||
RecordWorkoutActivity.ACTIVITY= activity;
|
||||
final Intent intent= new Intent(this, RecordWorkoutActivity.class);
|
||||
|
||||
@ -54,20 +54,18 @@ import java.util.List;
|
||||
|
||||
import de.tadris.fitness.Instance;
|
||||
import de.tadris.fitness.R;
|
||||
import de.tadris.fitness.announcement.AnnouncementGPSStatus;
|
||||
import de.tadris.fitness.announcement.VoiceAnnouncements;
|
||||
import de.tadris.fitness.data.Workout;
|
||||
import de.tadris.fitness.data.WorkoutType;
|
||||
import de.tadris.fitness.map.MapManager;
|
||||
import de.tadris.fitness.map.tilesource.TileSources;
|
||||
import de.tadris.fitness.recording.LocationListener;
|
||||
import de.tadris.fitness.recording.PressureService;
|
||||
import de.tadris.fitness.recording.WorkoutRecorder;
|
||||
import de.tadris.fitness.util.ThemeManager;
|
||||
import de.tadris.fitness.recording.announcement.AnnouncementGPSStatus;
|
||||
import de.tadris.fitness.recording.announcement.VoiceAnnouncements;
|
||||
import de.tadris.fitness.util.unit.UnitUtils;
|
||||
|
||||
public class RecordWorkoutActivity extends FitoTrackActivity implements LocationListener.LocationChangeListener, WorkoutRecorder.WorkoutRecorderListener, VoiceAnnouncements.VoiceAnnouncementCallback {
|
||||
|
||||
public static String ACTIVITY= Workout.WORKOUT_TYPE_RUNNING;
|
||||
public static WorkoutType ACTIVITY = WorkoutType.OTHER;
|
||||
|
||||
private MapView mapView;
|
||||
private TileDownloadLayer downloadLayer;
|
||||
@ -91,7 +89,7 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTheme(ThemeManager.getThemeByWorkoutType(ACTIVITY));
|
||||
setTheme(ACTIVITY.theme);
|
||||
setContentView(R.layout.activity_record_workout);
|
||||
|
||||
setTitle(R.string.recordWorkout);
|
||||
@ -149,13 +147,7 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
|
||||
|
||||
private void setupMap(){
|
||||
this.mapView= new MapView(this);
|
||||
TileSources.Purpose purpose;
|
||||
if(ACTIVITY.equals(Workout.WORKOUT_TYPE_CYCLING)){
|
||||
purpose= TileSources.Purpose.CYCLING;
|
||||
}else{
|
||||
purpose= TileSources.Purpose.OUTDOOR;
|
||||
}
|
||||
downloadLayer= MapManager.setupMap(mapView, purpose);
|
||||
downloadLayer = MapManager.setupMap(mapView);
|
||||
}
|
||||
|
||||
private void updateLine(){
|
||||
|
||||
@ -40,9 +40,9 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
import de.tadris.fitness.announcement.VoiceAnnouncements;
|
||||
import de.tadris.fitness.export.BackupController;
|
||||
import de.tadris.fitness.export.RestoreController;
|
||||
import de.tadris.fitness.recording.announcement.VoiceAnnouncements;
|
||||
import de.tadris.fitness.util.FileUtils;
|
||||
import de.tadris.fitness.util.unit.UnitUtils;
|
||||
import de.tadris.fitness.view.ProgressDialogController;
|
||||
|
||||
@ -21,13 +21,10 @@ package de.tadris.fitness.activity;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
@ -66,11 +63,15 @@ public class ShowWorkoutActivity extends WorkoutActivity implements DialogUtils.
|
||||
initBeforeContent();
|
||||
|
||||
setContentView(R.layout.activity_show_workout);
|
||||
root= findViewById(R.id.showWorkoutRoot);
|
||||
initRoot();
|
||||
|
||||
initAfterContent();
|
||||
|
||||
commentView = addText(getString(R.string.comment) + ": " + workout.comment);
|
||||
String commentStr = getString(R.string.comment) + ": " + workout.comment;
|
||||
if (workout.edited) {
|
||||
commentStr = getString(R.string.workoutEdited) + "\n" + commentStr;
|
||||
}
|
||||
commentView = addText(commentStr, true);
|
||||
commentView.setOnClickListener(v -> openEditCommentDialog());
|
||||
|
||||
addTitle(getString(R.string.workoutTime));
|
||||
@ -82,34 +83,43 @@ public class ShowWorkoutActivity extends WorkoutActivity implements DialogUtils.
|
||||
|
||||
addKeyValue(getString(R.string.workoutDistance), UnitUtils.getDistance(workout.length), getString(R.string.workoutPace), UnitUtils.getPace(workout.avgPace));
|
||||
|
||||
addTitle(getString(R.string.workoutRoute));
|
||||
if (hasSamples()) {
|
||||
addTitle(getString(R.string.workoutRoute));
|
||||
|
||||
addMap();
|
||||
addMap();
|
||||
|
||||
map.setClickable(false);
|
||||
mapRoot.setOnClickListener(v -> startActivity(new Intent(ShowWorkoutActivity.this, ShowWorkoutMapActivity.class)));
|
||||
|
||||
}
|
||||
|
||||
map.setClickable(false);
|
||||
mapRoot.setOnClickListener(v -> startActivity(new Intent(ShowWorkoutActivity.this, ShowWorkoutMapActivity.class)));
|
||||
|
||||
addTitle(getString(R.string.workoutSpeed));
|
||||
|
||||
addKeyValue(getString(R.string.workoutAvgSpeedShort), UnitUtils.getSpeed(workout.avgSpeed),
|
||||
getString(R.string.workoutTopSpeed), UnitUtils.getSpeed(workout.topSpeed));
|
||||
|
||||
addSpeedDiagram();
|
||||
if (hasSamples()) {
|
||||
|
||||
speedDiagram.setOnClickListener(v -> startDiagramActivity(ShowWorkoutMapDiagramActivity.DIAGRAM_TYPE_SPEED));
|
||||
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)));
|
||||
|
||||
addTitle(getString(R.string.height));
|
||||
if (hasSamples()) {
|
||||
addTitle(getString(R.string.height));
|
||||
|
||||
addKeyValue(getString(R.string.workoutAscent), UnitUtils.getDistance((int)workout.ascent),
|
||||
getString(R.string.workoutDescent), UnitUtils.getDistance((int)workout.descent));
|
||||
addKeyValue(getString(R.string.workoutAscent), UnitUtils.getDistance((int) workout.ascent),
|
||||
getString(R.string.workoutDescent), UnitUtils.getDistance((int) workout.descent));
|
||||
|
||||
addHeightDiagram();
|
||||
addHeightDiagram();
|
||||
|
||||
heightDiagram.setOnClickListener(v -> startDiagramActivity(ShowWorkoutMapDiagramActivity.DIAGRAM_TYPE_HEIGHT));
|
||||
heightDiagram.setOnClickListener(v -> startDiagramActivity(ShowWorkoutMapDiagramActivity.DIAGRAM_TYPE_HEIGHT));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -141,51 +151,6 @@ public class ShowWorkoutActivity extends WorkoutActivity implements DialogUtils.
|
||||
}
|
||||
|
||||
|
||||
private void addTitle(String title) {
|
||||
TextView textView= new TextView(this);
|
||||
textView.setText(title);
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||
textView.setTextColor(getThemePrimaryColor());
|
||||
textView.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
textView.setAllCaps(true);
|
||||
textView.setPadding(0, 20, 0, 0);
|
||||
|
||||
root.addView(textView);
|
||||
}
|
||||
|
||||
private TextView addText(String text) {
|
||||
TextView textView= new TextView(this);
|
||||
textView.setText(text);
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||
textView.setTextColor(getThemePrimaryColor());
|
||||
textView.setPadding(0, 20, 0, 0);
|
||||
|
||||
root.addView(textView);
|
||||
|
||||
return textView;
|
||||
}
|
||||
|
||||
private void addKeyValue(String key1, String value1) {
|
||||
addKeyValue(key1, value1, "", "");
|
||||
}
|
||||
|
||||
private void addKeyValue(String key1, String value1, String key2, String value2) {
|
||||
View v= getLayoutInflater().inflate(R.layout.show_entry, root, false);
|
||||
|
||||
TextView title1= v.findViewById(R.id.v1title);
|
||||
TextView title2= v.findViewById(R.id.v2title);
|
||||
TextView v1= v.findViewById(R.id.v1value);
|
||||
TextView v2= v.findViewById(R.id.v2value);
|
||||
|
||||
title1.setText(key1);
|
||||
title2.setText(key2);
|
||||
v1.setText(value1);
|
||||
v2.setText(value2);
|
||||
|
||||
root.addView(v);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
@ -299,4 +264,8 @@ public class ShowWorkoutActivity extends WorkoutActivity implements DialogUtils.
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
void initRoot() {
|
||||
root = findViewById(R.id.showWorkoutRoot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
* Copyright (c) 2020 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
@ -32,7 +32,7 @@ public class ShowWorkoutMapActivity extends WorkoutActivity {
|
||||
initBeforeContent();
|
||||
|
||||
setContentView(R.layout.activity_show_workout_map);
|
||||
root= findViewById(R.id.showWorkoutMapParent);
|
||||
initRoot();
|
||||
|
||||
initAfterContent();
|
||||
|
||||
@ -43,4 +43,8 @@ public class ShowWorkoutMapActivity extends WorkoutActivity {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
void initRoot() {
|
||||
root = findViewById(R.id.showWorkoutMapParent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
* Copyright (c) 2020 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
@ -36,7 +36,7 @@ public class ShowWorkoutMapDiagramActivity extends WorkoutActivity {
|
||||
initBeforeContent();
|
||||
|
||||
setContentView(R.layout.activity_show_workout_map_diagram);
|
||||
root= findViewById(R.id.showWorkoutMapParent);
|
||||
initRoot();
|
||||
|
||||
initAfterContent();
|
||||
|
||||
@ -54,4 +54,8 @@ public class ShowWorkoutMapDiagramActivity extends WorkoutActivity {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
void initRoot() {
|
||||
root = findViewById(R.id.showWorkoutMapParent);
|
||||
}
|
||||
}
|
||||
@ -55,18 +55,14 @@ 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 abstract class WorkoutActivity extends InformationActivity {
|
||||
|
||||
public static Workout selectedWorkout;
|
||||
|
||||
List<WorkoutSample> samples;
|
||||
Workout workout;
|
||||
ViewGroup root;
|
||||
private Resources.Theme theme;
|
||||
MapView map;
|
||||
private TileDownloadLayer downloadLayer;
|
||||
@ -79,14 +75,14 @@ public abstract class WorkoutActivity extends FitoTrackActivity {
|
||||
void initBeforeContent() {
|
||||
workout= selectedWorkout;
|
||||
samples= Arrays.asList(Instance.getInstance(this).db.workoutDao().getAllSamplesOfWorkout(workout.id));
|
||||
setTheme(ThemeManager.getThemeByWorkout(workout));
|
||||
setTheme(workout.getWorkoutType().theme);
|
||||
}
|
||||
|
||||
void initAfterContent() {
|
||||
if (getActionBar() != null) {
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
setTitle(WorkoutTypeCalculator.getType(workout));
|
||||
setTitle(workout.getWorkoutType().title);
|
||||
|
||||
theme= getTheme();
|
||||
}
|
||||
@ -259,7 +255,7 @@ public abstract class WorkoutActivity extends FitoTrackActivity {
|
||||
|
||||
void addMap(){
|
||||
map= new MapView(this);
|
||||
downloadLayer= MapManager.setupMap(map, TileSources.Purpose.DEFAULT);
|
||||
downloadLayer = MapManager.setupMap(map);
|
||||
|
||||
WorkoutLayer workoutLayer= new WorkoutLayer(samples, getThemePrimaryColor());
|
||||
map.addLayer(workoutLayer);
|
||||
@ -297,9 +293,15 @@ public abstract class WorkoutActivity extends FitoTrackActivity {
|
||||
return getWindowManager().getDefaultDisplay().getWidth()*3/4;
|
||||
}
|
||||
|
||||
protected boolean hasSamples() {
|
||||
return samples.size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
map.destroyAll();
|
||||
if (map != null) {
|
||||
map.destroyAll();
|
||||
}
|
||||
AndroidGraphicFactory.clearResourceMemoryCache();
|
||||
super.onDestroy();
|
||||
}
|
||||
@ -307,12 +309,16 @@ public abstract class WorkoutActivity extends FitoTrackActivity {
|
||||
@Override
|
||||
public void onPause(){
|
||||
super.onPause();
|
||||
downloadLayer.onPause();
|
||||
if (downloadLayer != null) {
|
||||
downloadLayer.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
public void onResume(){
|
||||
super.onResume();
|
||||
downloadLayer.onResume();
|
||||
if (downloadLayer != null) {
|
||||
downloadLayer.onResume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
* Copyright (c) 2020 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
@ -22,7 +22,7 @@ package de.tadris.fitness.data;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
@Database(version = 2, entities = {Workout.class, WorkoutSample.class})
|
||||
@Database(version = 3, entities = {Workout.class, WorkoutSample.class})
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
public abstract WorkoutDao workoutDao();
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
* Copyright (c) 2020 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
@ -19,6 +19,7 @@
|
||||
|
||||
package de.tadris.fitness.data;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
@ -31,10 +32,6 @@ import java.util.Date;
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Workout{
|
||||
|
||||
public static final String WORKOUT_TYPE_RUNNING= "running";
|
||||
public static final String WORKOUT_TYPE_HIKING= "hiking";
|
||||
public static final String WORKOUT_TYPE_CYCLING= "cycling";
|
||||
|
||||
@PrimaryKey
|
||||
public long id;
|
||||
|
||||
@ -63,12 +60,12 @@ public class Workout{
|
||||
public double topSpeed;
|
||||
|
||||
/**
|
||||
* Average pace of workout in km/min
|
||||
* Average pace of workout in min/km
|
||||
*/
|
||||
public double avgPace;
|
||||
|
||||
public String workoutType;
|
||||
|
||||
@ColumnInfo(name = "workoutType")
|
||||
public String workoutTypeId;
|
||||
|
||||
public float ascent;
|
||||
|
||||
@ -76,6 +73,8 @@ public class Workout{
|
||||
|
||||
public int calorie;
|
||||
|
||||
public boolean edited;
|
||||
|
||||
public String toString(){
|
||||
if(comment.length() > 2){
|
||||
return comment;
|
||||
@ -88,5 +87,13 @@ public class Workout{
|
||||
return SimpleDateFormat.getDateTimeInstance().format(new Date(start));
|
||||
}
|
||||
|
||||
public WorkoutType getWorkoutType() {
|
||||
return WorkoutType.getTypeById(workoutTypeId);
|
||||
}
|
||||
|
||||
public void setWorkoutType(WorkoutType workoutType) {
|
||||
this.workoutTypeId = workoutType.id;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
123
app/src/main/java/de/tadris/fitness/data/WorkoutBuilder.java
Normal file
123
app/src/main/java/de/tadris/fitness/data/WorkoutBuilder.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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 android.content.Context;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import de.tadris.fitness.Instance;
|
||||
import de.tadris.fitness.util.CalorieCalculator;
|
||||
|
||||
public class WorkoutBuilder {
|
||||
|
||||
private WorkoutType workoutType;
|
||||
|
||||
private Calendar start;
|
||||
private long duration;
|
||||
|
||||
private int length;
|
||||
|
||||
private String comment;
|
||||
|
||||
public WorkoutBuilder() {
|
||||
workoutType = WorkoutType.RUNNING;
|
||||
start = Calendar.getInstance();
|
||||
duration = 1000L * 60 * 10;
|
||||
length = 500;
|
||||
comment = "";
|
||||
}
|
||||
|
||||
public Workout create(Context context) {
|
||||
Workout workout = new Workout();
|
||||
|
||||
// Calculate values
|
||||
workout.start = start.getTimeInMillis();
|
||||
workout.end = workout.start + workout.duration;
|
||||
|
||||
workout.id = workout.start;
|
||||
workout.setWorkoutType(workoutType);
|
||||
|
||||
workout.duration = duration;
|
||||
workout.pauseDuration = 0;
|
||||
|
||||
workout.length = length;
|
||||
|
||||
workout.avgSpeed = (double) length / (double) (duration / 1000);
|
||||
workout.topSpeed = 0;
|
||||
workout.avgPace = ((double) workout.duration / 1000 / 60) / ((double) workout.length / 1000);
|
||||
|
||||
workout.ascent = 0;
|
||||
workout.descent = 0;
|
||||
|
||||
workout.calorie = CalorieCalculator.calculateCalories(workout, Instance.getInstance(context).userPreferences.getUserWeight());
|
||||
workout.comment = comment;
|
||||
|
||||
workout.edited = true;
|
||||
|
||||
return workout;
|
||||
}
|
||||
|
||||
public Workout insertWorkout(Context context) {
|
||||
Workout workout = create(context);
|
||||
Instance.getInstance(context).db.workoutDao().insertWorkout(workout);
|
||||
return workout;
|
||||
}
|
||||
|
||||
public WorkoutType getWorkoutType() {
|
||||
return workoutType;
|
||||
}
|
||||
|
||||
public void setWorkoutType(WorkoutType workoutType) {
|
||||
this.workoutType = workoutType;
|
||||
}
|
||||
|
||||
public Calendar getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(Calendar start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
}
|
||||
58
app/src/main/java/de/tadris/fitness/data/WorkoutType.java
Normal file
58
app/src/main/java/de/tadris/fitness/data/WorkoutType.java
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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 androidx.annotation.StringRes;
|
||||
import androidx.annotation.StyleRes;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
|
||||
public enum WorkoutType {
|
||||
|
||||
RUNNING("running", R.string.workoutTypeRunning, 7, true, R.style.Running),
|
||||
HIKING("hiking", R.string.workoutTypeHiking, 7, true, R.style.Hiking),
|
||||
CYCLING("cycling", R.string.workoutTypeCycling, 12, true, R.style.Bicycling),
|
||||
OTHER("other", R.string.workoutTypeOther, 7, true, R.style.AppTheme);
|
||||
|
||||
public String id;
|
||||
public @StringRes
|
||||
int title;
|
||||
public int minDistance; // Minimum distance between samples
|
||||
public boolean hasGPS;
|
||||
public @StyleRes
|
||||
int theme;
|
||||
|
||||
WorkoutType(String id, int title, int minDistance, boolean hasGPS, int theme) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.minDistance = minDistance;
|
||||
this.hasGPS = hasGPS;
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
public static WorkoutType getTypeById(String id) {
|
||||
for (WorkoutType type : values()) {
|
||||
if (type.id.equals(id)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return OTHER;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.dialog;
|
||||
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.os.Bundle;
|
||||
import android.widget.DatePicker;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
|
||||
|
||||
public DatePickerCallback callback;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
// Use the current date as the default date in the picker
|
||||
final Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(System.currentTimeMillis());
|
||||
int year = c.get(Calendar.YEAR);
|
||||
int month = c.get(Calendar.MONTH);
|
||||
int day = c.get(Calendar.DAY_OF_MONTH);
|
||||
|
||||
// Create a new instance of DatePickerDialog and return it
|
||||
return new DatePickerDialog(getActivity(), this, year, month, day);
|
||||
}
|
||||
|
||||
public void onDateSet(DatePicker view, int year, int month, int day) {
|
||||
callback.onDatePick(year, month, day);
|
||||
}
|
||||
|
||||
public interface DatePickerCallback {
|
||||
void onDatePick(int year, int month, int day);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.dialog;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.view.View;
|
||||
import android.widget.NumberPicker;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
|
||||
public class DurationPickerDialogFragment {
|
||||
|
||||
public Activity context;
|
||||
public DurationPickListener listener;
|
||||
public long initialDuration;
|
||||
|
||||
public DurationPickerDialogFragment(Activity context, DurationPickListener listener, long initialDuration) {
|
||||
this.context = context;
|
||||
this.listener = listener;
|
||||
this.initialDuration = initialDuration;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
final AlertDialog.Builder d = new AlertDialog.Builder(context);
|
||||
d.setTitle(R.string.setDuration);
|
||||
View v = context.getLayoutInflater().inflate(R.layout.dialog_duration_picker, null);
|
||||
NumberPicker hours = v.findViewById(R.id.durationPickerHours);
|
||||
hours.setFormatter(value -> value + " " + context.getString(R.string.timeHourShort));
|
||||
hours.setMinValue(0);
|
||||
hours.setMaxValue(60);
|
||||
hours.setValue(getInitialHours());
|
||||
|
||||
NumberPicker minutes = v.findViewById(R.id.durationPickerMinutes);
|
||||
minutes.setFormatter(value -> value + " " + context.getString(R.string.timeMinuteShort));
|
||||
minutes.setMinValue(0);
|
||||
minutes.setMaxValue(60);
|
||||
minutes.setValue(getInitialMinutes());
|
||||
|
||||
d.setView(v);
|
||||
|
||||
d.setNegativeButton(R.string.cancel, null);
|
||||
d.setPositiveButton(R.string.okay, (dialog, which) -> {
|
||||
listener.onDurationPick(getMillisFromPick(hours.getValue(), minutes.getValue()));
|
||||
});
|
||||
|
||||
d.create().show();
|
||||
}
|
||||
|
||||
private int getInitialHours() {
|
||||
return (int) (initialDuration / 1000 / 60 / 60);
|
||||
}
|
||||
|
||||
private int getInitialMinutes() {
|
||||
return (int) (initialDuration / 1000 / 60 % 60);
|
||||
}
|
||||
|
||||
private static long getMillisFromPick(int hours, int minutes) {
|
||||
long minuteInMillis = 1000L * 60;
|
||||
long hourInMillis = minuteInMillis * 60;
|
||||
return hours * hourInMillis + minutes * minuteInMillis;
|
||||
}
|
||||
|
||||
public interface DurationPickListener {
|
||||
void onDurationPick(long duration);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.dialog;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
import de.tadris.fitness.data.WorkoutType;
|
||||
|
||||
public class SelectWorkoutTypeDialog {
|
||||
|
||||
private Activity context;
|
||||
private WorkoutTypeSelectListener listener;
|
||||
private WorkoutType[] options;
|
||||
|
||||
public SelectWorkoutTypeDialog(Activity context, WorkoutTypeSelectListener listener) {
|
||||
this.context = context;
|
||||
this.listener = listener;
|
||||
this.options = WorkoutType.values();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
AlertDialog.Builder builderSingle = new AlertDialog.Builder(context);
|
||||
|
||||
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(context, R.layout.select_dialog_singlechoice_material);
|
||||
for (WorkoutType type : options) {
|
||||
arrayAdapter.add(context.getString(type.title));
|
||||
}
|
||||
|
||||
builderSingle.setAdapter(arrayAdapter, (dialog, which) -> listener.onSelectWorkoutType(options[which]));
|
||||
builderSingle.show();
|
||||
}
|
||||
|
||||
public interface WorkoutTypeSelectListener {
|
||||
void onSelectWorkoutType(WorkoutType workoutType);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.os.Bundle;
|
||||
import android.text.format.DateFormat;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
|
||||
|
||||
public TimePickerCallback callback;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
// Use the current time as the default values for the picker
|
||||
final Calendar c = Calendar.getInstance();
|
||||
int hour = c.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = c.get(Calendar.MINUTE);
|
||||
|
||||
// Create a new instance of TimePickerDialog and return it
|
||||
return new TimePickerDialog(getActivity(), this, hour, minute, DateFormat.is24HourFormat(getActivity()));
|
||||
}
|
||||
|
||||
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
|
||||
callback.onTimePick(hourOfDay, minute);
|
||||
}
|
||||
|
||||
public interface TimePickerCallback {
|
||||
void onTimePick(int hour, int minute);
|
||||
}
|
||||
}
|
||||
@ -30,11 +30,10 @@ 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){
|
||||
public static TileDownloadLayer setupMap(MapView mapView) {
|
||||
FitoTrackTileSource tileSource;
|
||||
|
||||
String chosenTileLayer= Instance.getInstance(mapView.getContext()).userPreferences.getMapStyle();
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.tilesource;
|
||||
|
||||
|
||||
public class TileSources {
|
||||
|
||||
public static FitoTrackTileSource[] tileSources= new FitoTrackTileSource[]{
|
||||
MapnikTileSource.INSTANCE, HumanitarianTileSource.INSTANCE, ThunderforestTileSource.OUTDOORS, ThunderforestTileSource.CYCLE_MAP
|
||||
};
|
||||
|
||||
public enum Purpose{
|
||||
DEFAULT, OUTDOOR, CYCLING
|
||||
}
|
||||
|
||||
}
|
||||
@ -32,21 +32,11 @@ import java.util.List;
|
||||
import de.tadris.fitness.Instance;
|
||||
import de.tadris.fitness.data.Workout;
|
||||
import de.tadris.fitness.data.WorkoutSample;
|
||||
import de.tadris.fitness.data.WorkoutType;
|
||||
import de.tadris.fitness.util.CalorieCalculator;
|
||||
|
||||
public class WorkoutRecorder implements LocationListener.LocationChangeListener {
|
||||
|
||||
private static int getMinDistance(String workoutType){
|
||||
switch (workoutType){
|
||||
case Workout.WORKOUT_TYPE_HIKING:
|
||||
case Workout.WORKOUT_TYPE_RUNNING:
|
||||
return 8;
|
||||
case Workout.WORKOUT_TYPE_CYCLING:
|
||||
return 15;
|
||||
default: return 10;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int PAUSE_TIME= 10000;
|
||||
|
||||
/**
|
||||
@ -72,17 +62,18 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
||||
private final WorkoutRecorderListener workoutRecorderListener;
|
||||
private GpsState gpsState= GpsState.SIGNAL_LOST;
|
||||
|
||||
public WorkoutRecorder(Context context, String workoutType, WorkoutRecorderListener workoutRecorderListener) {
|
||||
public WorkoutRecorder(Context context, WorkoutType workoutType, WorkoutRecorderListener workoutRecorderListener) {
|
||||
this.context= context;
|
||||
this.state= RecordingState.IDLE;
|
||||
this.workoutRecorderListener = workoutRecorderListener;
|
||||
|
||||
this.workout= new Workout();
|
||||
workout.edited = false;
|
||||
|
||||
// Default values
|
||||
this.workout.comment= "";
|
||||
|
||||
this.workout.workoutType= workoutType;
|
||||
this.workout.setWorkoutType(workoutType);
|
||||
}
|
||||
|
||||
public void start(){
|
||||
@ -214,7 +205,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
||||
WorkoutSample lastSample= samples.get(samples.size() - 1);
|
||||
distance= LocationListener.locationToLatLong(location).sphericalDistance(new LatLong(lastSample.lat, lastSample.lon));
|
||||
long timediff= lastSample.absoluteTime - location.getTime();
|
||||
if(distance < getMinDistance(workout.workoutType) && timediff < 500){
|
||||
if (distance < workout.getWorkoutType().minDistance && timediff < 500) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.announcement;
|
||||
package de.tadris.fitness.recording.announcement;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.PreferenceManager;
|
||||
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.announcement;
|
||||
package de.tadris.fitness.recording.announcement;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.announcement;
|
||||
package de.tadris.fitness.recording.announcement;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.announcement;
|
||||
package de.tadris.fitness.recording.announcement;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.announcement;
|
||||
package de.tadris.fitness.recording.announcement;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.announcement;
|
||||
package de.tadris.fitness.recording.announcement;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.announcement;
|
||||
package de.tadris.fitness.recording.announcement;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.PreferenceManager;
|
||||
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.announcement;
|
||||
package de.tadris.fitness.recording.announcement;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
@ -20,6 +20,7 @@
|
||||
package de.tadris.fitness.util;
|
||||
|
||||
import de.tadris.fitness.data.Workout;
|
||||
import de.tadris.fitness.data.WorkoutType;
|
||||
|
||||
public class CalorieCalculator {
|
||||
|
||||
@ -47,12 +48,11 @@ public class CalorieCalculator {
|
||||
*/
|
||||
private static double getMET(Workout workout) {
|
||||
double speedInKmh= workout.avgSpeed * 3.6;
|
||||
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_RUNNING) || workout.workoutType.equals(Workout.WORKOUT_TYPE_HIKING)){
|
||||
// This is a linear graph based on the website linked above
|
||||
WorkoutType type = workout.getWorkoutType();
|
||||
if (type == WorkoutType.RUNNING || type == WorkoutType.HIKING) {
|
||||
return Math.max(1.5, speedInKmh*1.117 - 2.1906);
|
||||
}
|
||||
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_CYCLING)){
|
||||
// This is a linear graph based on the website linked above
|
||||
if (type == WorkoutType.CYCLING) {
|
||||
return Math.max(3, (speedInKmh-10) / 1.5);
|
||||
}
|
||||
return -1;
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
* FitoTrack is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FitoTrack is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.util;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
import de.tadris.fitness.data.Workout;
|
||||
|
||||
public class ThemeManager {
|
||||
|
||||
public static int getThemeByWorkoutType(String type){
|
||||
switch (type){
|
||||
case Workout.WORKOUT_TYPE_RUNNING: return R.style.Running;
|
||||
case Workout.WORKOUT_TYPE_CYCLING: return R.style.Bicycling;
|
||||
case Workout.WORKOUT_TYPE_HIKING: return R.style.Hiking;
|
||||
default: return R.style.AppTheme;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getThemeByWorkout(Workout workout){
|
||||
return getThemeByWorkoutType(workout.workoutType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
* FitoTrack is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FitoTrack is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.util;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
import de.tadris.fitness.data.Workout;
|
||||
|
||||
public class WorkoutTypeCalculator {
|
||||
|
||||
public static int getType(Workout workout){
|
||||
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_RUNNING)){
|
||||
if(workout.avgSpeed < 1.9){
|
||||
return R.string.workoutTypeWalking;
|
||||
}else if(workout.avgSpeed < 2.7){
|
||||
return R.string.workoutTypeJogging;
|
||||
}else{
|
||||
return R.string.workoutTypeRunning;
|
||||
}
|
||||
}
|
||||
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_CYCLING)){
|
||||
return R.string.workoutTypeCycling;
|
||||
}
|
||||
if(workout.workoutType.equals(Workout.WORKOUT_TYPE_HIKING)){
|
||||
return R.string.workoutTypeHiking;
|
||||
}
|
||||
return R.string.workoutTypeUnknown;
|
||||
}
|
||||
|
||||
}
|
||||
@ -61,7 +61,7 @@ public class GpxExporter {
|
||||
track.cmt= workout.comment;
|
||||
track.desc= workout.comment;
|
||||
track.src= "FitoTrack";
|
||||
track.type= workout.workoutType;
|
||||
track.type = workout.getWorkoutType().id;
|
||||
track.trkseg= new ArrayList<>();
|
||||
|
||||
TrackSegment segment= new TrackSegment();
|
||||
|
||||
@ -32,7 +32,6 @@ import java.util.Date;
|
||||
|
||||
import de.tadris.fitness.R;
|
||||
import de.tadris.fitness.data.Workout;
|
||||
import de.tadris.fitness.util.WorkoutTypeCalculator;
|
||||
import de.tadris.fitness.util.unit.UnitUtils;
|
||||
|
||||
public class WorkoutAdapter extends RecyclerView.Adapter<WorkoutAdapter.WorkoutViewHolder>{
|
||||
@ -78,7 +77,7 @@ public class WorkoutAdapter extends RecyclerView.Adapter<WorkoutAdapter.WorkoutV
|
||||
public void onBindViewHolder(WorkoutViewHolder holder, final int position) {
|
||||
Workout workout= workouts[position];
|
||||
holder.dateText.setText(SimpleDateFormat.getDateTimeInstance().format(new Date(workout.start)));
|
||||
holder.typeText.setText(WorkoutTypeCalculator.getType(workout));
|
||||
holder.typeText.setText(workout.getWorkoutType().title);
|
||||
if(workout.comment != null){
|
||||
if(workout.comment.length() > 33){
|
||||
holder.commentText.setText(workout.comment.substring(0, 30) + "...");
|
||||
|
||||
32
app/src/main/res/layout/activity_enter_workout.xml
Normal file
32
app/src/main/res/layout/activity_enter_workout.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2020 Jannis Scheibe <jannis@tadris.de>
|
||||
~
|
||||
~ This file is part of FitoTrack
|
||||
~
|
||||
~ FitoTrack is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ FitoTrack is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activity.EnterWorkoutActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/enterWorkoutRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="15dp" />
|
||||
</ScrollView>
|
||||
@ -72,6 +72,16 @@
|
||||
app:fab_label="@string/workoutTypeCycling"
|
||||
app:fab_size="normal" />
|
||||
|
||||
<com.github.clans.fab.FloatingActionButton
|
||||
android:id="@+id/workoutListEnter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_add_white"
|
||||
app:fab_colorNormal="@color/colorPrimary"
|
||||
app:fab_colorPressed="@color/colorPrimaryDark"
|
||||
app:fab_label="@string/enterWorkout"
|
||||
app:fab_size="normal" />
|
||||
|
||||
</com.github.clans.fab.FloatingActionMenu>
|
||||
|
||||
|
||||
|
||||
43
app/src/main/res/layout/dialog_duration_picker.xml
Normal file
43
app/src/main/res/layout/dialog_duration_picker.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2020 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"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<NumberPicker
|
||||
android:id="@+id/durationPickerHours"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="30dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=":" />
|
||||
|
||||
<NumberPicker
|
||||
android:id="@+id/durationPickerMinutes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="30dp" />
|
||||
|
||||
</LinearLayout>
|
||||
73
app/src/main/res/layout/enter_workout_line.xml
Normal file
73
app/src/main/res/layout/enter_workout_line.xml
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2020 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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginLeft="-15dp"
|
||||
android:layout_marginRight="-15dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="?android:selectableItemBackground">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:paddingStart="15dp"
|
||||
android:paddingEnd="15dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lineKey"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:textSize="20sp"
|
||||
android:textColor="@color/textLighterBlack" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/lineViewRoot"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@+id/lineValue"
|
||||
android:layout_toEndOf="@+id/lineKey"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="right|center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lineValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:textSize="20sp"
|
||||
android:textColor="@color/textLighterBlack"
|
||||
android:layout_centerVertical="true"
|
||||
android:textAlignment="textEnd" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?android:dividerHorizontal" />
|
||||
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2020 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/>.
|
||||
-->
|
||||
|
||||
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
|
||||
android:drawablePadding="20dp"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="48dip"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Medium"
|
||||
android:textColor="?android:attr/textColorAlertDialogListItem" />
|
||||
27
app/src/main/res/menu/enter_workout_menu.xml
Normal file
27
app/src/main/res/menu/enter_workout_menu.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2020 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/actionEnterWorkoutAdd"
|
||||
android:icon="@drawable/ic_add_white"
|
||||
android:showAsAction="always"
|
||||
android:title="@string/save" />
|
||||
</menu>
|
||||
@ -49,10 +49,16 @@
|
||||
|
||||
<string name="timeMinuteSingular">Minute</string>
|
||||
<string name="timeMinutePlural">Minutes</string>
|
||||
<string name="timeMinuteShort">min</string>
|
||||
<string name="timeHourSingular">Hour</string>
|
||||
<string name="timeHourPlural">Hours</string>
|
||||
<string name="timeHourShort">h</string>
|
||||
<string name="and">and</string>
|
||||
|
||||
<string name="errorEnterValidNumber">Enter a valid number</string>
|
||||
<string name="errorWorkoutAddFuture">The workout cannot be in the future</string>
|
||||
<string name="errorEnterValidDuration">Enter a valid duration</string>
|
||||
|
||||
<string name="announcementGPSStatus">GPS Status</string>
|
||||
|
||||
<string name="voiceAnnouncementsTitle">Voice Announcements</string>
|
||||
@ -83,6 +89,7 @@
|
||||
<string name="workoutBurnedEnergy">Burned Energy</string>
|
||||
<string name="workoutTotalEnergy">Total Energy</string>
|
||||
<string name="workoutEnergyConsumption">Energy Consumption</string>
|
||||
<string name="workoutEdited">This workout has been edited.</string>
|
||||
<string name="uploading">Uploading</string>
|
||||
<string name="enterVerificationCode">Enter Verification Code</string>
|
||||
<string name="authenticationFailed">Authentication failed.</string>
|
||||
@ -102,7 +109,15 @@
|
||||
<string name="workoutTypeJogging">Jogging</string>
|
||||
<string name="workoutTypeCycling">Cycling</string>
|
||||
<string name="workoutTypeHiking">Hiking</string>
|
||||
<string name="workoutTypeOther">Other</string>
|
||||
<string name="workoutTypeUnknown">Unknown</string>
|
||||
<string name="type">Type</string>
|
||||
|
||||
<string name="custom">Custom</string>
|
||||
<string name="enterWorkout">Enter Workout</string>
|
||||
|
||||
<string name="setDuration">Set Duration</string>
|
||||
|
||||
|
||||
<string name="recordWorkout">Record Workout</string>
|
||||
|
||||
@ -155,4 +170,5 @@
|
||||
<string name="share">Share</string>
|
||||
<string name="savedToDownloads">Saved to Downloads</string>
|
||||
<string name="savingFailed">Saving failed</string>
|
||||
<string name="info">Info</string>
|
||||
</resources>
|
||||
|
||||
@ -23,6 +23,7 @@ import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import de.tadris.fitness.data.Workout;
|
||||
import de.tadris.fitness.data.WorkoutType;
|
||||
import de.tadris.fitness.util.CalorieCalculator;
|
||||
|
||||
public class CalorieCalculatorTest {
|
||||
@ -31,7 +32,7 @@ public class CalorieCalculatorTest {
|
||||
public void testCalculation() {
|
||||
Workout workout = new Workout();
|
||||
workout.avgSpeed = 2.7d;
|
||||
workout.workoutType = Workout.WORKOUT_TYPE_RUNNING;
|
||||
workout.setWorkoutType(WorkoutType.RUNNING);
|
||||
workout.duration = 1000L * 60 * 10;
|
||||
int calorie = CalorieCalculator.calculateCalories(workout, 80);
|
||||
System.out.println("Calories: " + calorie);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user