package com.boardgamegeek.ui;
import android.content.Context;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.widget.ContentLoadingProgressBar;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Pair;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.boardgamegeek.R;
import com.boardgamegeek.io.Adapter;
import com.boardgamegeek.io.BggService;
import com.boardgamegeek.model.HotGame;
import com.boardgamegeek.model.HotnessResponse;
import com.boardgamegeek.ui.loader.BggLoader;
import com.boardgamegeek.ui.loader.SafeResponse;
import com.boardgamegeek.util.ActivityUtils;
import com.boardgamegeek.util.AnimationUtils;
import com.boardgamegeek.util.ImageUtils;
import com.boardgamegeek.util.PreferencesUtils;
import com.boardgamegeek.util.PresentationUtils;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import hugo.weaving.DebugLog;
import retrofit2.Call;
public class HotnessFragment extends Fragment implements LoaderManager.LoaderCallbacks<SafeResponse<HotnessResponse>>, ActionMode.Callback {
private static final int LOADER_ID = 1;
private HotGamesAdapter adapter;
private ActionMode actionMode;
private Unbinder unbinder;
@BindView(R.id.root_container) CoordinatorLayout containerView;
@BindView(android.R.id.progress) ContentLoadingProgressBar progressView;
@BindView(android.R.id.empty) TextView emptyView;
@BindView(android.R.id.list) RecyclerView recyclerView;
@DebugLog
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_hotness, container, false);
unbinder = ButterKnife.bind(this, rootView);
setUpRecyclerView();
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (unbinder != null) unbinder.unbind();
}
private void setUpRecyclerView() {
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setHasFixedSize(true);
}
@Override
public Loader<SafeResponse<HotnessResponse>> onCreateLoader(int id, Bundle data) {
return new HotnessLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<SafeResponse<HotnessResponse>> loader, SafeResponse<HotnessResponse> data) {
if (getActivity() == null) {
return;
}
if (adapter == null) {
adapter = new HotGamesAdapter(getActivity(),
data == null || data.getBody() == null ? new ArrayList<HotGame>() : data.getBody().games,
new Callback() {
@Override
public boolean onItemClick(int position) {
if (actionMode == null) {
return false;
}
toggleSelection(position);
return true;
}
@Override
public boolean onItemLongClick(int position) {
if (actionMode != null) {
return false;
}
actionMode = getActivity().startActionMode(HotnessFragment.this);
toggleSelection(position);
return true;
}
private void toggleSelection(int position) {
adapter.toggleSelection(position);
int count = adapter.getSelectedItemCount();
if (count == 0) {
actionMode.finish();
} else {
actionMode.setTitle(getResources().getQuantityString(R.plurals.msg_games_selected, count, count));
actionMode.invalidate();
}
}
});
recyclerView.setAdapter(adapter);
} else {
adapter.notifyDataSetChanged();
}
if (data == null) {
AnimationUtils.fadeOut(recyclerView);
AnimationUtils.fadeIn(emptyView);
} else if (data.hasError()) {
emptyView.setText(getString(R.string.empty_http_error, data.getErrorMessage()));
AnimationUtils.fadeOut(recyclerView);
AnimationUtils.fadeIn(emptyView);
} else {
AnimationUtils.fadeOut(emptyView);
AnimationUtils.fadeIn(getActivity(), recyclerView, isResumed());
}
progressView.hide();
}
@Override
public void onLoaderReset(Loader<SafeResponse<HotnessResponse>> loader) {
}
private static class HotnessLoader extends BggLoader<SafeResponse<HotnessResponse>> {
private final BggService bggService;
public HotnessLoader(Context context) {
super(context);
bggService = Adapter.createForXml();
}
@Override
public SafeResponse<HotnessResponse> loadInBackground() {
Call<HotnessResponse> call = bggService.getHotness(BggService.HOTNESS_TYPE_BOARDGAME);
return new SafeResponse<>(call);
}
}
public interface Callback {
boolean onItemClick(int position);
boolean onItemLongClick(int position);
}
public class HotGamesAdapter extends RecyclerView.Adapter<HotGamesAdapter.ViewHolder> {
private final LayoutInflater inflater;
private final List<HotGame> games;
private final Callback callback;
private final SparseBooleanArray selectedItems;
public HotGamesAdapter(Context context, List<HotGame> games, Callback callback) {
this.games = games;
this.callback = callback;
inflater = LayoutInflater.from(context);
selectedItems = new SparseBooleanArray();
setHasStableIds(true);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.row_hotness, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(getItem(position), position);
}
@Override
public int getItemCount() {
return games == null ? 0 : games.size();
}
@Override
public long getItemId(int position) {
return position;
}
public HotGame getItem(int position) {
return games.get(position);
}
public class ViewHolder extends RecyclerView.ViewHolder {
private int gameId;
private String gameName;
@BindView(R.id.name) TextView name;
@BindView(R.id.year) TextView year;
@BindView(R.id.rank) TextView rank;
@BindView(R.id.thumbnail) ImageView thumbnail;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public void bind(HotGame game, final int position) {
if (game == null) return;
gameId = game.id;
gameName = game.name;
name.setText(game.name);
year.setText(PresentationUtils.describeYear(name.getContext(), game.yearPublished));
rank.setText(String.valueOf(game.rank));
ImageUtils.loadThumbnail(game.thumbnailUrl, thumbnail);
itemView.setActivated(selectedItems.get(position, false));
itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
boolean handled = false;
if (callback != null) {
handled = callback.onItemClick(position);
}
if (!handled) {
ActivityUtils.launchGame(itemView.getContext(), gameId, gameName);
}
}
});
itemView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return callback != null && callback.onItemLongClick(position);
}
});
}
}
public void toggleSelection(int position) {
if (selectedItems.get(position, false)) {
selectedItems.delete(position);
} else {
selectedItems.put(position, true);
}
notifyItemChanged(position);
}
public void clearSelections() {
selectedItems.clear();
notifyDataSetChanged();
}
public int getSelectedItemCount() {
return selectedItems.size();
}
public List<Integer> getSelectedItems() {
List<Integer> items = new ArrayList<>(selectedItems.size());
for (int i = 0; i < selectedItems.size(); i++) {
items.add(selectedItems.keyAt(i));
}
return items;
}
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
adapter.clearSelections();
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.game_context, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
int count = adapter.getSelectedItemCount();
menu.findItem(R.id.menu_log_play).setVisible(count == 1 && PreferencesUtils.showLogPlay(getActivity()));
menu.findItem(R.id.menu_log_play_quick).setVisible(PreferencesUtils.showQuickLogPlay(getActivity()));
menu.findItem(R.id.menu_link).setVisible(count == 1);
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
actionMode = null;
adapter.clearSelections();
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
final List<Integer> selectedItems = adapter.getSelectedItems();
if (selectedItems.size() == 0) return false;
HotGame game = adapter.getItem(selectedItems.get(0));
switch (item.getItemId()) {
case R.id.menu_log_play:
mode.finish();
ActivityUtils.logPlay(getActivity(), game.id, game.name, game.thumbnailUrl, game.thumbnailUrl, false);
return true;
case R.id.menu_log_play_quick:
mode.finish();
String text = getResources().getQuantityString(R.plurals.msg_logging_plays, adapter.getSelectedItemCount());
Snackbar.make(containerView, text, Snackbar.LENGTH_SHORT).show();
for (int position : selectedItems) {
HotGame g = adapter.getItem(position);
ActivityUtils.logQuickPlay(getActivity(), g.id, g.name);
}
return true;
case R.id.menu_share:
mode.finish();
final String shareMethod = "Hotness";
if (adapter.getSelectedItemCount() == 1) {
ActivityUtils.shareGame(getActivity(), game.id, game.name, shareMethod);
} else {
List<Pair<Integer, String>> games = new ArrayList<>(adapter.getSelectedItemCount());
for (int position : selectedItems) {
HotGame g = adapter.getItem(position);
games.add(Pair.create(g.id, g.name));
}
ActivityUtils.shareGames(getActivity(), games, shareMethod);
}
return true;
case R.id.menu_link:
mode.finish();
ActivityUtils.linkBgg(getActivity(), game.id);
return true;
}
return false;
}
}