video trailers

This commit is contained in:
danijoo
2015-10-30 14:55:28 +01:00
parent c7e2afb783
commit 1f1d3ee57b
10 changed files with 298 additions and 2 deletions

View File

@@ -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();
}
}

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}