package com.ronakmanglani.watchlist.ui.fragment; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.android.volley.AuthFailureError; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonArrayRequest; import com.ronakmanglani.watchlist.R; import com.ronakmanglani.watchlist.WatchlistApp; import com.ronakmanglani.watchlist.ui.activity.ReviewActivity; import com.ronakmanglani.watchlist.ui.activity.ReviewDetailActivity; import com.ronakmanglani.watchlist.ui.adapter.ReviewAdapter; import com.ronakmanglani.watchlist.model.Review; import com.ronakmanglani.watchlist.api.ApiHelper; import com.ronakmanglani.watchlist.util.TextUtil; import com.ronakmanglani.watchlist.api.VolleySingleton; import org.json.JSONArray; import org.json.JSONObject; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Map; import butterknife.BindView; import butterknife.BindBool; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; public class ReviewFragment extends Fragment implements ReviewAdapter.OnReviewClickListener { private Unbinder unbinder; private String movieId; private String movieName; private ReviewAdapter adapter; private LinearLayoutManager layoutManager; private int pageToDownload = 1; private int totalPages = 1; private boolean isLoading = false; private boolean isLoadingLocked = false; @BindBool(R.bool.is_tablet) boolean isTablet; @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.toolbar_title) TextView toolbarTitle; @BindView(R.id.toolbar_subtitle) TextView toolbarSubtitle; @BindView(R.id.review_list) RecyclerView reviewList; @BindView(R.id.error_message) View errorMessage; @BindView(R.id.no_results) View noResults; @BindView(R.id.no_results_message) TextView noResultsMessage; @BindView(R.id.progress_circle) View progressCircle; @BindView(R.id.loading_more) View loadingMore; // Fragment lifecycle @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_review,container,false); unbinder = ButterKnife.bind(this, v); // Initialize variables movieId = getArguments().getString(WatchlistApp.MOVIE_ID); movieName = getArguments().getString(WatchlistApp.MOVIE_NAME); // Setup toolbar toolbar.setTitle(""); toolbarTitle.setText(R.string.reviews_title); toolbarSubtitle.setText(movieName); toolbar.setNavigationIcon(ContextCompat.getDrawable(getActivity(), R.drawable.action_home)); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { getActivity().finish(); } }); // Setup RecyclerView adapter = new ReviewAdapter(new ArrayList<Review>(), this); layoutManager = new LinearLayoutManager(getContext()); reviewList.setHasFixedSize(true); reviewList.setLayoutManager(layoutManager); reviewList.setAdapter(adapter); reviewList.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // Load more data if reached the end of the list if (layoutManager.findLastVisibleItemPosition() == adapter.reviewList.size() - 1 && !isLoadingLocked && !isLoading) { if (pageToDownload < totalPages) { loadingMore.setVisibility(View.VISIBLE); downloadMovieReviews(); } } } }); // Download reviews if (savedInstanceState == null || !savedInstanceState.containsKey(WatchlistApp.REVIEW_LIST)) { downloadMovieReviews(); } else { adapter.reviewList = savedInstanceState.getParcelableArrayList(WatchlistApp.REVIEW_LIST); totalPages = savedInstanceState.getInt(WatchlistApp.TOTAL_PAGES); pageToDownload = savedInstanceState.getInt(WatchlistApp.PAGE_TO_DOWNLOAD); isLoadingLocked = savedInstanceState.getBoolean(WatchlistApp.IS_LOCKED); isLoading = savedInstanceState.getBoolean(WatchlistApp.IS_LOADING); // If download stopped, download again, else display list if (isLoading) { if (pageToDownload > 1) { progressCircle.setVisibility(View.GONE); reviewList.setVisibility(View.VISIBLE); loadingMore.setVisibility(View.VISIBLE); } downloadMovieReviews(); } else { onDownloadSuccessful(); } } return v; } @Override public void onSaveInstanceState(Bundle outState) { if (layoutManager != null && adapter != null) { outState.putParcelableArrayList(WatchlistApp.REVIEW_LIST, adapter.reviewList); outState.putBoolean(WatchlistApp.IS_LOADING, isLoading); outState.putBoolean(WatchlistApp.IS_LOCKED, isLoadingLocked); outState.putInt(WatchlistApp.PAGE_TO_DOWNLOAD, pageToDownload); outState.putInt(WatchlistApp.TOTAL_PAGES, totalPages); } super.onSaveInstanceState(outState); } @Override public void onDestroyView() { super.onDestroyView(); VolleySingleton.getInstance().requestQueue.cancelAll(this.getClass().getName()); unbinder.unbind(); } // JSON parsing and display private void downloadMovieReviews() { if (adapter == null) { adapter = new ReviewAdapter(new ArrayList<Review>(), this); reviewList.setAdapter(adapter); } JsonArrayRequest request = new JsonArrayRequest( Request.Method.GET, ApiHelper.getMovieReviewsLink(movieId, pageToDownload), null, new Response.Listener<JSONArray>() { @Override public void onResponse(JSONArray array) { try { for (int i = 0; i < array.length(); i++) { JSONObject review = array.getJSONObject(i); String id = review.getString("id"); String comment = review.getString("comment"); boolean hasSpoiler = review.getBoolean("spoiler"); // Get date and format it String inputTime = review.getString("created_at").substring(0, 10); DateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd"); Date date = inputFormat.parse(inputTime); DateFormat outputFormat = new SimpleDateFormat("dd MMM yyyy"); String createdAt = outputFormat.format(date); // Get user name JSONObject user = review.getJSONObject("user"); String userName = user.getString("username"); if (!user.getBoolean("private")) { String name = user.getString("name"); if (!TextUtil.isNullOrEmpty(name)) { userName = name; } } adapter.reviewList.add(new Review(id, userName, comment, createdAt, hasSpoiler)); } onDownloadSuccessful(); } catch (Exception ex) { // Parsing error onDownloadFailed(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { if (volleyError.networkResponse.statusCode == 404 || volleyError.networkResponse.statusCode == 405) { // No such movie exists onDownloadSuccessful(); } else { // Network error, failed to load onDownloadFailed(); } } }) { // Add Request Headers @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> params = new HashMap<>(); params.put("Content-type", "application/json"); params.put("trakt-api-key", ApiHelper.getTraktKey(getContext())); params.put("trakt-api-version", "2"); return params; } // Get Response Headers @Override protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) { pageToDownload = Integer.parseInt(response.headers.get("X-Pagination-Page")) + 1; totalPages = Integer.parseInt(response.headers.get("X-Pagination-Page-Count")); return super.parseNetworkResponse(response); } }; isLoading = true; request.setTag(getClass().getName()); VolleySingleton.getInstance().requestQueue.add(request); } private void onDownloadSuccessful() { isLoading = false; if (adapter.reviewList.size() == 0) { noResultsMessage.setText(R.string.reviews_no_results); noResults.setVisibility(View.VISIBLE); errorMessage.setVisibility(View.GONE); progressCircle.setVisibility(View.GONE); loadingMore.setVisibility(View.GONE); reviewList.setVisibility(View.GONE); if (isTablet) { ((ReviewActivity) getActivity()).loadDetailFragmentWith("null", null); } } else { errorMessage.setVisibility(View.GONE); progressCircle.setVisibility(View.GONE); loadingMore.setVisibility(View.GONE); reviewList.setVisibility(View.VISIBLE); adapter.notifyDataSetChanged(); if (isTablet) { ((ReviewActivity) getActivity()).loadDetailFragmentWith(movieName, adapter.reviewList.get(0)); } } } private void onDownloadFailed() { isLoading = false; if (pageToDownload == 1) { errorMessage.setVisibility(View.VISIBLE); reviewList.setVisibility(View.GONE); } else { errorMessage.setVisibility(View.GONE); reviewList.setVisibility(View.VISIBLE); isLoadingLocked = true; } progressCircle.setVisibility(View.GONE); loadingMore.setVisibility(View.GONE); } // Click events @OnClick(R.id.try_again) public void onTryAgainClicked() { // Toggle visibility reviewList.setVisibility(View.GONE); errorMessage.setVisibility(View.GONE); progressCircle.setVisibility(View.VISIBLE); // Reset counters pageToDownload = 1; totalPages = 1; // Download reviews again adapter = null; downloadMovieReviews(); } @Override public void onReviewClicked(int position) { Review review = adapter.reviewList.get(position); if (isTablet) { ((ReviewActivity) getActivity()).loadDetailFragmentWith(movieName, review); } else { Intent intent = new Intent(getContext(), ReviewDetailActivity.class); intent.putExtra(WatchlistApp.MOVIE_NAME, movieName); intent.putExtra(WatchlistApp.REVIEW_OBJECT, review); startActivity(intent); } } }