movie details screen
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
package net.headlezz.udacityproject1;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
import net.headlezz.udacityproject1.tmdbapi.Movie;
|
||||
|
||||
/**
|
||||
* Main activity is mainly for handling fragment transactions
|
||||
*/
|
||||
public class MainActivity extends AppCompatActivity implements MovieNavigation, FragmentManager.OnBackStackChangedListener {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -15,11 +21,41 @@ public class MainActivity extends AppCompatActivity {
|
||||
setTitle(getString(R.string.app_name));
|
||||
|
||||
if(savedInstanceState == null) {
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.fragmentHolder, new MovieListFragment())
|
||||
.commit();
|
||||
}
|
||||
|
||||
// activity needs to listen to fragment changes to adjust the home as up arrow
|
||||
getSupportFragmentManager().addOnBackStackChangedListener(this);
|
||||
shouldDisplayHomeUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the list with a details view showing the selected movie
|
||||
* @param movie Movie to show
|
||||
*/
|
||||
public void showDetailsFragment(Movie movie) {
|
||||
MovieDetailsFragment frag = MovieDetailsFragment.newInstance(movie);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.fragmentHolder, frag)
|
||||
.addToBackStack(MovieDetailsFragment.TAG)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public void shouldDisplayHomeUp(){
|
||||
boolean hasBackstack = getSupportFragmentManager().getBackStackEntryCount()>0;
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(hasBackstack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
getSupportFragmentManager().popBackStack();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackStackChanged() {
|
||||
shouldDisplayHomeUp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package net.headlezz.udacityproject1;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.headlezz.udacityproject1.tmdbapi.Movie;
|
||||
import net.headlezz.udacityproject1.tmdbapi.TMDBApi;
|
||||
|
||||
/**
|
||||
* Fragment to show the details of a movie
|
||||
*/
|
||||
public class MovieDetailsFragment extends Fragment {
|
||||
|
||||
// TODO make me pretty
|
||||
|
||||
public static final String TAG = MovieDetailsFragment.class.getSimpleName();
|
||||
public static final String BUNDLE_ARG_MOVIE = "movie";
|
||||
|
||||
ImageView ivPoster;
|
||||
TextView tvTitle;
|
||||
TextView tvOverview;
|
||||
TextView tvReleaseDate;
|
||||
TextView tvRating;
|
||||
|
||||
Movie mMovie;
|
||||
|
||||
public static MovieDetailsFragment newInstance(Movie movie) {
|
||||
MovieDetailsFragment frag = new MovieDetailsFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(BUNDLE_ARG_MOVIE, movie);
|
||||
frag.setArguments(args);
|
||||
return frag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if(getArguments().containsKey(BUNDLE_ARG_MOVIE)) {
|
||||
mMovie = getArguments().getParcelable(BUNDLE_ARG_MOVIE);
|
||||
Log.d(TAG, "Bundled movie: " + mMovie.getTitle());
|
||||
} else
|
||||
throw new RuntimeException(TAG + " opened without bundled movie!");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_movie_details, container, false);
|
||||
ivPoster = (ImageView) view.findViewById(R.id.movie_details_ivPoster);
|
||||
tvTitle = (TextView) view.findViewById(R.id.movie_details_tvTitle);
|
||||
tvOverview = (TextView) view.findViewById(R.id.movie_details_tvOverview);
|
||||
tvReleaseDate = (TextView) view.findViewById(R.id.movie_details_tvReleaseDate);
|
||||
tvRating = (TextView) view.findViewById(R.id.movie_details_tvRating);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
TMDBApi.loadPoster(ivPoster, mMovie);
|
||||
tvTitle.setText(mMovie.getTitle());
|
||||
tvOverview.setText(mMovie.getOverview());
|
||||
String formatedDate = DateUtils.formatDateTime(tvReleaseDate.getContext(), mMovie.getReleaseDate(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_YEAR);
|
||||
tvReleaseDate.setText(formatedDate);
|
||||
tvRating.setText(String.valueOf(mMovie.getAvRating()));
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
package net.headlezz.udacityproject1;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.headlezz.udacityproject1.tmdbapi.Movie;
|
||||
import net.headlezz.udacityproject1.tmdbapi.TMDBApi;
|
||||
@@ -15,11 +13,11 @@ import java.util.List;
|
||||
|
||||
public class MovieListAdapter extends RecyclerView.Adapter<MovieListAdapter.MovieViewHolder>{
|
||||
|
||||
Context context;
|
||||
MovieNavigation mMovieNavigation;
|
||||
List<Movie> mMovies;
|
||||
|
||||
public MovieListAdapter(Context context, List<Movie> movies) {
|
||||
this.context = context;
|
||||
public MovieListAdapter(MovieNavigation mn, List<Movie> movies) {
|
||||
mMovieNavigation = mn;
|
||||
mMovies = movies;
|
||||
}
|
||||
|
||||
@@ -53,7 +51,7 @@ public class MovieListAdapter extends RecyclerView.Adapter<MovieListAdapter.Movi
|
||||
ivPoster.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Toast.makeText(v.getContext(), movie.getTitle() + " clicked.", Toast.LENGTH_SHORT).show();
|
||||
mMovieNavigation.showDetailsFragment(movie);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.headlezz.udacityproject1;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
@@ -28,13 +29,14 @@ import retrofit.Call;
|
||||
public class MovieListFragment extends Fragment {
|
||||
|
||||
// TODO fix restore
|
||||
// TODO show progressbar while loading
|
||||
|
||||
public static final String TAG = MovieListFragment.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* The number of columns our movie grid shows
|
||||
*/
|
||||
private static final int NUM_COLUMNS = 2;
|
||||
private static final int NUM_COLUMNS = 3; // TODO adjust colum count for landscape
|
||||
|
||||
/**
|
||||
* The currently selected sorting order of the list
|
||||
@@ -120,7 +122,7 @@ public class MovieListFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void setListToGrid(List<Movie> movies) {
|
||||
mMovieGridView.setAdapter(new MovieListAdapter(getActivity(), movies));
|
||||
mMovieGridView.setAdapter(new MovieListAdapter((MovieNavigation) getActivity(), movies));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,4 +140,11 @@ public class MovieListFragment extends Fragment {
|
||||
super.onStop();
|
||||
stopLoadingMovies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if(!(context instanceof MovieNavigation))
|
||||
throw new RuntimeException("Activity must implement " + MovieNavigation.class.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.headlezz.udacityproject1;
|
||||
|
||||
import net.headlezz.udacityproject1.tmdbapi.Movie;
|
||||
|
||||
public interface MovieNavigation {
|
||||
|
||||
void showDetailsFragment(Movie movie);
|
||||
|
||||
}
|
||||
@@ -1,15 +1,22 @@
|
||||
package net.headlezz.udacityproject1.tmdbapi;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Data object to represent a single movie
|
||||
* Only required data from the api is stored to save memory
|
||||
*/
|
||||
public class Movie {
|
||||
public class Movie implements Parcelable {
|
||||
|
||||
// empty constructor for gson/retrofit
|
||||
public Movie() {}
|
||||
|
||||
String title;
|
||||
String posterPath;
|
||||
String overview;
|
||||
double avRating;
|
||||
long releaseDate;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
@@ -26,4 +33,44 @@ public class Movie {
|
||||
public double getAvRating() {
|
||||
return avRating;
|
||||
}
|
||||
|
||||
public long getReleaseDate() {
|
||||
return releaseDate;
|
||||
}
|
||||
|
||||
/**** Parcelable stuff *****/
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(title);
|
||||
dest.writeString(posterPath);
|
||||
dest.writeString(overview);
|
||||
dest.writeDouble(avRating);
|
||||
dest.writeLong(releaseDate);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Movie> CREATOR = new Parcelable.Creator<Movie>() {
|
||||
public Movie createFromParcel(Parcel src) {
|
||||
return new Movie(src);
|
||||
}
|
||||
|
||||
public Movie[] newArray(int size) {
|
||||
return new Movie[size];
|
||||
}
|
||||
};
|
||||
|
||||
private Movie(Parcel src) {
|
||||
title = src.readString();
|
||||
posterPath = src.readString();
|
||||
overview = src.readString();
|
||||
avRating = src.readDouble();
|
||||
releaseDate = src.readLong();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -17,6 +18,7 @@ public class MovieListDeserializer implements JsonDeserializer<MovieList> {
|
||||
@Override
|
||||
public MovieList deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
List<Movie> movieList = new ArrayList<>();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD");
|
||||
for(JsonElement elem : json.getAsJsonObject().getAsJsonArray("results")) {
|
||||
try { // TODO fix this and remove try/catch
|
||||
JsonObject jsonObj = elem.getAsJsonObject();
|
||||
@@ -24,8 +26,8 @@ public class MovieListDeserializer implements JsonDeserializer<MovieList> {
|
||||
m.title = jsonObj.get("title").getAsString();
|
||||
m.overview = jsonObj.get("overview").getAsString();
|
||||
m.avRating = jsonObj.get("vote_average").getAsDouble();
|
||||
JsonElement posterPath = jsonObj.get("poster_path");
|
||||
m.posterPath = posterPath.getAsString();
|
||||
m.posterPath = jsonObj.get("poster_path").getAsString();
|
||||
m.releaseDate = sdf.parse(jsonObj.get("release_date").getAsString()).getTime();
|
||||
movieList.add(m);
|
||||
} catch (Exception e) {
|
||||
Log.e(MovieListDeserializer.class.getSimpleName(), e.toString());
|
||||
|
||||
@@ -20,7 +20,7 @@ import retrofit.http.Query;
|
||||
public class TMDBApi {
|
||||
|
||||
private static final String BASE_URL = "http://api.themoviedb.org/3/";
|
||||
private static final String IMAGE_BASE_URL = "http://image.tmdb.org/t/p/w342"; // TODO select size depending on device screen ratios
|
||||
private static final String IMAGE_BASE_URL = "http://image.tmdb.org/t/p/w185"; // TODO select size depending on device screen ratios
|
||||
|
||||
/**
|
||||
* These are the possible sorting orders
|
||||
|
||||
Reference in New Issue
Block a user