Java tutorial
/* * Copyright 2016. Dmitry Malkovich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.dmitrymalkovich.android.popularmoviesapp.details; import android.app.Activity; import android.content.ContentValues; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; import android.os.AsyncTask; import android.support.annotation.Nullable; import android.support.design.widget.CollapsingToolbarLayout; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.ShareActionProvider; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.dmitrymalkovich.android.popularmoviesapp.data.MovieContract; import com.dmitrymalkovich.android.popularmoviesapp.network.Movie; import com.dmitrymalkovich.android.popularmoviesapp.MovieListActivity; import com.dmitrymalkovich.android.popularmoviesapp.R; import com.dmitrymalkovich.android.popularmoviesapp.network.Review; import com.dmitrymalkovich.android.popularmoviesapp.network.Trailer; import com.squareup.picasso.Picasso; import java.util.ArrayList; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; /** * A fragment representing a single Movie detail screen. * This fragment is either contained in a {@link MovieListActivity} * in two-pane mode (on tablets) or a {@link MovieDetailActivity} * on handsets. */ public class MovieDetailFragment extends Fragment implements FetchTrailersTask.Listener, TrailerListAdapter.Callbacks, FetchReviewsTask.Listener, ReviewListAdapter.Callbacks { @SuppressWarnings("unused") public static final String LOG_TAG = MovieDetailFragment.class.getSimpleName(); /** * The fragment argument representing the movie that this fragment * represents. */ public static final String ARG_MOVIE = "ARG_MOVIE"; public static final String EXTRA_TRAILERS = "EXTRA_TRAILERS"; public static final String EXTRA_REVIEWS = "EXTRA_REVIEWS"; private Movie mMovie; private TrailerListAdapter mTrailerListAdapter; private ReviewListAdapter mReviewListAdapter; private ShareActionProvider mShareActionProvider; @Bind(R.id.trailer_list) RecyclerView mRecyclerViewForTrailers; @Bind(R.id.review_list) RecyclerView mRecyclerViewForReviews; @Bind(R.id.movie_title) TextView mMovieTitleView; @Bind(R.id.movie_overview) TextView mMovieOverviewView; @Bind(R.id.movie_release_date) TextView mMovieReleaseDateView; @Bind(R.id.movie_user_rating) TextView mMovieRatingView; @Bind(R.id.movie_poster) ImageView mMoviePosterView; @Bind(R.id.button_watch_trailer) Button mButtonWatchTrailer; @Bind(R.id.button_mark_as_favorite) Button mButtonMarkAsFavorite; @Bind(R.id.button_remove_from_favorites) Button mButtonRemoveFromFavorites; @Bind({ R.id.rating_first_star, R.id.rating_second_star, R.id.rating_third_star, R.id.rating_fourth_star, R.id.rating_fifth_star }) List<ImageView> ratingStarViews; public MovieDetailFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments().containsKey(ARG_MOVIE)) { mMovie = getArguments().getParcelable(ARG_MOVIE); } setHasOptionsMenu(true); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Activity activity = getActivity(); CollapsingToolbarLayout appBarLayout = (CollapsingToolbarLayout) activity.findViewById(R.id.toolbar_layout); if (appBarLayout != null && activity instanceof MovieDetailActivity) { appBarLayout.setTitle(mMovie.getTitle()); } ImageView movieBackdrop = ((ImageView) activity.findViewById(R.id.movie_backdrop)); if (movieBackdrop != null) { Picasso.with(activity).load(mMovie.getBackdropUrl(getContext())).config(Bitmap.Config.RGB_565) .into(movieBackdrop); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.movie_detail, container, false); ButterKnife.bind(this, rootView); mMovieTitleView.setText(mMovie.getTitle()); mMovieOverviewView.setText(mMovie.getOverview()); mMovieReleaseDateView.setText(mMovie.getReleaseDate(getContext())); Picasso.with(getContext()).load(mMovie.getPosterUrl(getContext())).config(Bitmap.Config.RGB_565) .into(mMoviePosterView); updateRatingBar(); updateFavoriteButtons(); // For horizontal list of trailers LinearLayoutManager layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false); mRecyclerViewForTrailers.setLayoutManager(layoutManager); mTrailerListAdapter = new TrailerListAdapter(new ArrayList<Trailer>(), this); mRecyclerViewForTrailers.setAdapter(mTrailerListAdapter); mRecyclerViewForTrailers.setNestedScrollingEnabled(false); // For vertical list of reviews mReviewListAdapter = new ReviewListAdapter(new ArrayList<Review>(), this); mRecyclerViewForReviews.setAdapter(mReviewListAdapter); // Fetch trailers only if savedInstanceState == null if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_TRAILERS)) { List<Trailer> trailers = savedInstanceState.getParcelableArrayList(EXTRA_TRAILERS); mTrailerListAdapter.add(trailers); mButtonWatchTrailer.setEnabled(true); } else { fetchTrailers(); } // Fetch reviews only if savedInstanceState == null if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_REVIEWS)) { List<Review> reviews = savedInstanceState.getParcelableArrayList(EXTRA_REVIEWS); mReviewListAdapter.add(reviews); } else { fetchReviews(); } return rootView; } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); ArrayList<Trailer> trailers = mTrailerListAdapter.getTrailers(); if (trailers != null && !trailers.isEmpty()) { outState.putParcelableArrayList(EXTRA_TRAILERS, trailers); } ArrayList<Review> reviews = mReviewListAdapter.getReviews(); if (reviews != null && !reviews.isEmpty()) { outState.putParcelableArrayList(EXTRA_REVIEWS, reviews); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.movie_detail_fragment, menu); MenuItem shareTrailerMenuItem = menu.findItem(R.id.share_trailer); mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareTrailerMenuItem); } @Override public void watch(Trailer trailer, int position) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trailer.getTrailerUrl()))); } @Override public void read(Review review, int position) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(review.getUrl()))); } @Override public void onFetchFinished(List<Trailer> trailers) { mTrailerListAdapter.add(trailers); mButtonWatchTrailer.setEnabled(!trailers.isEmpty()); if (mTrailerListAdapter.getItemCount() > 0) { Trailer trailer = mTrailerListAdapter.getTrailers().get(0); updateShareActionProvider(trailer); } } @Override public void onReviewsFetchFinished(List<Review> reviews) { mReviewListAdapter.add(reviews); } private void fetchTrailers() { FetchTrailersTask task = new FetchTrailersTask(this); task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mMovie.getId()); } private void fetchReviews() { FetchReviewsTask task = new FetchReviewsTask(this); task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mMovie.getId()); } public void markAsFavorite() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { if (!isFavorite()) { ContentValues movieValues = new ContentValues(); movieValues.put(MovieContract.MovieEntry.COLUMN_MOVIE_ID, mMovie.getId()); movieValues.put(MovieContract.MovieEntry.COLUMN_MOVIE_TITLE, mMovie.getTitle()); movieValues.put(MovieContract.MovieEntry.COLUMN_MOVIE_POSTER_PATH, mMovie.getPoster()); movieValues.put(MovieContract.MovieEntry.COLUMN_MOVIE_OVERVIEW, mMovie.getOverview()); movieValues.put(MovieContract.MovieEntry.COLUMN_MOVIE_VOTE_AVERAGE, mMovie.getUserRating()); movieValues.put(MovieContract.MovieEntry.COLUMN_MOVIE_RELEASE_DATE, mMovie.getReleaseDate()); movieValues.put(MovieContract.MovieEntry.COLUMN_MOVIE_BACKDROP_PATH, mMovie.getBackdrop()); getContext().getContentResolver().insert(MovieContract.MovieEntry.CONTENT_URI, movieValues); } return null; } @Override protected void onPostExecute(Void aVoid) { updateFavoriteButtons(); } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } public void removeFromFavorites() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { if (isFavorite()) { getContext().getContentResolver().delete(MovieContract.MovieEntry.CONTENT_URI, MovieContract.MovieEntry.COLUMN_MOVIE_ID + " = " + mMovie.getId(), null); } return null; } @Override protected void onPostExecute(Void aVoid) { updateFavoriteButtons(); } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } private void updateRatingBar() { if (mMovie.getUserRating() != null && !mMovie.getUserRating().isEmpty()) { String userRatingStr = getResources().getString(R.string.user_rating_movie, mMovie.getUserRating()); mMovieRatingView.setText(userRatingStr); float userRating = Float.valueOf(mMovie.getUserRating()) / 2; int integerPart = (int) userRating; // Fill stars for (int i = 0; i < integerPart; i++) { ratingStarViews.get(i).setImageResource(R.drawable.ic_star_black_24dp); } // Fill half star if (Math.round(userRating) > integerPart) { ratingStarViews.get(integerPart).setImageResource(R.drawable.ic_star_half_black_24dp); } } else { mMovieRatingView.setVisibility(View.GONE); } } private void updateFavoriteButtons() { // Needed to avoid "skip frames". new AsyncTask<Void, Void, Boolean>() { @Override protected Boolean doInBackground(Void... params) { return isFavorite(); } @Override protected void onPostExecute(Boolean isFavorite) { if (isFavorite) { mButtonRemoveFromFavorites.setVisibility(View.VISIBLE); mButtonMarkAsFavorite.setVisibility(View.GONE); } else { mButtonMarkAsFavorite.setVisibility(View.VISIBLE); mButtonRemoveFromFavorites.setVisibility(View.GONE); } } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); mButtonMarkAsFavorite.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { markAsFavorite(); } }); mButtonWatchTrailer.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mTrailerListAdapter.getItemCount() > 0) { watch(mTrailerListAdapter.getTrailers().get(0), 0); } } }); mButtonRemoveFromFavorites.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { removeFromFavorites(); } }); } private boolean isFavorite() { Cursor movieCursor = getContext().getContentResolver().query(MovieContract.MovieEntry.CONTENT_URI, new String[] { MovieContract.MovieEntry.COLUMN_MOVIE_ID }, MovieContract.MovieEntry.COLUMN_MOVIE_ID + " = " + mMovie.getId(), null, null); if (movieCursor != null && movieCursor.moveToFirst()) { movieCursor.close(); return true; } else { return false; } } private void updateShareActionProvider(Trailer trailer) { Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, mMovie.getTitle()); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, trailer.getName() + ": " + trailer.getTrailerUrl()); mShareActionProvider.setShareIntent(sharingIntent); } }