diff --git a/app/build.gradle b/app/build.gradle index a3525fe..0bf42a8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 22 + compileSdkVersion 23 buildToolsVersion "22.0.1" defaultConfig { applicationId "za.co.ubiquitech.vmovies" - minSdkVersion 17 - targetSdkVersion 22 + minSdkVersion 19 + targetSdkVersion 23 versionCode 1 versionName "1.0" } @@ -24,8 +24,14 @@ repositories { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:22.2.1' + + compile 'com.android.support:appcompat-v7:23.0.1' + compile 'com.inthecheesefactory.thecheeselibrary:stated-fragment-support-v4:0.9.3' compile 'com.squareup.picasso:picasso:2.5.2' compile 'com.squareup.retrofit:retrofit:2.0.0-beta1' - + compile 'com.android.support:design:23.0.1' + compile 'com.android.support:appcompat-v7:23.0.1' + compile 'com.android.support:support-v4:23.0.1' + compile 'com.android.support:cardview-v7:23.0.1' + compile 'com.facebook.stetho:stetho:1.2.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 52dcb84..1d695a5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,32 +1,43 @@ + package="za.co.ubiquitech.vmovies" > + + + android:theme="@style/AppTheme" > + android:label="@string/app_name" + android:launchMode="singleTop" + android:noHistory="false"> + android:name=".DetailActivity" + android:parentActivityName=".MainActivity" + android:label="Review" + android:launchMode="singleTop" + android:noHistory="false"> - - + + diff --git a/app/src/main/ic_calendar-web.png b/app/src/main/ic_calendar-web.png new file mode 100644 index 0000000..43382a7 Binary files /dev/null and b/app/src/main/ic_calendar-web.png differ diff --git a/app/src/main/ic_calender-web.png b/app/src/main/ic_calender-web.png new file mode 100644 index 0000000..683bd88 Binary files /dev/null and b/app/src/main/ic_calender-web.png differ diff --git a/app/src/main/ic_star-web.png b/app/src/main/ic_star-web.png new file mode 100644 index 0000000..f84652f Binary files /dev/null and b/app/src/main/ic_star-web.png differ diff --git a/app/src/main/ic_white_star-web.png b/app/src/main/ic_white_star-web.png new file mode 100644 index 0000000..a3f4e13 Binary files /dev/null and b/app/src/main/ic_white_star-web.png differ diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/DetailActivity.java b/app/src/main/java/za/co/ubiquitech/vmovies/DetailActivity.java new file mode 100644 index 0000000..dc50c9f --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/DetailActivity.java @@ -0,0 +1,21 @@ +package za.co.ubiquitech.vmovies; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +public class DetailActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_movie_detail); + if (savedInstanceState == null) { + Bundle arguments = new Bundle(); + arguments.putParcelable(DetailFragment.DETAIL_MOVIE, getIntent().getParcelableExtra(DetailFragment.DETAIL_MOVIE)); + DetailFragment fragment = new DetailFragment(); + fragment.setArguments(arguments); + getSupportFragmentManager().beginTransaction() + .add(R.id.movie_detail_container, fragment) + .commit(); + } + } +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/DetailFragment.java b/app/src/main/java/za/co/ubiquitech/vmovies/DetailFragment.java new file mode 100644 index 0000000..6dc7204 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/DetailFragment.java @@ -0,0 +1,562 @@ +package za.co.ubiquitech.vmovies; + +import android.app.ProgressDialog; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Environment; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.Snackbar; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v4.view.MenuItemCompat; +import android.support.v7.widget.ShareActionProvider; +import android.util.Log; +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.AdapterView; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.squareup.picasso.Picasso; +import com.squareup.picasso.Target; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Vector; + +import za.co.ubiquitech.vmovies.database.MoviesContract; +import za.co.ubiquitech.vmovies.formObjects.MovieDetailsForm; +import za.co.ubiquitech.vmovies.formObjects.MovieReviews; +import za.co.ubiquitech.vmovies.formObjects.Review; +import za.co.ubiquitech.vmovies.util.CustomListView; +import za.co.ubiquitech.vmovies.util.CustomTrailerViewAdapter; +import za.co.ubiquitech.vmovies.util.JsonRequests; + +/** + * A placeholder fragment containing a simple view. + */ +public class DetailFragment extends Fragment implements LoaderManager.LoaderCallbacks { + private final String LOG_TAG = DetailFragment.class.getSimpleName(); + private CustomTrailerViewAdapter mTrailerAdapter; + private MovieDetailsForm selectedMovie; + private MovieReviews currentMovieReview; + private CustomListView customTrailerListView; + private int mPosition; + private Uri mUri; + private static final int CURSOR_LOADER = 1; + static final String DETAIL_MOVIE = "SELECTED_MOVIE"; + + private ShareActionProvider mShareActionProvider; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.menu_movie_detail, menu); + + MenuItem item = menu.findItem(R.id.share_trailer); + mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item); + ; + + /** Setting a share intent */ + mShareActionProvider.setShareIntent(getDefaultShareIntent()); + super.onCreateOptionsMenu(menu, inflater); + } + + /** + * Returns a share intent + */ + private Intent getDefaultShareIntent() { + String trailerMessage; + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + trailerMessage = "Vmovies: No movie Trailer"; + sendIntent.putExtra(Intent.EXTRA_TEXT, trailerMessage); + sendIntent.setType("text/plain"); + return sendIntent; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + //getLoaderManager().initLoader(CURSOR_LOADER, null, DetailFragment.this); + super.onActivityCreated(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View rootView = inflater.inflate(R.layout.fragment_movie_detail, container, false); + CoordinatorLayout detailLayout = (CoordinatorLayout) rootView.findViewById(R.id.detail_layout); + + Bundle arguments = getArguments(); + if (arguments != null) { + selectedMovie = arguments.getParcelable(DetailFragment.DETAIL_MOVIE); + customTrailerListView = (CustomListView) rootView.findViewById(R.id.trailer_list_view); + ((TextView) rootView.findViewById(R.id.detail_movie_name)).setText(selectedMovie.getMovieName()); + ((TextView) rootView.findViewById(R.id.detail_movie_plot)).setText(selectedMovie.getMoviePlot()); + ((TextView) rootView.findViewById(R.id.release_date_view)).setText(selectedMovie.getMovieReleaseDate()); + ((TextView) rootView.findViewById(R.id.rating_view)).setText(selectedMovie.getMovieRating() + "/10"); + + ImageView moviePoster = (ImageView) rootView.findViewById(R.id.detail_poster_image); + Picasso.with(getActivity()) + .load(selectedMovie.getMovieBackdrop()) + .into(moviePoster); + + this.mPosition = Integer.parseInt(selectedMovie.getMovieId()); + this.mUri = ContentUris.withAppendedId(MoviesContract.ReviewEntry.CONTENT_URI, + mPosition); + + if (savedInstanceState != null) { + currentMovieReview = savedInstanceState.getParcelable("reviews"); + mTrailerAdapter = new CustomTrailerViewAdapter(getActivity(), currentMovieReview.getMovieYouTubeURL()); + customTrailerListView.setAdapter(mTrailerAdapter); + customTrailerListView.setExpanded(true); + } else { + getLoaderManager().restartLoader(CURSOR_LOADER, null, DetailFragment.this); + } + + Button btn_review = (Button) rootView.findViewById(R.id.btn_reviews); + btn_review.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + if (currentMovieReview.getReviews() != null && currentMovieReview.getReviews().size() > 0) { + Bundle args = new Bundle(); + args.putParcelable("review", currentMovieReview); + ReviewFragment movieReviewsFragment = new ReviewFragment(); + movieReviewsFragment.setArguments(args); + android.support.v4.app.FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.movie_detail_container, movieReviewsFragment); + transaction.addToBackStack(null); + transaction.commit(); + } else { + showError("No reviews found for this movie"); + } + } + }); + + customTrailerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + //http://intransitione.com/blog/play-a-video-on-youtube-using-an-intent/ + String movieKey = mTrailerAdapter.getItem(position); + Uri uri = Uri.parse(movieKey); + Intent youTubeIntent = new Intent(Intent.ACTION_VIEW, uri); + startActivity(youTubeIntent); + } + }); + } + + if (selectedMovie == null) { + detailLayout.setVisibility(View.GONE); + } else { + detailLayout.setVisibility(View.VISIBLE); + } + + FloatingActionButton favButton = (FloatingActionButton) rootView.findViewById(R.id.btn_fav_submit); + favButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + safeImages(); + } + }); + + return rootView; + } + + private void showError(String message) { + //Display error + final Snackbar snackBar = Snackbar.make(getView(), message, Snackbar.LENGTH_LONG); + snackBar.setAction("Dismiss", new View.OnClickListener() { + @Override + public void onClick(View v) { + snackBar.dismiss(); + } + }); + snackBar.show(); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new CursorLoader(getActivity(), + mUri, + null, + null, + null, + null); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + } + + // Set the cursor in our CursorAdapter once the Cursor is loaded + @Override + public void onLoadFinished(Loader loader, Cursor data) { + + int count = 0; + int authorIndex = data.getColumnIndex(MoviesContract.ReviewEntry.COLUMN_AUTHOR); + int contentIndex = data.getColumnIndex(MoviesContract.ReviewEntry.COLUMN_CONTENT); + int movieId = data.getColumnIndex(MoviesContract.ReviewEntry.COLUMN_MOVIE_ID); + + Review[] reviews = new Review[data.getCount()]; + if (data.getCount() > 0) {//check if cursor not empty + data.moveToFirst(); + do { + reviews[count] = new Review(data.getString(authorIndex), + data.getString(contentIndex), + data.getString(movieId)); + count++; + data.moveToNext(); + } while (!data.isAfterLast()); + } + + currentMovieReview = new MovieReviews(); + if (data.getCount() > 0) { + currentMovieReview.setReviews(Arrays.asList(reviews)); + } else { + updateReviews(); + } + } + + // reset CursorAdapter on Loader Reset + @Override + public void onLoaderReset(Loader loader) { + } + + private void safeImages() { + Picasso.with(getActivity()).load(selectedMovie.getMoviePoster()).into(target); + Picasso.with(getActivity()).load(selectedMovie.getMovieBackdrop()).into(target2); + + ///Movie poster file name + String filename = "poster_" + selectedMovie.getMovieId() + ".jpg"; + File fileDir = new File(getAppStorageDir()); + String mFilePath = fileDir.toString(); + File file = new File(mFilePath, filename); + selectedMovie.setMoviePoster("file://" + file.toString()); + + ///Movie backdrop file name + filename = "backdrop_" + selectedMovie.getMovieId() + ".jpg"; + fileDir = new File(getAppStorageDir()); + mFilePath = fileDir.toString(); + file = new File(mFilePath, filename); + selectedMovie.setMovieBackdrop("file://" + file.toString()); + insertData(selectedMovie); + } + + private Target target = new Target() { + @Override + public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) { + new Thread(new Runnable() { + @Override + public void run() { + File file = null; + try { + String filename = "poster_" + selectedMovie.getMovieId() + ".jpg"; + + File fileDir = new File(getAppStorageDir()); + String mFilePath = fileDir.toString(); + + File dir = new File(mFilePath); + if (!dir.mkdirs()) { + Log.e(LOG_TAG, "Directory not created"); + } + file = new File(mFilePath, filename); + if (file.exists()) + file.delete(); + file.createNewFile(); + + FileOutputStream ostream = new FileOutputStream(file); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream); + ostream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + } + + @Override + public void onBitmapFailed(Drawable errorDrawable) { + } + + @Override + public void onPrepareLoad(Drawable placeHolderDrawable) { + if (placeHolderDrawable != null) { + } + } + }; + private Target target2 = new Target() { + @Override + public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) { + new Thread(new Runnable() { + @Override + public void run() { + File file = null; + + try { + String filename = "backdrop_" + selectedMovie.getMovieId() + ".jpg"; + + File fileDir = new File(getAppStorageDir()); + String mFilePath = fileDir.toString(); + + File dir = new File(mFilePath); + if (!dir.mkdirs()) { + Log.e(LOG_TAG, "Directory not created"); + } + + file = new File(mFilePath, filename); + if (file.exists()) + file.delete(); + file.createNewFile(); + + FileOutputStream ostream = new FileOutputStream(file); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream); + ostream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + } + + @Override + public void onBitmapFailed(Drawable errorDrawable) { + } + + @Override + public void onPrepareLoad(Drawable placeHolderDrawable) { + if (placeHolderDrawable != null) { + } + } + }; + + public String getAppStorageDir() { + // Get the directory for the user's public pictures directory. + String appName = getActivity().getResources().getString(R.string.app_name); + File file = new File(Environment.getExternalStoragePublicDirectory(appName), "Images"); + if (!file.mkdirs()) { + Log.e(LOG_TAG, "Directory not created"); + } + return file.toString(); + } + + // insert data into database + public void insertData(MovieDetailsForm movie) { + + ContentValues movieValuesArr = new ContentValues(); + movieValuesArr.put(MoviesContract.MovieEntry.COLUMN_ID, movie.getMovieId()); + movieValuesArr.put(MoviesContract.MovieEntry.COLUMN_NAME, movie.getMovieName()); + movieValuesArr.put(MoviesContract.MovieEntry.COLUMN_POSTER, movie.getMoviePoster()); + movieValuesArr.put(MoviesContract.MovieEntry.COLUMN_PLOT, movie.getMoviePlot()); + movieValuesArr.put(MoviesContract.MovieEntry.COLUMN_BACKDROP, movie.getMovieBackdrop()); + movieValuesArr.put(MoviesContract.MovieEntry.COLUMN_RELEASEDATE, movie.getMovieReleaseDate()); + movieValuesArr.put(MoviesContract.MovieEntry.COLUMN_RATING, movie.getMovieRating()); + + // bulkInsert ContentValues array + Uri uri = getActivity().getContentResolver().insert(MoviesContract.MovieEntry.CONTENT_URI, + movieValuesArr); + if (uri == null) { + showError(selectedMovie.getMovieName() + " is already in your favourite list"); + + } else { + writeReviewsToDatabase(currentMovieReview.getReviews()); + showError(selectedMovie.getMovieName() + " has been added to your favourite list"); + } + } + + private void writeReviewsToDatabase(List reviews) { + Vector cVVector = new Vector(reviews.size()); + + for (int i = 0; i < reviews.size(); i++) { + ContentValues reviewArr = new ContentValues(); + + Review movieReviews = reviews.get(i); + + reviewArr.put(MoviesContract.ReviewEntry.COLUMN_MOVIE_ID, movieReviews.getMovieId()); + reviewArr.put(MoviesContract.ReviewEntry.COLUMN_AUTHOR, movieReviews.getAuthor()); + reviewArr.put(MoviesContract.ReviewEntry.COLUMN_CONTENT, movieReviews.getContent()); + + cVVector.add(reviewArr); + } + // bulkInsert reviews + if (cVVector.size() > 0) { + ContentValues[] cvArray = new ContentValues[cVVector.size()]; + cVVector.toArray(cvArray); + getActivity().getContentResolver().bulkInsert(MoviesContract.ReviewEntry.CONTENT_URI, + cvArray); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable("reviews", currentMovieReview); + } + + private void updateReviews() { + FetchReviewTask fetchReviewTask = new FetchReviewTask(); + fetchReviewTask.execute(); + } + + public class FetchReviewTask extends AsyncTask { + private ProgressDialog progressDialog; + + @Override + protected MovieReviews doInBackground(Void... params) { + HttpURLConnection urlConnection = null; + BufferedReader reader = null; + String moviesJsonStr = null; + try { + final String MOVIES_BASE_URL = "https://api.themoviedb.org/3/movie/"; + final String apiKey = "/reviews?api_key=" + MainActivity.MOVIE_API_KEY; + + URL url = new URL(MOVIES_BASE_URL + selectedMovie.getMovieId() + apiKey); + urlConnection = (HttpURLConnection) url.openConnection(); + + urlConnection.setRequestMethod("GET"); + urlConnection.setConnectTimeout(10 * 1000); + urlConnection.connect(); + + InputStream inputStream = urlConnection.getInputStream(); + + StringBuffer buffer = new StringBuffer(); + + if (inputStream == null) { + Log.v(LOG_TAG, "Inputstream is null "); + return null; + } + + reader = new BufferedReader(new InputStreamReader(inputStream)); + + String line; + while ((line = reader.readLine()) != null) { + // Since it's JSON, adding a newline isn't necessary (it won't affect parsing) + // But it does make debugging a *lot* easier if you print out the completed + // buffer for debugging. + buffer.append(line + "\n"); + } + //Stream was emplty. No need to parse + if (buffer.length() == 0) { + Log.v(LOG_TAG, "Buffer is null "); + return null; + } + moviesJsonStr = buffer.toString(); + + } catch (IOException e) { + Log.d(LOG_TAG, "Error ", e); + return null; + } finally { + if (urlConnection != null) { + urlConnection.disconnect(); + } + if (reader != null) { + try { + reader.close(); + } catch (final IOException e) { + Log.e(LOG_TAG, "Error closing stream", e); + } + } + } + + try { + return getReviewDataFromJSON(moviesJsonStr); + } catch (JSONException e) { + Log.d(LOG_TAG, e.getMessage(), e); + e.printStackTrace(); + } + return null; + } + + private MovieReviews getReviewDataFromJSON(String movieStr) throws JSONException { + String author; + String content; + List movieYouTubeUrl; + + JSONObject jsonObj = new JSONObject(movieStr); + + //get JSON ARRAY node + JSONArray movieResults = jsonObj.getJSONArray("results"); + List reviewList = new ArrayList<>(); + //loop through all movie results + for (int i = 0; i < movieResults.length(); i++) { + JSONObject object = movieResults.getJSONObject(i); + author = object.getString("author"); + content = object.getString("content"); + reviewList.add(new Review(author, content, selectedMovie.getMovieId())); + } + movieYouTubeUrl = new JsonRequests().FetchMovieVideoKey(selectedMovie.getMovieId()); + return new MovieReviews(movieYouTubeUrl, reviewList); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + progressDialog = new ProgressDialog(getActivity()); + progressDialog.setIndeterminate(true); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setMessage("Loading Reviews..."); + progressDialog.show(); + } + + @Override + protected void onPostExecute(MovieReviews result) { + progressDialog.dismiss(); + if (result != null) { + currentMovieReview = result; + String trailerMessage; + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.setType("text/plain"); + if (!currentMovieReview.getMovieYouTubeURL().isEmpty()) { + trailerMessage = "Vmovies: " + selectedMovie.getMovieName() + " " + currentMovieReview.getMovieYouTubeURL().get(0); + + } else { + trailerMessage = "Vmovies: " + selectedMovie.getMovieName() + " NO youTube trailer available"; + } + sendIntent.putExtra(Intent.EXTRA_TEXT, trailerMessage); + mShareActionProvider.setShareIntent(sendIntent); + + mTrailerAdapter = new CustomTrailerViewAdapter(getActivity(), result.getMovieYouTubeURL()); + customTrailerListView.setAdapter(mTrailerAdapter); + customTrailerListView.setExpanded(true); + } + } + + } + +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/MainActivity.java b/app/src/main/java/za/co/ubiquitech/vmovies/MainActivity.java index ec8fa51..916156c 100644 --- a/app/src/main/java/za/co/ubiquitech/vmovies/MainActivity.java +++ b/app/src/main/java/za/co/ubiquitech/vmovies/MainActivity.java @@ -2,19 +2,35 @@ import android.content.Intent; import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; -import za.co.ubiquitech.vmovies.util.MoviePreferenceActivity; +import com.facebook.stetho.Stetho; -public class MainActivity extends AppCompatActivity { +import za.co.ubiquitech.vmovies.formObjects.MovieDetailsForm; + +public class MainActivity extends AppCompatActivity implements MovieFragment.Callback { public static final String MOVIE_API_KEY = "b3d57ac00feabdc38238f51d1255f024"; + private boolean mTwoPane = false; + private static final String DETAILFRAGMENT_TAG = "DFTAG"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + //http://facebook.github.io/stetho/ + Stetho.initializeWithDefaults(this); setContentView(R.layout.activity_main); + if (findViewById(R.id.movie_detail_container) != null) { + mTwoPane = true; + DetailFragment detailFragment = new DetailFragment(); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.movie_detail_container, detailFragment, DETAILFRAGMENT_TAG).commit(); + } else { + mTwoPane = false; + getSupportActionBar().setElevation(0f); + } } @Override @@ -24,8 +40,6 @@ public boolean onCreateOptionsMenu(Menu menu) { return true; } - -///testing @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will @@ -33,13 +47,29 @@ public boolean onOptionsItemSelected(MenuItem item) { // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); - //noinspection SimplifiableIfStatement - if (id == R.id.action_settings) { - Intent settingIntent = new Intent(this, MoviePreferenceActivity.class); - startActivity(settingIntent); - return true; - } - return super.onOptionsItemSelected(item); } + + @Override + public void onItemSelected(MovieDetailsForm selectedMovie) { + if (mTwoPane) { + // In two-pane mode, show the detail view in this activity by + // adding or replacing the detail fragment using a + // fragment transaction. + Bundle args = new Bundle(); + args.putParcelable(DetailFragment.DETAIL_MOVIE, selectedMovie); + + DetailFragment fragment = new DetailFragment(); + fragment.setArguments(args); + + getSupportFragmentManager().beginTransaction() + .replace(R.id.movie_detail_container, fragment, DETAILFRAGMENT_TAG) + .commit(); + } else { + Intent intent = new Intent(this, DetailActivity.class); + intent.putExtra(DetailFragment.DETAIL_MOVIE, selectedMovie); + startActivity(intent); + } + } + } diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/MainActivityMoviesViewFragment.java b/app/src/main/java/za/co/ubiquitech/vmovies/MainActivityMoviesViewFragment.java deleted file mode 100644 index 81da1eb..0000000 --- a/app/src/main/java/za/co/ubiquitech/vmovies/MainActivityMoviesViewFragment.java +++ /dev/null @@ -1,227 +0,0 @@ -package za.co.ubiquitech.vmovies; - -import android.app.Fragment; -import android.app.ProgressDialog; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.AsyncTask; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.util.Log; -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.AdapterView; -import android.widget.GridView; -import android.widget.Toast; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; - -import za.co.ubiquitech.vmovies.formObjects.MovieDetailsForm; -import za.co.ubiquitech.vmovies.util.ImageDownloadAdapter; - -/** - * @author vane - * @since 2015/09/23. - */ -public class MainActivityMoviesViewFragment extends Fragment { - private final String LOG_TAG = MainActivityMoviesViewFragment.class.getSimpleName(); - JSONArray movieResults = null; - private static ProgressDialog progressDialog; - private ImageDownloadAdapter mMovieAdapter; - private GridView gridView; - - public MainActivityMoviesViewFragment() { - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - updateMovies(); - setHasOptionsMenu(true); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.moviefragment, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == R.id.action_refresh) { - updateMoveResults(); - } - return super.onOptionsItemSelected(item); - } - - private void updateMoveResults() { - - FetchMoviesTask moviesTask = new FetchMoviesTask(); - moviesTask.execute(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_main_activity_movies_view, container, false); - gridView = (GridView) rootView.findViewById(R.id.gridview_movies); - - - gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - MovieDetailsForm movieDetails = mMovieAdapter.getItem(position); - Toast toast = Toast.makeText(getActivity(), movieDetails.getMovieName(), Toast.LENGTH_SHORT); - toast.show(); - - Intent intent = new Intent(getActivity(), MovieDetailActivity.class).putExtra("selected_movie", movieDetails); - startActivity(intent); - } - }); - - return rootView; - } - - private void updateMovies() { - FetchMoviesTask fetchMoviesTask = new FetchMoviesTask(); - fetchMoviesTask.execute(); - } - - public class FetchMoviesTask extends AsyncTask { - - @Override - protected MovieDetailsForm[] doInBackground(String... params) { - HttpURLConnection urlConnection = null; - BufferedReader reader = null; - String moviesJsonStr = null; - try { - - SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getActivity().getBaseContext()); - String sortBy = SP.getString("sort_by", ""); - - final String MOVIES_BASE_URL = "http://api.themoviedb.org/3/discover/movie?api_key=" + MainActivity.MOVIE_API_KEY + - "&" + sortBy; - - URL url = new URL(MOVIES_BASE_URL); - - urlConnection = (HttpURLConnection) url.openConnection(); - - urlConnection.setRequestMethod("GET"); - urlConnection.connect(); - - - InputStream inpustStream = urlConnection.getInputStream(); - - StringBuffer buffer = new StringBuffer(); - - if (inpustStream == null) { - Log.v(LOG_TAG, "Inputstream is null "); - return null; - } - - reader = new BufferedReader(new InputStreamReader(inpustStream)); - - String line; - while ((line = reader.readLine()) != null) { - // Since it's JSON, adding a newline isn't necessary (it won't affect parsing) - // But it does make debugging a *lot* easier if you print out the completed - // buffer for debugging. - buffer.append(line + "\n"); - } - //Stream was emplty. No need to parse - if (buffer.length() == 0) { - Log.v(LOG_TAG, "Buffer is null "); - return null; - } - - moviesJsonStr = buffer.toString(); - - } catch (IOException e) { - Log.d(LOG_TAG, "Error ", e); - return null; - } finally { - if (urlConnection != null) { - urlConnection.disconnect(); - } - if (reader != null) { - try { - reader.close(); - } catch (final IOException e) { - Log.e(LOG_TAG, "Error closing stream", e); - } - } - } - - try { - return getMovieDataFromJSON(moviesJsonStr); - } catch (JSONException e) { - Log.d(LOG_TAG, e.getMessage(), e); - e.printStackTrace(); - } - return null; - } - - - @Override - protected void onPreExecute() { - super.onPreExecute(); - progressDialog = new ProgressDialog(getActivity()); - progressDialog.setIndeterminate(true); - progressDialog.setMessage("Loading..."); - progressDialog.show(); - } - - @Override - protected void onPostExecute(MovieDetailsForm[] result) { - progressDialog.dismiss(); - if (result != null) { - mMovieAdapter = new ImageDownloadAdapter(getActivity(), result); - gridView.setAdapter(mMovieAdapter); - } - } - - private MovieDetailsForm[] getMovieDataFromJSON(String movieStr) throws JSONException { - String moviePoster; - String movieName; - String moviePlot; - Double movieRating; - String movieRealseDate; - - JSONObject jsonObj = new JSONObject(movieStr); - - //get JSON ARRAY node - movieResults = jsonObj.getJSONArray("results"); - MovieDetailsForm[] resultStrs = new MovieDetailsForm[movieResults.length() + 1]; - //loop through all movie results - for (int i = 0; i < movieResults.length(); i++) { - JSONObject object = movieResults.getJSONObject(i); - moviePoster = "http://image.tmdb.org/t/p/w185" + object.getString("poster_path"); - movieName = object.getString("original_title"); - moviePlot = object.getString("overview"); - movieRating = object.getDouble("vote_average"); - movieRealseDate = object.getString("release_date"); - resultStrs[i] = new MovieDetailsForm(moviePoster, movieName, moviePlot, movieRating, movieRealseDate); - } - - for (MovieDetailsForm s : resultStrs) { - Log.v(LOG_TAG, "Movie Results: " + s); - } - return resultStrs; - } - - } - -} \ No newline at end of file diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/MovieDetailActivity.java b/app/src/main/java/za/co/ubiquitech/vmovies/MovieDetailActivity.java deleted file mode 100644 index 47d96f5..0000000 --- a/app/src/main/java/za/co/ubiquitech/vmovies/MovieDetailActivity.java +++ /dev/null @@ -1,35 +0,0 @@ -package za.co.ubiquitech.vmovies; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.view.Menu; -import android.view.MenuItem; - -public class MovieDetailActivity extends AppCompatActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_movie_detail); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.menu_movie_detail, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - - //noinspection SimplifiableIfStatement - if (id == R.id.action_settings) { - return true; - } - return super.onOptionsItemSelected(item); - } -} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/MovieDetailActivityFragment.java b/app/src/main/java/za/co/ubiquitech/vmovies/MovieDetailActivityFragment.java deleted file mode 100644 index 221cbf7..0000000 --- a/app/src/main/java/za/co/ubiquitech/vmovies/MovieDetailActivityFragment.java +++ /dev/null @@ -1,43 +0,0 @@ -package za.co.ubiquitech.vmovies; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import com.squareup.picasso.Picasso; - -import za.co.ubiquitech.vmovies.formObjects.MovieDetailsForm; - -/** - * A placeholder fragment containing a simple view. - */ -public class MovieDetailActivityFragment extends Fragment { - - public MovieDetailActivityFragment() { - } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_movie_detail, container, false); - Intent intent = getActivity().getIntent(); - - if (intent != null && intent.hasExtra("selected_movie")) { - MovieDetailsForm movieDetailsForm = (MovieDetailsForm) intent.getSerializableExtra("selected_movie"); - ((TextView) rootView.findViewById(R.id.detail_movie_name)).setText(movieDetailsForm.getMovieName()); - ((TextView) rootView.findViewById(R.id.detail_movie_plot)).setText(movieDetailsForm.getMoviePlot()); - ((TextView) rootView.findViewById(R.id.release_date_view)).setText(movieDetailsForm.getMovieRealseDate()); - ((TextView) rootView.findViewById(R.id.rating_view)).setText(Double.toString(movieDetailsForm.getMovieRating()) + "/10"); - - ImageView moviePoster = (ImageView) rootView.findViewById(R.id.detail_poster_image); - Picasso.with(getActivity()) - .load(movieDetailsForm.getMoviePoster()) - .into(moviePoster); - } - return rootView; - } -} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/MovieFragment.java b/app/src/main/java/za/co/ubiquitech/vmovies/MovieFragment.java new file mode 100644 index 0000000..1ecb392 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/MovieFragment.java @@ -0,0 +1,394 @@ +package za.co.ubiquitech.vmovies; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.ContentUris; +import android.content.Context; +import android.content.DialogInterface; +import android.database.Cursor; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.design.widget.Snackbar; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.util.Log; +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.AdapterView; +import android.widget.GridView; +import android.widget.Toast; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import za.co.ubiquitech.vmovies.database.MoviesContract; +import za.co.ubiquitech.vmovies.formObjects.MovieDetailsForm; +import za.co.ubiquitech.vmovies.util.ImageDownloadAdapter; + +/** + * @author vane + * @since 2015/09/23. + */ +public class MovieFragment extends Fragment implements LoaderManager.LoaderCallbacks { + private final String LOG_TAG = MovieFragment.class.getSimpleName(); + JSONArray movieResults = null; + private ImageDownloadAdapter mMovieAdapter; + private GridView gridView; + + private static final int CURSOR_LOADER = 0; + + + /** + * A callback interface that all activities containing this fragment must + * implement. This mechanism allows activities to be notified of item + * selections. + */ + public interface Callback { + /** + * DetailFragmentCallback for when an item has been selected. + */ + public void onItemSelected(MovieDetailsForm selectedMovie); + } + + public MovieFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.moviefragment, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + int id = item.getItemId(); + + if (id == R.id.most_popular) { + updateMovies("popular"); + } + + if (id == R.id.top_rated) { + updateMovies("top_rated"); + } + + if (id == R.id.favourite) { + updateMovies("favourite"); + } + + return super.onOptionsItemSelected(item); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_main_activity_movies_view, container, false); + gridView = (GridView) rootView.findViewById(R.id.gridview_movies); + getActivity().setTitle("Favourite"); + + gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + MovieDetailsForm movieDetails = mMovieAdapter.getItem(position); + Toast toast = Toast.makeText(getActivity(), movieDetails.getMovieName(), Toast.LENGTH_SHORT); + toast.show(); + ((Callback) getActivity()).onItemSelected(movieDetails); + } + }); + + //Long press gives user option to delete a request + gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView adapterView, View view, final int position, long id) { + if (getActivity().getTitle().equals("Favourite")) { + AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity()); + alertDialog.setMessage("Delete Movie from list"); + alertDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + MovieDetailsForm movieDetails = mMovieAdapter.getItem(position); + + List deleteFile = new ArrayList<>(); + + deleteFile.add(new File(getRealPathFromURI(movieDetails.getMovieBackdrop()))); + deleteFile.add(new File(getRealPathFromURI(movieDetails.getMoviePoster()))); + Uri mUri = ContentUris.withAppendedId(MoviesContract.MovieEntry.CONTENT_URI, + position + 1); + getActivity().getContentResolver().delete(mUri, null, null); + mUri = ContentUris.withAppendedId(MoviesContract.ReviewEntry.CONTENT_URI, + Long.parseLong(movieDetails.getMovieId())); + getActivity().getContentResolver().delete(mUri, null, null); + deletePictures((deleteFile)); + getLoaderManager().restartLoader(CURSOR_LOADER, null, MovieFragment.this); + } + }); + alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + alertDialog.show(); + } + return true; + } + }); + + return rootView; + } + + private String getRealPathFromURI(String contentURI) { + Uri contentUri = Uri.parse(contentURI); + Cursor cursor = getActivity().getContentResolver().query(contentUri, null, null, null, null); + if (cursor == null) { + return contentUri.getPath(); + } else { + cursor.moveToFirst(); + int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); + String path = cursor.getString(index); + cursor.close(); + return path; + } + } + + //Delete downloaded pictures from phone storage + private void deletePictures(List fileList) { + File file; + for (int i = 0; i < fileList.size(); i++) { + file = fileList.get(i); + file.delete(); + } + } + + private void updateMovies(String sortBy) { + + FetchMoviesTask fetchMoviesTask = new FetchMoviesTask(getActivity()); + if (sortBy.equals("popular")) { + fetchMoviesTask.execute(sortBy, "Most Popular"); + } else if (sortBy.equals("top_rated")) { + fetchMoviesTask.execute(sortBy, "Top Rated"); + } else { + getActivity().setTitle("Favourite"); + getLoaderManager().restartLoader(CURSOR_LOADER, null, MovieFragment.this); + } + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + getLoaderManager().initLoader(CURSOR_LOADER, null, MovieFragment.this); + super.onActivityCreated(savedInstanceState); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new CursorLoader(getActivity(), + MoviesContract.MovieEntry.CONTENT_URI, + null, + null, + null, + null); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + + int count = 0; + MovieDetailsForm[] movies = new MovieDetailsForm[data.getCount()]; + if (data.getCount() > 0) {//check if cursor not empty + data.moveToFirst(); + do { + movies[count] = new MovieDetailsForm( + data.getString(1), + data.getString(2), + data.getString(3), + data.getString(4), + data.getString(5), + data.getString(6), + data.getString(7)); + count++; + data.moveToNext(); + } while (!data.isAfterLast()); + } + mMovieAdapter = new ImageDownloadAdapter(getActivity(), movies); + gridView.setAdapter(mMovieAdapter); + } + + @Override + public void onLoaderReset(Loader loader) { + } + + public class FetchMoviesTask extends AsyncTask { + + private final Context mContext; + private String title; + private ProgressDialog progressDialog; + + FetchMoviesTask(Activity activity) { + this.mContext = activity; + } + + @Override + protected MovieDetailsForm[] doInBackground(String... params) { + HttpURLConnection urlConnection = null; + BufferedReader reader = null; + String moviesJsonStr = null; + title = params[1]; + + try { + String sortBy = params[0]; + final String MOVIES_BASE_URL = "http://api.themoviedb.org/3/movie/" + sortBy + "?api_key=" + MainActivity.MOVIE_API_KEY + + "&" + sortBy; + + URL url = new URL(MOVIES_BASE_URL); + + urlConnection = (HttpURLConnection) url.openConnection(); + + urlConnection.setRequestMethod("GET"); + urlConnection.setConnectTimeout(10 * 1000); + urlConnection.connect(); + + + InputStream inputStream = urlConnection.getInputStream(); + + StringBuffer buffer = new StringBuffer(); + + if (inputStream == null) { + Log.v(LOG_TAG, "Inputstream is null "); + return null; + } + + reader = new BufferedReader(new InputStreamReader(inputStream)); + + String line; + while ((line = reader.readLine()) != null) { + // Since it's JSON, adding a newline isn't necessary (it won't affect parsing) + // But it does make debugging a *lot* easier if you print out the completed + // buffer for debugging. + buffer.append(line + "\n"); + } + //Stream was emplty. No need to parse + if (buffer.length() == 0) { + Log.v(LOG_TAG, "Buffer is null "); + return null; + } + + moviesJsonStr = buffer.toString(); + + } catch (IOException e) { + Log.d(LOG_TAG, "Error ", e); + return null; + } finally { + if (urlConnection != null) { + urlConnection.disconnect(); + } + if (reader != null) { + try { + reader.close(); + } catch (final IOException e) { + Log.e(LOG_TAG, "Error closing stream", e); + } + } + } + + try { + + return getMovieDataFromJSON(moviesJsonStr); + } catch (JSONException e) { + Log.d(LOG_TAG, e.getMessage(), e); + e.printStackTrace(); + } + return null; + } + + + @Override + protected void onPreExecute() { + super.onPreExecute(); + progressDialog = new ProgressDialog(getActivity()); + progressDialog.setIndeterminate(true); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setMessage("Loading..."); + progressDialog.show(); + } + + @Override + protected void onPostExecute(MovieDetailsForm[] result) { + progressDialog.dismiss(); + if (result != null) { + getActivity().setTitle(title); + mMovieAdapter = new ImageDownloadAdapter(getActivity(), result); + gridView.setAdapter(mMovieAdapter); + } else { + showError("Error retrieving movie, please check internet connection"); + } + } + + private MovieDetailsForm[] getMovieDataFromJSON(String movieStr) throws JSONException { + String moviePoster; + String movieName; + String moviePlot; + String movieRating; + String movieReleaseDate; + String movieId; + String movieBackdrop; + + JSONObject jsonObj = new JSONObject(movieStr); + + //get JSON ARRAY node + movieResults = jsonObj.getJSONArray("results"); + MovieDetailsForm[] resultStrs = new MovieDetailsForm[movieResults.length() + 1]; + //loop through all movie results + for (int i = 0; i < movieResults.length(); i++) { + JSONObject object = movieResults.getJSONObject(i); + movieBackdrop = "http://image.tmdb.org/t/p/w500" + object.getString("backdrop_path"); + moviePoster = "http://image.tmdb.org/t/p/w342" + object.getString("poster_path"); + movieName = object.getString("original_title"); + moviePlot = object.getString("overview"); + movieRating = object.getString("vote_average"); + movieReleaseDate = object.getString("release_date"); + movieId = object.getString("id"); + resultStrs[i] = new MovieDetailsForm(movieId, movieName, moviePoster, movieBackdrop, moviePlot, movieReleaseDate, movieRating); + } + return resultStrs; + } + + } + + private void showError(String message) { + //Display error + final Snackbar snackBar = Snackbar.make(getView(), message, Snackbar.LENGTH_LONG); + snackBar.setAction("Dismiss", new View.OnClickListener() { + @Override + public void onClick(View v) { + snackBar.dismiss(); + } + }); + snackBar.show(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/ReviewFragment.java b/app/src/main/java/za/co/ubiquitech/vmovies/ReviewFragment.java new file mode 100644 index 0000000..8a596d1 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/ReviewFragment.java @@ -0,0 +1,34 @@ +package za.co.ubiquitech.vmovies; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import za.co.ubiquitech.vmovies.formObjects.MovieReviews; +import za.co.ubiquitech.vmovies.util.CustomReviewsViewAdapter; + +public class ReviewFragment extends Fragment { + private final String LOG_TAG = ReviewFragment.class.getSimpleName(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View rootView = inflater.inflate(R.layout.fragment_movie_review, container, false); + ListView customReviewsListView = (ListView) rootView.findViewById(R.id.reviews_list_view); + Bundle args = getArguments(); + MovieReviews currentMovieReview = args.getParcelable("review"); + CustomReviewsViewAdapter mReviewsAdapter = new CustomReviewsViewAdapter(getActivity(), currentMovieReview.getReviews()); + customReviewsListView.setAdapter(mReviewsAdapter); + return rootView; + } + +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/database/MoviesContract.java b/app/src/main/java/za/co/ubiquitech/vmovies/database/MoviesContract.java new file mode 100644 index 0000000..a099957 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/database/MoviesContract.java @@ -0,0 +1,75 @@ +package za.co.ubiquitech.vmovies.database; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.net.Uri; +import android.provider.BaseColumns; + +/** + * @author Vane + * @since 21/10/2015 + */ +public class MoviesContract { + public static final String CONTENT_AUTHORITY = "za.co.ubiquitech.vmovies"; + + public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); + + public static final class MovieEntry implements BaseColumns { + // Table Name + public static final String TABLE_MOVIES = "movies"; + // Columns + public static final String COLUMN_ID = "id"; + public static final String COLUMN_NAME = "name"; + public static final String COLUMN_POSTER = "poster"; + public static final String COLUMN_BACKDROP = "backdrop"; + public static final String COLUMN_PLOT = "plot"; + public static final String COLUMN_RELEASEDATE = "release_date"; + public static final String COLUMN_RATING = "rating"; + + //create content uri + public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + .appendPath(TABLE_MOVIES).build(); + + //create cursor for base type directory for multiple enteries + public static final String CONTENT_DIR_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + + "/" + CONTENT_AUTHORITY + "/" + TABLE_MOVIES; + + // create cursor of base type item for single entry + public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + + "/" + CONTENT_AUTHORITY + "/" + TABLE_MOVIES; + + //for building URIs on insertion + public static Uri buildMovieUri(long id) { + return ContentUris.withAppendedId(CONTENT_URI, id); + } + + } + + public static final class ReviewEntry implements BaseColumns { + // Table Name + public static final String TABLE_REVIEWS = "reviews"; + // Columns + public static final String COLUMN_MOVIE_ID = "movie_id"; + public static final String COLUMN_AUTHOR = "author"; + public static final String COLUMN_CONTENT = "content"; + + //create content uri + public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + .appendPath(TABLE_REVIEWS).build(); + + //create cursor for base type directory for multiple enteries + public static final String CONTENT_DIR_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + + "/" + CONTENT_AUTHORITY + "/" + TABLE_REVIEWS; + + // create cursor of base type item for single entry + public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + + "/" + CONTENT_AUTHORITY + "/" + TABLE_REVIEWS; + + //for building URIs on insertion + public static Uri buildReviewUri(long id) { + return ContentUris.withAppendedId(CONTENT_URI, id); + } + + } + +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/database/MoviesDBHelper.java b/app/src/main/java/za/co/ubiquitech/vmovies/database/MoviesDBHelper.java new file mode 100644 index 0000000..51d4150 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/database/MoviesDBHelper.java @@ -0,0 +1,72 @@ +package za.co.ubiquitech.vmovies.database; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +/** + * @author Vane + * @since 21/10/2015 + */ +public class MoviesDBHelper extends SQLiteOpenHelper { + public static final String LOG_TAG = MoviesDBHelper.class.getSimpleName(); + + //name and version + private static final String DATABASE_NAME = "movies.db"; + private static final int DATABASE_VERSION = 1; /// TODO: 21/10/2015 + + MoviesDBHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + + // Create database + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + + final String SQL_CREATE_MOVIE_TABLE = "CREATE TABLE " + + MoviesContract.MovieEntry.TABLE_MOVIES + "(" + MoviesContract.MovieEntry._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + MoviesContract.MovieEntry.COLUMN_ID + " TEXT NOT NULL, " + + MoviesContract.MovieEntry.COLUMN_NAME + " TEXT NOT NULL, " + + MoviesContract.MovieEntry.COLUMN_POSTER + " TEXT, " + + MoviesContract.MovieEntry.COLUMN_BACKDROP + " TEXT, " + + MoviesContract.MovieEntry.COLUMN_PLOT + " TEXT, " + + MoviesContract.MovieEntry.COLUMN_RELEASEDATE + " TEXT, " + + MoviesContract.MovieEntry.COLUMN_RATING + " TEXT);"; + + + final String SQL_CREATE_REVIEW_TABLE = "CREATE TABLE " + + MoviesContract.ReviewEntry.TABLE_REVIEWS + "(" + + MoviesContract.ReviewEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + MoviesContract.ReviewEntry.COLUMN_MOVIE_ID + " INTEGER NOT NULL, " + + MoviesContract.ReviewEntry.COLUMN_AUTHOR + " TEXT NOT NULL, " + + MoviesContract.ReviewEntry.COLUMN_CONTENT + " TEXT NOT NULL, " + + + "FOREIGN KEY (" + MoviesContract.ReviewEntry.COLUMN_MOVIE_ID + ") REFERENCES " + + MoviesContract.MovieEntry.TABLE_MOVIES + " (" + MoviesContract.MovieEntry._ID + ") );"; + + sqLiteDatabase.execSQL(SQL_CREATE_MOVIE_TABLE); + sqLiteDatabase.execSQL(SQL_CREATE_REVIEW_TABLE); + } + + // Upgrade database when version is changed. + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { + Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to " + + newVersion + ". OLD DATA WILL BE DESTROYED"); + // Drop the table + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + MoviesContract.MovieEntry.TABLE_MOVIES); + sqLiteDatabase.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + + MoviesContract.MovieEntry.TABLE_MOVIES + "'"); + + // Drop the table + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + MoviesContract.ReviewEntry.TABLE_REVIEWS); + sqLiteDatabase.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + + MoviesContract.ReviewEntry.TABLE_REVIEWS + "'"); + + // re-create database + onCreate(sqLiteDatabase); + } +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/database/MoviesProvider.java b/app/src/main/java/za/co/ubiquitech/vmovies/database/MoviesProvider.java new file mode 100644 index 0000000..da35220 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/database/MoviesProvider.java @@ -0,0 +1,286 @@ +package za.co.ubiquitech.vmovies.database; + +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.sqlite.SQLiteConstraintException; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.support.annotation.Nullable; +import android.util.Log; + +/** + * @author Vane + * @since 21/10/2015 + */ +public class MoviesProvider extends ContentProvider { + private static final String LOG_TAG = MoviesProvider.class.getSimpleName(); + private static final UriMatcher sUriMatcher = buildUriMatcher(); + private MoviesDBHelper mOpenHelper; + + //code for the UriMatcher + private static final int MOVIES = 25; + private static final int MOVIES_WITH_ID = 50; + private static final int REVIEWS = 100; + private static final int REVIEW_WITH_ID = 150; + + private static UriMatcher buildUriMatcher() { + // Build a UriMatcher by adding a specific code to return based on a match + // It's common to use NO_MATCH as the code for this case. + + final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); + final String authority = MoviesContract.CONTENT_AUTHORITY; + + // add a code for each type of URI you need + matcher.addURI(authority, MoviesContract.MovieEntry.TABLE_MOVIES, MOVIES); + //# = number + matcher.addURI(authority, MoviesContract.MovieEntry.TABLE_MOVIES + "/#", MOVIES_WITH_ID); + + matcher.addURI(authority, MoviesContract.ReviewEntry.TABLE_REVIEWS, REVIEWS); + matcher.addURI(authority, MoviesContract.ReviewEntry.TABLE_REVIEWS + "/#", REVIEW_WITH_ID); + + return matcher; + } + + + @Override + public boolean onCreate() { + mOpenHelper = new MoviesDBHelper(getContext()); + return true; + } + + @Nullable + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + Cursor retCursor; + + switch (sUriMatcher.match(uri)) { + //All Movies Selected + case MOVIES: { + retCursor = mOpenHelper.getReadableDatabase().query( + MoviesContract.MovieEntry.TABLE_MOVIES, + projection, + selection, + selectionArgs, + null, + null, + sortOrder); + return retCursor; + } + case REVIEW_WITH_ID: { + retCursor = mOpenHelper.getReadableDatabase().query( + MoviesContract.ReviewEntry.TABLE_REVIEWS, + projection, + MoviesContract.ReviewEntry.COLUMN_MOVIE_ID + " = ?", + new String[]{String.valueOf(ContentUris.parseId(uri))}, + null, + null, + sortOrder); + return retCursor; + } + // Individual flavor based on Id selected + case MOVIES_WITH_ID: { + retCursor = mOpenHelper.getReadableDatabase().query( + MoviesContract.MovieEntry.TABLE_MOVIES, + projection, + MoviesContract.MovieEntry._ID + " = ?", + new String[]{String.valueOf(ContentUris.parseId(uri))}, + null, + null, + sortOrder); + return retCursor; + } + default: { + // By default, we assume a bad URI + throw new UnsupportedOperationException("Unknown uri: " + uri); + } + } + + } + + @Nullable + @Override + public String getType(Uri uri) { + + final int match = sUriMatcher.match(uri); + + switch (match) { + case MOVIES: { + return MoviesContract.MovieEntry.CONTENT_DIR_TYPE; + } + case REVIEWS: { + return MoviesContract.ReviewEntry.CONTENT_DIR_TYPE; + } + case MOVIES_WITH_ID: { + return MoviesContract.MovieEntry.CONTENT_ITEM_TYPE; + } + default: { + throw new UnsupportedOperationException("Unknown Uri: " + uri); + } + } + + } + + @Nullable + @Override + public Uri insert(Uri uri, ContentValues contentValues) { + final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + Uri returnUri = null; + + String[] projection = {MoviesContract.MovieEntry.COLUMN_ID}; + String[] selection = {contentValues.get(MoviesContract.MovieEntry.COLUMN_ID).toString()}; + switch (sUriMatcher.match(uri)) { + case MOVIES: { + + Cursor cursor = mOpenHelper.getReadableDatabase().query( + MoviesContract.MovieEntry.TABLE_MOVIES, + projection, + MoviesContract.MovieEntry.COLUMN_ID + " = ?", + selection, + null, + null, + null); + if (cursor.moveToFirst()) { + break; + } else { + long _id = db.insert(MoviesContract.MovieEntry.TABLE_MOVIES, null, contentValues); + // insert unless it is already contained in the database + if (_id > 0) { + returnUri = MoviesContract.MovieEntry.buildMovieUri(_id); + } else { + throw new android.database.SQLException("Failed to insert row into: " + uri); + } + } + break; + } + + default: { + throw new UnsupportedOperationException("Unknown uri: " + uri); + + } + } + getContext().getContentResolver().notifyChange(uri, null); + return returnUri; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + final int match = sUriMatcher.match(uri); + int numDeleted; + switch (match) { + case MOVIES: + numDeleted = db.delete( + MoviesContract.MovieEntry.TABLE_MOVIES, selection, selectionArgs); + // reset _ID + db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + + MoviesContract.MovieEntry.TABLE_MOVIES + "'"); + break; + case MOVIES_WITH_ID: + numDeleted = db.delete(MoviesContract.MovieEntry.TABLE_MOVIES, + MoviesContract.MovieEntry._ID + " = ?", + new String[]{String.valueOf(ContentUris.parseId(uri))}); + // reset _ID + db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + + MoviesContract.MovieEntry.TABLE_MOVIES + "'"); + break; + case REVIEW_WITH_ID: + numDeleted = db.delete(MoviesContract.ReviewEntry.TABLE_REVIEWS, + MoviesContract.ReviewEntry.COLUMN_MOVIE_ID + " = ?", + new String[]{String.valueOf(ContentUris.parseId(uri))}); + // reset _ID + db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + + MoviesContract.ReviewEntry.TABLE_REVIEWS + "'"); + break; + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); + } + + return numDeleted; + } + + @Override + public int bulkInsert(Uri uri, ContentValues[] values) { + final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + final int match = sUriMatcher.match(uri); + switch (match) { + case REVIEWS: + // allows for multiple transactions + db.beginTransaction(); + + // keep track of successful inserts + int numInserted = 0; + try { + for (ContentValues value : values) { + if (value == null) { + throw new IllegalArgumentException("Cannot have null content values"); + } + long _id = -1; + try { + _id = db.insertOrThrow(MoviesContract.ReviewEntry.TABLE_REVIEWS, + null, value); + } catch (SQLiteConstraintException e) { + e.printStackTrace(); + } + if (_id != -1) { + numInserted++; + } + } + if (numInserted > 0) { + // If no errors, declare a successful transaction. + // database will not populate if this is not called + db.setTransactionSuccessful(); + } + } finally { + // all transactions occur at once + db.endTransaction(); + } + if (numInserted > 0) { + // if there was successful insertion, notify the content resolver that there + // was a change + getContext().getContentResolver().notifyChange(uri, null); + } + return numInserted; + default: + return super.bulkInsert(uri, values); + } + } + + @Override + public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) { + final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + int numUpdated = 0; + + if (contentValues == null) { + throw new IllegalArgumentException("Cannot have null content values"); + } + + switch (sUriMatcher.match(uri)) { + case MOVIES: { + numUpdated = db.update(MoviesContract.MovieEntry.TABLE_MOVIES, + contentValues, + selection, + selectionArgs); + break; + } + case MOVIES_WITH_ID: { + numUpdated = db.update(MoviesContract.MovieEntry.TABLE_MOVIES, + contentValues, + MoviesContract.MovieEntry._ID + " = ?", + new String[]{String.valueOf(ContentUris.parseId(uri))}); + break; + } + default: { + throw new UnsupportedOperationException("Unknown uri: " + uri); + } + } + + if (numUpdated > 0) { + getContext().getContentResolver().notifyChange(uri, null); + } + + return numUpdated; + } +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/MovieDetailsForm.java b/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/MovieDetailsForm.java index 6a19b1b..1ee4e80 100644 --- a/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/MovieDetailsForm.java +++ b/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/MovieDetailsForm.java @@ -1,64 +1,105 @@ package za.co.ubiquitech.vmovies.formObjects; -import java.io.Serializable; +import android.os.Parcel; +import android.os.Parcelable; /** * @author vane * @since 8/21/2015. */ -public class MovieDetailsForm implements Serializable { - String moviePoster; - String movieName; - String moviePlot; - Double movieRating; - String movieRealseDate; - - public MovieDetailsForm(String moviePoster, String movieName, String moviePlot, Double movieRating, String movieRealseDate) { +public class MovieDetailsForm implements Parcelable { + private String moviePoster; + private String movieName; + private String moviePlot; + private String movieRating; + private String movieId; + private String movieReleaseDate; + private String movieBackdrop; + + + public MovieDetailsForm(String movieId, String movieName, String moviePoster, String movieBackdrop, + String moviePlot, String movieReleaseDate, String movieRating) { + this.movieBackdrop = movieBackdrop; this.moviePoster = moviePoster; this.movieName = movieName; this.moviePlot = moviePlot; this.movieRating = movieRating; - this.movieRealseDate = movieRealseDate; + this.movieReleaseDate = movieReleaseDate; + this.movieId = movieId; + } + public static final Creator CREATOR = new Creator() { + @Override + public MovieDetailsForm createFromParcel(Parcel in) { + return new MovieDetailsForm(in); + } + + @Override + public MovieDetailsForm[] newArray(int size) { + return new MovieDetailsForm[size]; + } + }; + public String getMoviePoster() { return moviePoster; } - public void setMoviePoster(String moviePoster) { - this.moviePoster = moviePoster; - } - public String getMovieName() { return movieName; } - public void setMovieName(String movieName) { - this.movieName = movieName; - } - public String getMoviePlot() { return moviePlot; } - public void setMoviePlot(String moviePlot) { - this.moviePlot = moviePlot; + public String getMovieRating() { + return movieRating; } - public Double getMovieRating() { - return movieRating; + public String getMovieId() { + return movieId; } - public void setMovieRating(Double movieRating) { - this.movieRating = movieRating; + public String getMovieBackdrop() { + return movieBackdrop; + } + + public String getMovieReleaseDate() { + return movieReleaseDate; + } + + public void setMovieBackdrop(String movieBackdrop) { + this.movieBackdrop = movieBackdrop; + } + + public void setMoviePoster(String moviePoster) { + this.moviePoster = moviePoster; } - public String getMovieRealseDate() { - return movieRealseDate; + @Override + public int describeContents() { + return 0; } - public void setMovieRealseDate(String movieRealseDate) { - this.movieRealseDate = movieRealseDate; + protected MovieDetailsForm(Parcel in) { + this.moviePoster = in.readString(); + this.movieName = in.readString(); + this.moviePlot = in.readString(); + this.movieReleaseDate = in.readString(); + this.movieId = in.readString(); + this.movieRating = in.readString(); + this.movieBackdrop = in.readString(); } + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(moviePoster); + parcel.writeString(movieName); + parcel.writeString(moviePlot); + parcel.writeString(movieReleaseDate); + parcel.writeString(movieId); + parcel.writeString(movieRating); + parcel.writeString(movieBackdrop); + } } diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/MovieReviews.java b/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/MovieReviews.java new file mode 100644 index 0000000..1cf60d0 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/MovieReviews.java @@ -0,0 +1,72 @@ +package za.co.ubiquitech.vmovies.formObjects; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Vane + * @since 18/10/2015 + */ +public class MovieReviews implements Parcelable { + private List reviews = new ArrayList(); + ; + private List movieYouTubeURL = new ArrayList(); + + public MovieReviews(List youTubeURL, List reviews) { + this.movieYouTubeURL = youTubeURL; + this.reviews = reviews; + } + + protected MovieReviews(Parcel in) { + this.movieYouTubeURL = new ArrayList(); + in.readList(movieYouTubeURL, null); + this.reviews = new ArrayList(); + in.readList(reviews, MovieReviews.class.getClassLoader()); + + } + + public MovieReviews() { + } + + public List getReviews() { + return reviews; + } + + public void setReviews(List reviews) { + this.reviews = reviews; + } + + public List getMovieYouTubeURL() { + return movieYouTubeURL; + } + + public void setMovieYouTubeURL(List movieYouTubeURL) { + this.movieYouTubeURL = movieYouTubeURL; + } + + public static final Creator CREATOR = new Creator() { + @Override + public MovieReviews createFromParcel(Parcel in) { + return new MovieReviews(in); + } + + @Override + public MovieReviews[] newArray(int size) { + return new MovieReviews[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeList(movieYouTubeURL); + parcel.writeList(reviews); + } +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/Review.java b/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/Review.java new file mode 100644 index 0000000..7e2690b --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/formObjects/Review.java @@ -0,0 +1,76 @@ +package za.co.ubiquitech.vmovies.formObjects; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @author Vane + * @since 22/10/2015 + */ +public class Review implements Parcelable { + + private String author; + private String content; + private String movieId; + + public Review(String author, String content, String movieId) { + this.author = author; + this.content = content; + this.movieId = movieId; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMovieId() { + return movieId; + } + + public void setMovieId(String movieId) { + this.movieId = movieId; + } + + protected Review(Parcel in) { + author = in.readString(); + content = in.readString(); + movieId = in.readString(); + + } + + public static final Creator CREATOR = new Creator() { + @Override + public Review createFromParcel(Parcel in) { + return new Review(in); + } + + @Override + public Review[] newArray(int size) { + return new Review[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(author); + parcel.writeString(content); + parcel.writeString(movieId); + } +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/util/CustomListView.java b/app/src/main/java/za/co/ubiquitech/vmovies/util/CustomListView.java new file mode 100644 index 0000000..b709d0c --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/util/CustomListView.java @@ -0,0 +1,56 @@ +package za.co.ubiquitech.vmovies.util; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.ViewGroup; +import android.widget.GridView; +import android.widget.ListView; + +import org.w3c.dom.Text; + +/** + * @author Vane + * @since 06/10/2015 + */ +public class CustomListView extends GridView{ + +boolean expanded = false; + + public CustomListView(Context context) { + super(context); + } + + public CustomListView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CustomListView(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public boolean isExpanded() { + return expanded; + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // HACK! TAKE THAT ANDROID! + if (isExpanded()) { + // Calculate entire height by providing a very large height hint. + // View.MEASURED_SIZE_MASK represents the largest height possible. + int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, + MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandSpec); + + ViewGroup.LayoutParams params = getLayoutParams(); + params.height = getMeasuredHeight(); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + public void setExpanded(boolean expanded) { + this.expanded = expanded; + } +} \ No newline at end of file diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/util/CustomReviewsViewAdapter.java b/app/src/main/java/za/co/ubiquitech/vmovies/util/CustomReviewsViewAdapter.java new file mode 100644 index 0000000..d8b73f1 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/util/CustomReviewsViewAdapter.java @@ -0,0 +1,72 @@ +package za.co.ubiquitech.vmovies.util; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import za.co.ubiquitech.vmovies.R; +import za.co.ubiquitech.vmovies.formObjects.MovieReviews; +import za.co.ubiquitech.vmovies.formObjects.Review; + +/** + * @author Vane + * @since 18/10/2015 + */ +public class CustomReviewsViewAdapter extends BaseAdapter { + private final Context context; + private List movieReviews = new ArrayList(); + + public CustomReviewsViewAdapter(Context context, List reviews) { + this.context = context; + movieReviews = reviews; + } + + @Override + public int getCount() { + return movieReviews.size(); + } + + @Override + public Review getItem(int i) { + + return movieReviews.get(i); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup viewGroup) { + + ViewHolder viewHolder; + + if (convertView == null) { + convertView = LayoutInflater.from(context).inflate(R.layout.list_reviews, viewGroup, false); + viewHolder = new ViewHolder(); + viewHolder.authorTextView = (TextView) convertView.findViewById(R.id.list_item_reviews_author_textview); + viewHolder.contentTextView = (TextView) convertView.findViewById(R.id.list_item_reviews_content_textview); + convertView.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + + viewHolder.authorTextView.setText(getItem(position).getAuthor()); + viewHolder.contentTextView.setText(getItem(position).getContent()); + + return convertView; + } + + static class ViewHolder { + TextView authorTextView; + TextView contentTextView; + } + +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/util/CustomTrailerViewAdapter.java b/app/src/main/java/za/co/ubiquitech/vmovies/util/CustomTrailerViewAdapter.java new file mode 100644 index 0000000..1ef00a5 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/util/CustomTrailerViewAdapter.java @@ -0,0 +1,72 @@ +package za.co.ubiquitech.vmovies.util; + +import android.app.Activity; +import android.content.Context; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import za.co.ubiquitech.vmovies.R; +import za.co.ubiquitech.vmovies.formObjects.MovieDetailsForm; +import za.co.ubiquitech.vmovies.formObjects.MovieReviews; + +/** + * @author Vane + * @since 17/10/2015 + */ +public class CustomTrailerViewAdapter extends BaseAdapter { + + private final Context context; + private List youTubeKeys = new ArrayList(); + + public CustomTrailerViewAdapter(Context context,List videoKey) { + this.context = context; + this.youTubeKeys=videoKey; + } + @Override + public int getCount() { + return youTubeKeys.size(); + } + + @Override + public String getItem(int i) { + return youTubeKeys.get(i); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + String trailer="Trailer "; + ViewHolder viewHolder; + + if(convertView ==null){ + convertView = LayoutInflater.from(context).inflate(R.layout.list_trailer, parent, false); + viewHolder = new ViewHolder(); + viewHolder.trailerTextView = (TextView) convertView.findViewById(R.id.textview_trailer); + convertView.setTag(viewHolder); + + }else { + viewHolder = (ViewHolder) convertView.getTag(); + } + + viewHolder.trailerTextView.setText(trailer + (position + 1)); + return convertView; + } + + static class ViewHolder { + TextView trailerTextView; + } +} diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/util/ImageDownloadAdapter.java b/app/src/main/java/za/co/ubiquitech/vmovies/util/ImageDownloadAdapter.java index 223103d..028afb7 100644 --- a/app/src/main/java/za/co/ubiquitech/vmovies/util/ImageDownloadAdapter.java +++ b/app/src/main/java/za/co/ubiquitech/vmovies/util/ImageDownloadAdapter.java @@ -35,7 +35,7 @@ public ImageDownloadAdapter(Context context, MovieDetailsForm[] movieDetailForms @Override public int getCount() { - return movies.size() - 1; + return movies.size(); } @Override diff --git a/app/src/main/java/za/co/ubiquitech/vmovies/util/JsonRequests.java b/app/src/main/java/za/co/ubiquitech/vmovies/util/JsonRequests.java new file mode 100644 index 0000000..7200005 --- /dev/null +++ b/app/src/main/java/za/co/ubiquitech/vmovies/util/JsonRequests.java @@ -0,0 +1,115 @@ +package za.co.ubiquitech.vmovies.util; + +import android.util.Log; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import za.co.ubiquitech.vmovies.MainActivity; + +/** + * @author Vane + * @since 20/10/2015 + */ +public class JsonRequests { + private static final String LOG_TAG = JsonRequests.class.getSimpleName(); + + public List FetchMovieVideoKey(String id) { + + HttpURLConnection urlConnection = null; + BufferedReader reader = null; + String moviesJsonStr = null; + try { + + final String MOVIES_BASE_URL = "https://api.themoviedb.org/3/movie/"; + final String apiKey = "/videos?api_key=" + MainActivity.MOVIE_API_KEY; + + URL url = new URL(MOVIES_BASE_URL + id + apiKey); + urlConnection = (HttpURLConnection) url.openConnection(); + + urlConnection.setRequestMethod("GET"); + urlConnection.connect(); + + InputStream inputStream = urlConnection.getInputStream(); + + StringBuilder buffer = new StringBuilder(); + + if (inputStream == null) { + Log.v(LOG_TAG, "Inputstream is null "); + return null; + } + + reader = new BufferedReader(new InputStreamReader(inputStream)); + + String line; + while ((line = reader.readLine()) != null) { + // Since it's JSON, adding a newline isn't necessary (it won't affect parsing) + // But it does make debugging a *lot* easier if you print out the completed + // buffer for debugging. + buffer.append(line).append("\n"); + } + //Stream was emplty. No need to parse + if (buffer.length() == 0) { + Log.v(LOG_TAG, "Buffer is null "); + return null; + } + moviesJsonStr = buffer.toString(); + + } catch (IOException e) { + Log.d(LOG_TAG, "Error ", e); + return null; + } finally { + if (urlConnection != null) { + urlConnection.disconnect(); + } + if (reader != null) { + try { + reader.close(); + } catch (final IOException e) { + Log.e(LOG_TAG, "Error closing stream", e); + } + } + } + + try { + return getMovieDataFromJSON(moviesJsonStr); + } catch (JSONException e) { + Log.d(LOG_TAG, e.getMessage(), e); + e.printStackTrace(); + } + return null; + } + + private List getMovieDataFromJSON(String movieStr) throws JSONException { + String movieKey; + + JSONObject jsonObj = new JSONObject(movieStr); + + //get JSON ARRAY node + JSONArray movieResults = jsonObj.getJSONArray("results"); + List resultStrs = new ArrayList<>(); + //loop through all movie results + for (int i = 0; i < movieResults.length(); i++) { + JSONObject object = movieResults.getJSONObject(i); + String baseYouTubeUrl = "http://www.youtube.com/watch?v="; + movieKey = baseYouTubeUrl + object.getString("key"); + resultStrs.add(movieKey); + } + return resultStrs; + } + +} + + + + diff --git a/app/src/main/res/layout-sw600dp/activity_main.xml b/app/src/main/res/layout-sw600dp/activity_main.xml new file mode 100644 index 0000000..b5faec4 --- /dev/null +++ b/app/src/main/res/layout-sw600dp/activity_main.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7bb9fbf..ee1af39 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,7 +1,8 @@ + tools:context=".MovieFragment" + tools:layout="@android:layout/list_content" /> diff --git a/app/src/main/res/layout/activity_movie_detail.xml b/app/src/main/res/layout/activity_movie_detail.xml index af3b34c..2a08cc5 100644 --- a/app/src/main/res/layout/activity_movie_detail.xml +++ b/app/src/main/res/layout/activity_movie_detail.xml @@ -1,7 +1,9 @@ - + tools:context=".DetailActivity" + tools:ignore="MergeRootFrame"/> + + diff --git a/app/src/main/res/layout/fragment_main_activity_movies_view.xml b/app/src/main/res/layout/fragment_main_activity_movies_view.xml index 7b5a50b..e7083b8 100644 --- a/app/src/main/res/layout/fragment_main_activity_movies_view.xml +++ b/app/src/main/res/layout/fragment_main_activity_movies_view.xml @@ -1,17 +1,20 @@ + tools:context=".MainActivity"> - - + android:layout_height="match_parent" + android:gravity="center" + android:numColumns="auto_fit" + android:padding="0dp" /> diff --git a/app/src/main/res/layout/fragment_movie_detail.xml b/app/src/main/res/layout/fragment_movie_detail.xml index d3e00db..25fd3ca 100644 --- a/app/src/main/res/layout/fragment_movie_detail.xml +++ b/app/src/main/res/layout/fragment_movie_detail.xml @@ -1,107 +1,198 @@ - - - - - - - + android:id="@+id/detail_layout"> + android:fillViewport="false" + android:orientation="vertical"> - + android:layout_height="wrap_content"> - - - - - - + android:layout_margin="5dp" + card_view:cardBackgroundColor="#9E9E9E" + card_view:cardCornerRadius="5dp"> + android:orientation="vertical"> - + android:gravity="center" + android:orientation="vertical"> + + + android:contentDescription="@string/movie_content" + android:paddingTop="5dp" + android:scaleType="centerCrop" + android:src="@mipmap/ic_launcher" /> + + + - - - + android:gravity="center"> + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + - - + android:layout_below="@+id/card_view3" + android:gravity="center"> +