package com.maxiee.heartbeat.ui.fragments; import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.github.mikephil.charting.charts.CombinedChart; import com.github.mikephil.charting.charts.PieChart; import com.github.mikephil.charting.components.Legend; import com.github.mikephil.charting.components.XAxis; 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.CombinedData; import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.data.LineDataSet; import com.github.mikephil.charting.data.PieData; import com.github.mikephil.charting.data.PieDataSet; import com.github.mikephil.charting.utils.ColorTemplate; import com.github.mikephil.charting.utils.PercentFormatter; import com.github.mikephil.charting.utils.ValueFormatter; import com.maxiee.heartbeat.R; import com.maxiee.heartbeat.common.TimeUtils; import com.maxiee.heartbeat.data.DataManager; import com.maxiee.heartbeat.database.api.GetCountByNameApi; import com.maxiee.heartbeat.database.api.GetCountSpecDayApi; import com.maxiee.heartbeat.database.utils.ThoughtUtils; import com.maxiee.heartbeat.model.Event; import com.maxiee.heartbeat.support.StopWatch; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import butterknife.Bind; import butterknife.ButterKnife; /** * Created by maxiee on 15-7-15. */ public class StatisticsFragment extends Fragment{ private static final String TAG = StatisticsFragment.class.getSimpleName(); private final static int WEEK_COUNT = 7; private final static int DISTRIBUTION_COUNT = 10; @Bind(R.id.chart) CombinedChart mChart; @Bind(R.id.pie_chart) PieChart mPieChart; @Bind(R.id.tv_event_count) TextView mTvEventCount; @Bind(R.id.tv_thought_count) TextView mTvThoughtCount; @Bind(R.id.distribution_hint) TextView mTvDistriHint; private int mAccentColor; private int mPrimaryColor; private int mPrimaryColorDark; private long mThoughtCount; private long mEventCount; private ArrayList<Map.Entry<Event, Integer>> mEvents; private int mWasteBookCount; // 流水帐数目 private CombinedData mCombinedData; private PieData mPieData; private DataManager mDataManager; private UpdateCountTask mUpdateCountTask; private UpdateChartTask mUpdateChartTask; private UpdatePieChartTask mUpdatePieChartTask; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_statistics, container, false); ButterKnife.bind(this, v); TypedValue accentValue = new TypedValue(); getActivity().getTheme().resolveAttribute(R.attr.colorAccent, accentValue, true); mAccentColor = accentValue.data; getActivity().getTheme().resolveAttribute(R.attr.colorPrimary, accentValue, true); mPrimaryColor = accentValue.data; getActivity().getTheme().resolveAttribute(R.attr.colorPrimaryDark, accentValue, true); mPrimaryColorDark = accentValue.data; mDataManager = DataManager.getInstance(getContext()); mUpdateCountTask = new UpdateCountTask(); mUpdateChartTask = new UpdateChartTask(); mUpdatePieChartTask = new UpdatePieChartTask(); mUpdateChartTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); mUpdateCountTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); mUpdatePieChartTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); return v; } @Override public void onStop() { super.onStop(); if (mUpdateCountTask != null && mUpdateCountTask.getStatus() == AsyncTask.Status.RUNNING) mUpdateCountTask.cancel(true); if (mUpdateChartTask != null && mUpdateChartTask.getStatus() == AsyncTask.Status.RUNNING) mUpdateChartTask.cancel(true); if (mUpdatePieChartTask != null && mUpdatePieChartTask.getStatus() == AsyncTask.Status.RUNNING) mUpdatePieChartTask.cancel(true); } private class IntValueFormatter implements ValueFormatter { @Override public String getFormattedValue(float value) { return String.valueOf((int) value); } } private class UpdateCountTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { StopWatch watch = new StopWatch(TAG, UpdateCountTask.class.getSimpleName()); mEventCount = new GetCountByNameApi(getActivity()) .exec(GetCountByNameApi.EVENT); mThoughtCount = new GetCountByNameApi(getActivity()) .exec(GetCountByNameApi.THOUGHT); watch.stop(); return null; } @Override protected void onPostExecute(Void aVoid) { mTvEventCount.setText( String.valueOf(mEventCount) ); mTvThoughtCount.setText( String.valueOf(mThoughtCount) ); } } private class UpdateChartTask extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { mChart.setDoubleTapToZoomEnabled(false); mChart.setTouchEnabled(false); mChart.setDragEnabled(false); mChart.setScaleEnabled(false); mChart.setDescription(""); mChart.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.window_background)); mChart.setDrawGridBackground(false); mChart.setDrawBarShadow(false); mChart.setDrawOrder( new CombinedChart.DrawOrder[]{ CombinedChart.DrawOrder.BAR, CombinedChart.DrawOrder.LINE }); YAxis leftAxis = mChart.getAxisLeft(); leftAxis.setValueFormatter(new IntValueFormatter()); leftAxis.setDrawGridLines(false); XAxis xAxis = mChart.getXAxis(); xAxis.setDrawGridLines(false); xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); YAxis rightAxis = mChart.getAxisRight(); rightAxis.setEnabled(false); } @Override protected Void doInBackground(Void... params) { StopWatch watch = new StopWatch(TAG, UpdateChartTask.class.getSimpleName()); mCombinedData = new CombinedData(TimeUtils.getWeekDateString()); mCombinedData.setData(getWeekEventData()); mCombinedData.setData(getWeekThoughtData()); watch.stop(); return null; } @Override protected void onPostExecute(Void aVoid) { mChart.setData(mCombinedData); mChart.invalidate(); } private BarData getWeekEventData() { BarData d = new BarData(); ArrayList<BarEntry> entries = new ArrayList<>(); for (int i=0; i<WEEK_COUNT; i++) { entries.add( new BarEntry( new GetCountSpecDayApi(getActivity()).exec( TimeUtils.calendarDaysBefore(WEEK_COUNT-i), GetCountSpecDayApi.EVENT ),i ) ); } BarDataSet set = new BarDataSet(entries, getString(R.string.event_count_text)); set.setColor(mPrimaryColorDark); set.setValueFormatter(new IntValueFormatter()); d.addDataSet(set); set.setAxisDependency(YAxis.AxisDependency.LEFT); return d; } private LineData getWeekThoughtData() { LineData d = new LineData(); ArrayList<Entry> entries = new ArrayList<>(); for (int i=0; i<WEEK_COUNT; i++) { entries.add( new BarEntry( new GetCountSpecDayApi(getActivity()).exec( TimeUtils.calendarDaysBefore(WEEK_COUNT-i), GetCountSpecDayApi.THOUGHT ),i ) ); } LineDataSet set = new LineDataSet(entries, getString(R.string.thought_count_text)); set.setColor(mAccentColor); set.setLineWidth(2.5f); set.setAxisDependency(YAxis.AxisDependency.LEFT); set.setCircleColor(mPrimaryColorDark); set.setCircleSize(5f); set.setFillColor(mPrimaryColor); set.setDrawValues(true); set.setValueFormatter(new IntValueFormatter()); d.addDataSet(set); return d; } } private class UpdatePieChartTask extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { mPieChart.setTouchEnabled(false); mPieChart.setUsePercentValues(true); mPieChart.setDescription(""); mPieChart.setDrawHoleEnabled(true); mPieChart.setHoleColorTransparent(true); mPieChart.setTransparentCircleColor(Color.WHITE); mPieChart.setHoleRadius(40f); mPieChart.setTransparentCircleRadius(45f); mPieChart.setDrawCenterText(false); Legend legend = mPieChart.getLegend(); legend.setEnabled(false); } @Override protected Void doInBackground(Void... params) { StopWatch watch = new StopWatch(TAG, UpdatePieChartTask.class.getSimpleName()); getDistributionData(); watch.stop(); return null; } @Override protected void onPostExecute(Void aVoid) { mPieChart.setData(mPieData); mPieChart.invalidate(); String averageHead = getString(R.string.distri_hint_average_head); float averageCountV = 1f * mThoughtCount / mEventCount; if (mThoughtCount == 0) averageCountV = 0; String averageCount = String.valueOf(averageCountV); String averageTail = getString(R.string.distri_hint_average_tail); String wasteBook = getString(R.string.disti_hint_waste_book); String wasteCount = String.valueOf(mWasteBookCount); if (averageCount.length()>3) { averageCount = averageCount.substring(0, 3); } mTvDistriHint.setText(averageHead + averageCount + averageTail + wasteBook +wasteCount); } private void getDistributionData() { Map<Integer, Integer> freqCount = new TreeMap<>(); Map<Event, Integer> eventsMap = new HashMap<>(); ArrayList<Event> events = mDataManager.getEventManager().getEvents(); for (Event event: events) { int count = ThoughtUtils.getEventCount(getActivity(), event.getId()); eventsMap.put(event, count); if (!freqCount.containsKey(count)) { freqCount.put(count, 1); } else { int freq = freqCount.get(count) + 1; freqCount.put(count, freq); } } ArrayList<Map.Entry<Integer, Integer>> freqCountSort = new ArrayList<>(freqCount.entrySet()); Collections.sort(freqCountSort, new Comparator<Map.Entry<Integer, Integer>>() { @Override public int compare(Map.Entry<Integer, Integer> lhs, Map.Entry<Integer, Integer> rhs) { return rhs.getValue() - lhs.getValue(); } }); mEvents = new ArrayList<>(eventsMap.entrySet()); Collections.sort(mEvents, new Comparator<Map.Entry<Event, Integer>>() { @Override public int compare(Map.Entry<Event, Integer> lhs, Map.Entry<Event, Integer> rhs) { return rhs.getValue() - lhs.getValue(); } }); // 获取流水帐数目 fix bug4. if (!freqCount.isEmpty() && freqCount.containsKey(1)) { mWasteBookCount = freqCount.get(1); } else { mWasteBookCount = 0; } ArrayList<String> xVals = new ArrayList<>(); ArrayList<Entry> yVals = new ArrayList<>(); int distributionCount = freqCountSort.size() < DISTRIBUTION_COUNT ? freqCountSort.size() : DISTRIBUTION_COUNT; for (int i=0; i<distributionCount; i++) { if (1.0f * freqCountSort.get(i).getValue() / mEventCount < 0.1) { xVals.add(String.valueOf(freqCountSort.get(i).getKey())); } else { xVals.add(String.valueOf(freqCountSort.get(i).getKey()) + getString(R.string.thought_count_pie)); } yVals.add(new Entry(freqCountSort.get(i).getValue(), i)); } PieDataSet set = new PieDataSet(yVals, "事件数目"); set.setSliceSpace(3f); ArrayList<Integer> colors = new ArrayList<Integer>(); for (int c : ColorTemplate.VORDIPLOM_COLORS) colors.add(c); for (int c : ColorTemplate.JOYFUL_COLORS) colors.add(c); for (int c : ColorTemplate.COLORFUL_COLORS) colors.add(c); for (int c : ColorTemplate.LIBERTY_COLORS) colors.add(c); for (int c : ColorTemplate.PASTEL_COLORS) colors.add(c); colors.add(ColorTemplate.getHoloBlue()); set.setColors(colors); PieData d = new PieData(xVals, set); d.setValueFormatter(new PercentFormatter()); d.setValueTextSize(11f); d.setValueTextColor(mPrimaryColorDark); mPieData = d; } } }