video trailers
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
package net.headlezz.udacityproject1;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.format.DateUtils;
|
||||
@@ -10,17 +14,26 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.headlezz.udacityproject1.tmdbapi.Movie;
|
||||
import net.headlezz.udacityproject1.tmdbapi.TMDBApi;
|
||||
import net.headlezz.udacityproject1.tmdbapi.Video;
|
||||
import net.headlezz.udacityproject1.tmdbapi.VideoList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.Bind;
|
||||
import butterknife.ButterKnife;
|
||||
import retrofit.Call;
|
||||
import retrofit.Callback;
|
||||
import retrofit.Response;
|
||||
import retrofit.Retrofit;
|
||||
|
||||
/**
|
||||
* Fragment to show the details of a movie
|
||||
*/
|
||||
public class MovieDetailsFragment extends Fragment {
|
||||
public class MovieDetailsFragment extends Fragment implements Callback<VideoList> {
|
||||
|
||||
public static final String TAG = MovieDetailsFragment.class.getSimpleName();
|
||||
public static final String BUNDLE_ARG_MOVIE = "movie";
|
||||
@@ -30,8 +43,16 @@ public class MovieDetailsFragment extends Fragment {
|
||||
@Bind(R.id.movie_details_tvOverview) TextView tvOverview;
|
||||
@Bind(R.id.movie_details_tvReleaseDate) TextView tvReleaseDate;
|
||||
@Bind(R.id.movie_details_tvRating) TextView tvRating;
|
||||
@Bind(R.id.movie_details_trailerHolder) ViewGroup trailerHolder;
|
||||
|
||||
Movie mMovie;
|
||||
VideoList mVideoList;
|
||||
|
||||
/**
|
||||
* Hold a reference to the videolist download call so
|
||||
* it can be canceled when stopping
|
||||
*/
|
||||
Call<VideoList> mVideoListCall;
|
||||
|
||||
public static MovieDetailsFragment newInstance(Movie movie) {
|
||||
MovieDetailsFragment frag = new MovieDetailsFragment();
|
||||
@@ -49,6 +70,9 @@ public class MovieDetailsFragment extends Fragment {
|
||||
Log.d(TAG, "Bundled movie: " + mMovie.getTitle());
|
||||
} else
|
||||
throw new RuntimeException(TAG + " opened without bundled movie!");
|
||||
|
||||
if(savedInstanceState != null && savedInstanceState.containsKey("videolist"))
|
||||
mVideoList = savedInstanceState.getParcelable("videolist");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -68,5 +92,82 @@ public class MovieDetailsFragment extends Fragment {
|
||||
String formatedDate = DateUtils.formatDateTime(tvReleaseDate.getContext(), mMovie.getReleaseDate().getTime(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_YEAR);
|
||||
tvReleaseDate.setText(getString(R.string.movie_release_date, formatedDate));
|
||||
tvRating.setText(getString(R.string.movie_rating, mMovie.getAvRating()));
|
||||
|
||||
if(mVideoList == null)
|
||||
loadVideoList();
|
||||
else
|
||||
showVideoList(mVideoList);
|
||||
}
|
||||
|
||||
private void loadVideoList() {
|
||||
if(mVideoListCall != null)
|
||||
mVideoListCall.cancel();
|
||||
mVideoListCall = TMDBApi.getVideosForMovie(mMovie, getString(R.string.api_key));
|
||||
mVideoListCall.enqueue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response<VideoList> response, Retrofit retrofit) {
|
||||
if(response.isSuccess()) {
|
||||
mVideoList = response.body();
|
||||
if(getActivity() != null)
|
||||
showVideoList(mVideoList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
if(getActivity() != null)
|
||||
Toast.makeText(getActivity(), "Failed to load videos: " + t.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
// TODO high res image for video link
|
||||
|
||||
/**
|
||||
* shows a list of links to youtube videos for the selected movie
|
||||
* if the videolist has no videos, the user sees a message that there are no.
|
||||
* @param videoList VideoList to show
|
||||
*/
|
||||
private void showVideoList(@NonNull VideoList videoList) {
|
||||
List<Video> videos = videoList.getVideos();
|
||||
if(videos.size() > 0) {
|
||||
for (Video video : videoList.getVideos()) {
|
||||
View view = LayoutInflater.from(getActivity()).inflate(R.layout.movie_details_trailer_item, trailerHolder, false);
|
||||
TextView tv = (TextView) view.findViewById(R.id.trailer_item_tvName);
|
||||
tv.setText(video.getName());
|
||||
view.setTag(video);
|
||||
view.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
String videoId = ((Video) view.getTag()).getKey();
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:" + videoId));
|
||||
intent.putExtra("VIDEO_ID", videoId);
|
||||
try {
|
||||
startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getActivity(), "Youtube app not found.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
trailerHolder.addView(view);
|
||||
}
|
||||
} else {
|
||||
trailerHolder.getChildAt(0).setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
if(mVideoList != null)
|
||||
outState.putParcelable("videolist", mVideoList);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if(mVideoListCall != null)
|
||||
mVideoListCall.cancel();
|
||||
super.onStop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ public class Movie implements Parcelable {
|
||||
// empty constructor for gson/retrofit
|
||||
public Movie() {}
|
||||
|
||||
long id;
|
||||
|
||||
String title;
|
||||
|
||||
@SerializedName("poster_path")
|
||||
@@ -49,6 +51,10 @@ public class Movie implements Parcelable {
|
||||
return releaseDate;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**** Parcelable stuff *****/
|
||||
|
||||
@Override
|
||||
@@ -63,6 +69,7 @@ public class Movie implements Parcelable {
|
||||
dest.writeString(overview);
|
||||
dest.writeDouble(avRating);
|
||||
dest.writeLong(releaseDate.getTime());
|
||||
dest.writeLong(id);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Movie> CREATOR = new Parcelable.Creator<Movie>() {
|
||||
@@ -81,6 +88,7 @@ public class Movie implements Parcelable {
|
||||
overview = src.readString();
|
||||
avRating = src.readDouble();
|
||||
releaseDate = new Date(src.readLong());
|
||||
id = src.readLong();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import retrofit.GsonConverterFactory;
|
||||
import retrofit.Retrofit;
|
||||
import retrofit.http.GET;
|
||||
import retrofit.http.Headers;
|
||||
import retrofit.http.Path;
|
||||
import retrofit.http.Query;
|
||||
|
||||
/**
|
||||
@@ -37,6 +38,7 @@ public class TMDBApi {
|
||||
private static TMDBApiService buildApiService() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(MovieList.class, new MovieListDeserializer())
|
||||
.registerTypeAdapter(VideoList.class, new VideoListDeserializer())
|
||||
.create();
|
||||
Retrofit retrofit = new Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
@@ -61,6 +63,10 @@ public class TMDBApi {
|
||||
return apiService.discoverMovies(sort, apiKey);
|
||||
}
|
||||
|
||||
public static Call<VideoList> getVideosForMovie(Movie movie, String apiKey) {
|
||||
return apiService.getVideosForMovie(movie.getId(), apiKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Api interface for retrofit
|
||||
*/
|
||||
@@ -68,6 +74,10 @@ public class TMDBApi {
|
||||
@Headers("Accept: application/json")
|
||||
@GET("discover/movie")
|
||||
Call<MovieList> discoverMovies(@Query("sort_by") String sortOrder, @Query("api_key") String apiKey);
|
||||
|
||||
@Headers("Accept: application/json")
|
||||
@GET("movie/{id}/videos")
|
||||
Call<VideoList> getVideosForMovie(@Path("id") long id, @Query("api_key") String apiKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package net.headlezz.udacityproject1.tmdbapi;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public class Video implements Parcelable {
|
||||
|
||||
private String name;
|
||||
private String key;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int i) {
|
||||
parcel.writeString(name);
|
||||
parcel.writeString(key);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Video> CREATOR = new Parcelable.Creator<Video>() {
|
||||
public Video createFromParcel(Parcel src) {
|
||||
return new Video(src);
|
||||
}
|
||||
|
||||
public Video[] newArray(int size) {
|
||||
return new Video[size];
|
||||
}
|
||||
};
|
||||
|
||||
private Video(Parcel src) {
|
||||
name = src.readString();
|
||||
key = src.readString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package net.headlezz.udacityproject1.tmdbapi;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A list of trailers for a movie
|
||||
*/
|
||||
public class VideoList implements Parcelable {
|
||||
|
||||
private long id;
|
||||
private List<Video> videos;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<Video> getVideos() {
|
||||
return videos;
|
||||
}
|
||||
|
||||
public VideoList(long id, List<Video> videos) {
|
||||
this.id = id;
|
||||
this.videos = videos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int i) {
|
||||
parcel.writeLong(id);
|
||||
parcel.writeList(videos);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<VideoList> CREATOR = new Parcelable.Creator<VideoList>() {
|
||||
public VideoList createFromParcel(Parcel src) {
|
||||
return new VideoList(src);
|
||||
}
|
||||
|
||||
public VideoList[] newArray(int size) {
|
||||
return new VideoList[size];
|
||||
}
|
||||
};
|
||||
|
||||
private VideoList(Parcel src) {
|
||||
id = src.readLong();
|
||||
videos = src.readArrayList(Video.class.getClassLoader());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.headlezz.udacityproject1.tmdbapi;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class VideoListDeserializer implements JsonDeserializer<VideoList> {
|
||||
@Override
|
||||
public VideoList deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
Gson gson = new Gson();
|
||||
List<Video> videos = new ArrayList<>();
|
||||
for(JsonElement elem : json.getAsJsonObject().getAsJsonArray("results")) {
|
||||
if(elem.getAsJsonObject().get("site").getAsString().equals("YouTube")) // filter non youtube videos out
|
||||
videos.add(gson.fromJson(elem, Video.class));
|
||||
}
|
||||
long id = json.getAsJsonObject().get("id").getAsLong();
|
||||
return new VideoList(id, videos);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user