From 1b8f906324b2154a31b7a4c0ef1ef7e17db6207a Mon Sep 17 00:00:00 2001 From: Michael Bel Date: Tue, 26 Dec 2017 19:29:24 +0300 Subject: [PATCH] initial commit --- .gitignore | 9 + .idea/compiler.xml | 21 + .idea/copyright/profiles_settings.xml | 3 + .idea/dictionaries/Michael.xml | 14 + .idea/dictionaries/User.xml | 3 + .idea/encodings.xml | 6 + .idea/gradle.xml | 18 + .idea/misc.xml | 100 ++ .idea/modules.xml | 9 + .idea/runConfigurations.xml | 12 + app/.gitignore | 1 + app/build.gradle | 51 + app/google-services.json | 42 + app/proguard-rules.pro | 17 + app/src/main/AndroidManifest.xml | 82 ++ app/src/main/assets/config.properties | 2 + .../application/moviemade/ApiFactory.java | 27 + .../moviemade/AppBarStateChangeListener.java | 83 ++ .../application/moviemade/AppLoader.java | 20 + .../application/moviemade/LayoutHelper.java | 155 +++ .../application/moviemade/Theme.java | 454 +++++++++ .../michaelbel/application/moviemade/Url.java | 27 + .../moviemade/annotation/Beta.java | 20 + .../moviemade/browser/Browser.java | 59 ++ .../moviemade/eventbus/Events.java | 14 + .../application/moviemade/eventbus/RxBus.java | 33 + .../application/rest/api/ACCOUNT.java | 105 ++ .../application/rest/api/AUTHENTICATION.java | 35 + .../application/rest/api/CERTIFICATIONS.java | 9 + .../application/rest/api/CHANGES.java | 11 + .../application/rest/api/COLLECTIONS.java | 9 + .../application/rest/api/COMPANIES.java | 9 + .../application/rest/api/CONFIGURATIONS.java | 7 + .../application/rest/api/CREDITS.java | 7 + .../application/rest/api/DISCOVER.java | 9 + .../michaelbel/application/rest/api/FIND.java | 7 + .../application/rest/api/GENRES.java | 28 + .../application/rest/api/GUESTSESSIONS.java | 11 + .../michaelbel/application/rest/api/JOBS.java | 7 + .../application/rest/api/KEYWORDS.java | 9 + .../application/rest/api/LISTS.java | 19 + .../application/rest/api/MOVIES.java | 157 +++ .../application/rest/api/NETWORKS.java | 7 + .../application/rest/api/PEOPLE.java | 83 ++ .../application/rest/api/REVIEWS.java | 18 + .../application/rest/api/SEARCH.java | 32 + .../application/rest/api/TIMEZONES.java | 7 + .../michaelbel/application/rest/api/TV.java | 47 + .../application/rest/api/TVEPISODES.java | 23 + .../application/rest/api/TVSEASONS.java | 19 + .../application/rest/model/Account.java | 37 + .../application/rest/model/Auth.java | 49 + .../application/rest/model/Backdrop.java | 28 + .../application/rest/model/Cast.java | 28 + .../application/rest/model/Crew.java | 25 + .../application/rest/model/Genre.java | 13 + .../application/rest/model/Movie.java | 129 +++ .../application/rest/model/Person.java | 48 + .../application/rest/model/Poster.java | 28 + .../application/rest/model/Review.java | 31 + .../application/rest/model/Trailer.java | 31 + .../rest/response/CreditResponse.java | 21 + .../rest/response/ImageResponse.java | 21 + .../rest/response/MovieResponse.java | 35 + .../rest/response/ReviewResponse.java | 26 + .../rest/response/VideoResponse.java | 17 + .../application/sqlite/DatabaseHelper.java | 178 ++++ .../application/ui/AboutActivity.java | 51 + .../application/ui/FavsActivity.java | 66 ++ .../application/ui/MainActivity.java | 292 ++++++ .../application/ui/MovieActivity.java | 129 +++ .../application/ui/PersonActivity.java | 74 ++ .../application/ui/ReviewActivity.java | 40 + .../application/ui/SearchActivity.java | 67 ++ .../application/ui/SettingsActivity.java | 51 + .../application/ui/TrailersActivity.java | 40 + .../application/ui/adapter/Holder.java | 12 + .../ui/adapter/MoviesListAdapter.java | 88 ++ .../ui/fragment/AboutFragment.java | 246 +++++ .../ui/fragment/CastMovieFragment.java | 144 +++ .../ui/fragment/FavoriteMoviesFragment.java | 247 +++++ .../ui/fragment/ImageQualityFragment.java | 263 +++++ .../application/ui/fragment/LibsFragment.java | 146 +++ .../ui/fragment/MovieFragment.java | 276 ++++++ .../ui/fragment/NowPlayingFragment.java | 205 ++++ .../ui/fragment/PersonFragment.java | 185 ++++ .../ui/fragment/PopularFragment.java | 191 ++++ .../ui/fragment/RelatedMovieFragment.java | 216 +++++ .../ui/fragment/ReviewDetailsFragment.java | 166 ++++ .../ui/fragment/ReviewsMovieFragment.java | 174 ++++ .../ui/fragment/SearchFragment.java | 200 ++++ .../ui/fragment/SettingsFragment.java | 239 +++++ .../ui/fragment/SimilarMoviesFragment.java | 216 +++++ .../ui/fragment/TopRatedFragment.java | 188 ++++ .../ui/fragment/TrailersFragment.java | 196 ++++ .../ui/fragment/UpcomingFragment.java | 190 ++++ .../application/ui/view/CardButton.java | 89 ++ .../application/ui/view/CastView.java | 141 +++ .../application/ui/view/EmptyView.java | 58 ++ .../application/ui/view/FavButton.java | 86 ++ .../ui/view/ImagesSectionView.java | 132 +++ .../application/ui/view/LoadingView.java | 24 + .../application/ui/view/MovieInfoLayout.java | 912 ++++++++++++++++++ .../application/ui/view/MoviePageView.java | 97 ++ .../application/ui/view/MovieViewCompat.java | 159 +++ .../application/ui/view/MovieViewList2.java | 144 +++ .../application/ui/view/NavigationView.java | 442 +++++++++ .../application/ui/view/RatingView.java | 188 ++++ .../application/ui/view/ReviewView.java | 131 +++ .../application/ui/view/TitleView.java | 68 ++ .../ui/view/TrailersSectionView.java | 90 ++ .../application/ui/view/cell/DateCell.java | 50 + .../application/ui/view/cell/EmptyCell.java | 114 +++ .../application/ui/view/cell/TextCell.java | 217 +++++ .../ui/view/cell/TextDetailCell.java | 244 +++++ .../ui/view/movie/MovieViewCard.java | 135 +++ .../ui/view/movie/MovieViewList.java | 171 ++++ .../ui/view/movie/MovieViewPoster.java | 69 ++ .../ui/view/trailer/TrailerCompatView.java | 164 ++++ .../ui/view/trailer/TrailerView.java | 150 +++ .../ui/view/widget/AppBarLayoutBehavior.java | 30 + .../ui/view/widget/ColorPicker.java | 413 ++++++++ .../ui/view/widget/FragmentsPagerAdapter.java | 48 + .../ui/view/widget/GestureTextView.java | 101 ++ .../ui/view/widget/IndicatorView.java | 277 ++++++ .../ui/view/widget/MaskImageView.java | 166 ++++ .../ui/view/widget/PaddingItemDecoration.java | 28 + .../ui/view/widget/RecyclerListView.java | 412 ++++++++ .../ui/view/widget/SectionListView.java | 455 +++++++++ .../ui/view/widget/SnackbarBehavior.java | 15 + .../ui/view/widget/ViewPagerAdapter.java | 60 ++ .../michaelbel/application/util/AppUtils.java | 100 ++ .../application/util/DateUtils.java | 49 + .../application/util/DeviceUtils.java | 74 ++ .../application/util/FileUtils.java | 55 ++ .../application/util/KeyboardUtils.java | 47 + .../application/util/NetworkUtils.java | 34 + .../application/util/ScreenUtils.java | 77 ++ .../application/util/SizeUtils.java | 29 + .../main/res/animator/scale_with_alpha.xml | 14 + app/src/main/res/drawable-hdpi/book_user.png | Bin 0 -> 3161 bytes .../main/res/drawable-hdpi/ic_button_play.png | Bin 0 -> 1742 bytes .../main/res/drawable-hdpi/logo_avatar.png | Bin 0 -> 1642 bytes .../res/drawable-hdpi/review_placeholder.png | Bin 0 -> 7870 bytes .../search_history_placeholder.png | Bin 0 -> 9969 bytes .../main/res/drawable-hdpi/thumb_color.9.png | Bin 0 -> 17243 bytes app/src/main/res/drawable-mdpi/book_user.png | Bin 0 -> 2303 bytes .../main/res/drawable-mdpi/ic_button_play.png | Bin 0 -> 927 bytes .../main/res/drawable-mdpi/logo_avatar.png | Bin 0 -> 1115 bytes .../res/drawable-mdpi/review_placeholder.png | Bin 0 -> 5995 bytes .../search_history_placeholder.png | Bin 0 -> 7413 bytes .../main/res/drawable-mdpi/thumb_color.9.png | Bin 0 -> 789 bytes app/src/main/res/drawable-xhdpi/book_user.png | Bin 0 -> 3972 bytes .../res/drawable-xhdpi/ic_button_play.png | Bin 0 -> 1863 bytes .../main/res/drawable-xhdpi/logo_avatar.png | Bin 0 -> 2195 bytes .../res/drawable-xhdpi/review_placeholder.png | Bin 0 -> 10533 bytes .../search_history_placeholder.png | Bin 0 -> 13337 bytes .../main/res/drawable-xhdpi/thumb_color.9.png | Bin 0 -> 18134 bytes .../main/res/drawable-xxhdpi/book_user.png | Bin 0 -> 5470 bytes .../res/drawable-xxhdpi/ic_button_play.png | Bin 0 -> 3624 bytes .../main/res/drawable-xxhdpi/logo_avatar.png | Bin 0 -> 3327 bytes .../res/drawable-xxhdpi/rect_quality_mini.xml | 14 + .../drawable-xxhdpi/review_placeholder.png | Bin 0 -> 15231 bytes .../search_history_placeholder.png | Bin 0 -> 19815 bytes .../res/drawable-xxhdpi/thumb_color.9.png | Bin 0 -> 19985 bytes .../res/drawable-xxxhdpi/drawer_header.jpg | Bin 0 -> 25436 bytes .../drawable-xxxhdpi/movie_placeholder.jpg | Bin 0 -> 20897 bytes .../main/res/drawable-xxxhdpi/tmdb_icon.png | Bin 0 -> 4032 bytes app/src/main/res/drawable/dot_oval.xml | 7 + .../res/drawable/filter_empty_divider.xml | 3 + app/src/main/res/drawable/ic_about.xml | 9 + app/src/main/res/drawable/ic_account.xml | 9 + .../main/res/drawable/ic_account_multiple.xml | 9 + app/src/main/res/drawable/ic_arrow_back.xml | 9 + .../main/res/drawable/ic_bookmark_check.xml | 9 + .../main/res/drawable/ic_bookmark_plus.xml | 9 + .../res/drawable/ic_bookmark_plus_outline.xml | 9 + .../main/res/drawable/ic_bookmark_remove.xml | 9 + app/src/main/res/drawable/ic_calendar.xml | 9 + .../main/res/drawable/ic_calendar_clock.xml | 9 + .../main/res/drawable/ic_chevron_right.xml | 9 + app/src/main/res/drawable/ic_clear.xml | 9 + app/src/main/res/drawable/ic_clock.xml | 9 + app/src/main/res/drawable/ic_delete.xml | 9 + app/src/main/res/drawable/ic_delete_sweep.xml | 9 + app/src/main/res/drawable/ic_dots_menu.xml | 9 + app/src/main/res/drawable/ic_earth.xml | 10 + app/src/main/res/drawable/ic_favorite.xml | 9 + app/src/main/res/drawable/ic_heart.xml | 9 + .../main/res/drawable/ic_heart_outline.xml | 9 + app/src/main/res/drawable/ic_history.xml | 9 + app/src/main/res/drawable/ic_home.xml | 9 + app/src/main/res/drawable/ic_menu.xml | 9 + app/src/main/res/drawable/ic_movie.xml | 9 + app/src/main/res/drawable/ic_movie_cadr.xml | 9 + app/src/main/res/drawable/ic_offline.xml | 9 + app/src/main/res/drawable/ic_photos.xml | 9 + app/src/main/res/drawable/ic_play.xml | 9 + app/src/main/res/drawable/ic_release_date.xml | 9 + app/src/main/res/drawable/ic_reviews.xml | 9 + app/src/main/res/drawable/ic_schedule.xml | 9 + app/src/main/res/drawable/ic_search.xml | 9 + app/src/main/res/drawable/ic_search_error.xml | 9 + app/src/main/res/drawable/ic_series.xml | 9 + app/src/main/res/drawable/ic_settings.xml | 9 + app/src/main/res/drawable/ic_share.xml | 9 + app/src/main/res/drawable/ic_star.xml | 9 + app/src/main/res/drawable/ic_star_border.xml | 9 + app/src/main/res/drawable/ic_star_circle.xml | 9 + app/src/main/res/drawable/ic_star_half.xml | 9 + app/src/main/res/drawable/ic_tune.xml | 9 + app/src/main/res/drawable/ic_url.xml | 9 + app/src/main/res/drawable/ic_videos.xml | 9 + app/src/main/res/drawable/ic_view_compat.xml | 9 + app/src/main/res/drawable/ic_view_default.xml | 9 + app/src/main/res/drawable/ic_view_list.xml | 9 + app/src/main/res/drawable/ic_voice.xml | 9 + app/src/main/res/drawable/ic_watch.xml | 9 + app/src/main/res/drawable/ic_whatshot.xml | 9 + app/src/main/res/drawable/ic_youtube.xml | 9 + app/src/main/res/drawable/image_circle.xml | 5 + app/src/main/res/drawable/image_rect.xml | 6 + app/src/main/res/drawable/rect_quality.xml | 14 + app/src/main/res/drawable/white_radius.xml | 3 + app/src/main/res/layout/activity_favs.xml | 45 + app/src/main/res/layout/activity_main.xml | 66 ++ app/src/main/res/layout/activity_movie.xml | 63 ++ app/src/main/res/layout/activity_person.xml | 44 + app/src/main/res/layout/activity_review.xml | 39 + app/src/main/res/layout/activity_search.xml | 44 + app/src/main/res/layout/activity_settings.xml | 40 + app/src/main/res/layout/activity_trailers.xml | 35 + app/src/main/res/layout/fragment_about.xml | 11 + app/src/main/res/layout/fragment_favs.xml | 26 + app/src/main/res/layout/fragment_movie.xml | 27 + .../main/res/layout/fragment_nowplaying.xml | 29 + app/src/main/res/layout/fragment_person.xml | 44 + app/src/main/res/layout/fragment_review.xml | 28 + .../res/layout/fragment_review_details.xml | 53 + app/src/main/res/layout/fragment_search.xml | 27 + app/src/main/res/layout/fragment_videos.xml | 29 + app/src/main/res/menu/search_item.xml | 10 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes app/src/main/res/values-sw600dp/bools.xml | 3 + app/src/main/res/values-sw720dp/bools.xml | 3 + app/src/main/res/values/attrs.xml | 32 + app/src/main/res/values/bools.xml | 3 + app/src/main/res/values/colors.xml | 64 ++ .../res/values/material-design-colors.xml | 339 +++++++ app/src/main/res/values/strings.xml | 168 ++++ app/src/main/res/values/styles.xml | 46 + build.gradle | 21 + desktop.ini | 2 + gradle.properties | 17 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53636 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 160 +++ gradlew.bat | 90 ++ settings.gradle | 1 + 268 files changed, 15977 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/dictionaries/Michael.xml create mode 100644 .idea/dictionaries/User.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/google-services.json create mode 100644 app/proguard-rules.pro create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/assets/config.properties create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/ApiFactory.java create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/AppBarStateChangeListener.java create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/AppLoader.java create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/LayoutHelper.java create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/Theme.java create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/Url.java create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/annotation/Beta.java create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/browser/Browser.java create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/eventbus/Events.java create mode 100644 app/src/main/java/org/michaelbel/application/moviemade/eventbus/RxBus.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/ACCOUNT.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/AUTHENTICATION.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/CERTIFICATIONS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/CHANGES.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/COLLECTIONS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/COMPANIES.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/CONFIGURATIONS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/CREDITS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/DISCOVER.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/FIND.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/GENRES.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/GUESTSESSIONS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/JOBS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/KEYWORDS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/LISTS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/MOVIES.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/NETWORKS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/PEOPLE.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/REVIEWS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/SEARCH.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/TIMEZONES.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/TV.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/TVEPISODES.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/api/TVSEASONS.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Account.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Auth.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Backdrop.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Cast.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Crew.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Genre.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Movie.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Person.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Poster.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Review.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/model/Trailer.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/response/CreditResponse.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/response/ImageResponse.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/response/MovieResponse.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/response/ReviewResponse.java create mode 100644 app/src/main/java/org/michaelbel/application/rest/response/VideoResponse.java create mode 100644 app/src/main/java/org/michaelbel/application/sqlite/DatabaseHelper.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/AboutActivity.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/FavsActivity.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/MainActivity.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/MovieActivity.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/PersonActivity.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/ReviewActivity.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/SearchActivity.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/SettingsActivity.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/TrailersActivity.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/adapter/Holder.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/adapter/MoviesListAdapter.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/AboutFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/CastMovieFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/FavoriteMoviesFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/ImageQualityFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/LibsFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/MovieFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/NowPlayingFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/PersonFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/PopularFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/RelatedMovieFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/ReviewDetailsFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/ReviewsMovieFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/SearchFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/SettingsFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/SimilarMoviesFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/TopRatedFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/TrailersFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/fragment/UpcomingFragment.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/CardButton.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/CastView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/EmptyView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/FavButton.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/ImagesSectionView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/LoadingView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/MovieInfoLayout.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/MoviePageView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/MovieViewCompat.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/MovieViewList2.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/NavigationView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/RatingView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/ReviewView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/TitleView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/TrailersSectionView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/cell/DateCell.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/cell/EmptyCell.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/cell/TextCell.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/cell/TextDetailCell.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewCard.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewList.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewPoster.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/trailer/TrailerCompatView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/trailer/TrailerView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/AppBarLayoutBehavior.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/ColorPicker.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/FragmentsPagerAdapter.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/GestureTextView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/IndicatorView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/MaskImageView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/PaddingItemDecoration.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/RecyclerListView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/SectionListView.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/SnackbarBehavior.java create mode 100644 app/src/main/java/org/michaelbel/application/ui/view/widget/ViewPagerAdapter.java create mode 100644 app/src/main/java/org/michaelbel/application/util/AppUtils.java create mode 100644 app/src/main/java/org/michaelbel/application/util/DateUtils.java create mode 100644 app/src/main/java/org/michaelbel/application/util/DeviceUtils.java create mode 100644 app/src/main/java/org/michaelbel/application/util/FileUtils.java create mode 100644 app/src/main/java/org/michaelbel/application/util/KeyboardUtils.java create mode 100644 app/src/main/java/org/michaelbel/application/util/NetworkUtils.java create mode 100644 app/src/main/java/org/michaelbel/application/util/ScreenUtils.java create mode 100644 app/src/main/java/org/michaelbel/application/util/SizeUtils.java create mode 100644 app/src/main/res/animator/scale_with_alpha.xml create mode 100644 app/src/main/res/drawable-hdpi/book_user.png create mode 100644 app/src/main/res/drawable-hdpi/ic_button_play.png create mode 100644 app/src/main/res/drawable-hdpi/logo_avatar.png create mode 100644 app/src/main/res/drawable-hdpi/review_placeholder.png create mode 100644 app/src/main/res/drawable-hdpi/search_history_placeholder.png create mode 100644 app/src/main/res/drawable-hdpi/thumb_color.9.png create mode 100644 app/src/main/res/drawable-mdpi/book_user.png create mode 100644 app/src/main/res/drawable-mdpi/ic_button_play.png create mode 100644 app/src/main/res/drawable-mdpi/logo_avatar.png create mode 100644 app/src/main/res/drawable-mdpi/review_placeholder.png create mode 100644 app/src/main/res/drawable-mdpi/search_history_placeholder.png create mode 100644 app/src/main/res/drawable-mdpi/thumb_color.9.png create mode 100644 app/src/main/res/drawable-xhdpi/book_user.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_button_play.png create mode 100644 app/src/main/res/drawable-xhdpi/logo_avatar.png create mode 100644 app/src/main/res/drawable-xhdpi/review_placeholder.png create mode 100644 app/src/main/res/drawable-xhdpi/search_history_placeholder.png create mode 100644 app/src/main/res/drawable-xhdpi/thumb_color.9.png create mode 100644 app/src/main/res/drawable-xxhdpi/book_user.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_button_play.png create mode 100644 app/src/main/res/drawable-xxhdpi/logo_avatar.png create mode 100644 app/src/main/res/drawable-xxhdpi/rect_quality_mini.xml create mode 100644 app/src/main/res/drawable-xxhdpi/review_placeholder.png create mode 100644 app/src/main/res/drawable-xxhdpi/search_history_placeholder.png create mode 100644 app/src/main/res/drawable-xxhdpi/thumb_color.9.png create mode 100644 app/src/main/res/drawable-xxxhdpi/drawer_header.jpg create mode 100644 app/src/main/res/drawable-xxxhdpi/movie_placeholder.jpg create mode 100644 app/src/main/res/drawable-xxxhdpi/tmdb_icon.png create mode 100644 app/src/main/res/drawable/dot_oval.xml create mode 100644 app/src/main/res/drawable/filter_empty_divider.xml create mode 100644 app/src/main/res/drawable/ic_about.xml create mode 100644 app/src/main/res/drawable/ic_account.xml create mode 100644 app/src/main/res/drawable/ic_account_multiple.xml create mode 100644 app/src/main/res/drawable/ic_arrow_back.xml create mode 100644 app/src/main/res/drawable/ic_bookmark_check.xml create mode 100644 app/src/main/res/drawable/ic_bookmark_plus.xml create mode 100644 app/src/main/res/drawable/ic_bookmark_plus_outline.xml create mode 100644 app/src/main/res/drawable/ic_bookmark_remove.xml create mode 100644 app/src/main/res/drawable/ic_calendar.xml create mode 100644 app/src/main/res/drawable/ic_calendar_clock.xml create mode 100644 app/src/main/res/drawable/ic_chevron_right.xml create mode 100644 app/src/main/res/drawable/ic_clear.xml create mode 100644 app/src/main/res/drawable/ic_clock.xml create mode 100644 app/src/main/res/drawable/ic_delete.xml create mode 100644 app/src/main/res/drawable/ic_delete_sweep.xml create mode 100644 app/src/main/res/drawable/ic_dots_menu.xml create mode 100644 app/src/main/res/drawable/ic_earth.xml create mode 100644 app/src/main/res/drawable/ic_favorite.xml create mode 100644 app/src/main/res/drawable/ic_heart.xml create mode 100644 app/src/main/res/drawable/ic_heart_outline.xml create mode 100644 app/src/main/res/drawable/ic_history.xml create mode 100644 app/src/main/res/drawable/ic_home.xml create mode 100644 app/src/main/res/drawable/ic_menu.xml create mode 100644 app/src/main/res/drawable/ic_movie.xml create mode 100644 app/src/main/res/drawable/ic_movie_cadr.xml create mode 100644 app/src/main/res/drawable/ic_offline.xml create mode 100644 app/src/main/res/drawable/ic_photos.xml create mode 100644 app/src/main/res/drawable/ic_play.xml create mode 100644 app/src/main/res/drawable/ic_release_date.xml create mode 100644 app/src/main/res/drawable/ic_reviews.xml create mode 100644 app/src/main/res/drawable/ic_schedule.xml create mode 100644 app/src/main/res/drawable/ic_search.xml create mode 100644 app/src/main/res/drawable/ic_search_error.xml create mode 100644 app/src/main/res/drawable/ic_series.xml create mode 100644 app/src/main/res/drawable/ic_settings.xml create mode 100644 app/src/main/res/drawable/ic_share.xml create mode 100644 app/src/main/res/drawable/ic_star.xml create mode 100644 app/src/main/res/drawable/ic_star_border.xml create mode 100644 app/src/main/res/drawable/ic_star_circle.xml create mode 100644 app/src/main/res/drawable/ic_star_half.xml create mode 100644 app/src/main/res/drawable/ic_tune.xml create mode 100644 app/src/main/res/drawable/ic_url.xml create mode 100644 app/src/main/res/drawable/ic_videos.xml create mode 100644 app/src/main/res/drawable/ic_view_compat.xml create mode 100644 app/src/main/res/drawable/ic_view_default.xml create mode 100644 app/src/main/res/drawable/ic_view_list.xml create mode 100644 app/src/main/res/drawable/ic_voice.xml create mode 100644 app/src/main/res/drawable/ic_watch.xml create mode 100644 app/src/main/res/drawable/ic_whatshot.xml create mode 100644 app/src/main/res/drawable/ic_youtube.xml create mode 100644 app/src/main/res/drawable/image_circle.xml create mode 100644 app/src/main/res/drawable/image_rect.xml create mode 100644 app/src/main/res/drawable/rect_quality.xml create mode 100644 app/src/main/res/drawable/white_radius.xml create mode 100644 app/src/main/res/layout/activity_favs.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/activity_movie.xml create mode 100644 app/src/main/res/layout/activity_person.xml create mode 100644 app/src/main/res/layout/activity_review.xml create mode 100644 app/src/main/res/layout/activity_search.xml create mode 100644 app/src/main/res/layout/activity_settings.xml create mode 100644 app/src/main/res/layout/activity_trailers.xml create mode 100644 app/src/main/res/layout/fragment_about.xml create mode 100644 app/src/main/res/layout/fragment_favs.xml create mode 100644 app/src/main/res/layout/fragment_movie.xml create mode 100644 app/src/main/res/layout/fragment_nowplaying.xml create mode 100644 app/src/main/res/layout/fragment_person.xml create mode 100644 app/src/main/res/layout/fragment_review.xml create mode 100644 app/src/main/res/layout/fragment_review_details.xml create mode 100644 app/src/main/res/layout/fragment_search.xml create mode 100644 app/src/main/res/layout/fragment_videos.xml create mode 100644 app/src/main/res/menu/search_item.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values-sw600dp/bools.xml create mode 100644 app/src/main/res/values-sw720dp/bools.xml create mode 100644 app/src/main/res/values/attrs.xml create mode 100644 app/src/main/res/values/bools.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/material-design-colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 build.gradle create mode 100644 desktop.ini create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..39fb081a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..1f2af519b --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 000000000..e7bedf337 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/dictionaries/Michael.xml b/.idea/dictionaries/Michael.xml new file mode 100644 index 000000000..e06a913d3 --- /dev/null +++ b/.idea/dictionaries/Michael.xml @@ -0,0 +1,14 @@ + + + + favs + firebase + gson + halfbit + moviemade + sergej + shafarenka + tagline + + + \ No newline at end of file diff --git a/.idea/dictionaries/User.xml b/.idea/dictionaries/User.xml new file mode 100644 index 000000000..72b3a5828 --- /dev/null +++ b/.idea/dictionaries/User.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 000000000..97626ba45 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 000000000..7ac24c777 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..b67661da3 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Android + + + + + + + + + + + + + + + + + + + + + + 1.8 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..01240c9f7 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 000000000..7f68460d8 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 000000000..9a68ca354 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,51 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 27 + buildToolsVersion '26.0.3' + + defaultConfig { + applicationId "org.michaelbel.application" + minSdkVersion 21 + targetSdkVersion 27 + versionCode 1 + versionName "1.0.0" + } + + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + dataBinding { + enabled true + } +} + +dependencies { + implementation 'com.android.support:appcompat-v7:27.0.2' + implementation 'com.android.support:cardview-v7:27.0.2' + implementation 'com.android.support:design:27.0.2' + implementation 'com.android.support:customtabs:27.0.2' + + implementation 'io.reactivex.rxjava2:rxjava:2.1.7' + implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' + + implementation 'com.squareup.retrofit2:retrofit:2.3.0' + implementation 'com.squareup.retrofit2:adapter-rxjava:2.3.0' + implementation 'com.squareup.retrofit2:converter-gson:2.3.0' + + implementation 'org.michaelbel:bottomsheet:1.1.0' + implementation 'com.github.bumptech.glide:glide:4.4.0' + + implementation 'com.alexvasilkov:gesture-views:2.4.0' + implementation 'com.alexvasilkov:android-commons:2.0.2' + implementation 'com.alexvasilkov:events:1.0.0' +} \ No newline at end of file diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 000000000..31e880505 --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,42 @@ +{ + "project_info": { + "project_number": "769096314290", + "firebase_url": "https://movieapp-274c7.firebaseio.com", + "project_id": "movieapp-274c7", + "storage_bucket": "movieapp-274c7.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:769096314290:android:2ba2493b09f433bc", + "android_client_info": { + "package_name": "org.michaelbel.application" + } + }, + "oauth_client": [ + { + "client_id": "769096314290-6c20urdtpjplmmp0c3cfo6ma3o6h0gc6.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyB2K-fBT-bUVNgMKL_F51U9HMIXEB7QaIY" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 000000000..70481a7a5 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Soft\Android_SDK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..bfc4ff155 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/config.properties b/app/src/main/assets/config.properties new file mode 100644 index 000000000..ce6046e40 --- /dev/null +++ b/app/src/main/assets/config.properties @@ -0,0 +1,2 @@ +TMDbApiKey=9488634afe35eb3d4d80080bea06b8e3 +TMDbApiToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI5NDg4NjM0YWZlMzVlYjNkNGQ4MDA4MGJlYTA2YjhlMyIsInN1YiI6IjU3ZmI5NDVkYzNhMzY4M2FjOTAwOGJkMCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.gRqFsXTGPBCGOkPICIN9-Ua6O5f9q8tXyXciSSDKeu0 diff --git a/app/src/main/java/org/michaelbel/application/moviemade/ApiFactory.java b/app/src/main/java/org/michaelbel/application/moviemade/ApiFactory.java new file mode 100644 index 000000000..3a4de72b0 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/ApiFactory.java @@ -0,0 +1,27 @@ +package org.michaelbel.application.moviemade; + +import android.support.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +@SuppressWarnings("all") +public class ApiFactory { + + public static Gson GSON = new GsonBuilder().setDateFormat(Url.GSON_DATE_FORMAT).create(); + + @NonNull + public static Retrofit getRetrofit() { + Retrofit retrofit = new Retrofit.Builder() + .baseUrl(Url.TMDB_API) + .addConverterFactory(GsonConverterFactory.create(GSON)) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .build(); + + return retrofit; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/moviemade/AppBarStateChangeListener.java b/app/src/main/java/org/michaelbel/application/moviemade/AppBarStateChangeListener.java new file mode 100644 index 000000000..eb92ee17a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/AppBarStateChangeListener.java @@ -0,0 +1,83 @@ +package org.michaelbel.application.moviemade; + +import android.content.Context; +import android.graphics.Point; +import android.support.design.widget.AppBarLayout; +import android.util.TypedValue; +import android.view.Display; +import android.view.WindowManager; + +import org.michaelbel.application.R; + +@SuppressWarnings("all") +public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener { + + public enum State { + EXPANDED, + COLLAPSED, + IDLE + } + + private State mCurrentState = State.IDLE; + + @Override + public final void onOffsetChanged(AppBarLayout appBarLayout, int i) { + if (i == 0) { + if (mCurrentState != State.EXPANDED) { + onStateChanged(appBarLayout, State.EXPANDED); + } + + mCurrentState = State.EXPANDED; + } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) { + if (mCurrentState != State.COLLAPSED) { + onStateChanged(appBarLayout, State.COLLAPSED); + } + + mCurrentState = State.COLLAPSED; + } else { + if (mCurrentState != State.IDLE) { + onStateChanged(appBarLayout, State.IDLE); + } + + mCurrentState = State.IDLE; + } + + onOffsetChanged(mCurrentState, Math.abs(i / (float) appBarLayout.getTotalScrollRange())); + } + + public abstract void onStateChanged(AppBarLayout appBarLayout, State state); + + public abstract void onOffsetChanged(State state, float offset); + + public static int getStatusBarHeightPixel(Context context) { + int result = 0; + int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + + if (resourceId > 0) { + result = context.getResources().getDimensionPixelSize(resourceId); + } + + return result; + } + + public static int getActionBarHeightPixel(Context context) { + TypedValue tv = new TypedValue(); + + if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { + return TypedValue.complexToDimensionPixelSize(tv.data, + context.getResources().getDisplayMetrics()); + } else if (context.getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) { + return TypedValue.complexToDimensionPixelSize(tv.data, + context.getResources().getDisplayMetrics()); + } else { + return 0; + } + } + + public static Point getDisplayDimen(Context context) { + Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + Point size = new Point(); + display.getSize(size); + return size; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/moviemade/AppLoader.java b/app/src/main/java/org/michaelbel/application/moviemade/AppLoader.java new file mode 100644 index 000000000..65da24055 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/AppLoader.java @@ -0,0 +1,20 @@ +package org.michaelbel.application.moviemade; + +import android.app.Application; +import android.content.Context; +import android.os.Handler; + +@SuppressWarnings("all") +public class AppLoader extends Application { + + public static volatile Context AppContext; + public static volatile Handler AppHandler; + + @Override + public void onCreate() { + super.onCreate(); + + AppContext = getApplicationContext(); + AppHandler = new Handler(getApplicationContext().getMainLooper()); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/moviemade/LayoutHelper.java b/app/src/main/java/org/michaelbel/application/moviemade/LayoutHelper.java new file mode 100644 index 000000000..f9ee214fe --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/LayoutHelper.java @@ -0,0 +1,155 @@ +package org.michaelbel.application.moviemade; + +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; + +import org.michaelbel.application.util.ScreenUtils; + +@SuppressWarnings("all") +public class LayoutHelper { + + public static final int MATCH_PARENT = -1; + public static final int WRAP_CONTENT = -2; + + private static int getSize(float size) { + return (int) (size < 0 ? size : ScreenUtils.dp(size)); + } + + public static FrameLayout.LayoutParams makeFrame(int width, int height) { + return new FrameLayout.LayoutParams(getSize(width), getSize(height)); + } + + public static FrameLayout.LayoutParams makeFrame(int width, int height, int gravity) { + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(getSize(width), getSize(height)); + params.gravity = gravity; + return params; + } + + public static FrameLayout.LayoutParams makeFrame(int width, int height, float start, float top, float end, float bottom) { + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(getSize(width), getSize(height)); + params.leftMargin = getSize(start); + params.topMargin = getSize(top); + params.rightMargin = getSize(end); + params.bottomMargin = getSize(bottom); + return params; + } + + public static FrameLayout.LayoutParams makeFrame(int width, int height, int gravity, float start, float top, float end, float bottom) { + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(getSize(width), getSize(height)); + params.gravity = gravity; + params.leftMargin = getSize(start); + params.topMargin = getSize(top); + params.rightMargin = getSize(end); + params.bottomMargin = getSize(bottom); + return params; + } + + public static LinearLayout.LayoutParams makeLinear(int width, int height) { + return new LinearLayout.LayoutParams(getSize(width), getSize(height)); + } + + public static LinearLayout.LayoutParams makeLinear(int width, int height, int gravity) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getSize(width), getSize(height)); + params.gravity = gravity; + return params; + } + + public static LinearLayout.LayoutParams makeLinear(int width, int height, float start, float top, float end, float bottom) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getSize(width), getSize(height)); + params.leftMargin = getSize(start); + params.topMargin = getSize(top); + params.rightMargin = getSize(end); + params.bottomMargin = getSize(bottom); + return params; + } + + public static LinearLayout.LayoutParams makeLinear(int width, int height, int gravity, float start, float top, float end, float bottom) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getSize(width), getSize(height)); + params.gravity = gravity; + params.leftMargin = getSize(start); + params.topMargin = getSize(top); + params.rightMargin = getSize(end); + params.bottomMargin = getSize(bottom); + return params; + } + + public static LinearLayout.LayoutParams makeLinear(int width, int height, float weight) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getSize(width), getSize(height)); + params.weight = weight; + return params; + } + + public static LinearLayout.LayoutParams makeLinear(int width, int height, int gravity, float weight) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getSize(width), getSize(height)); + params.gravity = gravity; + params.weight = weight; + return params; + } + + public static LinearLayout.LayoutParams makeLinear(int width, int height, float weight, float start, float top, float end, float bottom) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getSize(width), getSize(height)); + params.weight = weight; + params.leftMargin = getSize(start); + params.topMargin = getSize(top); + params.rightMargin = getSize(end); + params.bottomMargin = getSize(bottom); + return params; + } + + public static LinearLayout.LayoutParams makeLinear(int width, int height, int gravity, float weight, float start, float top, float end, float bottom) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getSize(width), getSize(height)); + params.gravity = gravity; + params.weight = weight; + params.leftMargin = getSize(start); + params.topMargin = getSize(top); + params.rightMargin = getSize(end); + params.bottomMargin = getSize(bottom); + return params; + } + + public static RelativeLayout.LayoutParams makeRelative(int width, int height) { + return new RelativeLayout.LayoutParams(getSize(width), getSize(height)); + } + + public static RelativeLayout.LayoutParams makeRelative(int width, int height, float start, float top, float end, float bottom) { + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getSize(width), getSize(height)); + params.leftMargin = getSize(start); + params.topMargin = getSize(top); + params.rightMargin = getSize(end); + params.bottomMargin = getSize(bottom); + return params; + } + + public static RelativeLayout.LayoutParams makeRelative(int width, int height, int verb) { + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getSize(width), getSize(height)); + params.addRule(verb); + return params; + } + + public static RelativeLayout.LayoutParams makeRelative(int width, int height, int verb, int anhor) { + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getSize(width), getSize(height)); + params.addRule(verb, anhor); + return params; + } + + public static RelativeLayout.LayoutParams makeRelative(int width, int height,int verb, float start, float top, float end, float bottom) { + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getSize(width), getSize(height)); + params.addRule(verb); + params.leftMargin = getSize(start); + params.topMargin = getSize(top); + params.rightMargin = getSize(end); + params.bottomMargin = getSize(bottom); + return params; + } + + public static RelativeLayout.LayoutParams makeRelative(int width, int height,int verb, int anhor, float start, float top, float end, float bottom) { + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getSize(width), getSize(height)); + params.addRule(verb, anhor); + params.leftMargin = getSize(start); + params.topMargin = getSize(top); + params.rightMargin = getSize(end); + params.bottomMargin = getSize(bottom); + return params; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/moviemade/Theme.java b/app/src/main/java/org/michaelbel/application/moviemade/Theme.java new file mode 100644 index 000000000..d2a177b84 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/Theme.java @@ -0,0 +1,454 @@ +package org.michaelbel.application.moviemade; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.ArrayRes; +import android.support.annotation.AttrRes; +import android.support.annotation.ColorInt; +import android.support.annotation.DrawableRes; +import android.support.annotation.FloatRange; +import android.support.annotation.NonNull; +import android.widget.EditText; +import android.widget.TextView; + +import org.michaelbel.application.R; + +import java.lang.reflect.Field; + +@SuppressWarnings("all") +public class Theme { + + public static final int LIGHT_THEME = 0; + public static final int NIGHT_THEME = 1; + public static final int NIGHT_BLUE_THEME = 2; + + private static Context getContext() { + return AppLoader.AppContext; + } + + public static int getAppTheme() { + SharedPreferences prefs = getContext().getSharedPreferences("mainconfig", Context.MODE_PRIVATE); + return prefs.getInt("theme", 2); + } + + public static int primaryColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.colorPrimary; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.colorPrimary; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.colorPrimary; + } + + return 0; + } + + public static int primaryDarkColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.colorPrimaryDark; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.colorPrimaryDark; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.colorPrimaryDark; + } + + return 0; + } + + public static int accentColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.colorAccent; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.colorAccent; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.colorAccent; + } + + return 0; + } + + public static int primaryTextColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.primaryTextColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_primaryTextColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_primaryTextColor; + } + + return 0; + } + + public static int secondaryTextColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.secondaryTextColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_secondaryTextColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_secondaryTextColor; + } + + return 0; + } + + public static int hindTextColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.disabledHintTextColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_disabledHintTextColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_disabledHintTextColor; + } + + return 0; + } + + public static int dividerColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.dividerColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_dividerColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_dividerColor; + } + + return 0; + } + + public static int iconActiveColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.iconActiveColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_iconActiveColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_iconActiveColor; + } + + return 0; + } + + public static int iconInactiveColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.iconInactiveColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_iconInactiveColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_iconInactiveColor; + } + + return 0; + } + + public static int statusBarColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.statusBarColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_statusBarColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_statusBarColor; + } + + return 0; + } + + public static int appBarColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.appBarColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_appBarColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_appBarColor; + } + + return 0; + } + + public static int backgroundColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.backgroundColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_backgroundColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_backgroundColor; + } + + return 0; + } + + public static int foregroundColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.foregroundColor; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_foregroundColor; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_foregroundColor; + } + + return 0; + } + + public static int thumbOnColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.switch_thumbOn; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_switch_thumbOn; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_switch_thumbOn; + } + + return 0; + } + + public static int thumbOffColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.switch_thumbOff; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_switch_thumbOff; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_switch_thumbOff; + } + + return 0; + } + + public static int trackOnColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.switch_trackOn; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_switch_trackOn; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_switch_trackOn; + } + + return 0; + } + + public static int trackOffColor() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.color.switch_trackOff; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.color.night_switch_trackOff; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return R.color.night_blue_switch_trackOff; + } + + return 0; + } + + // STYLES + + public static int popupTheme() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.style.ThemeOverlay_AppCompat_Light; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.style.ThemeOverlay_AppCompat; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return -1; + } + + return 0; + } + + public static int alertTheme() { + if (Theme.getAppTheme() == LIGHT_THEME) { + return R.style.AlertLight; + } else if (Theme.getAppTheme() == NIGHT_THEME) { + return R.style.AlertNight; + } else if (Theme.getAppTheme() == NIGHT_BLUE_THEME) { + return -1; + } + + return 0; + } + + public static int selectableItemBackground() { + int[] attrs = new int[] { + R.attr.selectableItemBackground + }; + + TypedArray typedArray = getContext().obtainStyledAttributes(attrs); + int backgroundResource = typedArray.getResourceId(0, 0); + typedArray.recycle(); + + return backgroundResource; + } + + public static int selectableItemBackgroundBorderless() { + int[] attrs = new int[] { + R.attr.selectableItemBackgroundBorderless + }; + + TypedArray typedArray = getContext().obtainStyledAttributes(attrs); + int backgroundResource = typedArray.getResourceId(0, 0); + typedArray.recycle(); + + return backgroundResource; + } + + public static Drawable selectableItemBackgroundDrawable() { + int[] attrs = new int[] { + android.R.attr.selectableItemBackground + }; + + TypedArray typedArray = getContext().obtainStyledAttributes(attrs); + Drawable drawableFromTheme = typedArray.getDrawable(0); + typedArray.recycle(); + + return drawableFromTheme; + } + + public static Drawable selectableItemBackgroundBorderlessDrawable() { + int[] attrs = new int[] { + android.R.attr.selectableItemBackgroundBorderless + }; + + TypedArray typedArray = getContext().obtainStyledAttributes(attrs); + Drawable drawableFromTheme = typedArray.getDrawable(0); + typedArray.recycle(); + + return drawableFromTheme; + } + + public static Drawable getIcon(@DrawableRes int resource, int colorFilter) { + return getIcon(resource, colorFilter, PorterDuff.Mode.MULTIPLY); + } + + public static Drawable getIcon(@DrawableRes int resource, int colorFilter, PorterDuff.Mode mode) { + Drawable iconDrawable = getContext().getResources().getDrawable(resource, null); + + if (iconDrawable != null) { + iconDrawable.clearColorFilter(); + iconDrawable.mutate().setColorFilter(colorFilter, mode); + } + + return iconDrawable; + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) + public static void clearCursorDrawable(EditText editText) { + if (editText == null) { + return; + } + try { + Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); + mCursorDrawableRes.setAccessible(true); + mCursorDrawableRes.setInt(editText, 0); + } catch (Exception e) { + + } + } + + public static int getAttrColor(@NonNull Context context, @AttrRes int colorAttr) { + int color = 0; + int[] attrs = new int[] { + colorAttr + }; + + try { + TypedArray typedArray = context.obtainStyledAttributes(attrs); + color = typedArray.getColor(0, 0); + typedArray.recycle(); + } catch (Exception e) { + + } + + return color; + } + + @ColorInt + public static int adjustAlpha(@ColorInt int color, @FloatRange(from = 0.00F, to = 1.00F) float factor) { + int alpha = Math.round(Color.alpha(color) * factor); + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + return Color.argb(alpha, red, green, blue); + } + + public static int[] getColorArray(@NonNull Context context, @ArrayRes int arrayRes) { + if (arrayRes == 0) { + return null; + } + + TypedArray ta = context.getResources().obtainTypedArray(arrayRes); + int[] colors = new int[ta.length()]; + + for (int i = 0; i < ta.length(); i++) { + colors[i] = ta.getColor(i, 0); + } + + ta.recycle(); + return colors; + } + + private static double[] rgbToHsv(int r, int g, int b) { + double rf = r / 255.0; + double gf = g / 255.0; + double bf = b / 255.0; + double max = (rf > gf && rf > bf) ? rf : (gf > bf) ? gf : bf; + double min = (rf < gf && rf < bf) ? rf : (gf < bf) ? gf : bf; + double h, s; + double d = max - min; + s = max == 0 ? 0 : d / max; + if (max == min) { + h = 0; + } else { + if (rf > gf && rf > bf) { + h = (gf - bf) / d + (gf < bf ? 6 : 0); + } else if (gf > bf) { + h = (bf - rf) / d + 2; + } else { + h = (rf - gf) / d + 4; + } + h /= 6; + } + return new double[]{h, s, max}; + } + + private static int[] hsvToRgb(double h, double s, double v) { + double r = 0, g = 0, b = 0; + double i = (int) Math.floor(h * 6); + double f = h * 6 - i; + double p = v * (1 - s); + double q = v * (1 - f * s); + double t = v * (1 - (1 - f) * s); + switch ((int) i % 6) { + case 0: + r = v; + g = t; + b = p; + break; + case 1: + r = q; + g = v; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + case 3: + r = p; + g = q; + b = v; + break; + case 4: + r = t; + g = p; + b = v; + break; + case 5: + r = v; + g = p; + b = q; + break; + } + return new int[]{(int) (r * 255), (int) (g * 255), (int) (b * 255)}; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/moviemade/Url.java b/app/src/main/java/org/michaelbel/application/moviemade/Url.java new file mode 100644 index 000000000..f107e601a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/Url.java @@ -0,0 +1,27 @@ +package org.michaelbel.application.moviemade; + +import org.michaelbel.application.util.AppUtils; + +@SuppressWarnings("all") +public class Url { + public static final String GSON_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; + public static final String TMDB_API = "https://api.themoviedb.org/3/"; + public static final String TMDB_MOVIE = "https://themoviedb.org/movie/"; + public static final String TMDB_API_KEY = AppUtils.getProperty("TMDbApiKey"); + public static final String TMDB_API_TOKEN = AppUtils.getProperty("TMDbApiToken"); + + public static final String SEARCH_FOR_COMPANIES = "company"; + public static final String SEARCH_FOR_COLLECTIONS = "collection"; + public static final String SEARCH_FOR_KEYWORDS = "keyword"; + public static final String SEARCH_FOR_MOVIES = "movie"; + public static final String SEARCH_FOR_MULTI = "multi"; + public static final String SEARCH_FOR_PEOPLE = "person"; + public static final String SEARCH_FOR_TVSHOWS = "tv"; + + public static final String en_US = "en-US"; + public static final String de_DE = "de-DE"; + public static final String ru_RU = "ru-RU"; + public static final String pt_BR = "pt-BR"; + public static final String pt_PT = "pt-PT"; + public static final String pt_US = "pt-US"; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/moviemade/annotation/Beta.java b/app/src/main/java/org/michaelbel/application/moviemade/annotation/Beta.java new file mode 100644 index 000000000..7593aa111 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/annotation/Beta.java @@ -0,0 +1,20 @@ +package org.michaelbel.application.moviemade.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.CLASS) +@Target({ + ElementType.ANNOTATION_TYPE, + ElementType.CONSTRUCTOR, + ElementType.FIELD, + ElementType.METHOD, + ElementType.TYPE }) +@Documented +@Beta +@SuppressWarnings("all") +public @interface Beta { +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/moviemade/browser/Browser.java b/app/src/main/java/org/michaelbel/application/moviemade/browser/Browser.java new file mode 100644 index 000000000..cf5bd5311 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/browser/Browser.java @@ -0,0 +1,59 @@ +package org.michaelbel.application.moviemade.browser; + +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.util.Log; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.Theme; + +@SuppressWarnings("all") +public class Browser { + + private static final String TAG = Browser.class.getSimpleName(); + + public static void openUrl(@NonNull Context context, @NonNull String url) { + SharedPreferences prefs = context.getSharedPreferences("mainconfig", Context.MODE_PRIVATE); + if (prefs.getBoolean("in_app_browser", true)) { + openInAppUrl(context, url); + } else { + openBrowserUrl(context, url); + } + } + + private static void openInAppUrl(@NonNull Context context, @NonNull String url) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.putExtra("android.support.customtabs.extra.SESSION", (Parcelable) null); + intent.putExtra("android.support.customtabs.extra.TOOLBAR_COLOR", Theme.getAttrColor(context, R.attr.colorPrimary)); + intent.putExtra("android.support.customtabs.extra.TITLE_VISIBILITY", 1); + Intent actionIntent = new Intent(Intent.ACTION_SEND); + actionIntent.setType("text/plain"); + actionIntent.putExtra(Intent.EXTRA_TEXT, Uri.parse(url).toString()); + actionIntent.putExtra(Intent.EXTRA_SUBJECT, ""); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, actionIntent, PendingIntent.FLAG_ONE_SHOT); + Bundle bundle = new Bundle(); + bundle.putInt("android.support.customtabs.customaction.ID", 0); + bundle.putParcelable("android.support.customtabs.customaction.ICON", BitmapFactory.decodeResource(context.getResources(), R.drawable.abc_ic_menu_share_mtrl_alpha)); + bundle.putString("android.support.customtabs.customaction.DESCRIPTION", "Share link"); + bundle.putParcelable("android.support.customtabs.customaction.PENDING_INTENT", pendingIntent); + intent.putExtra("android.support.customtabs.extra.ACTION_BUTTON_BUNDLE", bundle); + intent.putExtra("android.support.customtabs.extra.TINT_ACTION_BUTTON", false); + intent.putExtra(android.provider.Browser.EXTRA_APPLICATION_ID, context.getPackageName()); + context.startActivity(intent); + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } + } + + private static void openBrowserUrl(@NonNull Context context, @NonNull String url) { + context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/moviemade/eventbus/Events.java b/app/src/main/java/org/michaelbel/application/moviemade/eventbus/Events.java new file mode 100644 index 000000000..3d610265d --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/eventbus/Events.java @@ -0,0 +1,14 @@ +package org.michaelbel.application.moviemade.eventbus; + +@SuppressWarnings("all") +public class Events { + + public static class Listener { + + public CharSequence query; + + public Listener(CharSequence query) { + this.query = query; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/moviemade/eventbus/RxBus.java b/app/src/main/java/org/michaelbel/application/moviemade/eventbus/RxBus.java new file mode 100644 index 000000000..afc698640 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/moviemade/eventbus/RxBus.java @@ -0,0 +1,33 @@ +package org.michaelbel.application.moviemade.eventbus; + +import rx.Observable; +import rx.subjects.PublishSubject; +import rx.subjects.SerializedSubject; +import rx.subjects.Subject; + +@SuppressWarnings("all") +public class RxBus { + + private static volatile RxBus instance; + + private final Subject bus = new SerializedSubject<>(PublishSubject.create()); + + public static RxBus getInstance() { + if (instance == null) { + synchronized (RxBus.class) { + if (instance == null) { + instance = new RxBus(); + } + } + } + return instance; + } + + public void send(Object o) { + bus.onNext(o); + } + + public Observable toObservable() { + return bus; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/ACCOUNT.java b/app/src/main/java/org/michaelbel/application/rest/api/ACCOUNT.java new file mode 100644 index 000000000..658ed256f --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/ACCOUNT.java @@ -0,0 +1,105 @@ +package org.michaelbel.application.rest.api; + +import org.michaelbel.application.rest.model.Account; +import org.michaelbel.application.rest.response.MovieResponse; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Path; +import retrofit2.http.Query; + +@SuppressWarnings("all") +public interface ACCOUNT { + + @GET("account?") + Call getDetails( + @Query("api_key") String apiKey, + @Query("session_id") String sessionId + ); + + @GET("account/{account_id}/lists?") + Call getCreatedLists( + @Path("account_id") int id, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId, + @Query("language") String language + ); + + @GET("account/{account_id}/favorite/movies?") + Call getFavoriteMovies( + @Path("account_id") int accountId, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId, + @Query("language") String lang, + @Query("sort_by") String sort + ); + + @GET("account/{account_id}/favorite/tv?") + Call getFavoriteTVShows( + @Path("account_id") int accountId, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId, + @Query("language") String lang, + @Query("sort_by") String sort + ); + + @POST("account/{account_id}/favorite?") + Call markAsFavorite( + @Path("account_id") int id, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId + ); + + @GET("account/{account_id}/rated/movies?") + Call getRatedMovies( + @Path("account_id") int id, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId, + @Query("language") String language, + @Query("sort_by") String sort + ); + + @GET("account/{account_id}/rated/tv?") + Call getRatedTVShows( + @Path("account_id") int id, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId, + @Query("language") String language, + @Query("sort_by") String sort + ); + + @GET("account/{account_id}/rated/tv/episodes?") + Call getRatedTVEpisodes( + @Path("account_id") int id, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId, + @Query("language") String language, + @Query("sort_by") String sort + ); + + @GET("account/{account_id}/watchlist/movies?") + Call getMovieWatchlist( + @Path("account_id") int id, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId, + @Query("language") String language, + @Query("sort_by") String sort + ); + + @GET("account/{account_id}/watchlist/tv?") + Call getTVShowsWatchlist( + @Path("account_id") int id, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId, + @Query("language") String language, + @Query("sort_by") String sort + ); + + @POST("account/{account_id}/watchlist?") + Call addToWatchlist( + @Path("account_id") int id, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId + ); +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/AUTHENTICATION.java b/app/src/main/java/org/michaelbel/application/rest/api/AUTHENTICATION.java new file mode 100644 index 000000000..7452d0ca6 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/AUTHENTICATION.java @@ -0,0 +1,35 @@ +package org.michaelbel.application.rest.api; + +import org.michaelbel.application.rest.model.Auth; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Query; + +@SuppressWarnings("all") +public interface AUTHENTICATION { + + @GET("authentication/token/new?") + Call createRequestToken( + @Query("api_key") String apiKey + ); + + @GET("authentication/token/validate_with_login?") + Call validateRequestToken( + @Query("api_key") String apiKey, + @Query("username") String username, + @Query("password") String password, + @Query("request_token") String requestToken + ); + + @GET("authentication/session/new?") + Call createSession( + @Query("api_key") String apiKey, + @Query("request_token") String requestToken + ); + + @GET("authentication/guest_session/new?") + Call createGuestSession( + @Query("api_key") String apiKey + ); +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/CERTIFICATIONS.java b/app/src/main/java/org/michaelbel/application/rest/api/CERTIFICATIONS.java new file mode 100644 index 000000000..f62b1c128 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/CERTIFICATIONS.java @@ -0,0 +1,9 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface CERTIFICATIONS { + + // getMovieCertifications + + // getTVCertifications +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/CHANGES.java b/app/src/main/java/org/michaelbel/application/rest/api/CHANGES.java new file mode 100644 index 000000000..5ea4c755a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/CHANGES.java @@ -0,0 +1,11 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface CHANGES { + + // getMovieChangeList + + // getTVChangeList + + // getPersonChangeList +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/COLLECTIONS.java b/app/src/main/java/org/michaelbel/application/rest/api/COLLECTIONS.java new file mode 100644 index 000000000..259a4c79e --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/COLLECTIONS.java @@ -0,0 +1,9 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface COLLECTIONS { + + // getDetails + + // getImages +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/COMPANIES.java b/app/src/main/java/org/michaelbel/application/rest/api/COMPANIES.java new file mode 100644 index 000000000..221157f30 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/COMPANIES.java @@ -0,0 +1,9 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface COMPANIES { + + // getDetails + + // getMovies +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/CONFIGURATIONS.java b/app/src/main/java/org/michaelbel/application/rest/api/CONFIGURATIONS.java new file mode 100644 index 000000000..172338e5b --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/CONFIGURATIONS.java @@ -0,0 +1,7 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface CONFIGURATIONS { + + // getApiConfiguration +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/CREDITS.java b/app/src/main/java/org/michaelbel/application/rest/api/CREDITS.java new file mode 100644 index 000000000..5d6970c18 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/CREDITS.java @@ -0,0 +1,7 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface CREDITS { + + // getDetails +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/DISCOVER.java b/app/src/main/java/org/michaelbel/application/rest/api/DISCOVER.java new file mode 100644 index 000000000..424061d42 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/DISCOVER.java @@ -0,0 +1,9 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface DISCOVER { + + // movieDiscover + + // tvDiscover +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/FIND.java b/app/src/main/java/org/michaelbel/application/rest/api/FIND.java new file mode 100644 index 000000000..4b1bf658f --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/FIND.java @@ -0,0 +1,7 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface FIND { + + // findById +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/GENRES.java b/app/src/main/java/org/michaelbel/application/rest/api/GENRES.java new file mode 100644 index 000000000..429818d8e --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/GENRES.java @@ -0,0 +1,28 @@ +package org.michaelbel.application.rest.api; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Query; + +@SuppressWarnings("all") +public interface GENRES { + + @GET("genre/movie/list?") + Call getMovieList( + @Query("api_key") String apiKey, + @Query("language") String language + ); + + @GET("genre/tv/list?") + Call getTVList( + @Query("api_key") String apiKey, + @Query("language") String language + ); + + @GET("genre/{genre_id}/movies?") + Call getMovies( + @Query("api_key") String apiKey, + @Query("language") String language, + @Query("include_adult") boolean adult + ); +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/GUESTSESSIONS.java b/app/src/main/java/org/michaelbel/application/rest/api/GUESTSESSIONS.java new file mode 100644 index 000000000..f5b949380 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/GUESTSESSIONS.java @@ -0,0 +1,11 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface GUESTSESSIONS { + + // getRatedMovies + + // getRatedTVShows + + // getRatedTVEpisodes +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/JOBS.java b/app/src/main/java/org/michaelbel/application/rest/api/JOBS.java new file mode 100644 index 000000000..d91e71072 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/JOBS.java @@ -0,0 +1,7 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface JOBS { + + // getJobs +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/KEYWORDS.java b/app/src/main/java/org/michaelbel/application/rest/api/KEYWORDS.java new file mode 100644 index 000000000..34ee875cf --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/KEYWORDS.java @@ -0,0 +1,9 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface KEYWORDS { + + // getDetails + + // getMovies +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/LISTS.java b/app/src/main/java/org/michaelbel/application/rest/api/LISTS.java new file mode 100644 index 000000000..dd7fa78e7 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/LISTS.java @@ -0,0 +1,19 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface LISTS { + + // getDetails + + // checkItemStatus + + // createList + + // addMovie + + // removeMovie + + // clearList + + // deleteList +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/MOVIES.java b/app/src/main/java/org/michaelbel/application/rest/api/MOVIES.java new file mode 100644 index 000000000..6023ff389 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/MOVIES.java @@ -0,0 +1,157 @@ +package org.michaelbel.application.rest.api; + +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.response.CreditResponse; +import org.michaelbel.application.rest.response.ImageResponse; +import org.michaelbel.application.rest.response.MovieResponse; +import org.michaelbel.application.rest.response.ReviewResponse; +import org.michaelbel.application.rest.response.VideoResponse; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Path; +import retrofit2.http.Query; + +@SuppressWarnings("all") +public interface MOVIES { + + @GET("movie/{movie_id}?") + Call getDetails( + @Path("movie_id") int id, + @Query("api_key") String apiKey, + @Query("language") String language, + @Query("append_to_response") String responce + ); + + @GET("movie/{movie_id}/account_states?") + Call getAccountStates( + @Path("movie_id") int id, + @Query("api_key") String apiKey, + @Query("session_id") String sessionId, + @Query("quest_session_id") String questSessionId + ); + + @GET("movie/{movie_id}/changes?") + Call getChanges( + @Path("movie_id") int id, + @Query("api_key") String apiKey, + @Query("start_date") String startDate, + @Query("end_date") String endDate, + @Query("page") int page + ); + + @GET("movie/{movie_id}/alternative_titles?") + Call getAlternativeTitles( + @Path("movie_id") int id, + @Query("api_key") String apiKey, + @Query("country") String country + ); + + @GET("movie/{movie_id}/credits?") + Call getCredits( + @Path("movie_id") int id, + @Query("api_key") String apiKey + ); + + @GET("movie/{movie_id}/images?") + Call getImages( + @Path("movie_id") int id, + @Query("api_key") String apiKey, + @Query("include_image_language") String lang + ); + + @GET("movie/{movie_id}/keywords?") + Call getKeywords( + @Path("movie_id") int id, + @Query("api_key") String apiKey + ); + + @GET("movie/{movie_id}/release_dates?") + Call getReleaseDates( + @Path("movie_id") int id, + @Query("api_key") String apiKey + ); + + @GET("movie/{movie_id}/videos?") + Call getVideos( + @Path("movie_id") int id, + @Query("api_key") String apiKey, + @Query("language") String lang + ); + + @GET("movie/{movie_id}/translations?") + Call getTranslations( + @Query("api_key") String apiKey, + @Query("language") String lang + ); + + @GET("movie/{movie_id}/recommendations?") + Call getRecommendations( + @Path("movie_id") int id, + @Query("api_key") String apiKey, + @Query("language") String language, + @Query("page") int page + ); + + @GET("movie/{movie_id}/similar?") + Call getSimilarMovies( + @Path("movie_id") int id, + @Query("api_key") String apiKey, + @Query("language") String language, + @Query("page") int page + ); + + @GET("movie/{movie_id}/reviews?") + Call getReviews( + @Path("movie_id") int id, + @Query("api_key") String apiKey, + @Query("language") String language, + @Query("page") int page + ); + + @GET("movie/{movie_id}/lists?") + Call getLists( + @Path("movie_id") String param, + @Query("api_key") String apiKey, + @Query("language") String language, + @Query("page") int page + ); + + // rateMovie + + // deleteRating + + @GET("movie/latest?") + Call getLatest( + @Query("api_key") String apiKey, + @Query("language") String lang + ); + + @GET("movie/now_playing?") + Call getNowPlaying( + @Query("api_key") String apiKey, + @Query("language") String lang, + @Query("page") int page + ); + + @GET("movie/popular?") + Call getPopular( + @Query("api_key") String apiKey, + @Query("language") String lang, + @Query("page") int page + ); + + @GET("movie/top_rated?") + Call getTopRated( + @Query("api_key") String apiKey, + @Query("language") String lang, + @Query("page") int page + ); + + @GET("movie/upcoming?") + Call getUpcoming( + @Query("api_key") String apiKey, + @Query("language") String lang, + @Query("page") int page + ); +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/NETWORKS.java b/app/src/main/java/org/michaelbel/application/rest/api/NETWORKS.java new file mode 100644 index 000000000..4ea6161fe --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/NETWORKS.java @@ -0,0 +1,7 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface NETWORKS { + + // getDetails +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/PEOPLE.java b/app/src/main/java/org/michaelbel/application/rest/api/PEOPLE.java new file mode 100644 index 000000000..517509daa --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/PEOPLE.java @@ -0,0 +1,83 @@ +package org.michaelbel.application.rest.api; + +import org.michaelbel.application.rest.model.Person; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Path; +import retrofit2.http.Query; + +@SuppressWarnings("all") +public interface PEOPLE { + + @GET("person/{person_id}?") + Call getDetails( + @Path("person_id") int id, + @Query("api_key") String apiKey, + @Query("language") String language, + @Query("append_to_response") String responce + ); + + @GET("person/{person_id}/movie_credits?") + Call getMovieCredits( + @Path("person_id") int id, + @Query("api_key") String apiKey, + @Query("language") String language + ); + + @GET("person/{person_id}/tv_credits?") + Call getTVCredits( + @Path("person_id") int id, + @Query("api_key") String apiKey, + @Query("language") String language + ); + + @GET("person/{person_id}/combined_credits?") + Call getCombinedCredits( + @Path("person_id") int id, + @Query("api_key") String apiKey, + @Query("language") String language + ); + + @GET("person/{person_id}/external_ids?") + Call getExternalIDs( + @Path("person_id") int id, + @Query("api_key") String apiKey, + @Query("language") String language + ); + + @GET("person/{person_id}/images?") + Call getImages( + @Path("person_id") int id, + @Query("api_key") String apiKey + ); + + @GET("person/{person_id}/tagged_images?") + Call getTaggedImages( + @Path("person_id") int id, + @Query("api_key") String apiKey, + @Query("page") int page + ); + + @GET("person/{person_id}/changes?") + Call getChanges( + @Path("person_id") int id, + @Query("api_key") String apiKey, + @Query("end_date") String endDate, + @Query("start_date") String startDate, + @Query("page") int page + ); + + @GET("person/latest?") + Call getLatest( + @Query("api_key") String apiKey, + @Query("language") String language + ); + + @GET("person/popular?") + Call getLatest( + @Query("api_key") String apiKey, + @Query("language") String language, + @Query("page") int page + ); +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/REVIEWS.java b/app/src/main/java/org/michaelbel/application/rest/api/REVIEWS.java new file mode 100644 index 000000000..826c0a0ac --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/REVIEWS.java @@ -0,0 +1,18 @@ +package org.michaelbel.application.rest.api; + +import org.michaelbel.application.rest.model.Review; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Path; +import retrofit2.http.Query; + +@SuppressWarnings("all") +public interface REVIEWS { + + @GET("review/{review_id}") + Call getDetails( + @Path("review_id") String id, + @Query("api_key") String apiKey + ); +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/SEARCH.java b/app/src/main/java/org/michaelbel/application/rest/api/SEARCH.java new file mode 100644 index 000000000..3d52f64f0 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/SEARCH.java @@ -0,0 +1,32 @@ +package org.michaelbel.application.rest.api; + +import org.michaelbel.application.rest.response.MovieResponse; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Path; +import retrofit2.http.Query; + +@SuppressWarnings("all") +public interface SEARCH { + + // searchCompanies + + // searchCollections + + // searchKeywords + + @GET("search/{param}?") + Call searchMovies( + @Path("param") String param, + @Query("api_key") String apiKey, + @Query("language") String lang, + @Query("query") String query + ); + + // multiSearch + + // searchPeople + + // searchTvShows +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/TIMEZONES.java b/app/src/main/java/org/michaelbel/application/rest/api/TIMEZONES.java new file mode 100644 index 000000000..ecac59133 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/TIMEZONES.java @@ -0,0 +1,7 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface TIMEZONES { + + // getList +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/TV.java b/app/src/main/java/org/michaelbel/application/rest/api/TV.java new file mode 100644 index 000000000..9f6a5789a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/TV.java @@ -0,0 +1,47 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface TV { + + // getDetails + + // getAccountStates + + // getAlternativeTitles + + // getChanges + + // getContentRatings + + // getCredits + + // getExternalIDs + + // getImages + + // getKeywords + + // getRecommendations + + // getScreenedTheatrically + + // getSimilarTVShows + + // getTranslations + + // getVideos + + // rateTVShow + + // deleteRating + + // getLatest + + // getAiringToday + + // getTVOnTheAir + + // getPopular + + // getTopRated +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/TVEPISODES.java b/app/src/main/java/org/michaelbel/application/rest/api/TVEPISODES.java new file mode 100644 index 000000000..5ab2b960a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/TVEPISODES.java @@ -0,0 +1,23 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface TVEPISODES { + + // getDetails + + // getChanges + + // getAccountStates + + // getCredits + + // getTVEpisodeExternalIDs + + // getImages + + // rateTVEpisode + + // deleteRating + + // getVideos +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/api/TVSEASONS.java b/app/src/main/java/org/michaelbel/application/rest/api/TVSEASONS.java new file mode 100644 index 000000000..8c8942885 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/api/TVSEASONS.java @@ -0,0 +1,19 @@ +package org.michaelbel.application.rest.api; + +@SuppressWarnings("all") +public interface TVSEASONS { + + // getDetails + + // getChanges + + // getAccountStates + + // getCredits + + // getExternalIDs + + // getImages + + // getVideos +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Account.java b/app/src/main/java/org/michaelbel/application/rest/model/Account.java new file mode 100644 index 000000000..1007688ee --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Account.java @@ -0,0 +1,37 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("all") +public class Account { + + @SerializedName("avatar") + public Avatar avatar; + + @SerializedName("id") + public int id; + + @SerializedName("iso_639_1") + public String iso_639_1; + + @SerializedName("iso_3166_1") + public String iso_3166_1; + + @SerializedName("name") + public String name; + + @SerializedName("include_adult") + public boolean includeAdult; + + @SerializedName("username") + public String username; + + public class Avatar { + + public class GAvatar { + + @SerializedName("hash") + public String hash; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Auth.java b/app/src/main/java/org/michaelbel/application/rest/model/Auth.java new file mode 100644 index 000000000..7328e5962 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Auth.java @@ -0,0 +1,49 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("all") +public class Auth { + + public class CreatedRequest { + + @SerializedName("success") + public boolean success; + + @SerializedName("expires_at") + public String expires_at; + + @SerializedName("request_token") + public String request_token; + } + + public class ValidatedRequest { + + @SerializedName("success") + public boolean success; + + @SerializedName("request_token") + public String request_token; + } + + public class Session { + + @SerializedName("success") + public boolean success; + + @SerializedName("session_id") + public String sessionId; + } + + public class GuestSession { + + @SerializedName("success") + public boolean success; + + @SerializedName("expires_at") + public String expires_at; + + @SerializedName("quest_session_id") + public String questSessionId; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Backdrop.java b/app/src/main/java/org/michaelbel/application/rest/model/Backdrop.java new file mode 100644 index 000000000..33e5fab6e --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Backdrop.java @@ -0,0 +1,28 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("all") +public class Backdrop { + + @SerializedName("aspect_ratio") + public float aspectRatio; + + @SerializedName("file_path") + public String filePath; + + @SerializedName("height") + public int height; + + @SerializedName("width") + public int width; + + @SerializedName("iso_639_1") + public String code; + + @SerializedName("vote_averahe") + public float voteAverage; + + @SerializedName("vote_count") + public int voteCount; +} diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Cast.java b/app/src/main/java/org/michaelbel/application/rest/model/Cast.java new file mode 100644 index 000000000..fc0fccb45 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Cast.java @@ -0,0 +1,28 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("all") +public class Cast { + + @SerializedName("cast_id") + public int castId; + + @SerializedName("character") + public String character; + + @SerializedName("credit_id") + public String creditId; + + @SerializedName("id") + public int id; + + @SerializedName("name") + public String name; + + @SerializedName("order") + public int order; + + @SerializedName("profile_path") + public String profilePath; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Crew.java b/app/src/main/java/org/michaelbel/application/rest/model/Crew.java new file mode 100644 index 000000000..bf55d2943 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Crew.java @@ -0,0 +1,25 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("all") +public class Crew { + + @SerializedName("credit_id") + public String creditId; + + @SerializedName("department") + public String department; + + @SerializedName("id") + public int id; + + @SerializedName("job") + public String job; + + @SerializedName("name") + public String name; + + @SerializedName("profile_path") + public String profilePath; +} diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Genre.java b/app/src/main/java/org/michaelbel/application/rest/model/Genre.java new file mode 100644 index 000000000..b2fbb8b09 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Genre.java @@ -0,0 +1,13 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("all") +public class Genre { + + @SerializedName("id") + public int id; + + @SerializedName("name") + public String name; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Movie.java b/app/src/main/java/org/michaelbel/application/rest/model/Movie.java new file mode 100644 index 000000000..0680b650c --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Movie.java @@ -0,0 +1,129 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + +@SuppressWarnings("all") +public class Movie { + + @SerializedName("adult") + public boolean adult; + + @SerializedName("backdrop_path") + public String backdropPath; + + @SerializedName("budget") + public int budget; + + @SerializedName("homepage") + public String homepage; + + @SerializedName("id") + public int id; + + @SerializedName("imdb_id") + public String imdbId; + + @SerializedName("original_language") + public String originalLanguage; + + @SerializedName("original_title") + public String originalTitle; + + @SerializedName("overview") + public String overview; + + @SerializedName("popularity") + public double popularity; + + @SerializedName("poster_path") + public String posterPath; + + @SerializedName("release_date") + public String releaseDate; + + @SerializedName("revenue") + public int revenue; + + @SerializedName("runtime") + public int runtime; + + @SerializedName("status") + public String status; + + @SerializedName("tagline") + public String tagline; + + @SerializedName("title") + public String title; + + @SerializedName("video") + public boolean video; + + @SerializedName("vote_average") + public float voteAverage; + + @SerializedName("vote_count") + public int voteCount; + + @SerializedName("genres") + public List genresList; + + @SerializedName("production_companies") + public List companiesList; + + @SerializedName("production_countries") + public List countriesList; + + @SerializedName("spoken_languages") + public List languagesList; + + @SerializedName("belongs_to_collection") + public BelongsToCollection belongsToCollection; + + public class Companies implements Serializable { + + @SerializedName("id") + public int id; + + @SerializedName("name") + public String name; + } + + public class Countries implements Serializable { + + @SerializedName("iso_3166_1") + public String country; + + @SerializedName("name") + public String name; + } + + public class Languages implements Serializable { + + @SerializedName("iso_639_1") + public String language; + + @SerializedName("name") + public String name; + } + + public class BelongsToCollection implements Serializable { + + @SerializedName("id") + public int id; + + @SerializedName("name") + public String name; + + @SerializedName("poster_path") + public String posterPath; + + @SerializedName("backdrop_path") + public String backdropPath; + } + + public Movie() {} +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Person.java b/app/src/main/java/org/michaelbel/application/rest/model/Person.java new file mode 100644 index 000000000..c5c98fa83 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Person.java @@ -0,0 +1,48 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +@SuppressWarnings("all") +public class Person { + + @SerializedName("birthday") + public String birthday; + + @SerializedName("deathday") + public String deathday; + + @SerializedName("id") + public int id; + + @SerializedName("name") + public String name; + + @SerializedName("also_known_as") + public List names; + + @SerializedName("gender") + public int gender; + + @SerializedName("biography") + public String bio; + + @SerializedName("popularity") + public double popularity; + + @SerializedName("place_of_birth") + public String birthPlace; + + @SerializedName("profile_path") + public String profilePath; + + @SerializedName("adult") + public boolean adult; + + @SerializedName("imdb_id") + public String imdbId; + + @SerializedName("homepage") + public String homepage; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Poster.java b/app/src/main/java/org/michaelbel/application/rest/model/Poster.java new file mode 100644 index 000000000..613145a8d --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Poster.java @@ -0,0 +1,28 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("all") +public class Poster { + + @SerializedName("aspect_ratio") + public float aspectRatio; + + @SerializedName("file_path") + public String filePath; + + @SerializedName("height") + public int height; + + @SerializedName("width") + public int width; + + @SerializedName("iso_639_1") + public String code; + + @SerializedName("vote_averahe") + public float voteAverage; + + @SerializedName("vote_count") + public int voteCount; +} diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Review.java b/app/src/main/java/org/michaelbel/application/rest/model/Review.java new file mode 100644 index 000000000..34e19b077 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Review.java @@ -0,0 +1,31 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("all") +public class Review { + + @SerializedName("id") + public String id; + + @SerializedName("author") + public String author; + + @SerializedName("content") + public String content; + + @SerializedName("iso_639_1") + public String lang; + + @SerializedName("media_id") + public int mediaId; + + @SerializedName("media_title") + public String mediaTitle; + + @SerializedName("media_type") + public String mediaType; + + @SerializedName("url") + public String url; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/model/Trailer.java b/app/src/main/java/org/michaelbel/application/rest/model/Trailer.java new file mode 100644 index 000000000..bb1bd1a27 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/model/Trailer.java @@ -0,0 +1,31 @@ +package org.michaelbel.application.rest.model; + +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("all") +public class Trailer { + + @SerializedName("id") + public String id; + + @SerializedName("iso_639_1") + public String lang; + + @SerializedName("iso_3166_1") + public String country; + + @SerializedName("key") + public String key; + + @SerializedName("name") + public String name; + + @SerializedName("site") + public String site; + + @SerializedName("size") + public String size; + + @SerializedName("type") + public String type; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/response/CreditResponse.java b/app/src/main/java/org/michaelbel/application/rest/response/CreditResponse.java new file mode 100644 index 000000000..4645ff09a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/response/CreditResponse.java @@ -0,0 +1,21 @@ +package org.michaelbel.application.rest.response; + +import com.google.gson.annotations.SerializedName; + +import org.michaelbel.application.rest.model.Cast; +import org.michaelbel.application.rest.model.Crew; + +import java.util.List; + +@SuppressWarnings("all") +public class CreditResponse { + + @SerializedName("id") + public int id; + + @SerializedName("cast") + public List castList; + + @SerializedName("crew") + public List crewList; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/response/ImageResponse.java b/app/src/main/java/org/michaelbel/application/rest/response/ImageResponse.java new file mode 100644 index 000000000..e08d2f41e --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/response/ImageResponse.java @@ -0,0 +1,21 @@ +package org.michaelbel.application.rest.response; + +import com.google.gson.annotations.SerializedName; + +import org.michaelbel.application.rest.model.Backdrop; +import org.michaelbel.application.rest.model.Poster; + +import java.util.List; + +@SuppressWarnings("all") +public class ImageResponse { + + @SerializedName("id") + public int id; + + @SerializedName("backdrops") + public List backdropsList; + + @SerializedName("posters") + public List postersList; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/response/MovieResponse.java b/app/src/main/java/org/michaelbel/application/rest/response/MovieResponse.java new file mode 100644 index 000000000..0c41751ac --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/response/MovieResponse.java @@ -0,0 +1,35 @@ +package org.michaelbel.application.rest.response; + +import com.google.gson.annotations.SerializedName; + +import org.michaelbel.application.rest.model.Movie; + +import java.util.List; + +@SuppressWarnings("all") +public class MovieResponse { + + @SerializedName("results") + public List movieList; + + @SerializedName("page") + public int page; + + @SerializedName("total_pages") + public int totalPages; + + @SerializedName("total_results") + public int totalResults; + + @SerializedName("dates") + public ResultDates resultDates; + + public class ResultDates { + + @SerializedName("minimum") + public String minimumDate; + + @SerializedName("maximum") + public String maximumDate; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/response/ReviewResponse.java b/app/src/main/java/org/michaelbel/application/rest/response/ReviewResponse.java new file mode 100644 index 000000000..b001b7558 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/response/ReviewResponse.java @@ -0,0 +1,26 @@ +package org.michaelbel.application.rest.response; + +import com.google.gson.annotations.SerializedName; + +import org.michaelbel.application.rest.model.Review; + +import java.util.List; + +@SuppressWarnings("all") +public class ReviewResponse { + + @SerializedName("id") + public int id; + + @SerializedName("page") + public int page; + + @SerializedName("total_pages") + public int totalPages; + + @SerializedName("total_results") + public int totalResults; + + @SerializedName("results") + public List reviewList; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/rest/response/VideoResponse.java b/app/src/main/java/org/michaelbel/application/rest/response/VideoResponse.java new file mode 100644 index 000000000..1bc66de0d --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/rest/response/VideoResponse.java @@ -0,0 +1,17 @@ +package org.michaelbel.application.rest.response; + +import com.google.gson.annotations.SerializedName; + +import org.michaelbel.application.rest.model.Trailer; + +import java.util.List; + +@SuppressWarnings("all") +public class VideoResponse { + + @SerializedName("id") + public int id; + + @SerializedName("results") + public List trailersList; +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/sqlite/DatabaseHelper.java b/app/src/main/java/org/michaelbel/application/sqlite/DatabaseHelper.java new file mode 100644 index 000000000..7ff04ab10 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/sqlite/DatabaseHelper.java @@ -0,0 +1,178 @@ +package org.michaelbel.application.sqlite; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.michaelbel.application.moviemade.annotation.Beta; +import org.michaelbel.application.rest.model.Movie; + +import java.util.ArrayList; +import java.util.List; + +@Beta +public class DatabaseHelper extends SQLiteOpenHelper { + + private static final int DATABASE_VERSION = 9; + private static final String DATABASE_NAME = "MOVIES_DATABASE"; + + private static final String MOVIES_TABLE = "MOVIES"; + private static final String KEY_MOVIE_ID = "_id"; + private static final String KEY_MOVIE_TMDB_ID = "tmdb_id"; + private static final String KEY_MOVIE_TITLE = "movie_title"; + private static final String KEY_MOVIE_ORIGINAL_TITLE = "movie_original_title"; + private static final String KEY_MOVIE_OVERVIEW = "movie_overview"; + private static final String KEY_MOVIE_RUNTIME = "movie_runtime"; + private static final String KEY_MOVIE_RELEASE_DATE = "movie_release_date"; + private static final String KEY_MOVIE_ISFAVORITE = "movie_favorite"; + private static final String KEY_MOVIE_BACKDROP_PATH = "movie_backdrop_path"; + private static final String KEY_MOVIE_POSTER_PATH = "movie_poster_path"; + + private static volatile DatabaseHelper instance; + + public static synchronized DatabaseHelper getInstance(Context context) { + if (instance == null) { + instance = new DatabaseHelper(context.getApplicationContext()); + } + + return instance; + } + + private DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase database) { + database.execSQL("CREATE TABLE " + MOVIES_TABLE + " (" + + KEY_MOVIE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + KEY_MOVIE_TMDB_ID + " INTEGER, " + + KEY_MOVIE_TITLE + " TEXT, " + + KEY_MOVIE_ORIGINAL_TITLE + " TEXT, " + + KEY_MOVIE_OVERVIEW + " TEXT, " + + KEY_MOVIE_RUNTIME + " INTEGER, " + + KEY_MOVIE_RELEASE_DATE + " TEXT, " + + KEY_MOVIE_ISFAVORITE + " INTEGER, " + + KEY_MOVIE_BACKDROP_PATH + " INTEGER, " + + KEY_MOVIE_POSTER_PATH + " INTEGER) " + ); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + MOVIES_TABLE); + onCreate(db); + } + + public void addMovie(Movie movie) { + ContentValues values = new ContentValues(); + values.put(KEY_MOVIE_TMDB_ID, movie.id); + values.put(KEY_MOVIE_TITLE, movie.title); + values.put(KEY_MOVIE_ORIGINAL_TITLE, movie.originalTitle); + values.put(KEY_MOVIE_OVERVIEW, movie.overview); + values.put(KEY_MOVIE_RUNTIME, movie.runtime); + values.put(KEY_MOVIE_RELEASE_DATE, movie.releaseDate); + values.put(KEY_MOVIE_BACKDROP_PATH, movie.backdropPath); + values.put(KEY_MOVIE_POSTER_PATH, movie.posterPath); + + SQLiteDatabase database = this.getWritableDatabase(); + database.insert(MOVIES_TABLE, null, values); + database.close(); + } + + public void addMovie(int movieId) { + ContentValues values = new ContentValues(); + values.put(KEY_MOVIE_TMDB_ID, movieId); + + SQLiteDatabase database = this.getWritableDatabase(); + database.insert(MOVIES_TABLE, null, values); + database.close(); + } + + public void removeMovie(int movieId) { + SQLiteDatabase database = this.getWritableDatabase(); + database.delete(MOVIES_TABLE, KEY_MOVIE_TMDB_ID + " = ?", new String[]{String.valueOf(movieId)}); + database.close(); + } + + public void updateMovie(Movie movie) { + ContentValues values = new ContentValues(); + values.put(KEY_MOVIE_TITLE, movie.title); + values.put(KEY_MOVIE_ORIGINAL_TITLE, movie.originalTitle); + values.put(KEY_MOVIE_OVERVIEW, movie.overview); + values.put(KEY_MOVIE_RUNTIME, movie.runtime); + values.put(KEY_MOVIE_RELEASE_DATE, movie.releaseDate); + + SQLiteDatabase database = this.getWritableDatabase(); + database.update(MOVIES_TABLE, values, KEY_MOVIE_TMDB_ID + " = ? ", new String[]{String.valueOf(movie.id)}); + database.close(); + } + + public boolean isMovieExist(int tmdbId) { + SQLiteDatabase database = this.getReadableDatabase(); + Cursor cursor = database.rawQuery("SELECT * FROM " + MOVIES_TABLE + " WHERE " + + KEY_MOVIE_TMDB_ID + " = ?", new String[]{String.valueOf(tmdbId)}); + boolean isExist = cursor.getCount() > 0; + cursor.close(); + return isExist; + } + + public boolean isMovieFavorite(int movid_id) { + return false; + } + + public long getMoviesCount() { + SQLiteDatabase database = this.getReadableDatabase(); + long count = DatabaseUtils.queryNumEntries(database, MOVIES_TABLE); + database.close(); + return count; + } + + public Movie getMovie(int tmdbId) { + SQLiteDatabase database = this.getReadableDatabase(); + + Cursor cursor = database.rawQuery("SELECT * FROM " + MOVIES_TABLE + " WHERE " + + KEY_MOVIE_TMDB_ID + " = ?", new String[]{String.valueOf(tmdbId)}); + cursor.moveToFirst(); + + Movie movie = new Movie(); + movie.title = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_TITLE)); + movie.originalTitle = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_ORIGINAL_TITLE)); + movie.overview = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_OVERVIEW)); + movie.runtime = cursor.getInt(cursor.getColumnIndexOrThrow(KEY_MOVIE_RUNTIME)); + movie.releaseDate = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_RELEASE_DATE)); + + cursor.close(); + database.close(); + return movie; + } + + public List getMoviesList() { + List list = new ArrayList<>(); + SQLiteDatabase database = this.getWritableDatabase(); + + try (Cursor cursor = database.rawQuery("SELECT * FROM " + MOVIES_TABLE, null)) { + if (cursor.moveToFirst()) { + do { + Movie movie = new Movie(); + movie.id = cursor.getInt(cursor.getColumnIndexOrThrow(KEY_MOVIE_TMDB_ID)); + movie.title = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_TITLE)); + movie.originalTitle = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_ORIGINAL_TITLE)); + movie.overview = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_OVERVIEW)); + movie.runtime = cursor.getInt(cursor.getColumnIndexOrThrow(KEY_MOVIE_RUNTIME)); + movie.releaseDate = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_RELEASE_DATE)); + movie.backdropPath = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_BACKDROP_PATH)); + movie.posterPath = cursor.getString(cursor.getColumnIndexOrThrow(KEY_MOVIE_POSTER_PATH)); + + list.add(movie); + } while (cursor.moveToNext()); + } + } + + database.close(); + return list; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/AboutActivity.java b/app/src/main/java/org/michaelbel/application/ui/AboutActivity.java new file mode 100644 index 000000000..f50f579b9 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/AboutActivity.java @@ -0,0 +1,51 @@ +package org.michaelbel.application.ui; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.ui.fragment.AboutFragment; + +public class AboutActivity extends AppCompatActivity { + + public Toolbar toolbar; + public TextView toolbarTextView; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); + + toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + toolbarTextView = findViewById(R.id.toolbar_title); + + setRootFragment(new AboutFragment()); + } + + public void setRootFragment(Fragment fragment) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.fragment_layout, fragment) + .commit(); + } + + public void startFragment(Fragment fragment, String tag) { + getSupportFragmentManager() + .beginTransaction() + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) + .replace(R.id.fragment_layout, fragment) + .addToBackStack(tag) + .commit(); + } + + public void finishFragment() { + getSupportFragmentManager().popBackStack(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/FavsActivity.java b/app/src/main/java/org/michaelbel/application/ui/FavsActivity.java new file mode 100644 index 000000000..066e83187 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/FavsActivity.java @@ -0,0 +1,66 @@ +package org.michaelbel.application.ui; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.TabLayout; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.ViewPager; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.widget.TextView; + +import org.michaelbel.application.ui.view.widget.FragmentsPagerAdapter; +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.ui.fragment.FavoriteMoviesFragment; + +public class FavsActivity extends AppCompatActivity { + + public Toolbar toolbar; + public TextView toolbarTextView; + public ViewPager viewPager; + public TabLayout tabLayout; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_favs); + + toolbar = findViewById(R.id.toolbar); + toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + setSupportActionBar(toolbar); + + toolbarTextView = findViewById(R.id.toolbar_title); + toolbarTextView.setText(R.string.MyFavorites); + + FragmentsPagerAdapter adapter = new FragmentsPagerAdapter(this, getSupportFragmentManager()); + adapter.addFragment(new FavoriteMoviesFragment(), R.string.Movies); + + viewPager = findViewById(R.id.view_pager); + viewPager.setAdapter(adapter); + + tabLayout = findViewById(R.id.tab_layout); + tabLayout.setupWithViewPager(viewPager); + tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); + tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER); + tabLayout.setBackgroundColor(ContextCompat.getColor(this, Theme.primaryColor())); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + } + + return super.onOptionsItemSelected(item); + } + + public void startMovie(int movieId, String movieTitle) { + Intent intent = new Intent(this, MovieActivity.class); + intent.putExtra("movieId", movieId); + intent.putExtra("movieTitle", movieTitle); + startActivity(intent); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/MainActivity.java b/app/src/main/java/org/michaelbel/application/ui/MainActivity.java new file mode 100644 index 000000000..0c0659d04 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/MainActivity.java @@ -0,0 +1,292 @@ +package org.michaelbel.application.ui; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.customtabs.CustomTabsServiceConnection; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.TabLayout; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.GravityCompat; +import android.support.v4.view.ViewPager; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.KeyEvent; +import android.view.MenuItem; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.michaelbel.application.ui.view.widget.FragmentsPagerAdapter; +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.ui.fragment.NowPlayingFragment; +import org.michaelbel.application.ui.fragment.PopularFragment; +import org.michaelbel.application.ui.fragment.SearchFragment; +import org.michaelbel.application.ui.fragment.TopRatedFragment; +import org.michaelbel.application.ui.fragment.UpcomingFragment; +import org.michaelbel.application.ui.view.NavigationView; +import org.michaelbel.application.util.KeyboardUtils; + +public class MainActivity extends AppCompatActivity { + + private final int MENU_SEARCH = 10; + + public Toolbar toolbar; + public TextView toolbarTextView; + public ViewPager viewPager; + public TabLayout tabLayout; + + public DrawerLayout drawerLayout; + public AppBarLayout appBarLayout; + public NavigationView navigationView; + + public FrameLayout searchViewLayout; + + private String requestToken; + private CustomTabsServiceConnection connection; + private Uri uri; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + setTheme(R.style.AppThemeLight); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + //getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + //getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + //getWindow().setStatusBarColor(0x33000000); + + toolbar = findViewById(R.id.toolbar); + toolbar.setNavigationIcon(R.drawable.ic_menu); + setSupportActionBar(toolbar); + + toolbarTextView = findViewById(R.id.toolbar_title); + toolbarTextView.setText(R.string.AppName); + + drawerLayout = findViewById(R.id.drawer); + appBarLayout = findViewById(R.id.app_bar); + + navigationView = findViewById(R.id.navigation_view); + navigationView.setOnNavigationItemSelectedListener((view, position) -> { + drawerLayout.closeDrawer(GravityCompat.START); + + if (position == 2) { + startActivity(new Intent(this, FavsActivity.class)); + } else if (position == 4) { + startActivity(new Intent(this, SettingsActivity.class)); + } else if (position == 5) { + startActivity(new Intent(this, AboutActivity.class)); + } + }); + /*navigationView.setOnNavigationHeaderClick(new NavigationView.OnNavigationHeaderClickListener() { + @Override + public void onHeaderClick(View view) { + createRequestToken(); + } + });*/ + + viewPager = findViewById(R.id.view_pager); + + FragmentsPagerAdapter adapter = new FragmentsPagerAdapter(this, getSupportFragmentManager()); + adapter.addFragment(new NowPlayingFragment(), R.string.NowPlaying); + adapter.addFragment(new PopularFragment(), R.string.Popular); + adapter.addFragment(new TopRatedFragment(), R.string.TopRated); + adapter.addFragment(new UpcomingFragment(), R.string.Upcoming); + viewPager.setAdapter(adapter); + + tabLayout = findViewById(R.id.tab_layout); + tabLayout.setupWithViewPager(viewPager); + tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); + tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER); + tabLayout.setBackgroundColor(ContextCompat.getColor(this, Theme.primaryColor())); + + searchViewLayout = findViewById(R.id.search_fragment_view); + searchViewLayout.setBackgroundColor(0xFFFFFFFF); + searchViewLayout.setVisibility(View.INVISIBLE); + } + + /*@Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(0, MENU_SEARCH, Menu.NONE, "Search") + .setIcon(R.drawable.ic_search) + .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM) + .setOnMenuItemClickListener(item -> { + startActivity(new Intent(MainActivity.this, SearchActivity.class)); + return true; + }); + + return super.onCreateOptionsMenu(menu); + }*/ + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + if (drawerLayout != null) { + drawerLayout.openDrawer(GravityCompat.START); + } + } + + return super.onOptionsItemSelected(item); + } + + @Override + public void onBackPressed() { + if (drawerLayout != null && drawerLayout.isDrawerOpen(GravityCompat.START)) { + drawerLayout.closeDrawer(GravityCompat.START); + } else { + super.onBackPressed(); + } + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + + /*Toast.makeText(this, "Получилось!", Toast.LENGTH_SHORT).show(); + createSession(); + + String action = intent.getAction(); + String data = intent.getDataString(); + if (Intent.ACTION_VIEW.equals(action) && data != null) { + try { + Toast.makeText(this, "Получилось!", Toast.LENGTH_SHORT).show(); + drawerLayout.openDrawer(GravityCompat.START); + createSession(); + } catch (Exception e) { + FirebaseCrash.report(e); + } + }*/ + } + + @Override + public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_MENU) { + if (!drawerLayout.isDrawerOpen(GravityCompat.START)) { + if (getCurrentFocus() != null) { + KeyboardUtils.hideKeyboard(getCurrentFocus()); + drawerLayout.openDrawer(GravityCompat.START); + } + } else { + drawerLayout.closeDrawer(GravityCompat.START); + } + } + return super.onKeyUp(keyCode, event); + } + + public void startMovie(int movieId, String movieTitle) { + Intent intent = new Intent(this, MovieActivity.class); + intent.putExtra("movieId", movieId); + intent.putExtra("movieTitle", movieTitle); + startActivity(intent); + } + + public void startSearchFragment() { + searchViewLayout.setVisibility(View.VISIBLE); + + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.search_fragment_view, new SearchFragment()) + .commit(); + } + + public void finishSearchFragment() { + searchViewLayout.setVisibility(View.INVISIBLE); + } + + /*@Override + protected void onResume() { + super.onResume(); + Intent intent = getIntent(); + + String action = intent.getAction(); + String data = intent.getDataString(); + if (Intent.ACTION_VIEW.equals(action) && data != null) { + try { + Toast.makeText(this, "Получилось!", Toast.LENGTH_SHORT).show(); + drawerLayout.openDrawer(GravityCompat.START); + createSession(); + } catch (Exception e) { + FirebaseCrash.report(e); + } + } + }*/ + + /*private void createRequestToken() { + AUTHENTICATION service = ApiFactory.getRetrofit().create(AUTHENTICATION.class); + Call call = service.createRequestToken(Url.TMDB_API_KEY); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Auth.CreatedRequest request = response.body(); + requestToken = request.request_token; + + uri = Uri.parse("https://www.themoviedb.org/authenticate/" + requestToken + "?redirect_to=anything://auth_callback_anything"); + + connection = new CustomTabsServiceConnection() { + @Override + public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) { + CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); + CustomTabsIntent intent = builder.build(); + client.warmup(0L); + intent.launchUrl(MainActivity.this, uri); + + client.newSession(new CustomTabsCallback() { + @Override + public void onNavigationEvent(int navigationEvent, Bundle extras) { + //super.onNavigationEvent(navigationEvent, extras); + if (navigationEvent == NAVIGATION_FINISHED) { + Toast.makeText(MainActivity.this, "Это успех", Toast.LENGTH_SHORT).show(); + } + } + }); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + + } + }; + + if (requestToken != null) { + CustomTabsClient.bindCustomTabsService(MainActivity.this, "com.android.chrome", connection); + //Browser.openUrl(MainActivity.this, "https://www.themoviedb.org/authenticate/" + requestToken + "?redirect_to=anything://auth_callback_anything"); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + FirebaseCrash.report(t); + } + }); + } + + private void createSession() { + AUTHENTICATION service = ApiFactory.getRetrofit().create(AUTHENTICATION.class); + Call call = service.createSession(Url.TMDB_API_KEY, requestToken); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Auth.Session session = response.body(); + + if (session.sessionId != null) { + SharedPreferences preferences = getSharedPreferences("user_config", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("session_id", session.sessionId); + editor.apply(); + } + + Toast.makeText(MainActivity.this, "Session id получен", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onFailure(Call call, Throwable t) { + FirebaseCrash.report(t); + } + }); + }*/ +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/MovieActivity.java b/app/src/main/java/org/michaelbel/application/ui/MovieActivity.java new file mode 100644 index 000000000..cffd1cc87 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/MovieActivity.java @@ -0,0 +1,129 @@ +package org.michaelbel.application.ui; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.TabLayout; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.ViewPager; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuItem; +import android.view.WindowManager; +import android.widget.TextView; + +import org.michaelbel.application.ui.view.widget.FragmentsPagerAdapter; +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.ui.fragment.CastMovieFragment; +import org.michaelbel.application.ui.fragment.MovieFragment; +import org.michaelbel.application.ui.fragment.RelatedMovieFragment; +import org.michaelbel.application.ui.fragment.ReviewsMovieFragment; +import org.michaelbel.application.ui.fragment.SimilarMoviesFragment; + +public class MovieActivity extends AppCompatActivity { + + private int movieId; + private String movieTitle; + + public Toolbar toolbar; + public ViewPager viewPager; + public TabLayout tabLayout; + public TextView toolbarTextView; + public AppBarLayout appBarLayout; + public FloatingActionButton fabButton; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_movie); + + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + getWindow().setStatusBarColor(0x33000000); + + if (savedInstanceState == null) { + movieId = getIntent().getIntExtra("movieId", 0); + movieTitle = getIntent().getStringExtra("movieTitle"); + } + + toolbar = findViewById(R.id.toolbar); + toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + setSupportActionBar(toolbar); + + toolbarTextView = findViewById(R.id.toolbar_title); + toolbarTextView.setText(movieTitle); + + appBarLayout = findViewById(R.id.app_bar); + fabButton = findViewById(R.id.fab_button); + viewPager = findViewById(R.id.view_pager); + + FragmentsPagerAdapter adapter = new FragmentsPagerAdapter(this, getSupportFragmentManager()); + adapter.addFragment(MovieFragment.newInstance(movieId), "Info"); + adapter.addFragment(CastMovieFragment.newInstance(movieId), "Cast"); + adapter.addFragment(ReviewsMovieFragment.newInstance(movieId), "Reviews"); + adapter.addFragment(SimilarMoviesFragment.newInstance(movieId), "Similar"); + adapter.addFragment(RelatedMovieFragment.newInstance(movieId), "Related"); + viewPager.setAdapter(adapter); + + tabLayout = findViewById(R.id.tab_layout); + tabLayout.setupWithViewPager(viewPager); + tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); + tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER); + tabLayout.setBackgroundColor(ContextCompat.getColor(this, Theme.primaryColor())); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(R.string.Share) + .setIcon(R.drawable.ic_share) + .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM) + .setOnMenuItemClickListener(menuItem -> { + try { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, Url.TMDB_MOVIE + movieId); + startActivity(Intent.createChooser(intent, getString(R.string.ShareVia))); + return true; + } catch (Exception e) { + //FirebaseCrash.report(e); + return false; + } + }); + + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + } + + return super.onOptionsItemSelected(item); + } + + public void startMovie(int movieId, String movieTitle) { + Intent intent = new Intent(this, MovieActivity.class); + intent.putExtra("movieId", movieId); + intent.putExtra("movieTitle", movieTitle); + startActivity(intent); + } + + public void startPerson(int personId, String personName) { + Intent intent = new Intent(this, PersonActivity.class); + intent.putExtra("personId", personId); + intent.putExtra("personName", personName); + startActivity(intent); + } + + public void startReview(String reviewId) { + Intent intent = new Intent(this, ReviewActivity.class); + intent.putExtra("reviewId", reviewId); + startActivity(intent); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/PersonActivity.java b/app/src/main/java/org/michaelbel/application/ui/PersonActivity.java new file mode 100644 index 000000000..a6e980ae2 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/PersonActivity.java @@ -0,0 +1,74 @@ +package org.michaelbel.application.ui; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.TabLayout; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.ViewPager; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.widget.TextView; + +import org.michaelbel.application.ui.view.widget.FragmentsPagerAdapter; +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.ui.fragment.PersonFragment; + +public class PersonActivity extends AppCompatActivity { + + private int personId; + private String personName; + + public Toolbar toolbar; + public TextView toolbarTextView; + public ViewPager viewPager; + public TabLayout tabLayout; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_person); + + if (savedInstanceState == null) { + personId = getIntent().getIntExtra("personId", 0); + personName = getIntent().getStringExtra("personName"); + } + + toolbar = findViewById(R.id.toolbar); + toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + setSupportActionBar(toolbar); + + toolbarTextView = findViewById(R.id.toolbar_title); + toolbarTextView.setText(personName); + + FragmentsPagerAdapter adapter = new FragmentsPagerAdapter(this, getSupportFragmentManager()); + adapter.addFragment(PersonFragment.newInstance(personId, personName), R.string.Info); + + viewPager = findViewById(R.id.view_pager); + viewPager.setAdapter(adapter); + + tabLayout = findViewById(R.id.tab_layout); + tabLayout.setupWithViewPager(viewPager); + tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); + tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER); + tabLayout.setBackgroundColor(ContextCompat.getColor(this, Theme.primaryColor())); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + } + + return super.onOptionsItemSelected(item); + } + + public void startMovie(int movieId, String movieTitle) { + Intent intent = new Intent(this, MovieActivity.class); + intent.putExtra("movieId", movieId); + intent.putExtra("movieTitle", movieTitle); + startActivity(intent); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/ReviewActivity.java b/app/src/main/java/org/michaelbel/application/ui/ReviewActivity.java new file mode 100644 index 000000000..03f60116f --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/ReviewActivity.java @@ -0,0 +1,40 @@ +package org.michaelbel.application.ui; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.ui.fragment.ReviewDetailsFragment; + +public class ReviewActivity extends AppCompatActivity { + + public Toolbar toolbar; + public TextView toolbarTextView; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_review); + + toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + toolbarTextView = findViewById(R.id.toolbar_title); + + if (savedInstanceState == null) { + String reviewId = getIntent().getStringExtra("reviewId"); + setRootFragment(ReviewDetailsFragment.newInstance(reviewId)); + } + } + + public void setRootFragment(Fragment fragment) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.fragment_layout, fragment) + .commit(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/SearchActivity.java b/app/src/main/java/org/michaelbel/application/ui/SearchActivity.java new file mode 100644 index 000000000..102ab0967 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/SearchActivity.java @@ -0,0 +1,67 @@ +package org.michaelbel.application.ui; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.TabLayout; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.ViewPager; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.widget.TextView; + +import org.michaelbel.application.ui.view.widget.FragmentsPagerAdapter; +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.ui.fragment.SearchFragment; + +public class SearchActivity extends AppCompatActivity { + + public Toolbar toolbar; + public TextView toolbarTextView; + public ViewPager viewPager; + public TabLayout tabLayout; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_search); + + toolbar = findViewById(R.id.toolbar); + toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + setSupportActionBar(toolbar); + + toolbarTextView = findViewById(R.id.toolbar_title); + + SearchFragment fragment = new SearchFragment(); + + FragmentsPagerAdapter adapter = new FragmentsPagerAdapter(this, getSupportFragmentManager()); + adapter.addFragment(fragment, "Movies"); + + viewPager = findViewById(R.id.view_pager); + viewPager.setAdapter(adapter); + + tabLayout = findViewById(R.id.tab_layout); + tabLayout.setupWithViewPager(viewPager); + tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); + tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER); + tabLayout.setBackgroundColor(ContextCompat.getColor(this, Theme.primaryColor())); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + } + + return super.onOptionsItemSelected(item); + } + + public void startMovie(int movieId, String movieTitle) { + Intent intent = new Intent(this, MovieActivity.class); + intent.putExtra("movieId", movieId); + intent.putExtra("movieTitle", movieTitle); + startActivity(intent); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/SettingsActivity.java b/app/src/main/java/org/michaelbel/application/ui/SettingsActivity.java new file mode 100644 index 000000000..7897c75fb --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/SettingsActivity.java @@ -0,0 +1,51 @@ +package org.michaelbel.application.ui; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.ui.fragment.SettingsFragment; + +public class SettingsActivity extends AppCompatActivity { + + public Toolbar toolbar; + public TextView toolbarTextView; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); + + toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + toolbarTextView = findViewById(R.id.toolbar_title); + + setRootFragment(new SettingsFragment()); + } + + public void setRootFragment(Fragment fragment) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.fragment_layout, fragment) + .commit(); + } + + public void startFragment(Fragment fragment, String tag) { + getSupportFragmentManager() + .beginTransaction() + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) + .replace(R.id.fragment_layout, fragment) + .addToBackStack(tag) + .commit(); + } + + public void finishFragment() { + getSupportFragmentManager().popBackStack(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/TrailersActivity.java b/app/src/main/java/org/michaelbel/application/ui/TrailersActivity.java new file mode 100644 index 000000000..56980b538 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/TrailersActivity.java @@ -0,0 +1,40 @@ +package org.michaelbel.application.ui; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; + +import org.michaelbel.application.R; +import org.michaelbel.application.ui.fragment.TrailersFragment; +import org.michaelbel.application.ui.view.TitleView; + +public class TrailersActivity extends AppCompatActivity { + + public Toolbar toolbar; + public TitleView titleView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_trailers); + + toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + titleView = findViewById(R.id.toolbar_title); + + if (savedInstanceState == null) { + int movieId = getIntent().getIntExtra("movieId", 0); + String title = getIntent().getStringExtra("movieTitle"); + startFragment(TrailersFragment.newInstance(movieId, title)); + } + } + + public void startFragment(Fragment fragment) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.fragment_layout, fragment) + .commit(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/adapter/Holder.java b/app/src/main/java/org/michaelbel/application/ui/adapter/Holder.java new file mode 100644 index 000000000..fe9cc91b0 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/adapter/Holder.java @@ -0,0 +1,12 @@ +package org.michaelbel.application.ui.adapter; + +import android.support.v7.widget.RecyclerView; +import android.view.View; + +@SuppressWarnings("all") +public class Holder extends RecyclerView.ViewHolder { + + public Holder(View itemView) { + super(itemView); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/adapter/MoviesListAdapter.java b/app/src/main/java/org/michaelbel/application/ui/adapter/MoviesListAdapter.java new file mode 100644 index 000000000..4ab6c82ca --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/adapter/MoviesListAdapter.java @@ -0,0 +1,88 @@ +package org.michaelbel.application.ui.adapter; + +import android.content.Context; +import android.content.SharedPreferences; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.annotation.Beta; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.ui.view.LoadingView; +import org.michaelbel.application.ui.view.movie.MovieViewCard; +import org.michaelbel.application.ui.view.MovieViewCompat; +import org.michaelbel.application.ui.view.movie.MovieViewList; + +import java.util.List; + +@Beta +public class MoviesListAdapter extends RecyclerView.Adapter { + + private Context context; + private List list; + + public MoviesListAdapter(Context context, List items) { + this.context = context; + this.list = items; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { + View view; + + if (type == 0) { + view = new MovieViewCard(context); + } else if (type == 1) { + view = new MovieViewList(context); + } else if (type == 2) { + view = new MovieViewCompat(context); + } else { + view = new LoadingView(context); + } + + return new Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + Movie movie = list.get(position); + + if (getItemViewType(position) == 0) { + MovieViewCard view = (MovieViewCard) holder.itemView; + view.getPosterImage().setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, 150)); + view.setPoster(movie.posterPath) + .setTitle(movie.title) + .setYear(movie.releaseDate); + } else if (getItemViewType(position) == 1) { + //MovieViewList view = (MovieViewList) holder.itemView; + //view.setMovie(movie); + } else if (getItemViewType(position) == 2) { + MovieViewCompat view = (MovieViewCompat) holder.itemView; + view.setMovie(movie); + } else { + LoadingView view = (LoadingView) holder.itemView; + } + } + + @Override + public int getItemCount() { + return list != null ? list.size() : 0; + } + + @Override + public int getItemViewType(int position) { + SharedPreferences preferences = context.getSharedPreferences("main_config", Context.MODE_PRIVATE); + int viewType = preferences.getInt("view_type", 0); + + if (viewType == 0) { + return 0; + } else if (viewType == 1) { + return 1; + } else if (viewType == 2) { + return 2; + } else { + return 3; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/AboutFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/AboutFragment.java new file mode 100644 index 000000000..77f808b5b --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/AboutFragment.java @@ -0,0 +1,246 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.graphics.Typeface; +import android.net.Uri; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.browser.Browser; +import org.michaelbel.application.ui.AboutActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.cell.EmptyCell; +import org.michaelbel.application.ui.view.cell.TextCell; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.ScreenUtils; + +public class AboutFragment extends Fragment { + + private int rowCount; + private int infoRow; + private int forkGithubRow; + private int libsRow; + private int helpRow; + private int feedbackRow; + private int emptyRow; + + /*private int rateGooglePlayRow; + private int shareFriendsRow; + private int supportDevRow; + private int translationsRow; + private int analyticsInfoRow; + private int analyticsRow;*/ + + private AboutAdapter adapter; + private AboutActivity activity; + private LinearLayoutManager layoutManager; + + private RecyclerListView recyclerView; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (AboutActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_about, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + activity.toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + activity.toolbar.setNavigationOnClickListener(view -> activity.finish()); + activity.toolbarTextView.setText(R.string.About); + + rowCount = 0; + infoRow = rowCount++; + forkGithubRow = rowCount++; + libsRow = rowCount++; + helpRow = rowCount++; + feedbackRow = rowCount++; + emptyRow = rowCount++; + + adapter = new AboutAdapter(); + layoutManager = new LinearLayoutManager(activity); + + recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setOnItemClickListener((view1, position) -> { + if (position == forkGithubRow) { + Browser.openUrl(activity, "https://github.com/michaelbel/moviemade"); + } else if (position == feedbackRow) { + try { + PackageManager packageManager = activity.getPackageManager(); + PackageInfo packageInfo = packageManager.getPackageInfo("org.telegram.messenger", 0); + if (packageInfo != null) { + Intent telegram = new Intent(Intent.ACTION_VIEW , Uri.parse("https://t.me/michaelbel")); + startActivity(telegram); + } else { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_EMAIL, "michael-bel@outlook.com"); + intent.putExtra(Intent.EXTRA_SUBJECT, "Subject"); + intent.putExtra(Intent.EXTRA_TEXT, ""); + startActivity(Intent.createChooser(intent, "Feedback")); + } + } catch (PackageManager.NameNotFoundException e) { + + } + } else if (position == libsRow) { + activity.startFragment(new LibsFragment(), "libsFragment"); + } + }); + + return fragmentView; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Parcelable state = layoutManager.onSaveInstanceState(); + layoutManager = new LinearLayoutManager(getContext()); + recyclerView.setLayoutManager(layoutManager); + layoutManager.onRestoreInstanceState(state); + } + + private class AboutAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { + View view; + + if (type == 0) { + view = new AboutView(activity); + } else if (type == 1) { + view = new EmptyCell(activity); + } else { + view = new TextCell(activity); + } + + return new Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + int type = getItemViewType(position); + + if (type == 1) { + EmptyCell cell = (EmptyCell) holder.itemView; + cell.changeLayoutParams(); + + if (position == helpRow) { + cell.setMode(EmptyCell.MODE_TEXT); + cell.setText(getString(R.string.ProjectInfo, getString(R.string.AppName))); + } else if (position == emptyRow) { + cell.setMode(EmptyCell.MODE_DEFAULT); + cell.setHeight(ScreenUtils.dp(12)); + } + } else if (type == 2) { + TextCell cell = (TextCell) holder.itemView; + cell.changeLayoutParams(); + + if (position == forkGithubRow) { + cell.setText(R.string.ForkGithub); + cell.setDivider(true); + } else if (position == libsRow) { + cell.setHeight(ScreenUtils.dp(52)); + cell.setText(R.string.OpenSourceLibs); + } else if (position == feedbackRow) { + cell.setHeight(ScreenUtils.dp(52)); + cell.setText(R.string.Feedback); + } + } + } + + @Override + public int getItemCount() { + return rowCount; + } + + @Override + public int getItemViewType(int position) { + if (position == infoRow) { + return 0; + } else if (position == helpRow || position == emptyRow) { + return 1; + } else { + return 2; + } + } + } + + public class AboutView extends LinearLayout { + + private ImageView iconImageView; + private TextView nameTextView; + private TextView versionTextView; + + public AboutView(Context context) { + super(context); + + setOrientation(VERTICAL); + setPadding(ScreenUtils.dp(24), ScreenUtils.dp(24), ScreenUtils.dp(24), ScreenUtils.dp(24)); + + iconImageView = new ImageView(context); + iconImageView.setImageResource(R.mipmap.ic_launcher); + iconImageView.setLayoutParams(LayoutHelper.makeLinear(110, 110, Gravity.CENTER_HORIZONTAL)); + addView(iconImageView); + + nameTextView = new TextView(context); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20); + nameTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + nameTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + nameTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 5, 0, 0)); + addView(nameTextView); + + versionTextView = new TextView(context); + versionTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + versionTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + versionTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 4, 0, 0)); + addView(versionTextView); + + setVersion(); + } + + private void setVersion() { + try { + PackageInfo packageInfo = getContext().getPackageManager() + .getPackageInfo(getContext().getPackageName(), 0); + nameTextView.setText(getString(R.string.AppNameForAndroid, getString(R.string.AppName))); + versionTextView.setText(getString(R.string.VersionBuild, packageInfo.versionName, packageInfo.versionCode)); + } catch (Exception e) { + // todo report + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY); + int height = getMeasuredHeight(); + setMeasuredDimension(width, height); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/CastMovieFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/CastMovieFragment.java new file mode 100644 index 000000000..8d0bb3b0d --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/CastMovieFragment.java @@ -0,0 +1,144 @@ +package org.michaelbel.application.ui.fragment; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Cast; +import org.michaelbel.application.rest.response.CreditResponse; +import org.michaelbel.application.ui.MovieActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.CastView; +import org.michaelbel.application.ui.view.widget.RecyclerListView; + +import java.util.ArrayList; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +@SuppressWarnings("all") +public class CastMovieFragment extends Fragment { + + private int movieId; + + private CastAdapter adapter; + private MovieActivity activity; + private LinearLayoutManager layoutManager; + private List list = new ArrayList<>(); + + private RecyclerListView recyclerView; + + public static CastMovieFragment newInstance(int movieId) { + Bundle args = new Bundle(); + args.putInt("movieId", movieId); + + CastMovieFragment fragment = new CastMovieFragment(); + fragment.setArguments(args); + return fragment; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (MovieActivity) getActivity(); + + FrameLayout fragmentView = new FrameLayout(activity); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + + adapter = new CastAdapter(); + layoutManager = new LinearLayoutManager(activity); + + recyclerView = new RecyclerListView(activity); + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setVerticalScrollBarEnabled(true); + recyclerView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + /*recyclerView.setOnItemClickListener((view1, position) -> { + Cast cast = list.getTypeface(position); + activity.startPerson(cast.id, cast.name); + });*/ + recyclerView.setOnItemLongClickListener((view, position) -> { + + return true; + }); + fragmentView.addView(recyclerView); + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (getArguments() != null) { + movieId = getArguments().getInt("movieId"); + } + + loadCredits(); + } + + private void loadCredits() { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getCredits(movieId, Url.TMDB_API_KEY); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + if (!list.isEmpty()) { + list.clear(); + } + list.addAll(response.body().castList); + adapter.notifyDataSetChanged(); + + if (list.isEmpty()) { + + } + } else { + //FirebaseCrash.report(new Error("Server not found")); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + } + }); + } + + private class CastAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new Holder(new CastView(activity)); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { + Cast cast = list.get(position); + + CastView view = (CastView) holder.itemView; + view.setName(cast.name) + .setCharacter(cast.character) + .setProfileImage(cast.profilePath) + .setDivider(position != list.size() - 1); + } + + @Override + public int getItemCount() { + return list != null ? list.size() : 0; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/FavoriteMoviesFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/FavoriteMoviesFragment.java new file mode 100644 index 000000000..acde18fd3 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/FavoriteMoviesFragment.java @@ -0,0 +1,247 @@ +package org.michaelbel.application.ui.fragment; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.AppLoader; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.sqlite.DatabaseHelper; +import org.michaelbel.application.ui.FavsActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.widget.PaddingItemDecoration; +import org.michaelbel.application.ui.view.movie.MovieViewCard; +import org.michaelbel.application.ui.view.movie.MovieViewPoster; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.AppUtils; +import org.michaelbel.application.util.ScreenUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class FavoriteMoviesFragment extends Fragment { + + private FavsActivity activity; + private MovieAdapter adapter; + private GridLayoutManager layoutManager; + private PaddingItemDecoration itemDecoration; + private List movieList = new ArrayList<>(); + + private TextView emptyView; + private RecyclerListView recyclerView; + private SwipeRefreshLayout refreshLayout; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (FavsActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_favs, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + emptyView = fragmentView.findViewById(R.id.empty_view); + + refreshLayout = fragmentView.findViewById(R.id.swipe_refresh_layout); + refreshLayout.setColorSchemeResources(Theme.accentColor()); + refreshLayout.setOnRefreshListener(this :: loadMovies); + + SharedPreferences prefs = activity.getSharedPreferences("mainconfig", Context.MODE_PRIVATE); + int type = prefs.getInt("view_type", 0); + + adapter = new MovieAdapter(); + layoutManager = new GridLayoutManager(activity, getLayoutColumns()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + + itemDecoration = new PaddingItemDecoration(); + if (type == 0) { + itemDecoration.setOffset(ScreenUtils.dp(2)); + } else { + itemDecoration.setOffset(ScreenUtils.dp(1)); + } + + recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setLayoutManager(layoutManager); + recyclerView.addItemDecoration(itemDecoration); + if (type == 0) { + recyclerView.setPadding(ScreenUtils.dp(4), 0, ScreenUtils.dp(4), 0); + } + recyclerView.setOnItemClickListener((view1, position) -> { + Movie movie = movieList.get(position); + activity.startMovie(movie.id, movie.title); + }); + + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + loadMovies(); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + MenuItem viewItem = menu.add(R.string.ChangeViewType); + viewItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM); + + SharedPreferences prefs = activity.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + int viewType = prefs.getInt("view_type", 0); + + if (viewType == 0) { + viewItem.setIcon(R.drawable.ic_view_default); + } else if (viewType == 1) { + viewItem.setIcon(R.drawable.ic_view_compat); + } + + viewItem.setOnMenuItemClickListener(item -> { + int newType = prefs.getInt("view_type", 0); + + if (newType == 0) { + viewItem.setIcon(R.drawable.ic_view_compat); + newType = 1; + } else if (newType == 1) { + viewItem.setIcon(R.drawable.ic_view_default); + newType = 0; + } + + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt("view_type", newType); + editor.apply(); + + refreshLayout(); + return true; + }); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + layoutManager.setSpanCount(AppUtils.getColumns()); + } + + private void loadMovies() { + if (!movieList.isEmpty()) { + movieList.clear(); + } + + DatabaseHelper database = DatabaseHelper.getInstance(activity); + if (database.getMoviesList().isEmpty()) { + onLoadError(); + } else { + movieList.addAll(database.getMoviesList()); + Collections.reverse(movieList); + onLoadSuccessful(); + } + adapter.notifyDataSetChanged(); + database.close(); + } + + private void onLoadError() { + emptyView.setText(R.string.NoMovies); + refreshLayout.setRefreshing(false); + } + + private void onLoadSuccessful() { + refreshLayout.setRefreshing(false); + } + + private void refreshLayout() { + SharedPreferences prefs = activity.getSharedPreferences("mainconfig", Context.MODE_PRIVATE); + int type = prefs.getInt("view_type", 0); + + Parcelable state = layoutManager.onSaveInstanceState(); + layoutManager = new GridLayoutManager(activity, getLayoutColumns()); + recyclerView.setLayoutManager(layoutManager); + recyclerView.removeItemDecoration(itemDecoration); + if (type == 0) { + itemDecoration.setOffset(ScreenUtils.dp(2)); + recyclerView.addItemDecoration(itemDecoration); + recyclerView.setPadding(ScreenUtils.dp(4), 0, ScreenUtils.dp(4), 0); + } else { + itemDecoration.setOffset(ScreenUtils.dp(1)); + recyclerView.addItemDecoration(itemDecoration); + recyclerView.setPadding(0, 0, 0, 0); + } + layoutManager.onRestoreInstanceState(state); + } + + public int getLayoutColumns() { + SharedPreferences prefs = AppLoader.AppContext.getSharedPreferences("mainconfig", Context.MODE_PRIVATE); + int viewType = prefs.getInt("view_type", 0); + + if (viewType == 0) { + return ScreenUtils.isPortrait() ? 3 : 5; + } else { + return ScreenUtils.isPortrait() ? 2 : 3; + } + } + + public class MovieAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { + View view; + + if (type == 0) { + view = new MovieViewCard(activity); + } else { + view = new MovieViewPoster(activity); + } + + return new Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + Movie movie = movieList.get(position); + + if (getItemViewType(position) == 0) { + MovieViewCard view = (MovieViewCard) holder.itemView; + view.getPosterImage().setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, 150)); + view.setPoster(movie.posterPath) + .setTitle(movie.title) + .setYear(movie.releaseDate); + } else { + MovieViewPoster view = (MovieViewPoster) holder.itemView; + view.setPoster(movie.posterPath); + } + } + + @Override + public int getItemCount() { + return movieList != null ? movieList.size() : 0; + } + + @Override + public int getItemViewType(int position) { + SharedPreferences prefs = activity.getSharedPreferences("mainconfig", Context.MODE_PRIVATE); + return prefs.getInt("view_type", 0); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/ImageQualityFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/ImageQualityFragment.java new file mode 100644 index 000000000..b5908b331 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/ImageQualityFragment.java @@ -0,0 +1,263 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.ui.SettingsActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.cell.EmptyCell; +import org.michaelbel.application.ui.view.cell.TextCell; +import org.michaelbel.application.ui.view.cell.TextDetailCell; +import org.michaelbel.application.ui.view.widget.RecyclerListView; + +@SuppressWarnings("all") +public class ImageQualityFragment extends Fragment { + + private int rowCount; + private int backdropRow; + private int logoRow; + private int posterRow; + private int profileRow; + private int stillRow; + + private ListAdapter adapter; + private SharedPreferences prefs; + private SettingsActivity activity; + private LinearLayoutManager layoutManager; + + private RecyclerListView recyclerView; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (SettingsActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_about, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + + activity.toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + activity.toolbar.setNavigationOnClickListener(view -> activity.finishFragment()); + activity.toolbarTextView.setText(R.string.ImageQuality); + + rowCount = 0; + backdropRow = rowCount++; + logoRow = rowCount++; + posterRow = rowCount++; + profileRow = rowCount++; + stillRow = rowCount++; + + adapter = new ListAdapter(); + layoutManager = new LinearLayoutManager(activity); + prefs = activity.getSharedPreferences("main_config", Context.MODE_PRIVATE); + + recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setOnItemClickListener((view1, position) -> { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + + if (position == backdropRow) { + builder.setTitle("Backdrop"); + + String[] items = new String[] { + "w300", "w780", "w1280", "original" + }; + + builder.setItems(items, (dialogInterface, which) -> { + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("image_quality_backdrop", items[which]); + editor.putBoolean("image_quality_settings_customize", true); + editor.apply(); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + }); + } else if (position == logoRow) { + builder.setTitle("Logo"); + + String[] items = new String[] { + "w45", "w92", "w154", "w185", "w300", "w500", "original" + }; + + builder.setItems(items, (dialogInterface, which) -> { + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("image_quality_logo", items[which]); + editor.putBoolean("image_quality_settings_customize", true); + editor.apply(); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + }); + } else if (position == posterRow) { + builder.setTitle("Poster"); + + String[] items = new String[] { + "w92", "w154", "w185", "w342", "w500", "w780", "original" + }; + + builder.setItems(items, (dialogInterface, which) -> { + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("image_quality_poster", items[which]); + editor.putBoolean("image_quality_settings_customize", true); + editor.apply(); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + }); + } else if (position == profileRow) { + builder.setTitle("Profile"); + + String[] items = new String[] { + "w45", "w185", "w632", "original" + }; + + builder.setItems(items, (dialogInterface, which) -> { + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("image_quality_profile", items[which]); + editor.putBoolean("image_quality_settings_customize", true); + editor.apply(); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + }); + } else if (position == stillRow) { + builder.setTitle("Still"); + + String[] items = new String[] { + "w92", "w185", "w300", "original" + }; + + builder.setItems(items, (dialogInterface, which) -> { + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("image_quality_still", items[which]); + editor.putBoolean("image_quality_settings_customize", true); + editor.apply(); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + }); + } + + builder.setNegativeButton(R.string.Cancel, null); + builder.show(); + }); + + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Parcelable state = layoutManager.onSaveInstanceState(); + layoutManager = new LinearLayoutManager(getContext()); + recyclerView.setLayoutManager(layoutManager); + layoutManager.onRestoreInstanceState(state); + } + + public class ListAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { + View cell; + + if (type == 1) { + cell = new EmptyCell(activity); + } else if (type == 2) { + cell = new TextDetailCell(activity); + } else { + cell = new TextCell(activity); + } + + return new Holder(cell); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + int type = getItemViewType(position); + + if (type == 1) { + EmptyCell cell = (EmptyCell) holder.itemView; + cell.setMode(EmptyCell.MODE_DEFAULT); + } else if (type == 2) { + TextDetailCell cell = (TextDetailCell) holder.itemView; + cell.setMode(TextDetailCell.MODE_SWITCH); + cell.changeLayoutParams(); + } else { + TextCell cell = (TextCell) holder.itemView; + cell.changeLayoutParams(); + + if (position == backdropRow) { + String quality = prefs.getString("image_quality_backdrop", "w780"); + cell.setMode(TextCell.MODE_VALUE_TEXT); + cell.setText("Backdrop"); + cell.setValue(quality); + cell.setDivider(true); + } else if (position == logoRow) { + String quality = prefs.getString("image_quality_logo", "w185"); + cell.setMode(TextCell.MODE_VALUE_TEXT); + cell.setText("Logo"); + cell.setValue(quality); + cell.setDivider(true); + } else if (position == posterRow) { + String quality = prefs.getString("image_quality_poster", "w342"); + cell.setMode(TextCell.MODE_VALUE_TEXT); + cell.setText("Poster"); + cell.setValue(quality); + cell.setDivider(true); + } else if (position == profileRow) { + String quality = prefs.getString("image_quality_profile", "w185"); + cell.setMode(TextCell.MODE_VALUE_TEXT); + cell.setText("Profile"); + cell.setValue(quality); + cell.setDivider(true); + } else if (position == stillRow) { + String quality = prefs.getString("image_quality_still", "w185"); + cell.setMode(TextCell.MODE_VALUE_TEXT); + cell.setText("Still"); + cell.setValue(quality); + } + } + } + + @Override + public int getItemCount() { + return rowCount; + } + + @Override + public int getItemViewType(int position) { + if (position == -900) { + return 0; + } else if (position == -800) { + return 1; + } else if (position == -700) { + return 2; + } else { + return 3; + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/LibsFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/LibsFragment.java new file mode 100644 index 000000000..36cc6314c --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/LibsFragment.java @@ -0,0 +1,146 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.Toast; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.browser.Browser; +import org.michaelbel.application.ui.AboutActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.cell.TextDetailCell; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.ScreenUtils; +import org.michaelbel.bottomsheet.BottomSheet; + +import java.util.ArrayList; +import java.util.List; + +public class LibsFragment extends Fragment { + + private ListAdapter adapter; + private AboutActivity activity; + private LinearLayoutManager layoutManager; + private List list = new ArrayList<>(); + + private RecyclerListView recyclerView; + + private class Source { + + public String url; + public String name; + public String license; + + public Source(String name, String url, String license) { + this.url = url; + this.name = name; + this.license = license; + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (AboutActivity) getActivity(); + + FrameLayout fragmentView = new FrameLayout(activity); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + + activity.toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + activity.toolbar.setNavigationOnClickListener(view -> activity.finishFragment()); + activity.toolbarTextView.setText(R.string.OpenSourceLibs); + + list.add(new Source("BottomSheet", "https://github.com/michaelbel/bottomsheet","Apache License v2.0")); + list.add(new Source("Retrofit", "https://square.github.io/retrofit","Apache License v2.0")); + list.add(new Source("RxJava", "https://github.com/reactivex/rxjava","Apache License v2.0")); + list.add(new Source("RxAndroid", "https://github.com/reactivex/rxjava","Apache License v2.0")); + list.add(new Source("Realm Java", "https://github.com/realm/realm-java", "Apache License v2.0")); + list.add(new Source("Glide", "https://bumptech.github.io/glide/","BSD, MIT and Apache License v2.0")); + + adapter = new ListAdapter(); + layoutManager = new LinearLayoutManager(activity); + + recyclerView = new RecyclerListView(activity); + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + recyclerView.setOnItemClickListener((view1, position) -> { + Browser.openUrl(activity, list.get(position).url); + }); + recyclerView.setOnItemLongClickListener((view, position) -> { + BottomSheet.Builder builder = new BottomSheet.Builder(activity); + builder.setTitle(list.get(position).url); + builder.setTitleTextColor(ContextCompat.getColor(activity, Theme.secondaryTextColor())); + builder.setBackgroundColor(ContextCompat.getColor(activity, Theme.foregroundColor())); + builder.setItemTextColor(ContextCompat.getColor(activity, Theme.primaryTextColor())); + builder.setCellHeight(ScreenUtils.dp(52)); + builder.setItems(new int[] { R.string.Open, R.string.CopyLink }, (dialogInterface, i) -> { + if (i == 0) { + Browser.openUrl(activity, list.get(position).url); + } else if (i == 1) { + ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("Link", list.get(position).url); + if (clipboard != null) { + clipboard.setPrimaryClip(clip); + } + + Toast.makeText(activity, R.string.LinkCopied, Toast.LENGTH_SHORT).show(); + } + }); + builder.show(); + return true; + }); + fragmentView.addView(recyclerView); + + return fragmentView; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Parcelable state = layoutManager.onSaveInstanceState(); + layoutManager = new LinearLayoutManager(activity); + recyclerView.setLayoutManager(layoutManager); + layoutManager.onRestoreInstanceState(state); + } + + public class ListAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { + return new Holder(new TextDetailCell(activity)); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + Source source = list.get(position); + + TextDetailCell cell = (TextDetailCell) holder.itemView; + cell.changeLayoutParams(); + cell.setText(source.name); + cell.setValue(source.license); + cell.setDivider(position != list.size() - 1); + } + + @Override + public int getItemCount() { + return list != null ? list.size() : 0; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/MovieFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/MovieFragment.java new file mode 100644 index 000000000..6735f428a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/MovieFragment.java @@ -0,0 +1,276 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.NestedScrollView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.moviemade.browser.Browser; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Backdrop; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.model.Poster; +import org.michaelbel.application.rest.response.CreditResponse; +import org.michaelbel.application.rest.response.ImageResponse; +import org.michaelbel.application.rest.response.VideoResponse; +import org.michaelbel.application.sqlite.DatabaseHelper; +import org.michaelbel.application.ui.MovieActivity; +import org.michaelbel.application.ui.TrailersActivity; +import org.michaelbel.application.ui.view.FavButton; +import org.michaelbel.application.ui.view.MovieInfoLayout; +import org.michaelbel.application.util.NetworkUtils; + +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class MovieFragment extends Fragment { + + private int movieId; + private Movie currentMovie; + private MovieActivity activity; + + private TextView emptyView; + private ProgressBar progressBar; + private MovieInfoLayout movieView; + private NestedScrollView nestedScrollView; + + public static MovieFragment newInstance(int movieId) { + Bundle args = new Bundle(); + args.putInt("movieId", movieId); + + MovieFragment fragment = new MovieFragment(); + fragment.setArguments(args); + return fragment; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle args) { + activity = (MovieActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_movie, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + nestedScrollView = fragmentView.findViewById(R.id.scroll_view); + + movieView = new MovieInfoLayout(getContext()); + movieView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + nestedScrollView.addView(movieView); + + if (getArguments() != null) { + movieId = getArguments().getInt("movieId"); + } + + emptyView = fragmentView.findViewById(R.id.empty_view); + emptyView.setText(R.string.NoConnection); + emptyView.setVisibility(View.INVISIBLE); + + progressBar = fragmentView.findViewById(R.id.progress_bar); + + movieView.setVisibility(View.GONE); + movieView.setListener(new MovieInfoLayout.InfoMovieListener() { + @Override + public boolean onOverviewLongClick(View view) { + return true; + } + + @Override + public void onTrailersSectionClick(View view) { + Intent intent = new Intent(activity, TrailersActivity.class); + intent.putExtra("movieId", movieId); + intent.putExtra("movieTitle", currentMovie.title); + startActivity(intent); + + } + + @Override + public void onTrailerClick(View view, String trailerKey) { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:" + trailerKey))); + } + + @Override + public boolean onTrailerLongClick(View view, String trailerKey) { + return true; + } + + @Override + public void onMovieUrlClick(View view, int position) { + if (position == 1) { + Browser.openUrl(activity, "https://themoviedb.org/movie/" + movieId); + } else if (position == 2) { + Browser.openUrl(activity, "http://imdb.com/title/" + currentMovie.imdbId); + } else if (position == 3) { + Browser.openUrl(activity, currentMovie.homepage); + } + } + + @Override + public void onFavButtonClick(View view) { + DatabaseHelper database = DatabaseHelper.getInstance(activity); + boolean isExist = database.isMovieExist(movieId); + + if (isExist) { + database.removeMovie(movieId); + if (view instanceof FavButton) { + ((FavButton) view).setIcon(R.drawable.ic_heart_outline); + ((FavButton) view).setText(R.string.Add); + } + } else { + database.addMovie(currentMovie); + if (view instanceof FavButton) { + ((FavButton) view).setIcon(R.drawable.ic_heart); + ((FavButton) view).setText(R.string.Remove); + } + } + } + }); + movieView.setCallback(() -> { + progressBar.setVisibility(View.INVISIBLE); + movieView.setVisibility(View.VISIBLE); + }); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + progressBar.setVisibility(View.INVISIBLE); + emptyView.setVisibility(View.VISIBLE); + } else { + loadMovieDetails(movieId); + } + } + + private void loadMovieDetails(int movieId) { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getDetails(movieId, Url.TMDB_API_KEY, Url.en_US, null); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + currentMovie = response.body(); + displayMovie(currentMovie); + } else { + //FirebaseCrash.report(new Error("Server not found")); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + } + }); + } + + private void displayMovie(Movie movie) { + movieView.setPoster(movie.posterPath); + movieView.setTitle(movie.title); + movieView.setGenres(movie.genresList); + movieView.setDate(movie.releaseDate); + movieView.setRuntime(movie.runtime); + movieView.setCountries(movie.countriesList); + movieView.setStatus(movie.status); + movieView.setTagline(movie.tagline); + movieView.setBudget(movie.budget); + movieView.setRevenue(movie.revenue); + movieView.setOriginalTitle(movie.originalTitle); + movieView.setOriginalLang(movie.originalLanguage); + movieView.setCompanies(movie.companiesList); + movieView.setVoteAverage(movie.voteAverage); + movieView.setVoteCount(movie.voteCount); + movieView.setOverview(movie.overview); + movieView.setHomePage(movie.homepage); + movieView.setFavButton(movie.id); + + loadTrailers(movie.id); + loadImages(movie.id); + loadCredits(movie.id); + } + + private void loadTrailers(int movieId) { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getVideos(movieId, Url.TMDB_API_KEY, Url.en_US); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + movieView.setTrailers(response.body().trailersList); + } else { + //FirebaseCrash.report(new Error("Server not found")); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + } + }); + } + + private void loadImages(int movieId) { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getImages(movieId, Url.TMDB_API_KEY, null); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + List posterList = response.body().postersList; + List backdropList = response.body().backdropsList; + + String poster1 = posterList.get(0).filePath; + String backdrop1 = backdropList.get(0).filePath; + + movieView.setImages(poster1, backdrop1, posterList.size(), backdropList.size()); + } else { + //FirebaseCrash.report(new Error("Server not found")); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + } + }); + } + + private void loadCredits(int movieId) { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getCredits(movieId, Url.TMDB_API_KEY); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + movieView.setCrew(response.body().crewList); + } else { + //FirebaseCrash.report(new Error("Server not found")); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/NowPlayingFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/NowPlayingFragment.java new file mode 100644 index 000000000..956dc53ec --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/NowPlayingFragment.java @@ -0,0 +1,205 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.response.MovieResponse; +import org.michaelbel.application.ui.MainActivity; +import org.michaelbel.application.ui.adapter.MoviesListAdapter; +import org.michaelbel.application.ui.view.widget.PaddingItemDecoration; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.AppUtils; +import org.michaelbel.application.util.NetworkUtils; +import org.michaelbel.application.util.ScreenUtils; + +import java.util.ArrayList; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class NowPlayingFragment extends Fragment { + + private static final int TOTAL_PAGES = 1000; + + private int page; + private boolean isLoading; + + private TextView emptyView; + private SwipeRefreshLayout refreshLayout; + + private MainActivity activity; + private MoviesListAdapter adapter; + private GridLayoutManager layoutManager; + private ArrayList movieList = new ArrayList<>(); + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (MainActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_nowplaying, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + emptyView = fragmentView.findViewById(R.id.empty_view); + + refreshLayout = fragmentView.findViewById(R.id.swipe_refresh_layout); + refreshLayout.setColorSchemeResources(Theme.accentColor()); + if (movieList.isEmpty()) { + refreshLayout.setRefreshing(true); + } + refreshLayout.setOnRefreshListener(() -> { + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + if (movieList.isEmpty()) { + getNowPlaying(); + } else { + refreshLayout.setRefreshing(false); + } + } + }); + + page = 1; + adapter = new MoviesListAdapter(activity, movieList); + + layoutManager = new GridLayoutManager(getContext(), AppUtils.getColumns()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + + RecyclerListView recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setPadding(ScreenUtils.dp(4), 0, ScreenUtils.dp(4), 0); + recyclerView.addItemDecoration(new PaddingItemDecoration(ScreenUtils.dp(2))); + recyclerView.setOnItemClickListener((view1, position) -> { + Movie movie = movieList.get(position); + activity.startMovie(movie.id, movie.title); + }); + recyclerView.setOnItemLongClickListener((view, position) -> { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setItems(new CharSequence[] { + "Add to Watchlist", + "Add to Favorite" + }, (dialogInterface, i) -> { + if (i == 0) { + Toast.makeText(activity, "Added to WATCHLIST", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(activity, "Added to FAVORITE", Toast.LENGTH_SHORT).show(); + } + }); + //builder.show(); + return false; + }); + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (layoutManager.findLastVisibleItemPosition() == movieList.size() - 1 && !isLoading) { + if (page < TOTAL_PAGES) { + getNowPlaying(); + } + } + } + }); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + getNowPlaying(); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + layoutManager.setSpanCount(AppUtils.getColumns()); + } + + private void getNowPlaying() { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getNowPlaying(Url.TMDB_API_KEY, Url.en_US, page); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + SharedPreferences prefs = activity.getSharedPreferences("main_config", Context.MODE_PRIVATE); + boolean adult = prefs.getBoolean("adult", true); + + if (adult) { + movieList.addAll(response.body().movieList); + } else { + for (Movie movie : response.body().movieList) { + if (!movie.adult) { + movieList.add(movie); + } + } + } + + adapter.notifyDataSetChanged(); + + if (movieList.isEmpty()) { + emptyView.setText(R.string.NoMovies); + } else { + page++; + isLoading = false; + } + + onLoadSuccessful(); + } else { + //FirebaseCrash.report(new Error("Server not found")); + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + onLoadError(); + isLoading = false; + } + }); + + isLoading = true; + } + + private void onLoadSuccessful() { + refreshLayout.setRefreshing(false); + } + + private void onLoadError() { + refreshLayout.setRefreshing(false); + emptyView.setText(R.string.NoConnection); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/PersonFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/PersonFragment.java new file mode 100644 index 000000000..f668033cd --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/PersonFragment.java @@ -0,0 +1,185 @@ +package org.michaelbel.application.ui.fragment; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.NestedScrollView; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.PEOPLE; +import org.michaelbel.application.rest.model.Person; +import org.michaelbel.application.ui.PersonActivity; +import org.michaelbel.application.ui.view.EmptyView; +import org.michaelbel.application.util.NetworkUtils; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class PersonFragment extends Fragment { + + private int personId; + private String personName; + + private Person currentPerson; + private PersonActivity activity; + + private EmptyView emptyView; + private ProgressBar progressBar; + private NestedScrollView nestedScrollView; + + private ImageView posterImageView; + private TextView bornTextView; + private TextView bioTextView; + + public static PersonFragment newInstance(int personId, String personName) { + Bundle args = new Bundle(); + args.putInt("personId", personId); + args.putString("personName", personName); + + PersonFragment fragment = new PersonFragment(); + fragment.setArguments(args); + return fragment; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle args) { + activity = (PersonActivity) getActivity(); + setHasOptionsMenu(true); + + View fragmentView = inflater.inflate(R.layout.fragment_person, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + + if (getArguments() != null) { + personId = getArguments().getInt("personId"); + personName = getArguments().getString("personName"); + } + + FrameLayout topLayout = fragmentView.findViewById(R.id.top_layout); + topLayout.setBackgroundColor(ContextCompat.getColor(activity, Theme.foregroundColor())); + + posterImageView = new ImageView(activity); + posterImageView.setScaleType(ImageView.ScaleType.CENTER); + posterImageView.setImageResource(R.drawable.movie_placeholder); + posterImageView.setLayoutParams(LayoutHelper.makeFrame(110, 180, + Gravity.START | Gravity.TOP, 16, 16, 0, 16)); + topLayout.addView(posterImageView); + + LinearLayout bornLayout = new LinearLayout(activity); + bornLayout.setOrientation(LinearLayout.VERTICAL); + bornLayout.setBackgroundColor(ContextCompat.getColor(activity, Theme.foregroundColor())); + bornLayout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + Gravity.BOTTOM, 110 + 16 + 16, 0, 16, 16)); + topLayout.addView(bornLayout); + + TextView bornTitle = new TextView(activity); + bornTitle.setText("Born"); + bornTitle.setTextColor(ContextCompat.getColor(activity, Theme.primaryTextColor())); + bornTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + bornLayout.addView(bornTitle); + + bornTextView = new TextView(activity); + bornTextView.setTextColor(ContextCompat.getColor(activity, Theme.secondaryTextColor())); + bornTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0)); + bornLayout.addView(bornTextView); + + LinearLayout bioLayout = fragmentView.findViewById(R.id.bio_layout); + bioLayout.setBackgroundColor(ContextCompat.getColor(activity, Theme.foregroundColor())); + + bioTextView = new TextView(activity); + bioTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + bioTextView.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL)); + bioTextView.setTextColor(ContextCompat.getColor(activity, Theme.secondaryTextColor())); + bioTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, 16, 16, 16, 16)); + bioLayout.addView(bioTextView); + + nestedScrollView = fragmentView.findViewById(R.id.nested_scroll); + nestedScrollView.setVisibility(View.INVISIBLE); + + progressBar = fragmentView.findViewById(R.id.progress_bar); + + emptyView = fragmentView.findViewById(R.id.empty_view); + emptyView.setVisibility(View.INVISIBLE); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + progressBar.setVisibility(View.INVISIBLE); + nestedScrollView.setVisibility(View.INVISIBLE); + emptyView.setVisibility(View.VISIBLE); + } else { + loadPersonDetails(personId); + } + } + + private void loadPersonDetails(int personId) { + PEOPLE service = ApiFactory.getRetrofit().create(PEOPLE.class); + Call call = service.getDetails(personId, Url.TMDB_API_KEY, Url.en_US, null); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + currentPerson = response.body(); + startPerson(currentPerson); + } else { + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + onLoadError(); + } + }); + } + + private void startPerson(Person person) { + Glide.with(activity) + .load("http://image.tmdb.org/t/p/w500/" + person.profilePath) + .into(posterImageView); + + bornTextView.setText(person.birthday + ", " + person.birthPlace); + bioTextView.setText(person.bio); + + onLoadSuccessful(); + } + + private void onLoadSuccessful() { + progressBar.setVisibility(View.INVISIBLE); + nestedScrollView.setVisibility(View.VISIBLE); + } + + private void onLoadError() { + progressBar.setVisibility(View.INVISIBLE); + nestedScrollView.setVisibility(View.INVISIBLE); + emptyView.setVisibility(View.VISIBLE); + emptyView.setText(R.string.NoConnection); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/PopularFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/PopularFragment.java new file mode 100644 index 000000000..7d2dc08b8 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/PopularFragment.java @@ -0,0 +1,191 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.moviemade.annotation.Beta; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.response.MovieResponse; +import org.michaelbel.application.ui.MainActivity; +import org.michaelbel.application.ui.adapter.MoviesListAdapter; +import org.michaelbel.application.ui.view.widget.PaddingItemDecoration; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.AppUtils; +import org.michaelbel.application.util.NetworkUtils; +import org.michaelbel.application.util.ScreenUtils; + +import java.util.ArrayList; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +@Beta +public class PopularFragment extends Fragment { + + private static final int TOTAL_PAGES = 1000; + + private int page; + private boolean isLoading; + + private TextView emptyView; + private SwipeRefreshLayout refreshLayout; + + private MainActivity activity; + private MoviesListAdapter adapter; + private GridLayoutManager layoutManager; + private List movieList = new ArrayList<>(); + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (MainActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_nowplaying, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + emptyView = fragmentView.findViewById(R.id.empty_view); + + refreshLayout = fragmentView.findViewById(R.id.swipe_refresh_layout); + refreshLayout.setColorSchemeResources(Theme.accentColor()); + if (movieList.isEmpty()) { + refreshLayout.setRefreshing(true); + } + refreshLayout.setOnRefreshListener(() -> { + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + if (movieList.isEmpty()) { + getPopular(); + } else { + refreshLayout.setRefreshing(false); + } + } + }); + + page = 1; + adapter = new MoviesListAdapter(activity, movieList); + + layoutManager = new GridLayoutManager(getContext(), AppUtils.getColumns()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + + RecyclerListView recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setPadding(ScreenUtils.dp(4), 0, ScreenUtils.dp(4), 0); + recyclerView.addItemDecoration(new PaddingItemDecoration(ScreenUtils.dp(2))); + recyclerView.setOnItemClickListener((view1, position) -> { + Movie movie = movieList.get(position); + activity.startMovie(movie.id, movie.title); + }); + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (layoutManager.findLastVisibleItemPosition() == movieList.size() - 1 && !isLoading) { + if (page < TOTAL_PAGES) { + getPopular(); + } + } + } + }); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + getPopular(); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + layoutManager.setSpanCount(AppUtils.getColumns()); + } + + private void getPopular() { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getPopular(Url.TMDB_API_KEY, Url.en_US, page); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + SharedPreferences prefs = activity.getSharedPreferences("main_config", Context.MODE_PRIVATE); + boolean adult = prefs.getBoolean("adult", true); + + if (adult) { + movieList.addAll(response.body().movieList); + } else { + for (Movie movie : response.body().movieList) { + if (!movie.adult) { + movieList.add(movie); + } + } + } + + adapter.notifyDataSetChanged(); + + if (movieList.isEmpty()) { + emptyView.setText(R.string.NoMovies); + } else { + page++; + isLoading = false; + } + + onLoadSuccessful(); + } else { + //FirebaseCrash.report(new Error("Server not found")); + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + onLoadError(); + isLoading = false; + } + }); + + isLoading = true; + } + + private void onLoadSuccessful() { + refreshLayout.setRefreshing(false); + } + + private void onLoadError() { + refreshLayout.setRefreshing(false); + emptyView.setText(R.string.NoConnection); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/RelatedMovieFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/RelatedMovieFragment.java new file mode 100644 index 000000000..376c509ea --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/RelatedMovieFragment.java @@ -0,0 +1,216 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.response.MovieResponse; +import org.michaelbel.application.ui.MovieActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.movie.MovieViewList; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.NetworkUtils; + +import java.util.ArrayList; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class RelatedMovieFragment extends Fragment { + + private static final int TOTAL_PAGES = 1000; + + private int movieId; + + private int page; + private boolean isLoading; + + private TextView emptyView; + private SwipeRefreshLayout refreshLayout; + + private MovieActivity activity; + private RelatedAdapter adapter; + private LinearLayoutManager layoutManager; + private List list = new ArrayList<>(); + + public static RelatedMovieFragment newInstance(int movieId) { + Bundle args = new Bundle(); + args.putInt("movieId", movieId); + + RelatedMovieFragment fragment = new RelatedMovieFragment(); + fragment.setArguments(args); + return fragment; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (MovieActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_favs, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + if (getArguments() != null) { + movieId = getArguments().getInt("movieId"); + } + + emptyView = fragmentView.findViewById(R.id.empty_view); + + refreshLayout = fragmentView.findViewById(R.id.swipe_refresh_layout); + refreshLayout.setColorSchemeResources(Theme.accentColor()); + if (list.isEmpty()) { + refreshLayout.setRefreshing(true); + } + refreshLayout.setOnRefreshListener(() -> { + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + if (list.isEmpty()) { + getRelatedMovies(); + } else { + refreshLayout.setRefreshing(false); + } + } + }); + + page = 1; + adapter = new RelatedAdapter(); + layoutManager = new LinearLayoutManager(activity); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + + RecyclerListView recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setVerticalScrollBarEnabled(true); + recyclerView.setOnItemClickListener((view1, position) -> { + Movie movie = list.get(position); + activity.startMovie(movie.id, movie.title); + }); + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (layoutManager.findLastVisibleItemPosition() == list.size() - 1 && !isLoading) { + if (page < TOTAL_PAGES) { + getRelatedMovies(); + } + } + } + }); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + getRelatedMovies(); + } + } + + private void getRelatedMovies() { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + service.getRecommendations(movieId, Url.TMDB_API_KEY, Url.en_US, page) + .enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + SharedPreferences prefs = activity.getSharedPreferences("main_config", Context.MODE_PRIVATE); + boolean adult = prefs.getBoolean("adult", true); + + if (adult) { + list.addAll(response.body().movieList); + } else { + for (Movie movie : response.body().movieList) { + if (!movie.adult) { + list.add(movie); + } + } + } + + adapter.notifyDataSetChanged(); + + if (list.isEmpty()) { + emptyView.setText(R.string.NoMovies); + } else { + page++; + isLoading = false; + } + + onLoadSuccessful(); + } else { + //FirebaseCrash.report(new Error("Server not found")); + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + onLoadError(); + isLoading = false; + } + }); + + isLoading = true; + } + + private void onLoadSuccessful() { + refreshLayout.setRefreshing(false); + } + + private void onLoadError() { + refreshLayout.setRefreshing(false); + emptyView.setText(R.string.NoConnection); + } + + public class RelatedAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { + return new Holder(new MovieViewList(activity)); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + Movie movie = list.get(position); + + MovieViewList view = (MovieViewList) holder.itemView; + view.setPoster(movie.posterPath) + .setTitle(movie.title) + .setYear(movie.releaseDate) + .setVoteAverage(movie.voteAverage) + .setDivider(position != list.size() - 1); + } + + @Override + public int getItemCount() { + return list != null ? list.size() : 0; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/ReviewDetailsFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/ReviewDetailsFragment.java new file mode 100644 index 000000000..827bb92ef --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/ReviewDetailsFragment.java @@ -0,0 +1,166 @@ +package org.michaelbel.application.ui.fragment; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.moviemade.browser.Browser; +import org.michaelbel.application.rest.api.REVIEWS; +import org.michaelbel.application.rest.model.Review; +import org.michaelbel.application.ui.ReviewActivity; +import org.michaelbel.application.ui.view.EmptyView; +import org.michaelbel.application.ui.view.widget.GestureTextView; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class ReviewDetailsFragment extends Fragment { + + private String reviewId; + private String reviewUrl; + private String reviewAuthor; + private String mediaTitle; + + private ReviewActivity activity; + + private TextView mediaTitleText; + private TextView authorTextView; + private GestureTextView reviewTextView; + private EmptyView emptyView; + private ProgressBar progressBar; + + public static ReviewDetailsFragment newInstance(String reviewId) { + Bundle args = new Bundle(); + args.putString("reviewId", reviewId); + + ReviewDetailsFragment fragment = new ReviewDetailsFragment(); + fragment.setArguments(args); + return fragment; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (ReviewActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_review_details, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + activity.toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + activity.toolbar.setNavigationOnClickListener(view -> activity.finish()); + activity.toolbarTextView.setText("Review details"); + + emptyView = fragmentView.findViewById(R.id.empty_view); + emptyView.setImage(R.drawable.review_placeholder); + emptyView.setVisibility(View.INVISIBLE); + + progressBar = fragmentView.findViewById(R.id.progress_bar); + + mediaTitleText = fragmentView.findViewById(R.id.media_title); + mediaTitleText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + mediaTitleText.setTextColor(ContextCompat.getColor(activity, Theme.primaryTextColor())); + mediaTitleText.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + + authorTextView = fragmentView.findViewById(R.id.review_author); + authorTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + authorTextView.setTextColor(ContextCompat.getColor(activity, Theme.primaryTextColor())); + authorTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + + reviewTextView = fragmentView.findViewById(R.id.review_text); + reviewTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + reviewTextView.setTextColor(ContextCompat.getColor(activity, Theme.secondaryTextColor())); + reviewTextView.getController().getSettings().setMaxZoom(2.0F); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (getArguments() != null) { + reviewId = getArguments().getString("reviewId"); + loadReview(); + } else { + progressBar.setVisibility(View.INVISIBLE); + emptyView.setVisibility(View.VISIBLE); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) { + menu.add(R.string.OpenReviewUrl) + .setIcon(R.drawable.ic_url) + .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM) + .setOnMenuItemClickListener(menuItem -> { + if (reviewUrl != null) { + Browser.openUrl(activity, reviewUrl); + } else { + Toast.makeText(getContext(), "Review url is not accessed", Toast.LENGTH_SHORT).show(); + } + + return true; + }); + } + + private void loadReview() { + REVIEWS service = ApiFactory.getRetrofit().create(REVIEWS.class); + Call call = service.getDetails(reviewId, Url.TMDB_API_KEY); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + Review review = response.body(); + + if (review != null) { + mediaTitleText.setText(review.mediaTitle); + authorTextView.setText("Author: " + review.author); + reviewTextView.setText(review.content); + reviewUrl = review.url; + + onLoadSuccessful(); + } else { + onLoadError(); + } + } else { + //FirebaseCrash.report(new Error("Server not found")); + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + onLoadError(); + } + }); + } + + private void onLoadError() { + progressBar.setVisibility(View.INVISIBLE); + emptyView.setVisibility(View.VISIBLE); + } + + private void onLoadSuccessful() { + progressBar.setVisibility(View.INVISIBLE); + emptyView.setVisibility(View.INVISIBLE); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/ReviewsMovieFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/ReviewsMovieFragment.java new file mode 100644 index 000000000..f7b608490 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/ReviewsMovieFragment.java @@ -0,0 +1,174 @@ +package org.michaelbel.application.ui.fragment; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Review; +import org.michaelbel.application.rest.response.ReviewResponse; +import org.michaelbel.application.ui.MovieActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.ReviewView; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.NetworkUtils; + +import java.util.ArrayList; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class ReviewsMovieFragment extends Fragment { + + private static final String MOVIE_ID = "movie_id"; + + private int movieId; + + private ReviewsAdapter adapter; + private MovieActivity activity; + private ArrayList reviewList = new ArrayList<>(); + + private TextView emptyView; + private SwipeRefreshLayout refreshLayout; + + public static ReviewsMovieFragment newInstance(int movieId) { + Bundle args = new Bundle(); + args.putInt(MOVIE_ID, movieId); + + ReviewsMovieFragment fragment = new ReviewsMovieFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (MovieActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_review, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + + emptyView = fragmentView.findViewById(R.id.empty_view); + emptyView.setTextColor(ContextCompat.getColor(activity, Theme.secondaryTextColor())); + + refreshLayout = fragmentView.findViewById(R.id.swipe_refresh_layout); + refreshLayout.setColorSchemeResources(Theme.accentColor()); + refreshLayout.setRefreshing(true); + refreshLayout.setOnRefreshListener(() -> { + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + if (reviewList.isEmpty()) { + getReviews(); + } else { + refreshLayout.setRefreshing(false); + } + } + }); + + adapter = new ReviewsAdapter(); + + RecyclerListView recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setLayoutManager(new LinearLayoutManager(activity)); + recyclerView.setOnItemClickListener((view, position) -> + activity.startReview(reviewList.get(position).id) + ); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (getArguments() != null) { + movieId = getArguments().getInt(MOVIE_ID); + } + + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + getReviews(); + } + } + + private void getReviews() { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getReviews(movieId, Url.TMDB_API_KEY, Url.en_US, 1); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + if (!reviewList.isEmpty()) { + reviewList.clear(); + } + + reviewList.addAll(response.body().reviewList); + adapter.notifyDataSetChanged(); + + if (reviewList.isEmpty()) { + emptyView.setText(R.string.NoReviews); + } + + onLoadSuccessful(); + } else { + //FirebaseCrash.report(new Error("Server not found")); + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + onLoadError(); + } + }); + } + + private void onLoadSuccessful() { + refreshLayout.setRefreshing(false); + } + + private void onLoadError() { + refreshLayout.setRefreshing(false); + emptyView.setText(R.string.NoConnection); + } + + public class ReviewsAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new Holder(new ReviewView(getContext())); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { + Review review = reviewList.get(position); + + ReviewView view = (ReviewView) holder.itemView; + view.setAuthor(review.author); + view.setContent(review.content); + view.setDivider(position != reviewList.size() - 1); + } + + @Override + public int getItemCount() { + return reviewList != null ? reviewList.size() : 0; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/SearchFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/SearchFragment.java new file mode 100644 index 000000000..06c01abd8 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/SearchFragment.java @@ -0,0 +1,200 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.SearchView; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AutoCompleteTextView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.SEARCH; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.response.MovieResponse; +import org.michaelbel.application.ui.SearchActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.MovieViewList2; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.KeyboardUtils; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class SearchFragment extends Fragment { + + private SearchActivity activity; + private SearchMovieAdapter adapter; + private List searchResults = new ArrayList<>(); + + private TextView emptyView; + private ProgressBar progressBar; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (SearchActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_search, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + progressBar = fragmentView.findViewById(R.id.progress_bar); + progressBar.setVisibility(View.INVISIBLE); + + emptyView = fragmentView.findViewById(R.id.empty_view); + emptyView.setTextColor(ContextCompat.getColor(activity, Theme.secondaryTextColor())); + emptyView.setText(R.string.NoResults); + + adapter = new SearchMovieAdapter(); + + RecyclerListView recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setVerticalScrollBarEnabled(true); + recyclerView.setLayoutManager(new LinearLayoutManager(activity)); + recyclerView.setOnItemClickListener((view1, position) -> { + Movie movie = searchResults.get(position); + activity.startMovie(movie.id, movie.title); + }); + return fragmentView; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.search_item, menu); + + MenuItem searchItem = menu.findItem(R.id.action_search); + + SearchView searchView = (SearchView) searchItem.getActionView(); + //searchView.setIconifiedByDefault(false); + searchView.setQueryHint(getString(R.string.Search)); + searchView.setMaxWidth(getResources().getDisplayMetrics().widthPixels); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + search(query); + KeyboardUtils.hideKeyboard(searchView); + return true; + } + + @Override + public boolean onQueryTextChange(String newText) { + return true; + } + }); + + AutoCompleteTextView searchTextView = searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text); + Theme.clearCursorDrawable(searchTextView); + try { + Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); + mCursorDrawableRes.setAccessible(true); + mCursorDrawableRes.set(searchTextView, null); + } catch (Exception e) { + } + searchTextView.setTextColor(ContextCompat.getColor(activity, Theme.foregroundColor())); + + + super.onCreateOptionsMenu(menu, inflater); + } + + private void search(String query) { + searchResults.clear(); + emptyView.setVisibility(View.INVISIBLE); + progressBar.setVisibility(View.VISIBLE); + performSearch(query); + } + + public void performSearch(String query) { + String finalQuery = query.trim().replace(" ", "-"); + + SEARCH service = ApiFactory.getRetrofit().create(SEARCH.class); + Call call = service.searchMovies(Url.SEARCH_FOR_MOVIES, Url.TMDB_API_KEY, Url.en_US, finalQuery); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + SharedPreferences prefs = activity.getSharedPreferences("main_config", Context.MODE_PRIVATE); + boolean adult = prefs.getBoolean("adult", true); + + if (adult) { + searchResults.addAll(response.body().movieList); + } else { + for (Movie movie : response.body().movieList) { + if (!movie.adult) { + searchResults.add(movie); + } + } + } + + adapter.notifyDataSetChanged(); + + if (searchResults.isEmpty()) { + emptyView.setVisibility(View.VISIBLE); + emptyView.setText(R.string.NoResults); + } + + onLoadSuccessful(); + } else { + //FirebaseCrash.report(new Error("Server not found")); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + } + }); + } + + private void onLoadSuccessful() { + progressBar.setVisibility(View.INVISIBLE); + } + + public class SearchMovieAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { + return new Holder(new MovieViewList2(activity)); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + Movie movie = searchResults.get(position); + + MovieViewList2 view = (MovieViewList2) holder.itemView; + view.setPoster(movie.posterPath); + view.setTitle(movie.title); + view.setYear(movie.releaseDate); + view.setRating(movie.voteAverage); + view.setDivider(position != searchResults.size() - 1); + view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + } + + @Override + public int getItemCount() { + return searchResults != null ? searchResults.size() : 0; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/SettingsFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/SettingsFragment.java new file mode 100644 index 000000000..0e7ac65b8 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/SettingsFragment.java @@ -0,0 +1,239 @@ +package org.michaelbel.application.ui.fragment; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.ui.SettingsActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.cell.EmptyCell; +import org.michaelbel.application.ui.view.cell.TextCell; +import org.michaelbel.application.ui.view.cell.TextDetailCell; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.ScreenUtils; +import org.michaelbel.bottomsheet.BottomSheet; + +public class SettingsFragment extends Fragment { + + private int rowCount; + private int imageQualityRow; + private int inAppBrowserRow; + private int adultRow; + private int emptyRow; + + private ListAdapter adapter; + private SharedPreferences prefs; + private SettingsActivity activity; + private LinearLayoutManager layoutManager; + + private RecyclerListView recyclerView; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (SettingsActivity) getActivity(); + + FrameLayout fragmentView = new FrameLayout(activity); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + + activity.toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + activity.toolbar.setNavigationOnClickListener(view -> activity.finish()); + activity.toolbarTextView.setText(R.string.Settings); + + rowCount = 0; + imageQualityRow = rowCount++; + adultRow = rowCount++; + inAppBrowserRow = rowCount++; + emptyRow = rowCount++; + + adapter = new ListAdapter(); + layoutManager = new LinearLayoutManager(activity); + prefs = activity.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + + recyclerView = new RecyclerListView(activity); + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + recyclerView.setOnItemClickListener((view, position) -> { + if (position == imageQualityRow) { + BottomSheet.Builder builder = new BottomSheet.Builder(activity); + builder.setBackgroundColor(ContextCompat.getColor(activity, Theme.foregroundColor())); + builder.setItemTextColor(ContextCompat.getColor(activity, Theme.primaryTextColor())); + builder.setCellHeight(ScreenUtils.dp(52)); + builder.setItems(new int[] { R.string.ImageQualityLow, R.string.ImageQualityMedium, R.string.ImageQualityHigh, R.string.ImageQualityOriginal}, (dialogInterface, i) -> { + String imageQualityBackdrop; + String imageQualityLogo; + String imageQualityPoster; + String imageQualityProfile; + String imageQualityStill; + + String imageQuality; + + if (i == 0) { + imageQuality = getString(R.string.ImageQualityLow); + + imageQualityBackdrop = "w300"; + imageQualityLogo = "w45"; + imageQualityPoster = "w92"; + imageQualityProfile = "w45"; + imageQualityStill = "w92"; + } else if (i == 1) { + imageQuality = getString(R.string.ImageQualityMedium); + + imageQualityBackdrop = "w780"; + imageQualityLogo = "w185"; + imageQualityPoster = "w342"; + imageQualityProfile = "w185"; + imageQualityStill = "w185"; + } else if (i == 2) { + imageQuality = getString(R.string.ImageQualityHigh); + + imageQualityBackdrop = "w1280"; + imageQualityLogo = "w500"; + imageQualityPoster = "w780"; + imageQualityProfile = "w632"; + imageQualityStill = "w300"; + } else { + imageQuality = getString(R.string.ImageQualityOriginal); + + imageQualityBackdrop = "original"; + imageQualityLogo = "original"; + imageQualityPoster = "original"; + imageQualityProfile = "original"; + imageQualityStill = "original"; + } + + SharedPreferences prefs = activity.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("image_quality", imageQuality); + editor.putString("image_quality_backdrop", imageQualityBackdrop); + editor.putString("image_quality_logo", imageQualityLogo); + editor.putString("image_quality_poster", imageQualityPoster); + editor.putString("image_quality_profile", imageQualityProfile); + editor.putString("image_quality_still", imageQualityStill); + editor.putBoolean("image_quality_custom", false); + editor.apply(); + + if (view instanceof TextDetailCell) { + ((TextDetailCell) view).setValue(imageQuality); + } + }); + builder.show(); + } else if (position == inAppBrowserRow) { + SharedPreferences prefs = activity.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + boolean enable = prefs.getBoolean("in_app_browser", true); + editor.putBoolean("in_app_browser", !enable); + editor.apply(); + if (view instanceof TextDetailCell) { + ((TextDetailCell) view).setChecked(!enable); + } + } else if (position == adultRow) { + SharedPreferences.Editor editor = prefs.edit(); + boolean enable = prefs.getBoolean("adult", true); + editor.putBoolean("adult", !enable); + editor.apply(); + if (view instanceof TextDetailCell) { + ((TextDetailCell) view).setChecked(!enable); + } + } + }); + fragmentView.addView(recyclerView); + return fragmentView; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Parcelable state = layoutManager.onSaveInstanceState(); + layoutManager = new LinearLayoutManager(getContext()); + recyclerView.setLayoutManager(layoutManager); + layoutManager.onRestoreInstanceState(state); + } + + public class ListAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { + View cell; + + if (type == 1) { + cell = new EmptyCell(activity); + } else if (type == 2) { + cell = new TextDetailCell(activity); + } else { + cell = new TextCell(activity); + } + + return new Holder(cell); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + int type = getItemViewType(position); + + if (type == 1) { + EmptyCell cell = (EmptyCell) holder.itemView; + cell.setMode(EmptyCell.MODE_DEFAULT); + + if (position == emptyRow) { + cell.setHeight(ScreenUtils.dp(12)); + } + } else if (type == 2) { + TextDetailCell cell = (TextDetailCell) holder.itemView; + cell.changeLayoutParams(); + + if (position == inAppBrowserRow) { + cell.setMode(TextDetailCell.MODE_SWITCH); + cell.setText(R.string.InAppBrowser); + cell.setValue(R.string.InAppBrowserInfo); + cell.setChecked(prefs.getBoolean("in_app_browser", true)); + } else if (position == adultRow) { + cell.setMode(TextDetailCell.MODE_SWITCH); + cell.setText(getString(R.string.IncludeAdult)); + cell.setValue("Toggle the inclusion of adult content"); + cell.setChecked(prefs.getBoolean("adult", true)); + cell.setDivider(true); + } else if (position == imageQualityRow) { + String imageQuality = prefs.getString("image_quality", getString(R.string.ImageQualityMedium)); + boolean customSettings = prefs.getBoolean("image_quality_settings_customize", false); + + cell.setText(getString(R.string.ImageQuality)); + cell.setValue(customSettings ? getString(R.string.Custom) : imageQuality); + cell.setDivider(true); + } + } + } + + @Override + public int getItemCount() { + return rowCount; + } + + @Override + public int getItemViewType(int position) { + if (position == emptyRow) { + return 1; + } else if (position == inAppBrowserRow || position == imageQualityRow || position == adultRow) { + return 2; + } else { + return 3; + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/SimilarMoviesFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/SimilarMoviesFragment.java new file mode 100644 index 000000000..cb784211c --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/SimilarMoviesFragment.java @@ -0,0 +1,216 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.response.MovieResponse; +import org.michaelbel.application.ui.MovieActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.movie.MovieViewList; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.NetworkUtils; + +import java.util.ArrayList; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class SimilarMoviesFragment extends Fragment { + + private static final int TOTAL_PAGES = 1000; + + private int movieId; + + private int page; + private boolean isLoading; + + private TextView emptyView; + private SwipeRefreshLayout refreshLayout; + + private MovieActivity activity; + private SimilarListAdapter adapter; + private LinearLayoutManager layoutManager; + private List movieList = new ArrayList<>(); + + public static SimilarMoviesFragment newInstance(int movieId) { + Bundle args = new Bundle(); + args.putInt("movieId", movieId); + + SimilarMoviesFragment fragment = new SimilarMoviesFragment(); + fragment.setArguments(args); + return fragment; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (MovieActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_favs, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + if (getArguments() != null) { + movieId = getArguments().getInt("movieId"); + } + + emptyView = fragmentView.findViewById(R.id.empty_view); + + refreshLayout = fragmentView.findViewById(R.id.swipe_refresh_layout); + refreshLayout.setColorSchemeResources(Theme.accentColor()); + if (movieList.isEmpty()) { + refreshLayout.setRefreshing(true); + } + refreshLayout.setOnRefreshListener(() -> { + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + if (movieList.isEmpty()) { + getSimilarMovies(); + } else { + refreshLayout.setRefreshing(false); + } + } + }); + + page = 1; + adapter = new SimilarListAdapter(); + layoutManager = new LinearLayoutManager(activity); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + + RecyclerListView recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setVerticalScrollBarEnabled(true); + recyclerView.setOnItemClickListener((view1, position) -> { + Movie movie = movieList.get(position); + activity.startMovie(movie.id, movie.title); + }); + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (layoutManager.findLastVisibleItemPosition() == movieList.size() - 1 && !isLoading) { + if (page < TOTAL_PAGES) { + getSimilarMovies(); + } + } + } + }); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + getSimilarMovies(); + } + } + + private void getSimilarMovies() { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + service.getSimilarMovies(movieId, Url.TMDB_API_KEY, Url.en_US, page) + .enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + SharedPreferences prefs = activity.getSharedPreferences("main_config", Context.MODE_PRIVATE); + boolean adult = prefs.getBoolean("adult", true); + + if (adult) { + movieList.addAll(response.body().movieList); + } else { + for (Movie movie : response.body().movieList) { + if (!movie.adult) { + movieList.add(movie); + } + } + } + + adapter.notifyDataSetChanged(); + + if (movieList.isEmpty()) { + emptyView.setText(R.string.NoMovies); + } else { + page++; + isLoading = false; + } + + onLoadSuccessful(); + } else { + //FirebaseCrash.report(new Error("Server not found")); + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + onLoadError(); + isLoading = false; + } + }); + + isLoading = true; + } + + private void onLoadSuccessful() { + refreshLayout.setRefreshing(false); + } + + private void onLoadError() { + refreshLayout.setRefreshing(false); + emptyView.setText(R.string.NoConnection); + } + + public class SimilarListAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { + return new Holder(new MovieViewList(activity)); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + Movie movie = movieList.get(position); + + MovieViewList view = (MovieViewList) holder.itemView; + view.setPoster(movie.posterPath) + .setTitle(movie.title) + .setYear(movie.releaseDate) + .setVoteAverage(movie.voteAverage) + .setDivider(position != movieList.size() - 1); + } + + @Override + public int getItemCount() { + return movieList != null ? movieList.size() : 0; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/TopRatedFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/TopRatedFragment.java new file mode 100644 index 000000000..07085f2de --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/TopRatedFragment.java @@ -0,0 +1,188 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.response.MovieResponse; +import org.michaelbel.application.ui.MainActivity; +import org.michaelbel.application.ui.adapter.MoviesListAdapter; +import org.michaelbel.application.ui.view.widget.PaddingItemDecoration; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.AppUtils; +import org.michaelbel.application.util.NetworkUtils; +import org.michaelbel.application.util.ScreenUtils; + +import java.util.ArrayList; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class TopRatedFragment extends Fragment { + + private static final int TOTAL_PAGES = 1000; + + private int page; + private boolean isLoading; + + private TextView emptyView; + private SwipeRefreshLayout refreshLayout; + + private MainActivity activity; + private MoviesListAdapter adapter; + private GridLayoutManager layoutManager; + private List movieList = new ArrayList<>(); + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (MainActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_nowplaying, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + emptyView = fragmentView.findViewById(R.id.empty_view); + + refreshLayout = fragmentView.findViewById(R.id.swipe_refresh_layout); + refreshLayout.setColorSchemeResources(Theme.accentColor()); + if (movieList.isEmpty()) { + refreshLayout.setRefreshing(true); + } + refreshLayout.setOnRefreshListener(() -> { + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + if (movieList.isEmpty()) { + getTopRated(); + } else { + refreshLayout.setRefreshing(false); + } + } + }); + + page = 1; + adapter = new MoviesListAdapter(activity, movieList); + + layoutManager = new GridLayoutManager(getContext(), AppUtils.getColumns()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + + RecyclerListView recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setPadding(ScreenUtils.dp(4), 0, ScreenUtils.dp(4), 0); + recyclerView.addItemDecoration(new PaddingItemDecoration(ScreenUtils.dp(2))); + recyclerView.setOnItemClickListener((view1, position) -> { + Movie movie = movieList.get(position); + activity.startMovie(movie.id, movie.title); + }); + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (layoutManager.findLastVisibleItemPosition() == movieList.size() - 1 && !isLoading) { + if (page < TOTAL_PAGES) { + getTopRated(); + } + } + } + }); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + getTopRated(); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + layoutManager.setSpanCount(AppUtils.getColumns()); + } + + private void getTopRated() { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getTopRated(Url.TMDB_API_KEY, Url.en_US, page); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + SharedPreferences prefs = activity.getSharedPreferences("main_config", Context.MODE_PRIVATE); + boolean adult = prefs.getBoolean("adult", true); + + if (adult) { + movieList.addAll(response.body().movieList); + } else { + for (Movie movie : response.body().movieList) { + if (!movie.adult) { + movieList.add(movie); + } + } + } + + adapter.notifyDataSetChanged(); + + if (movieList.isEmpty()) { + emptyView.setText(R.string.NoMovies); + } else { + page++; + isLoading = false; + } + + onLoadSuccessful(); + } else { + //FirebaseCrash.report(new Error("Server not found")); + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + onLoadError(); + isLoading = false; + } + }); + + isLoading = true; + } + + private void onLoadSuccessful() { + refreshLayout.setRefreshing(false); + } + + private void onLoadError() { + refreshLayout.setRefreshing(false); + emptyView.setText(R.string.NoConnection); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/TrailersFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/TrailersFragment.java new file mode 100644 index 000000000..9f7dc3dd8 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/TrailersFragment.java @@ -0,0 +1,196 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Intent; +import android.content.res.Configuration; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Trailer; +import org.michaelbel.application.rest.response.VideoResponse; +import org.michaelbel.application.ui.TrailersActivity; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.widget.PaddingItemDecoration; +import org.michaelbel.application.ui.view.trailer.TrailerCompatView; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.AppUtils; +import org.michaelbel.application.util.NetworkUtils; +import org.michaelbel.application.util.ScreenUtils; + +import java.util.ArrayList; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class TrailersFragment extends Fragment { + + private int movieId; + + private TrailersActivity activity; + private VideosAdapter adapter; + private GridLayoutManager layoutManager; + private ArrayList trailerList = new ArrayList<>(); + + private TextView emptyView; + private SwipeRefreshLayout refreshLayout; + + public static TrailersFragment newInstance(int movieId, String movieTitle) { + Bundle args = new Bundle(); + args.putInt("movieId", movieId); + args.putString("movieTitle", movieTitle); + + TrailersFragment fragment = new TrailersFragment(); + fragment.setArguments(args); + return fragment; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (TrailersActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_videos, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + + activity.toolbar.setNavigationIcon(R.drawable.ic_arrow_back); + activity.toolbar.setNavigationOnClickListener(view -> activity.finish()); + + activity.titleView.setTitle("Trailers"); + if (getArguments() != null) { + activity.titleView.setSubtitle(getArguments().getString("movieTitle")); + } + + emptyView = fragmentView.findViewById(R.id.empty_view); + + refreshLayout = fragmentView.findViewById(R.id.swipe_refresh_layout); + refreshLayout.setColorSchemeResources(Theme.accentColor()); + refreshLayout.setRefreshing(true); + refreshLayout.setOnRefreshListener(() -> { + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + if (trailerList.isEmpty()) { + loadVideos(); + } else { + refreshLayout.setRefreshing(false); + } + } + }); + + adapter = new VideosAdapter(); + layoutManager = new GridLayoutManager(activity, AppUtils.getColumnsForVideos()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + + RecyclerListView recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setLayoutManager(layoutManager); + recyclerView.addItemDecoration(new PaddingItemDecoration(ScreenUtils.dp(4))); + recyclerView.setOnItemClickListener((view, position) -> { + Trailer trailer = trailerList.get(position); + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:" + trailer.key))); + }); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (getArguments() != null) { + movieId = getArguments().getInt("movieId"); + } + + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + loadVideos(); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + layoutManager.setSpanCount(AppUtils.getColumnsForVideos()); + } + + private void loadVideos() { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getVideos(movieId, Url.TMDB_API_KEY, Url.en_US); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + trailerList.addAll(response.body().trailersList); + adapter.notifyDataSetChanged(); + + if (trailerList.isEmpty()) { + emptyView.setText(R.string.NoVideos); + } + + onLoadSuccessful(); + } else { + //FirebaseCrash.report(new Error("Server not found")); + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + onLoadError(); + } + }); + } + + private void onLoadSuccessful() { + refreshLayout.setRefreshing(false); + } + + private void onLoadError() { + refreshLayout.setRefreshing(false); + emptyView.setText(R.string.NoConnection); + } + + private class VideosAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new Holder(new TrailerCompatView(activity)); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { + Trailer trailer = trailerList.get(position); + + TrailerCompatView view = (TrailerCompatView) holder.itemView; + view.setTitle(trailer.name) + .setQuality(trailer.size) + .setSite(trailer.site) + .setTrailerImage(trailer.key); + } + + @Override + public int getItemCount() { + return trailerList != null ? trailerList.size() : 0; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/fragment/UpcomingFragment.java b/app/src/main/java/org/michaelbel/application/ui/fragment/UpcomingFragment.java new file mode 100644 index 000000000..745339782 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/fragment/UpcomingFragment.java @@ -0,0 +1,190 @@ +package org.michaelbel.application.ui.fragment; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.moviemade.annotation.Beta; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.response.MovieResponse; +import org.michaelbel.application.ui.MainActivity; +import org.michaelbel.application.ui.adapter.MoviesListAdapter; +import org.michaelbel.application.ui.view.widget.PaddingItemDecoration; +import org.michaelbel.application.ui.view.widget.RecyclerListView; +import org.michaelbel.application.util.AppUtils; +import org.michaelbel.application.util.NetworkUtils; +import org.michaelbel.application.util.ScreenUtils; + +import java.util.ArrayList; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +@Beta +public class UpcomingFragment extends Fragment { + + private static final int TOTAL_PAGES = 1000; + + private int page; + private boolean isLoading; + + private TextView emptyView; + private SwipeRefreshLayout refreshLayout; + + private MainActivity activity; + private MoviesListAdapter adapter; + private GridLayoutManager layoutManager; + private List movieList = new ArrayList<>(); + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + activity = (MainActivity) getActivity(); + + View fragmentView = inflater.inflate(R.layout.fragment_nowplaying, container, false); + fragmentView.setBackgroundColor(ContextCompat.getColor(activity, Theme.backgroundColor())); + setHasOptionsMenu(true); + + emptyView = fragmentView.findViewById(R.id.empty_view); + + refreshLayout = fragmentView.findViewById(R.id.swipe_refresh_layout); + refreshLayout.setColorSchemeResources(Theme.accentColor()); + if (movieList.isEmpty()) { + refreshLayout.setRefreshing(true); + } + refreshLayout.setOnRefreshListener(() -> { + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + if (movieList.isEmpty()) { + getUpcoming(); + } else { + refreshLayout.setRefreshing(false); + } + } + }); + + page = 1; + adapter = new MoviesListAdapter(activity, movieList); + + layoutManager = new GridLayoutManager(getContext(), AppUtils.getColumns()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + + RecyclerListView recyclerView = fragmentView.findViewById(R.id.recycler_view); + recyclerView.setAdapter(adapter); + recyclerView.setHasFixedSize(true); + recyclerView.setEmptyView(emptyView); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setPadding(ScreenUtils.dp(4), 0, ScreenUtils.dp(4), 0); + recyclerView.addItemDecoration(new PaddingItemDecoration(ScreenUtils.dp(2))); + recyclerView.setOnItemClickListener((view1, position) -> { + Movie movie = movieList.get(position); + activity.startMovie(movie.id, movie.title); + }); + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (layoutManager.findLastVisibleItemPosition() == movieList.size() - 1 && !isLoading) { + if (page < TOTAL_PAGES) { + getUpcoming(); + } + } + } + }); + + return fragmentView; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (NetworkUtils.getNetworkStatus() == NetworkUtils.TYPE_NOT_CONNECTED) { + onLoadError(); + } else { + getUpcoming(); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + layoutManager.setSpanCount(AppUtils.getColumns()); + } + + private void getUpcoming() { + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getUpcoming(Url.TMDB_API_KEY, Url.en_US, page); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + SharedPreferences prefs = activity.getSharedPreferences("main_config", Context.MODE_PRIVATE); + boolean adult = prefs.getBoolean("adult", true); + + if (adult) { + movieList.addAll(response.body().movieList); + } else { + for (Movie movie : response.body().movieList) { + if (!movie.adult) { + movieList.add(movie); + } + } + } + + adapter.notifyDataSetChanged(); + + if (movieList.isEmpty()) { + emptyView.setText(R.string.NoMovies); + } else { + page++; + isLoading = false; + } + + onLoadSuccessful(); + } else { + //FirebaseCrash.report(new Error("Server not found")); + onLoadError(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + onLoadError(); + isLoading = false; + } + }); + + isLoading = true; + } + + private void onLoadSuccessful() { + refreshLayout.setRefreshing(false); + } + + private void onLoadError() { + refreshLayout.setRefreshing(false); + emptyView.setText(R.string.NoConnection); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/CardButton.java b/app/src/main/java/org/michaelbel/application/ui/view/CardButton.java new file mode 100644 index 000000000..5a667172b --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/CardButton.java @@ -0,0 +1,89 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.support.annotation.StringRes; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.CardView; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class CardButton extends FrameLayout { + + private CardView cardView; + private TextView textText; + + private Rect rect = new Rect(); + + public CardButton(Context context) { + super(context); + + cardView = new CardView(context); + cardView.setCardElevation(0); + cardView.setUseCompatPadding(true); + cardView.setRadius(ScreenUtils.dp(16)); + cardView.setPreventCornerOverlap(false); + cardView.setForeground(Theme.selectableItemBackgroundBorderlessDrawable()); + cardView.setCardBackgroundColor(ContextCompat.getColor(context, Theme.accentColor())); + cardView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + addView(cardView); + + textText = new TextView(context); + textText.setMaxLines(1); + textText.setTextColor(0xFFFFFFFF); + textText.setGravity(Gravity.CENTER_VERTICAL); + textText.setEllipsize(TextUtils.TruncateAt.END); + textText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + textText.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + textText.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 16, 8, 16, 8)); + cardView.addView(textText); + } + + public void setText(@StringRes int textId) { + textText.setText(getContext().getText(textId).toString().toUpperCase()); + } + + public void setCardRadius(float radius) { + cardView.setRadius(radius); + } + + public void changeLayoutParams(boolean gravity) { + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + + if (gravity) { + params.leftMargin = ScreenUtils.dp(3F); + } else { + params.rightMargin = ScreenUtils.dp(3F); + } + + setLayoutParams(params); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (cardView.getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + cardView.getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/CastView.java b/app/src/main/java/org/michaelbel/application/ui/view/CastView.java new file mode 100644 index 000000000..eba7ced84 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/CastView.java @@ -0,0 +1,141 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.ui.view.widget.MaskImageView; +import org.michaelbel.application.util.ScreenUtils; + +public class CastView extends FrameLayout { + + public TextView nameTextView; + public TextView characterTextView; + public MaskImageView profileImageView; + + private Paint paint; + private boolean divider; + private Rect rect = new Rect(); + + public CastView(Context context) { + super(context); + + setForeground(Theme.selectableItemBackgroundDrawable()); + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + if (paint == null) { + paint = new Paint(); + paint.setStrokeWidth(1); + paint.setColor(ContextCompat.getColor(context, Theme.dividerColor())); + } + + profileImageView = new MaskImageView(context); + profileImageView.setShapeDrawable(MaskImageView.CIRCLE); + profileImageView.setScaleType(ImageView.ScaleType.CENTER); + profileImageView.setLayoutParams(LayoutHelper.makeFrame(62, 62, + Gravity.START, 8, 8, 0, 8)); + addView(profileImageView); + + nameTextView = new TextView(context); + nameTextView.setLines(1); + nameTextView.setMaxLines(1); + nameTextView.setSingleLine(true); + nameTextView.setEllipsize(TextUtils.TruncateAt.END); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17); + nameTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + nameTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + nameTextView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.TOP, 88, 18, 16, 0)); + addView(nameTextView); + + characterTextView = new TextView(context); + characterTextView.setLines(1); + characterTextView.setMaxLines(1); + characterTextView.setSingleLine(true); + characterTextView.setEllipsize(TextUtils.TruncateAt.END); + characterTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + characterTextView.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL)); + characterTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + characterTextView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.BOTTOM, 88, 0, 16, 18)); + addView(characterTextView); + } + + public CastView setProfileImage(@NonNull String profilePath) { + SharedPreferences prefs = getContext().getSharedPreferences("main_config", Context.MODE_PRIVATE); + String size = prefs.getString("image_quality_profile", "w185"); + + if (profilePath == null) { + profileImageView.setImageResource(R.drawable.book_user); + } else { + Glide.with(getContext()) + //.load("http://image.tmdb.org/t/p/" + size + profilePath) + .load("http://image.tmdb.org/t/p/w185/" + profilePath) + .into(profileImageView); + } + + return this; + } + + public CastView setName(@NonNull String name) { + nameTextView.setText(name); + return this; + } + + public CastView setCharacter(@NonNull String character) { + characterTextView.setText(character); + return this; + } + + public CastView setDivider(boolean divider) { + this.divider = divider; + setWillNotDraw(!divider); + return this; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY); + int height = getMeasuredHeight(); + setMeasuredDimension(width, height); + + } + + @Override + protected void onDraw(Canvas canvas) { + if (divider) { + canvas.drawLine(ScreenUtils.dp(88), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getForeground().setHotspot(event.getX(), event.getY()); + } + } + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/EmptyView.java b/app/src/main/java/org/michaelbel/application/ui/view/EmptyView.java new file mode 100644 index 000000000..7fc68fb57 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/EmptyView.java @@ -0,0 +1,58 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.support.annotation.StringRes; +import android.support.v4.content.ContextCompat; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.annotation.Beta; + +@Beta +public class EmptyView extends LinearLayout { + + private TextView emptyText; + private ImageView emptyImage; + + public EmptyView(Context context) { + super(context); + initialize(context); + } + + public EmptyView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context); + } + + private void initialize(Context context) { + setOrientation(VERTICAL); + setGravity(Gravity.CENTER); + + emptyImage = new ImageView(getContext()); + emptyImage.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT)); + addView(emptyImage); + + emptyText = new TextView(getContext()); + emptyText.setGravity(Gravity.CENTER); + emptyText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17); + emptyText.setTextColor(ContextCompat.getColor(getContext(), Theme.secondaryTextColor())); + emptyText.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 24, 16, 24, 0)); + addView(emptyText); + } + + public void setText(@StringRes int textId) { + emptyText.setText(getContext().getText(textId)); + } + + public void setImage(int resId) { + emptyImage.setImageResource(resId); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/FavButton.java b/app/src/main/java/org/michaelbel/application/ui/view/FavButton.java new file mode 100644 index 000000000..bb0e06860 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/FavButton.java @@ -0,0 +1,86 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.support.annotation.StringRes; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.CardView; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class FavButton extends FrameLayout { + + private CardView cardView; + + private ImageView iconView; + private TextView textText; + + private Rect rect = new Rect(); + + public FavButton(Context context) { + super(context); + + cardView = new CardView(context); + cardView.setCardElevation(0); + cardView.setUseCompatPadding(true); + cardView.setRadius(ScreenUtils.dp(10)); + cardView.setPreventCornerOverlap(false); + cardView.setForeground(Theme.selectableItemBackgroundBorderlessDrawable()); + cardView.setCardBackgroundColor(ContextCompat.getColor(context, Theme.accentColor())); + cardView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + addView(cardView); + + iconView = new ImageView(context); + iconView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL, 12, 6, 0, 6)); + cardView.addView(iconView); + + textText = new TextView(context); + textText.setLines(1); + textText.setMaxLines(1); + textText.setSingleLine(); + textText.setGravity(Gravity.CENTER_VERTICAL); + textText.setEllipsize(TextUtils.TruncateAt.END); + textText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + textText.setTextColor(ContextCompat.getColor(context, Theme.foregroundColor())); + textText.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + textText.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 24 + 12 + 10, 0, 12, 0)); + cardView.addView(textText); + } + + public FavButton setIcon(int icon) { + iconView.setImageDrawable(Theme.getIcon(icon, ContextCompat.getColor(getContext(), Theme.foregroundColor()))); + return this; + } + + public FavButton setText(@StringRes int textId) { + textText.setText(getContext().getText(textId).toString().toUpperCase()); + return this; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (cardView.getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + cardView.getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/ImagesSectionView.java b/app/src/main/java/org/michaelbel/application/ui/view/ImagesSectionView.java new file mode 100644 index 000000000..a91c76fb0 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/ImagesSectionView.java @@ -0,0 +1,132 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; + +public class ImagesSectionView extends FrameLayout { + + private ImageView posterImageView; + private ImageView backdropImageView; + + private TextView postersCountTextView; + private TextView backdropsCountTextView; + + public ImagesSectionView(Context context) { + super(context); + + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + TextView textView = new TextView(context); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(); + textView.setText("Images"); + textView.setGravity(Gravity.CENTER_VERTICAL); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + textView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + textView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + textView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, 48, + Gravity.START | Gravity.TOP, 16, 0, 16, 0)); + addView(textView); + + LinearLayout imagesLayout = new LinearLayout(context); + imagesLayout.setOrientation(LinearLayout.HORIZONTAL); + imagesLayout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, 150, + Gravity.TOP, 12, 48, 12, 12)); + addView(imagesLayout); + + //--- + + FrameLayout postersLayout = new FrameLayout(context); + postersLayout.setLayoutParams(LayoutHelper.makeLinear(0, LayoutHelper.MATCH_PARENT, + Gravity.CENTER, 1F)); + imagesLayout.addView(postersLayout); + + posterImageView = new ImageView(context); + posterImageView.setScaleType(ImageView.ScaleType.CENTER); + posterImageView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + postersLayout.addView(posterImageView); + + FrameLayout postersTitleLayout = new FrameLayout(context); + postersTitleLayout.setBackgroundColor(0x99000000); + postersTitleLayout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + Gravity.BOTTOM)); + postersLayout.addView(postersTitleLayout); + + postersCountTextView = new TextView(context); + postersCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); + postersCountTextView.setTextColor(ContextCompat.getColor(context, Theme.foregroundColor())); + postersCountTextView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL, 8, 6, 8, 6)); + postersTitleLayout.addView(postersCountTextView); + +//-------------------------------------------------------------------------------------------------- + + FrameLayout backdropsLayout = new FrameLayout(context); + backdropsLayout.setLayoutParams(LayoutHelper.makeLinear(0, LayoutHelper.MATCH_PARENT, + Gravity.CENTER,2F, 12, 0, 0, 0)); + imagesLayout.addView(backdropsLayout); + + backdropImageView = new ImageView(context); + backdropImageView.setScaleType(ImageView.ScaleType.CENTER); + backdropImageView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + backdropsLayout.addView(backdropImageView); + + FrameLayout backdropsTitleLayout = new FrameLayout(context); + backdropsTitleLayout.setBackgroundColor(0x99000000); + backdropsTitleLayout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + Gravity.BOTTOM)); + backdropsLayout.addView(backdropsTitleLayout); + + backdropsCountTextView = new TextView(context); + backdropsCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); + backdropsCountTextView.setTextColor(ContextCompat.getColor(context, Theme.foregroundColor())); + backdropsCountTextView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL, 8, 6, 8, 6)); + backdropsTitleLayout.addView(backdropsCountTextView); + } + + public ImagesSectionView setPoster(@NonNull String posterPath) { + SharedPreferences prefs = getContext().getSharedPreferences("main_config", Context.MODE_PRIVATE); + String size = prefs.getString("image_quality_poster", "w342"); + + Glide.with(getContext()) + .load("http://image.tmdb.org/t/p/" + size +"/" + posterPath) + .into(posterImageView); + return this; + } + + public ImagesSectionView setBackdrop(@NonNull String backdropPath) { + SharedPreferences prefs = getContext().getSharedPreferences("main_config", Context.MODE_PRIVATE); + String size = prefs.getString("image_quality_backdrop", "w780"); + + Glide.with(getContext()) + .load("http://image.tmdb.org/t/p/" + size +"/" + backdropPath) + .into(backdropImageView); + return this; + } + + public ImagesSectionView setPostersCount(int count) { + postersCountTextView.setText(count + " Posters"); + return this; + } + + public ImagesSectionView setBackdropsCount(int count) { + backdropsCountTextView.setText(count + " Backdrops"); + return this; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/LoadingView.java b/app/src/main/java/org/michaelbel/application/ui/view/LoadingView.java new file mode 100644 index 000000000..89a62d78c --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/LoadingView.java @@ -0,0 +1,24 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.ProgressBar; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.annotation.Beta; + +@Beta +public class LoadingView extends FrameLayout { + + private ProgressBar progressBar; + + public LoadingView(Context context) { + super(context); + + progressBar = new ProgressBar(context); + progressBar.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + addView(progressBar); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/MovieInfoLayout.java b/app/src/main/java/org/michaelbel/application/ui/view/MovieInfoLayout.java new file mode 100644 index 000000000..0d994daf0 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/MovieInfoLayout.java @@ -0,0 +1,912 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.GravityCompat; +import android.support.v7.widget.AppCompatImageView; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.rest.model.Crew; +import org.michaelbel.application.rest.model.Genre; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.rest.model.Trailer; +import org.michaelbel.application.sqlite.DatabaseHelper; +import org.michaelbel.application.ui.adapter.Holder; +import org.michaelbel.application.ui.view.trailer.TrailerView; +import org.michaelbel.application.util.ScreenUtils; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +public class MovieInfoLayout extends LinearLayout { + + private ImageView posterImageView; + + private LinearLayout titleSloganLayout; + private TextView titleTextView; + private TextView taglineTextView; + + private LinearLayout overviewLayout; + private TextView overviewTextView; + + private FavButton favButton; + + private TextView dateTextView; + private TextView runtimeTextView; + private TextView countriesTextView; + private TextView originalTitleTextView; + private TextView originalLangTextView; + private TextView statusTextView; + private TextView budgetTextView; + private TextView revenueTextView; + private TextView companiesTextView; + private RatingView ratingView; + private TextView ratingTextView; + private TextView voteCountTextView; + + private TextView genresTextView; + + private TextView directorsTitle; + private TextView directorsList; + private TextView writersTitle; + private TextView writersList; + private TextView producersTitle; + private TextView producersList; + + private LinearLayout linksLayout; + private MoviePageView page1; + private MoviePageView page2; + private MoviePageView page3; + + private TrailersSectionView trailersView; + private TrailersAdapter trailersAdapter; + private List trailersList = new ArrayList<>(); + + private ImagesSectionView imagesView; + + private InfoMovieListener infoMovieListener; + private Callback callback; + + public interface InfoMovieListener { + boolean onOverviewLongClick(View view); + + void onTrailersSectionClick(View view); + void onTrailerClick(View view, String trailerKey); + boolean onTrailerLongClick(View view, String trailerKey); + + void onMovieUrlClick(View view, int position); + + void onFavButtonClick(View view); + } + + public interface Callback { + void onMovieLoaded(); + } + + public MovieInfoLayout(Context context) { + super(context); + initialize(context); + } + + public MovieInfoLayout(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context); + } + + private void initialize(Context context) { + setOrientation(VERTICAL); + setBackgroundColor(ContextCompat.getColor(context, Theme.backgroundColor())); + + FrameLayout topLayout = new FrameLayout(context); + topLayout.setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + topLayout.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + addView(topLayout); + +//------POSTER IMAGE-------------------------------------------------------------------------------- + + posterImageView = new ImageView(context); + posterImageView.setScaleType(ImageView.ScaleType.FIT_XY); + posterImageView.setImageResource(R.drawable.movie_placeholder); + posterImageView.setLayoutParams(LayoutHelper.makeFrame(110, 180, + Gravity.START | Gravity.TOP, 16, 16, 0, 0)); + topLayout.addView(posterImageView); + +//-------------------------------------------------------------------------------------------------- + + LinearLayout layout1 = new LinearLayout(context); + layout1.setOrientation(VERTICAL); + layout1.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + GravityCompat.START | Gravity.TOP, 110 + 32, 16, 16, 0)); + topLayout.addView(layout1); + +//------RATING VIEW--------------------------------------------------------------------------------- + + LinearLayout layout0 = new LinearLayout(context); + layout0.setOrientation(HORIZONTAL); + layout1.addView(layout0); + + ratingView = new RatingView(context); + ratingView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL)); + layout0.addView(ratingView); + + ratingTextView = new TextView(context); + ratingTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + ratingTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + ratingTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + ratingTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL, 12, 0, 0, 0)); + layout0.addView(ratingTextView); + + LinearLayout layout6 = new LinearLayout(context); + layout6.setOrientation(HORIZONTAL); + layout6.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL, 12, 0, 0, 0)); + layout0.addView(layout6); + + voteCountTextView = new TextView(context); + voteCountTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + voteCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + voteCountTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + voteCountTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.BOTTOM)); + layout6.addView(voteCountTextView); + + ImageView voteCountIcon = new ImageView(context); + voteCountIcon.setImageDrawable(Theme.getIcon(R.drawable.ic_account_multiple, + ContextCompat.getColor(context, Theme.iconActiveColor()))); + voteCountIcon.setLayoutParams(LayoutHelper.makeLinear(12, 12, + Gravity.START | Gravity.BOTTOM, 2, 0, 0, 1)); + layout6.addView(voteCountIcon); + +//------DATE VIEW----------------------------------------------------------------------------------- + + LinearLayout layout2 = new LinearLayout(context); + layout2.setOrientation(HORIZONTAL); + layout2.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + GravityCompat.START, 0, 12, 0, 0)); + layout1.addView(layout2); + + ImageView dateIcon = new ImageView(context); + dateIcon.setImageDrawable(Theme.getIcon(R.drawable.ic_calendar, + ContextCompat.getColor(context, Theme.iconActiveColor()))); + dateIcon.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL)); + layout2.addView(dateIcon); + + dateTextView = new TextView(context); + dateTextView.setMaxLines(1); + dateTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + dateTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + dateTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + dateTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL,6, 0, 0, 0)); + layout2.addView(dateTextView); + +//------RUNTIME VIEW-------------------------------------------------------------------------------- + + LinearLayout layout3 = new LinearLayout(context); + layout3.setOrientation(HORIZONTAL); + layout3.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + GravityCompat.START, 0, 12, 0, 0)); + layout1.addView(layout3); + + ImageView clockIcon = new ImageView(context); + clockIcon.setImageDrawable(Theme.getIcon(R.drawable.ic_clock, + ContextCompat.getColor(context, Theme.iconActiveColor()))); + clockIcon.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL)); + layout3.addView(clockIcon); + + runtimeTextView = new TextView(context); + runtimeTextView.setMaxLines(1); + runtimeTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + runtimeTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + runtimeTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + runtimeTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL,6, 0, 0, 0)); + layout3.addView(runtimeTextView); + +//------COUNTRY VIEW-------------------------------------------------------------------------------- + + LinearLayout layout4 = new LinearLayout(context); + layout4.setOrientation(HORIZONTAL); + layout4.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + GravityCompat.START, 0, 12, 0, 0)); + layout1.addView(layout4); + + ImageView countriesIcon = new ImageView(context); + countriesIcon.setImageDrawable(Theme.getIcon(R.drawable.ic_earth, + ContextCompat.getColor(context, Theme.iconActiveColor()))); + countriesIcon.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START)); + layout4.addView(countriesIcon); + + countriesTextView = new TextView(context); + countriesTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + countriesTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + countriesTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + countriesTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL,6, 0, 0, 0)); + layout4.addView(countriesTextView); + +//------FAVORITE BUTTON----------------------------------------------------------------------------- + + favButton = new FavButton(context); + favButton.setOnClickListener(v -> { + if (infoMovieListener != null) { + infoMovieListener.onFavButtonClick(v); + } + }); + favButton.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.TOP | Gravity.END, 0, 16 + 180 - 36 - 4, 16, 0)); + topLayout.addView(favButton); + +//------TITLE and TAGLINE--------------------------------------------------------------------------- + + titleSloganLayout = new LinearLayout(context); + titleSloganLayout.setOrientation(VERTICAL); + titleSloganLayout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + GravityCompat.START | Gravity.TOP, 16, 202, 16, 12)); + topLayout.addView(titleSloganLayout); + + titleTextView = new TextView(context); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23); + titleTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + titleTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + titleSloganLayout.addView(titleTextView); + + taglineTextView = new TextView(context); + taglineTextView.setLines(1); + taglineTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + taglineTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + titleSloganLayout.addView(taglineTextView); + +//------OVERVIEW------------------------------------------------------------------------------------ + + overviewLayout = new LinearLayout(context); + overviewLayout.setOrientation(VERTICAL); + overviewLayout.setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + overviewLayout.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 0, 6, 0, 0)); + overviewLayout.setOnLongClickListener(view -> { + if (infoMovieListener != null) { + infoMovieListener.onOverviewLongClick(view); + return true; + } + return false; + }); + addView(overviewLayout); + + overviewTextView = new TextView(context); + overviewTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + overviewTextView.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL)); + overviewTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + overviewTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 16, 16, 16)); + overviewLayout.addView(overviewTextView); + +//------TRAILERS SECTION VIEW----------------------------------------------------------------------- + + trailersAdapter = new TrailersAdapter(); + + trailersView = new TrailersSectionView(context); + trailersView.setPadding(0, 0, 0, ScreenUtils.dp(4)); + trailersView.setAdapter(trailersAdapter); + trailersView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 0, 6, 0, 0)); + trailersView.setOnClickListener(view -> { + if (infoMovieListener != null) { + infoMovieListener.onTrailersSectionClick(view); + } + }); + trailersView.setListener(new TrailersSectionView.SectionTrailersListener() { + @Override + public void onTrailerClick(View view, int position) { + if (infoMovieListener != null) { + Trailer trailer = trailersList.get(position); + infoMovieListener.onTrailerClick(view, trailer.key); + } + } + + @Override + public boolean onTrailerLongClick(View view, int position) { + if (infoMovieListener != null) { + Trailer trailer = trailersList.get(position); + infoMovieListener.onTrailerLongClick(view, trailer.key); + return true; + } + return false; + } + }); + addView(trailersView); + +//------IMAGES SECTION VIEW------------------------------------------------------------------------- + + imagesView = new ImagesSectionView(context); + imagesView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 0, 6, 0, 0)); + //addView(imagesView); + +//------CREW VIEW-------------------------------------------------------------------------------------------- + + LinearLayout crewLayout = new LinearLayout(context); + crewLayout.setOrientation(VERTICAL); + crewLayout.setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + crewLayout.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 0, 6, 0, 0)); + addView(crewLayout); + + TextView crewTitle = new TextView(context); + crewTitle.setLines(1); + crewTitle.setMaxLines(1); + crewTitle.setSingleLine(); + crewTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + crewTitle.setText(context.getString(R.string.Crew)); + crewTitle.setGravity(Gravity.CENTER_VERTICAL); + crewTitle.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + crewTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + crewTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, 48, + 16, 0, 16, 0)); + crewLayout.addView(crewTitle); + + directorsTitle = new TextView(context); + directorsTitle.setText(context.getString(R.string.Directors)); + directorsTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + directorsTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + crewLayout.addView(directorsTitle); + + directorsList = new TextView(context); + directorsList.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + directorsList.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + crewLayout.addView(directorsList); + + writersTitle = new TextView(context); + writersTitle.setText(context.getString(R.string.Writers)); + writersTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + writersTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, 16, 16, 16, 0)); + crewLayout.addView(writersTitle); + + writersList = new TextView(context); + writersList.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + writersList.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + crewLayout.addView(writersList); + + producersTitle = new TextView(context); + producersTitle.setText(context.getString(R.string.Producers)); + producersTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + producersTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + 16, 16, 16, 0)); + crewLayout.addView(producersTitle); + + producersList = new TextView(context); + producersList.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + producersList.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 16)); + crewLayout.addView(producersList); + +//------INFO VIEW-------------------------------------------------------------------------------------------- + + LinearLayout infoLayout = new LinearLayout(context); + infoLayout.setOrientation(VERTICAL); + infoLayout.setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + infoLayout.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 0, 6, 0, 0)); + addView(infoLayout); + + TextView infoTitle = new TextView(context); + infoTitle.setLines(1); + infoTitle.setMaxLines(1); + infoTitle.setSingleLine(); + infoTitle.setText(context.getString(R.string.Info)); + infoTitle.setGravity(Gravity.CENTER_VERTICAL); + infoTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + infoTitle.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + infoTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + infoTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, 48, + 16, 0, 16, 0)); + infoLayout.addView(infoTitle); + + TextView originalTitle = new TextView(context); + originalTitle.setText(context.getString(R.string.OriginalTitle)); + originalTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + originalTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + infoLayout.addView(originalTitle); + + originalTitleTextView = new TextView(context); + originalTitleTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + originalTitleTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + infoLayout.addView(originalTitleTextView); + + TextView originalLang = new TextView(context); + originalLang.setText(context.getString(R.string.OriginalLang)); + originalLang.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + originalLang.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + 16, 16, 16, 0)); + infoLayout.addView(originalLang); + + originalLangTextView = new TextView(context); + originalLangTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + originalLangTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + infoLayout.addView(originalLangTextView); + + TextView statusTitle = new TextView(context); + statusTitle.setText(context.getString(R.string.Status)); + statusTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + statusTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + 16, 16, 16, 0)); + infoLayout.addView(statusTitle); + + statusTextView = new TextView(context); + statusTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + statusTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + infoLayout.addView(statusTextView); + + TextView budgetTitle = new TextView(context); + budgetTitle.setText(context.getString(R.string.Budget)); + budgetTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + budgetTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + 16, 16, 16, 0)); + infoLayout.addView(budgetTitle); + + budgetTextView = new TextView(context); + budgetTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + budgetTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + infoLayout.addView(budgetTextView); + + TextView revenueTitle = new TextView(context); + revenueTitle.setText(context.getString(R.string.Revenue)); + revenueTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + revenueTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + 16, 16, 16, 0)); + infoLayout.addView(revenueTitle); + + revenueTextView = new TextView(context); + revenueTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + revenueTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + infoLayout.addView(revenueTextView); + +//-------------------------------------------------------------------------------------------------- + + TextView genresTitle = new TextView(context); + genresTitle.setText(context.getString(R.string.Genres)); + genresTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + genresTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + 16, 16, 16, 0)); + infoLayout.addView(genresTitle); + + genresTextView = new TextView(context); + genresTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + genresTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + infoLayout.addView(genresTextView); + +//-------------------------------------------------------------------------------------------------- + + TextView companiesTitle = new TextView(context); + companiesTitle.setText(context.getString(R.string.ProductionCompanies)); + companiesTitle.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + companiesTitle.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + 16, 16, 16, 0)); + infoLayout.addView(companiesTitle); + + companiesTextView = new TextView(context); + companiesTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + companiesTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, 16, 0, 16, 12)); + infoLayout.addView(companiesTextView); + +//------WEB LINKS-------------------------------------------------------------------------------------------- + + linksLayout = new LinearLayout(context); + linksLayout.setOrientation(VERTICAL); + linksLayout.setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + linksLayout.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 0, 6, 0, 6)); + addView(linksLayout); + + page1 = new MoviePageView(context); + page1.setText("View on TMDb"); + //page1.setIcon(getResources().getDrawable(R.drawable.icon_tmdb)); + page1.setDivider(true); + page1.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + page1.setOnClickListener(view -> { + if (infoMovieListener != null) { + infoMovieListener.onMovieUrlClick(view, 1); + } + }); + linksLayout.addView(page1); + + page2 = new MoviePageView(context); + page2.setText("View on IMDb"); + //page2.setIcon(getResources().getDrawable(R.drawable.icon_imdb)); + page2.setDivider(true); + page2.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + page2.setOnClickListener(view -> { + if (infoMovieListener != null) { + infoMovieListener.onMovieUrlClick(view, 2); + } + }); + linksLayout.addView(page2); + + page3 = new MoviePageView(context); + page3.setText("View Homepage"); + page3.setIcon(Theme.getIcon(R.drawable.ic_home, + ContextCompat.getColor(getContext(), Theme.primaryColor()))); + page3.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + page3.setOnClickListener(view -> { + if (infoMovieListener != null) { + infoMovieListener.onMovieUrlClick(view, 3); + } + }); + linksLayout.addView(page3); + } + +//-------------------------------------------------------------------------------------------------- + + public void setPoster(@NonNull String posterPath) { + SharedPreferences prefs = getContext().getSharedPreferences("main_config", Context.MODE_PRIVATE); + String size = prefs.getString("image_quality_poster", "w342"); + + Glide.with(getContext()) + .load("http://image.tmdb.org/t/p/" + size +"/" + posterPath) + .into(posterImageView); + } + + public MovieInfoLayout setFavButton(int movieId) { + DatabaseHelper database = DatabaseHelper.getInstance(getContext()); + boolean isExist = database.isMovieExist(movieId); + + if (isExist) { + favButton.setIcon(R.drawable.ic_heart); + favButton.setText(R.string.Remove); + } else { + favButton.setIcon(R.drawable.ic_heart_outline); + favButton.setText(R.string.Add); + } + + database.close(); + return this; + } + + public void setTitle(@NonNull String movieTitle) { + titleTextView.setText(movieTitle.isEmpty() ? "-" : movieTitle); + } + + public void setGenres(@NonNull List genresList) { + StringBuilder text = new StringBuilder(); + for (Genre genre : genresList) { + text.append(genre.name); + if (genre != genresList.get(genresList.size() - 1)) { + text.append(", "); + } + } + + genresTextView.setText(genresList.isEmpty() ? "-" : text); + } + + public void setDate(@NonNull String releaseDate) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + SimpleDateFormat newFormat = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()); + + Date date = null; + try { + date = format.parse(releaseDate); + } catch (ParseException e) { + //FirebaseCrash.report(e); + } + + dateTextView.setText(releaseDate.isEmpty() ? "-" : newFormat.format(date)); + } + + public void setRuntime(int runTime) { + SimpleDateFormat formatMin = new SimpleDateFormat("m", Locale.getDefault()); + SimpleDateFormat formatHours = new SimpleDateFormat("H:m", Locale.getDefault()); + + Date date; + String str = null; + + try { + date = formatMin.parse(String.valueOf(runTime)); + str = formatHours.format(date); + } catch (ParseException e) { + //FirebaseCrash.report(e); + } + + runtimeTextView.setText(runTime == 0 ? "-" : getContext().getString(R.string.RuntimeMin, runTime) + " / " + str); + } + + public void setCountries(@NonNull List countriesList) { + StringBuilder text = new StringBuilder(); + for (Movie.Countries country : countriesList) { + if (country.name.equals("United States of America")) { + country.name = "USA"; + } + + text.append(country.name); + if (country != countriesList.get(countriesList.size() - 1)) { + text.append(", "); + } + } + + countriesTextView.setText(countriesList.isEmpty() ? "-" : text); + } + + public void setStatus(@NonNull String status) { + statusTextView.setText(status.isEmpty() ? "-" : status); + } + + public MovieInfoLayout setTagline(@NonNull String tagline) { + if (tagline.isEmpty()) { + titleSloganLayout.removeView(taglineTextView); + } else { + taglineTextView.setText(tagline); + } + return this; + } + + public MovieInfoLayout setBudget(int budget) { + if (budget == 0) { + // delete views + budgetTextView.setText("-"); + } else { + NumberFormat formatter = NumberFormat.getInstance(Locale.getDefault()); + budgetTextView.setText("$ " + formatter.format(budget)); + } + return this; + } + + public MovieInfoLayout setRevenue(int revenue) { + if (revenue == 0) { + // delete views + revenueTextView.setText("-"); + } else { + NumberFormat formatter = NumberFormat.getInstance(Locale.getDefault()); + revenueTextView.setText("$ " + formatter.format(revenue)); + } + return this; + } + + public void setOriginalTitle(@NonNull String originalTitle) { + originalTitleTextView.setText(originalTitle.isEmpty() ? "-" : originalTitle); + } + + public void setOriginalLang(@NonNull String originalLang) { + originalLangTextView.setText(originalLang.isEmpty() ? "-" : originalLang); + } + + public void setCompanies(@NonNull List companiesList) { + StringBuilder text = new StringBuilder(); + for (Movie.Companies company : companiesList) { + text.append(company.name); + if (company != companiesList.get(companiesList.size() - 1)) { + text.append(", "); + } + } + + companiesTextView.setText(companiesList.isEmpty() ? "-" : text); + } + + public void setVoteAverage(float voteAverage) { + ratingView.setRating(voteAverage); + ratingTextView.setText(String.valueOf(voteAverage)); + } + + public void setVoteCount(int voteCount) { + voteCountTextView.setText(String.valueOf(voteCount)); + } + + public MovieInfoLayout setOverview (@NonNull String overview) { + if (overview.isEmpty()) { + removeView(overviewLayout); + } else { + overviewTextView.setText(overview); + } + return this; + } + + public MovieInfoLayout setHomePage(@NonNull String homePage) { + if (homePage.isEmpty()) { + page2.setDivider(false); + linksLayout.removeView(page3); + } + return this; + } + + public void setCrew(@NonNull List crewList) { + List directors = new ArrayList<>(); + List writers = new ArrayList<>(); + List producers = new ArrayList<>(); + + for (Crew crew : crewList) { + switch (crew.department) { + case "Directing": + directors.add(crew.name); + break; + case "Writing": + writers.add(crew.name); + break; + case "Production": + producers.add(crew.name); + break; + } + } + + StringBuilder text1 = new StringBuilder(); + for (String director : directors) { + text1.append(director); + if (!Objects.equals(director, directors.get(directors.size() - 1))) { + text1.append(", "); + } + } + + if (!text1.toString().isEmpty()) { + directorsList.setText(text1.toString()); + } else { + removeView(directorsTitle); + removeView(directorsList); + } + + StringBuilder text2 = new StringBuilder(); + for (String writer : writers) { + text2.append(writer); + if (!Objects.equals(writer, writers.get(writers.size() - 1))) { + text2.append(", "); + } + } + + if (!text2.toString().isEmpty()) { + writersList.setText(text2.toString()); + } else { + removeView(writersTitle); + removeView(writersList); + } + + StringBuilder text3 = new StringBuilder(); + for (String producer : producers) { + text3.append(producer); + if (!Objects.equals(producer, producers.get(producers.size() - 1))) { + text3.append(", "); + } + } + + if (!text3.toString().isEmpty()) { + producersList.setText(text3.toString()); + } else { + removeView(producersTitle); + removeView(producersList); + } + + callback.onMovieLoaded(); + } + + public MovieInfoLayout setTrailers(@NonNull List list) { + if (list.isEmpty()) { + removeView(trailersView); + } else { + trailersList.addAll(list); + trailersAdapter.notifyDataSetChanged(); + } + + return this; + } + + public MovieInfoLayout setImages(@NonNull String poster, @NonNull String backdrop, int postersCount, int backdropsCount) { + imagesView.setPoster(poster); + imagesView.setBackdrop(backdrop); + imagesView.setPostersCount(postersCount); + imagesView.setBackdropsCount(backdropsCount); + return this; + } + + public void setListener(@NonNull InfoMovieListener listener) { + infoMovieListener = listener; + } + + public void setCallback(Callback listener) { + callback = listener; + } + + public class TabCell extends FrameLayout { + + private ImageView iconView; + private TextView textView; + + public TabCell(Context context) { + super(context); + + setForeground(Theme.selectableItemBackgroundBorderlessDrawable()); + + iconView = new AppCompatImageView(context); + iconView.setLayoutParams(LayoutHelper.makeFrame(24, 24, + Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 16, 0, 0)); + addView(iconView); + + textView = new TextView(context); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + textView.setTextColor(ContextCompat.getColor(context, Theme.primaryColor())); + textView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + textView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 16, 48, 16, 16)); + addView(textView); + } + + public void setIcon(int icon) { + iconView.setImageResource(icon); + } + + public void setText(@NonNull String text) { + textView.setText(text.toUpperCase()); + } + } + + public class TrailersAdapter extends RecyclerView.Adapter { + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new Holder(new TrailerView(getContext())); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { + Trailer trailer = trailersList.get(position); + + TrailerView view = (TrailerView) holder.itemView; + view.setTitle(trailer.name) + .setQuality(trailer.size) + .setSite(trailer.site) + .setTrailerImage(trailer.key); + + if (position == 0) { + view.changeLayoutParams(true); + } + + if (position == trailersList.size() - 1) { + view.changeLayoutParams(false); + } + } + + @Override + public int getItemCount() { + return trailersList != null ? trailersList.size() : 0; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/MoviePageView.java b/app/src/main/java/org/michaelbel/application/ui/view/MoviePageView.java new file mode 100644 index 000000000..8791e2cbe --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/MoviePageView.java @@ -0,0 +1,97 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.AppCompatTextView; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class MoviePageView extends FrameLayout { + + private TextView textView; + private ImageView iconView; + + private Paint paint; + private boolean divider; + + public MoviePageView(Context context) { + super(context); + + setForeground(Theme.selectableItemBackgroundBorderlessDrawable()); + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + if (paint == null) { + paint = new Paint(); + paint.setStrokeWidth(1); + paint.setColor(ContextCompat.getColor(context, Theme.dividerColor())); + } + + iconView = new ImageView(context); + iconView.setScaleType(ImageView.ScaleType.FIT_XY); + iconView.setLayoutParams(LayoutHelper.makeFrame(24, 24, + Gravity.START | Gravity.CENTER_VERTICAL, 16, 0, 0, 0)); + //addView(iconView); + + textView = new AppCompatTextView(context); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + textView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + textView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL, 16, 0, 56, 0)); + addView(textView); + + ImageView iconView2 = new ImageView(context); + iconView2.setImageDrawable(Theme.getIcon(R.drawable.ic_chevron_right, + ContextCompat.getColor(getContext(), Theme.iconActiveColor()))); + iconView2.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 12, 0)); + addView(iconView2); + } + + public MoviePageView setText(@NonNull String text) { + textView.setText(text); + return this; + } + + public MoviePageView setIcon(@NonNull Drawable icon) { + iconView.setImageDrawable(icon); + return this; + } + + public MoviePageView setDivider(boolean divider) { + this.divider = divider; + setWillNotDraw(!divider); + return this; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY); + int height = ScreenUtils.dp(48) + (divider ? 1 : 0); + + setMeasuredDimension(width, height); + } + + @Override + protected void onDraw(Canvas canvas) { + if (divider) { + canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/MovieViewCompat.java b/app/src/main/java/org/michaelbel/application/ui/view/MovieViewCompat.java new file mode 100644 index 000000000..8e1363810 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/MovieViewCompat.java @@ -0,0 +1,159 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.CardView; +import android.text.TextUtils; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.MOVIES; +import org.michaelbel.application.rest.model.Movie; +import org.michaelbel.application.util.ScreenUtils; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class MovieViewCompat extends FrameLayout { + + public int movieId; + + private CardView cardView; + private ImageView posterImage; + private TextView titleText; + + private LinearLayout layout; + private TextView yearAndGenresText; + private TextView overviewText; + + private Rect rect = new Rect(); + + public MovieViewCompat(Context context) { + super(context); + + cardView = new CardView(context); + cardView.setUseCompatPadding(true); + cardView.setRadius(ScreenUtils.dp(2)); + cardView.setPreventCornerOverlap(false); + cardView.setCardElevation(ScreenUtils.dp(1.5F)); + cardView.setForeground(Theme.selectableItemBackgroundBorderlessDrawable()); + cardView.setCardBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + cardView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + addView(cardView); + + posterImage = new ImageView(context); + posterImage.setScaleType(ImageView.ScaleType.FIT_XY); + posterImage.setLayoutParams(LayoutHelper.makeFrame(110, 180, Gravity.START)); + cardView.addView(posterImage); + + layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, + 110, 0, 0, 0)); + cardView.addView(layout); + + titleText = new TextView(context); + titleText.setLines(1); + titleText.setMaxLines(2); + titleText.setEllipsize(TextUtils.TruncateAt.END); + titleText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + titleText.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + titleText.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + titleText.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, 12, 12, 12, 0)); + layout.addView(titleText); + + yearAndGenresText = new TextView(context); + yearAndGenresText.setLines(1); + yearAndGenresText.setMaxLines(1); + yearAndGenresText.setSingleLine(true); + yearAndGenresText.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + yearAndGenresText.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, 12, 4, 12, 0)); + layout.addView(yearAndGenresText); + + overviewText = new TextView(context); + overviewText.setMaxLines(4); + overviewText.setEllipsize(TextUtils.TruncateAt.END); + overviewText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + overviewText.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, 12, 4, 12, 12)); + layout.addView(overviewText); + } + + public void setMovie(@NonNull Movie movie) { + movieId = movie.id; + + Glide.with(getContext()) + .load("http://image.tmdb.org/t/p/w1280/" + movie.posterPath) + //.placeholder(R.drawable.movie_placeholder) + .into(posterImage); + + titleText.setText(movie.title != null ? movie.title : null); + + if (movie.releaseDate != null && movie.releaseDate.length() >= 4) { + yearAndGenresText.setText(movie.releaseDate.substring(0, 4)); + } + + MOVIES service = ApiFactory.getRetrofit().create(MOVIES.class); + Call call = service.getDetails(movieId, Url.TMDB_API_KEY, Url.en_US, null); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + Movie movie = response.body(); + + if (movie.overview != null) { + overviewText.setText(movie.overview); + } + } else { + Log.e("tag", "Server not found"); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.e("tag", t.toString()); + } + }); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (cardView.getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + cardView.getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY); + int height = getMeasuredHeight(); + setMeasuredDimension(width, height); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/MovieViewList2.java b/app/src/main/java/org/michaelbel/application/ui/view/MovieViewList2.java new file mode 100644 index 000000000..5bcad8afb --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/MovieViewList2.java @@ -0,0 +1,144 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; + +public class MovieViewList2 extends FrameLayout { + + public int movieId; + + private ImageView posterImage; + private TextView titleText; + private TextView yearText; + private TextView ratingText; + + private Paint paint; + private boolean divider; + private Rect rect = new Rect(); + + public MovieViewList2(Context context) { + super(context); + + setForeground(Theme.selectableItemBackgroundBorderlessDrawable()); + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + if (paint == null) { + paint = new Paint(); + paint.setStrokeWidth(1); + paint.setColor(ContextCompat.getColor(context, Theme.dividerColor())); + } + + posterImage = new ImageView(context); + posterImage.setScaleType(ImageView.ScaleType.FIT_XY); + posterImage.setLayoutParams(LayoutHelper.makeFrame(45, 65, + Gravity.START | Gravity.CENTER_VERTICAL, 6, 6, 0, 6)); + addView(posterImage); + + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, + LayoutHelper.MATCH_PARENT, 45 + 16, 12, 0, 12)); + addView(layout); + + titleText = new TextView(context); + titleText.setMaxLines(1); + titleText.setGravity(Gravity.CENTER_VERTICAL); + titleText.setEllipsize(TextUtils.TruncateAt.END); + titleText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + titleText.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + titleText.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + titleText.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 0, 12, 0)); + layout.addView(titleText); + + yearText = new TextView(context); + yearText.setMaxLines(1); + yearText.setGravity(Gravity.CENTER_VERTICAL); + yearText.setEllipsize(TextUtils.TruncateAt.END); + yearText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + yearText.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + yearText.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 0, 12, 0)); + layout.addView(yearText); + + ratingText = new TextView(context); + ratingText.setMaxLines(1); + ratingText.setGravity(Gravity.CENTER_VERTICAL); + ratingText.setEllipsize(TextUtils.TruncateAt.END); + ratingText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + ratingText.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + ratingText.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 0, 12, 0)); + layout.addView(ratingText); + } + + public void setPoster(@NonNull String posterPath) { + SharedPreferences prefs = getContext().getSharedPreferences("main_config", Context.MODE_PRIVATE); + String imageQualityPoster = prefs.getString("image_quality_poster", "w342"); + + Glide.with(getContext()) + .load("http://image.tmdb.org/t/p/" + imageQualityPoster + "/" + posterPath) + //.placeholder(R.drawable.movie_placeholder) + .into(posterImage); + } + + public void setTitle(@NonNull String title) { + titleText.setText(title); + } + + public void setYear(@NonNull String date) { + if (date.length() >= 4) { + yearText.setText(date.substring(0, 4)); + } + } + + public void setRating(float rating) { + ratingText.setText(String.valueOf(rating)); + } + + public void setDivider(boolean divider) { + this.divider = divider; + setWillNotDraw(!divider); + } + + @Override + protected void onDraw(Canvas canvas) { + if (divider) { + canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/NavigationView.java b/app/src/main/java/org/michaelbel/application/ui/view/NavigationView.java new file mode 100644 index 000000000..2ab8626d5 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/NavigationView.java @@ -0,0 +1,442 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.ApiFactory; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.Url; +import org.michaelbel.application.rest.api.ACCOUNT; +import org.michaelbel.application.rest.model.Account; +import org.michaelbel.application.ui.view.cell.EmptyCell; +import org.michaelbel.application.util.ScreenUtils; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class NavigationView extends FrameLayout { + + private int rowCount; + private int headerRow; + private int emptyRow1; + private int moviesRow; + private int mostPopularRow; + private int topRatedRow; + private int upComingRow; + private int dividerRow1; + private int watchlistRow; + private int favoritesRow; + private int dividerRow2; + private int settingsRow; + private int aboutRow; + private int emptyRow2; + + private Rect rect; + private int drawerMaxWidth; + private Rect tempRect = new Rect(); + private Drawable insetForeground = new ColorDrawable(0x33000000); + private OnNavigationItemSelectedListener onNavigationItemSelectedListener; + private OnNavigationHeaderClickListener onNavigationHeaderClick; + + public interface OnNavigationItemSelectedListener { + void onNavigationItemSelected(View view, int position); + } + + public interface OnNavigationHeaderClickListener { + void onHeaderClick(View view); + } + + public NavigationView(Context context) { + super(context); + initialize(context); + } + + public NavigationView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context); + } + + public void initialize(Context context) { + rowCount = 0; + headerRow = rowCount++; + emptyRow1 = rowCount++; + favoritesRow = rowCount++; + dividerRow2 = rowCount++; + settingsRow = rowCount++; + aboutRow = rowCount++; + emptyRow2 = rowCount++; + + ListView listView = new ListView(context); + listView.setDividerHeight(0); + listView.setDrawSelectorOnTop(true); + listView.setVerticalScrollBarEnabled(false); + listView.setAdapter(new NavigationViewAdapter()); + listView.setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + listView.setOnItemClickListener((parent, view, position, id) -> { + if (onNavigationItemSelectedListener != null) { + onNavigationItemSelectedListener.onNavigationItemSelected(view, position); + } + }); + addView(listView); + } + + @Override + protected void onSizeChanged(int w, int h, int oldW, int oldH) { + super.onSizeChanged(w, h, oldW, oldH); + + if (w != oldW) { + if (drawerMaxWidth <= 0) { + if (getLayoutParams().width != ViewGroup.LayoutParams.MATCH_PARENT && + getLayoutParams().width != ViewGroup.LayoutParams.WRAP_CONTENT) { + drawerMaxWidth = getLayoutParams().width; + updateWidth(); + } else { + drawerMaxWidth = ScreenUtils.dp(400); + updateWidth(); + } + } + + updateWidth(); + } + } + + @Override + protected boolean fitSystemWindows(Rect insets) { + rect = new Rect(insets); + setWillNotDraw(insetForeground == null); + return true; + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + int width = getWidth(); + int height = getHeight(); + + if (rect != null && insetForeground != null) { + int sc = canvas.save(); + canvas.translate(getScrollX(), getScrollY()); + + tempRect.set(0, 0, width, rect.top); + insetForeground.setBounds(tempRect); + insetForeground.draw(canvas); + + tempRect.set(0, height - rect.bottom, width, height); + insetForeground.setBounds(tempRect); + insetForeground.draw(canvas); + + tempRect.set(0, rect.top, rect.left, height - rect.bottom); + insetForeground.setBounds(tempRect); + insetForeground.draw(canvas); + + tempRect.set(width - rect.right, rect.top, width, height - rect.bottom); + insetForeground.setBounds(tempRect); + insetForeground.draw(canvas); + + canvas.restoreToCount(sc); + } + } + + private void updateWidth() { + int viewportWidth = getContext().getResources().getDisplayMetrics().widthPixels; + int viewportHeight = getContext().getResources().getDisplayMetrics().heightPixels; + + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + int navigationBarWidthResId = getResources().getIdentifier("navigation_bar_width", "dimen", "android"); + if (navigationBarWidthResId > 0) { + viewportWidth -= getResources().getDimensionPixelSize(navigationBarWidthResId); + } + } + + int viewportMin = Math.min(viewportWidth, viewportHeight); + + TypedValue typedValue = new TypedValue(); + getContext().getTheme().resolveAttribute(R.attr.actionBarSize, typedValue, true); + int actionBarSize = TypedValue.complexToDimensionPixelSize(typedValue.data, getResources().getDisplayMetrics()); + + int width = viewportMin - actionBarSize; + + getLayoutParams().width = Math.min(width, drawerMaxWidth); + } + + public void setOnNavigationItemSelectedListener(OnNavigationItemSelectedListener listener) { + onNavigationItemSelectedListener = listener; + } + + public void setOnNavigationHeaderClick(OnNavigationHeaderClickListener listener) { + onNavigationHeaderClick = listener; + } + + private class NavigationViewAdapter extends BaseAdapter { + + @Override + public boolean isEnabled(int i) { + return !(i == emptyRow1 || i == emptyRow2 || i == dividerRow1 || i == dividerRow2); + } + + @Override + public int getCount() { + return rowCount; + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View view, ViewGroup parent) { + int type = getItemViewType(position); + + if (type == 0) { + if (view == null) { + view = new DrawerHeaderCell(getContext()); + } + } else if (type == 1) { + if (view == null) { + view = new DrawerActionCell(getContext()); + } + + DrawerActionCell cell = (DrawerActionCell) view; + + if (position == moviesRow) { + cell.setIcon(Theme.getIcon(R.drawable.ic_movie, 0xFFF44336)); + cell.setText(getContext().getString(R.string.Movies)); + } else if (position == mostPopularRow) { + cell.setIcon(Theme.getIcon(R.drawable.ic_whatshot, 0xFFFF9800)); + cell.setText(getContext().getString(R.string.Popular)); + } else if (position == topRatedRow) { + cell.setIcon(Theme.getIcon(R.drawable.ic_star_circle, 0xFF4CAF50)); + cell.setText(getContext().getString(R.string.TopRated)); + } else if (position == upComingRow) { + cell.setIcon(Theme.getIcon(R.drawable.ic_movie_cadr, 0xFF2196F3)); + cell.setText(getContext().getString(R.string.Upcoming)); + } else if (position == watchlistRow) { + cell.setIcon(Theme.getIcon(R.drawable.ic_watch, + ContextCompat.getColor(getContext(), Theme.iconActiveColor()))); + cell.setText(getContext().getString(R.string.Watchlist)); + } else if (position == favoritesRow) { + cell.setIcon(Theme.getIcon(R.drawable.ic_favorite, + ContextCompat.getColor(getContext(), Theme.iconActiveColor()))); + cell.setText(getContext().getString(R.string.Favorites)); + } else if (position == settingsRow) { + cell.setIcon(Theme.getIcon(R.drawable.ic_settings, + ContextCompat.getColor(getContext(), Theme.iconActiveColor()))); + cell.setText(getContext().getString(R.string.Settings)); + } else if (position == aboutRow) { + cell.setIcon(Theme.getIcon(R.drawable.ic_about, + ContextCompat.getColor(getContext(), Theme.iconActiveColor()))); + cell.setText(getContext().getString(R.string.About)); + } + } else if (type == 2) { + if (view == null) { + view = new EmptyCell(getContext()); + } + + EmptyCell cell = (EmptyCell) view; + cell.setMode(EmptyCell.MODE_DEFAULT); + cell.setHeight(ScreenUtils.dp(8)); + } else if (type == 3) { + if (view == null) { + view = new DividerCell(getContext()); + } + } + + return view; + } + + @Override + public int getItemViewType(int i) { + if (i == headerRow) { + return 0; + } else if (i == moviesRow || i == mostPopularRow || i == settingsRow || + i == aboutRow || i == watchlistRow || i == favoritesRow || i == topRatedRow || + i == upComingRow) { + return 1; + } else if (i == emptyRow1 || i == emptyRow2) { + return 2; + } else if (i == dividerRow1 || i == dividerRow2) { + return 3; + } + + return -1; + } + + @Override + public int getViewTypeCount() { + return 4; + } + } + + public class DrawerHeaderCell extends FrameLayout { + + private ImageView avatarImageView; + private TextView nameTextView; + + public DrawerHeaderCell(Context context) { + super(context); + + setBackground(context.getDrawable(R.drawable.drawer_header)); + setOnClickListener(view -> { + if (onNavigationHeaderClick != null) { + onNavigationHeaderClick.onHeaderClick(view); + } + }); + + avatarImageView = new ImageView(context); + avatarImageView.setBackground(context.getDrawable(R.drawable.tmdb_icon)); + avatarImageView.setLayoutParams(LayoutHelper.makeFrame(64, 64, Gravity.START | Gravity.BOTTOM, 16, 0, 0, 56)); + addView(avatarImageView); + + nameTextView = new TextView(context); + nameTextView.setMaxLines(1); + nameTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + nameTextView.setGravity(Gravity.START); + //nameTextView.setText("Link your TMDb account"); + nameTextView.setText(R.string.AppName); + nameTextView.setEllipsize(TextUtils.TruncateAt.END); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + nameTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + nameTextView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.BOTTOM, 16, 0, 16, 16)); + addView(nameTextView); + } + + private void setHeader() { + SharedPreferences preferences = getContext().getSharedPreferences("user_config", Context.MODE_PRIVATE); + String sessionId = preferences.getString("session_id", null); + + Log.e("ytt", "session id :" + sessionId); + Log.e("ytt", "api key :" + Url.TMDB_API_KEY); + + if (sessionId == null) { + nameTextView.setText("Link your TMDb account"); + avatarImageView.setImageResource(R.drawable.tmdb_icon); + } else { + ACCOUNT service = ApiFactory.getRetrofit().create(ACCOUNT.class); + Call call = service.getDetails(Url.TMDB_API_KEY, sessionId); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + Account account = response.body(); + + nameTextView.setText(account.name); + + if (account.username != null) { + //statusText.setText(account.username); + } + + Log.e("ytt", "api key :" + account.id); + } else { + Log.e("tag", "server not found"); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //FirebaseCrash.report(t); + } + }); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = getMeasuredWidth(); + int height = ScreenUtils.dp(148) + ScreenUtils.getStatusBarHeight(); + setMeasuredDimension(width, height); + } + } + + public class DrawerActionCell extends FrameLayout { + + private TextView textView; + private ImageView imageView; + + public DrawerActionCell(Context context) { + super(context); + + imageView = new ImageView(context); + imageView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 16, 0, 0, 0)); + addView(imageView); + + textView = new TextView(context); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + textView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + textView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + textView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 72, 0, 16, 0)); + addView(textView); + } + + public void setIcon(@NonNull Drawable resId) { + imageView.setImageDrawable(resId); + } + + public void setText(@NonNull String text) { + textView.setText(text); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = getMeasuredWidth(); + int height = ScreenUtils.dp(48); + setMeasuredDimension(width, height); + } + } + + public class DividerCell extends FrameLayout { + + public DividerCell(Context context) { + super(context); + + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, 1 + ); + params.topMargin = ScreenUtils.dp(8); + params.bottomMargin = ScreenUtils.dp(8); + + View view = new View(context); + view.setBackgroundColor(ContextCompat.getColor(context, Theme.dividerColor())); + view.setLayoutParams(params); + addView(view); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/RatingView.java b/app/src/main/java/org/michaelbel/application/ui/view/RatingView.java new file mode 100644 index 000000000..c280f0221 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/RatingView.java @@ -0,0 +1,188 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.v4.content.ContextCompat; +import android.widget.LinearLayout; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; + +@SuppressWarnings("all") +public class RatingView extends LinearLayout { + + private StarView[] stars = new StarView[5]; + + public RatingView(Context context) { + super(context); + + setOrientation(HORIZONTAL); + + int starCount = 5; + for (int i = 0; i < starCount; i++) { + StarView view = new StarView(context); + view.setLayoutParams(LayoutHelper.makeLinear(20, 20)); + addView(view); + stars[i] = view; + } + } + + public void setRating(float rating) { + float myRating = rating / 2; + + int a = (int) myRating; // 3 + int b = (int) (10 * (myRating - a)); + int c; + c = (b >= 5) ? 5 : 0; + + if (c == 0) { + switch (a) { + case 0: + for(StarView star : stars) { + star.setIcon(StarView.ICON_STAR_BORDER); + } + break; + case 1: + stars[0].setIcon(StarView.ICON_STAR); + stars[1].setIcon(StarView.ICON_STAR_BORDER); + stars[2].setIcon(StarView.ICON_STAR_BORDER); + stars[3].setIcon(StarView.ICON_STAR_BORDER); + stars[4].setIcon(StarView.ICON_STAR_BORDER); + break; + case 2: + stars[0].setIcon(StarView.ICON_STAR); + stars[1].setIcon(StarView.ICON_STAR); + stars[2].setIcon(StarView.ICON_STAR_BORDER); + stars[3].setIcon(StarView.ICON_STAR_BORDER); + stars[4].setIcon(StarView.ICON_STAR_BORDER); + break; + case 3: + stars[0].setIcon(StarView.ICON_STAR); + stars[1].setIcon(StarView.ICON_STAR); + stars[2].setIcon(StarView.ICON_STAR); + stars[3].setIcon(StarView.ICON_STAR_BORDER); + stars[4].setIcon(StarView.ICON_STAR_BORDER); + break; + case 4: + stars[0].setIcon(StarView.ICON_STAR); + stars[1].setIcon(StarView.ICON_STAR); + stars[2].setIcon(StarView.ICON_STAR); + stars[3].setIcon(StarView.ICON_STAR); + stars[4].setIcon(StarView.ICON_STAR_BORDER); + break; + case 5: + for(StarView star : stars) { + star.setIcon(StarView.ICON_STAR); + } + break; + } + } else if (c == 5) { + switch (a) { + case 0: + stars[0].setIcon(StarView.ICON_STAR_HALF); + stars[1].setIcon(StarView.ICON_STAR_BORDER); + stars[2].setIcon(StarView.ICON_STAR_BORDER); + stars[3].setIcon(StarView.ICON_STAR_BORDER); + stars[4].setIcon(StarView.ICON_STAR_BORDER); + break; + case 1: + stars[0].setIcon(StarView.ICON_STAR); + stars[1].setIcon(StarView.ICON_STAR_HALF); + stars[2].setIcon(StarView.ICON_STAR_BORDER); + stars[3].setIcon(StarView.ICON_STAR_BORDER); + stars[4].setIcon(StarView.ICON_STAR_BORDER); + break; + case 2: + stars[0].setIcon(StarView.ICON_STAR); + stars[1].setIcon(StarView.ICON_STAR); + stars[2].setIcon(StarView.ICON_STAR_HALF); + stars[3].setIcon(StarView.ICON_STAR_BORDER); + stars[4].setIcon(StarView.ICON_STAR_BORDER); + break; + case 3: + stars[0].setIcon(StarView.ICON_STAR); + stars[1].setIcon(StarView.ICON_STAR); + stars[2].setIcon(StarView.ICON_STAR); + stars[3].setIcon(StarView.ICON_STAR_HALF); + stars[4].setIcon(StarView.ICON_STAR_BORDER); + break; + case 4: + stars[0].setIcon(StarView.ICON_STAR); + stars[1].setIcon(StarView.ICON_STAR); + stars[2].setIcon(StarView.ICON_STAR); + stars[3].setIcon(StarView.ICON_STAR); + stars[4].setIcon(StarView.ICON_STAR_HALF); + break; + } + } + + /*for(StarView star: stars) { + for (int i = 0; i < a; i++) { + star.setIcon(StarView.ICON_STAR); + } + + if (c == 5) { + star.setIcon(StarView.ICON_STAR_HALF); + } else { + star.setIcon(StarView.ICON_STAR_BORDER); + } + + star.setIcon(StarView.ICON_STAR_BORDER); + }*/ + + /*Log.e("Проверочка", "Число перед запятой: " + a); // 3 + Log.e("Проверочка", "Число после запятой: " + b); // 9 + + for (int i = 0; i < stars.length; i++) { + for (int j = 0; j < a; j++) { + stars[i].setIcon(StarView.ICON_STAR); + } + + if (b == 0) { + c = 5 - a; + for (int k = 0; k < c; k++) { + stars[i].setIcon(StarView.ICON_STAR_BORDER); + } + } else { + if (b <= 5) { + c = 5 - a; + for (int k = 0; k < c; k++) { + stars[i].setIcon(StarView.ICON_STAR_BORDER); + } + } else { + stars[i].setIcon(StarView.ICON_STAR_HALF); + + } + } + }*/ + } + + public class StarView extends android.support.v7.widget.AppCompatImageView { + + public static final int ICON_STAR = 0; + public static final int ICON_STAR_HALF = 1; + public static final int ICON_STAR_BORDER = 2; + + private Drawable icon; + + public StarView(Context context) { + super(context); + + icon = Theme.getIcon(R.drawable.ic_star, ContextCompat.getColor(context, Theme.iconActiveColor())); + setImageDrawable(icon); + } + + public void setIcon(int style) { + if (style == ICON_STAR) { + icon = Theme.getIcon(R.drawable.ic_star, ContextCompat.getColor(getContext(), Theme.iconActiveColor())); + } else if (style == ICON_STAR_HALF) { + icon = Theme.getIcon(R.drawable.ic_star_half, ContextCompat.getColor(getContext(), Theme.iconActiveColor())); + } else if (style == ICON_STAR_BORDER) { + icon = Theme.getIcon(R.drawable.ic_star_border, ContextCompat.getColor(getContext(), Theme.iconActiveColor())); + } + + setImageDrawable(icon); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/ReviewView.java b/app/src/main/java/org/michaelbel/application/ui/view/ReviewView.java new file mode 100644 index 000000000..587c591c4 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/ReviewView.java @@ -0,0 +1,131 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; + +public class ReviewView extends FrameLayout { + + private TextView authorTextView; + private TextView contentTextView; + + private Paint paint; + private boolean divider; + private Rect rect = new Rect(); + + public ReviewView(Context context) { + super(context); + + setForeground(Theme.selectableItemBackgroundDrawable()); + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + if (paint == null) { + paint = new Paint(); + paint.setStrokeWidth(1); + paint.setColor(ContextCompat.getColor(context, Theme.dividerColor())); + } + + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, + LayoutHelper.MATCH_PARENT, 12, 12, 12, 12)); + addView(layout); + +//-------------------------------------------------------------------------------------------------- + + LinearLayout layout1 = new LinearLayout(context); + layout1.setOrientation(LinearLayout.HORIZONTAL); + layout.addView(layout1); + + ImageView userImageView = new ImageView(context); + userImageView.setImageDrawable(Theme.getIcon(R.drawable.ic_account, ContextCompat.getColor(context, Theme.iconActiveColor()))); + userImageView.setLayoutParams(LayoutHelper.makeLinear(18, 18, + Gravity.START | Gravity.CENTER_VERTICAL)); + layout1.addView(userImageView); + + authorTextView = new TextView(context); + authorTextView.setMaxLines(1); + authorTextView.setEllipsize(TextUtils.TruncateAt.END); + authorTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + authorTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + authorTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + authorTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL, 4, 0, 0, 0)); + layout1.addView(authorTextView); + +//-------------------------------------------------------------------------------------------------- + + contentTextView = new TextView(context); + contentTextView.setMaxLines(5); + contentTextView.setEllipsize(TextUtils.TruncateAt.END); + contentTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + contentTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + contentTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.TOP, 0, 2, 0, 0)); + layout.addView(contentTextView); + } + + public ReviewView setAuthor(@NonNull String name) { + authorTextView.setText(name); + return this; + } + + public ReviewView setContent(@NonNull String text) { + contentTextView.setText(text); + return this; + } + + public ReviewView setDivider(boolean divider) { + this.divider = divider; + setWillNotDraw(!divider); + return this; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY); + int height = getMeasuredHeight() + (divider ? 1 : 0); + + setMeasuredDimension(width, height); + } + + @Override + protected void onDraw(Canvas canvas) { + if (divider) { + canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/TitleView.java b/app/src/main/java/org/michaelbel/application/ui/view/TitleView.java new file mode 100644 index 000000000..561c8bf96 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/TitleView.java @@ -0,0 +1,68 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.michaelbel.application.moviemade.LayoutHelper; + +@SuppressWarnings("all") +public class TitleView extends FrameLayout { + + public TextView titleTextView; + public TextView subtitleTextView; + + public TitleView(Context context) { + super(context); + initialize(context); + } + + public TitleView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context); + } + + public void initialize(Context context) { + titleTextView = new TextView(context); + titleTextView.setSingleLine(); + titleTextView.setTextColor(0xFFFFFFFF); + titleTextView.setEllipsize(TextUtils.TruncateAt.END); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + titleTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + titleTextView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.TOP, 0, 8, 0, 0)); + addView(titleTextView); + + subtitleTextView = new TextView(context); + subtitleTextView.setSingleLine(); + subtitleTextView.setTextColor(0xFFD5E8F7); + subtitleTextView.setEllipsize(TextUtils.TruncateAt.END); + subtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + subtitleTextView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 0, 0, 0, 8)); + addView(subtitleTextView); + } + + public void setTitle(@NonNull CharSequence title) { + titleTextView.setText(title); + } + + public void setTitle(@StringRes int textId) { + setTitle(getContext().getText(textId)); + } + + public void setSubtitle(@NonNull CharSequence subtitle) { + subtitleTextView.setText(subtitle); + } + + public void setSubtitle(@StringRes int textId) { + setSubtitle(getContext().getText(textId)); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/TrailersSectionView.java b/app/src/main/java/org/michaelbel/application/ui/view/TrailersSectionView.java new file mode 100644 index 000000000..a9bc0c735 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/TrailersSectionView.java @@ -0,0 +1,90 @@ +package org.michaelbel.application.ui.view; + +import android.content.Context; +import android.graphics.Typeface; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.ui.view.widget.RecyclerListView; + +public class TrailersSectionView extends FrameLayout { + + private RecyclerListView recyclerView; + private SectionTrailersListener sectionListener; + + public interface SectionTrailersListener { + void onTrailerClick(View view, int position); + boolean onTrailerLongClick(View view, int position); + } + + public TrailersSectionView(Context context) { + super(context); + + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + TextView textView = new TextView(context); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(); + textView.setText("Trailers"); + textView.setGravity(Gravity.CENTER_VERTICAL); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + textView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + textView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + textView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, 48, + Gravity.START | Gravity.TOP, 16, 0, 16, 0)); + addView(textView); + + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); + + recyclerView = new RecyclerListView(context); + recyclerView.setHasFixedSize(true); + recyclerView.setLayoutManager(layoutManager); + //recyclerView.setNestedScrollingEnabled(false); + recyclerView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 48, 0, 0)); + recyclerView.setOnItemClickListener((view, position) -> { + if (sectionListener != null) { + sectionListener.onTrailerClick(view, position); + } + }); + recyclerView.setOnItemLongClickListener((view, position) -> { + if (sectionListener != null) { + sectionListener.onTrailerLongClick(view, position); + return true; + } + return false; + }); + addView(recyclerView); + } + + public TrailersSectionView setListener(SectionTrailersListener listener) { + sectionListener = listener; + return this; + } + + public TrailersSectionView setAdapter(RecyclerView.Adapter adapter) { + recyclerView.setAdapter(adapter); + return this; + } + + public RecyclerListView getRecyclerView() { + return recyclerView; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + setMeasuredDimension(width, height); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/cell/DateCell.java b/app/src/main/java/org/michaelbel/application/ui/view/cell/DateCell.java new file mode 100644 index 000000000..d9b73be8b --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/cell/DateCell.java @@ -0,0 +1,50 @@ +package org.michaelbel.application.ui.view.cell; + +import android.content.Context; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.moviemade.annotation.Beta; +import org.michaelbel.application.util.ScreenUtils; + +@Beta +public class DateCell extends FrameLayout { + + private TextView textView; + + public DateCell(Context context) { + super(context); + + setBackgroundColor(ContextCompat.getColor(context, R.color.md_grey_200)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + textView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + textView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + textView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL, 16, 0, 16, 0)); + addView(textView); + } + + public void setText(@NonNull String text) { + textView.setText(text.toUpperCase()); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY); + int height = ScreenUtils.dp(32); + + setMeasuredDimension(width, height); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/cell/EmptyCell.java b/app/src/main/java/org/michaelbel/application/ui/view/cell/EmptyCell.java new file mode 100644 index 000000000..0a252154d --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/cell/EmptyCell.java @@ -0,0 +1,114 @@ +package org.michaelbel.application.ui.view.cell; + +import android.content.Context; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.support.v4.content.ContextCompat; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class EmptyCell extends FrameLayout { + + public static final int MODE_DEFAULT = 10; + public static final int MODE_TEXT = 11; + public static final int MODE_LOADING = 12; + + @IntDef({ MODE_DEFAULT, MODE_TEXT, MODE_LOADING }) + private @interface Mode {} + + private int mHeight = 8; + private int currentMode = MODE_DEFAULT; + + private ProgressBar progressBar; + private TextView textView; + + public EmptyCell(Context context) { + super(context); + + textView = new TextView(context); + textView.setVisibility(INVISIBLE); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + textView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + textView.setPadding(ScreenUtils.dp(16), ScreenUtils.dp(12), ScreenUtils.dp(16), ScreenUtils.dp(12)); + textView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + addView(textView); + + progressBar = new ProgressBar(context); + progressBar.setVisibility(INVISIBLE); + progressBar.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + addView(progressBar); + } + + public void setHeight(int height) { + if (currentMode == MODE_DEFAULT) { + mHeight = height; + requestLayout(); + } + } + + public void setText(@NonNull CharSequence text) { + if (currentMode == MODE_TEXT) { + textView.setText(text); + } + } + + public void setText(@StringRes int textId) { + setText(getContext().getText(textId)); + } + + public void setMode(@Mode int mode) { + currentMode = mode; + + if (currentMode == MODE_DEFAULT) { + textView.setVisibility(GONE); + progressBar.setVisibility(GONE); + } else if (currentMode == MODE_TEXT) { + textView.setVisibility(VISIBLE); + progressBar.setVisibility(GONE); + } else if (currentMode == MODE_LOADING) { + progressBar.setVisibility(VISIBLE); + textView.setVisibility(GONE); + } + } + + public void changeLayoutParams() { + LayoutParams params = new LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + + if (ScreenUtils.isLandscape()) { + params.leftMargin = ScreenUtils.dp(56); + params.rightMargin = ScreenUtils.dp(56); + } + + setLayoutParams(params); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY); + int height = mHeight; + + if (currentMode == MODE_TEXT) { + width = getMeasuredWidth(); + height = getMeasuredHeight(); + } else if (currentMode == MODE_LOADING) { + height = MeasureSpec.makeMeasureSpec(ScreenUtils.dp(54), MeasureSpec.EXACTLY); + } else if (currentMode == MODE_DEFAULT) { + height = mHeight; + } + + setMeasuredDimension(width, height); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/cell/TextCell.java b/app/src/main/java/org/michaelbel/application/ui/view/cell/TextCell.java new file mode 100644 index 000000000..a6d170e78 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/cell/TextCell.java @@ -0,0 +1,217 @@ +package org.michaelbel.application.ui.view.cell; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.support.annotation.ColorRes; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.AppCompatCheckBox; +import android.support.v7.widget.AppCompatTextView; +import android.support.v7.widget.SwitchCompat; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class TextCell extends FrameLayout { + + public static final int MODE_DEFAULT = 100; + public static final int MODE_VALUE_TEXT = 200; + public static final int MODE_SWITCH = 300; + public static final int MODE_CHECKBOX = 400; + public static final int MODE_COLOR = 500; + + @IntDef({ + MODE_DEFAULT, + MODE_VALUE_TEXT, + MODE_SWITCH, + MODE_CHECKBOX, + MODE_COLOR + }) + private @interface Mode {} + + protected TextView textView; + protected TextView valueText; + protected SwitchCompat switchCompat; + protected AppCompatCheckBox checkBox; + + private Paint paint; + private boolean divider; + private Rect rect = new Rect(); + private int currentMode = MODE_DEFAULT; + + private int cellHeight; + + public TextCell(Context context) { + super(context); + + cellHeight = ScreenUtils.dp(48); + + setElevation(ScreenUtils.dp(1)); + setForeground(Theme.selectableItemBackgroundDrawable()); + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + if (paint == null) { + paint = new Paint(); + paint.setStrokeWidth(1); + paint.setColor(ContextCompat.getColor(context, Theme.dividerColor())); + } + + textView = new AppCompatTextView(context); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + textView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + textView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 16, 0, 16, 0)); + addView(textView); + + valueText = new AppCompatTextView(context); + valueText.setLines(1); + valueText.setMaxLines(1); + valueText.setSingleLine(); + valueText.setVisibility(INVISIBLE); + valueText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + valueText.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + valueText.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 16, 0)); + addView(valueText); + + switchCompat = new SwitchCompat(context); + switchCompat.setClickable(false); + switchCompat.setFocusable(false); + switchCompat.setVisibility(INVISIBLE); + switchCompat.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 16, 0)); + addView(switchCompat); + + checkBox = new AppCompatCheckBox(context); + checkBox.setClickable(false); + checkBox.setFocusable(false); + checkBox.setVisibility(INVISIBLE); + checkBox.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 16, 0)); + addView(checkBox); + + setMode(currentMode); + } + + public void setText(@NonNull String text) { + textView.setText(text); + } + + public void setText(@StringRes int textId) { + textView.setText(getContext().getText(textId)); + } + + public void setChecked(boolean value) { + if (currentMode == MODE_SWITCH) { + switchCompat.setChecked(value); + } + + if (currentMode == MODE_CHECKBOX) { + checkBox.setChecked(value); + } + } + + public void setValue(@NonNull String value) { + valueText.setText(value); + } + + public void setValue(@StringRes int textId) { + valueText.setText(getContext().getText(textId)); + } + + public void setMode(@Mode int mode) { + currentMode = mode; + + if (currentMode == MODE_DEFAULT) { + valueText.setVisibility(INVISIBLE); + switchCompat.setVisibility(INVISIBLE); + checkBox.setVisibility(INVISIBLE); + } else if (currentMode == MODE_VALUE_TEXT) { + valueText.setVisibility(VISIBLE); + switchCompat.setVisibility(INVISIBLE); + checkBox.setVisibility(INVISIBLE); + } else if (currentMode == MODE_SWITCH) { + switchCompat.setVisibility(VISIBLE); + valueText.setVisibility(INVISIBLE); + checkBox.setVisibility(INVISIBLE); + } else if (currentMode == MODE_CHECKBOX) { + checkBox.setVisibility(VISIBLE); + valueText.setVisibility(INVISIBLE); + switchCompat.setVisibility(INVISIBLE); + } else if (currentMode == MODE_COLOR) { + valueText.setVisibility(INVISIBLE); + switchCompat.setVisibility(INVISIBLE); + checkBox.setVisibility(INVISIBLE); + } + } + + public void setDivider(boolean divider) { + this.divider = divider; + setWillNotDraw(!divider); + } + + public void changeLayoutParams() { + LayoutParams params = new LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + + if (ScreenUtils.isLandscape()) { + params.leftMargin = ScreenUtils.dp(56); + params.rightMargin = ScreenUtils.dp(56); + } + + setLayoutParams(params); + } + + public void setTextColor(@ColorRes int color) { + textView.setTextColor(ContextCompat.getColor(getContext(), color)); + } + + public TextCell setHeight(int height) { + cellHeight = height; + return this; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY); + int height = cellHeight + (divider ? 1 : 0); + setMeasuredDimension(width, height); + } + + @Override + protected void onDraw(Canvas canvas) { + if (divider) { + canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getForeground().setHotspot(event.getX(), event.getY()); + } + } + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/cell/TextDetailCell.java b/app/src/main/java/org/michaelbel/application/ui/view/cell/TextDetailCell.java new file mode 100644 index 000000000..8e743f38d --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/cell/TextDetailCell.java @@ -0,0 +1,244 @@ +package org.michaelbel.application.ui.view.cell; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.support.v4.content.ContextCompat; +import android.support.v4.graphics.drawable.DrawableCompat; +import android.support.v7.widget.AppCompatCheckBox; +import android.support.v7.widget.SwitchCompat; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class TextDetailCell extends FrameLayout { + + public static final int MODE_DEFAULT = 100; + public static final int MODE_SWITCH = 200; + public static final int MODE_CHECKBOX = 300; + + @IntDef({ + MODE_DEFAULT, + MODE_SWITCH, + MODE_CHECKBOX + }) + private @interface Mode {} + + protected TextView textView; + protected TextView valueText; + protected SwitchCompat switchCompat; + protected AppCompatCheckBox checkBox; + + private Paint paint; + private boolean divider; + private boolean multiline; + private Rect rect = new Rect(); + private int currentMode = MODE_DEFAULT; + + public TextDetailCell(Context context) { + super(context); + + setElevation(ScreenUtils.dp(1)); + setForeground(Theme.selectableItemBackgroundDrawable()); + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + if (paint == null) { + paint = new Paint(); + paint.setStrokeWidth(1); + paint.setColor(ContextCompat.getColor(context, Theme.dividerColor())); + } + + textView = new TextView(context); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + textView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + textView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 16, 10, 16, 0)); + addView(textView); + + valueText = new TextView(context); + valueText.setLines(1); + valueText.setMaxLines(1); + valueText.setSingleLine(); + valueText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + valueText.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + valueText.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 16, 35, 16, 0)); + addView(valueText); + + switchCompat = new SwitchCompat(context); // Theme.switchTheme() + switchCompat.setClickable(false); + switchCompat.setFocusable(false); + switchCompat.setVisibility(INVISIBLE); + switchCompat.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 16, 0)); + addView(switchCompat); + + checkBox = new AppCompatCheckBox(context); + checkBox.setClickable(false); + checkBox.setFocusable(false); + checkBox.setVisibility(INVISIBLE); + checkBox.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 16, 0)); + addView(checkBox); + + changeSwitchTheme(); + setMode(currentMode); + } + + public void setText(@NonNull String text) { + textView.setText(text); + } + + public void setText(@StringRes int textId) { + textView.setText(getContext().getText(textId)); + } + + public void setValue(@NonNull String text) { + valueText.setText(text); + } + + public void setValue(@StringRes int textId) { + valueText.setText(getContext().getText(textId)); + } + + public void setChecked(boolean value) { + if (currentMode == MODE_SWITCH) { + switchCompat.setChecked(value); + } else if (currentMode == MODE_CHECKBOX) { + checkBox.setChecked(value); + } + } + + public void setMode(int mode) { + currentMode = mode; + + if (currentMode == MODE_DEFAULT) { + valueText.setVisibility(VISIBLE); + switchCompat.setVisibility(INVISIBLE); + checkBox.setVisibility(INVISIBLE); + } else if (currentMode == MODE_SWITCH) { + valueText.setVisibility(VISIBLE); + switchCompat.setVisibility(VISIBLE); + checkBox.setVisibility(INVISIBLE); + } else if (currentMode == MODE_CHECKBOX) { + valueText.setVisibility(VISIBLE); + checkBox.setVisibility(VISIBLE); + switchCompat.setVisibility(INVISIBLE); + } + } + + public void setDivider(boolean divider) { + this.divider = divider; + setWillNotDraw(!divider); + } + + public void setMultiline(boolean value) { + multiline = value; + + if (value) { + valueText.setLines(0); + valueText.setMaxLines(0); + valueText.setSingleLine(false); + valueText.setPadding(0, 0, 0, ScreenUtils.dp(12)); + } else { + valueText.setLines(1); + valueText.setMaxLines(1); + valueText.setSingleLine(); + valueText.setPadding(0, 0, 0, 0); + } + } + + public void changeLayoutParams() { + LayoutParams params = new LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + + if (ScreenUtils.isLandscape()) { + params.leftMargin = ScreenUtils.dp(56); + params.rightMargin = ScreenUtils.dp(56); + } + + setLayoutParams(params); + } + + public void changeSwitchTheme() { + int thumbOn = ContextCompat.getColor(getContext(), Theme.thumbOnColor()); + int thumbOff = ContextCompat.getColor(getContext(), Theme.thumbOffColor()); + + int trackOn = ContextCompat.getColor(getContext(), Theme.trackOnColor()); + int trackOff = ContextCompat.getColor(getContext(), Theme.trackOffColor()); + + DrawableCompat.setTintList(switchCompat.getThumbDrawable(), new ColorStateList( + new int[][]{ + new int[]{ android.R.attr.state_checked }, + new int[]{} + }, + new int[]{ + thumbOn, + thumbOff + })); + + DrawableCompat.setTintList(switchCompat.getTrackDrawable(), new ColorStateList( + new int[][]{ + new int[]{ android.R.attr.state_checked }, + new int[]{} + }, + new int[]{ + trackOn, + trackOff + })); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int height; + int width = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY); + + if (multiline) { + height = getMeasuredHeight(); + } else { + height = ScreenUtils.dp(64) + (divider ? 1 : 0); + } + + setMeasuredDimension(width, height); + } + + @Override + protected void onDraw(Canvas canvas) { + if (divider) { + canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewCard.java b/app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewCard.java new file mode 100644 index 000000000..90afef9dc --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewCard.java @@ -0,0 +1,135 @@ +package org.michaelbel.application.ui.view.movie; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.CardView; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class MovieViewCard extends FrameLayout { + + private CardView cardView; + private ImageView posterImageView; + private TextView titleTextView; + private TextView yearTextView; + + private Rect rect = new Rect(); + + public MovieViewCard(Context context) { + super(context); + + cardView = new CardView(context); + cardView.setUseCompatPadding(true); + cardView.setPreventCornerOverlap(false); + cardView.setRadius(ScreenUtils.dp(2)); + cardView.setCardElevation(ScreenUtils.dp(1.5F)); + cardView.setForeground(Theme.selectableItemBackgroundBorderlessDrawable()); + cardView.setCardBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + cardView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + addView(cardView); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.VERTICAL); + cardView.addView(linearLayout); + + posterImageView = new ImageView(context); + posterImageView.setScaleType(ImageView.ScaleType.FIT_XY); + posterImageView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + linearLayout.addView(posterImageView); + + titleTextView = new TextView(context); + titleTextView.setLines(1); + titleTextView.setMaxLines(2); + titleTextView.setEllipsize(TextUtils.TruncateAt.END); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + titleTextView.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL)); + titleTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + titleTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + Gravity.START, 8, 6, 8, 0)); + linearLayout.addView(titleTextView); + + yearTextView = new TextView(context); + yearTextView.setLines(1); + yearTextView.setMaxLines(1); + yearTextView.setSingleLine(); + yearTextView.setEllipsize(TextUtils.TruncateAt.END); + yearTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + yearTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + yearTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + Gravity.START, 8, 0, 8, 6)); + linearLayout.addView(yearTextView); + } + + public ImageView getPosterImage() { + return posterImageView; + } + + public MovieViewCard setPoster(@NonNull String posterPath) { + SharedPreferences prefs = getContext().getSharedPreferences("main_config", Context.MODE_PRIVATE); + String size = prefs.getString("image_quality_poster", "w342"); + + Glide.with(getContext()) + .load("http://image.tmdb.org/t/p/" + size + "/" + posterPath) + .into(posterImageView); + return this; + } + + public MovieViewCard setTitle(@NonNull String title) { + titleTextView.setText(title.isEmpty() ? "" : title); + return this; + } + + public MovieViewCard setYear(@NonNull String releaseDate) { + if (releaseDate.length() >= 4) { + yearTextView.setText(releaseDate.substring(0, 4)); + } + return this; + } + + public MovieViewCard changeLayoutParams(boolean gravity) { + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + + if (gravity) { + params.leftMargin = ScreenUtils.dp(3F); + } else { + params.rightMargin = ScreenUtils.dp(3F); + } + + setLayoutParams(params); + return this; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (cardView.getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + cardView.getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewList.java b/app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewList.java new file mode 100644 index 000000000..394912abd --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewList.java @@ -0,0 +1,171 @@ +package org.michaelbel.application.ui.view.movie; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.ui.view.RatingView; + +import static android.widget.LinearLayout.HORIZONTAL; + +public class MovieViewList extends FrameLayout { + + public int movieId; + + private ImageView posterImageView; + private TextView titleTextView; + private TextView yearTextView; + private RatingView ratingView; + private TextView ratingTextView; + + private Paint paint; + private boolean divider; + private Rect rect = new Rect(); + + public MovieViewList(Context context) { + super(context); + + setForeground(Theme.selectableItemBackgroundDrawable()); + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + if (paint == null) { + paint = new Paint(); + paint.setStrokeWidth(1); + paint.setColor(ContextCompat.getColor(context, Theme.dividerColor())); + } + + posterImageView = new ImageView(context); + posterImageView.setScaleType(ImageView.ScaleType.FIT_XY); + posterImageView.setLayoutParams(LayoutHelper.makeFrame(60, 90, + Gravity.START, 8, 8, 0, 8)); + addView(posterImageView); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, + 72, 0, 0, 0)); + addView(linearLayout); + + titleTextView = new TextView(context); + titleTextView.setLines(1); + titleTextView.setMaxLines(2); + titleTextView.setEllipsize(TextUtils.TruncateAt.END); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17); + titleTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + titleTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + titleTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.TOP, 16, 16, 16, 0)); + linearLayout.addView(titleTextView); + + yearTextView = new TextView(context); + yearTextView.setLines(1); + yearTextView.setMaxLines(1); + yearTextView.setSingleLine(); + yearTextView.setEllipsize(TextUtils.TruncateAt.END); + yearTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + yearTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + yearTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.TOP, 16, 0, 12, 0)); + linearLayout.addView(yearTextView); + + LinearLayout ratingLayout = new LinearLayout(context); + ratingLayout.setOrientation(HORIZONTAL); + ratingLayout.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, + 16, 0, 16, 0)); + linearLayout.addView(ratingLayout); + + ratingView = new RatingView(context); + ratingView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL)); + //ratingLayout.addView(ratingView); + + ratingTextView = new TextView(context); + ratingTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + ratingTextView.setTextColor(ContextCompat.getColor(context, Theme.secondaryTextColor())); + ratingTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + ratingTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.CENTER_VERTICAL, /*12*/ 0, 0, 0, 0)); + ratingLayout.addView(ratingTextView); + } + + public MovieViewList setPoster(@NonNull String posterPath) { + SharedPreferences prefs = getContext().getSharedPreferences("main_config", Context.MODE_PRIVATE); + String size = prefs.getString("image_quality_poster", "w342"); + + Glide.with(getContext()) + .load("http://image.tmdb.org/t/p/" + size +"/" + posterPath) + .into(posterImageView); + return this; + } + + public MovieViewList setTitle(@NonNull String title) { + titleTextView.setText(title); + return this; + } + + public MovieViewList setYear(@NonNull String date) { + if (date.length() >= 4) { + yearTextView.setText(date.substring(0, 4)); + } + return this; + } + + public MovieViewList setVoteAverage(float voteAverage) { + ratingView.setRating(voteAverage); + ratingTextView.setText(String.valueOf(voteAverage)); + return this; + } + + public MovieViewList setDivider(boolean divider) { + this.divider = divider; + setWillNotDraw(!divider); + return this; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY); + int height = getMeasuredHeight(); + setMeasuredDimension(width, height); + } + + @Override + protected void onDraw(Canvas canvas) { + if (divider) { + canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewPoster.java b/app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewPoster.java new file mode 100644 index 000000000..fb68263ae --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/movie/MovieViewPoster.java @@ -0,0 +1,69 @@ +package org.michaelbel.application.ui.view.movie; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Rect; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.CardView; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class MovieViewPoster extends FrameLayout { + + private CardView cardView; + private ImageView posterImageView; + + private Rect rect = new Rect(); + + public MovieViewPoster(Context context) { + super(context); + + cardView = new CardView(context); + cardView.setUseCompatPadding(false); + cardView.setPreventCornerOverlap(false); + cardView.setRadius(ScreenUtils.dp(2)); + cardView.setCardElevation(ScreenUtils.dp(0)); + cardView.setForeground(Theme.selectableItemBackgroundBorderlessDrawable()); + cardView.setCardBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + cardView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, 260)); + addView(cardView); + + posterImageView = new ImageView(context); + posterImageView.setScaleType(ImageView.ScaleType.FIT_XY); + posterImageView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + cardView.addView(posterImageView); + } + + public MovieViewPoster setPoster(@NonNull String posterPath) { + SharedPreferences prefs = getContext().getSharedPreferences("main_config", Context.MODE_PRIVATE); + String size = prefs.getString("image_quality_poster", "w342"); + + Glide.with(getContext()) + .load("http://image.tmdb.org/t/p/" + size +"/" + posterPath) + .into(posterImageView); + return this; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (cardView.getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + cardView.getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/trailer/TrailerCompatView.java b/app/src/main/java/org/michaelbel/application/ui/view/trailer/TrailerCompatView.java new file mode 100644 index 000000000..0e8a3ab84 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/trailer/TrailerCompatView.java @@ -0,0 +1,164 @@ +package org.michaelbel.application.ui.view.trailer; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.CardView; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class TrailerCompatView extends FrameLayout { + + private CardView cardView; + private ImageView trailerImage; + private ImageView playerImage; + private TextView titleText; + private TextView qualityText; + + private Rect rect = new Rect(); + + public TrailerCompatView(Context context) { + super(context); + + cardView = new CardView(context); + cardView.setUseCompatPadding(true); + cardView.setPreventCornerOverlap(false); + cardView.setForeground(Theme.selectableItemBackgroundBorderlessDrawable()); + cardView.setCardBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + cardView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, + LayoutHelper.MATCH_PARENT)); + addView(cardView); + + trailerImage = new ImageView(context); + trailerImage.setScaleType(ImageView.ScaleType.CENTER_CROP); + trailerImage.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, 180, Gravity.TOP)); + cardView.addView(trailerImage); + + ImageView playImageView = new ImageView(context); + playImageView.setImageResource(R.drawable.ic_button_play); + playImageView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 24)); + cardView.addView(playImageView); + + FrameLayout layout = new FrameLayout(context); + layout.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP, 0, 185, 0, 0)); + cardView.addView(layout); + + playerImage = new ImageView(context); + playerImage.setVisibility(INVISIBLE); + playerImage.setImageDrawable(Theme.getIcon(R.drawable.ic_youtube, ContextCompat.getColor(context, R.color.youtubeColor))); + playerImage.setLayoutParams(LayoutHelper.makeFrame(24, 24, Gravity.START | Gravity.CENTER_VERTICAL, 12, 0, 0, 0)); + layout.addView(playerImage); + + titleText = new TextView(context); + titleText.setMaxLines(1); + titleText.setEllipsize(TextUtils.TruncateAt.END); + titleText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + titleText.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + titleText.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 12, 0, 12, 0)); + layout.addView(titleText); + + qualityText = new TextView(context); + qualityText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 11); + qualityText.setTextColor(ContextCompat.getColor(context, Theme.primaryColor())); + qualityText.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + qualityText.setBackground(ContextCompat.getDrawable(context, R.drawable.rect_quality)); + qualityText.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 12, 0)); + layout.addView(qualityText); + } + + public TrailerCompatView setTitle(@NonNull String title) { + titleText.setText(title); + return this; + } + + public TrailerCompatView setQuality(@NonNull String quality) { + qualityText.setText(quality + "p"); + return this; + } + + public TrailerCompatView setSite(String site) { + if (site != null) { + if (site.equals("YouTube")) { + playerImage.setVisibility(VISIBLE); + titleText.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 48, 0, 64, 0)); + } else { + playerImage.setVisibility(INVISIBLE); + titleText.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 12, 0, 50, 0)); + } + } else { + playerImage.setVisibility(INVISIBLE); + titleText.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, + LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 12, 0, 50, 0)); + } + return this; + } + + public TrailerCompatView setTrailerImage(@NonNull String trailerKey) { + try { + Glide.with(getContext()) + .load("http://img.youtube.com/vi/" + trailerKey + "/0.jpg") + .into(trailerImage); + } catch (Exception e) { + //FirebaseCrash.report(e); + } + return this; + } + + public TrailerCompatView changeLayoutParams(boolean gravity) { + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + + if (gravity) { + params.leftMargin = ScreenUtils.dp(3F); + } else { + params.rightMargin = ScreenUtils.dp(3F); + } + + setLayoutParams(params); + return this; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (cardView.getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + cardView.getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + setMeasuredDimension(width, height); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/trailer/TrailerView.java b/app/src/main/java/org/michaelbel/application/ui/view/trailer/TrailerView.java new file mode 100644 index 000000000..fd6fbb88a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/trailer/TrailerView.java @@ -0,0 +1,150 @@ +package org.michaelbel.application.ui.view.trailer; + +import android.content.Context; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import org.michaelbel.application.R; +import org.michaelbel.application.moviemade.LayoutHelper; +import org.michaelbel.application.moviemade.Theme; +import org.michaelbel.application.util.ScreenUtils; + +public class TrailerView extends FrameLayout { + + private ImageView trailerImageView; + private ImageView playerImageView; + private TextView titleTextView; + private TextView qualityTextView; + + /*private Rect rect = new Rect();*/ + + public TrailerView(Context context) { + super(context); + + setForeground(Theme.selectableItemBackgroundDrawable()); + setBackgroundColor(ContextCompat.getColor(context, Theme.foregroundColor())); + + FrameLayout imageLayout = new FrameLayout(context); + imageLayout.setLayoutParams(LayoutHelper.makeFrame(180, 100, + Gravity.TOP, 8, 8, 8, 0)); + addView(imageLayout); + + trailerImageView = new ImageView(context); + trailerImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + trailerImageView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + imageLayout.addView(trailerImageView); + + ImageView playImageView = new ImageView(context); + playImageView.setImageResource(R.drawable.ic_button_play); + playImageView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.CENTER)); + imageLayout.addView(playImageView); + + qualityTextView = new TextView(context); + qualityTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 8); + qualityTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryColor())); + qualityTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + qualityTextView.setBackground(ContextCompat.getDrawable(context, R.drawable.rect_quality_mini)); + qualityTextView.setLayoutParams(LayoutHelper.makeFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.END | Gravity.BOTTOM, 0, 0, 5, 5)); + imageLayout.addView(qualityTextView); + + LinearLayout titleLayout = new LinearLayout(context); + titleLayout.setOrientation(LinearLayout.HORIZONTAL); + titleLayout.setLayoutParams(LayoutHelper.makeFrame(180, LayoutHelper.WRAP_CONTENT, + Gravity.TOP, 8, 112, 8, 0)); + addView(titleLayout); + + playerImageView = new ImageView(context); + playerImageView.setImageDrawable(Theme.getIcon(R.drawable.ic_youtube, 0xFFF44336)); + playerImageView.setLayoutParams(LayoutHelper.makeLinear(24, 24, + Gravity.START | Gravity.TOP, 0, 2, 0, 0)); + titleLayout.addView(playerImageView); + + titleTextView = new TextView(context); + titleTextView.setLines(2); + titleTextView.setMaxLines(2); + titleTextView.setEllipsize(TextUtils.TruncateAt.END); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + titleTextView.setTextColor(ContextCompat.getColor(context, Theme.primaryTextColor())); + titleTextView.setLayoutParams(LayoutHelper.makeLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, + Gravity.START | Gravity.TOP, 5, 5, 0, 0)); + titleLayout.addView(titleTextView); + } + + public TrailerView setTrailerImage(@NonNull String trailerKey) { + Glide.with(getContext()) + .load("http://img.youtube.com/vi/" + trailerKey + "/0.jpg") + .into(trailerImageView); + return this; + } + + public TrailerView setTitle(@NonNull String title) { + titleTextView.setText(title); + return this; + } + + public TrailerView setQuality(@NonNull String quality) { + qualityTextView.setText(quality + "p"); + return this; + } + + public TrailerView setSite(@NonNull String site) { + if (site.equals("YouTube")) { + playerImageView.setVisibility(VISIBLE); + } else { + playerImageView.setVisibility(INVISIBLE); + } + return this; + } + + public void changeLayoutParams(boolean gravity) { + LayoutParams params = new LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + + if (gravity) { + params.leftMargin = ScreenUtils.dp(3F); + } else { + params.rightMargin = ScreenUtils.dp(3F); + } + + setLayoutParams(params); + } + + /*@Override + public boolean onTouchEvent(MotionEvent event) { + if (getForeground() != null) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getForeground().setHotspot(event.getX(), event.getY()); + } + } + + return super.onTouchEvent(event); + }*/ + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + + setMeasuredDimension(width, height); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/AppBarLayoutBehavior.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/AppBarLayoutBehavior.java new file mode 100644 index 000000000..04f7a306f --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/AppBarLayoutBehavior.java @@ -0,0 +1,30 @@ +package org.michaelbel.application.ui.view.widget; + +import android.content.Context; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CoordinatorLayout; +import android.util.AttributeSet; +import android.view.View; + +@SuppressWarnings("all") +public class AppBarLayoutBehavior extends AppBarLayout.Behavior { + + private boolean enabled; + + public AppBarLayoutBehavior(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + + @Override + public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View targetChild, View target, int nestedScrollAxes) { + return enabled && super.onStartNestedScroll(parent, child, targetChild, target, nestedScrollAxes); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/ColorPicker.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/ColorPicker.java new file mode 100644 index 000000000..1ff2c0726 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/ColorPicker.java @@ -0,0 +1,413 @@ +package org.michaelbel.application.ui.view.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.SweepGradient; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.ColorInt; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import org.michaelbel.application.util.ScreenUtils; + +@SuppressWarnings("all") +public class ColorPicker extends View { + + private static final String STATE_ANGLE = "angle"; + private static final String STATE_PARENT = "parent"; + private static final String STATE_OLD_COLOR = "color"; + private static final String STATE_SHOW_OLD_COLOR = "showColor"; + + /** + * Used material design colors. + */ + private final int[] COLORS = new int[] { + 0xFFF44336, + 0xFF9C27B0, + 0xFF2196F3, + 0xFF00BCD4, + 0xFF4CAF50, + 0xFFFFEB3B, + 0xFFF44336 + }; + + private Paint mPointerColor; + private Paint mColorWheelPaint; + private Paint mPointerHaloPaint; + + private int mColorWheelThickness; + private int mColorWheelRadius; + private int mPreferredColorWheelRadius; + private int mColorCenterRadius; + private int mPreferredColorCenterRadius; + private int mColorCenterHaloRadius; + private int mPreferredColorCenterHaloRadius; + private int mColorPointerRadius; + private int mColorPointerHaloRadius; + + private RectF mColorWheelRectangle = new RectF(); + private RectF mCenterRectangle = new RectF(); + + private boolean mUserIsMovingPointer = false; + private int mCenterOldColor; + private boolean mShowCenterOldColor; + private int mCenterNewColor; + private float mTranslationOffset; + private float mSlopX; + private float mSlopY; + private float mAngle; + + private Paint mCenterOldPaint; + private Paint mCenterNewPaint; + private Paint mCenterHaloPaint; + + private boolean mTouchAnywhereOnColorWheelEnabled = true; + + private ColorPicker.OnColorChangedListener onColorChangedListener; + private ColorPicker.OnColorSelectedListener onColorSelectedListener; + + private int oldChangedListenerColor; + private int oldSelectedListenerColor; + + public ColorPicker(Context context) { + super(context); + initialize(context, null, 0); + } + + public ColorPicker(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context, attrs, 0); + } + + public ColorPicker(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initialize(context, attrs, defStyle); + } + + private void initialize(Context context, AttributeSet attrs, int defStyle) { + mColorWheelThickness = ScreenUtils.dp(9); + mColorWheelRadius = ScreenUtils.dp(124); + mPreferredColorWheelRadius = mColorWheelRadius; + mColorCenterRadius = ScreenUtils.dp(54); + mPreferredColorCenterRadius = mColorCenterRadius; + mColorCenterHaloRadius = ScreenUtils.dp(54); + mPreferredColorCenterHaloRadius = mColorCenterHaloRadius; + mColorPointerRadius = ScreenUtils.dp(16); + mColorPointerHaloRadius = ScreenUtils.dp(16); + + mAngle = (float) (-Math.PI / 2); + + Shader s = new SweepGradient(0, 0, COLORS, null); + + mColorWheelPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mColorWheelPaint.setShader(s); + mColorWheelPaint.setStyle(Paint.Style.STROKE); + mColorWheelPaint.setStrokeWidth(mColorWheelThickness); + + mPointerHaloPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPointerHaloPaint.setColor(Color.BLACK); + mPointerHaloPaint.setAlpha(0x50); + + mPointerColor = new Paint(Paint.ANTI_ALIAS_FLAG); + mPointerColor.setColor(calculateColor(mAngle)); + + mCenterNewPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mCenterNewPaint.setColor(calculateColor(mAngle)); + mCenterNewPaint.setStyle(Paint.Style.FILL); + + mCenterOldPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mCenterOldPaint.setColor(calculateColor(mAngle)); + mCenterOldPaint.setStyle(Paint.Style.FILL); + + mCenterHaloPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mCenterHaloPaint.setColor(Color.BLACK); + mCenterHaloPaint.setAlpha(0x00); + + mCenterNewColor = calculateColor(mAngle); + mCenterOldColor = calculateColor(mAngle); + mShowCenterOldColor = true; + } + + public ColorPicker setNewCenterColor(@ColorInt int color) { + mCenterNewColor = color; + mCenterNewPaint.setColor(color); + + if (mCenterOldColor == 0) { + mCenterOldColor = color; + mCenterOldPaint.setColor(color); + } + + if (onColorChangedListener != null && color != oldChangedListenerColor ) { + onColorChangedListener.onColorChanged(color); + oldChangedListenerColor = color; + } + + invalidate(); + return this; + } + + public ColorPicker setOldCenterColor(int color) { + mCenterOldColor = color; + mCenterOldPaint.setColor(color); + invalidate(); + return this; + } + + public ColorPicker setShowOldCenterColor(boolean show) { + mShowCenterOldColor = show; + invalidate(); + return this; + } + + public ColorPicker setColor(int color) { + mAngle = colorToAngle(color); + mPointerColor.setColor(calculateColor(mAngle)); + setNewCenterColor(color); + return this; + } + + public interface OnColorChangedListener { + void onColorChanged(int color); + } + + public interface OnColorSelectedListener { + void onColorSelected(int color); + } + + public void setOnColorChangedListener(ColorPicker.OnColorChangedListener listener) { + onColorChangedListener = listener; + } + + public ColorPicker.OnColorChangedListener getOnColorChangedListener() { + return onColorChangedListener; + } + + public void setOnColorSelectedListener(ColorPicker.OnColorSelectedListener listener) { + onColorSelectedListener = listener; + } + + public ColorPicker.OnColorSelectedListener getOnColorSelectedListener() { + return onColorSelectedListener; + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.translate(mTranslationOffset, mTranslationOffset); + canvas.drawOval(mColorWheelRectangle, mColorWheelPaint); + + float[] pointerPosition = calculatePointerPosition(mAngle); + + canvas.drawCircle(pointerPosition[0], pointerPosition[1], mColorPointerHaloRadius, mPointerHaloPaint); + canvas.drawCircle(pointerPosition[0], pointerPosition[1], mColorPointerRadius, mPointerColor); + canvas.drawCircle(0, 0, mColorCenterHaloRadius, mCenterHaloPaint); + + if (mShowCenterOldColor) { + canvas.drawArc(mCenterRectangle, 90, 180, true, mCenterOldPaint); + canvas.drawArc(mCenterRectangle, 270, 180, true, mCenterNewPaint); + } else { + canvas.drawArc(mCenterRectangle, 0, 360, true, mCenterNewPaint); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int intrinsicSize = 2 * (mPreferredColorWheelRadius + mColorPointerHaloRadius); + + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + int width; + int height; + + if (widthMode == MeasureSpec.EXACTLY) { + width = widthSize; + } else if (widthMode == MeasureSpec.AT_MOST) { + width = Math.min(intrinsicSize, widthSize); + } else { + width = intrinsicSize; + } + + if (heightMode == MeasureSpec.EXACTLY) { + height = heightSize; + } else if (heightMode == MeasureSpec.AT_MOST) { + height = Math.min(intrinsicSize, heightSize); + } else { + height = intrinsicSize; + } + + int min = Math.min(width, height); + setMeasuredDimension(min, min); + mTranslationOffset = min * 0.5f; + + mColorWheelRadius = min / 2 - mColorWheelThickness - mColorPointerHaloRadius; + mColorWheelRectangle.set(-mColorWheelRadius, -mColorWheelRadius, mColorWheelRadius, mColorWheelRadius); + + mColorCenterRadius = (int) ((float) mPreferredColorCenterRadius * ((float) mColorWheelRadius / (float) mPreferredColorWheelRadius)); + mColorCenterHaloRadius = (int) ((float) mPreferredColorCenterHaloRadius * ((float) mColorWheelRadius / (float) mPreferredColorWheelRadius)); + mCenterRectangle.set(-mColorCenterRadius, -mColorCenterRadius, mColorCenterRadius, mColorCenterRadius); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + getParent().requestDisallowInterceptTouchEvent(true); + + float x = event.getX() - mTranslationOffset; + float y = event.getY() - mTranslationOffset; + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + float[] pointerPosition = calculatePointerPosition(mAngle); + + if (x >= (pointerPosition[0] - mColorPointerHaloRadius) && x <= (pointerPosition[0] + mColorPointerHaloRadius) && y >= (pointerPosition[1] - mColorPointerHaloRadius) && y <= (pointerPosition[1] + mColorPointerHaloRadius)) { + mSlopX = x - pointerPosition[0]; + mSlopY = y - pointerPosition[1]; + mUserIsMovingPointer = true; + invalidate(); + } else if (x >= -mColorCenterRadius && x <= mColorCenterRadius && y >= -mColorCenterRadius && y <= mColorCenterRadius && mShowCenterOldColor) { + mCenterHaloPaint.setAlpha(0x50); + setColor(getOldCenterColor()); + invalidate(); + } else if (Math.sqrt(x * x + y * y) <= mColorWheelRadius + mColorPointerHaloRadius && Math.sqrt(x * x + y * y) >= mColorWheelRadius - mColorPointerHaloRadius && mTouchAnywhereOnColorWheelEnabled) { + mUserIsMovingPointer = true; + invalidate(); + } else { + getParent().requestDisallowInterceptTouchEvent(false); + return false; + } + + break; + case MotionEvent.ACTION_MOVE: + if (mUserIsMovingPointer) { + mAngle = (float) Math.atan2(y - mSlopY, x - mSlopX); + mPointerColor.setColor(calculateColor(mAngle)); + setNewCenterColor(mCenterNewColor = calculateColor(mAngle)); + invalidate(); + } else { + getParent().requestDisallowInterceptTouchEvent(false); + return false; + } + + break; + case MotionEvent.ACTION_UP: + mUserIsMovingPointer = false; + mCenterHaloPaint.setAlpha(0x00); + + if (onColorSelectedListener != null && mCenterNewColor != oldSelectedListenerColor) { + onColorSelectedListener.onColorSelected(mCenterNewColor); + oldSelectedListenerColor = mCenterNewColor; + } + + invalidate(); + break; + case MotionEvent.ACTION_CANCEL: + if (onColorSelectedListener != null && mCenterNewColor != oldSelectedListenerColor) { + onColorSelectedListener.onColorSelected(mCenterNewColor); + oldSelectedListenerColor = mCenterNewColor; + } + + break; + } + + return true; + } + + @Override + protected Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + Bundle state = new Bundle(); + state.putParcelable(STATE_PARENT, superState); + state.putFloat(STATE_ANGLE, mAngle); + state.putInt(STATE_OLD_COLOR, mCenterOldColor); + state.putBoolean(STATE_SHOW_OLD_COLOR, mShowCenterOldColor); + return state; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + Bundle savedState = (Bundle) state; + Parcelable superState = savedState.getParcelable(STATE_PARENT); + super.onRestoreInstanceState(superState); + + mAngle = savedState.getFloat(STATE_ANGLE); + setOldCenterColor(savedState.getInt(STATE_OLD_COLOR)); + mShowCenterOldColor = savedState.getBoolean(STATE_SHOW_OLD_COLOR); + + int currentColor = calculateColor(mAngle); + mPointerColor.setColor(currentColor); + setNewCenterColor(currentColor); + } + + private int ave(int s, int d, float p) { + return s + Math.round(p * (d - s)); + } + + private int calculateColor(float angle) { + float unit = (float) (angle / (2 * Math.PI)); + int[] colors = COLORS; + + if (unit < 0) { + unit += 1; + } + + if (unit <= 0) { + return colors[0]; + } + + if (unit >= 1) { + return colors[colors.length - 1]; + } + + float p = unit * (colors.length - 1); + int i = (int) p; + p -= i; + + int c0 = colors[i]; + int c1 = colors[i + 1]; + int a = ave(Color.alpha(c0), Color.alpha(c1), p); + int r = ave(Color.red(c0), Color.red(c1), p); + int g = ave(Color.green(c0), Color.green(c1), p); + int b = ave(Color.blue(c0), Color.blue(c1), p); + + return Color.argb(a, r, g, b); + } + + public int getColor() { + return mCenterNewColor; + } + + private float colorToAngle(int color) { + float[] colors = new float[3]; + Color.colorToHSV(color, colors); + return (float) Math.toRadians(-colors[0]); + } + + private float[] calculatePointerPosition(float angle) { + float x = (float) (mColorWheelRadius * Math.cos(angle)); + float y = (float) (mColorWheelRadius * Math.sin(angle)); + return new float[] { x, y }; + } + + public int getOldCenterColor() { + return mCenterOldColor; + } + + public boolean getShowOldCenterColor() { + return mShowCenterOldColor; + } + + public void setTouchAnywhereOnColorWheelEnabled(boolean TouchAnywhereOnColorWheelEnabled){ + mTouchAnywhereOnColorWheelEnabled = TouchAnywhereOnColorWheelEnabled; + } + + public boolean getTouchAnywhereOnColorWheel(){ + return mTouchAnywhereOnColorWheelEnabled; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/FragmentsPagerAdapter.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/FragmentsPagerAdapter.java new file mode 100644 index 000000000..163a53dc6 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/FragmentsPagerAdapter.java @@ -0,0 +1,48 @@ +package org.michaelbel.application.ui.view.widget; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.annotation.StringRes; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class FragmentsPagerAdapter extends FragmentPagerAdapter { + + private Context mContext; + private final List mFragments = new ArrayList<>(); + private final List mTitles = new ArrayList<>(); + + public FragmentsPagerAdapter(Context context, FragmentManager fragmentManager) { + super(fragmentManager); + mContext = context; + } + + public void addFragment(Fragment fragment, CharSequence title) { + mFragments.add(fragment); + mTitles.add(title); + } + + public void addFragment(Fragment fragment, @StringRes int stringId) { + addFragment(fragment, mContext.getText(stringId)); + } + + @Override + public Fragment getItem(int position) { + return mFragments.get(position); + } + + @Override + public int getCount() { + return mFragments.size(); + } + + @Nullable + @Override + public CharSequence getPageTitle(int position) { + return mTitles.get(position); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/GestureTextView.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/GestureTextView.java new file mode 100644 index 000000000..e12001026 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/GestureTextView.java @@ -0,0 +1,101 @@ +package org.michaelbel.application.ui.view.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.AppCompatTextView; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; + +import com.alexvasilkov.gestures.GestureController; +import com.alexvasilkov.gestures.State; +import com.alexvasilkov.gestures.views.interfaces.GestureView; + +@SuppressWarnings("all") +public class GestureTextView extends AppCompatTextView implements GestureView { + + private final GestureController controller; + + private float origSize; + private float size; + + public GestureTextView(Context context) { + this(context, null, 0); + } + + public GestureTextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public GestureTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + controller = new GestureController(this); + controller.getSettings().setOverzoomFactor(1f).setPanEnabled(false); + controller.getSettings().initFromAttributes(context, attrs); + controller.addOnStateChangeListener(new GestureController.OnStateChangeListener() { + @Override + public void onStateChanged(State state) { + applyState(state); + } + + @Override + public void onStateReset(State oldState, State newState) { + applyState(newState); + } + }); + + origSize = getTextSize(); + } + + /** + * {@inheritDoc} + */ + @Override + public GestureController getController() { + return controller; + } + + @SuppressLint("ClickableViewAccessibility") // performClick will be called by controller + @Override + public boolean onTouchEvent(@NonNull MotionEvent event) { + return controller.onTouch(this, event); + } + + @Override + public void setTextSize(float size) { + super.setTextSize(size); + origSize = getTextSize(); + applyState(controller.getState()); + } + + @Override + public void setTextSize(int unit, float size) { + super.setTextSize(unit, size); + origSize = getTextSize(); + applyState(controller.getState()); + } + + @Override + protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) { + super.onSizeChanged(width, height, oldWidth, oldHeight); + controller.getSettings().setViewport(width, height).setImage(width, height); + controller.updateState(); + } + + protected void applyState(State state) { + float size = origSize * state.getZoom(); + float maxSize = origSize * controller.getSettings().getMaxZoom(); + size = Math.max(origSize, Math.min(size, maxSize)); + + // Bigger text size steps for smoother scaling + size = Math.round(size); + + if (!State.equals(this.size, size)) { + this.size = size; + super.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); + } + } + +} diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/IndicatorView.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/IndicatorView.java new file mode 100644 index 000000000..24f5f72fb --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/IndicatorView.java @@ -0,0 +1,277 @@ +package org.michaelbel.application.ui.view.widget; + +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.content.Context; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.support.annotation.AnimatorRes; +import android.support.annotation.DrawableRes; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.animation.Interpolator; +import android.widget.LinearLayout; + +import org.michaelbel.application.R; + +import static android.support.v4.view.ViewPager.OnPageChangeListener; + +@SuppressWarnings("all") +public class IndicatorView extends LinearLayout { + + private final static int DEFAULT_INDICATOR_WIDTH = 5; + private ViewPager mViewpager; + private int mIndicatorMargin = -1; + private int mIndicatorWidth = -1; + private int mIndicatorHeight = -1; + private int mAnimatorResId = R.animator.scale_with_alpha; + private int mAnimatorReverseResId = 0; + private int mIndicatorBackgroundResId = R.drawable.white_radius; + private int mIndicatorUnselectedBackgroundResId = R.drawable.white_radius; + private Animator mAnimatorOut; + private Animator mAnimatorIn; + private Animator mImmediateAnimatorOut; + private Animator mImmediateAnimatorIn; + private int mLastPosition = -1; + + public IndicatorView(Context context) { + super(context); + initialize(context, null); + } + + public IndicatorView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context, attrs); + } + + public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initialize(context, attrs); + } + + private void initialize(Context context, AttributeSet attrs) { + handleTypedArray(context, attrs); + checkIndicatorConfig(context); + } + + private void handleTypedArray(Context context, AttributeSet attrs) { + if (attrs == null) { + return; + } + + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.IndicatorView); + mIndicatorWidth = typedArray.getDimensionPixelSize(R.styleable.IndicatorView_ci_width, -1); + mIndicatorHeight = typedArray.getDimensionPixelSize(R.styleable.IndicatorView_ci_height, -1); + mIndicatorMargin = typedArray.getDimensionPixelSize(R.styleable.IndicatorView_ci_margin, -1); + mAnimatorResId = typedArray.getResourceId(R.styleable.IndicatorView_ci_animator, R.animator.scale_with_alpha); + mAnimatorReverseResId = typedArray.getResourceId(R.styleable.IndicatorView_ci_animator_reverse, 0); + mIndicatorBackgroundResId = typedArray.getResourceId(R.styleable.IndicatorView_ci_drawable, R.drawable.white_radius); + mIndicatorUnselectedBackgroundResId = typedArray.getResourceId(R.styleable.IndicatorView_ci_drawable_unselected, mIndicatorBackgroundResId); + + int orientation = typedArray.getInt(R.styleable.IndicatorView_ci_orientation, -1); + setOrientation(orientation == VERTICAL ? VERTICAL : HORIZONTAL); + + int gravity = typedArray.getInt(R.styleable.IndicatorView_ci_gravity, -1); + setGravity(gravity >= 0 ? gravity : Gravity.CENTER); + + typedArray.recycle(); + } + + public void configureIndicator(int indicatorWidth, int indicatorHeight, int indicatorMargin) { + configureIndicator(indicatorWidth, indicatorHeight, indicatorMargin, + R.animator.scale_with_alpha, 0, R.drawable.white_radius, R.drawable.white_radius); + } + + public void configureIndicator(int indicatorWidth, int indicatorHeight, int indicatorMargin, + @AnimatorRes int animatorId, @AnimatorRes int animatorReverseId, + @DrawableRes int indicatorBackgroundId, + @DrawableRes int indicatorUnselectedBackgroundId) { + + mIndicatorWidth = indicatorWidth; + mIndicatorHeight = indicatorHeight; + mIndicatorMargin = indicatorMargin; + + mAnimatorResId = animatorId; + mAnimatorReverseResId = animatorReverseId; + mIndicatorBackgroundResId = indicatorBackgroundId; + mIndicatorUnselectedBackgroundResId = indicatorUnselectedBackgroundId; + + checkIndicatorConfig(getContext()); + } + + private void checkIndicatorConfig(Context context) { + mIndicatorWidth = (mIndicatorWidth < 0) ? dip2px(DEFAULT_INDICATOR_WIDTH) : mIndicatorWidth; + mIndicatorHeight = (mIndicatorHeight < 0) ? dip2px(DEFAULT_INDICATOR_WIDTH) : mIndicatorHeight; + mIndicatorMargin = (mIndicatorMargin < 0) ? dip2px(DEFAULT_INDICATOR_WIDTH) : mIndicatorMargin; + + mAnimatorResId = (mAnimatorResId == 0) ? R.animator.scale_with_alpha : mAnimatorResId; + + mAnimatorOut = createAnimatorOut(context); + mImmediateAnimatorOut = createAnimatorOut(context); + mImmediateAnimatorOut.setDuration(0); + + mAnimatorIn = createAnimatorIn(context); + mImmediateAnimatorIn = createAnimatorIn(context); + mImmediateAnimatorIn.setDuration(0); + + mIndicatorBackgroundResId = (mIndicatorBackgroundResId == 0) ? R.drawable.white_radius : mIndicatorBackgroundResId; + mIndicatorUnselectedBackgroundResId = (mIndicatorUnselectedBackgroundResId == 0) ? mIndicatorBackgroundResId : mIndicatorUnselectedBackgroundResId; + } + + private Animator createAnimatorOut(Context context) { + return AnimatorInflater.loadAnimator(context, mAnimatorResId); + } + + private Animator createAnimatorIn(Context context) { + Animator animatorIn; + + if (mAnimatorReverseResId == 0) { + animatorIn = AnimatorInflater.loadAnimator(context, mAnimatorResId); + animatorIn.setInterpolator(new ReverseInterpolator()); + } else { + animatorIn = AnimatorInflater.loadAnimator(context, mAnimatorReverseResId); + } + + return animatorIn; + } + + public void setViewPager(ViewPager viewPager) { + mViewpager = viewPager; + + if (mViewpager != null && mViewpager.getAdapter() != null) { + mLastPosition = -1; + createIndicators(); + mViewpager.removeOnPageChangeListener(mInternalPageChangeListener); + mViewpager.addOnPageChangeListener(mInternalPageChangeListener); + mInternalPageChangeListener.onPageSelected(mViewpager.getCurrentItem()); + } + } + + private final OnPageChangeListener mInternalPageChangeListener = new OnPageChangeListener() { + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} + + @Override + public void onPageSelected(int position) { + if (mViewpager.getAdapter() == null || mViewpager.getAdapter().getCount() <= 0) { + return; + } + + if (mAnimatorIn.isRunning()) { + mAnimatorIn.end(); + mAnimatorIn.cancel(); + } + + if (mAnimatorOut.isRunning()) { + mAnimatorOut.end(); + mAnimatorOut.cancel(); + } + + View currentIndicator; + if (mLastPosition >= 0 && (currentIndicator = getChildAt(mLastPosition)) != null) { + currentIndicator.setBackgroundResource(mIndicatorUnselectedBackgroundResId); + mAnimatorIn.setTarget(currentIndicator); + mAnimatorIn.start(); + } + + View selectedIndicator = getChildAt(position); + if (selectedIndicator != null) { + selectedIndicator.setBackgroundResource(mIndicatorBackgroundResId); + mAnimatorOut.setTarget(selectedIndicator); + mAnimatorOut.start(); + } + mLastPosition = position; + } + + @Override + public void onPageScrollStateChanged(int state) {} + }; + + public DataSetObserver getDataSetObserver() { + return mInternalDataSetObserver; + } + + private DataSetObserver mInternalDataSetObserver = new DataSetObserver() { + @Override + public void onChanged() { + super.onChanged(); + if (mViewpager == null) { + return; + } + + int newCount = mViewpager.getAdapter().getCount(); + int currentCount = getChildCount(); + + if (newCount == currentCount) { + return; + } else if (mLastPosition < newCount) { + mLastPosition = mViewpager.getCurrentItem(); + } else { + mLastPosition = -1; + } + + createIndicators(); + } + }; + + private void createIndicators() { + removeAllViews(); + int count = mViewpager.getAdapter().getCount(); + + if (count <= 0) { + return; + } + + int currentItem = mViewpager.getCurrentItem(); + int orientation = getOrientation(); + + for (int i = 0; i < count; i++) { + if (currentItem == i) { + addIndicator(orientation, mIndicatorBackgroundResId, mImmediateAnimatorOut); + } else { + addIndicator(orientation, mIndicatorUnselectedBackgroundResId, mImmediateAnimatorIn); + } + } + } + + private void addIndicator(int orientation, @DrawableRes int backgroundDrawableId, Animator animator) { + if (animator.isRunning()) { + animator.end(); + animator.cancel(); + } + + View Indicator = new View(getContext()); + Indicator.setBackgroundResource(backgroundDrawableId); + addView(Indicator, mIndicatorWidth, mIndicatorHeight); + LayoutParams lp = (LayoutParams) Indicator.getLayoutParams(); + + if (orientation == HORIZONTAL) { + lp.leftMargin = mIndicatorMargin; + lp.rightMargin = mIndicatorMargin; + } else { + lp.topMargin = mIndicatorMargin; + lp.bottomMargin = mIndicatorMargin; + } + + Indicator.setLayoutParams(lp); + + animator.setTarget(Indicator); + animator.start(); + } + + private class ReverseInterpolator implements Interpolator { + + @Override + public float getInterpolation(float value) { + return Math.abs(1.0f - value); + } + } + + public int dip2px(float dpValue) { + final float scale = getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/MaskImageView.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/MaskImageView.java new file mode 100644 index 000000000..b00a61bb8 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/MaskImageView.java @@ -0,0 +1,166 @@ +package org.michaelbel.application.ui.view.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.support.v4.view.ViewCompat; +import android.support.v7.widget.AppCompatImageView; + +import org.michaelbel.application.R; + +public class MaskImageView extends AppCompatImageView { + + private Paint mMaskedPaint; + private Rect mBounds; + private RectF mBoundsF; + private Drawable mMaskDrawable; + private Bitmap mCacheBitmap; + + private int mCachedWidth; + private int mCachedHeight; + private int mImageShape; + private boolean mCacheValid = false; + + public static final int CUSTOM = 0; + public static final int CIRCLE = 1; + public static final int ROUNDED = 2; + + public MaskImageView(Context context) { + super(context); + prepareDrawables(mImageShape); + setUpPaints(); + } + + private void prepareDrawables(int checkShape) { + if (checkShape == CIRCLE) { + mMaskDrawable = getResources().getDrawable(R.drawable.image_circle, null); + + if (mMaskDrawable != null) { + mMaskDrawable.setCallback(this); + } + } else if (checkShape == ROUNDED) { + mMaskDrawable = getResources().getDrawable(R.drawable.image_rect, null); + + if (mMaskDrawable != null) { + mMaskDrawable.setCallback(this); + } + } + } + + private void setUpPaints() { + Paint mBlackPaint = new Paint(); + mBlackPaint.setColor(0xFF000000); + mMaskedPaint = new Paint(); + mMaskedPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + mCacheBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + } + + @Override + protected boolean setFrame(int l, int t, int r, int b) { + final boolean changed = super.setFrame(l, t, r, b); + mBounds = new Rect(0, 0, r - l, b - t); + mBoundsF = new RectF(mBounds); + + if (mMaskDrawable != null) { + mMaskDrawable.setBounds(mBounds); + } + + if (changed) { + mCacheValid = false; + } + + return changed; + } + + @SuppressLint("DrawAllocation") + @Override + protected void onDraw(Canvas canvas) { + if (mBounds == null) { + return; + } + + int width = mBounds.width(); + int height = mBounds.height(); + + if (width == 0 || height == 0) { + return; + } + + if (!mCacheValid || width != mCachedWidth || height != mCachedHeight) { + if (width == mCachedWidth && height == mCachedHeight) { + mCacheBitmap.eraseColor(0); + } else { + mCacheBitmap.recycle(); + mCacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + mCachedWidth = width; + mCachedHeight = height; + } + + Canvas cacheCanvas = new Canvas(mCacheBitmap); + + if (mMaskDrawable != null) { + int sc = cacheCanvas.save(); + mMaskDrawable.draw(cacheCanvas); + cacheCanvas.saveLayer(mBoundsF, mMaskedPaint, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG); + super.onDraw(cacheCanvas); + cacheCanvas.restoreToCount(sc); + } else { + super.onDraw(cacheCanvas); + } + } + + canvas.drawBitmap(mCacheBitmap, mBounds.left, mBounds.top, null); + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + + if (mMaskDrawable != null && mMaskDrawable.isStateful()) { + mMaskDrawable.setState(getDrawableState()); + } + + if (isDuplicateParentStateEnabled()) { + ViewCompat.postInvalidateOnAnimation(this); + } + } + + @Override + public void invalidateDrawable(Drawable who) { + if (who == mMaskDrawable) { + invalidate(); + } else { + super.invalidateDrawable(who); + } + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return who == mMaskDrawable || super.verifyDrawable(who); + } + + public void setShapeDrawable(Drawable drawable) { + this.mMaskDrawable = drawable; + + if (mMaskDrawable != null) { + mMaskDrawable.setCallback(this); + } + + setUpPaints(); + } + + public void setShapeDrawable(int drawable) { + if (drawable != CUSTOM) { + mImageShape = drawable; + prepareDrawables(mImageShape); + setUpPaints(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/PaddingItemDecoration.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/PaddingItemDecoration.java new file mode 100644 index 000000000..0e1be905c --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/PaddingItemDecoration.java @@ -0,0 +1,28 @@ +package org.michaelbel.application.ui.view.widget; + +import android.graphics.Rect; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +public class PaddingItemDecoration extends RecyclerView.ItemDecoration { + + private int itemOffset; + + public PaddingItemDecoration() { + } + + public PaddingItemDecoration(int itemOffset) { + this.itemOffset = itemOffset; + } + + public PaddingItemDecoration setOffset(int itemOffset) { + this.itemOffset = itemOffset; + return this; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + outRect.set(itemOffset, itemOffset, itemOffset, itemOffset); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/RecyclerListView.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/RecyclerListView.java new file mode 100644 index 000000000..d50cdee3e --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/RecyclerListView.java @@ -0,0 +1,412 @@ +package org.michaelbel.application.ui.view.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; + + +import org.michaelbel.application.util.AppUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +@SuppressWarnings("all") +public class RecyclerListView extends RecyclerView { + + private static final String TAG = RecyclerListView.class.getSimpleName(); + + private RecyclerListView.OnItemClickListener onItemClickListener; + private RecyclerListView.OnItemLongClickListener onItemLongClickListener; + private RecyclerView.OnScrollListener onScrollListener; + private RecyclerListView.OnInterceptTouchListener onInterceptTouchListener; + + private View emptyView; + private Runnable selectChildRunnable; + + private GestureDetector mGestureDetector; + private View currentChildView; + private int currentChildPosition; + private boolean interceptedByChild; + private boolean wasPressed; + private boolean disallowInterceptTouchEvents; + private boolean instantClick; + private Runnable clickRunnable; + + private static int[] attributes; + private static boolean gotAttributes; + + public RecyclerListView(Context context) { + this(context, null); + } + + public RecyclerListView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public RecyclerListView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initialize(context, attrs, defStyle); + } + + private void initialize(Context context, AttributeSet attrs, int defStyle) { + try { + if (!gotAttributes) { + attributes = getResourceDeclareStyleableIntArray("com.android.internal", "View"); + gotAttributes = true; + } + + TypedArray a = context.getTheme().obtainStyledAttributes(attributes); + Method initializeScrollbars = android.view.View.class.getDeclaredMethod("initializeScrollbars", TypedArray.class); + initializeScrollbars.invoke(this, a); + a.recycle(); + } catch (Throwable e) { + //FirebaseCrash.report(e); + } + + super.addOnScrollListener(new OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + if (newState != SCROLL_STATE_IDLE && currentChildView != null) { + if (selectChildRunnable != null) { + AppUtils.cancelRunOnUIThread(selectChildRunnable); + selectChildRunnable = null; + } + + MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); + try { + mGestureDetector.onTouchEvent(event); + } catch (Exception e) { + //FirebaseCrash.report(e); + } + + currentChildView.onTouchEvent(event); + event.recycle(); + currentChildView.setPressed(false); + currentChildView = null; + interceptedByChild = false; + } + if (onScrollListener != null) { + onScrollListener.onScrollStateChanged(recyclerView, newState); + } + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + if (onScrollListener != null) { + onScrollListener.onScrolled(recyclerView, dx, dy); + } + } + }); + addOnItemTouchListener(new RecyclerListView.RecyclerListViewItemClickListener(context)); + } + + public interface OnItemClickListener { + void onItemClick(View view, int position); + } + + public interface OnItemLongClickListener { + boolean onItemClick(View view, int position); + } + + public interface OnInterceptTouchListener { + boolean onInterceptTouchEvent(MotionEvent event); + } + + private class RecyclerListViewItemClickListener implements RecyclerView.OnItemTouchListener { + + public RecyclerListViewItemClickListener(Context context) { + mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (currentChildView != null && onItemClickListener != null) { + currentChildView.setPressed(true); + final View view = currentChildView; + + if (instantClick) { + view.playSoundEffect(SoundEffectConstants.CLICK); + onItemClickListener.onItemClick(view, currentChildPosition); + } + + AppUtils.runOnUIThread(clickRunnable = new Runnable() { + @Override + public void run() { + if (this == clickRunnable) { + clickRunnable = null; + } + + if (view != null) { + view.setPressed(false); + if (!instantClick) { + view.playSoundEffect(SoundEffectConstants.CLICK); + if (onItemClickListener != null) { + onItemClickListener.onItemClick(view, currentChildPosition); + } + } + } + } + }, ViewConfiguration.getPressedStateDuration()); + + if (selectChildRunnable != null) { + AppUtils.cancelRunOnUIThread(selectChildRunnable); + selectChildRunnable = null; + currentChildView = null; + interceptedByChild = false; + } + } + + return true; + } + + @Override + public void onLongPress(MotionEvent event) { + if (currentChildView != null) { + if (onItemLongClickListener != null) { + if (onItemLongClickListener.onItemClick(currentChildView, currentChildPosition)) { + currentChildView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + } + } + } + } + }); + } + + @Override + public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent event) { + int action = event.getActionMasked(); + boolean isScrollIdle = RecyclerListView.this.getScrollState() == RecyclerListView.SCROLL_STATE_IDLE; + + if ((action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) && currentChildView == null && isScrollIdle) { + currentChildView = view.findChildViewUnder(event.getX(), event.getY()); + if (currentChildView instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) currentChildView; + float x = event.getX() - currentChildView.getLeft(); + float y = event.getY() - currentChildView.getTop(); + final int count = viewGroup.getChildCount(); + for (int i = count - 1; i >= 0; i--) { + final View child = viewGroup.getChildAt(i); + if (x >= child.getLeft() && x <= child.getRight() && y >= child.getTop() && y <= child.getBottom()) { + if (child.isClickable()) { + currentChildView = null; + break; + } + } + } + } + currentChildPosition = -1; + if (currentChildView != null) { + currentChildPosition = view.getChildPosition(currentChildView); + MotionEvent childEvent = MotionEvent.obtain(0, 0, event.getActionMasked(), event.getX() - currentChildView.getLeft(), event.getY() - currentChildView.getTop(), 0); + if (currentChildView.onTouchEvent(childEvent)) { + interceptedByChild = true; + } + childEvent.recycle(); + } + } + + if (currentChildView != null && !interceptedByChild) { + try { + if (event != null) { + mGestureDetector.onTouchEvent(event); + } + } catch (Exception e) { + //FirebaseCrash.report(e); + } + } + + if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) { + if (!interceptedByChild && currentChildView != null) { + selectChildRunnable = () -> { + if (selectChildRunnable != null && currentChildView != null) { + currentChildView.setPressed(true); + selectChildRunnable = null; + } + }; + + AppUtils.runOnUIThread(selectChildRunnable, ViewConfiguration.getTapTimeout()); + } + } else if (currentChildView != null && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_CANCEL || !isScrollIdle)) { + if (selectChildRunnable != null) { + AppUtils.cancelRunOnUIThread(selectChildRunnable); + selectChildRunnable = null; + } + + currentChildView.setPressed(false); + currentChildView = null; + interceptedByChild = false; + } + + return false; + } + + @Override + public void onTouchEvent(RecyclerView view, MotionEvent event) {} + + @Override + public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { + cancelClickRunnables(true); + } + } + + public void cancelClickRunnables(boolean uncheck) { + if (selectChildRunnable != null) { + AppUtils.cancelRunOnUIThread(selectChildRunnable); + selectChildRunnable = null; + } + + if (currentChildView != null) { + if (uncheck) { + currentChildView.setPressed(false); + } + + currentChildView = null; + } + + if (clickRunnable != null) { + AppUtils.cancelRunOnUIThread(clickRunnable); + clickRunnable = null; + } + + interceptedByChild = false; + } + + private AdapterDataObserver observer = new AdapterDataObserver() { + @Override + public void onChanged() { + checkIfEmpty(); + } + + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + checkIfEmpty(); + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + checkIfEmpty(); + } + }; + + public int[] getResourceDeclareStyleableIntArray(String packageName, String name) { + try { + Field f = Class.forName(packageName + ".R$styleable").getField(name); + if (f != null) { + return (int[]) f.get(null); + } + } catch (Throwable e) { + //FirebaseCrash.report(e); + } + + return null; + } + + @Override + public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { + if (attributes != null) { + super.setVerticalScrollBarEnabled(verticalScrollBarEnabled); + } + } + + public void setOnItemClickListener(RecyclerListView.OnItemClickListener listener) { + onItemClickListener = listener; + } + + public void setOnItemLongClickListener(RecyclerListView.OnItemLongClickListener listener) { + onItemLongClickListener = listener; + } + + public void setEmptyView(@NonNull View view) { + if (emptyView == view) { + return; + } + + emptyView = view; + checkIfEmpty(); + } + + public View getEmptyView() { + return emptyView; + } + + public void invalidateViews() { + int count = getChildCount(); + for (int a = 0; a < count; a++) { + getChildAt(a).invalidate(); + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + if (disallowInterceptTouchEvents) { + requestDisallowInterceptTouchEvent(true); + } + + return onInterceptTouchListener != null && onInterceptTouchListener.onInterceptTouchEvent(e) || super.onInterceptTouchEvent(e); + } + + private void checkIfEmpty() { + if (emptyView == null || getAdapter() == null) { + return; + } + + boolean emptyViewVisible = getAdapter().getItemCount() == 0; + emptyView.setVisibility(emptyViewVisible ? VISIBLE : GONE); + setVisibility(emptyViewVisible ? INVISIBLE : VISIBLE); + } + + @Override + public void addOnScrollListener(OnScrollListener listener) { + onScrollListener = listener; + } + + public void setOnInterceptTouchListener(RecyclerListView.OnInterceptTouchListener listener) { + onInterceptTouchListener = listener; + } + + public void setInstantClick(boolean value) { + instantClick = value; + } + + public void setDisallowInterceptTouchEvents(boolean value) { + disallowInterceptTouchEvents = value; + } + + @Override + public void setAdapter(Adapter adapter) { + final Adapter oldAdapter = getAdapter(); + + if (oldAdapter != null) { + oldAdapter.unregisterAdapterDataObserver(observer); + } + + super.setAdapter(adapter); + + if (adapter != null) { + adapter.registerAdapterDataObserver(observer); + } + + checkIfEmpty(); + } + + @Override + public void stopScroll() { + try { + super.stopScroll(); + } catch (NullPointerException e) { + //FirebaseCrash.report(e); + } + } + + @Override + public boolean hasOverlappingRendering() { + return false; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/SectionListView.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/SectionListView.java new file mode 100644 index 000000000..15bb35999 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/SectionListView.java @@ -0,0 +1,455 @@ +package org.michaelbel.application.ui.view.widget; + +import android.content.Context; +import android.database.DataSetObserver; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PointF; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.GradientDrawable.Orientation; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.widget.AbsListView; +import android.widget.HeaderViewListAdapter; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.SectionIndexer; + +@SuppressWarnings("all") +public class SectionListView extends ListView { + + public interface PinnedSectionListAdapter extends ListAdapter { + boolean isItemViewTypePinned(int viewType); + } + + public static class PinnedSection { + public View view; + public int position; + public long id; + } + + private final Rect mTouchRect = new Rect(); + private final PointF mTouchPoint = new PointF(); + private int mTouchSlop; + private View mTouchTarget; + private MotionEvent mDownEvent; + + private GradientDrawable mShadowDrawable; + private int mSectionsDistanceY; + private int mShadowHeight; + + private OnScrollListener mDelegateOnScrollListener; + private PinnedSection mRecycleSection; + private PinnedSection mPinnedSection; + private int mTranslateY; + + private final OnScrollListener mOnScrollListener = new OnScrollListener() { + + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + if (mDelegateOnScrollListener != null) { + mDelegateOnScrollListener.onScrollStateChanged(view, scrollState); + } + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + if (mDelegateOnScrollListener != null) { + mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); + } + + ListAdapter adapter = getAdapter(); + if (adapter == null || visibleItemCount == 0) { + return; + } + + boolean isFirstVisibleItemSection = isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem)); + if (isFirstVisibleItemSection) { + View sectionView = getChildAt(0); + if (sectionView.getTop() == getPaddingTop()) { + destroyPinnedShadow(); + } else { + ensureShadowForPosition(firstVisibleItem, firstVisibleItem, visibleItemCount); + } + } else { + int sectionPosition = findCurrentSectionPosition(firstVisibleItem); + if (sectionPosition > -1) { + ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount); + } else { + destroyPinnedShadow(); + } + } + } + }; + + private final DataSetObserver mDataSetObserver = new DataSetObserver() { + + @Override + public void onChanged() { + recreatePinnedShadow(); + } + + @Override + public void onInvalidated() { + recreatePinnedShadow(); + } + }; + + public SectionListView(Context context) { + super(context); + initialize(context); + } + + public SectionListView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context); + } + + public SectionListView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initialize(context); + } + + private void initialize(Context context) { + setOnScrollListener(mOnScrollListener); + mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + initShadow(true); + setShadowVisible(false); + } + + public void setShadowVisible(boolean visible) { + initShadow(visible); + if (mPinnedSection != null) { + View v = mPinnedSection.view; + invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight); + } + } + + public void initShadow(boolean visible) { + if (visible) { + if (mShadowDrawable == null) { + mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, + new int[] { Color.parseColor("#ffa0a0a0"), Color.parseColor("#50a0a0a0"), Color.parseColor("#00a0a0a0")}); + mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density); + } + } else { + if (mShadowDrawable != null) { + mShadowDrawable = null; + mShadowHeight = 0; + } + } + } + + private void createPinnedShadow(int position) { + PinnedSection pinnedShadow = mRecycleSection; + mRecycleSection = null; + + if (pinnedShadow == null) { + pinnedShadow = new PinnedSection(); + } + + View pinnedView = getAdapter().getView(position, pinnedShadow.view, SectionListView.this); + + ViewGroup.LayoutParams layoutParams = pinnedView.getLayoutParams(); + if (layoutParams == null) { + layoutParams = generateDefaultLayoutParams(); + pinnedView.setLayoutParams(layoutParams); + } + + int heightMode = MeasureSpec.getMode(layoutParams.height); + int heightSize = MeasureSpec.getSize(layoutParams.height); + + if (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY; + + int maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom(); + if (heightSize > maxHeight) heightSize = maxHeight; + + int ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY); + int hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode); + pinnedView.measure(ws, hs); + pinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight()); + mTranslateY = 0; + + pinnedShadow.view = pinnedView; + pinnedShadow.position = position; + pinnedShadow.id = getAdapter().getItemId(position); + + mPinnedSection = pinnedShadow; + } + + private void destroyPinnedShadow() { + if (mPinnedSection != null) { + mRecycleSection = mPinnedSection; + mPinnedSection = null; + } + } + + private void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) { + if (visibleItemCount < 2) { + destroyPinnedShadow(); + return; + } + + if (mPinnedSection != null && mPinnedSection.position != sectionPosition) { + destroyPinnedShadow(); + } + + if (mPinnedSection == null) { + createPinnedShadow(sectionPosition); + } + + int nextPosition = sectionPosition + 1; + if (nextPosition < getCount()) { + int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition, visibleItemCount - (nextPosition - firstVisibleItem)); + if (nextSectionPosition > -1) { + View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem); + int bottom = mPinnedSection.view.getBottom() + getPaddingTop(); + mSectionsDistanceY = nextSectionView.getTop() - bottom; + if (mSectionsDistanceY < 0) { + mTranslateY = mSectionsDistanceY; + } else { + mTranslateY = 0; + } + } else { + mTranslateY = 0; + mSectionsDistanceY = Integer.MAX_VALUE; + } + } + + } + + private int findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) { + ListAdapter adapter = getAdapter(); + + int adapterDataCount = adapter.getCount(); + if (getLastVisiblePosition() >= adapterDataCount) { + return -1; + } + + if (firstVisibleItem+visibleItemCount >= adapterDataCount){ + visibleItemCount = adapterDataCount-firstVisibleItem; + } + + for (int childIndex = 0; childIndex < visibleItemCount; childIndex++) { + int position = firstVisibleItem + childIndex; + int viewType = adapter.getItemViewType(position); + if (isItemViewTypePinned(adapter, viewType)) { + return position; + } + } + + return -1; + } + + private int findCurrentSectionPosition(int fromPosition) { + ListAdapter adapter = getAdapter(); + + if (fromPosition >= adapter.getCount()) { + return -1; + } + + if (adapter instanceof SectionIndexer) { + SectionIndexer indexer = (SectionIndexer) adapter; + int sectionPosition = indexer.getSectionForPosition(fromPosition); + int itemPosition = indexer.getPositionForSection(sectionPosition); + int typeView = adapter.getItemViewType(itemPosition); + if (isItemViewTypePinned(adapter, typeView)) { + return itemPosition; + } + } + + for (int position=fromPosition; position>=0; position--) { + int viewType = adapter.getItemViewType(position); + if (isItemViewTypePinned(adapter, viewType)) { + return position; + } + } + + return -1; + } + + private void recreatePinnedShadow() { + destroyPinnedShadow(); + ListAdapter adapter = getAdapter(); + + if (adapter != null && adapter.getCount() > 0) { + int firstVisiblePosition = getFirstVisiblePosition(); + int sectionPosition = findCurrentSectionPosition(firstVisiblePosition); + if (sectionPosition == -1) { + return; + } + + ensureShadowForPosition(sectionPosition, firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition); + } + } + + @Override + public void setOnScrollListener(OnScrollListener listener) { + if (listener == mOnScrollListener) { + super.setOnScrollListener(listener); + } else { + mDelegateOnScrollListener = listener; + } + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + super.onRestoreInstanceState(state); + post(this :: recreatePinnedShadow); + } + + @Override + public void setAdapter(ListAdapter adapter) { + if (adapter != null) { + if (!(adapter instanceof PinnedSectionListAdapter)) + throw new IllegalArgumentException("Does your adapter implement PinnedSectionListAdapter?"); + if (adapter.getViewTypeCount() < 2) + throw new IllegalArgumentException("Does your adapter handle at least two types" + + " of views in getViewTypeCount() method: items and sections?"); + } + + ListAdapter oldAdapter = getAdapter(); + if (oldAdapter != null) { + oldAdapter.unregisterDataSetObserver(mDataSetObserver); + } + if (adapter != null) { + adapter.registerDataSetObserver(mDataSetObserver); + } + if (oldAdapter != adapter) { + destroyPinnedShadow(); + } + + super.setAdapter(adapter); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + if (mPinnedSection != null) { + int parentWidth = r - l - getPaddingLeft() - getPaddingRight(); + int shadowWidth = mPinnedSection.view.getWidth(); + + if (parentWidth != shadowWidth) { + recreatePinnedShadow(); + } + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (mPinnedSection != null) { + int pLeft = getListPaddingLeft(); + int pTop = getListPaddingTop(); + View view = mPinnedSection.view; + canvas.save(); + int clipHeight = view.getHeight() + (mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY)); + canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight); + canvas.translate(pLeft, pTop + mTranslateY); + drawChild(canvas, mPinnedSection.view, getDrawingTime()); + + if (mShadowDrawable != null && mSectionsDistanceY > 0) { + mShadowDrawable.setBounds(mPinnedSection.view.getLeft(), + mPinnedSection.view.getBottom(), + mPinnedSection.view.getRight(), + mPinnedSection.view.getBottom() + mShadowHeight); + mShadowDrawable.draw(canvas); + } + + canvas.restore(); + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + final float x = ev.getX(); + final float y = ev.getY(); + final int action = ev.getAction(); + + if (action == MotionEvent.ACTION_DOWN + && mTouchTarget == null + && mPinnedSection != null + && isPinnedViewTouched(mPinnedSection.view, x, y)) { + + mTouchTarget = mPinnedSection.view; + mTouchPoint.x = x; + mTouchPoint.y = y; + mDownEvent = MotionEvent.obtain(ev); + } + + if (mTouchTarget != null) { + if (isPinnedViewTouched(mTouchTarget, x, y)) { + mTouchTarget.dispatchTouchEvent(ev); + } + + if (action == MotionEvent.ACTION_UP) { + super.dispatchTouchEvent(ev); + performPinnedItemClick(); + clearTouchTarget(); + } else if (action == MotionEvent.ACTION_CANCEL) { + clearTouchTarget(); + } else if (action == MotionEvent.ACTION_MOVE) { + if (Math.abs(y - mTouchPoint.y) > mTouchSlop) { + MotionEvent event = MotionEvent.obtain(ev); + event.setAction(MotionEvent.ACTION_CANCEL); + mTouchTarget.dispatchTouchEvent(event); + event.recycle(); + super.dispatchTouchEvent(mDownEvent); + super.dispatchTouchEvent(ev); + clearTouchTarget(); + } + } + return true; + } + return super.dispatchTouchEvent(ev); + } + + private boolean isPinnedViewTouched(View view, float x, float y) { + view.getHitRect(mTouchRect); + mTouchRect.top += mTranslateY; + mTouchRect.bottom += mTranslateY + getPaddingTop(); + mTouchRect.left += getPaddingLeft(); + mTouchRect.right -= getPaddingRight(); + return mTouchRect.contains((int)x, (int)y); + } + + private void clearTouchTarget() { + mTouchTarget = null; + if (mDownEvent != null) { + mDownEvent.recycle(); + mDownEvent = null; + } + } + + private boolean performPinnedItemClick() { + if (mPinnedSection == null) { + return false; + } + + OnItemClickListener listener = getOnItemClickListener(); + if (listener != null && getAdapter().isEnabled(mPinnedSection.position)) { + View view = mPinnedSection.view; + playSoundEffect(SoundEffectConstants.CLICK); + if (view != null) { + view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); + } + listener.onItemClick(this, view, mPinnedSection.position, mPinnedSection.id); + return true; + } + return false; + } + + public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) { + if (adapter instanceof HeaderViewListAdapter) { + adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter(); + } + return ((PinnedSectionListAdapter) adapter).isItemViewTypePinned(viewType); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/SnackbarBehavior.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/SnackbarBehavior.java new file mode 100644 index 000000000..b5905227b --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/SnackbarBehavior.java @@ -0,0 +1,15 @@ +package org.michaelbel.application.ui.view.widget; + +import android.support.annotation.NonNull; +import android.support.design.widget.Snackbar; +import android.support.design.widget.SwipeDismissBehavior; +import android.view.View; + +@SuppressWarnings("all") +public class SnackbarBehavior extends SwipeDismissBehavior { + + @Override + public boolean canSwipeDismissView(@NonNull View view) { + return false; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/ui/view/widget/ViewPagerAdapter.java b/app/src/main/java/org/michaelbel/application/ui/view/widget/ViewPagerAdapter.java new file mode 100644 index 000000000..3ac6c925b --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/ui/view/widget/ViewPagerAdapter.java @@ -0,0 +1,60 @@ +package org.michaelbel.application.ui.view.widget; + +import android.content.Context; +import android.support.annotation.StringRes; +import android.support.v4.view.PagerAdapter; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import java.util.ArrayList; +import java.util.List; + +public class ViewPagerAdapter extends PagerAdapter { + + private Context context; + private List layouts = new ArrayList<>(); + private List titles = new ArrayList<>(); + + public ViewPagerAdapter(Context context) { + this.context = context; + } + + public void addLayout(View view, CharSequence title) { + layouts.add(view); + titles.add(title); + } + + public void addLayout(View view, @StringRes int stringId) { + addLayout(view, context.getText(stringId)); + } + + @Override + public CharSequence getPageTitle(int position) { + return titles.get(position); + } + + @Override + public int getCount() { + return layouts.size(); + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + FrameLayout layout = new FrameLayout(context); + layout.addView(layouts.get(position)); + + container.addView(layout); + return layout; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((FrameLayout) object); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/util/AppUtils.java b/app/src/main/java/org/michaelbel/application/util/AppUtils.java new file mode 100644 index 000000000..7932117cb --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/util/AppUtils.java @@ -0,0 +1,100 @@ +package org.michaelbel.application.util; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.graphics.Point; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; + +import org.michaelbel.application.moviemade.AppLoader; + +import java.io.InputStream; +import java.util.Properties; + +public class AppUtils { + + public static String getProperty(String key) { + try { + Properties properties = new Properties(); + AssetManager assetManager = AppLoader.AppContext.getAssets(); + InputStream inputStream = assetManager.open("config.properties"); + properties.load(inputStream); + return properties.getProperty(key); + } catch (Exception e) { + //FirebaseCrash.logcat(Log.ERROR, "e_message", "Error retrieving file asset"); + //FirebaseCrash.report(e); + } + + return null; + } + + public static int getColumns() { + SharedPreferences prefs = AppLoader.AppContext.getSharedPreferences("main_config", Context.MODE_PRIVATE); + int type = prefs.getInt("view_type", 0); + + if (type == 0) { + return ScreenUtils.isTablet() ? ScreenUtils.isPortrait() ? 6 : 8 : ScreenUtils.isPortrait() ? 3 : 5; + } else if (type == 1) { + return ScreenUtils.isTablet() ? ScreenUtils.isPortrait() ? 2 : 4 : ScreenUtils.isPortrait() ? 1 : 2; + } else { + return ScreenUtils.isTablet() ? ScreenUtils.isPortrait() ? 2 : 4 : ScreenUtils.isPortrait() ? 1 : 2; + } + } + + public static int getColumnsForVideos() { + return ScreenUtils.isTablet() ? ScreenUtils.isPortrait() ? 2 : 4 : ScreenUtils.isPortrait() ? 1 : 2; + } + + public static int getColumnsForImages() { + return ScreenUtils.isPortrait() ? 3 : 6; + } + + private static Point displaySize = new Point(); + private static boolean usingHardwareInput; + private static DisplayMetrics displayMetrics = new DisplayMetrics(); + + public static float getPixelsInCM(float cm, boolean isX) { + return (cm / 2.54f) * (isX ? displayMetrics.xdpi : displayMetrics.ydpi); + } + + public static void runOnUIThread(Runnable runnable) { + runOnUIThread(runnable, 0); + } + + public static void runOnUIThread(Runnable runnable, long delay) { + if (delay == 0) { + AppLoader.AppHandler.post(runnable); + } else { + AppLoader.AppHandler.postDelayed(runnable, delay); + } + } + + public static void cancelRunOnUIThread(Runnable runnable) { + AppLoader.AppHandler.removeCallbacks(runnable); + } + + static { + checkDisplaySize(); + } + + private static void checkDisplaySize() { + try { + Configuration configuration = AppLoader.AppContext.getResources().getConfiguration(); + usingHardwareInput = configuration.keyboard != Configuration.KEYBOARD_NOKEYS && configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; + WindowManager manager = (WindowManager) AppLoader.AppContext.getSystemService(Context.WINDOW_SERVICE); + if (manager != null) { + Display display = manager.getDefaultDisplay(); + if (display != null) { + display.getMetrics(displayMetrics); + display.getSize(displaySize); + } + } + } catch (Exception e) { + //FirebaseCrash.logcat(Log.ERROR, "e_message", "Error check display size"); + //FirebaseCrash.report(e); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/util/DateUtils.java b/app/src/main/java/org/michaelbel/application/util/DateUtils.java new file mode 100644 index 000000000..5e4535c5a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/util/DateUtils.java @@ -0,0 +1,49 @@ +package org.michaelbel.application.util; + +import android.support.annotation.NonNull; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +@SuppressWarnings("all") +public class DateUtils { + + private static final String DEFAULT_DATE_FORMAT = "MMMM yyyy"; + + public static String getYesterdayDate() { + return getYesterdayDate(DEFAULT_DATE_FORMAT); + } + + public static String getYesterdayDate(@NonNull String format) { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DATE, -1); + return formatDate(format, calendar.getTime()); + } + + public static String getTodayDate() { + return getTodayDate(DEFAULT_DATE_FORMAT); + } + + public static String getTodayDate(@NonNull String format) { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DATE, 0); + return formatDate(format, calendar.getTime()); + } + + public static String getTomorrowDate() { + return getTomorrowDate(DEFAULT_DATE_FORMAT); + } + + public static String getTomorrowDate(@NonNull String format) { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DATE, 1); + return formatDate(format, calendar.getTime()); + } + + private static String formatDate(String format, Date date) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.US); + return simpleDateFormat.format(date != null ? date : new Date()); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/util/DeviceUtils.java b/app/src/main/java/org/michaelbel/application/util/DeviceUtils.java new file mode 100644 index 000000000..ee71513b4 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/util/DeviceUtils.java @@ -0,0 +1,74 @@ +package org.michaelbel.application.util; + +import android.Manifest; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.BatteryManager; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.RequiresPermission; + +import org.michaelbel.application.moviemade.AppLoader; + +@SuppressWarnings("all") +public class DeviceUtils { + + @RequiresPermission(Manifest.permission.ACCESS_WIFI_STATE) + public static String getMacAddress(@NonNull Context context) { + String macAddress = null; + + try { + WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + macAddress = wifiInfo.getMacAddress(); + } catch (Exception e) { + //FirebaseCrash.logcat(Log.ERROR, "e_message", "Get macaddress error"); + //FirebaseCrash.report(e); + } + + return macAddress; + } + + public static String getModel() { + String model = Build.MODEL; + if (model != null) { + model = model.trim().replaceAll("\\s*", ""); + } else { + model = ""; + } + return model; + } + + public static String getBatteryLevel(@NonNull Context context) { + Intent intent; + int level = 0; + int scale = 0; + int percent; + + intent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + if (intent != null) { + level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); + scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100); + } + + percent = (level * 100) / scale; + return String.valueOf(percent) + "%"; + } + + public static void addToClipboard(CharSequence text) { + try { + ClipboardManager clipboardManager = (ClipboardManager) + AppLoader.AppContext.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = ClipData.newPlainText("label", text); + clipboardManager.setPrimaryClip(clipData); + } catch (Exception e) { + //FirebaseCrash.logcat(Log.ERROR, "e_message", "Add to clipboard error"); + //FirebaseCrash.report(e); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/util/FileUtils.java b/app/src/main/java/org/michaelbel/application/util/FileUtils.java new file mode 100644 index 000000000..29b565138 --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/util/FileUtils.java @@ -0,0 +1,55 @@ +package org.michaelbel.application.util; + +import android.support.annotation.NonNull; + +import org.michaelbel.application.moviemade.AppLoader; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; + +@SuppressWarnings("all") +public class FileUtils { + + public static File getFileByPath(@NonNull String path) { + return new File(path); + } + + public static boolean makeDirectory(@NonNull String path) { + File directory = new File(path); + return !directory.exists() && directory.mkdirs(); + } + + public static void copyFile(File source, File destination) throws IOException { + FileInputStream fromFile = new FileInputStream(source); + FileOutputStream toFile = new FileOutputStream(destination); + FileChannel fromChannel = null; + FileChannel toChannel = null; + try { + fromChannel = fromFile.getChannel(); + toChannel = toFile.getChannel(); + fromChannel.transferTo(0, fromChannel.size(), toChannel); + } finally { + try { + if (fromChannel != null) { + fromChannel.close(); + } + } finally { + if (toChannel != null) { + toChannel.close(); + } + } + } + } + + private static boolean createCacheDirectory(@NonNull String directoryName) { + File directory = new File(AppLoader.AppContext.getCacheDir(), directoryName); + if (!directory.exists()) { + return directory.mkdir(); + } + + return directory.exists(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/util/KeyboardUtils.java b/app/src/main/java/org/michaelbel/application/util/KeyboardUtils.java new file mode 100644 index 000000000..b530bba2a --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/util/KeyboardUtils.java @@ -0,0 +1,47 @@ +package org.michaelbel.application.util; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +@SuppressWarnings("all") +public class KeyboardUtils { + + private static final String TAG = KeyboardUtils.class.getSimpleName(); + + public static void showKeyboard(@NonNull View view) { + try { + InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); + } catch (Exception e) { + //FirebaseCrash.logcat(Log.ERROR, "e_message", "Show keyboard error"); + //FirebaseCrash.report(e); + } + } + + public static boolean isKeyboardShowed(@NonNull View view) { + try { + InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + return inputManager.isActive(view); + } catch (Exception e) { + //FirebaseCrash.logcat(Log.ERROR, "e_message", "Is keyboard showed keyboard"); + //FirebaseCrash.report(e); + } + + return false; + } + + public static void hideKeyboard(@NonNull View view) { + try { + InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (!imm.isActive()) { + return; + } + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } catch (Exception e) { + //FirebaseCrash.logcat(Log.ERROR, "e_message", "Hide keyboard error"); + //FirebaseCrash.report(e); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/util/NetworkUtils.java b/app/src/main/java/org/michaelbel/application/util/NetworkUtils.java new file mode 100644 index 000000000..e57b024eb --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/util/NetworkUtils.java @@ -0,0 +1,34 @@ +package org.michaelbel.application.util; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +import org.michaelbel.application.moviemade.AppLoader; + +@SuppressWarnings("all") +public class NetworkUtils { + + public static final int TYPE_WIFI = 1; + public static final int TYPE_MOBILE = 2; + public static final int TYPE_VPN = 3; + public static final int TYPE_NOT_CONNECTED = 0; + + public static int getNetworkStatus() { + ConnectivityManager connectivityManager = (ConnectivityManager) + AppLoader.AppContext.getSystemService(Context.CONNECTIVITY_SERVICE); + + NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); + if (networkInfo != null) { + if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { + return TYPE_WIFI; + } else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { + return TYPE_MOBILE; + } else if (networkInfo.getType() == ConnectivityManager.TYPE_VPN) { + return TYPE_VPN; + } + } + + return TYPE_NOT_CONNECTED; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/util/ScreenUtils.java b/app/src/main/java/org/michaelbel/application/util/ScreenUtils.java new file mode 100644 index 000000000..9ff2e6eda --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/util/ScreenUtils.java @@ -0,0 +1,77 @@ +package org.michaelbel.application.util; + +import android.annotation.TargetApi; +import android.app.KeyguardManager; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Build; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.WindowManager; + +import org.michaelbel.application.moviemade.AppLoader; +import org.michaelbel.application.R; + +@SuppressWarnings("all") +public class ScreenUtils { + + public static int dp(float value) { + return (int) Math.ceil(AppLoader.AppContext.getResources().getDisplayMetrics().density * value); + } + + public static boolean isTablet() { + return AppLoader.AppContext.getResources().getBoolean(R.bool.Tablet); + } + + public static int getScreenWidth() { + WindowManager windowManager = (WindowManager) AppLoader.AppContext.getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return displayMetrics.widthPixels; + } + + public static int getScreenHeight() { + WindowManager windowManager = (WindowManager) AppLoader.AppContext.getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return displayMetrics.heightPixels; + } + + public static boolean isPortrait() { + return AppLoader.AppContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; + } + + public static boolean isLandscape() { + return AppLoader.AppContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + } + + public static boolean isUndefined() { + return AppLoader.AppContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_UNDEFINED; + } + + public static int getStatusBarHeight() { + int result = 0; + int resourceId = AppLoader.AppContext.getResources().getIdentifier("status_bar_height", "dimen", "android"); + + if (resourceId > 0) { + result = AppLoader.AppContext.getResources().getDimensionPixelSize(resourceId); + } + + return result; + } + + public static boolean isScreenLock() { + KeyguardManager keyguardManager = (KeyguardManager) AppLoader.AppContext.getSystemService(Context.KEYGUARD_SERVICE); + return keyguardManager.inKeyguardRestrictedInputMode(); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + private boolean isRTL() { + return AppLoader.AppContext.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + private boolean isLTR() { + return AppLoader.AppContext.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/michaelbel/application/util/SizeUtils.java b/app/src/main/java/org/michaelbel/application/util/SizeUtils.java new file mode 100644 index 000000000..c9bc6906f --- /dev/null +++ b/app/src/main/java/org/michaelbel/application/util/SizeUtils.java @@ -0,0 +1,29 @@ +package org.michaelbel.application.util; + +import java.util.Locale; + +@SuppressWarnings("all") +public class SizeUtils { + + public static String formatSize(long size) { + if (size < 1024) { + return String.format(Locale.getDefault(), "%d B", size); + } else if (size < Math.pow(1024, 2)) { + return String.format(Locale.getDefault(), "%.1f KB", size / 1024.0F); + } else if (size < Math.pow(1024, 3)) { + return String.format(Locale.getDefault(), "%.1f MB", size / Math.pow(1024.0F, 2)); + } else if (size < Math.pow(1024, 4)) { + return String.format(Locale.getDefault(), "%.1f GB", size / Math.pow(1024.0F, 3)); + } else if (size < Math.pow(1024, 5)) { + return String.format(Locale.getDefault(), "%.1f TB", size / Math.pow(1024.0F, 4)); + } else if (size < Math.pow(1024, 6)) { + return String.format(Locale.getDefault(), "%.1f PB", size / Math.pow(1024.0F, 5)); + } else if (size < Math.pow(1024, 7)) { + return String.format(Locale.getDefault(), "%.1f EB", size / Math.pow(1024.0F, 6)); + } else if (size < Math.pow(1024, 8)) { + return String.format(Locale.getDefault(), "%.1f ZB", size / Math.pow(1024.0F, 7)); + } else { + return String.format(Locale.getDefault(), "%.1f YB", size / Math.pow(1024.0F, 8)); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/animator/scale_with_alpha.xml b/app/src/main/res/animator/scale_with_alpha.xml new file mode 100644 index 000000000..e20d5a999 --- /dev/null +++ b/app/src/main/res/animator/scale_with_alpha.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/book_user.png b/app/src/main/res/drawable-hdpi/book_user.png new file mode 100644 index 0000000000000000000000000000000000000000..c39c071232a7708a3e1d55b34280c375c7b00093 GIT binary patch literal 3161 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_button_play.png b/app/src/main/res/drawable-hdpi/ic_button_play.png new file mode 100644 index 0000000000000000000000000000000000000000..73231b1ce3678c3c946fd8d903d6f60e3c653d06 GIT binary patch literal 1742 zcmV;<1~K`GP)002t}1^@s6I8J)%000J+Nkle$F}1`93ed z%W?9BHOLm^2yzDP0PO_b1KLGD@%QbZZ6F8G-5^VDlLY?LzM#iICqN0HbD+0Dxu9ZD z2}ldN0xASu0%d^Cf=+`XK#zj<5Ij}IU7&|SiJ%LhJOWX=0TqF=2_i!GRPr5X1G*P< z6qK_;Fl!OsiLZhlp}W^gDUkd?FVN#tDzWepP6s^=+6}T`6_hLJMS9FiWfnrq1RbFZ z$VA|kv!{ez!~mq_lm^;Mxl`7-ACx3O!WLWkph%FD9FXwM6GCq!E#shg;RSu2{F`L4 zg%W77LLe>GCGvWrTMf)l&nXxbuXjK}VuErYV_BkbP`nC2VPb&78t$ZuK$!vy67rG6 zg7+BcvdTc2K9asd!Fp1~piGnghTf8BIQz%gPwLyAG@b%2Uigz7i}x=I7@Z>gwt`0|Ejn7=rfNN_FE&IbrcJJUpz=%F1d2 zn^DdHEG^wc|FH{ivH%NXc6N5YqoZRuG&J-R27sMd3d>jQ8qgeAe9X+u%oY?Bw0L=W zU6m15hUw%Rz10(9mp1Ex#pklNwzk2<#Kapid9!R<6}U4PJtg)ZT`w#?rl+S3H8nLq zdw6(AeU}x{ZpC6a(&(FMSbU6(jOb%yW9wX8Tt1KxSOou8#Fd^brNF{47z}^b*VlK2 zg@t`85vr<+VpPX5x_ z+4+4TVMV9~meFX$deVR%%-!8x$l*vaKZHG~23YvmwYRqqB_$=@u(!7t+Ct>g8Ys74 z>9DYF%*n}V@$~e(YH4XH#^eb1^j$crs1*roZfY z#3@ipN=kza3nK^leijZApAmcOcq6bdfmc^o|AYopY6!`qy|jL2hCJRPIWffEpV6NDj+jFw8YIHTC)X`(I~lIV9r$ z7DEn62@C7F-rinaT3XsSuCA`-jDgBtZAS}>#S2ov!cwKOva;RJ&+j@TkK9t7T5VmD zKOmqL3l>0H7#J8Bi;Ih^x3aQgbzL%_205$7ePY;%{{H@(V`F2}Wo2dGd3$?*#Q08W z!djPbE$N7ypdX;Nwzd<8qPDiSWsHL=GWWEFhE|+QH<|ub2bvS!QjGN(66Wb-I#X$O zSZ$I+PP}sH23hyl8({n9rA+_|2NIz|9HHBx@&iu@>Zp(hG~H+~Ty3CmdkD{bZxQkD;Lh6W^z$q2l`@$IiLxVmhewAje=>QhVo^%oYO^ z_$%bdojAtBnmVqB#O&#>Abd*)&_M_bPGO;;snHpFL<n@M-DwX&e4Iv4QM9#koIFto kz4G0usCT56ujGLK2IP#@EHj4)%K!iX07*qoM6N<$f`iabQUCw| literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/logo_avatar.png b/app/src/main/res/drawable-hdpi/logo_avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..8892c08dcb920145ccc9301d94d0665cf7a6ecec GIT binary patch literal 1642 zcmV-w29^1VP)KZw~)gbkP(3j+KH$b^ey3^N%sPl0uw+sKoi}#j~1=@)nPnxtL5TBdYURXV1Df zvoPhT?mpv@qxq941ClN)arqPrLp)+W@EqbF7`VLP{HE6McNnF312y%WU@ZnLOT--! z(?la0%ZZD&7^D(_U3tMR2Z}2Ru%yEIoZ??rB$r#>J_)N;@f|X) zJbZ(fk14xsYG2eaKoDhuecuHx8_hNfMo{C~26WOb z`MQV%j%LcmdVEaTO>0HRYux*pFF3cN9IWFKv)}}ET53W!r4@DjXF6j)*|L6#;|G!8 z&}C9TwCk_qVE@FE0-H~f5rkbhO3{@6*Qf@w|A+Zkv6rE3HC@-N70y`0`V$ccQ#Ms7=QKKGcN*V5hfT%9cGZZRO z547(hmyHX!lWsD{fX*;-)?YKqC7#NPrqNkXV5w&)c?)GQO&}7_o1C62O{^|q5mXx* zK>%_&otNcKQrG3CJa~zRdUi&Ai3NbHAhLtmk~4%jqnN~k67)_w30A5OEFvSTSrv1N zb+Gt#V3`ja+s<$~bDu4TZM0;cH70<^cuj62Kh;RT%%|QcR1^HZ+-iZziVSA^Vko+EFB1Q;MUpX7KA?-h+8 zEMCkPG=_w5J);;w&Od0&(OYcUbA>5e&QHG&!eQD+5lrD)lC}WWgXW<8t0%Krvi7^X# zBz?H9qvyu?`jQ!YY}qRLWkZfu3ry4%oR_n$m7Z0XqMc_s1}sbLI+x5B@o6kuK^r4F^};Jgpa9xJTx+AlWD7W4k7ZS0YUBOCya@fzO4XZm|9 ok=F^mbnG^x{`l31yu*_}0lcu}@Z{9BrT_o{07*qoM6N<$f}Y16MgRZ+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/review_placeholder.png b/app/src/main/res/drawable-hdpi/review_placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..c5144e5b5d860386d59ce95f6cf6051581ce3c99 GIT binary patch literal 7870 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 B5GViu literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/search_history_placeholder.png b/app/src/main/res/drawable-hdpi/search_history_placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..f5a92625979750c2e515ca7c6dd03e8892596748 GIT binary patch literal 9969 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/thumb_color.9.png b/app/src/main/res/drawable-hdpi/thumb_color.9.png new file mode 100644 index 0000000000000000000000000000000000000000..adcb9e96c6881217d22730b0f7d0d49229cba580 GIT binary patch literal 17243 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 M`2;dgt%=+DUw;w93IG5A literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_button_play.png b/app/src/main/res/drawable-mdpi/ic_button_play.png new file mode 100644 index 0000000000000000000000000000000000000000..7abcf81a054b331c9aac526d79e27e2cc03877af GIT binary patch literal 927 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/thumb_color.9.png b/app/src/main/res/drawable-mdpi/thumb_color.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9bdd2eafaf90f3eae2bf6678fa19df4218f3f088 GIT binary patch literal 789 zcmV+w1M2*VP)#U`fi#Kpx;*qC62 zfj~;wNJ)eyP`KmH_c`C0mr8&;+770d{POO-_xpZ--*@l#{@lvSpT|<{GM<0pT~^?^ zs;)$MQ*Bv3VOqIdUUQ5(?H3+ApU-Ot2M24jeCWsTLPid`Gg1-cezV!!>vTGAj*pK& zP*SITn*Y-2kjv#(g{|{0KKqk?zyEDC8lC96Zk;vS>BmoE*TF9(0)kX3#pl-;@pwEo z2qsEwB1~6|x+VJ!{K0{rBV?uspA@j#>-D}mMXc)%1h=2z^*CJ}Q+B+%2SW<)m4}5M!*mG7W6keTYPQd3T zC)nAvOeXVqFc_RjA)Z$UczEE0cgmqQeV<4slk9GRcDwy!GMR8Nd72V%;NgKUolg7R z?wA|<`}=z`Cp_<%;NgMK)sD#%kH>F{B2=kVKAWb=sB|}H2mau|!z1}zpQ2hQ6uKkI z2O_h-i@CHjT~3WTBRKsA{@}n%9?jEzA`*#Q-`w2X60eU+rP3ENozck)%!Gi7*{gtl z{O|_{9-d`xR=!{`xFJRo5$~~VHv6*CX#5-whXWFhfR0h8oqqiA2M2z}U1H(ezAqdO z-w<}s@Aq>EJxnAL&kqj|Ul)tTPmGw7I_>o1hd;PE0$lxaK(ro<#cqp{ahcr_hM<^Y z)OYB|5B~)OczQU7{eeK>*7o-H-QC^Ya5Ng-qNGkc{nGF1H}L=a7qu?Hrar#`XztR+ T8%h1=00000NkvXXu0mjf*M^0^ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/book_user.png b/app/src/main/res/drawable-xhdpi/book_user.png new file mode 100644 index 0000000000000000000000000000000000000000..64df4bf317337ac62977c0dcbc937bfcbbd0445a GIT binary patch literal 3972 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 MW1{m!+d1NY0NkqFNB{r; literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_button_play.png b/app/src/main/res/drawable-xhdpi/ic_button_play.png new file mode 100644 index 0000000000000000000000000000000000000000..f565fde2d11413c057644ce54296624e170f8c5b GIT binary patch literal 1863 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/search_history_placeholder.png b/app/src/main/res/drawable-xhdpi/search_history_placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..225e8eac3e8798067efbb626f990a01c527e0f44 GIT binary patch literal 13337 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® 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 + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xxhdpi/review_placeholder.png b/app/src/main/res/drawable-xxhdpi/review_placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..c2f25b8a4a839cdd90a8ac148c57916d3c1dd221 GIT binary patch literal 15231 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 QoMdsr+T0#iVTz9XKctj)DF6Tf literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/thumb_color.9.png b/app/src/main/res/drawable-xxhdpi/thumb_color.9.png new file mode 100644 index 0000000000000000000000000000000000000000..00fb83ec9f0a5520cd2867c03cacc1a6218ff7f2 GIT binary patch literal 19985 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/drawer_header.jpg b/app/src/main/res/drawable-xxxhdpi/drawer_header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a7136a1001fe5ad49aaf3ca265477fdab6e821c1 GIT binary patch literal 25436 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 z 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/movie_placeholder.jpg b/app/src/main/res/drawable-xxxhdpi/movie_placeholder.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e71d5754ef1aaa329c0b2d43e144929ef6b9f3e0 GIT binary patch literal 20897 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 + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/filter_empty_divider.xml b/app/src/main/res/drawable/filter_empty_divider.xml new file mode 100644 index 000000000..98afb5a4a --- /dev/null +++ b/app/src/main/res/drawable/filter_empty_divider.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_about.xml b/app/src/main/res/drawable/ic_about.xml new file mode 100644 index 000000000..51f244cb9 --- /dev/null +++ b/app/src/main/res/drawable/ic_about.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_account.xml b/app/src/main/res/drawable/ic_account.xml new file mode 100644 index 000000000..5b422a8ca --- /dev/null +++ b/app/src/main/res/drawable/ic_account.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_account_multiple.xml b/app/src/main/res/drawable/ic_account_multiple.xml new file mode 100644 index 000000000..10492bc00 --- /dev/null +++ b/app/src/main/res/drawable/ic_account_multiple.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml new file mode 100644 index 000000000..61388684b --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_back.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bookmark_check.xml b/app/src/main/res/drawable/ic_bookmark_check.xml new file mode 100644 index 000000000..1ec529b0e --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_check.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bookmark_plus.xml b/app/src/main/res/drawable/ic_bookmark_plus.xml new file mode 100644 index 000000000..1a34a2538 --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_plus.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bookmark_plus_outline.xml b/app/src/main/res/drawable/ic_bookmark_plus_outline.xml new file mode 100644 index 000000000..fe4fd1a08 --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_plus_outline.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bookmark_remove.xml b/app/src/main/res/drawable/ic_bookmark_remove.xml new file mode 100644 index 000000000..f40360d57 --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_remove.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_calendar.xml b/app/src/main/res/drawable/ic_calendar.xml new file mode 100644 index 000000000..d8ce6acba --- /dev/null +++ b/app/src/main/res/drawable/ic_calendar.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_calendar_clock.xml b/app/src/main/res/drawable/ic_calendar_clock.xml new file mode 100644 index 000000000..386e0209a --- /dev/null +++ b/app/src/main/res/drawable/ic_calendar_clock.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_chevron_right.xml b/app/src/main/res/drawable/ic_chevron_right.xml new file mode 100644 index 000000000..e7c0b53ac --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_right.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_clear.xml b/app/src/main/res/drawable/ic_clear.xml new file mode 100644 index 000000000..74f700229 --- /dev/null +++ b/app/src/main/res/drawable/ic_clear.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_clock.xml b/app/src/main/res/drawable/ic_clock.xml new file mode 100644 index 000000000..d3c3d331d --- /dev/null +++ b/app/src/main/res/drawable/ic_clock.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 000000000..bcf322d17 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete_sweep.xml b/app/src/main/res/drawable/ic_delete_sweep.xml new file mode 100644 index 000000000..bce540412 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_sweep.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_dots_menu.xml b/app/src/main/res/drawable/ic_dots_menu.xml new file mode 100644 index 000000000..969cc4bc7 --- /dev/null +++ b/app/src/main/res/drawable/ic_dots_menu.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_earth.xml b/app/src/main/res/drawable/ic_earth.xml new file mode 100644 index 000000000..f5319666f --- /dev/null +++ b/app/src/main/res/drawable/ic_earth.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_favorite.xml b/app/src/main/res/drawable/ic_favorite.xml new file mode 100644 index 000000000..845888ec6 --- /dev/null +++ b/app/src/main/res/drawable/ic_favorite.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_heart.xml b/app/src/main/res/drawable/ic_heart.xml new file mode 100644 index 000000000..696199eee --- /dev/null +++ b/app/src/main/res/drawable/ic_heart.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_heart_outline.xml b/app/src/main/res/drawable/ic_heart_outline.xml new file mode 100644 index 000000000..554ee14b1 --- /dev/null +++ b/app/src/main/res/drawable/ic_heart_outline.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_history.xml b/app/src/main/res/drawable/ic_history.xml new file mode 100644 index 000000000..fbcbcffe0 --- /dev/null +++ b/app/src/main/res/drawable/ic_history.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_home.xml b/app/src/main/res/drawable/ic_home.xml new file mode 100644 index 000000000..82e9eeb4f --- /dev/null +++ b/app/src/main/res/drawable/ic_home.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 000000000..bb7b8d983 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_movie.xml b/app/src/main/res/drawable/ic_movie.xml new file mode 100644 index 000000000..c257d7c04 --- /dev/null +++ b/app/src/main/res/drawable/ic_movie.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_movie_cadr.xml b/app/src/main/res/drawable/ic_movie_cadr.xml new file mode 100644 index 000000000..b1dc51134 --- /dev/null +++ b/app/src/main/res/drawable/ic_movie_cadr.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_offline.xml b/app/src/main/res/drawable/ic_offline.xml new file mode 100644 index 000000000..1c99589f4 --- /dev/null +++ b/app/src/main/res/drawable/ic_offline.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_photos.xml b/app/src/main/res/drawable/ic_photos.xml new file mode 100644 index 000000000..69c719cff --- /dev/null +++ b/app/src/main/res/drawable/ic_photos.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_play.xml b/app/src/main/res/drawable/ic_play.xml new file mode 100644 index 000000000..98ae7e338 --- /dev/null +++ b/app/src/main/res/drawable/ic_play.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_release_date.xml b/app/src/main/res/drawable/ic_release_date.xml new file mode 100644 index 000000000..a0be0d0e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_release_date.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_reviews.xml b/app/src/main/res/drawable/ic_reviews.xml new file mode 100644 index 000000000..49bd88181 --- /dev/null +++ b/app/src/main/res/drawable/ic_reviews.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_schedule.xml b/app/src/main/res/drawable/ic_schedule.xml new file mode 100644 index 000000000..339c229af --- /dev/null +++ b/app/src/main/res/drawable/ic_schedule.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_search.xml b/app/src/main/res/drawable/ic_search.xml new file mode 100644 index 000000000..c060084d3 --- /dev/null +++ b/app/src/main/res/drawable/ic_search.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_search_error.xml b/app/src/main/res/drawable/ic_search_error.xml new file mode 100644 index 000000000..41bb5d2e8 --- /dev/null +++ b/app/src/main/res/drawable/ic_search_error.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_series.xml b/app/src/main/res/drawable/ic_series.xml new file mode 100644 index 000000000..b1dc51134 --- /dev/null +++ b/app/src/main/res/drawable/ic_series.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 000000000..9c05016bb --- /dev/null +++ b/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 000000000..8c1f1d442 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_star.xml b/app/src/main/res/drawable/ic_star.xml new file mode 100644 index 000000000..6bf92682e --- /dev/null +++ b/app/src/main/res/drawable/ic_star.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_star_border.xml b/app/src/main/res/drawable/ic_star_border.xml new file mode 100644 index 000000000..233f78dd4 --- /dev/null +++ b/app/src/main/res/drawable/ic_star_border.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_star_circle.xml b/app/src/main/res/drawable/ic_star_circle.xml new file mode 100644 index 000000000..bb0562f80 --- /dev/null +++ b/app/src/main/res/drawable/ic_star_circle.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_star_half.xml b/app/src/main/res/drawable/ic_star_half.xml new file mode 100644 index 000000000..16651a30e --- /dev/null +++ b/app/src/main/res/drawable/ic_star_half.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tune.xml b/app/src/main/res/drawable/ic_tune.xml new file mode 100644 index 000000000..0584ac35d --- /dev/null +++ b/app/src/main/res/drawable/ic_tune.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_url.xml b/app/src/main/res/drawable/ic_url.xml new file mode 100644 index 000000000..21aa898d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_url.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_videos.xml b/app/src/main/res/drawable/ic_videos.xml new file mode 100644 index 000000000..40ee214b2 --- /dev/null +++ b/app/src/main/res/drawable/ic_videos.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_view_compat.xml b/app/src/main/res/drawable/ic_view_compat.xml new file mode 100644 index 000000000..ba316d207 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_compat.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_view_default.xml b/app/src/main/res/drawable/ic_view_default.xml new file mode 100644 index 000000000..e57d20fc0 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_default.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_view_list.xml b/app/src/main/res/drawable/ic_view_list.xml new file mode 100644 index 000000000..38ef318f0 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_list.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_voice.xml b/app/src/main/res/drawable/ic_voice.xml new file mode 100644 index 000000000..53b098dcf --- /dev/null +++ b/app/src/main/res/drawable/ic_voice.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_watch.xml b/app/src/main/res/drawable/ic_watch.xml new file mode 100644 index 000000000..210741262 --- /dev/null +++ b/app/src/main/res/drawable/ic_watch.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_whatshot.xml b/app/src/main/res/drawable/ic_whatshot.xml new file mode 100644 index 000000000..0e1fde078 --- /dev/null +++ b/app/src/main/res/drawable/ic_whatshot.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_youtube.xml b/app/src/main/res/drawable/ic_youtube.xml new file mode 100644 index 000000000..a4db476ca --- /dev/null +++ b/app/src/main/res/drawable/ic_youtube.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/image_circle.xml b/app/src/main/res/drawable/image_circle.xml new file mode 100644 index 000000000..18b4c7bf8 --- /dev/null +++ b/app/src/main/res/drawable/image_circle.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/image_rect.xml b/app/src/main/res/drawable/image_rect.xml new file mode 100644 index 000000000..17fce392f --- /dev/null +++ b/app/src/main/res/drawable/image_rect.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rect_quality.xml b/app/src/main/res/drawable/rect_quality.xml new file mode 100644 index 000000000..96c06ac51 --- /dev/null +++ b/app/src/main/res/drawable/rect_quality.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/white_radius.xml b/app/src/main/res/drawable/white_radius.xml new file mode 100644 index 000000000..1d25687ef --- /dev/null +++ b/app/src/main/res/drawable/white_radius.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_favs.xml b/app/src/main/res/layout/activity_favs.xml new file mode 100644 index 000000000..ea5a7b2f9 --- /dev/null +++ b/app/src/main/res/layout/activity_favs.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..8d12e0593 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_movie.xml b/app/src/main/res/layout/activity_movie.xml new file mode 100644 index 000000000..8f4fee8e3 --- /dev/null +++ b/app/src/main/res/layout/activity_movie.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_person.xml b/app/src/main/res/layout/activity_person.xml new file mode 100644 index 000000000..5a8601755 --- /dev/null +++ b/app/src/main/res/layout/activity_person.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_review.xml b/app/src/main/res/layout/activity_review.xml new file mode 100644 index 000000000..75fcae45c --- /dev/null +++ b/app/src/main/res/layout/activity_review.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml new file mode 100644 index 000000000..5a8601755 --- /dev/null +++ b/app/src/main/res/layout/activity_search.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml new file mode 100644 index 000000000..759e2695e --- /dev/null +++ b/app/src/main/res/layout/activity_settings.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_trailers.xml b/app/src/main/res/layout/activity_trailers.xml new file mode 100644 index 000000000..ff8221c50 --- /dev/null +++ b/app/src/main/res/layout/activity_trailers.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml new file mode 100644 index 000000000..105995942 --- /dev/null +++ b/app/src/main/res/layout/fragment_about.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_favs.xml b/app/src/main/res/layout/fragment_favs.xml new file mode 100644 index 000000000..3237b20b3 --- /dev/null +++ b/app/src/main/res/layout/fragment_favs.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_movie.xml b/app/src/main/res/layout/fragment_movie.xml new file mode 100644 index 000000000..474a854d3 --- /dev/null +++ b/app/src/main/res/layout/fragment_movie.xml @@ -0,0 +1,27 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_nowplaying.xml b/app/src/main/res/layout/fragment_nowplaying.xml new file mode 100644 index 000000000..978ac7e74 --- /dev/null +++ b/app/src/main/res/layout/fragment_nowplaying.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_person.xml b/app/src/main/res/layout/fragment_person.xml new file mode 100644 index 000000000..91694afb5 --- /dev/null +++ b/app/src/main/res/layout/fragment_person.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_review.xml b/app/src/main/res/layout/fragment_review.xml new file mode 100644 index 000000000..ef4faffbd --- /dev/null +++ b/app/src/main/res/layout/fragment_review.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_review_details.xml b/app/src/main/res/layout/fragment_review_details.xml new file mode 100644 index 000000000..de4dc464a --- /dev/null +++ b/app/src/main/res/layout/fragment_review_details.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml new file mode 100644 index 000000000..5731662f5 --- /dev/null +++ b/app/src/main/res/layout/fragment_search.xml @@ -0,0 +1,27 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_videos.xml b/app/src/main/res/layout/fragment_videos.xml new file mode 100644 index 000000000..978ac7e74 --- /dev/null +++ b/app/src/main/res/layout/fragment_videos.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/search_item.xml b/app/src/main/res/menu/search_item.xml new file mode 100644 index 000000000..f384d8c8a --- /dev/null +++ b/app/src/main/res/menu/search_item.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f5908281d070150700378b64a84c7db1f97aa1 GIT binary patch literal 3056 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 axPAxe%7rDusX+w*00006jj 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⁣ zwiG+x#%j}{0gU~J8;<|!B1@-XaB@{KORFwrYg_8rOv({b0EO#DbeQRm;B6_9=mXGf z-x|VL{zd`)#@yN}HkCSJbjbNlE|zL3Wm9Q8HY`sV)}3%pgN>cL^67{Z;PPL(*wT8N zUjXU{@|*hvm}({wsAC=x0^ok0%UAz0;sogW{B!nDqk|JJ5x~4NfTDgP49^zeu`csl?5mY@JdQdISc zFs!E{^grmkLnUk9 zny~m)1vws@5BFI<-0Tuo2JWX(0v`W|t(wg;s--L47WTvTMz-8l#TL^=OJNRS2?_Qj z3AKT+gvbyBi#H*-tJ%tWD|>EV3wy|8qxfzS!5RW;Jpl5*zo&^UBU=fG#2}UvRyNkK zA06Dy9;K1ca@r2T>yThYgI!ont$(G{6q#2QT+00r_x0(b)gsE`lBB?2gr55gq^D3Fi&p%E(p9>U%bv zkg1Jco(RbyTX7FDHOnl7-O@ zI$AaIl?9NJKPm(WiBP`1-#CB1QzU>&hKm)fpa5DKE{2$X0hGz-0uZ?cyTk(YC!Y&| zL=1VrNERSA5NA2jq7FACfX4JfPyj5XXl1yv0>~s;eF7L2$>&oMqeTFT2m$y7FlkON z_yurD1yIOvA;5C6016pyxBznGUt0kJ&k5r#;&>Jow`r)sp9R~PmK~lz$3xH%LT*1U zJdOyABZ3!FvNoR*vN$5ykHS8f`jA4zV+|L}i1C4`B2c{R0;UdYxaU|H)2avz@ z=mEYc|2S<+(B2Tj+FkX+2D+yFI!k9lWMA61DJ{)e;lum$(;O87?vGJJe!KtK04+N_ zI*P~t@dUb>9Xh{dbyl{-ZQ(UMgz7$|QfL5XSPkskt^NgctYC#;4WcZB1@%@wy@2t3 z2z0DI7&%b$*Aw~abe?GxE`ez@+6hOh-6*8fHRV{1os$EL@}uUZeG4h1&Be`98q*7j z=3-v+lhIjfWVo12!<>%V^a6lTgW3+_#W6n|p*~==zOH7z$0{LSZk(Tpd7EaD04hnA zL;#fxS0aD{`5^&D`}>0Uq?byDD-l2=!wm_bLcUl4gc(% za1p|itVANvFF>hghAS07Im1;IK;|b*W)}VDyI;BIp2=K*yu2a)j?B|f<44NI$NbmJ z#dE0>jI$fMr&@>4kN8MLFb4&2O9fEKaQg%(QO$4_1rVQywG^CmBLh#}_7gKW3vd?| z2?1^&KWq8}8I^_S0|)MowU_pw$q@nl@Nkn$z>BQq_KA^9yaR`(R3u{{Ig;cwt z@AJ^{ODQCm^neroM9nKNUAXi9RCK`OsP_LuR0PUR(YZCCX5dNF6VzcoK&=b^r`W?ltt|*F zpkoae%ZT{C1h~EcFui~b7fF`vb<<~j_VquuUA$}QqIKYELPp#;{u?q8Dz}WAG-(3; zjrm$i%7UbyZMM(Y{>!uJ#vNB?R~B{6Htp=>e*<{fQQ5W7V(1coCWlOON!MzZxhum| ztZBQpGR z;~#ur^&PockKdV{Q6R>o`Pl{0x!DEbpZ7y9Y;*ZvE!*gU`V1W3znva{f=?WO5I&>B z&hw6}tjECtaghm5z|C#%M;Yf_*pI^};h}Vl=^r9EN=tVDj86D;C$jIJ?K7VP+00000NkvXXu0mjf D5i!M* literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..459ca609d3ae0d3943ab44cdc27feef9256dc6d7 GIT binary patch literal 7098 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca12fe024be86e868d14e91120a6902f8e88ac6 GIT binary patch literal 6464 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 B0*L?s literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..8e19b410a1b15ff180f3dacac19395fe3046cdec GIT binary patch literal 10676 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..4c19a13c239cb67b8a2134ddd5f325db1d2d5bee GIT binary patch literal 15523 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 BIP(Ai literal 0 HcmV?d00001 diff --git a/app/src/main/res/values-sw600dp/bools.xml b/app/src/main/res/values-sw600dp/bools.xml new file mode 100644 index 000000000..d20364bba --- /dev/null +++ b/app/src/main/res/values-sw600dp/bools.xml @@ -0,0 +1,3 @@ + + true + \ No newline at end of file diff --git a/app/src/main/res/values-sw720dp/bools.xml b/app/src/main/res/values-sw720dp/bools.xml new file mode 100644 index 000000000..d20364bba --- /dev/null +++ b/app/src/main/res/values-sw720dp/bools.xml @@ -0,0 +1,3 @@ + + true + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 000000000..48740391b --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/bools.xml b/app/src/main/res/values/bools.xml new file mode 100644 index 000000000..0e9eeb5ab --- /dev/null +++ b/app/src/main/res/values/bools.xml @@ -0,0 +1,3 @@ + + false + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..279697004 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,64 @@ + + #202E3B + #18222C + #FFAB40 + + #FFF44336 + + + #DE000000 + #8A000000 + #61000000 + #1F000000 + #8A000000 + #61000000 + #E0E0E0 + #F5F5F5 + #FFF0F0F0 + #FFFFFFFF + + #FF4CAF50 + #804CAF50 + #FFFAFAFA + #61000000 + #FFBDBDBD + #1F000000 + + + #FFFFFFFF + #B3FFFFFF + #80FFFFFF + #1FFFFFFF + #FFFFFFFF + #80FFFFFF + #000000 + #212121 + #303030 + #424242 + + #FFA5D6A7 + #80A5D6A7 + #FFBDBDBD + #4DFFFFFF + #FF424242 + #1AFFFFFF + + + #FFFFFFFF + #B3FFFFFF + #80FFFFFF + #1FFFFFFF + #FFFFFFFF + #80FFFFFF + #000000 + #212121 + #FF151D26 + #FF1C2732 + + #FFCC80 + #80FFCC80 + #FFBDBDBD + #4DFFFFFF + #FF424242 + #1AFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/material-design-colors.xml b/app/src/main/res/values/material-design-colors.xml new file mode 100644 index 000000000..edd35ad3e --- /dev/null +++ b/app/src/main/res/values/material-design-colors.xml @@ -0,0 +1,339 @@ + + + @color/md_red_500 + @color/md_pink_500 + @color/md_purple_500 + @color/md_deep_purple_500 + @color/md_indigo_500 + @color/md_blue_500 + @color/md_light_blue_500 + @color/md_cyan_500 + @color/md_teal_500 + @color/md_green_500 + @color/md_light_green_500 + @color/md_lime_500 + @color/md_yellow_500 + @color/md_amber_500 + @color/md_orange_500 + @color/md_deep_orange_500 + @color/md_brown_500 + @color/md_grey_500 + @color/md_blue_grey_500 + + + @color/md_red_700 + @color/md_pink_700 + @color/md_purple_700 + @color/md_deep_purple_700 + @color/md_indigo_700 + @color/md_blue_700 + @color/md_light_blue_700 + @color/md_cyan_700 + @color/md_teal_700 + @color/md_green_700 + @color/md_light_green_700 + @color/md_lime_700 + @color/md_yellow_700 + @color/md_amber_700 + @color/md_orange_700 + @color/md_deep_orange_700 + @color/md_brown_700 + @color/md_grey_700 + @color/md_blue_grey_700 + + + @color/md_red_A200 + @color/md_pink_A200 + @color/md_purple_A200 + @color/md_deep_purple_A200 + @color/md_indigo_A200 + @color/md_blue_A200 + @color/md_light_blue_A200 + @color/md_cyan_A200 + @color/md_teal_A200 + @color/md_green_A200 + @color/md_light_green_A200 + @color/md_lime_A200 + @color/md_yellow_A200 + @color/md_amber_A200 + @color/md_orange_A200 + @color/md_deep_orange_A200 + + + #FFEBEE + #FFCDD2 + #EF9A9A + #E57373 + #EF5350 + #F44336 + #E53935 + #D32F2F + #C62828 + #B71C1C + #FF8A80 + #FF5252 + #FF1744 + #D50000 + + #FCE4EC + #F8BBD0 + #F48FB1 + #F06292 + #EC407A + #E91E63 + #D81B60 + #C2185B + #AD1457 + #880E4F + #FF80AB + #FF4081 + #F50057 + #C51162 + + #F3E5F5 + #E1BEE7 + #CE93D8 + #BA68C8 + #AB47BC + #9C27B0 + #8E24AA + #7B1FA2 + #6A1B9A + #4A148C + #EA80FC + #E040FB + #D500F9 + #AA00FF + + #EDE7F6 + #D1C4E9 + #B39DDB + #9575CD + #7E57C2 + #673AB7 + #5E35B1 + #512DA8 + #4527A0 + #311B92 + #B388FF + #7C4DFF + #651FFF + #6200EA + + #E8EAF6 + #C5CAE9 + #9FA8DA + #7986CB + #5C6BC0 + #3F51B5 + #3949AB + #303F9F + #283593 + #1A237E + #8C9EFF + #536DFE + #3D5AFE + #304FFE + + #E3F2FD + #BBDEFB + #90CAF9 + #64B5F6 + #42A5F5 + #2196F3 + #1E88E5 + #1976D2 + #1565C0 + #0D47A1 + #82B1FF + #448AFF + #2979FF + #2962FF + + #E1F5FE + #B3E5FC + #81D4FA + #4FC3F7 + #29B6F6 + #03A9F4 + #039BE5 + #0288D1 + #0277BD + #01579B + #80D8FF + #40C4FF + #00B0FF + #0091EA + + #E0F7FA + #B2EBF2 + #80DEEA + #4DD0E1 + #26C6DA + #00BCD4 + #00ACC1 + #0097A7 + #00838F + #006064 + #84FFFF + #18FFFF + #00E5FF + #00B8D4 + + #E0F2F1 + #B2DFDB + #80CBC4 + #4DB6AC + #26A69A + #009688 + #00897B + #00796B + #00695C + #004D40 + #A7FFEB + #64FFDA + #1DE9B6 + #00BFA5 + + #E8F5E9 + #C8E6C9 + #A5D6A7 + #81C784 + #66BB6A + #4CAF50 + #43A047 + #388E3C + #2E7D32 + #1B5E20 + #B9F6CA + #69F0AE + #00E676 + #00C853 + + #F1F8E9 + #DCEDC8 + #C5E1A5 + #AED581 + #9CCC65 + #8BC34A + #7CB342 + #689F38 + #558B2F + #33691E + #CCFF90 + #B2FF59 + #76FF03 + #64DD17 + + #F9FBE7 + #F0F4C3 + #E6EE9C + #DCE775 + #D4E157 + #CDDC39 + #C0CA33 + #AFB42B + #9E9D24 + #827717 + #F4FF81 + #EEFF41 + #C6FF00 + #AEEA00 + + #FFFDE7 + #FFF9C4 + #FFF59D + #FFF176 + #FFEE58 + #FFEB3B + #FDD835 + #FBC02D + #F9A825 + #F57F17 + #FFFF8D + #FFFF00 + #FFEA00 + #FFD600 + + #FFF8E1 + #FFECB3 + #FFE082 + #FFD54F + #FFCA28 + #FFC107 + #FFB300 + #FFA000 + #FF8F00 + #FF6F00 + #FFE57F + #FFD740 + #FFC400 + #FFAB00 + + #FFF3E0 + #FFE0B2 + #FFCC80 + #FFB74D + #FFA726 + #FF9800 + #FB8C00 + #F57C00 + #EF6C00 + #E65100 + #FFD180 + #FFAB40 + #FF9100 + #FF6D00 + + #FBE9E7 + #FFCCBC + #FFAB91 + #FF8A65 + #FF7043 + #FF5722 + #F4511E + #E64A19 + #D84315 + #BF360C + #FF9E80 + #FF6E40 + #FF3D00 + #DD2C00 + + #EFEBE9 + #D7CCC8 + #BCAAA4 + #A1887F + #8D6E63 + #795548 + #6D4C41 + #5D4037 + #4E342E + #3E2723 + + #FAFAFA + #F5F5F5 + #EEEEEE + #E0E0E0 + #BDBDBD + #9E9E9E + #757575 + #616161 + #424242 + #303030 + #212121 + + #ECEFF1 + #CFD8DC + #B0BEC5 + #90A4AE + #78909C + #607D8B + #546E7A + #455A64 + #37474F + #263238 + + #000000 + #FFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..9541b946c --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,168 @@ + + Moviemade + Moviemade + English + English + en + + Movies + Search + TV Shows + People + Watchlist + Favorites + Now Playing + Popular + Top Rated + Upcoming + Retry + Now Playing Movies + Popular Movies + Top Rated Movies + Upcoming Movies + Change View + No connection + Something went wrong + Please, check your internet connection + Speak now + Connecting… + Waiting for network… + Online + Offline + Genres + Recommended + Loading user… + No results + No Movies + + Add + Remove + Open + Copy link + Share link + Similar Movies + Share via + Overview + More + Share + Open in TMDb + Open in IMDb + Home page + Add to Favorites + Remove to Favorites + Images + Videos + Reviews + View All + Close + Copy + Open in… + Loading movie… + Crew + Directors + Writers + Producers + Actors + %1$d min + %1$d votes + Review + Info + Original Title + Original Language + Status + Tagline + Budget + Revenue + Production Companies + Homepage + + No Videos + + No Reviews + Review by %1$s + Open Review url + + My Favorites + + Settings + In-App Browser + Open external links within the app + Include Adult + Language + Cancel + OK + Customize + Toolbar Badges + Search History + Cache Settings + Local Database + Calculating… + Screen Orientation + System + Portrait + Landscape + Appearance + Search Filters + Show set of filters under searchbox + Network Settings + Quality + Image Quality + Original + Low + Medium + High + Custom + Clear History + Search history is empty + + Notifications + Enabled + Disabled + Alert + Vibrate + Default + Short + Long + Only if silent + Sound + No sound + Default + Select ringtone + Priority + High + Max + Popup Notifications + No popup + Only when screen \"on\" + Only when screen \"off\" + Always show popup + LED Color + Repeat + Repeat Notifications + Off + 5 minutes + 10 minutes + 30 minutes + 1 hour + 2 hours + 6 hours + Reset + Reset All Notifications + Undo all custom notification settings + + About + Open + Link copied to clipboard + Rate on Google Play + Fork on Github + Feedback + Open-source Libraries + Share with Friends + Support Development + Contribute Translations + Enable Analytics + Share App + %1$s for Android + Version %1$s (Build %2$d) + %1$s is an open source project maintained by one develop. You can help improve the project in one of the following ways: + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..90d66f5fa --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..a56c3975d --- /dev/null +++ b/build.gradle @@ -0,0 +1,21 @@ +buildscript { + repositories { + jcenter() + google() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.0.1' + } +} + +allprojects { + repositories { + jcenter() + google() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/desktop.ini b/desktop.ini new file mode 100644 index 000000000..35f853da0 --- /dev/null +++ b/desktop.ini @@ -0,0 +1,2 @@ +[.ShellClassInfo] +IconResource=C:\Program Files\Android\Android Studio\bin\studio.ico,0 diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..aac7c9b46 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,17 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..13372aef5e24af05341d49695ee84e5f9b594659 GIT binary patch literal 53636 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ⅅ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 H-+%o-(+5aQ literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..094c3fef3 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Nov 17 07:29:37 MSK 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/gradlew b/gradlew new file mode 100644 index 000000000..9d82f7891 --- /dev/null +++ b/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..8a0b282aa --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..e7b4def49 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app'