├── app
├── .gitignore
├── src
│ └── main
│ │ ├── web_hi_res_512.png
│ │ ├── res
│ │ ├── drawable
│ │ │ ├── baps.webp
│ │ │ ├── github.webp
│ │ │ ├── play_store.webp
│ │ │ ├── splash_screen_logo.webp
│ │ │ ├── tmdb_placeholder.webp
│ │ │ ├── tmdb_placeholder_land.webp
│ │ │ ├── cursor_search.xml
│ │ │ ├── shadow.xml
│ │ │ ├── ic_expand_less_white_24dp.xml
│ │ │ ├── ic_expand_more_white_24dp.xml
│ │ │ ├── ic_arrow_back_white_24dp.xml
│ │ │ ├── ic_play_circle_filled_black_24dp.xml
│ │ │ ├── ic_favorite.xml
│ │ │ ├── ic_info_outline_white_24dp.xml
│ │ │ ├── ic_cancel_white_24dp.xml
│ │ │ ├── ic_favorite_black_24dp.xml
│ │ │ ├── ic_hourglass_empty_black_24dp.xml
│ │ │ ├── ic_stars_black_24dp.xml
│ │ │ ├── ic_keyboard_voice_white_24dp.xml
│ │ │ ├── ic_search_white_24dp.xml
│ │ │ ├── ic_favorite_border.xml
│ │ │ ├── ic_timeline_black_24dp.xml
│ │ │ └── ic_language_white_36dp.xml
│ │ ├── font
│ │ │ └── hammersmith_one.ttf
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── imdb_icon.webp
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── imdb_icon.webp
│ │ ├── mipmap-xhdpi
│ │ │ ├── imdb_icon.webp
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── imdb_icon.webp
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── imdb_icon.webp
│ │ │ └── ic_launcher.png
│ │ ├── drawable-hdpi
│ │ │ ├── ic_stat_notification.webp
│ │ │ ├── no_internet_placeholder.webp
│ │ │ └── no_internet_placeholder_landscape.webp
│ │ ├── drawable-mdpi
│ │ │ ├── ic_stat_notification.png
│ │ │ ├── no_internet_placeholder.webp
│ │ │ └── no_internet_placeholder_landscape.webp
│ │ ├── drawable-xhdpi
│ │ │ ├── ic_stat_notification.webp
│ │ │ ├── no_internet_placeholder.webp
│ │ │ └── no_internet_placeholder_landscape.webp
│ │ ├── drawable-xxhdpi
│ │ │ ├── ic_stat_notification.webp
│ │ │ ├── no_internet_placeholder.webp
│ │ │ └── no_internet_placeholder_landscape.webp
│ │ ├── drawable-xxxhdpi
│ │ │ ├── ic_stat_notification.webp
│ │ │ ├── no_internet_placeholder.webp
│ │ │ └── no_internet_placeholder_landscape.webp
│ │ ├── color
│ │ │ └── selector.xml
│ │ ├── anim
│ │ │ └── bounce.xml
│ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── styles.xml
│ │ │ └── strings.xml
│ │ ├── menu
│ │ │ ├── menu_main.xml
│ │ │ └── menu_bottom_nav.xml
│ │ └── layout
│ │ │ ├── rv_genre_item.xml
│ │ │ ├── rv_movie_item.xml
│ │ │ ├── rv_cast.xml
│ │ │ ├── activity_splash_screen.xml
│ │ │ ├── rv_trailer_item.xml
│ │ │ ├── rv_review_item.xml
│ │ │ ├── activity_about_me.xml
│ │ │ ├── activity_main.xml
│ │ │ └── activity_details.xml
│ │ ├── java
│ │ └── bapspatil
│ │ │ └── silverscreener
│ │ │ ├── utils
│ │ │ ├── SilverScreenerGlideModule.java
│ │ │ ├── NetworkUtils.java
│ │ │ └── EndlessScrollListener.java
│ │ │ ├── SilverScreenerApp.java
│ │ │ ├── data
│ │ │ └── RealmDataSource.java
│ │ │ ├── ui
│ │ │ ├── SplashScreenActivity.java
│ │ │ ├── AboutMeActivity.java
│ │ │ ├── MainActivity.java
│ │ │ └── DetailsActivity.java
│ │ │ ├── model
│ │ │ ├── TMDBReviewResponse.java
│ │ │ ├── TMDBTrailerResponse.java
│ │ │ ├── Crew.java
│ │ │ ├── Cast.java
│ │ │ ├── Review.java
│ │ │ ├── GenresItem.java
│ │ │ ├── Trailer.java
│ │ │ ├── TMDBCreditsResponse.java
│ │ │ ├── MovieRecyclerView.java
│ │ │ ├── TMDBResponse.java
│ │ │ ├── Movie.java
│ │ │ └── TMDBDetailsResponse.java
│ │ │ ├── adapters
│ │ │ ├── GenresRecyclerViewAdapter.java
│ │ │ ├── CastRecyclerViewAdapter.java
│ │ │ ├── MovieRecyclerViewAdapter.java
│ │ │ ├── ReviewRecyclerViewAdapter.java
│ │ │ └── TrailerRecyclerViewAdapter.java
│ │ │ └── network
│ │ │ └── RetrofitAPI.java
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── design
├── screen0.png
├── screen1.png
├── screen2.png
├── screen3.png
├── screen4.png
└── screen5.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── README.md
├── gradlew.bat
├── gradlew
└── LICENSE
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/design/screen0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/design/screen0.png
--------------------------------------------------------------------------------
/design/screen1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/design/screen1.png
--------------------------------------------------------------------------------
/design/screen2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/design/screen2.png
--------------------------------------------------------------------------------
/design/screen3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/design/screen3.png
--------------------------------------------------------------------------------
/design/screen4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/design/screen4.png
--------------------------------------------------------------------------------
/design/screen5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/design/screen5.png
--------------------------------------------------------------------------------
/app/src/main/web_hi_res_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/web_hi_res_512.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baps.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable/baps.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/github.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable/github.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_store.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable/play_store.webp
--------------------------------------------------------------------------------
/app/src/main/res/font/hammersmith_one.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/font/hammersmith_one.ttf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/imdb_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-hdpi/imdb_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/imdb_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-mdpi/imdb_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/imdb_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-xhdpi/imdb_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/imdb_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-xxhdpi/imdb_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/imdb_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-xxxhdpi/imdb_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/splash_screen_logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable/splash_screen_logo.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tmdb_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable/tmdb_placeholder.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tmdb_placeholder_land.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable/tmdb_placeholder_land.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_stat_notification.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-hdpi/ic_stat_notification.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_stat_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-mdpi/ic_stat_notification.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/no_internet_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-hdpi/no_internet_placeholder.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/no_internet_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-mdpi/no_internet_placeholder.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_stat_notification.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-xhdpi/ic_stat_notification.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_stat_notification.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-xxhdpi/ic_stat_notification.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_stat_notification.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-xxxhdpi/ic_stat_notification.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/no_internet_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-xhdpi/no_internet_placeholder.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/no_internet_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-xxhdpi/no_internet_placeholder.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/no_internet_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-xxxhdpi/no_internet_placeholder.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/no_internet_placeholder_landscape.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-hdpi/no_internet_placeholder_landscape.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/no_internet_placeholder_landscape.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-mdpi/no_internet_placeholder_landscape.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/no_internet_placeholder_landscape.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-xhdpi/no_internet_placeholder_landscape.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/no_internet_placeholder_landscape.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-xxhdpi/no_internet_placeholder_landscape.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/no_internet_placeholder_landscape.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/SilverScreener/HEAD/app/src/main/res/drawable-xxxhdpi/no_internet_placeholder_landscape.webp
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .idea
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 | /gradle.properties
10 | app/release/
11 | app/src/main/res/layout-land/
12 | app/google-services.json
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cursor_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Dec 26 12:28:34 IST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shadow.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/color/selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/utils/SilverScreenerGlideModule.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.utils;
2 |
3 | import com.bumptech.glide.annotation.GlideModule;
4 | import com.bumptech.glide.module.AppGlideModule;
5 |
6 | /**
7 | * Created by bapspatil
8 | */
9 |
10 | @GlideModule
11 | public class SilverScreenerGlideModule extends AppGlideModule {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_expand_less_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_expand_more_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/bounce.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_play_circle_filled_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #323846
4 | #0c121f
5 | #fbf9f3
6 | #818181
7 | #929292
8 | #FFFFFF
9 | #000000
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info_outline_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cancel_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_hourglass_empty_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_stars_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_keyboard_voice_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/SilverScreenerApp.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener;
2 |
3 | import android.app.Application;
4 |
5 | import io.realm.Realm;
6 | import io.realm.RealmConfiguration;
7 |
8 | /**
9 | * Created by bapspatil
10 | */
11 |
12 | public class SilverScreenerApp extends Application {
13 |
14 | @Override
15 | public void onCreate() {
16 | super.onCreate();
17 | Realm.init(this);
18 | RealmConfiguration realmConfig = new RealmConfiguration.Builder()
19 | .name("silverscreener.realm")
20 | .deleteRealmIfMigrationNeeded()
21 | .build();
22 | Realm.setDefaultConfiguration(realmConfig);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_timeline_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_genre_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_movie_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_language_white_36dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SilverScreener
3 | Poster Of The Movie
4 | Popular
5 | Top Rated
6 | Sort By
7 | Backdrop of the movie
8 | Looks like no one bothered to write reviews for this movie! :-P
9 | Search
10 | REVIEWS
11 | CAST
12 | Cast Images
13 | About The Developer
14 | This is Bapusaheb Patil
15 | Bapusaheb Patil
16 | Hi! I am a Google-certified Android Developer and an IDF-certified UX Designer.\n\nI love making apps, watchfaces and memes.\n\nNot specifically in that order.\n\nSee more of my apps and my work here:
17 | Voice Search
18 |
19 |
20 | - Most Popular
21 | - Highest Rated
22 | - Favorites
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_bottom_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/data/RealmDataSource.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.data;
2 |
3 | import java.util.ArrayList;
4 |
5 | import bapspatil.silverscreener.model.Movie;
6 | import io.realm.Realm;
7 | import io.realm.RealmResults;
8 |
9 | /**
10 | * Created by bapspatil
11 | */
12 |
13 | public class RealmDataSource {
14 | private Realm realm;
15 |
16 | public RealmDataSource() {
17 | // Empty constructor
18 | }
19 |
20 | public void open() {
21 | realm = Realm.getDefaultInstance();
22 | }
23 |
24 | public void close() {
25 | realm.close();
26 | }
27 |
28 | public ArrayList getAllFavMovies() {
29 | RealmResults movies = realm.where(Movie.class).findAll();
30 | ArrayList movieArrayList = new ArrayList<>();
31 | movieArrayList.addAll(realm.copyFromRealm(movies));
32 | return movieArrayList;
33 | }
34 |
35 | public Movie findMovieWithId(int id) {
36 | return realm.where(Movie.class)
37 | .equalTo("id", id)
38 | .findFirst();
39 | }
40 |
41 | public void addMovieToFavs(final Movie movie) {
42 | realm.executeTransaction(realm -> realm.insertOrUpdate(movie));
43 | }
44 |
45 | public void deleteMovieFromFavs(final Movie movie) {
46 | realm.executeTransaction(realm -> movie.deleteFromRealm());
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_cast.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
17 |
18 |
24 |
25 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/ui/SplashScreenActivity.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.ui;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.view.View;
7 |
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | import bapspatil.silverscreener.R;
11 |
12 | public class SplashScreenActivity extends AppCompatActivity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_splash_screen);
18 | hideSystemUI();
19 | int SPLASH_TIME_OUT = 1000;
20 | new Handler().postDelayed(() -> {
21 | Intent i = new Intent(SplashScreenActivity.this, MainActivity.class);
22 | startActivity(i);
23 | finish();
24 | }, SPLASH_TIME_OUT);
25 | }
26 |
27 | private void hideSystemUI() {
28 | getWindow().getDecorView().setSystemUiVisibility(
29 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
30 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
31 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
32 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
33 | | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
34 | | View.SYSTEM_UI_FLAG_IMMERSIVE);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/TMDBReviewResponse.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | import java.util.ArrayList;
9 |
10 | /**
11 | * Created by bapspatil
12 | */
13 |
14 | public class TMDBReviewResponse implements Parcelable {
15 | public static final Creator CREATOR = new Creator() {
16 | @Override
17 | public TMDBReviewResponse createFromParcel(Parcel source) {
18 | return new TMDBReviewResponse(source);
19 | }
20 |
21 | @Override
22 | public TMDBReviewResponse[] newArray(int size) {
23 | return new TMDBReviewResponse[size];
24 | }
25 | };
26 | @SerializedName("results")
27 | private ArrayList results;
28 |
29 | public TMDBReviewResponse() {
30 | }
31 |
32 | protected TMDBReviewResponse(Parcel in) {
33 | this.results = in.createTypedArrayList(Review.CREATOR);
34 | }
35 |
36 | public ArrayList getResults() {
37 | return results;
38 | }
39 |
40 | public void setResults(ArrayList results) {
41 | this.results = results;
42 | }
43 |
44 | @Override
45 | public int describeContents() {
46 | return 0;
47 | }
48 |
49 | @Override
50 | public void writeToParcel(Parcel dest, int flags) {
51 | dest.writeTypedList(this.results);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/TMDBTrailerResponse.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | import java.util.ArrayList;
9 |
10 | /**
11 | * Created by bapspatil
12 | */
13 |
14 | public class TMDBTrailerResponse implements Parcelable {
15 | public static final Creator CREATOR = new Creator() {
16 | @Override
17 | public TMDBTrailerResponse createFromParcel(Parcel source) {
18 | return new TMDBTrailerResponse(source);
19 | }
20 |
21 | @Override
22 | public TMDBTrailerResponse[] newArray(int size) {
23 | return new TMDBTrailerResponse[size];
24 | }
25 | };
26 | @SerializedName("results")
27 | private ArrayList results;
28 |
29 | public TMDBTrailerResponse() {
30 | }
31 |
32 | protected TMDBTrailerResponse(Parcel in) {
33 | this.results = in.createTypedArrayList(Trailer.CREATOR);
34 | }
35 |
36 | public ArrayList getResults() {
37 | return results;
38 | }
39 |
40 | public void setResults(ArrayList results) {
41 | this.results = results;
42 | }
43 |
44 | @Override
45 | public int describeContents() {
46 | return 0;
47 | }
48 |
49 | @Override
50 | public void writeToParcel(Parcel dest, int flags) {
51 | dest.writeTypedList(this.results);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/Crew.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | /**
9 | * Created by bapspatil on 11/17/17.
10 | */
11 |
12 | public class Crew implements Parcelable {
13 | public static final Creator CREATOR = new Creator() {
14 | @Override
15 | public Crew createFromParcel(Parcel source) {
16 | return new Crew(source);
17 | }
18 |
19 | @Override
20 | public Crew[] newArray(int size) {
21 | return new Crew[size];
22 | }
23 | };
24 | @SerializedName("job")
25 | private String job;
26 | @SerializedName("name")
27 | private String name;
28 |
29 | public Crew() {
30 | }
31 |
32 | protected Crew(Parcel in) {
33 | this.job = in.readString();
34 | this.name = in.readString();
35 | }
36 |
37 | public String getJob() {
38 | return job;
39 | }
40 |
41 | public void setJob(String job) {
42 | this.job = job;
43 | }
44 |
45 | public String getName() {
46 | return name;
47 | }
48 |
49 | public void setName(String name) {
50 | this.name = name;
51 | }
52 |
53 | @Override
54 | public int describeContents() {
55 | return 0;
56 | }
57 |
58 | @Override
59 | public void writeToParcel(Parcel dest, int flags) {
60 | dest.writeString(this.job);
61 | dest.writeString(this.name);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/Cast.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | /**
9 | * Created by bapspatil
10 | */
11 |
12 | public class Cast implements Parcelable {
13 | public static final Creator CREATOR = new Creator() {
14 | @Override
15 | public Cast createFromParcel(Parcel source) {
16 | return new Cast(source);
17 | }
18 |
19 | @Override
20 | public Cast[] newArray(int size) {
21 | return new Cast[size];
22 | }
23 | };
24 | @SerializedName("name")
25 | private String name;
26 | @SerializedName("profile_path")
27 | private String profilePath;
28 |
29 | public Cast() {
30 | }
31 |
32 | protected Cast(Parcel in) {
33 | this.name = in.readString();
34 | this.profilePath = in.readString();
35 | }
36 |
37 | public String getName() {
38 | return name;
39 | }
40 |
41 | public void setName(String name) {
42 | this.name = name;
43 | }
44 |
45 | public String getProfilePath() {
46 | return profilePath;
47 | }
48 |
49 | public void setProfilePath(String profilePath) {
50 | this.profilePath = profilePath;
51 | }
52 |
53 | @Override
54 | public int describeContents() {
55 | return 0;
56 | }
57 |
58 | @Override
59 | public void writeToParcel(Parcel dest, int flags) {
60 | dest.writeString(this.name);
61 | dest.writeString(this.profilePath);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/Review.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | /**
9 | * Created by bapspatil
10 | */
11 |
12 | public class Review implements Parcelable {
13 | public static final Creator CREATOR = new Creator() {
14 | @Override
15 | public Review createFromParcel(Parcel source) {
16 | return new Review(source);
17 | }
18 |
19 | @Override
20 | public Review[] newArray(int size) {
21 | return new Review[size];
22 | }
23 | };
24 | @SerializedName("author")
25 | private String author;
26 | @SerializedName("content")
27 | private String content;
28 |
29 | public Review() {
30 | }
31 |
32 | protected Review(Parcel in) {
33 | this.author = in.readString();
34 | this.content = in.readString();
35 | }
36 |
37 | public String getAuthor() {
38 | return author;
39 | }
40 |
41 | public void setAuthor(String author) {
42 | this.author = author;
43 | }
44 |
45 | public String getContent() {
46 | return content;
47 | }
48 |
49 | public void setContent(String content) {
50 | this.content = content;
51 | }
52 |
53 | @Override
54 | public int describeContents() {
55 | return 0;
56 | }
57 |
58 | @Override
59 | public void writeToParcel(Parcel dest, int flags) {
60 | dest.writeString(this.author);
61 | dest.writeString(this.content);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/GenresItem.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | public class GenresItem implements Parcelable {
9 |
10 | public static final Creator CREATOR = new Creator() {
11 | @Override
12 | public GenresItem createFromParcel(Parcel source) {
13 | return new GenresItem(source);
14 | }
15 |
16 | @Override
17 | public GenresItem[] newArray(int size) {
18 | return new GenresItem[size];
19 | }
20 | };
21 | @SerializedName("name")
22 | private String name;
23 | @SerializedName("id")
24 | private int id;
25 |
26 | public GenresItem() {
27 | }
28 |
29 | public GenresItem(String name, int id) {
30 |
31 | this.name = name;
32 | this.id = id;
33 | }
34 |
35 | protected GenresItem(Parcel in) {
36 | this.name = in.readString();
37 | this.id = in.readInt();
38 | }
39 |
40 | public String getName() {
41 | return name;
42 | }
43 |
44 | public void setName(String name) {
45 | this.name = name;
46 | }
47 |
48 | public int getId() {
49 | return id;
50 | }
51 |
52 | public void setId(int id) {
53 | this.id = id;
54 | }
55 |
56 | @Override
57 | public int describeContents() {
58 | return 0;
59 | }
60 |
61 | @Override
62 | public void writeToParcel(Parcel dest, int flags) {
63 | dest.writeString(this.name);
64 | dest.writeInt(this.id);
65 | }
66 | }
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/Trailer.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | /**
9 | * Created by bapspatil
10 | */
11 |
12 | public class Trailer implements Parcelable {
13 | public static final Creator CREATOR = new Creator() {
14 | @Override
15 | public Trailer createFromParcel(Parcel source) {
16 | return new Trailer(source);
17 | }
18 |
19 | @Override
20 | public Trailer[] newArray(int size) {
21 | return new Trailer[size];
22 | }
23 | };
24 | @SerializedName("name")
25 | private String name;
26 | @SerializedName("key")
27 | private String key;
28 |
29 | public Trailer() {
30 | }
31 |
32 | protected Trailer(Parcel in) {
33 | this.name = in.readString();
34 | this.key = in.readString();
35 | }
36 |
37 | public static Creator getCREATOR() {
38 | return CREATOR;
39 | }
40 |
41 | public String getName() {
42 | return name;
43 | }
44 |
45 | public void setName(String name) {
46 | this.name = name;
47 | }
48 |
49 | public String getKey() {
50 | return key;
51 | }
52 |
53 | public void setKey(String key) {
54 | this.key = key;
55 | }
56 |
57 | @Override
58 | public int describeContents() {
59 | return 0;
60 | }
61 |
62 | @Override
63 | public void writeToParcel(Parcel dest, int flags) {
64 | dest.writeString(this.name);
65 | dest.writeString(this.key);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
22 |
23 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_trailer_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
25 |
26 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/TMDBCreditsResponse.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | import java.util.ArrayList;
9 |
10 | /**
11 | * Created by bapspatil
12 | */
13 |
14 | public class TMDBCreditsResponse implements Parcelable {
15 | public static final Creator CREATOR = new Creator() {
16 | @Override
17 | public TMDBCreditsResponse createFromParcel(Parcel source) {
18 | return new TMDBCreditsResponse(source);
19 | }
20 |
21 | @Override
22 | public TMDBCreditsResponse[] newArray(int size) {
23 | return new TMDBCreditsResponse[size];
24 | }
25 | };
26 | @SerializedName("cast")
27 | private ArrayList cast;
28 | @SerializedName("crew")
29 | private ArrayList crew;
30 |
31 | public TMDBCreditsResponse() {
32 | }
33 |
34 | protected TMDBCreditsResponse(Parcel in) {
35 | this.cast = in.createTypedArrayList(Cast.CREATOR);
36 | this.crew = in.createTypedArrayList(Crew.CREATOR);
37 | }
38 |
39 | public ArrayList getCast() {
40 | return cast;
41 | }
42 |
43 | public void setCast(ArrayList cast) {
44 | this.cast = cast;
45 | }
46 |
47 | public ArrayList getCrew() {
48 | return crew;
49 | }
50 |
51 | public void setCrew(ArrayList crew) {
52 | this.crew = crew;
53 | }
54 |
55 | @Override
56 | public int describeContents() {
57 | return 0;
58 | }
59 |
60 | @Override
61 | public void writeToParcel(Parcel dest, int flags) {
62 | dest.writeTypedList(this.cast);
63 | dest.writeTypedList(this.crew);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/utils/NetworkUtils.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.utils;
2 |
3 | import android.content.Context;
4 | import android.net.ConnectivityManager;
5 | import android.net.NetworkInfo;
6 |
7 | import bapspatil.silverscreener.network.RetrofitAPI;
8 | import okhttp3.Cache;
9 | import okhttp3.OkHttpClient;
10 | import okhttp3.Request;
11 | import retrofit2.Retrofit;
12 | import retrofit2.converter.gson.GsonConverterFactory;
13 |
14 | public class NetworkUtils {
15 |
16 | public static Boolean hasNetwork(Context context) {
17 | Boolean isConnected = false; // Initial Value
18 | ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
19 | NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
20 | if (activeNetwork != null && activeNetwork.isConnectedOrConnecting())
21 | isConnected = true;
22 | return isConnected;
23 | }
24 |
25 | public static Retrofit getCacheEnabledRetrofit(final Context context) {
26 | OkHttpClient okHttpClient = new OkHttpClient.Builder()
27 | .cache(new Cache(context.getCacheDir(), 5 * 1024 * 1024))
28 | .addInterceptor(chain -> {
29 | Request request = chain.request();
30 | if (hasNetwork(context))
31 | request = request.newBuilder().header("Cache-Control", "public, max-age=" + 1).build();
32 | else
33 | request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 7).build();
34 | return chain.proceed(request);
35 | })
36 | .build();
37 |
38 | return new Retrofit.Builder()
39 | .addConverterFactory(GsonConverterFactory.create())
40 | .client(okHttpClient)
41 | .baseUrl(RetrofitAPI.BASE_URL)
42 | .build();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/adapters/GenresRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.adapters;
2 |
3 | import android.content.Context;
4 | import android.graphics.Typeface;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.TextView;
9 |
10 | import androidx.core.content.res.ResourcesCompat;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | import java.util.ArrayList;
14 |
15 | import bapspatil.silverscreener.R;
16 | import bapspatil.silverscreener.model.GenresItem;
17 | import butterknife.BindView;
18 | import butterknife.ButterKnife;
19 |
20 | /**
21 | * Created by bapspatil
22 | */
23 |
24 | public class GenresRecyclerViewAdapter extends RecyclerView.Adapter {
25 |
26 | private Context mContext;
27 | private ArrayList mGenres;
28 |
29 | public GenresRecyclerViewAdapter(Context context, ArrayList genres) {
30 | this.mContext = context;
31 | this.mGenres = genres;
32 | }
33 |
34 | @Override
35 | public GenreViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
36 | View view = LayoutInflater.from(mContext).inflate(R.layout.rv_genre_item, parent, false);
37 | return new GenreViewHolder(view);
38 | }
39 |
40 | @Override
41 | public void onBindViewHolder(GenreViewHolder holder, int position) {
42 | Typeface hammersmithOne = ResourcesCompat.getFont(mContext, R.font.hammersmith_one);
43 | holder.mGenreTextView.setTypeface(hammersmithOne);
44 | holder.mGenreTextView.setText(mGenres.get(position).getName());
45 | }
46 |
47 | @Override
48 | public int getItemCount() {
49 | if (mGenres != null)
50 | return mGenres.size();
51 | else
52 | return 0;
53 | }
54 |
55 | public class GenreViewHolder extends RecyclerView.ViewHolder {
56 | @BindView(R.id.genre_tv)
57 | TextView mGenreTextView;
58 |
59 | public GenreViewHolder(View itemView) {
60 | super(itemView);
61 | ButterKnife.bind(this, itemView);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # SilverScreener
3 |
4 | A feature-rich movie guide app, that lets you discover movies from TMDb.
5 |
6 |
7 |
8 | ## Screenshots
9 |
10 |
11 |
12 |
13 |
14 | ## Libraries Used
15 |
16 | * [Android Support Library](https://developer.android.com/topic/libraries/support-library/)
17 | * [Firebase](https://firebase.google.com/)
18 | * [Retrofit](https://github.com/square/retrofit/)
19 | * [Glide](https://github.com/bumptech/glide/)
20 | * [CookieBar2](https://github.com/AviranAbady/CookieBar2)
21 | * [Gson](https://github.com/google/gson/)
22 | * [ButterKnife](https://github.com/JakeWharton/butterknife)
23 | * [recyclerview-animators](https://github.com/wasabeef/recyclerview-animators/)
24 | * [Android-ExpandableTextView](https://github.com/Blogcat/Android-ExpandableTextView)
25 | * [floatingsearchview](https://github.com/arimorty/floatingsearchview)
26 | * [Realm Database](http://realm.io/)
27 |
28 | ## Developed By
29 |
30 | Bapusaheb Patil
31 |
32 |
33 |
34 | https://bapspatil.com
35 |
36 | ## License
37 |
38 | Copyright 2018 Bapusaheb Patil
39 |
40 | Licensed under the Apache License, Version 2.0 (the "License");
41 | you may not use this file except in compliance with the License.
42 | You may obtain a copy of the License at
43 |
44 | http://www.apache.org/licenses/LICENSE-2.0
45 |
46 | Unless required by applicable law or agreed to in writing, software
47 | distributed under the License is distributed on an "AS IS" BASIS,
48 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
49 | See the License for the specific language governing permissions and
50 | limitations under the License.
51 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/ui/AboutMeActivity.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.ui;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.widget.ImageView;
8 |
9 | import androidx.appcompat.app.AppCompatActivity;
10 | import androidx.appcompat.widget.Toolbar;
11 | import androidx.core.content.ContextCompat;
12 |
13 | import com.bumptech.glide.Glide;
14 |
15 | import bapspatil.silverscreener.R;
16 | import butterknife.BindView;
17 | import butterknife.ButterKnife;
18 |
19 | public class AboutMeActivity extends AppCompatActivity {
20 |
21 | @BindView(R.id.toolbar)
22 | Toolbar toolbar;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_about_me);
28 | ButterKnife.bind(this);
29 | getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimary));
30 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
31 | getWindow().setNavigationBarColor(ContextCompat.getColor(this, R.color.colorPrimary));
32 | }
33 | toolbar.setTitle("");
34 | setSupportActionBar(toolbar);
35 | (findViewById(R.id.play_iv)).setOnClickListener(view -> {
36 | Uri uri = Uri.parse("https://play.google.com/store/apps/dev?id=7368032842071222295");
37 | Intent intentToPlayStore = new Intent(Intent.ACTION_VIEW, uri);
38 | startActivity(intentToPlayStore);
39 | });
40 | (findViewById(R.id.github_iv)).setOnClickListener(view -> {
41 | Uri uri = Uri.parse("https://github.com/bapspatil");
42 | Intent intentToGitHub = new Intent(Intent.ACTION_VIEW, uri);
43 | startActivity(intentToGitHub);
44 | });
45 | Glide.with(this)
46 | .load("https://github.com/bapspatil.png")
47 | .into((ImageView) findViewById(R.id.bapspatil_iv));
48 | }
49 |
50 | @Override
51 | public void onBackPressed() {
52 | super.onBackPressed();
53 | overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\bapoo\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
27 | # For Glide
28 | -keep public class * implements com.bumptech.glide.module.GlideModule
29 | -keep public class * extends com.bumptech.glide.AppGlideModule
30 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
31 | **[] $VALUES;
32 | public *;
33 | }
34 |
35 | # For Realm
36 | -keep class io.realm.annotations.RealmModule
37 | -keep @io.realm.annotations.RealmModule class *
38 | -keep class io.realm.internal.Keep
39 | -keep @io.realm.internal.Keep class *
40 | -dontwarn javax.**
41 | -dontwarn io.realm.**
42 |
43 | # For Retrofit
44 | -dontwarn okio.**
45 | -dontwarn javax.annotation.**
46 |
47 | -keep class com.google.gson.** { *; }
48 | -keep class com.google.inject.** { *; }
49 |
50 | -keep class org.apache.http.** { *; }
51 | -keep class org.apache.james.mime4j.** { *; }
52 |
53 | -keep class javax.inject.** { *; }
54 | -keep class javax.xml.stream.** { *; }
55 |
56 | -keep class retrofit.** { *; }
57 |
58 | -keep class com.google.appengine.** { *; }
59 |
60 | -keepattributes *Annotation*
61 | -keepattributes Signature
62 |
63 | -dontwarn com.squareup.okhttp.*
64 | -dontwarn rx.**
65 |
66 | -dontwarn javax.xml.stream.**
67 | -dontwarn com.google.appengine.**
68 | -dontwarn java.nio.file.**
69 | -dontwarn org.codehaus.**
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
18 |
22 |
28 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
46 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/MovieRecyclerView.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.os.Parcelable;
6 | import android.util.AttributeSet;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.recyclerview.widget.RecyclerView;
10 |
11 | public final class MovieRecyclerView extends RecyclerView {
12 |
13 | private static final String SAVED_SUPER_STATE = "super-state";
14 | private static final String SAVED_LAYOUT_MANAGER = "layout-manager-state";
15 | private Parcelable mLayoutManagerSavedState;
16 |
17 | public MovieRecyclerView(Context context) {
18 | super(context);
19 | }
20 |
21 | public MovieRecyclerView(Context context, @Nullable AttributeSet attrs) {
22 | super(context, attrs);
23 | }
24 |
25 | public MovieRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
26 | super(context, attrs, defStyle);
27 | }
28 |
29 | @Override
30 | protected Parcelable onSaveInstanceState() {
31 | Bundle bundle = new Bundle();
32 | bundle.putParcelable(SAVED_SUPER_STATE, super.onSaveInstanceState());
33 | bundle.putParcelable(SAVED_LAYOUT_MANAGER, this.getLayoutManager().onSaveInstanceState());
34 | return bundle;
35 | }
36 |
37 | @Override
38 | protected void onRestoreInstanceState(Parcelable state) {
39 | if (state instanceof Bundle) {
40 | Bundle bundle = (Bundle) state;
41 | mLayoutManagerSavedState = bundle.getParcelable(SAVED_LAYOUT_MANAGER);
42 | state = bundle.getParcelable(SAVED_SUPER_STATE);
43 | }
44 | super.onRestoreInstanceState(state);
45 | }
46 |
47 |
48 | @Override
49 | public void setAdapter(Adapter adapter) {
50 | super.setAdapter(adapter);
51 | restorePosition();
52 | }
53 |
54 | /**
55 | * Restores scroll position after configuration change.
56 | * NOTE: Must be called after adapter has been set.
57 | */
58 | public void restorePosition() {
59 | if (mLayoutManagerSavedState != null) {
60 | this.getLayoutManager().onRestoreInstanceState(mLayoutManagerSavedState);
61 | mLayoutManagerSavedState = null;
62 | }
63 | }
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/network/RetrofitAPI.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.network;
2 |
3 | import bapspatil.silverscreener.model.TMDBCreditsResponse;
4 | import bapspatil.silverscreener.model.TMDBDetailsResponse;
5 | import bapspatil.silverscreener.model.TMDBResponse;
6 | import bapspatil.silverscreener.model.TMDBReviewResponse;
7 | import bapspatil.silverscreener.model.TMDBTrailerResponse;
8 | import retrofit2.Call;
9 | import retrofit2.Retrofit;
10 | import retrofit2.converter.gson.GsonConverterFactory;
11 | import retrofit2.http.GET;
12 | import retrofit2.http.Path;
13 | import retrofit2.http.Query;
14 |
15 | /**
16 | * Created by bapspatil
17 | */
18 |
19 | public interface RetrofitAPI {
20 |
21 | String POSTER_BASE_URL = "https://image.tmdb.org/t/p/w342";
22 | String BACKDROP_BASE_URL = "https://image.tmdb.org/t/p/w500";
23 | String BASE_URL = "https://api.themoviedb.org/3/";
24 | Retrofit retrofit = new Retrofit.Builder()
25 | .baseUrl(BASE_URL)
26 | .addConverterFactory(GsonConverterFactory.create())
27 | .build();
28 |
29 | @GET("movie/{type}")
30 | Call getMovies(@Path("type") String TYPE, @Query("api_key") String API_KEY, @Query("language") String LANGUAGE, @Query("page") int PAGE);
31 |
32 | @GET("search/movie")
33 | Call searchMovies(@Query("api_key") String API_KEY, @Query("language") String LANGUAGE, @Query("page") int PAGE, @Query("query") String QUERY);
34 |
35 | @GET("movie/{movie_id}/videos")
36 | Call getTrailers(@Path("movie_id") int MOVIE_ID, @Query("api_key") String API_KEY, @Query("language") String LANGUAGE);
37 |
38 | @GET("movie/{movie_id}/reviews")
39 | Call getReviews(@Path("movie_id") int MOVIE_ID, @Query("api_key") String API_KEY, @Query("language") String LANGUAGE);
40 |
41 | @GET("movie/{movie_id}/credits")
42 | Call getCredits(@Path("movie_id") int MOVIE_ID, @Query("api_key") String API_KEY);
43 |
44 | @GET("movie/{movie_id}")
45 | Call getDetails(@Path("movie_id") int MOVIE_ID, @Query("api_key") String API_KEY, @Query("language") String LANGUAGE);
46 |
47 | @GET("movie/{movie_id}/similar")
48 | Call getSimilarMovies(@Path("movie_id") int MOVIE_ID, @Query("api_key") String API_KEY, @Query("language") String LANGUAGE);
49 |
50 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/TMDBResponse.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | import java.util.ArrayList;
9 |
10 | /**
11 | * Created by bapspatil
12 | */
13 |
14 | public class TMDBResponse implements Parcelable {
15 | public static final Creator CREATOR = new Creator() {
16 | @Override
17 | public TMDBResponse createFromParcel(Parcel source) {
18 | return new TMDBResponse(source);
19 | }
20 |
21 | @Override
22 | public TMDBResponse[] newArray(int size) {
23 | return new TMDBResponse[size];
24 | }
25 | };
26 | @SerializedName("page")
27 | private int page;
28 | @SerializedName("results")
29 | private ArrayList results;
30 | @SerializedName("total_results")
31 | private int totalResults;
32 | @SerializedName("total_pages")
33 | private int totalPages;
34 |
35 | public TMDBResponse() {
36 | }
37 |
38 | protected TMDBResponse(Parcel in) {
39 | this.page = in.readInt();
40 | this.results = in.createTypedArrayList(Movie.CREATOR);
41 | this.totalResults = in.readInt();
42 | this.totalPages = in.readInt();
43 | }
44 |
45 | public static Creator getCREATOR() {
46 | return CREATOR;
47 | }
48 |
49 | public int getPage() {
50 | return page;
51 | }
52 |
53 | public void setPage(int page) {
54 | this.page = page;
55 | }
56 |
57 | public ArrayList getResults() {
58 | return results;
59 | }
60 |
61 | public void setResults(ArrayList results) {
62 | this.results = results;
63 | }
64 |
65 | public int getTotalResults() {
66 | return totalResults;
67 | }
68 |
69 | public void setTotalResults(int totalResults) {
70 | this.totalResults = totalResults;
71 | }
72 |
73 | public int getTotalPages() {
74 | return totalPages;
75 | }
76 |
77 | public void setTotalPages(int totalPages) {
78 | this.totalPages = totalPages;
79 | }
80 |
81 | @Override
82 | public int describeContents() {
83 | return 0;
84 | }
85 |
86 | @Override
87 | public void writeToParcel(Parcel dest, int flags) {
88 | dest.writeInt(this.page);
89 | dest.writeTypedList(this.results);
90 | dest.writeInt(this.totalResults);
91 | dest.writeInt(this.totalPages);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/adapters/CastRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.adapters;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageView;
8 | import android.widget.TextView;
9 |
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | import java.util.ArrayList;
13 |
14 | import bapspatil.silverscreener.R;
15 | import bapspatil.silverscreener.model.Cast;
16 | import bapspatil.silverscreener.network.RetrofitAPI;
17 | import bapspatil.silverscreener.utils.GlideApp;
18 |
19 | /**
20 | * Created by bapspatil
21 | */
22 |
23 | public class CastRecyclerViewAdapter extends RecyclerView.Adapter {
24 | private ArrayList mCastList;
25 | private Context mContext;
26 | private OnActorClickHandler mActorClickHandler;
27 |
28 | public CastRecyclerViewAdapter(Context context, ArrayList cast, OnActorClickHandler onActorClickHandler) {
29 | this.mContext = context;
30 | this.mCastList = cast;
31 | this.mActorClickHandler = onActorClickHandler;
32 | }
33 |
34 | @Override
35 | public CastViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
36 | View view = LayoutInflater.from(mContext).inflate(R.layout.rv_cast, parent, false);
37 | return new CastViewHolder(view);
38 | }
39 |
40 | @Override
41 | public void onBindViewHolder(CastViewHolder holder, int position) {
42 | holder.mCastTextView.setText(mCastList.get(position).getName());
43 | GlideApp.with(mContext)
44 | .load(RetrofitAPI.POSTER_BASE_URL + mCastList.get(position).getProfilePath())
45 | .into(holder.mCastImageView);
46 | }
47 |
48 | @Override
49 | public int getItemCount() {
50 | return mCastList.size();
51 | }
52 |
53 | public interface OnActorClickHandler {
54 | void onActorClicked(String actorName);
55 | }
56 |
57 | public class CastViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
58 | public TextView mCastTextView;
59 | public ImageView mCastImageView;
60 |
61 | public CastViewHolder(View itemView) {
62 | super(itemView);
63 | mCastImageView = itemView.findViewById(R.id.cast_iv);
64 | mCastTextView = itemView.findViewById(R.id.cast_tv);
65 | itemView.setOnClickListener(this);
66 | }
67 |
68 | @Override
69 | public void onClick(View view) {
70 | mActorClickHandler.onActorClicked(mCastTextView.getText().toString());
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'realm-android'
3 | apply plugin: 'io.fabric' // Fabric's Crashlytics Gradle Plugin
4 |
5 | android {
6 | compileSdkVersion 29
7 | buildToolsVersion '29.0.2'
8 | defaultConfig {
9 | applicationId "bapspatil.silverscreener"
10 | minSdkVersion 21
11 | targetSdkVersion 29
12 | versionCode 63
13 | versionName "one.three.four"
14 | }
15 | buildTypes {
16 | release {
17 | shrinkResources true
18 | minifyEnabled true
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 |
23 | buildTypes.each {
24 | it.buildConfigField 'String', 'TMDB_API_TOKEN', MyTheMovieDBApiToken
25 | }
26 |
27 | compileOptions {
28 | sourceCompatibility JavaVersion.VERSION_1_8
29 | targetCompatibility JavaVersion.VERSION_1_8
30 | }
31 | }
32 |
33 | repositories {
34 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
35 | }
36 |
37 | ext {
38 | constraintVer = '1.1.3'
39 | glideVer = '4.9.0'
40 | butterknifeVer = '10.1.0'
41 | floatingsearchviewVer = '2.1.1'
42 | retrofitVer = '2.6.0'
43 | gsonVer = '2.8.5'
44 | cookiebar2Ver = '1.1.3'
45 | rvAnimVer = '3.0.0'
46 | expandTextVer = '1.0.5'
47 | }
48 |
49 | dependencies {
50 | implementation fileTree(include: ['*.jar'], dir: 'libs')
51 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
52 | implementation 'androidx.appcompat:appcompat:1.1.0'
53 | implementation 'com.google.android.material:material:1.2.0-alpha01'
54 | implementation 'androidx.recyclerview:recyclerview:1.1.0-rc01'
55 |
56 | implementation "com.github.bumptech.glide:glide:$glideVer"
57 | annotationProcessor "com.github.bumptech.glide:compiler:$glideVer"
58 | implementation "com.jakewharton:butterknife:$butterknifeVer"
59 | annotationProcessor "com.jakewharton:butterknife-compiler:$butterknifeVer"
60 | implementation "com.squareup.retrofit2:retrofit:$retrofitVer"
61 | implementation "com.squareup.retrofit2:converter-gson:$retrofitVer"
62 | implementation "com.google.code.gson:gson:$gsonVer"
63 | implementation "org.aviran.cookiebar2:cookiebar2:$cookiebar2Ver"
64 | implementation "jp.wasabeef:recyclerview-animators:$rvAnimVer"
65 | implementation "at.blogc:expandabletextview:$expandTextVer"
66 | implementation "com.github.arimorty:floatingsearchview:$floatingsearchviewVer"
67 |
68 | implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' // Firebase Crashlytics
69 | implementation "com.google.firebase:firebase-core:17.2.1" // Firebase Analytics
70 | implementation "com.google.firebase:firebase-messaging:20.0.0" // Firebase Cloud Messaging
71 | }
72 |
73 | apply plugin: 'com.google.gms.google-services' // Google Services Gradle Plugin
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_review_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
27 |
28 |
37 |
38 |
39 |
54 |
55 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/adapters/MovieRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.adapters;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageView;
8 |
9 | import androidx.recyclerview.widget.RecyclerView;
10 |
11 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
12 |
13 | import java.util.ArrayList;
14 |
15 | import bapspatil.silverscreener.R;
16 | import bapspatil.silverscreener.model.Movie;
17 | import bapspatil.silverscreener.network.RetrofitAPI;
18 | import bapspatil.silverscreener.utils.GlideApp;
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 |
22 | public class MovieRecyclerViewAdapter extends RecyclerView.Adapter {
23 |
24 | private ArrayList mMoviesArrayList;
25 | private Context mContext;
26 | private ItemClickListener mClickListener;
27 |
28 | public MovieRecyclerViewAdapter(Context context, ArrayList movieArrayList, ItemClickListener itemClickListener) {
29 | this.mContext = context;
30 | this.mMoviesArrayList = movieArrayList;
31 | this.mClickListener = itemClickListener;
32 | }
33 |
34 | @Override
35 | public MovieViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
36 | View view = LayoutInflater.from(mContext).inflate(R.layout.rv_movie_item, viewGroup, false);
37 | return new MovieViewHolder(view);
38 | }
39 |
40 | @Override
41 | public void onBindViewHolder(MovieViewHolder holder, int position) {
42 | Movie theMovie = mMoviesArrayList.get(position);
43 | if (theMovie.getPosterBytes() != null) {
44 | GlideApp.with(mContext)
45 | .load(theMovie.getPosterBytes())
46 | .centerCrop()
47 | .error(R.drawable.tmdb_placeholder)
48 | .fallback(R.drawable.tmdb_placeholder)
49 | .transition(new DrawableTransitionOptions().crossFade())
50 | .into(holder.mPosterImageView);
51 | } else {
52 | GlideApp.with(mContext)
53 | .load(RetrofitAPI.POSTER_BASE_URL + theMovie.getPosterPath())
54 | .centerCrop()
55 | .error(R.drawable.tmdb_placeholder)
56 | .fallback(R.drawable.tmdb_placeholder)
57 | .transition(new DrawableTransitionOptions().crossFade())
58 | .into(holder.mPosterImageView);
59 | }
60 | }
61 |
62 | @Override
63 | public int getItemCount() {
64 | if (mMoviesArrayList == null) return 0;
65 | else return mMoviesArrayList.size();
66 | }
67 |
68 | public interface ItemClickListener {
69 | void onItemClick(int position, ImageView posterImageView);
70 | }
71 |
72 | public class MovieViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
73 | @BindView(R.id.poster_image_view)
74 | ImageView mPosterImageView;
75 |
76 | MovieViewHolder(View itemView) {
77 | super(itemView);
78 | ButterKnife.bind(this, itemView);
79 | itemView.setOnClickListener(this);
80 | }
81 |
82 | @Override
83 | public void onClick(View v) {
84 | if (mClickListener != null)
85 | mClickListener.onItemClick(getAdapterPosition(), mPosterImageView);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/adapters/ReviewRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.adapters;
2 |
3 | import android.content.Context;
4 | import android.graphics.Typeface;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.view.animation.OvershootInterpolator;
9 | import android.widget.ImageButton;
10 | import android.widget.LinearLayout;
11 | import android.widget.TextView;
12 |
13 | import androidx.core.content.res.ResourcesCompat;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | import java.util.ArrayList;
17 |
18 | import at.blogc.android.views.ExpandableTextView;
19 | import bapspatil.silverscreener.R;
20 | import butterknife.BindView;
21 | import butterknife.ButterKnife;
22 |
23 | public class ReviewRecyclerViewAdapter extends RecyclerView.Adapter {
24 |
25 | private ArrayList mReviewAuthors, mReviewContents;
26 | private Context mContext;
27 |
28 | public ReviewRecyclerViewAdapter(Context context, ArrayList reviewAuthors, ArrayList reviewContents) {
29 | this.mContext = context;
30 | this.mReviewAuthors = reviewAuthors;
31 | this.mReviewContents = reviewContents;
32 | }
33 |
34 | @Override
35 | public ReviewItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
36 | View view = LayoutInflater.from(mContext).inflate(R.layout.rv_review_item, parent, false);
37 | return new ReviewItemViewHolder(view);
38 | }
39 |
40 | @Override
41 | public void onBindViewHolder(final ReviewItemViewHolder holder, int position) {
42 | String reviewAuthor = mReviewAuthors.get(position);
43 | Typeface hammersmithOne = ResourcesCompat.getFont(mContext, R.font.hammersmith_one);
44 | holder.reviewAuthorTextView.setTypeface(hammersmithOne);
45 | holder.reviewContentTextView.setTypeface(hammersmithOne);
46 | holder.reviewAuthorTextView.setText(reviewAuthor);
47 | holder.reviewContentTextView.setInterpolator(new OvershootInterpolator());
48 | holder.reviewContentTextView.setText(mReviewContents.get(position));
49 | holder.reviewExpandButton.setOnClickListener(view -> {
50 | holder.reviewExpandButton.setImageResource(holder.reviewContentTextView.isExpanded() ? R.drawable.ic_expand_more_white_24dp : R.drawable.ic_expand_less_white_24dp);
51 | holder.reviewContentTextView.toggle();
52 | });
53 | holder.reviewLinearLayout.setOnClickListener(view -> {
54 | holder.reviewExpandButton.setImageResource(holder.reviewContentTextView.isExpanded() ? R.drawable.ic_expand_more_white_24dp : R.drawable.ic_expand_less_white_24dp);
55 | holder.reviewContentTextView.toggle();
56 | });
57 | }
58 |
59 | @Override
60 | public int getItemCount() {
61 | if (mReviewAuthors == null) return 0;
62 | else return mReviewAuthors.size();
63 | }
64 |
65 | public class ReviewItemViewHolder extends RecyclerView.ViewHolder {
66 | @BindView(R.id.review_author_tv)
67 | TextView reviewAuthorTextView;
68 | @BindView(R.id.review_content_tv)
69 | ExpandableTextView reviewContentTextView;
70 | @BindView(R.id.review_expand_button)
71 | ImageButton reviewExpandButton;
72 | @BindView(R.id.review_linear_layout)
73 | LinearLayout reviewLinearLayout;
74 |
75 | ReviewItemViewHolder(View itemView) {
76 | super(itemView);
77 | ButterKnife.bind(this, itemView);
78 |
79 | }
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/adapters/TrailerRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.adapters;
2 |
3 | import android.content.Context;
4 | import android.graphics.Typeface;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import androidx.core.content.res.ResourcesCompat;
12 | import androidx.recyclerview.widget.RecyclerView;
13 |
14 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
15 |
16 | import java.util.ArrayList;
17 |
18 | import bapspatil.silverscreener.R;
19 | import bapspatil.silverscreener.utils.GlideApp;
20 | import butterknife.BindView;
21 | import butterknife.ButterKnife;
22 |
23 | public class TrailerRecyclerViewAdapter extends RecyclerView.Adapter {
24 |
25 | private ArrayList mTrailerTitles, mTrailerPaths;
26 | private Context mContext;
27 | private ItemClickListener mClickListener;
28 |
29 | public TrailerRecyclerViewAdapter(Context context, ArrayList trailerTitles, ArrayList trailerPaths, ItemClickListener itemClickListener) {
30 | this.mContext = context;
31 | this.mClickListener = itemClickListener;
32 | this.mTrailerTitles = trailerTitles;
33 | this.mTrailerPaths = trailerPaths;
34 | }
35 |
36 | @Override
37 | public TrailerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
38 | View view = LayoutInflater.from(mContext).inflate(R.layout.rv_trailer_item, viewGroup, false);
39 | return new TrailerViewHolder(view);
40 | }
41 |
42 | @Override
43 | public void onBindViewHolder(TrailerViewHolder viewHolder, int position) {
44 | String title = mTrailerTitles.get(position);
45 | Typeface hammersmithOne = ResourcesCompat.getFont(mContext, R.font.hammersmith_one);
46 | viewHolder.trailerTitleTextView.setTypeface(hammersmithOne);
47 | if (title == null)
48 | viewHolder.trailerTitleTextView.setText("Why aren't you connected to the internet? Or maybe there are no trailers for this movie...");
49 | else
50 | viewHolder.trailerTitleTextView.setText(title);
51 |
52 | String thumbnailUrlStr = "https://img.youtube.com/vi/" + mTrailerPaths.get(position) + "/0.jpg";
53 | GlideApp.with(mContext)
54 | .load(thumbnailUrlStr)
55 | .error(R.drawable.cursor_search)
56 | .fallback(R.drawable.cursor_search)
57 | .centerCrop()
58 | .transition(new DrawableTransitionOptions().crossFade())
59 | .into(viewHolder.trailerThumbnailImageView);
60 | }
61 |
62 | @Override
63 | public int getItemCount() {
64 | if (mTrailerTitles == null) return 0;
65 | else return mTrailerTitles.size();
66 | }
67 |
68 | public interface ItemClickListener {
69 | void onItemClick(String stringUrlTrailerClicked);
70 | }
71 |
72 | public class TrailerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
73 | @BindView(R.id.trailer_title_tv)
74 | TextView trailerTitleTextView;
75 | @BindView(R.id.trailer_thumbnail_iv)
76 | ImageView trailerThumbnailImageView;
77 |
78 | TrailerViewHolder(View itemView) {
79 | super(itemView);
80 | ButterKnife.bind(this, itemView);
81 | itemView.setOnClickListener(this);
82 | }
83 |
84 | @Override
85 | public void onClick(View v) {
86 | if (mClickListener != null)
87 | mClickListener.onItemClick(mTrailerPaths.get(getAdapterPosition()));
88 | }
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_about_me.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
19 |
20 |
23 |
24 |
33 |
34 |
35 |
36 |
43 |
51 |
52 |
61 |
62 |
68 |
69 |
75 |
76 |
82 |
83 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/Movie.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | import io.realm.RealmObject;
9 | import io.realm.annotations.PrimaryKey;
10 |
11 | public class Movie extends RealmObject implements Parcelable {
12 |
13 | public static final Creator CREATOR = new Creator() {
14 | @Override
15 | public Movie createFromParcel(Parcel source) {
16 | return new Movie(source);
17 | }
18 |
19 | @Override
20 | public Movie[] newArray(int size) {
21 | return new Movie[size];
22 | }
23 | };
24 | @PrimaryKey
25 | @SerializedName("id")
26 | private int id;
27 | @SerializedName("poster_path")
28 | private String posterPath;
29 | @SerializedName("title")
30 | private String title;
31 | @SerializedName("overview")
32 | private String plot;
33 | @SerializedName("release_date")
34 | private String date;
35 | @SerializedName("vote_average")
36 | private String rating;
37 | @SerializedName("backdrop_path")
38 | private String backdropPath;
39 | private byte[] posterBytes;
40 |
41 | public Movie() {
42 | }
43 |
44 | public Movie(String posterPath, String title, String plot, String date, String rating, String backdropPath, int id, byte[] posterBytes) {
45 |
46 | this.posterPath = posterPath;
47 | this.title = title;
48 | this.plot = plot;
49 | this.date = date;
50 | this.rating = rating;
51 | this.backdropPath = backdropPath;
52 | this.id = id;
53 | this.posterBytes = posterBytes;
54 | }
55 |
56 | protected Movie(Parcel in) {
57 | this.posterPath = in.readString();
58 | this.title = in.readString();
59 | this.plot = in.readString();
60 | this.date = in.readString();
61 | this.rating = in.readString();
62 | this.backdropPath = in.readString();
63 | this.id = in.readInt();
64 | this.posterBytes = in.createByteArray();
65 | }
66 |
67 | public String getPosterPath() {
68 |
69 | return posterPath;
70 | }
71 |
72 | public void setPosterPath(String posterPath) {
73 | this.posterPath = posterPath;
74 | }
75 |
76 | public String getTitle() {
77 | return title;
78 | }
79 |
80 | public void setTitle(String title) {
81 | this.title = title;
82 | }
83 |
84 | public String getPlot() {
85 | return plot;
86 | }
87 |
88 | public void setPlot(String plot) {
89 | this.plot = plot;
90 | }
91 |
92 | public String getDate() {
93 | return date;
94 | }
95 |
96 | public void setDate(String date) {
97 | this.date = date;
98 | }
99 |
100 | public String getRating() {
101 | return rating;
102 | }
103 |
104 | public void setRating(String rating) {
105 | this.rating = rating;
106 | }
107 |
108 | public String getBackdropPath() {
109 | return backdropPath;
110 | }
111 |
112 | public void setBackdropPath(String backdropPath) {
113 | this.backdropPath = backdropPath;
114 | }
115 |
116 | public int getId() {
117 | return id;
118 | }
119 |
120 | public void setId(int id) {
121 | this.id = id;
122 | }
123 |
124 | public byte[] getPosterBytes() {
125 | return posterBytes;
126 | }
127 |
128 | public void setPosterBytes(byte[] posterBytes) {
129 | this.posterBytes = posterBytes;
130 | }
131 |
132 | @Override
133 | public int describeContents() {
134 | return 0;
135 | }
136 |
137 | @Override
138 | public void writeToParcel(Parcel dest, int flags) {
139 | dest.writeString(this.posterPath);
140 | dest.writeString(this.title);
141 | dest.writeString(this.plot);
142 | dest.writeString(this.date);
143 | dest.writeString(this.rating);
144 | dest.writeString(this.backdropPath);
145 | dest.writeInt(this.id);
146 | dest.writeByteArray(this.posterBytes);
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
17 |
18 |
27 |
28 |
43 |
44 |
45 |
46 |
52 |
53 |
57 |
58 |
66 |
67 |
74 |
75 |
76 |
80 |
81 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/utils/EndlessScrollListener.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.utils;
2 |
3 | import androidx.recyclerview.widget.GridLayoutManager;
4 | import androidx.recyclerview.widget.LinearLayoutManager;
5 | import androidx.recyclerview.widget.RecyclerView;
6 | import androidx.recyclerview.widget.StaggeredGridLayoutManager;
7 |
8 | /*
9 | ** Created by bapspatil
10 | */
11 |
12 | public abstract class EndlessScrollListener extends RecyclerView.OnScrollListener {
13 |
14 | RecyclerView.LayoutManager mLayoutManager;
15 | // The minimum amount of items to have below your current scroll position
16 | // before loading more.
17 | private int visibleThreshold = 5;
18 | // The current offset index of data you have loaded
19 | private int currentPage = 1;
20 | // The total number of items in the dataset after the last load
21 | private int previousTotalItemCount = 0;
22 | // True if we are still waiting for the last set of data to load.
23 | private boolean loading = true;
24 | // Sets the starting page index
25 | private int startingPageIndex = 0;
26 |
27 | public EndlessScrollListener(LinearLayoutManager layoutManager) {
28 | this.mLayoutManager = layoutManager;
29 | }
30 |
31 | public EndlessScrollListener(GridLayoutManager layoutManager) {
32 | this.mLayoutManager = layoutManager;
33 | visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
34 | }
35 |
36 | public EndlessScrollListener(StaggeredGridLayoutManager layoutManager) {
37 | this.mLayoutManager = layoutManager;
38 | visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
39 | }
40 |
41 | public int getLastVisibleItem(int[] lastVisibleItemPositions) {
42 | int maxSize = 0;
43 | for (int i = 0; i < lastVisibleItemPositions.length; i++) {
44 | if (i == 0) {
45 | maxSize = lastVisibleItemPositions[i];
46 | } else if (lastVisibleItemPositions[i] > maxSize) {
47 | maxSize = lastVisibleItemPositions[i];
48 | }
49 | }
50 | return maxSize;
51 | }
52 |
53 | // This happens many times a second during a scroll, so be wary of the code you place here.
54 | // We are given a few useful parameters to help us work out if we need to load some more data,
55 | // but first we check if we are waiting for the previous load to finish.
56 | @Override
57 | public void onScrolled(RecyclerView view, int dx, int dy) {
58 | int lastVisibleItemPosition = 0;
59 | int totalItemCount = mLayoutManager.getItemCount();
60 |
61 | if (mLayoutManager instanceof StaggeredGridLayoutManager) {
62 | int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
63 | // get maximum element within the list
64 | lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
65 | } else if (mLayoutManager instanceof LinearLayoutManager) {
66 | lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
67 | } else if (mLayoutManager instanceof GridLayoutManager) {
68 | lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
69 | }
70 |
71 | // If the total item count is zero and the previous isn't, assume the
72 | // list is invalidated and should be reset back to initial state
73 | if (totalItemCount < previousTotalItemCount) {
74 | this.currentPage = this.startingPageIndex;
75 | this.previousTotalItemCount = totalItemCount;
76 | if (totalItemCount == 0) {
77 | this.loading = true;
78 | }
79 | }
80 | // If it’s still loading, we check to see if the dataset count has
81 | // changed, if so we conclude it has finished loading and update the current page
82 | // number and total item count.
83 | if (loading && (totalItemCount > previousTotalItemCount)) {
84 | loading = false;
85 | previousTotalItemCount = totalItemCount;
86 | }
87 |
88 | // If it isn’t currently loading, we check to see if we have breached
89 | // the visibleThreshold and need to reload more data.
90 | // If we do need to reload some more data, we execute onLoadMore to fetch the data.
91 | // threshold should reflect how many total columns there are too
92 | if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) {
93 | currentPage++;
94 | onLoadMore(currentPage, totalItemCount);
95 | loading = true;
96 | }
97 | }
98 |
99 | // Defines the process for actually loading more data based on page
100 | public abstract void onLoadMore(int page, int totalItemsCount);
101 |
102 | }
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/model/TMDBDetailsResponse.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | import java.util.List;
9 |
10 | public class TMDBDetailsResponse implements Parcelable {
11 |
12 | public static final Creator CREATOR = new Creator() {
13 | @Override
14 | public TMDBDetailsResponse createFromParcel(Parcel source) {
15 | return new TMDBDetailsResponse(source);
16 | }
17 |
18 | @Override
19 | public TMDBDetailsResponse[] newArray(int size) {
20 | return new TMDBDetailsResponse[size];
21 | }
22 | };
23 | @SerializedName("original_language")
24 | private String originalLanguage;
25 | @SerializedName("imdb_id")
26 | private String imdbId;
27 | @SerializedName("video")
28 | private boolean video;
29 | @SerializedName("title")
30 | private String title;
31 | @SerializedName("backdrop_path")
32 | private String backdropPath;
33 | @SerializedName("revenue")
34 | private int revenue;
35 | @SerializedName("genres")
36 | private List genres;
37 | @SerializedName("popularity")
38 | private double popularity;
39 | @SerializedName("id")
40 | private int id;
41 | @SerializedName("vote_count")
42 | private int voteCount;
43 | @SerializedName("budget")
44 | private int budget;
45 | @SerializedName("overview")
46 | private String overview;
47 | @SerializedName("original_title")
48 | private String originalTitle;
49 | @SerializedName("runtime")
50 | private int runtime;
51 | @SerializedName("poster_path")
52 | private String posterPath;
53 | @SerializedName("release_date")
54 | private String releaseDate;
55 | @SerializedName("vote_average")
56 | private double voteAverage;
57 | @SerializedName("tagline")
58 | private String tagline;
59 | @SerializedName("adult")
60 | private boolean adult;
61 | @SerializedName("homepage")
62 | private String homepage;
63 | @SerializedName("status")
64 | private String status;
65 |
66 | public TMDBDetailsResponse() {
67 | }
68 |
69 | public TMDBDetailsResponse(String originalLanguage, String imdbId, boolean video, String title, String backdropPath, int revenue, List genres, double popularity, int id, int voteCount, int budget, String overview, String originalTitle, int runtime, String posterPath, String releaseDate, double voteAverage, String tagline, boolean adult, String homepage, String status) {
70 | this.originalLanguage = originalLanguage;
71 | this.imdbId = imdbId;
72 | this.video = video;
73 | this.title = title;
74 |
75 | this.backdropPath = backdropPath;
76 | this.revenue = revenue;
77 | this.genres = genres;
78 | this.popularity = popularity;
79 | this.id = id;
80 | this.voteCount = voteCount;
81 | this.budget = budget;
82 | this.overview = overview;
83 | this.originalTitle = originalTitle;
84 | this.runtime = runtime;
85 | this.posterPath = posterPath;
86 | this.releaseDate = releaseDate;
87 | this.voteAverage = voteAverage;
88 | this.tagline = tagline;
89 | this.adult = adult;
90 | this.homepage = homepage;
91 | this.status = status;
92 | }
93 |
94 | protected TMDBDetailsResponse(Parcel in) {
95 | this.originalLanguage = in.readString();
96 | this.imdbId = in.readString();
97 | this.video = in.readByte() != 0;
98 | this.title = in.readString();
99 | this.backdropPath = in.readString();
100 | this.revenue = in.readInt();
101 | this.genres = in.createTypedArrayList(GenresItem.CREATOR);
102 | this.popularity = in.readDouble();
103 | this.id = in.readInt();
104 | this.voteCount = in.readInt();
105 | this.budget = in.readInt();
106 | this.overview = in.readString();
107 | this.originalTitle = in.readString();
108 | this.runtime = in.readInt();
109 | this.posterPath = in.readString();
110 | this.releaseDate = in.readString();
111 | this.voteAverage = in.readDouble();
112 | this.tagline = in.readString();
113 | this.adult = in.readByte() != 0;
114 | this.homepage = in.readString();
115 | this.status = in.readString();
116 | }
117 |
118 | public String getOriginalLanguage() {
119 | return originalLanguage;
120 | }
121 |
122 | public void setOriginalLanguage(String originalLanguage) {
123 | this.originalLanguage = originalLanguage;
124 | }
125 |
126 | public String getImdbId() {
127 | return imdbId;
128 | }
129 |
130 | public void setImdbId(String imdbId) {
131 | this.imdbId = imdbId;
132 | }
133 |
134 | public boolean isVideo() {
135 | return video;
136 | }
137 |
138 | public void setVideo(boolean video) {
139 | this.video = video;
140 | }
141 |
142 | public String getTitle() {
143 | return title;
144 | }
145 |
146 | public void setTitle(String title) {
147 | this.title = title;
148 | }
149 |
150 | public String getBackdropPath() {
151 | return backdropPath;
152 | }
153 |
154 | public void setBackdropPath(String backdropPath) {
155 | this.backdropPath = backdropPath;
156 | }
157 |
158 | public int getRevenue() {
159 | return revenue;
160 | }
161 |
162 | public void setRevenue(int revenue) {
163 | this.revenue = revenue;
164 | }
165 |
166 | public List getGenres() {
167 | return genres;
168 | }
169 |
170 | public void setGenres(List genres) {
171 | this.genres = genres;
172 | }
173 |
174 | public double getPopularity() {
175 | return popularity;
176 | }
177 |
178 | public void setPopularity(double popularity) {
179 | this.popularity = popularity;
180 | }
181 |
182 | public int getId() {
183 | return id;
184 | }
185 |
186 | public void setId(int id) {
187 | this.id = id;
188 | }
189 |
190 | public int getVoteCount() {
191 | return voteCount;
192 | }
193 |
194 | public void setVoteCount(int voteCount) {
195 | this.voteCount = voteCount;
196 | }
197 |
198 | public int getBudget() {
199 | return budget;
200 | }
201 |
202 | public void setBudget(int budget) {
203 | this.budget = budget;
204 | }
205 |
206 | public String getOverview() {
207 | return overview;
208 | }
209 |
210 | public void setOverview(String overview) {
211 | this.overview = overview;
212 | }
213 |
214 | public String getOriginalTitle() {
215 | return originalTitle;
216 | }
217 |
218 | public void setOriginalTitle(String originalTitle) {
219 | this.originalTitle = originalTitle;
220 | }
221 |
222 | public int getRuntime() {
223 | return runtime;
224 | }
225 |
226 | public void setRuntime(int runtime) {
227 | this.runtime = runtime;
228 | }
229 |
230 | public String getPosterPath() {
231 | return posterPath;
232 | }
233 |
234 | public void setPosterPath(String posterPath) {
235 | this.posterPath = posterPath;
236 | }
237 |
238 | public String getReleaseDate() {
239 | return releaseDate;
240 | }
241 |
242 | public void setReleaseDate(String releaseDate) {
243 | this.releaseDate = releaseDate;
244 | }
245 |
246 | public double getVoteAverage() {
247 | return voteAverage;
248 | }
249 |
250 | public void setVoteAverage(double voteAverage) {
251 | this.voteAverage = voteAverage;
252 | }
253 |
254 | public String getTagline() {
255 | return tagline;
256 | }
257 |
258 | public void setTagline(String tagline) {
259 | this.tagline = tagline;
260 | }
261 |
262 | public boolean isAdult() {
263 | return adult;
264 | }
265 |
266 | public void setAdult(boolean adult) {
267 | this.adult = adult;
268 | }
269 |
270 | public String getHomepage() {
271 | return homepage;
272 | }
273 |
274 | public void setHomepage(String homepage) {
275 | this.homepage = homepage;
276 | }
277 |
278 | public String getStatus() {
279 | return status;
280 | }
281 |
282 | public void setStatus(String status) {
283 | this.status = status;
284 | }
285 |
286 | @Override
287 | public int describeContents() {
288 | return 0;
289 | }
290 |
291 | @Override
292 | public void writeToParcel(Parcel dest, int flags) {
293 | dest.writeString(this.originalLanguage);
294 | dest.writeString(this.imdbId);
295 | dest.writeByte(this.video ? (byte) 1 : (byte) 0);
296 | dest.writeString(this.title);
297 | dest.writeString(this.backdropPath);
298 | dest.writeInt(this.revenue);
299 | dest.writeTypedList(this.genres);
300 | dest.writeDouble(this.popularity);
301 | dest.writeInt(this.id);
302 | dest.writeInt(this.voteCount);
303 | dest.writeInt(this.budget);
304 | dest.writeString(this.overview);
305 | dest.writeString(this.originalTitle);
306 | dest.writeInt(this.runtime);
307 | dest.writeString(this.posterPath);
308 | dest.writeString(this.releaseDate);
309 | dest.writeDouble(this.voteAverage);
310 | dest.writeString(this.tagline);
311 | dest.writeByte(this.adult ? (byte) 1 : (byte) 0);
312 | dest.writeString(this.homepage);
313 | dest.writeString(this.status);
314 | }
315 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.ui;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.res.Configuration;
7 | import android.graphics.Color;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 | import android.speech.RecognizerIntent;
11 | import android.transition.Slide;
12 | import android.view.Gravity;
13 | import android.view.View;
14 | import android.widget.ImageView;
15 | import android.widget.ProgressBar;
16 | import android.widget.Toast;
17 |
18 | import androidx.annotation.NonNull;
19 | import androidx.appcompat.app.AppCompatActivity;
20 | import androidx.core.app.ActivityOptionsCompat;
21 | import androidx.core.content.ContextCompat;
22 | import androidx.recyclerview.widget.GridLayoutManager;
23 | import androidx.recyclerview.widget.RecyclerView;
24 |
25 | import com.arlib.floatingsearchview.FloatingSearchView;
26 | import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion;
27 | import com.google.android.material.bottomnavigation.BottomNavigationView;
28 |
29 | import org.aviran.cookiebar2.CookieBar;
30 |
31 | import java.util.ArrayList;
32 |
33 | import bapspatil.silverscreener.BuildConfig;
34 | import bapspatil.silverscreener.R;
35 | import bapspatil.silverscreener.adapters.MovieRecyclerViewAdapter;
36 | import bapspatil.silverscreener.data.RealmDataSource;
37 | import bapspatil.silverscreener.model.Movie;
38 | import bapspatil.silverscreener.model.MovieRecyclerView;
39 | import bapspatil.silverscreener.model.TMDBResponse;
40 | import bapspatil.silverscreener.network.RetrofitAPI;
41 | import bapspatil.silverscreener.utils.NetworkUtils;
42 | import butterknife.BindView;
43 | import butterknife.ButterKnife;
44 | import jp.wasabeef.recyclerview.adapters.ScaleInAnimationAdapter;
45 | import retrofit2.Call;
46 | import retrofit2.Callback;
47 | import retrofit2.Response;
48 |
49 | public class MainActivity extends AppCompatActivity implements MovieRecyclerViewAdapter.ItemClickListener {
50 | private static final int SEARCH_TASK = 0, POPULAR_TASK = 1, TOP_RATED_TASK = 2, UPCOMING_TASK = 3, NOW_PLAYING_TASK = 4;
51 | private final int VOICE_RECOGNITION_REQUEST_CODE = 13;
52 | @BindView(R.id.loading_indicator)
53 | ProgressBar mProgressBar;
54 | @BindView(R.id.rv_movies)
55 | MovieRecyclerView mRecyclerView;
56 | @BindView(R.id.bottom_navigation)
57 | BottomNavigationView bottomNavigationView;
58 | @BindView(R.id.search_view)
59 | FloatingSearchView searchView;
60 | private MovieRecyclerViewAdapter mAdapter;
61 | private ArrayList movieArray = new ArrayList<>();
62 | private Context mContext;
63 | private RealmDataSource dataSource;
64 |
65 | @Override
66 | protected void onCreate(Bundle savedInstanceState) {
67 | super.onCreate(savedInstanceState);
68 | setContentView(R.layout.activity_main);
69 | ButterKnife.bind(this);
70 | getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimary));
71 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
72 | getWindow().setNavigationBarColor(ContextCompat.getColor(this, R.color.colorPrimary));
73 | }
74 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
75 | Slide slide = new Slide(Gravity.LEFT);
76 | getWindow().setExitTransition(slide);
77 | }
78 | mContext = getApplicationContext();
79 | CookieBar.build(MainActivity.this)
80 | .setLayoutGravity(Gravity.BOTTOM)
81 | .setBackgroundColor(R.color.colorAccent)
82 | .setTitleColor(R.color.colorPrimary)
83 | .setTitle("App developed by Bapusaheb Patil")
84 | .show();
85 |
86 | dataSource = new RealmDataSource();
87 | dataSource.open();
88 |
89 | int columns = 2;
90 | if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
91 | columns = 4;
92 | GridLayoutManager gridLayoutManager = new GridLayoutManager(mContext, columns);
93 | mRecyclerView.setLayoutManager(gridLayoutManager);
94 |
95 | mAdapter = new MovieRecyclerViewAdapter(mContext, movieArray, this);
96 | mRecyclerView.setAdapter(new ScaleInAnimationAdapter(mAdapter));
97 |
98 | fetchMovies(POPULAR_TASK, null);
99 |
100 | bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
101 | switch (item.getItemId()) {
102 | case R.id.action_popular:
103 | mRecyclerView.smoothScrollToPosition(0);
104 | fetchMovies(POPULAR_TASK, null);
105 | break;
106 | case R.id.action_rated:
107 | mRecyclerView.smoothScrollToPosition(0);
108 | fetchMovies(TOP_RATED_TASK, null);
109 | break;
110 | case R.id.action_upcoming:
111 | mRecyclerView.smoothScrollToPosition(0);
112 | fetchMovies(UPCOMING_TASK, null);
113 | break;
114 | case R.id.action_now:
115 | mRecyclerView.smoothScrollToPosition(0);
116 | fetchMovies(NOW_PLAYING_TASK, null);
117 | break;
118 | case R.id.action_favorites:
119 | mRecyclerView.smoothScrollToPosition(0);
120 | fetchFavs();
121 | break;
122 | default:
123 | fetchMovies(POPULAR_TASK, null);
124 | }
125 | return true;
126 | });
127 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
128 | @Override
129 | public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
130 | super.onScrolled(recyclerView, dx, dy);
131 | if (dy > 0) { // Scrolled up
132 | bottomNavigationView.setVisibility(View.GONE);
133 | } else {
134 | bottomNavigationView.setVisibility(View.VISIBLE);
135 | }
136 | }
137 | });
138 |
139 | searchView = findViewById(R.id.search_view);
140 | searchView.setOnSearchListener(new FloatingSearchView.OnSearchListener() {
141 | @Override
142 | public void onSuggestionClicked(SearchSuggestion searchSuggestion) {
143 |
144 | }
145 |
146 | @Override
147 | public void onSearchAction(String currentQuery) {
148 | mRecyclerView.smoothScrollToPosition(0);
149 | fetchMovies(SEARCH_TASK, currentQuery);
150 | searchView.clearQuery();
151 | }
152 | });
153 | searchView.setOnMenuItemClickListener(item -> {
154 | switch (item.getItemId()) {
155 | case R.id.action_about_me:
156 | Intent intentToAboutMe = new Intent(this, AboutMeActivity.class);
157 | ActivityOptionsCompat options = ActivityOptionsCompat.makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out);
158 | startActivity(intentToAboutMe, options.toBundle());
159 | break;
160 | case R.id.action_voice_search:
161 | startVoiceRecognition();
162 | }
163 | });
164 | }
165 |
166 | private void fetchMovies(int taskId, String taskQuery) {
167 | mRecyclerView.setVisibility(View.INVISIBLE);
168 | mProgressBar.setVisibility(View.VISIBLE);
169 | RetrofitAPI retrofitAPI = NetworkUtils.getCacheEnabledRetrofit(getApplicationContext()).create(RetrofitAPI.class);
170 | Call call;
171 | switch (taskId) {
172 | case SEARCH_TASK:
173 | call = retrofitAPI.searchMovies(BuildConfig.TMDB_API_TOKEN, "en-US", 1, taskQuery);
174 | break;
175 | case POPULAR_TASK:
176 | call = retrofitAPI.getMovies("popular", BuildConfig.TMDB_API_TOKEN, "en-US", 1);
177 | break;
178 | case TOP_RATED_TASK:
179 | call = retrofitAPI.getMovies("top_rated", BuildConfig.TMDB_API_TOKEN, "en-US", 1);
180 | break;
181 | case UPCOMING_TASK:
182 | call = retrofitAPI.getMovies("upcoming", BuildConfig.TMDB_API_TOKEN, "en-US", 1);
183 | break;
184 | case NOW_PLAYING_TASK:
185 | call = retrofitAPI.getMovies("now_playing", BuildConfig.TMDB_API_TOKEN, "en-US", 1);
186 | break;
187 | default:
188 | call = retrofitAPI.getMovies("popular", BuildConfig.TMDB_API_TOKEN, "en-US", 1);
189 | }
190 | call.enqueue(new Callback() {
191 | @Override
192 | public void onResponse(Call call, Response response) {
193 | TMDBResponse tmdbResponse = response.body();
194 | movieArray.clear();
195 | if (tmdbResponse != null) {
196 | movieArray.addAll(tmdbResponse.getResults());
197 | mAdapter.notifyDataSetChanged();
198 | }
199 | mRecyclerView.setVisibility(View.VISIBLE);
200 | mProgressBar.setVisibility(View.INVISIBLE);
201 | }
202 |
203 | @Override
204 | public void onFailure(Call call, Throwable t) {
205 | Toast.makeText(mContext, "Error!", Toast.LENGTH_LONG).show();
206 | mRecyclerView.setVisibility(View.INVISIBLE);
207 | mProgressBar.setVisibility(View.GONE);
208 | }
209 | });
210 | }
211 |
212 | private void fetchFavs() {
213 | mRecyclerView.setVisibility(View.INVISIBLE);
214 | mProgressBar.setVisibility(View.VISIBLE);
215 | movieArray.clear();
216 | movieArray.addAll(dataSource.getAllFavMovies());
217 | mAdapter.notifyDataSetChanged();
218 | mRecyclerView.setVisibility(View.VISIBLE);
219 | mProgressBar.setVisibility(View.INVISIBLE);
220 | }
221 |
222 | @Override
223 | public void onItemClick(int position, ImageView posterImageView) {
224 | Movie movie;
225 | movie = movieArray.get(position);
226 | Intent startDetailsActivity = new Intent(mContext, DetailsActivity.class);
227 | startDetailsActivity.putExtra("movie", movie);
228 | ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, posterImageView, "posterTransition");
229 | startActivity(startDetailsActivity, options.toBundle());
230 | }
231 |
232 | private void startVoiceRecognition() {
233 | Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
234 | intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
235 | intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Voice searching...");
236 | startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
237 | }
238 |
239 | @Override
240 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
241 | if (requestCode == VOICE_RECOGNITION_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
242 | ArrayList matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
243 | if (matches != null) {
244 | if (!matches.isEmpty()) {
245 | String query = matches.get(0);
246 | fetchMovies(SEARCH_TASK, query);
247 | Toast.makeText(this, "Searching for " + query + "...", Toast.LENGTH_LONG).show();
248 | }
249 | }
250 | }
251 | super.onActivityResult(requestCode, resultCode, data);
252 | }
253 |
254 | @Override
255 | public void onBackPressed() {
256 | if (searchView.isSearchBarFocused())
257 | searchView.clearQuery();
258 | else
259 | super.onBackPressed();
260 | }
261 |
262 | @Override
263 | protected void onDestroy() {
264 | super.onDestroy();
265 | dataSource.close();
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
17 |
18 |
27 |
28 |
36 |
37 |
42 |
43 |
44 |
45 |
51 |
52 |
61 |
62 |
66 |
67 |
79 |
80 |
91 |
92 |
101 |
102 |
107 |
108 |
115 |
116 |
124 |
125 |
126 |
127 |
132 |
133 |
140 |
141 |
150 |
151 |
152 |
157 |
158 |
165 |
166 |
175 |
176 |
177 |
178 |
186 |
187 |
192 |
193 |
200 |
201 |
209 |
210 |
211 |
216 |
217 |
224 |
225 |
233 |
234 |
235 |
240 |
241 |
248 |
249 |
257 |
258 |
259 |
260 |
272 |
273 |
281 |
282 |
288 |
289 |
299 |
300 |
308 |
309 |
314 |
315 |
319 |
320 |
321 |
322 |
331 |
332 |
337 |
338 |
343 |
344 |
345 |
346 |
357 |
358 |
364 |
365 |
368 |
369 |
375 |
376 |
377 |
386 |
387 |
393 |
394 |
395 |
396 |
397 |
407 |
417 |
418 |
425 |
426 |
427 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/silverscreener/ui/DetailsActivity.java:
--------------------------------------------------------------------------------
1 | package bapspatil.silverscreener.ui;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.graphics.Bitmap;
6 | import android.graphics.drawable.BitmapDrawable;
7 | import android.graphics.drawable.Drawable;
8 | import android.net.Uri;
9 | import android.os.Build;
10 | import android.os.Bundle;
11 | import android.transition.Slide;
12 | import android.view.Gravity;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.widget.ImageButton;
16 | import android.widget.ImageView;
17 | import android.widget.TextView;
18 | import android.widget.Toast;
19 |
20 | import androidx.annotation.Nullable;
21 | import androidx.appcompat.app.AppCompatActivity;
22 | import androidx.appcompat.widget.Toolbar;
23 | import androidx.core.app.NavUtils;
24 | import androidx.core.content.ContextCompat;
25 | import androidx.recyclerview.widget.LinearLayoutManager;
26 | import androidx.recyclerview.widget.RecyclerView;
27 |
28 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
29 | import com.bumptech.glide.request.Request;
30 | import com.bumptech.glide.request.target.SizeReadyCallback;
31 | import com.bumptech.glide.request.target.Target;
32 | import com.bumptech.glide.request.transition.Transition;
33 | import com.google.android.material.appbar.AppBarLayout;
34 | import com.google.android.material.appbar.CollapsingToolbarLayout;
35 | import com.google.android.material.floatingactionbutton.FloatingActionButton;
36 |
37 | import org.aviran.cookiebar2.CookieBar;
38 |
39 | import java.io.ByteArrayOutputStream;
40 | import java.text.DateFormat;
41 | import java.text.ParseException;
42 | import java.text.SimpleDateFormat;
43 | import java.util.ArrayList;
44 | import java.util.Date;
45 |
46 | import bapspatil.silverscreener.BuildConfig;
47 | import bapspatil.silverscreener.R;
48 | import bapspatil.silverscreener.adapters.CastRecyclerViewAdapter;
49 | import bapspatil.silverscreener.adapters.GenresRecyclerViewAdapter;
50 | import bapspatil.silverscreener.adapters.MovieRecyclerViewAdapter;
51 | import bapspatil.silverscreener.adapters.ReviewRecyclerViewAdapter;
52 | import bapspatil.silverscreener.adapters.TrailerRecyclerViewAdapter;
53 | import bapspatil.silverscreener.data.RealmDataSource;
54 | import bapspatil.silverscreener.model.Cast;
55 | import bapspatil.silverscreener.model.Crew;
56 | import bapspatil.silverscreener.model.GenresItem;
57 | import bapspatil.silverscreener.model.Movie;
58 | import bapspatil.silverscreener.model.MovieRecyclerView;
59 | import bapspatil.silverscreener.model.Review;
60 | import bapspatil.silverscreener.model.TMDBCreditsResponse;
61 | import bapspatil.silverscreener.model.TMDBDetailsResponse;
62 | import bapspatil.silverscreener.model.TMDBResponse;
63 | import bapspatil.silverscreener.model.TMDBReviewResponse;
64 | import bapspatil.silverscreener.model.TMDBTrailerResponse;
65 | import bapspatil.silverscreener.model.Trailer;
66 | import bapspatil.silverscreener.network.RetrofitAPI;
67 | import bapspatil.silverscreener.utils.GlideApp;
68 | import bapspatil.silverscreener.utils.NetworkUtils;
69 | import butterknife.BindView;
70 | import butterknife.ButterKnife;
71 | import jp.wasabeef.recyclerview.adapters.ScaleInAnimationAdapter;
72 | import retrofit2.Call;
73 | import retrofit2.Callback;
74 | import retrofit2.Response;
75 |
76 | public class DetailsActivity extends AppCompatActivity implements TrailerRecyclerViewAdapter.ItemClickListener {
77 | private static final int TRAILERS_DETAILS_TYPE = 0, REVIEWS_DETAILS_TYPE = 1;
78 | Movie tempMovie, mMovie;
79 | @BindView(R.id.appbar)
80 | AppBarLayout appBarLayout;
81 | @BindView(R.id.collapsing_toolbar_layout)
82 | CollapsingToolbarLayout collapsingToolbarLayout;
83 | @BindView(R.id.toolbar)
84 | Toolbar toolbar;
85 | @BindView(R.id.trailer_label_tv)
86 | TextView mTrailersLabel0;
87 | @BindView(R.id.trailers_hint_tv)
88 | TextView mTrailersLabel1;
89 | @BindView(R.id.reviews_label_tv)
90 | TextView mReviewsLabel0;
91 | @BindView(R.id.rating_value_tv)
92 | TextView mRatingTextView;
93 | @BindView(R.id.date_value_tv)
94 | TextView mDateTextView;
95 | @BindView(R.id.title_tv)
96 | TextView mTitleTextView;
97 | @BindView(R.id.plot_tv)
98 | TextView mPlotTextView;
99 | @BindView(R.id.poster_image_view)
100 | ImageView mPosterImageView;
101 | @BindView(R.id.rv_trailers)
102 | MovieRecyclerView mTrailerRecyclerView;
103 | @BindView(R.id.rv_reviews)
104 | MovieRecyclerView mReviewRecyclerView;
105 | @BindView(R.id.fav_button)
106 | FloatingActionButton mFavoriteButton;
107 | @BindView(R.id.backdrop_iv)
108 | ImageView mBackdropImageView;
109 | @BindView(R.id.director_value_tv)
110 | TextView mDirectorTextView;
111 | @BindView(R.id.cast_rv)
112 | RecyclerView mCastRecyclerView;
113 | @BindView(R.id.tagline_tv)
114 | TextView mTaglineTextView;
115 | @BindView(R.id.votes_value_tv)
116 | TextView mVotesTextView;
117 | @BindView(R.id.minutes_value_tv)
118 | TextView mMinutesTextView;
119 | @BindView(R.id.imdb_value_tv)
120 | ImageButton mImdbButton;
121 | @BindView(R.id.genres_rv)
122 | RecyclerView mGenresRecyclerView;
123 | @BindView(R.id.similar_movies_rv)
124 | RecyclerView mSimilarMoviesRecyclerView;
125 | private TrailerRecyclerViewAdapter mTrailerAdapter;
126 | private ReviewRecyclerViewAdapter mReviewAdapter;
127 | private GenresRecyclerViewAdapter mGenreAdapter;
128 | private MovieRecyclerViewAdapter mSimilarMoviesAdapter;
129 | private Context mContext;
130 | private ArrayList mTrailerTitles = new ArrayList<>();
131 | private ArrayList mTrailerPaths = new ArrayList<>();
132 | private ArrayList mReviewAuthors = new ArrayList<>();
133 | private ArrayList mReviewContents = new ArrayList<>();
134 | private ArrayList mGenres = new ArrayList<>();
135 | private ArrayList mSimilarMovies = new ArrayList<>();
136 | private byte[] imageBytes;
137 | private RealmDataSource dataSource;
138 |
139 | @Override
140 | protected void onCreate(Bundle savedInstanceState) {
141 | super.onCreate(savedInstanceState);
142 | setContentView(R.layout.activity_details);
143 | ButterKnife.bind(this);
144 | getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimary));
145 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
146 | getWindow().setNavigationBarColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
147 | }
148 | mContext = getApplicationContext();
149 | if (Build.VERSION.SDK_INT >= 21) {
150 | Slide slide = new Slide(Gravity.BOTTOM);
151 | getWindow().setEnterTransition(slide);
152 | postponeEnterTransition();
153 | }
154 | setSupportActionBar(toolbar);
155 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
156 | mMovie = getIntent().getParcelableExtra("movie");
157 | collapsingToolbarLayout.setTitle(mMovie.getTitle());
158 | collapsingToolbarLayout.setExpandedTitleColor(getResources().getColor(android.R.color.transparent));
159 | collapsingToolbarLayout.setCollapsedTitleTextColor(getResources().getColor(android.R.color.white));
160 | appBarLayout.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
161 | if (Math.abs(verticalOffset) - appBarLayout.getTotalScrollRange() == 0)
162 | mPosterImageView.setVisibility(View.GONE);
163 | else
164 | mPosterImageView.setVisibility(View.VISIBLE);
165 | });
166 |
167 | dataSource = new RealmDataSource();
168 | dataSource.open();
169 |
170 | mRatingTextView.setText(mMovie.getRating());
171 | if (mMovie.getDate() != null && !mMovie.getDate().equals(""))
172 | mDateTextView.setText(prettifyDate(mMovie.getDate()));
173 | mTitleTextView.setText(mMovie.getTitle());
174 | mPlotTextView.setText(mMovie.getPlot());
175 | favButtonInit(mMovie.getId());
176 | GlideApp.with(getApplicationContext())
177 | .load(RetrofitAPI.BACKDROP_BASE_URL + mMovie.getBackdropPath())
178 | .centerCrop()
179 | .placeholder(R.drawable.tmdb_placeholder_land)
180 | .error(R.drawable.tmdb_placeholder_land)
181 | .fallback(R.drawable.tmdb_placeholder_land)
182 | .transition(new DrawableTransitionOptions().crossFade())
183 | .into(mBackdropImageView);
184 | if (mMovie.getPosterBytes() != null) {
185 | GlideApp.with(getApplicationContext())
186 | .load(mMovie.getPosterBytes())
187 | .centerCrop()
188 | .error(R.drawable.tmdb_placeholder)
189 | .fallback(R.drawable.tmdb_placeholder)
190 | .transition(new DrawableTransitionOptions().crossFade())
191 | .into(mPosterImageView);
192 | } else {
193 | GlideApp.with(mContext)
194 | .load(RetrofitAPI.POSTER_BASE_URL + mMovie.getPosterPath())
195 | .error(R.drawable.tmdb_placeholder)
196 | .fallback(R.drawable.tmdb_placeholder)
197 | .centerCrop()
198 | .transition(new DrawableTransitionOptions().crossFade())
199 | .into(mPosterImageView);
200 | }
201 |
202 | if (!NetworkUtils.hasNetwork(mContext)) {
203 | (findViewById(R.id.tagline_tv)).setVisibility(View.GONE);
204 | (findViewById(R.id.similar_label_tv)).setVisibility(View.GONE);
205 | (findViewById(R.id.cast_label_tv)).setVisibility(View.GONE);
206 | (findViewById(R.id.votes_label_tv)).setVisibility(View.GONE);
207 | (findViewById(R.id.votes_value_tv)).setVisibility(View.GONE);
208 | (findViewById(R.id.minutes_label_tv)).setVisibility(View.GONE);
209 | (findViewById(R.id.minutes_value_tv)).setVisibility(View.GONE);
210 | (findViewById(R.id.imdb_label_tv)).setVisibility(View.GONE);
211 | (findViewById(R.id.imdb_value_tv)).setVisibility(View.GONE);
212 | (findViewById(R.id.director_label_tv)).setVisibility(View.GONE);
213 | (findViewById(R.id.director_value_tv)).setVisibility(View.GONE);
214 | (findViewById(R.id.genres_label_tv)).setVisibility(View.GONE);
215 | (findViewById(R.id.trailers_hint_tv)).setVisibility(View.GONE);
216 | (findViewById(R.id.trailer_label_tv)).setVisibility(View.GONE);
217 | (findViewById(R.id.reviews_label_tv)).setVisibility(View.GONE);
218 | } else {
219 | fetchCredits();
220 | fetchMoreDetails();
221 |
222 | mTrailerRecyclerView.setLayoutManager(new LinearLayoutManager(DetailsActivity.this, RecyclerView.HORIZONTAL, false));
223 | mTrailerAdapter = new TrailerRecyclerViewAdapter(mContext, mTrailerTitles, mTrailerPaths, this);
224 | mTrailerRecyclerView.setAdapter(new ScaleInAnimationAdapter(mTrailerAdapter));
225 |
226 | mReviewRecyclerView.setLayoutManager(new LinearLayoutManager(DetailsActivity.this, RecyclerView.VERTICAL, false));
227 | mReviewAdapter = new ReviewRecyclerViewAdapter(mContext, mReviewAuthors, mReviewContents);
228 | mReviewRecyclerView.setAdapter(mReviewAdapter);
229 |
230 | mGenresRecyclerView.setLayoutManager(new LinearLayoutManager(DetailsActivity.this, RecyclerView.HORIZONTAL, false));
231 | mGenreAdapter = new GenresRecyclerViewAdapter(mContext, mGenres);
232 | mGenresRecyclerView.setAdapter(new ScaleInAnimationAdapter(mGenreAdapter));
233 |
234 | mSimilarMoviesRecyclerView.setLayoutManager(new LinearLayoutManager(DetailsActivity.this, RecyclerView.HORIZONTAL, false));
235 | mSimilarMoviesAdapter = new MovieRecyclerViewAdapter(mContext, mSimilarMovies, (position, posterImageView) -> CookieBar.build(DetailsActivity.this)
236 | .setBackgroundColor(android.R.color.holo_green_dark)
237 | .setTitle(mSimilarMovies.get(position).getTitle())
238 | .setMessage("Rating: " + mSimilarMovies.get(position).getRating() + " \nRelease: " + mSimilarMovies.get(position).getDate())
239 | .show());
240 | mSimilarMoviesRecyclerView.setAdapter(new ScaleInAnimationAdapter(mSimilarMoviesAdapter));
241 |
242 | fetchDetails(mMovie.getId(), TRAILERS_DETAILS_TYPE);
243 | fetchDetails(mMovie.getId(), REVIEWS_DETAILS_TYPE);
244 | fetchSimilarMovies(mMovie.getId());
245 | }
246 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
247 | startPostponedEnterTransition();
248 | }
249 | }
250 |
251 | private void fetchSimilarMovies(int id) {
252 | RetrofitAPI retrofitAPI = NetworkUtils.getCacheEnabledRetrofit(getApplicationContext()).create(RetrofitAPI.class);
253 | Call similarMoviesCall = retrofitAPI.getSimilarMovies(id, BuildConfig.TMDB_API_TOKEN, "en-US");
254 | similarMoviesCall.enqueue(new Callback() {
255 | @Override
256 | public void onResponse(Call call, Response response) {
257 | if (response.body() != null && response.body().getResults() != null && response.body().getResults().size() != 0) {
258 | mSimilarMovies.addAll(response.body().getResults());
259 | mSimilarMoviesAdapter.notifyDataSetChanged();
260 | } else {
261 | (findViewById(R.id.similar_label_tv)).setVisibility(View.GONE);
262 | mSimilarMoviesRecyclerView.setVisibility(View.GONE);
263 | }
264 | }
265 |
266 | @Override
267 | public void onFailure(Call call, Throwable t) {
268 | // Do I really have to do this?
269 | }
270 | });
271 | }
272 |
273 | private void fetchDetails(int movieId, int detailsType) {
274 | RetrofitAPI retrofitAPI = NetworkUtils.getCacheEnabledRetrofit(getApplicationContext()).create(RetrofitAPI.class);
275 | switch (detailsType) {
276 | case TRAILERS_DETAILS_TYPE:
277 | mTrailerRecyclerView.setVisibility(View.GONE);
278 | mTrailersLabel0.setVisibility(View.GONE);
279 | mTrailersLabel1.setVisibility(View.GONE);
280 | Call trailerResponseCall = retrofitAPI.getTrailers(movieId, BuildConfig.TMDB_API_TOKEN, "en-US");
281 | trailerResponseCall.enqueue(new Callback() {
282 | @Override
283 | public void onResponse(Call call, Response response) {
284 | TMDBTrailerResponse tmdbTrailerResponse = response.body();
285 | if (tmdbTrailerResponse != null && tmdbTrailerResponse.getResults().size() != 0) {
286 | mTrailerTitles.clear();
287 | mTrailerPaths.clear();
288 | for (Trailer trailer : tmdbTrailerResponse.getResults()) {
289 | mTrailerTitles.add(trailer.getName());
290 | mTrailerPaths.add(trailer.getKey());
291 | }
292 | mTrailerAdapter.notifyDataSetChanged();
293 | mTrailerRecyclerView.setVisibility(View.VISIBLE);
294 | mTrailersLabel0.setVisibility(View.VISIBLE);
295 | mTrailersLabel1.setVisibility(View.VISIBLE);
296 | }
297 | }
298 |
299 | @Override
300 | public void onFailure(Call call, Throwable t) {
301 |
302 | }
303 | });
304 | break;
305 | case REVIEWS_DETAILS_TYPE:
306 | mReviewsLabel0.setVisibility(View.GONE);
307 | mReviewRecyclerView.setVisibility(View.GONE);
308 | Call reviewResponseCall = retrofitAPI.getReviews(movieId, BuildConfig.TMDB_API_TOKEN, "en-US");
309 | reviewResponseCall.enqueue(new Callback() {
310 | @Override
311 | public void onResponse(Call call, Response response) {
312 | TMDBReviewResponse tmdbReviewResponse = response.body();
313 | if (tmdbReviewResponse != null && tmdbReviewResponse.getResults().size() != 0) {
314 | mReviewAuthors.clear();
315 | mReviewContents.clear();
316 | for (Review review : tmdbReviewResponse.getResults()) {
317 | mReviewAuthors.add(review.getAuthor());
318 | mReviewContents.add(review.getContent());
319 | }
320 | mReviewAdapter.notifyDataSetChanged();
321 | mReviewRecyclerView.setVisibility(View.VISIBLE);
322 | mReviewsLabel0.setVisibility(View.VISIBLE);
323 | }
324 | }
325 |
326 | @Override
327 | public void onFailure(Call call, Throwable t) {
328 |
329 | }
330 | });
331 | break;
332 | }
333 | }
334 |
335 | private void fetchCredits() {
336 | LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false);
337 | mCastRecyclerView.setLayoutManager(layoutManager);
338 |
339 | final ArrayList castList = new ArrayList<>();
340 | final CastRecyclerViewAdapter mCastAdapter = new CastRecyclerViewAdapter(this, castList, actorName -> {
341 | try {
342 | Uri uri = Uri.parse("https://www.google.com/search?q=" + actorName + " movies");
343 | Intent actorMoviesIntent = new Intent(Intent.ACTION_VIEW, uri);
344 | startActivity(actorMoviesIntent);
345 | } catch (Exception e) {
346 | // Who doesn't have Google? Or a browser?
347 | e.printStackTrace();
348 | }
349 | });
350 | mCastRecyclerView.setAdapter(new ScaleInAnimationAdapter(mCastAdapter));
351 |
352 | RetrofitAPI retrofitAPI = NetworkUtils.getCacheEnabledRetrofit(getApplicationContext()).create(RetrofitAPI.class);
353 | final Call creditsCall = retrofitAPI.getCredits(mMovie.getId(), BuildConfig.TMDB_API_TOKEN);
354 | creditsCall.enqueue(new Callback() {
355 | @Override
356 | public void onResponse(Call call, Response response) {
357 | TMDBCreditsResponse creditsResponse = response.body();
358 |
359 | // Get cast info
360 | castList.clear();
361 | if (creditsResponse != null && creditsResponse.getCast().size() != 0) {
362 | castList.addAll(creditsResponse.getCast());
363 | mCastAdapter.notifyDataSetChanged();
364 | } else {
365 | (findViewById(R.id.cast_label_tv)).setVisibility(View.GONE);
366 | mCastRecyclerView.setVisibility(View.GONE);
367 | }
368 |
369 | // Get director info
370 | if (creditsResponse != null) {
371 | for (Crew crew : creditsResponse.getCrew()) {
372 | if (crew.getJob().equals("Director")) {
373 | mDirectorTextView.setText(crew.getName());
374 | break;
375 | }
376 | }
377 | }
378 | }
379 |
380 | @Override
381 | public void onFailure(Call call, Throwable t) {
382 | // Why bother doing anything here?
383 | }
384 | });
385 | }
386 |
387 | private void fetchMoreDetails() {
388 | RetrofitAPI retrofitAPI = NetworkUtils.getCacheEnabledRetrofit(getApplicationContext()).create(RetrofitAPI.class);
389 | Call detailsResponseCall = retrofitAPI.getDetails(mMovie.getId(), BuildConfig.TMDB_API_TOKEN, "en-US");
390 | detailsResponseCall.enqueue(new Callback() {
391 | @Override
392 | public void onResponse(Call call, Response response) {
393 | final TMDBDetailsResponse tmdbDetailsResponse = response.body();
394 | String tagline = null;
395 | if (tmdbDetailsResponse != null) {
396 | tagline = tmdbDetailsResponse.getTagline();
397 | }
398 | if (tagline != null && !tagline.equals("")) {
399 | mTaglineTextView.setText(tagline);
400 | } else {
401 | mTaglineTextView.setVisibility(View.GONE);
402 | }
403 | mVotesTextView.setText(String.valueOf(tmdbDetailsResponse.getVoteCount()));
404 | mMinutesTextView.setText(String.valueOf(tmdbDetailsResponse.getRuntime()));
405 | mImdbButton.setOnClickListener(view -> {
406 | String imdbId = tmdbDetailsResponse.getImdbId();
407 | try {
408 | Uri uri;
409 | if (imdbId != null && !imdbId.equals(""))
410 | uri = Uri.parse("http://www.imdb.com/title/" + imdbId + "/");
411 | else {
412 | Toast.makeText(mContext, "Movie isn't there on IMDB. Here is a Google search for it instead!", Toast.LENGTH_LONG).show();
413 | uri = Uri.parse("https://www.google.com/search?q=" + tmdbDetailsResponse.getTitle());
414 | }
415 | Intent imdbIntent = new Intent(Intent.ACTION_VIEW, uri);
416 | startActivity(imdbIntent);
417 | } catch (Exception e) {
418 | e.printStackTrace();
419 | }
420 | });
421 | if (tmdbDetailsResponse.getGenres() != null && tmdbDetailsResponse.getGenres().size() != 0) {
422 | mGenres.clear();
423 | mGenres.addAll(tmdbDetailsResponse.getGenres());
424 | mGenreAdapter.notifyDataSetChanged();
425 | } else {
426 | (findViewById(R.id.genres_label_tv)).setVisibility(View.GONE);
427 | mGenresRecyclerView.setVisibility(View.GONE);
428 | }
429 | }
430 |
431 | @Override
432 | public void onFailure(Call call, Throwable t) {
433 | // Why bother doing anything here
434 | }
435 | });
436 | }
437 |
438 | @Override
439 | public void onItemClick(String stringUrlTrailerClicked) {
440 | Uri youtubeUri = Uri.parse("https://www.youtube.com/watch?v=" + stringUrlTrailerClicked);
441 | Intent openYoutube = new Intent(Intent.ACTION_VIEW, youtubeUri);
442 | startActivity(openYoutube);
443 | }
444 |
445 | private String prettifyDate(String jsonDate) {
446 | DateFormat sourceDateFormat = new SimpleDateFormat("yyyy-MM-dd");
447 | Date date = null;
448 | try {
449 | date = sourceDateFormat.parse(jsonDate);
450 | } catch (ParseException e) {
451 | e.printStackTrace();
452 | }
453 | DateFormat destDateFormat = new SimpleDateFormat("MMM dd\nyyyy");
454 | String dateStr = destDateFormat.format(date);
455 | return dateStr;
456 | }
457 |
458 | private void favButtonInit(final int id) {
459 | Movie checkedMovie = dataSource.findMovieWithId(id);
460 | if (checkedMovie == null)
461 | mFavoriteButton.setImageResource(R.drawable.ic_favorite_border);
462 | else
463 | mFavoriteButton.setImageResource(R.drawable.ic_favorite);
464 | mFavoriteButton.setOnClickListener(view -> {
465 | Movie transactedMovie = dataSource.findMovieWithId(id);
466 | if (transactedMovie == null) {
467 | tempMovie = mMovie;
468 | GlideApp.with(mContext)
469 | .load(tempMovie.getPosterPath())
470 | .centerCrop()
471 | .into(new Target() {
472 | @Override
473 | public void onLoadStarted(@Nullable Drawable placeholder) {
474 |
475 | }
476 |
477 | @Override
478 | public void onLoadFailed(@Nullable Drawable errorDrawable) {
479 |
480 | }
481 |
482 | @Override
483 | public void onResourceReady(Drawable resource, Transition super Drawable> transition) {
484 | Bitmap bitmap = ((BitmapDrawable) resource).getBitmap();
485 | ByteArrayOutputStream stream = new ByteArrayOutputStream();
486 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
487 | imageBytes = stream.toByteArray();
488 | }
489 |
490 | @Override
491 | public void onLoadCleared(@Nullable Drawable placeholder) {
492 |
493 | }
494 |
495 | @Override
496 | public void getSize(SizeReadyCallback cb) {
497 |
498 | }
499 |
500 | @Override
501 | public void removeCallback(SizeReadyCallback cb) {
502 |
503 | }
504 |
505 | @Nullable
506 | @Override
507 | public Request getRequest() {
508 | return null;
509 | }
510 |
511 | @Override
512 | public void setRequest(@Nullable Request request) {
513 |
514 | }
515 |
516 | @Override
517 | public void onStart() {
518 |
519 | }
520 |
521 | @Override
522 | public void onStop() {
523 |
524 | }
525 |
526 | @Override
527 | public void onDestroy() {
528 |
529 | }
530 | });
531 | tempMovie.setPosterBytes(imageBytes);
532 | dataSource.addMovieToFavs(tempMovie);
533 | mFavoriteButton.setImageResource(R.drawable.ic_favorite);
534 | CookieBar.build(DetailsActivity.this)
535 | .setBackgroundColor(android.R.color.holo_blue_dark)
536 | .setTitle("Movie added to favorites!")
537 | .setMessage("You can now see the details, even when offline, in your Favorites.")
538 | .show();
539 | } else {
540 | CookieBar.build(DetailsActivity.this)
541 | .setBackgroundColor(android.R.color.holo_red_dark)
542 | .setTitle("Movie removed from favorites!")
543 | .setMessage("But did you really have to? :-(")
544 | .show();
545 | dataSource.deleteMovieFromFavs(transactedMovie);
546 | mFavoriteButton.setImageResource(R.drawable.ic_favorite_border);
547 | }
548 | });
549 | }
550 |
551 | @Override
552 | public boolean onOptionsItemSelected(MenuItem item) {
553 | switch (item.getItemId()) {
554 | case android.R.id.home:
555 | NavUtils.navigateUpFromSameTask(this);
556 | return true;
557 | }
558 | return super.onOptionsItemSelected(item);
559 | }
560 |
561 | @Override
562 | protected void onDestroy() {
563 | super.onDestroy();
564 | dataSource.close();
565 | }
566 |
567 | }
568 |
--------------------------------------------------------------------------------