/*
CYAxisopyright (C) 2012 Haowen Ning
This program 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 2
of the License, or (at your option) any later version.
This program 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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.liberty.android.fantastischmemo.ui;
import android.app.ProgressDialog;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.widget.FrameLayout;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.formatter.YAxisValueFormatter;
import com.github.mikephil.charting.utils.ColorTemplate;
import com.github.mikephil.charting.utils.ViewPortHandler;
import org.liberty.android.fantastischmemo.common.AnyMemoDBOpenHelper;
import org.liberty.android.fantastischmemo.common.AnyMemoDBOpenHelperManager;
import org.liberty.android.fantastischmemo.R;
import org.liberty.android.fantastischmemo.common.BaseActivity;
import org.liberty.android.fantastischmemo.dao.CardDao;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class StatisticsScreen extends BaseActivity {
public static final String EXTRA_DBPATH = "dbpath";
private FrameLayout statisticsGraphFrame;
private CardDao cardDao;
private AnyMemoDBOpenHelper dbOpenHelper;
private DrawerLayout drawerLayout;
private NavigationView navigationView;
private static final ValueFormatter valueFormatter = new ChartValueFormatter();
private static final YAxisValueFormatter yAxisValueFormatter = new ChartYAxisValueFormatter();
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.statistics_screen);
setTitle(R.string.statistics_text);
Bundle extras = getIntent().getExtras();
assert extras != null : "Open StatisticsScreen without extras";
String dbPath = extras.getString(EXTRA_DBPATH);
assert dbPath != null : "dbPath shouldn't be null";
dbOpenHelper = AnyMemoDBOpenHelperManager.getHelper(this, dbPath);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
statisticsGraphFrame = (FrameLayout) findViewById(R.id.statistics_graph_frame);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initDrawer();
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// For the first execution to display default statistics info
setTitle(R.string.number_of_cards_scheduled_in_a_day_text);
new CardToReviewTask().execute((Void)null);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
drawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
private void initDrawer() {
navigationView = (NavigationView) findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.cards_scheduled_in_a_month_menu:
setTitle(R.string.number_of_cards_scheduled_in_a_day_text);
new CardToReviewTask()
.execute((Void)null);
break;
case R.id.accumulative_cards_scheduled_menu:
setTitle(R.string.accumulative_cards_scheduled_text);
new AccumulativeCardsToReviewTask()
.execute((Void) null);
break;
case R.id.new_cards_learned_in_the_past_month_menu:
setTitle(R.string.number_of_new_cards_learned_in_a_day_text);
new NewCardTask().execute((Void) null);
break;
case R.id.grade_statistics_menu:
setTitle(R.string.grade_statistics_text);
new GradeStatisticsTask()
.execute((Void)null);
break;
}
menuItem.setChecked(true);
drawerLayout.closeDrawers();
return true;
}
}
);
}
@Override
public void onDestroy() {
super.onDestroy();
AnyMemoDBOpenHelperManager.releaseHelper(dbOpenHelper);
}
private abstract class ChartTask<T, K, ResultT> extends AsyncTask<T, K, ResultT> {
private ProgressDialog progressDialog;
@Override
public void onPreExecute() {
progressDialog = new ProgressDialog(StatisticsScreen.this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setTitle(getString(R.string.loading_please_wait));
progressDialog.setMessage(getString(R.string.loading_database));
progressDialog.setCancelable(false);
progressDialog.show();
}
public abstract Chart generateChart(ResultT result);
@Override
public void onPostExecute(ResultT result) {
Chart chart = generateChart(result);
statisticsGraphFrame.removeAllViews();
statisticsGraphFrame.addView(chart);
progressDialog.dismiss();
}
}
private class NewCardTask extends ChartTask<Void, Void, BarData> {
private static final int INITIAL_CAPACITY = 30;
private static final int MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000;
@Override
public BarData doInBackground(Void... params) {
cardDao = dbOpenHelper.getCardDao();
List<String> xVals = new ArrayList<String>(INITIAL_CAPACITY);
List<BarEntry> yVals = new ArrayList<BarEntry>(INITIAL_CAPACITY);
Date now = new Date();
for (int i = -INITIAL_CAPACITY; i < 1; i++) {
Date endDate = new Date(now.getTime() + i * MILLISECONDS_PER_DAY);
Date startDate = new Date(endDate.getTime() - MILLISECONDS_PER_DAY);
xVals.add("" + i);
yVals.add(new BarEntry((float)cardDao.getNewLearnedCardCount(null, startDate, endDate),
INITIAL_CAPACITY + i)); // the order has to be nonnegative
}
BarDataSet dataSet = new BarDataSet(yVals, getString(R.string.number_of_new_cards_learned_in_a_day_text));
BarData data = new BarData(xVals, dataSet);
data.setValueTextColor(Color.WHITE);
data.setValueFormatter(valueFormatter);
return data;
}
@Override
public Chart generateChart(BarData data) {
BarChart chart = new BarChart(StatisticsScreen.this);
chart.setDrawGridBackground(false);
chart.getLegend().setTextColor(Color.WHITE);
chart.getXAxis().setTextColor(Color.WHITE);
chart.getAxisLeft().setTextColor(Color.WHITE);
chart.getAxisRight().setTextColor(Color.WHITE);
chart.getAxisLeft().setValueFormatter(yAxisValueFormatter);
chart.getAxisRight().setValueFormatter(yAxisValueFormatter);
chart.setData(data);
chart.setDescription("");
return chart;
}
}
private class CardToReviewTask extends ChartTask<Void, Void, BarData> {
@Override
public BarData doInBackground(Void... params) {
cardDao = dbOpenHelper.getCardDao();
List<String> xVals = new ArrayList<String>(30);
List<BarEntry> yVals = new ArrayList<BarEntry>(30);
Date now = new Date();
for (int i = 0; i < 30; i++) {
Date startDate = new Date(now.getTime() + i * 60 * 60 * 24 * 1000);
Date endDate = new Date(startDate.getTime() + 1 * 60 * 60 * 24 * 1000);
xVals.add("" + i);
yVals.add(new BarEntry((float)cardDao.getScheduledCardCount(null, startDate, endDate), i));
}
BarDataSet dataSet = new BarDataSet(yVals, getString(R.string.number_of_cards_scheduled_in_a_day_text));
BarData data = new BarData(xVals, dataSet);
data.setValueTextColor(Color.WHITE);
data.setValueFormatter(valueFormatter);
return data;
}
@Override
public Chart generateChart(BarData data) {
BarChart chart = new BarChart(StatisticsScreen.this);
chart.setDrawGridBackground(false);
chart.getLegend().setTextColor(Color.WHITE);
chart.getXAxis().setTextColor(Color.WHITE);
chart.getAxisLeft().setTextColor(Color.WHITE);
chart.getAxisRight().setTextColor(Color.WHITE);
chart.getAxisLeft().setValueFormatter(yAxisValueFormatter);
chart.getAxisRight().setValueFormatter(yAxisValueFormatter);
chart.setData(data);
chart.setDescription("");
return chart;
}
}
private class AccumulativeCardsToReviewTask extends ChartTask<Void, Void, BarData> {
@Override
public BarData doInBackground(Void... params) {
cardDao = dbOpenHelper.getCardDao();
List<String> xVals = new ArrayList<String>(30);
List<BarEntry> yVals = new ArrayList<BarEntry>(30);
Date now = new Date();
Date startDate = new Date(0);
for (int i = 0; i < 30; i++) {
Date endDate = new Date(now.getTime() + (i + 1) * 60 * 60 * 24 * 1000);
xVals.add("" + i);
yVals.add(new BarEntry((float)cardDao.getScheduledCardCount(null, startDate, endDate), i));
}
BarDataSet dataSet = new BarDataSet(yVals, getString(R.string.accumulative_cards_scheduled_text));
BarData data = new BarData(xVals, dataSet);
data.setValueTextColor(Color.WHITE);
data.setValueFormatter(valueFormatter);
return data;
}
@Override
public Chart generateChart(BarData data) {
BarChart chart = new BarChart(StatisticsScreen.this);
chart.setDrawGridBackground(false);
chart.getLegend().setTextColor(Color.WHITE);
chart.getXAxis().setTextColor(Color.WHITE);
chart.getAxisLeft().setTextColor(Color.WHITE);
chart.getAxisRight().setTextColor(Color.WHITE);
chart.getAxisLeft().setValueFormatter(yAxisValueFormatter);
chart.getAxisRight().setValueFormatter(yAxisValueFormatter);
chart.setData(data);
chart.setDescription("");
return chart;
}
}
private class GradeStatisticsTask extends ChartTask<Void, Void, PieData> {
@Override
public PieData doInBackground(Void... params) {
cardDao = dbOpenHelper.getCardDao();
List<String> xVals = new ArrayList<String>(6);
List<Entry> yVals = new ArrayList<Entry>(6);
for (int i = 0; i < 6; i++) {
long n = cardDao.getNumberOfCardsWithGrade(i);
xVals.add("" + i);
yVals.add(new Entry((float)cardDao.getNumberOfCardsWithGrade(i), i));
}
PieDataSet dataSet = new PieDataSet(yVals, getString(R.string.grade_statistics_text));
List<Integer> colors = new ArrayList<Integer>();
for (int c : ColorTemplate.COLORFUL_COLORS) {
colors.add(c);
}
colors.add(ColorTemplate.JOYFUL_COLORS[0]);
dataSet.setColors(colors);
dataSet.setSliceSpace(3f);
dataSet.setSelectionShift(5f);
PieData data = new PieData(xVals, dataSet);
data.setValueFormatter(valueFormatter);
return data;
}
@Override
public Chart generateChart(PieData data) {
PieChart chart = new PieChart(StatisticsScreen.this);
chart.getLegend().setTextColor(Color.WHITE);
chart.setData(data);
chart.setDescription("");
return chart;
}
}
private static final class ChartValueFormatter implements ValueFormatter {
private static final DecimalFormat formatter = new DecimalFormat("###,###,##0");
public String getFormattedValue(float value, Entry entry, int dataSetIndex,
ViewPortHandler viewPortHandler) {
return formatter.format(value);
}
}
private static final class ChartYAxisValueFormatter implements YAxisValueFormatter {
private static final DecimalFormat formatter = new DecimalFormat("###,###,##0");
public String getFormattedValue(float value, YAxis yAxis) {
return formatter.format(value);
}
}
}