package com.boardgamegeek.ui;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.TextView;
import com.boardgamegeek.R;
import com.boardgamegeek.provider.BggContract;
import com.boardgamegeek.provider.BggContract.Artists;
import com.boardgamegeek.provider.BggContract.Categories;
import com.boardgamegeek.provider.BggContract.Designers;
import com.boardgamegeek.provider.BggContract.Games;
import com.boardgamegeek.provider.BggContract.GamesExpansions;
import com.boardgamegeek.provider.BggContract.Mechanics;
import com.boardgamegeek.provider.BggContract.Publishers;
import com.boardgamegeek.util.ActivityUtils;
import com.boardgamegeek.util.AnimationUtils;
import com.boardgamegeek.util.UIUtils;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import timber.log.Timber;
public class GameDetailFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private GameDetailAdapter adapter;
private int gameId;
private int queryToken;
private Query query;
Unbinder unbinder;
@BindView(R.id.root_container) CoordinatorLayout containerView;
@BindView(android.R.id.progress) View progressView;
@BindView(android.R.id.empty) TextView emptyView;
@BindView(android.R.id.list) RecyclerView recyclerView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_game_details, container, false);
unbinder = ButterKnife.bind(this, rootView);
setUpRecyclerView();
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final Intent intent = UIUtils.fragmentArgumentsToIntent(getArguments());
gameId = intent.getIntExtra(ActivityUtils.KEY_GAME_ID, BggContract.INVALID_ID);
queryToken = intent.getIntExtra(ActivityUtils.KEY_QUERY_TOKEN, BggContract.INVALID_ID);
makeQuery();
if (query != null) {
getLoaderManager().restartLoader(queryToken, getArguments(), this);
} else {
final String message = getString(R.string.msg_invalid_token, String.valueOf(queryToken));
Timber.w(message);
emptyView.setText(message);
AnimationUtils.fadeIn(emptyView);
AnimationUtils.fadeOut(recyclerView);
AnimationUtils.fadeOut(progressView);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (unbinder != null) unbinder.unbind();
}
private void setUpRecyclerView() {
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle data) {
return new CursorLoader(getActivity(), query.getUri(), query.getProjection(), query.getSelection(), query.getSelectionArgs(), null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (getActivity() == null) {
return;
}
if (adapter == null) {
adapter = new GameDetailAdapter(getActivity(), cursor, query);
recyclerView.setAdapter(adapter);
}
int token = loader.getId();
if (token == queryToken) {
adapter.changeCursor(cursor);
} else {
Timber.d("Query complete, Not Actionable: %s", token);
cursor.close();
}
AnimationUtils.fadeOut(progressView);
AnimationUtils.fadeIn(getActivity(), recyclerView, isResumed());
}
public class GameDetailAdapter extends RecyclerView.Adapter<GameDetailAdapter.DetailViewHolder> {
private final LayoutInflater inflater;
private Cursor cursor;
private final Query query;
public GameDetailAdapter(Context context, Cursor cursor, Query query) {
this.cursor = cursor;
this.query = query;
inflater = LayoutInflater.from(context);
setHasStableIds(true);
}
@Override
public DetailViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.row_text, parent, false);
return new DetailViewHolder(view);
}
@Override
public void onBindViewHolder(DetailViewHolder holder, int position) {
if (cursor.moveToPosition(position)) {
holder.bind(cursor);
}
}
@Override
public int getItemCount() {
return cursor.getCount();
}
@Override
public long getItemId(int position) {
if (cursor.moveToPosition(position)) {
return cursor.getInt(cursor.getColumnIndex(query.getIdColumnName()));
}
return RecyclerView.NO_ID;
}
public class DetailViewHolder extends RecyclerView.ViewHolder {
@BindView(android.R.id.title) TextView titleView;
private Uri uri;
public DetailViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public void bind(final Cursor cursor) {
titleView.setText(cursor.getString(cursor.getColumnIndex(query.getTitleColumnName())));
uri = query.getUri(cursor);
if (query.isClickable()) {
itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (uri != null) {
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
}
});
}
}
}
public void changeCursor(Cursor cursor) {
Cursor old = swapCursor(cursor);
if (old != null) {
old.close();
}
}
public Cursor swapCursor(Cursor newCursor) {
if (newCursor == cursor) {
return null;
}
Cursor oldCursor = cursor;
cursor = newCursor;
if (newCursor != null) {
notifyDataSetChanged();
} else {
notifyItemRangeRemoved(0, oldCursor.getCount());
}
return oldCursor;
}
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
adapter.changeCursor(null);
}
private void makeQuery() {
if (queryToken == getResources().getInteger(R.integer.query_token_designers)) {
query = new DesignerQuery();
} else if (queryToken == getResources().getInteger(R.integer.query_token_artists)) {
query = new ArtistQuery();
} else if (queryToken == getResources().getInteger(R.integer.query_token_publishers)) {
query = new PublisherQuery();
} else if (queryToken == getResources().getInteger(R.integer.query_token_categories)) {
query = new CategoryQuery();
} else if (queryToken == getResources().getInteger(R.integer.query_token_mechanics)) {
query = new MechanicQuery();
} else if (queryToken == getResources().getInteger(R.integer.query_token_expansions)) {
query = new ExpansionQuery();
} else if (queryToken == getResources().getInteger(R.integer.query_token_base_games)) {
query = new BaseGameQuery();
}
}
abstract class Query {
public abstract String[] getProjection();
public abstract String getIdColumnName();
public abstract String getTitleColumnName();
public abstract Uri getUri();
public String getSelection() {
return null;
}
public String[] getSelectionArgs() {
return null;
}
public Uri getUri(Cursor cursor) {
return null;
}
public boolean isClickable() {
return true;
}
}
private class DesignerQuery extends Query {
@Override
public String[] getProjection() {
return new String[] { Designers.DESIGNER_ID, Designers.DESIGNER_NAME, Designers._ID };
}
@Override
public String getIdColumnName() {
return Designers._ID;
}
@Override
public String getTitleColumnName() {
return Designers.DESIGNER_NAME;
}
@Override
public Uri getUri() {
return Games.buildDesignersUri(gameId);
}
@Override
public Uri getUri(Cursor cursor) {
return Designers.buildDesignerUri(cursor.getInt(0));
}
}
private class ArtistQuery extends Query {
@Override
public String[] getProjection() {
return new String[] { Artists.ARTIST_ID, Artists.ARTIST_NAME, Artists._ID };
}
@Override
public String getIdColumnName() {
return Artists._ID;
}
@Override
public String getTitleColumnName() {
return Artists.ARTIST_NAME;
}
@Override
public Uri getUri() {
return Games.buildArtistsUri(gameId);
}
@Override
public Uri getUri(Cursor cursor) {
return Artists.buildArtistUri(cursor.getInt(0));
}
}
private class PublisherQuery extends Query {
@Override
public String[] getProjection() {
return new String[] { Publishers.PUBLISHER_ID, Publishers.PUBLISHER_NAME, Publishers._ID };
}
@Override
public String getIdColumnName() {
return Publishers._ID;
}
@Override
public String getTitleColumnName() {
return Publishers.PUBLISHER_NAME;
}
@Override
public Uri getUri() {
return Games.buildPublishersUri(gameId);
}
@Override
public Uri getUri(Cursor cursor) {
return Publishers.buildPublisherUri(cursor.getInt(0));
}
}
private class CategoryQuery extends Query {
@Override
public String[] getProjection() {
return new String[] { Categories.CATEGORY_ID, Categories.CATEGORY_NAME, Categories._ID };
}
@Override
public String getIdColumnName() {
return Categories._ID;
}
@Override
public String getTitleColumnName() {
return Categories.CATEGORY_NAME;
}
@Override
public Uri getUri() {
return Games.buildCategoriesUri(gameId);
}
@Override
public boolean isClickable() {
return false;
}
}
private class MechanicQuery extends Query {
@Override
public String[] getProjection() {
return new String[] { Mechanics.MECHANIC_ID, Mechanics.MECHANIC_NAME, Mechanics._ID };
}
@Override
public String getIdColumnName() {
return Mechanics._ID;
}
@Override
public String getTitleColumnName() {
return Mechanics.MECHANIC_NAME;
}
@Override
public Uri getUri() {
return Games.buildMechanicsUri(gameId);
}
@Override
public boolean isClickable() {
return false;
}
}
private class ExpansionBaseQuery extends Query {
@Override
public String[] getProjection() {
return new String[] { GamesExpansions.EXPANSION_ID, GamesExpansions.EXPANSION_NAME, GamesExpansions._ID };
}
@Override
public String getIdColumnName() {
return GamesExpansions._ID;
}
@Override
public String getTitleColumnName() {
return GamesExpansions.EXPANSION_NAME;
}
@Override
public Uri getUri() {
return Games.buildExpansionsUri(gameId);
}
public String getSelection() {
return GamesExpansions.INBOUND + "=?";
}
@Override
public Uri getUri(Cursor cursor) {
return Games.buildGameUri(cursor.getInt(0));
}
}
private class ExpansionQuery extends ExpansionBaseQuery {
public String[] getSelectionArgs() {
return new String[] { "0" };
}
}
private class BaseGameQuery extends ExpansionBaseQuery {
public String[] getSelectionArgs() {
return new String[] { "1" };
}
}
}