package com.boardgamegeek.ui; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.boardgamegeek.R; import com.boardgamegeek.io.Adapter; import com.boardgamegeek.io.BggService; import com.boardgamegeek.model.Game.Comment; import com.boardgamegeek.model.ThingResponse; import com.boardgamegeek.provider.BggContract.Games; import com.boardgamegeek.ui.adapter.GameCommentsRecyclerViewAdapter; import com.boardgamegeek.ui.loader.PaginatedLoader; import com.boardgamegeek.ui.model.GameComments; import com.boardgamegeek.ui.model.PaginatedData; import com.boardgamegeek.util.ActivityUtils; import com.boardgamegeek.util.AnimationUtils; import com.boardgamegeek.util.UIUtils; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import hugo.weaving.DebugLog; import icepick.Icepick; import icepick.State; import retrofit2.Call; public class CommentsFragment extends Fragment implements LoaderManager.LoaderCallbacks<PaginatedData<Comment>> { private static final int LOADER_ID = 0; private static final int VISIBLE_THRESHOLD = 5; private GameCommentsRecyclerViewAdapter adapter; private int gameId; @State boolean isSortedByRating = false; private Unbinder unbinder; @BindView(android.R.id.progress) View progressView; @BindView(android.R.id.empty) View emptyView; @BindView(android.R.id.list) RecyclerView recyclerView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Icepick.restoreInstanceState(this, savedInstanceState); final Intent intent = UIUtils.fragmentArgumentsToIntent(getArguments()); gameId = Games.getGameId(intent.getData()); isSortedByRating = intent.getIntExtra(ActivityUtils.KEY_SORT, CommentsActivity.SORT_USER) == CommentsActivity.SORT_RATING; } @DebugLog @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_comments, container, false); unbinder = ButterKnife.bind(this, rootView); setUpRecyclerView(); return rootView; } @Override public void onResume() { super.onResume(); getLoaderManager().initLoader(LOADER_ID, null, this); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } @Override public void onDestroyView() { super.onDestroyView(); if (unbinder != null) unbinder.unbind(); } private void setUpRecyclerView() { final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); layoutManager.setOrientation(LinearLayoutManager.VERTICAL); recyclerView.setLayoutManager(layoutManager); recyclerView.setHasFixedSize(true); recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL)); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); final CommentsLoader loader = getLoader(); if (loader != null && !loader.isLoading() && loader.hasMoreResults()) { int totalItemCount = layoutManager.getItemCount(); int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); if (lastVisibleItemPosition + VISIBLE_THRESHOLD >= totalItemCount) { loadMoreResults(); } } } }); } @DebugLog private void loadMoreResults() { if (isAdded()) { Loader<List<Comment>> loader = getLoaderManager().getLoader(LOADER_ID); if (loader != null) { loader.forceLoad(); } } } @DebugLog private CommentsLoader getLoader() { if (isAdded()) { Loader<PaginatedData<Comment>> loader = getLoaderManager().getLoader(LOADER_ID); return (CommentsLoader) loader; } return null; } @Override public Loader<PaginatedData<Comment>> onCreateLoader(int id, Bundle data) { return new CommentsLoader(getActivity(), gameId, isSortedByRating); } @Override public void onLoadFinished(Loader<PaginatedData<Comment>> loader, PaginatedData<Comment> data) { if (getActivity() == null) { return; } if (adapter == null) { adapter = new GameCommentsRecyclerViewAdapter(getActivity(), data); recyclerView.setAdapter(adapter); } else { adapter.update(data); } if (adapter.getItemCount() == 0) { AnimationUtils.fadeIn(getActivity(), emptyView, isResumed()); } else { AnimationUtils.fadeIn(getActivity(), recyclerView, isResumed()); } AnimationUtils.fadeOut(progressView); } @Override public void onLoaderReset(Loader<PaginatedData<Comment>> loader) { } private static class CommentsLoader extends PaginatedLoader<Comment> { final BggService bggService; private final int gameId; private final boolean isSortedByRating; public CommentsLoader(Context context, int gameId, boolean isSortedByRating) { super(context); bggService = Adapter.createForXml(); this.gameId = gameId; this.isSortedByRating = isSortedByRating; } @Override protected PaginatedData<Comment> fetchPage(int pageNumber) { GameComments data; Call<ThingResponse> call; if (isSortedByRating) { call = bggService.thingWithRatings(gameId, pageNumber); } else { call = bggService.thingWithComments(gameId, pageNumber); } try { data = new GameComments(call.execute().body().getGames().get(0).comments, pageNumber); } catch (Exception e) { data = new GameComments(e); } return data; } } }