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 000000000..c39c07123 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/book_user.png differ 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 000000000..73231b1ce Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_button_play.png differ 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 000000000..8892c08dc Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo_avatar.png differ 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 000000000..c5144e5b5 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/review_placeholder.png differ 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 000000000..f5a926259 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/search_history_placeholder.png differ 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 000000000..adcb9e96c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/thumb_color.9.png differ diff --git a/app/src/main/res/drawable-mdpi/book_user.png b/app/src/main/res/drawable-mdpi/book_user.png new file mode 100644 index 000000000..66bf3b1d5 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/book_user.png differ 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 000000000..7abcf81a0 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_button_play.png differ diff --git a/app/src/main/res/drawable-mdpi/logo_avatar.png b/app/src/main/res/drawable-mdpi/logo_avatar.png new file mode 100644 index 000000000..c2de7747c Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo_avatar.png differ diff --git a/app/src/main/res/drawable-mdpi/review_placeholder.png b/app/src/main/res/drawable-mdpi/review_placeholder.png new file mode 100644 index 000000000..946c1bd5e Binary files /dev/null and b/app/src/main/res/drawable-mdpi/review_placeholder.png differ diff --git a/app/src/main/res/drawable-mdpi/search_history_placeholder.png b/app/src/main/res/drawable-mdpi/search_history_placeholder.png new file mode 100644 index 000000000..c422f689e Binary files /dev/null and b/app/src/main/res/drawable-mdpi/search_history_placeholder.png differ 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 000000000..9bdd2eafa Binary files /dev/null and b/app/src/main/res/drawable-mdpi/thumb_color.9.png differ 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 000000000..64df4bf31 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/book_user.png differ 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 000000000..f565fde2d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_button_play.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo_avatar.png b/app/src/main/res/drawable-xhdpi/logo_avatar.png new file mode 100644 index 000000000..10c2dc9af Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo_avatar.png differ diff --git a/app/src/main/res/drawable-xhdpi/review_placeholder.png b/app/src/main/res/drawable-xhdpi/review_placeholder.png new file mode 100644 index 000000000..a9c21c33e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/review_placeholder.png differ 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 000000000..225e8eac3 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/search_history_placeholder.png differ diff --git a/app/src/main/res/drawable-xhdpi/thumb_color.9.png b/app/src/main/res/drawable-xhdpi/thumb_color.9.png new file mode 100644 index 000000000..435ce2150 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/thumb_color.9.png differ diff --git a/app/src/main/res/drawable-xxhdpi/book_user.png b/app/src/main/res/drawable-xxhdpi/book_user.png new file mode 100644 index 000000000..2f54d6b5e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/book_user.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_button_play.png b/app/src/main/res/drawable-xxhdpi/ic_button_play.png new file mode 100644 index 000000000..37f8ed629 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_button_play.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo_avatar.png b/app/src/main/res/drawable-xxhdpi/logo_avatar.png new file mode 100644 index 000000000..df02f04f7 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo_avatar.png differ diff --git a/app/src/main/res/drawable-xxhdpi/rect_quality_mini.xml b/app/src/main/res/drawable-xxhdpi/rect_quality_mini.xml new file mode 100644 index 000000000..dae07717b --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/rect_quality_mini.xml @@ -0,0 +1,14 @@ + + + + + \ 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 000000000..c2f25b8a4 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/review_placeholder.png differ diff --git a/app/src/main/res/drawable-xxhdpi/search_history_placeholder.png b/app/src/main/res/drawable-xxhdpi/search_history_placeholder.png new file mode 100644 index 000000000..7e02daebd Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/search_history_placeholder.png differ 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 000000000..00fb83ec9 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/thumb_color.9.png differ 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 000000000..a7136a100 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/drawer_header.jpg differ 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 000000000..e71d5754e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/movie_placeholder.jpg differ diff --git a/app/src/main/res/drawable-xxxhdpi/tmdb_icon.png b/app/src/main/res/drawable-xxxhdpi/tmdb_icon.png new file mode 100644 index 000000000..910f91e8b Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/tmdb_icon.png differ diff --git a/app/src/main/res/drawable/dot_oval.xml b/app/src/main/res/drawable/dot_oval.xml new file mode 100644 index 000000000..46fad45b6 --- /dev/null +++ b/app/src/main/res/drawable/dot_oval.xml @@ -0,0 +1,7 @@ + + + + + + + \ 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 000000000..a2f590828 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..1b5239980 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..ff10afd6e Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..115a4c768 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..dcd3cd808 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ 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 000000000..459ca609d Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ 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 000000000..8ca12fe02 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ 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 000000000..8e19b410a Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..b824ebdd4 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ 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 000000000..4c19a13c2 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ 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 000000000..13372aef5 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ 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'