package com.boardgamegeek.ui;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ScrollView;
import android.widget.Switch;
import android.widget.TextView;
import com.boardgamegeek.R;
import com.boardgamegeek.provider.BggContract;
import com.boardgamegeek.provider.BggContract.GamePollResults;
import com.boardgamegeek.provider.BggContract.GamePollResultsResult;
import com.boardgamegeek.provider.BggContract.GamePolls;
import com.boardgamegeek.provider.BggContract.Games;
import com.boardgamegeek.ui.widget.IntegerValueFormatter;
import com.boardgamegeek.ui.widget.PlayerNumberRow;
import com.boardgamegeek.ui.widget.PollKeyRow;
import com.boardgamegeek.util.ActivityUtils;
import com.boardgamegeek.util.ColorUtils;
import com.boardgamegeek.util.UIUtils;
import com.github.mikephil.charting.animation.Easing.EasingOption;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.Legend.LegendPosition;
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.highlight.Highlight;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import java.text.DecimalFormat;
import java.text.Format;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
import timber.log.Timber;
public class PollFragment extends DialogFragment implements LoaderCallbacks<Cursor>, OnChartValueSelectedListener {
public static final String LANGUAGE_DEPENDENCE = "language_dependence";
public static final String SUGGESTED_PLAYER_AGE = "suggested_playerage";
public static final String SUGGESTED_NUM_PLAYERS = "suggested_numplayers";
// The following should not be externalized, they're used to match the incoming XML
private static final String BEST = "Best";
private static final String RECOMMENDED = "Recommended";
private static final String NOT_RECOMMENDED = "Not Recommended";
private static final Format FORMAT = new DecimalFormat("#0");
private String pollType;
private int totalVoteCount;
private int keyCount;
private boolean isBarChart;
private Uri pollResultUri;
private int[] chartColors;
private Snackbar snackbar;
private Unbinder unbinder;
@BindView(R.id.progress) View progressView;
@BindView(R.id.poll_scroll) ScrollView scrollView;
@BindView(R.id.poll_vote_total) TextView totalVoteView;
@BindView(R.id.pie_chart) PieChart pieChart;
@BindView(R.id.poll_list) LinearLayout pollList;
@BindView(R.id.poll_key) LinearLayout keyList;
@BindView(R.id.poll_key2) LinearLayout keyList2;
@BindView(R.id.poll_key_container) View keyContainer;
@BindView(R.id.poll_key_divider) View keyDivider;
@BindView(R.id.no_votes_switch) Switch noVotesSwitch;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = UIUtils.fragmentArgumentsToIntent(getArguments());
int gameId = intent.getIntExtra(ActivityUtils.KEY_GAME_ID, BggContract.INVALID_ID);
pollType = intent.getStringExtra(ActivityUtils.KEY_TYPE);
pollResultUri = Games.buildPollResultsResultUri(gameId, pollType);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_poll, container, false);
unbinder = ButterKnife.bind(this, rootView);
pieChart.setDrawSliceText(false);
pieChart.setRotationEnabled(false);
Legend legend = pieChart.getLegend();
legend.setPosition(LegendPosition.BELOW_CHART_LEFT);
legend.setWordWrapEnabled(true);
pieChart.setDescription(null);
pieChart.setOnChartValueSelectedListener(this);
return rootView;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// size the graph to be 80% of the screen width
DisplayMetrics display = this.getResources().getDisplayMetrics();
ViewGroup.LayoutParams lp = pieChart.getLayoutParams();
lp.width = (int) (display.widthPixels * .8);
pieChart.setLayoutParams(lp);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (pollType == null) {
Timber.w("Missing type");
}
switch (pollType) {
case LANGUAGE_DEPENDENCE:
getDialog().setTitle(R.string.language_dependence);
chartColors = ColorUtils.FIVE_STAGE_COLORS;
break;
case SUGGESTED_PLAYER_AGE:
getDialog().setTitle(R.string.suggested_playerage);
chartColors = null;
break;
case SUGGESTED_NUM_PLAYERS:
isBarChart = true;
getDialog().setTitle(R.string.suggested_numplayers);
addKeyRow(ContextCompat.getColor(getActivity(), R.color.best), BEST);
addKeyRow(ContextCompat.getColor(getActivity(), R.color.recommended), RECOMMENDED);
addKeyRow(ContextCompat.getColor(getActivity(), R.color.not_recommended), NOT_RECOMMENDED);
break;
}
getLoaderManager().restartLoader(Query._TOKEN, null, this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle data) {
CursorLoader loader = null;
if (id == Query._TOKEN) {
loader = new CursorLoader(getActivity(), pollResultUri, Query.PROJECTION, null, null, Query.SORT);
}
return loader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (getActivity() == null) {
return;
}
if (loader.getId() == Query._TOKEN) {
if (cursor != null && cursor.moveToFirst()) {
totalVoteCount = cursor.getInt(Query.POLL_TOTAL_VOTES);
} else {
totalVoteCount = 0;
}
totalVoteView.setText(getResources().getQuantityString(R.plurals.votes_suffix, totalVoteCount, totalVoteCount));
totalVoteView.setVisibility(!isBarChart ? View.GONE : View.VISIBLE);
pieChart.setVisibility((totalVoteCount == 0 || isBarChart) ? View.GONE : View.VISIBLE);
pollList.setVisibility((totalVoteCount == 0 || !isBarChart) ? View.GONE : View.VISIBLE);
keyContainer.setVisibility((totalVoteCount == 0 || !isBarChart) ? View.GONE : View.VISIBLE);
noVotesSwitch.setVisibility((totalVoteCount == 0 || !isBarChart) ? View.GONE : View.VISIBLE);
if (totalVoteCount > 0) {
if (isBarChart) {
createBarChart(cursor);
} else {
createPieChart(cursor, totalVoteCount);
}
}
progressView.setVisibility(View.GONE);
scrollView.setVisibility(View.VISIBLE);
} else {
if (cursor != null) {
cursor.close();
}
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
@Override
public void onValueSelected(Entry e, int dataSetIndex, Highlight h) {
if (e == null || pieChart == null) {
if (snackbar != null) {
snackbar.dismiss();
}
return;
}
final View view = getView();
if (view != null) {
String message = getString(R.string.pie_chart_click_description, FORMAT.format(e.getVal()), pieChart.getXValue(e.getXIndex()));
snackbar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE);
snackbar.show();
}
}
@Override
public void onNothingSelected() {
if (snackbar != null) {
snackbar.dismiss();
}
}
@OnClick(R.id.no_votes_switch)
public void onNoVotesClick() {
for (int i = 0; i < pollList.getChildCount(); i++) {
PlayerNumberRow row = (PlayerNumberRow) pollList.getChildAt(i);
row.showNoVotes(noVotesSwitch.isChecked());
}
}
private void createBarChart(Cursor cursor) {
pollList.removeAllViews();
PlayerNumberRow row = null;
String playerNumber;
String lastPlayerNumber = "-1";
do {
playerNumber = cursor.getString(Query.POLL_RESULTS_PLAYERS);
if (!lastPlayerNumber.equals(playerNumber)) {
lastPlayerNumber = playerNumber;
row = new PlayerNumberRow(getActivity());
row.setText(playerNumber);
row.setTotal(totalVoteCount);
row.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (int i = 0; i < pollList.getChildCount(); i++) {
((PlayerNumberRow) pollList.getChildAt(i)).clearHighlight();
}
PlayerNumberRow row = (PlayerNumberRow) v;
row.setHighlight();
int[] voteCount = row.getVotes();
for (int i = 0; i < keyList.getChildCount(); i++) {
((PollKeyRow) keyList.getChildAt(i)).setInfo(String.valueOf(voteCount[i]));
}
}
});
pollList.addView(row);
}
if (row != null) {
String value = cursor.getString(Query.POLL_RESULTS_RESULT_VALUE);
int votes = cursor.getInt(Query.POLL_RESULTS_RESULT_VOTES);
if (value == null) {
Timber.w("Missing key");
} else {
switch (value) {
case BEST:
row.setBest(votes);
break;
case RECOMMENDED:
row.setRecommended(votes);
break;
case NOT_RECOMMENDED:
row.setNotRecommended(votes);
break;
default:
Timber.w("Bad key: %s", value);
break;
}
}
}
} while (cursor.moveToNext());
}
private void createPieChart(Cursor cursor, int voteCount) {
List<String> labels = new ArrayList<>();
List<Entry> entries = new ArrayList<>();
int index = 0;
do {
String value = cursor.getString(Query.POLL_RESULTS_RESULT_VALUE);
int votes = cursor.getInt(Query.POLL_RESULTS_RESULT_VOTES);
labels.add(value);
entries.add(new Entry(votes, index));
index++;
} while (cursor.moveToNext());
PieDataSet dataSet = new PieDataSet(entries, "");
dataSet.setValueFormatter(new IntegerValueFormatter(true));
if (chartColors != null) {
dataSet.setColors(chartColors);
} else {
dataSet.setColors(ColorUtils.createColors(index));
}
PieData data = new PieData(labels, dataSet);
pieChart.setData(data);
pieChart.setCenterText(getResources().getQuantityString(R.plurals.votes_suffix, voteCount, voteCount));
pieChart.animateY(1000, EasingOption.EaseOutCubic);
}
private void addKeyRow(int color, CharSequence text) {
PollKeyRow pkr = new PollKeyRow(getActivity());
pkr.setColor(color);
pkr.setText(text);
keyCount++;
if (keyCount > 6) {
keyList2.addView(pkr);
keyList2.setLayoutParams(new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1.0f));
keyDivider.setVisibility(View.VISIBLE);
} else {
keyList.addView(pkr);
}
}
private interface Query {
int _TOKEN = 0x0;
String[] PROJECTION = { GamePollResultsResult.POLL_RESULTS_RESULT_VALUE,
GamePollResultsResult.POLL_RESULTS_RESULT_VOTES, GamePollResults.POLL_RESULTS_PLAYERS,
GamePolls.POLL_TOTAL_VOTES };
int POLL_RESULTS_RESULT_VALUE = 0;
int POLL_RESULTS_RESULT_VOTES = 1;
int POLL_RESULTS_PLAYERS = 2;
int POLL_TOTAL_VOTES = 3;
String SORT = GamePollResultsResult.POLL_RESULTS_SORT_INDEX + " ASC, "
+ GamePollResultsResult.POLL_RESULTS_RESULT_SORT_INDEX;
}
}