/**
* Copyright (C) 2013 - 2015 the enviroCar community
* <p>
* This file is part of the enviroCar app.
* <p>
* The enviroCar app 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.
* <p>
* The enviroCar app 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.
* <p>
* You should have received a copy of the GNU General Public License along
* with the enviroCar app. If not, see http://www.gnu.org/licenses/.
*/
package org.envirocar.app.view.trackdetails;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Fragment;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import org.envirocar.app.R;
import org.envirocar.core.entity.Measurement;
import org.envirocar.core.entity.Track;
import org.envirocar.core.injection.BaseInjectorActivity;
import org.envirocar.storage.EnviroCarDB;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import butterknife.ButterKnife;
import butterknife.InjectView;
import lecho.lib.hellocharts.formatter.SimpleAxisValueFormatter;
import lecho.lib.hellocharts.gesture.ZoomType;
import lecho.lib.hellocharts.listener.DummyVieportChangeListener;
import lecho.lib.hellocharts.model.Axis;
import lecho.lib.hellocharts.model.Line;
import lecho.lib.hellocharts.model.LineChartData;
import lecho.lib.hellocharts.model.PointValue;
import lecho.lib.hellocharts.model.Viewport;
import lecho.lib.hellocharts.util.ChartUtils;
import lecho.lib.hellocharts.view.LineChartView;
import lecho.lib.hellocharts.view.PreviewLineChartView;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* TODO JavaDoc
*
* @author dewall
*/
public class TrackStatisticsActivity extends BaseInjectorActivity {
private static final String EXTRA_TRACKID = "org.envirocar.app.extraTrackID";
public static void createInstance(Activity activity, int trackID) {
Intent intent = new Intent(activity, TrackStatisticsActivity.class);
intent.putExtra(EXTRA_TRACKID, trackID);
activity.startActivity(intent);
}
@Inject
protected EnviroCarDB enviroCarDB;
@InjectView(R.id.activity_track_statistics_toolbar)
protected Toolbar mToolbar;
private Track mTrack;
private PlaceholderFragment mPlaceholderFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_track_statistics_layout);
int trackID = getIntent().getIntExtra(EXTRA_TRACKID, -1);
Track.TrackId trackid = new Track.TrackId(trackID);
enviroCarDB.getTrack(trackid)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(track -> {
mTrack = track;
if (savedInstanceState == null) {
mPlaceholderFragment = new PlaceholderFragment(mTrack);
getFragmentManager().beginTransaction()
.add(R.id.activity_track_statistics_layout_container,
mPlaceholderFragment).commit();
}
// Workaround... for fast smartphones, the menu gets manually inflated to
// fast such that no menu gets rendered. Therefore, the inflatation is
// postponed by 100 milliseconds.
AndroidSchedulers.mainThread().createWorker().schedule(
() -> inflateMenuProperties(track), 100, TimeUnit.MILLISECONDS);
});
// Inject all annotated views.
ButterKnife.inject(this);
// Initializes the Toolbar.
setSupportActionBar(mToolbar);
getSupportActionBar().setTitle(R.string.track_statistics);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// for (Measurement.PropertyKey key : Measurement.PropertyKey.values()) {
// menu.add(key.getStringResource());
// }
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// click on the home button in the toolbar.
if (item.getItemId() == android.R.id.home) {
finish();
}
for (Measurement.PropertyKey key : Measurement.PropertyKey.values()) {
if (getString(key.getStringResource()).equals(item.getTitle())) {
mPlaceholderFragment.generateData(key);
break;
}
}
return super.onOptionsItemSelected(item);
}
private void inflateMenuProperties(Track track) {
Menu menu = mToolbar.getMenu();
menu.clear();
if (mTrack != null && !mTrack.getMeasurements().isEmpty()) {
for (Measurement.PropertyKey key : mTrack.getSupportedProperties()) {
menu.add(key.getStringResource());
}
}
mToolbar.postInvalidate();
}
public static class PlaceholderFragment extends Fragment {
@InjectView(R.id.activity_track_statistics_fragment_chart)
protected LineChartView mChart;
@InjectView(R.id.activity_track_statistics_fragment_chart_preview)
protected PreviewLineChartView mPreviewChart;
private LineChartData mChartData;
private LineChartData mPreviewChartData;
private final Track mTrack;
public PlaceholderFragment() {
this(null);
}
@SuppressLint("ValidFragment")
public PlaceholderFragment(Track track) {
this.mTrack = track;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_track_statistics_fragment,
container, false);
// Inject all annotated views.
ButterKnife.inject(this, rootView);
generateData(Measurement.PropertyKey.SPEED);
mChart.setZoomEnabled(false);
mChart.setScrollEnabled(false);
mPreviewChart.setViewportChangeListener(new DummyVieportChangeListener() {
@Override
public void onViewportChanged(Viewport viewport) {
mChart.setCurrentViewport(viewport);
}
});
return rootView;
}
private void generateData(Measurement.PropertyKey propertyKey) {
// Generate the PointValues for the Graph.
List<PointValue> values = generateDistancedBasedData(propertyKey, mTrack);
Line line = new Line(values);
line.setColor(getResources().getColor(R.color.green_dark_cario));
line.setHasPoints(false);
List<Line> lines = new ArrayList<>();
lines.add(line);
mChartData = new LineChartData(lines);
mChartData.setAxisXBottom(new Axis());
mChartData.setAxisYLeft(new Axis().setHasLines(true));
setDistanceAxis(mChartData);
setYAxis(propertyKey, mChartData);
mPreviewChartData = new LineChartData(mChartData);
mPreviewChartData.getLines().get(0).setColor(ChartUtils.DEFAULT_DARKEN_COLOR);
Axis axisXBottom = mPreviewChartData.getAxisXBottom();
axisXBottom.setHasSeparationLine(false);
axisXBottom.setHasTiltedLabels(true);
axisXBottom.setTextColor(ChartUtils.DEFAULT_DARKEN_COLOR);
mPreviewChartData.getAxisYLeft().setTextColor(ChartUtils.DEFAULT_DARKEN_COLOR);
// Set the data in the charts.
mChart.setLineChartData(mChartData);
mPreviewChart.setLineChartData(mPreviewChartData);
// set the preview extent
previewX();
}
private List<PointValue> generateDistancedBasedData(Measurement.PropertyKey propertyKey,
Track track) {
List<PointValue> values = new ArrayList<PointValue>();
// temporary array for computing distances.
float[] tmp = new float[1];
float distance = 0;
// temporary value for the last measurement
Measurement lastMeasurement = null;
for (Measurement m : track.getMeasurements()) {
if (lastMeasurement != null) {
Location.distanceBetween(lastMeasurement.getLatitude(), lastMeasurement
.getLongitude(), m.getLatitude(), m.getLongitude(), tmp);
distance += tmp[0] / 1000f; // we need km not meters.
}
if (m != null && m.hasProperty(propertyKey)) {
values.add(new PointValue(distance, m.getProperty(propertyKey).floatValue()));
}
lastMeasurement = m;
}
return values;
}
private void setDistanceAxis(LineChartData data) {
Axis distAxis = new Axis();
distAxis.setName(getString(R.string.track_statistics_distance));
distAxis.setTextColor(getResources().getColor(R.color.blue_dark_cario));
distAxis.setMaxLabelChars(5);
distAxis.setFormatter(new SimpleAxisValueFormatter()
.setAppendedText("km".toCharArray()));
distAxis.setHasLines(true);
distAxis.setHasTiltedLabels(true);
distAxis.setTextSize(10);
distAxis.setHasSeparationLine(false);
data.setAxisXBottom(distAxis);
}
private void setYAxis(Measurement.PropertyKey key, LineChartData data) {
Axis yAxis = new Axis();
yAxis.setName(getString(key.getStringResource()));
yAxis.setTextColor(getResources().getColor(R.color.blue_dark_cario));
yAxis.setMaxLabelChars(3);
yAxis.setHasLines(true);
yAxis.setTextSize(10);
yAxis.setFormatter(new SimpleAxisValueFormatter());
yAxis.setInside(false);
yAxis.setHasSeparationLine(false);
data.setAxisYLeft(yAxis);
}
private void previewX() {
Viewport tempViewport = new Viewport(mChart.getMaximumViewport());
float dx = tempViewport.width() / 3;
tempViewport.inset(dx, 0);
mPreviewChart.setCurrentViewportWithAnimation(tempViewport);
mPreviewChart.setZoomType(ZoomType.HORIZONTAL);
}
private void previewY() {
Viewport tempViewport = new Viewport(mChart.getMaximumViewport());
float dy = tempViewport.height() / 4;
tempViewport.inset(0, dy);
mPreviewChart.setCurrentViewportWithAnimation(tempViewport);
mPreviewChart.setZoomType(ZoomType.VERTICAL);
}
}
}