package com.iamthefij.otbeta; import android.app.Activity; import android.content.Intent; import android.graphics.Color; import android.os.AsyncTask; import android.support.design.widget.CollapsingToolbarLayout; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.goebl.david.Response; import com.goebl.david.WebbException; import com.jjoe64.graphview.DefaultLabelFormatter; import com.jjoe64.graphview.GraphView; import com.jjoe64.graphview.GridLabelRenderer; import com.jjoe64.graphview.ValueDependentColor; import com.jjoe64.graphview.series.BarGraphSeries; import com.jjoe64.graphview.series.DataPoint; import com.jjoe64.graphview.series.LineGraphSeries; import com.iamthefij.otbeta.api.Client; import com.iamthefij.otbeta.api.Exerciser; import com.iamthefij.otbeta.api.Interval; import com.iamthefij.otbeta.api.Workout; import java.util.List; /** * A fragment representing a single Workout detail screen. * This fragment is either contained in a {@link WorkoutListActivity} * in two-pane mode (on tablets) or a {@link WorkoutDetailActivity} * on handsets. */ public class WorkoutDetailFragment extends Fragment { /** * The fragment argument representing the item ID that this fragment * represents. */ public static final String ARG_EXERCISER_UUID = "exerciser_uuid"; public static final String ARG_WORKOUT_ID = "workout_id"; public static final String ARG_WORKOUT_TITLE = "workout_TITLE"; private Client mClient; private Exerciser mExerciser; private Interval mInterval; private Workout mWorkout; private View mRootView; private String mWorkoutTitle; /** * Mandatory empty constructor for the fragment manager to instantiate the * fragment (e.g. upon screen orientation changes). */ public WorkoutDetailFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mClient = new Client(this.getContext()); if (getArguments().containsKey(ARG_EXERCISER_UUID)) { // TODO: In a real-world scenario, use a Loader // to load content from a content provider. mExerciser = new Exerciser(getArguments().getString(ARG_EXERCISER_UUID)); mInterval = new Interval(getArguments().getInt(ARG_WORKOUT_ID)); mWorkoutTitle = getArguments().getString(ARG_WORKOUT_TITLE); } new WorkoutDetailGetter().execute(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mRootView = inflater.inflate(R.layout.workout_detail, container, false); maybeSetRootView(); setTitle(mWorkoutTitle); return mRootView; } private void setTitle(String workoutTitle) { Activity activity = this.getActivity(); CollapsingToolbarLayout appBarLayout = (CollapsingToolbarLayout) activity.findViewById(R.id.toolbar_layout); if (appBarLayout != null) { appBarLayout.setTitle(workoutTitle); } } private void maybeSetRootView() { if (mRootView != null && mWorkout != null) { fillHeartRateZoneGraph((GraphView) mRootView.findViewById(R.id.workout_hr_zone_graph)); fillHeartRateGraph((GraphView) mRootView.findViewById(R.id.workout_hrm_graph)); fillStats(mRootView.findViewById(R.id.workout_detail_insert)); } } private void fillStats(View view) { TextView splatPointsView = (TextView) view.findViewById(R.id.workout_detail_splat_points); splatPointsView.setText(String.valueOf(mWorkout.getPoints())); TextView caloriesView = (TextView) view.findViewById(R.id.workout_detail_calories); caloriesView.setText(String.valueOf(mWorkout.getCalories())); TextView avgHrView = (TextView) view.findViewById(R.id.workout_detail_avg_hr); avgHrView.setText(String.valueOf(mWorkout.getHeartRate().getAverage())); TextView durationView = (TextView) view.findViewById(R.id.workout_detail_duration); durationView.setText(String.valueOf(mWorkout.getDuration()/60)); } private void fillHeartRateZoneGraph(GraphView graphView) { Workout.HeartRateZones zones = mWorkout.getHrm(); BarGraphSeries series = new BarGraphSeries<>( new DataPoint[] { new DataPoint(0, zones.getGreyZoneSeconds()/60), new DataPoint(1, zones.getBlueZoneSeconds()/60), new DataPoint(2, zones.getGreenZoneSeconds()/60), new DataPoint(3, zones.getOrangeZoneSeconds()/60), new DataPoint(4, zones.getRedZoneSeconds()/60) } ); series.setAnimated(true); series.setDrawValuesOnTop(true); series.setValuesOnTopColor(R.color.colorPrimary); series.setValueDependentColor(new ValueDependentColor() { @Override public int get(DataPoint data) { switch ((int) data.getX()) { case 0: return Color.GRAY; case 1: return Color.BLUE; case 2: return Color.GREEN; case 3: return Color.rgb(255, 165, 0); case 4: return Color.RED; } return Color.DKGRAY; } }); graphView.getGridLabelRenderer().setHorizontalLabelsVisible(false); graphView.getGridLabelRenderer().setGridStyle(GridLabelRenderer.GridStyle.HORIZONTAL); graphView.getViewport().setXAxisBoundsManual(true); graphView.getViewport().setMinX(-0.5); graphView.getViewport().setMaxX(4.5); graphView.addSeries(series); } private void fillHeartRateGraph(GraphView graphView) { Workout.Metric heartRate = mWorkout.getHeartRate(); List values = heartRate.getValues(); double time = 0.0; int numIntervals = values.size(); int intervalLength = heartRate.getInterval(); int targetHeartRate = mWorkout.getHrm().getTargetHeartRate(); double percentOfTarget; DataPoint[] dataPoints = new DataPoint[numIntervals]; for (int i = 0; i < numIntervals; i++) { percentOfTarget = (values.get(i) / targetHeartRate) * 100; dataPoints[i] = new DataPoint(time, percentOfTarget); time += intervalLength; } graphView.getGridLabelRenderer().setVerticalAxisTitle("Heart Rate"); graphView.getGridLabelRenderer().setHorizontalAxisTitle("Minutes"); graphView.getGridLabelRenderer().setLabelFormatter(new DefaultLabelFormatter() { @Override public String formatLabel(double value, boolean isValueX) { if (isValueX) { // Convert to minutes value = value / 60; } return super.formatLabel(value, isValueX); } }); graphView.addSeries(new LineGraphSeries<>(dataPoints)); } /** * Represents an asynchronous task to retrieve workouts from the api and populate * the recycle view adapter */ private class WorkoutDetailGetter extends AsyncTask { private Workout mWorkoutTemp; private boolean mInvalidSession = false; @Override protected Boolean doInBackground(Void... params) { try { mWorkoutTemp = mClient.getWorkout(mExerciser, mInterval); } catch (WebbException ex) { Response response = ex.getResponse(); if (response.getStatusCode() == 403) { mInvalidSession = true; return false; } else { throw ex; } } return true; } @Override protected void onPostExecute(Boolean success) { super.onPostExecute(success); if (success) { mWorkout = mWorkoutTemp; maybeSetRootView(); } else if (mInvalidSession) { Intent loginActivity = new Intent(getActivity(), LoginActivity.class); startActivity(loginActivity); } } } }