diff --git a/.gitignore b/.gitignore
index 40302dc..5c42b3c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,10 +20,6 @@ gen-external-apklibs
#gradle
.gradle
-local.properties
-gradlew
-gradlew.bat
-gradle/
build/
#vi
diff --git a/README.md b/README.md
index e69de29..10ea820 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,42 @@
+### Working with shared elements
+
+Commit - [**8872619**](https://github.com/saulmm/Android-Material-Examples/commit/8872619ba751d99044a8426a35e6d2416d3af286)
+
+
+
+### Working with shared elements, explode transition, and animations
+
+Commit - [**901d62c**](https://github.com/saulmm/Android-Material-Examples/commit/901d62c65bbe70f55d944b718b8e6c6c2c69839d)
+
+
+
+## Playing with the new menu-to arrow toggle animattion added in the Support Library
+
+Commit - [**ead8ada**](https://github.com/saulmm/Android-Material-Examples/commit/ead8adaafb482bd29a9ef86568a08afebeffd043)
+
+
+
+## Reusing an example to build a pretty effect like the tab slide of google play app
+
+Commit - [**f502305**](https://github.com/saulmm/Android-Material-Examples/commit/f5023057d1e088cc69849c9c7f60d32279604214)
+
+
+
+## Using CircularReveal to show a pretty effect between activities
+
+Commit - [**ba9c202**](https://github.com/saulmm/Android-Material-Examples/commit/ba9c2026bbe5fc57d6166389f60030176d065623)
+
+
+
+## Replicating some parts of the lollypop dialer app basing on the material design principle: Motion provides meaning
+
+Commit - [**eb20707**](https://github.com/saulmm/Android-Material-Examples/commit/eb20707d8db3aef321ae30cb80faada5e3cd7b4d)
+
+
+
+
+## Using StateListAnimator to change the elevation of a view smootly
+
+Commit - [**3f1102b**](https://github.com/saulmm/Android-Material-Examples/commit/3f1102b50606d2b57781ad5c0de232697da47862)
+
+
diff --git a/app/build.gradle b/app/build.gradle
index 0d34007..924e79c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,25 +1,22 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 'android-L'
+ compileSdkVersion 22
buildToolsVersion "20.0.0"
defaultConfig {
applicationId "com.saulmm.material.myapplication"
- minSdkVersion 'L'
- targetSdkVersion 'L'
+ minSdkVersion 21
+ targetSdkVersion 22
versionCode 1
versionName "1.0"
}
- buildTypes {
- release {
- runProguard false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
+
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
- compile 'com.android.support:support-v4:20.0.0'
-}
+ compile 'com.android.support:cardview-v7:21.0.0'
+ compile 'com.android.support:appcompat-v7:22.0.0'
+ compile 'com.android.support:support-v4:22.0.0'
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/saulmm/material/myapplication/ApplicationTest.java b/app/src/androidTest/java/com/saulmm/material/myapplication/ApplicationTest.java
deleted file mode 100644
index 2475efc..0000000
--- a/app/src/androidTest/java/com/saulmm/material/myapplication/ApplicationTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.saulmm.material.myapplication;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * Testing Fundamentals
- */
-public class ApplicationTest extends ApplicationTestCase {
- public ApplicationTest() {
- super(Application.class);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a096cfd..2ebe7f2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,18 +7,35 @@
android:icon="@drawable/ic_launcher"
android:label=""
android:theme="@style/AppTheme" >
-
+
+
+
-
+
+
+
+
+
+
+
+
+ android:name="com.saulmm.material.activities.ColorActivity"
+ android:label="@string/title_activity_color" />
+
+
+
diff --git a/app/src/main/java/com/saulmm/material/MyActivity.java b/app/src/main/java/com/saulmm/material/MyActivity.java
deleted file mode 100644
index 65c57af..0000000
--- a/app/src/main/java/com/saulmm/material/MyActivity.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.saulmm.material;
-
-import android.app.Activity;
-import android.app.ActivityOptions;
-import android.content.Intent;
-import android.graphics.Outline;
-import android.os.Bundle;
-import android.transition.Explode;
-import android.transition.Scene;
-import android.transition.Slide;
-import android.transition.TransitionManager;
-import android.util.Pair;
-import android.view.Menu;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.Toast;
-
-import com.saulmm.material.R;
-
-
-public class MyActivity extends Activity {
-
- private FrameLayout frameContainer;
- private View holderView;
- private View fabButton;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_my);
-
- // Fab Button
- int fabSize = getResources().getDimensionPixelSize(R.dimen.fab_size);
- Outline fabOutLine = new Outline();
- fabOutLine.setOval(0, 0, fabSize, fabSize);
-
- // Fragment container
- frameContainer = (FrameLayout) findViewById(R.id.container);
-
- holderView = findViewById(R.id.holder_view);
-
- // FabView
- fabButton = findViewById(R.id.fab_button);
- fabButton.setOnClickListener(fabClickListener);
- fabButton.setOutline(fabOutLine);
- }
-
-
- View.OnClickListener fabClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(MyActivity.this,
- Pair.create(holderView, "holder2"),
- Pair.create(fabButton, "fab"));
-
- Intent i = new Intent (MyActivity.this, MyActivity2.class);
- startActivity(i, options.toBundle());
- }
- };
-}
diff --git a/app/src/main/java/com/saulmm/material/MyActivity2.java b/app/src/main/java/com/saulmm/material/MyActivity2.java
deleted file mode 100644
index 282fb98..0000000
--- a/app/src/main/java/com/saulmm/material/MyActivity2.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.saulmm.material;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.graphics.Outline;
-import android.os.Bundle;
-import android.transition.ChangeBounds;
-import android.transition.Explode;
-import android.transition.Scene;
-import android.transition.Slide;
-import android.transition.TransitionManager;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.FrameLayout;
-
-import com.saulmm.material.R;
-
-public class MyActivity2 extends Activity {
-
- private FrameLayout frameContainer;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_my2);
-
- // Fab Button
- int fabSize = getResources().getDimensionPixelSize(R.dimen.fab_size);
- Outline fabOutLine = new Outline();
- fabOutLine.setOval(0, 0, fabSize, fabSize);
- }
-
- @Override
- protected void onResume() {
-
- super.onResume();
-
- frameContainer = (FrameLayout) findViewById(R.id.container);
-
- Scene scene1 = Scene.getSceneForLayout(frameContainer, R.layout.activity_my_activity2, this);
- TransitionManager.go(scene1, new Explode());
- }
-}
diff --git a/app/src/main/java/com/saulmm/material/activities/ColorActivity.java b/app/src/main/java/com/saulmm/material/activities/ColorActivity.java
new file mode 100644
index 0000000..f7a1ec4
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/activities/ColorActivity.java
@@ -0,0 +1,162 @@
+package com.saulmm.material.activities;
+
+import android.animation.Animator;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.Switch;
+
+import com.saulmm.material.R;
+import com.saulmm.material.utils.GUIUtils;
+
+public class ColorActivity extends Activity {
+
+ private SharedPreferences sharedpreferences;
+ private View revealView;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+
+ super.onCreate(savedInstanceState);
+
+ // Set the saved theme
+ sharedpreferences = getSharedPreferences("test", Context.MODE_PRIVATE);
+ setTheme(sharedpreferences.getInt("theme", R.style.AppTheme));
+
+ setContentView(R.layout.activity_color);
+
+ // Views
+ Switch themeSwitch = (Switch) findViewById(R.id.theme_switch);
+ themeSwitch.setChecked(sharedpreferences.getBoolean(themeSwitch.getId()+"", false));
+ themeSwitch.setOnCheckedChangeListener(checkedListener);
+
+ CheckBox themeCheck = (CheckBox) findViewById(R.id.theme_check);
+ themeCheck.setChecked(sharedpreferences.getBoolean(themeCheck.getId()+"", false));
+ themeCheck.setOnCheckedChangeListener(checkedListener);
+
+ revealView = findViewById(R.id.reveal_view);
+
+ // Show the unReveal effect
+ final int cx = sharedpreferences.getInt("x", 0);
+ final int cy = sharedpreferences.getInt("y", 0);
+
+ startHideRevealEffect(cx, cy);
+ }
+
+ private void startHideRevealEffect(final int cx, final int cy) {
+
+ if (cx != 0 && cy != 0) {
+ // Show the unReveal effect when the view is attached to the window
+ revealView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+
+ // Get the accent color
+ TypedValue outValue = new TypedValue();
+ getTheme().resolveAttribute(android.R.attr.colorPrimary, outValue, true);
+ revealView.setBackgroundColor(outValue.data);
+
+ GUIUtils.hideRevealEffect(revealView, cx, cy, 1920);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {}
+ });
+ }
+ }
+
+
+ private void hideNavigationStatus() {
+
+ View decorView = getWindow().getDecorView();
+
+ int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ decorView.setSystemUiVisibility(uiOptions);
+ }
+
+
+ Animator.AnimatorListener revealAnimationListener = new Animator.AnimatorListener() {
+
+ @Override
+ public void onAnimationStart(Animator animation) {}
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+
+ Intent i = new Intent(ColorActivity.this, ColorActivity.class);
+ i.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ startActivity(i);
+ overridePendingTransition(0, 0);
+ finish();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {}
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {}
+ };
+
+
+ public void view(View view) {
+
+ int selectedTheme = 0;
+ int primaryColor = 0;
+
+ switch (view.getId()) {
+ case R.id.circle1:
+ selectedTheme = R.style.theme1;
+ primaryColor = getResources().getColor(R.color.color_set_1_primary);
+ break;
+
+ case R.id.circle2:
+ selectedTheme = R.style.theme2;
+ primaryColor = getResources().getColor(R.color.color_set_2_primary);
+ break;
+
+ case R.id.circle3:
+ selectedTheme = R.style.theme3;
+ primaryColor = getResources().getColor(R.color.color_set_3_primary);
+ break;
+
+ case R.id.circle4:
+ selectedTheme = R.style.theme4;
+ primaryColor = getResources().getColor(R.color.color_set_4_primary);
+ break;
+ }
+
+ int [] location = new int[2];
+ revealView.setBackgroundColor(primaryColor);
+ view.getLocationOnScreen(location);
+
+ int cx = (location[0] + (view.getWidth() / 2));
+ int cy = location[1] + (GUIUtils.getStatusBarHeight(this) / 2);
+
+ SharedPreferences.Editor ed = sharedpreferences.edit();
+ ed.putInt("x", cx);
+ ed.putInt("y", cy);
+ ed.putInt("theme", selectedTheme);
+ ed.apply();
+
+ hideNavigationStatus();
+ GUIUtils.showRevealEffect(revealView, cx, cy, revealAnimationListener);
+ }
+
+
+ CompoundButton.OnCheckedChangeListener checkedListener = new CompoundButton.OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ SharedPreferences.Editor ed = sharedpreferences.edit();
+ ed.putInt("theme", (isChecked) ? R.style.Base_Theme_AppCompat : R.style.Base_Theme_AppCompat_Light);
+ ed.putBoolean(buttonView.getId()+"", isChecked);
+ ed.apply();
+ }
+ };
+}
diff --git a/app/src/main/java/com/saulmm/material/activities/DialerSampleActivity.java b/app/src/main/java/com/saulmm/material/activities/DialerSampleActivity.java
new file mode 100644
index 0000000..527a101
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/activities/DialerSampleActivity.java
@@ -0,0 +1,47 @@
+
+
+package com.saulmm.material.activities;
+
+import android.graphics.Point;
+import android.os.Bundle;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Display;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.ArrayAdapter;
+import android.widget.FrameLayout;
+import android.widget.GridView;
+import android.widget.ImageButton;
+
+import com.saulmm.material.R;
+import com.saulmm.material.utils.GUIUtils;
+import com.saulmm.material.views.adapters.SamplePagerAdapter;
+import com.saulmm.material.views.widgets.SlidingTabLayout;
+
+public class DialerSampleActivity extends ActionBarActivity {
+
+ private int screenWidth;
+ private ImageButton fabButton;
+ private FrameLayout dialerKeysContainer;
+ private float absolutefabPosition;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_dialer);
+
+ configureToolbar();
+ }
+
+ private void configureToolbar() {
+
+ Toolbar mainToolbar = (Toolbar) findViewById(R.id.activity_dialer_toolbar);
+ mainToolbar.setTitleTextColor(getResources().getColor(R.color.theme_dialer_accent));
+ setSupportActionBar(mainToolbar);
+ getSupportActionBar().setTitle("Dialer");
+ }
+}
diff --git a/app/src/main/java/com/saulmm/material/activities/ElevationSampleActivity.java b/app/src/main/java/com/saulmm/material/activities/ElevationSampleActivity.java
new file mode 100644
index 0000000..a7ea4db
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/activities/ElevationSampleActivity.java
@@ -0,0 +1,17 @@
+package com.saulmm.material.activities;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.saulmm.material.R;
+
+public class ElevationSampleActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_elevation_sample);
+ }
+}
diff --git a/app/src/main/java/com/saulmm/material/activities/SlidingActivity.java b/app/src/main/java/com/saulmm/material/activities/SlidingActivity.java
new file mode 100644
index 0000000..98f92c5
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/activities/SlidingActivity.java
@@ -0,0 +1,114 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.saulmm.material.activities;
+
+import android.app.FragmentTransaction;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.ActionBarDrawerToggle;
+import android.support.v7.widget.Toolbar;
+import android.view.Gravity;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.saulmm.material.R;
+import com.saulmm.material.fragments.SlidingTabFragment;
+
+public class SlidingActivity extends ActionBarActivity {
+
+ private DrawerLayout mDrawerLayout;
+ private ActionBarDrawerToggle mDrawerToggle;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_sliding);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ SlidingTabFragment fragment = new SlidingTabFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+
+ configureToolbar();
+ configureDrawer();
+ }
+
+ private void configureToolbar() {
+ Toolbar mainToolbar = (Toolbar) findViewById(R.id.activity_transition_header);
+ setSupportActionBar(mainToolbar);
+ getSupportActionBar().setTitle("Sliding");
+
+ mainToolbar.setNavigationOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+
+ if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
+ mDrawerLayout.closeDrawer(Gravity.START);
+
+ } else {
+ mDrawerLayout.openDrawer(Gravity.START);
+ }
+ }
+ });
+ }
+
+ private void configureDrawer() {
+ // Configure drawer
+ mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+
+ mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
+ R.string.drawer_open,
+ R.string.drawer_closed) {
+
+ public void onDrawerClosed(View view) {
+ supportInvalidateOptionsMenu();
+ }
+
+ public void onDrawerOpened(View drawerView) {
+ supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
+ }
+ };
+
+ mDrawerLayout.setDrawerListener(mDrawerToggle);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+
+ if (mDrawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ mDrawerToggle.syncState();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mDrawerToggle.onConfigurationChanged(newConfig);
+ }
+}
diff --git a/app/src/main/java/com/saulmm/material/activities/TransitionFirstActivity.java b/app/src/main/java/com/saulmm/material/activities/TransitionFirstActivity.java
new file mode 100644
index 0000000..23e359b
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/activities/TransitionFirstActivity.java
@@ -0,0 +1,45 @@
+package com.saulmm.material.activities;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.transition.Slide;
+import android.util.Pair;
+import android.view.Gravity;
+import android.view.View;
+
+import com.saulmm.material.R;
+
+public class TransitionFirstActivity extends Activity {
+
+ private View mFabButton;
+ private View mHeader;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_transition_first);
+
+ mFabButton = findViewById(R.id.fab_button);
+ mHeader = findViewById(R.id.activity_transition_header);
+
+ Slide slideExitTransition = new Slide(Gravity.BOTTOM);
+ slideExitTransition.excludeTarget(android.R.id.navigationBarBackground, true);
+ slideExitTransition.excludeTarget(android.R.id.statusBarBackground, true);
+ slideExitTransition.excludeTarget(R.id.activity_transition_header, true);
+ getWindow().setExitTransition(slideExitTransition);
+ }
+
+ public void onFabPressed(View view) {
+
+ Intent i = new Intent (TransitionFirstActivity.this,
+ TransitionSecondActivity.class);
+
+ ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(
+ TransitionFirstActivity.this,Pair.create(mFabButton, "fab"), Pair.create(mHeader, "holder1"));
+
+ startActivity(i, transitionActivityOptions.toBundle());
+ }
+}
diff --git a/app/src/main/java/com/saulmm/material/activities/TransitionSecondActivity.java b/app/src/main/java/com/saulmm/material/activities/TransitionSecondActivity.java
new file mode 100644
index 0000000..376c26c
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/activities/TransitionSecondActivity.java
@@ -0,0 +1,75 @@
+package com.saulmm.material.activities;
+
+import android.animation.Animator;
+import android.app.Activity;
+import android.os.Bundle;
+import android.transition.Slide;
+import android.transition.Transition;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+import android.widget.LinearLayout;
+
+import com.saulmm.material.R;
+import com.saulmm.material.utils.AnimatorAdapter;
+import com.saulmm.material.utils.TransitionAdapter;
+
+public class TransitionSecondActivity extends Activity {
+
+ private static final int SCALE_DELAY = 30;
+ private LinearLayout rowContainer;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_transition_second);
+
+ rowContainer = (LinearLayout) findViewById(R.id.row_container2);
+
+ Slide slideExitTransition = new Slide(Gravity.BOTTOM);
+ slideExitTransition.excludeTarget(android.R.id.navigationBarBackground, true);
+ slideExitTransition.excludeTarget(android.R.id.statusBarBackground, true);
+
+
+ getWindow().getEnterTransition().addListener(new TransitionAdapter() {
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+
+ super.onTransitionEnd(transition);
+
+ getWindow().getEnterTransition().removeListener(this);
+
+ for (int i = 0; i < rowContainer.getChildCount(); i++) {
+
+ View rowView = rowContainer.getChildAt(i);
+ rowView.animate().setStartDelay(i * SCALE_DELAY)
+ .scaleX(1).scaleY(1);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onBackPressed() {
+
+ for (int i = 0; i < rowContainer.getChildCount(); i++) {
+
+ View rowView = rowContainer.getChildAt(i);
+
+ ViewPropertyAnimator propertyAnimator = rowView.animate()
+ .setStartDelay(i * SCALE_DELAY)
+ .scaleX(0).scaleY(0)
+ .setListener(new AnimatorAdapter() {
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+
+ super.onAnimationEnd(animation);
+ finishAfterTransition();
+ }
+ });
+ }
+ }
+}
diff --git a/app/src/main/java/com/saulmm/material/fragments/NavigationFragment.java b/app/src/main/java/com/saulmm/material/fragments/NavigationFragment.java
new file mode 100644
index 0000000..2738c3f
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/fragments/NavigationFragment.java
@@ -0,0 +1,19 @@
+package com.saulmm.material.fragments;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.saulmm.material.R;
+
+
+public class NavigationFragment extends Fragment {
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ return inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/saulmm/material/fragments/SamplePageFragment.java b/app/src/main/java/com/saulmm/material/fragments/SamplePageFragment.java
new file mode 100644
index 0000000..5bc38e2
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/fragments/SamplePageFragment.java
@@ -0,0 +1,22 @@
+package com.saulmm.material.fragments;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.saulmm.material.R;
+
+public class SamplePageFragment extends Fragment {
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ View rootView = inflater.inflate(R.layout.fragment_dialer_sample_page, container);
+
+ return rootView;
+ }
+}
diff --git a/app/src/main/java/com/saulmm/material/fragments/SlidingTabFragment.java b/app/src/main/java/com/saulmm/material/fragments/SlidingTabFragment.java
new file mode 100644
index 0000000..b50dd02
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/fragments/SlidingTabFragment.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.saulmm.material.fragments;
+
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.saulmm.material.R;
+import com.saulmm.material.views.adapters.SamplePagerAdapter;
+import com.saulmm.material.views.widgets.SlidingTabLayout;
+
+
+public class SlidingTabFragment extends Fragment {
+
+ static final String LOG_TAG = "SlidingTabsBasicFragment";
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ return inflater.inflate(R.layout.fragment_dialer_sliding, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+
+ ViewPager mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
+ mViewPager.setAdapter(new SamplePagerAdapter(getActivity()));
+
+ SlidingTabLayout mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
+ mSlidingTabLayout.setViewPager(mViewPager);
+ }
+}
diff --git a/app/src/main/java/com/saulmm/material/utils/AnimatorAdapter.java b/app/src/main/java/com/saulmm/material/utils/AnimatorAdapter.java
new file mode 100644
index 0000000..4de2736
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/utils/AnimatorAdapter.java
@@ -0,0 +1,25 @@
+package com.saulmm.material.utils;
+
+import android.animation.Animator;
+
+public class AnimatorAdapter implements Animator.AnimatorListener {
+ @Override
+ public void onAnimationStart(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+}
diff --git a/app/src/main/java/com/saulmm/material/utils/GUIUtils.java b/app/src/main/java/com/saulmm/material/utils/GUIUtils.java
new file mode 100644
index 0000000..4034769
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/utils/GUIUtils.java
@@ -0,0 +1,104 @@
+package com.saulmm.material.utils;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.graphics.Outline;
+import android.transition.Fade;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewPropertyAnimator;
+import android.view.Window;
+import android.view.animation.PathInterpolator;
+
+import com.saulmm.material.R;
+
+public class GUIUtils {
+
+ public static final int SCALE_FACTOR = 30;
+
+ public static void configureWindowEnterExitExplodeTransition(Window w) {
+
+ Fade ex = new Fade();
+ ex.setInterpolator(new PathInterpolator(0.4f, 0, 1, 1));
+ ex.setDuration(5000);
+ w.setExitTransition(ex);
+ w.setEnterTransition(ex);
+ }
+
+ public static void configureFab (View fabButton) {
+
+ int fabSize = fabButton.getContext().getResources()
+ .getDimensionPixelSize(R.dimen.fab_size);
+ Outline fabOutLine = new Outline();
+ fabOutLine.setOval(0, 0, fabSize, fabSize);
+ }
+
+ public static int getStatusBarHeight(Context c) {
+
+ int result = 0;
+ int resourceId = c.getResources().getIdentifier("status_bar_height", "dimen", "android");
+ if (resourceId > 0) {
+ result = c.getResources().getDimensionPixelSize(resourceId);
+ }
+ return result;
+ }
+
+
+ public static void hideRevealEffect (final View v, int centerX, int centerY, int initialRadius) {
+
+ v.setVisibility(View.VISIBLE);
+
+ // create the animation (the final radius is zero)
+ Animator anim = ViewAnimationUtils.createCircularReveal(
+ v, centerX, centerY, initialRadius, 0);
+
+ anim.setDuration(350);
+
+ // make the view invisible when the animation is done
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ v.setVisibility(View.INVISIBLE);
+ }
+ });
+
+ anim.start();
+ }
+
+ public static void showRevealEffect(final View v, int centerX, int centerY, Animator.AnimatorListener lis) {
+
+ v.setVisibility(View.VISIBLE);
+
+ int height = v.getHeight();
+
+ Animator anim = ViewAnimationUtils.createCircularReveal(
+ v, centerX, centerY, 0, height);
+
+ anim.setDuration(350);
+
+ anim.addListener(lis);
+ anim.start();
+ }
+
+
+
+ public static void hideViewByScale(View view) {
+
+ ViewPropertyAnimator propertyAnimator = view.animate().setStartDelay(SCALE_FACTOR)
+ .scaleX(0).scaleY(0);
+
+ propertyAnimator.start();
+ }
+
+ public static void showViewByScale(View view) {
+
+ ViewPropertyAnimator propertyAnimator = view.animate().setStartDelay(SCALE_FACTOR)
+ .scaleX(1).scaleY(1);
+
+ propertyAnimator.start();
+ }
+
+
+}
diff --git a/app/src/main/java/com/saulmm/material/utils/TransitionAdapter.java b/app/src/main/java/com/saulmm/material/utils/TransitionAdapter.java
new file mode 100644
index 0000000..1297bb8
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/utils/TransitionAdapter.java
@@ -0,0 +1,31 @@
+package com.saulmm.material.utils;
+
+import android.transition.Transition;
+
+public class TransitionAdapter implements Transition.TransitionListener {
+
+ @Override
+ public void onTransitionStart(Transition transition) {
+
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+
+ }
+}
diff --git a/app/src/main/java/com/saulmm/material/views/adapters/SamplePagerAdapter.java b/app/src/main/java/com/saulmm/material/views/adapters/SamplePagerAdapter.java
new file mode 100644
index 0000000..e46a832
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/views/adapters/SamplePagerAdapter.java
@@ -0,0 +1,53 @@
+package com.saulmm.material.views.adapters;
+
+import android.content.Context;
+import android.support.v4.view.PagerAdapter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.saulmm.material.R;
+
+@SuppressWarnings("FieldCanBeLocal")
+public class SamplePagerAdapter extends PagerAdapter {
+
+ private final String [] TITLES = {"SPEED DIAL", "RECENTS", "CONTACTS"};
+ private final int FRAGMENT_COUNT = 3;
+ private Context context;
+
+ public SamplePagerAdapter(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ public int getCount() {
+ return FRAGMENT_COUNT;
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object o) {
+ return o == view;
+ }
+
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return TITLES[position];
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+
+ View view = LayoutInflater.from(context).inflate(
+ R.layout.fragment_dialer_sample_page,
+ container, false);
+
+ container.addView(view);
+ return view;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ container.removeView((View) object);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/saulmm/material/views/widgets/SlidingTabLayout.java b/app/src/main/java/com/saulmm/material/views/widgets/SlidingTabLayout.java
new file mode 100644
index 0000000..dbf48ad
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/views/widgets/SlidingTabLayout.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.saulmm.material.views.widgets;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+import com.saulmm.material.R;
+
+import java.util.ArrayList;
+
+/**
+ * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
+ * the user's scroll progress.
+ *
+ * To use the component, simply add it to your view hierarchy. Then in your
+ * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
+ * {@link #setViewPager(android.support.v4.view.ViewPager)} providing it the ViewPager this layout is being used for.
+ *
+ * The colors can be customized in two ways. The first and simplest is to provide an array of colors
+ * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
+ * alternative is via the {@link SlidingTabLayout.TabColorizer} interface which provides you complete control over
+ * which color is used for any individual position.
+ *
+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
+ * providing the layout ID of your custom layout.
+ */
+public class SlidingTabLayout extends HorizontalScrollView {
+
+ /**
+ * Allows complete control over the colors drawn in the tab layout. Set with
+ * {@link #setCustomTabColorizer(SlidingTabLayout.TabColorizer)}.
+ */
+ public interface TabColorizer {
+
+ /**
+ * @return return the color of the indicator used when {@code position} is selected.
+ */
+ int getIndicatorColor(int position);
+
+ /**
+ * @return return the color of the divider drawn to the right of {@code position}.
+ */
+ int getDividerColor(int position);
+
+ }
+
+ private static final int TITLE_OFFSET_DIPS = 24;
+ private static final int TAB_VIEW_PADDING_DIPS = 16;
+ private static final int TAB_VIEW_TEXT_SIZE_SP = 14;
+
+ private int mTitleOffset;
+
+ private int mTabViewLayoutId;
+ private int mTabViewTextViewId;
+
+ private ViewPager mViewPager;
+ private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
+
+ private ArrayList pagerListeners = new ArrayList();
+
+ private final SlidingTabStrip mTabStrip;
+
+ public SlidingTabLayout(Context context) {
+ this(context, null);
+ }
+
+ public SlidingTabLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // Disable the Scroll Bar
+ setHorizontalScrollBarEnabled(false);
+ // Make sure that the Tab Strips fills this View
+ setFillViewport(true);
+
+ mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
+
+ mTabStrip = new SlidingTabStrip(context);
+ addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+
+ pagerListeners.add(new InternalViewPagerListener());
+ }
+
+ public void addPagerListener (ViewPager.OnPageChangeListener listener) {
+ pagerListeners.add(listener);
+ }
+
+ /**
+ * Set the custom {@link SlidingTabLayout.TabColorizer} to be used.
+ *
+ * If you only require simple custmisation then you can use
+ * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
+ * similar effects.
+ */
+ public void setCustomTabColorizer(TabColorizer tabColorizer) {
+ mTabStrip.setCustomTabColorizer(tabColorizer);
+ }
+
+ /**
+ * Sets the colors to be used for indicating the selected tab. These colors are treated as a
+ * circular array. Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setSelectedIndicatorColors(int... colors) {
+ mTabStrip.setSelectedIndicatorColors(colors);
+ }
+
+ /**
+ * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
+ * Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setDividerColors(int... colors) {
+ mTabStrip.setDividerColors(colors);
+ }
+
+ /**
+ * Set the {@link android.support.v4.view.ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
+ * required to set any {@link android.support.v4.view.ViewPager.OnPageChangeListener} through this method. This is so
+ * that the layout can update it's scroll position correctly.
+ *
+ * @see android.support.v4.view.ViewPager#setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener)
+ */
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+ mViewPagerPageChangeListener = listener;
+ }
+
+ /**
+ * Set the custom layout to be inflated for the tab views.
+ *
+ * @param layoutResId Layout id to be inflated
+ * @param textViewId id of the {@link android.widget.TextView} in the inflated view
+ */
+ public void setCustomTabView(int layoutResId, int textViewId) {
+ mTabViewLayoutId = layoutResId;
+ mTabViewTextViewId = textViewId;
+ }
+
+ /**
+ * Sets the associated view pager. Note that the assumption here is that the pager content
+ * (number of tabs and tab titles) does not change after this call has been made.
+ */
+ public void setViewPager(ViewPager viewPager) {
+ mTabStrip.removeAllViews();
+
+ mViewPager = viewPager;
+ if (viewPager != null) {
+ viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int i, float v, int i2) {
+
+ for (ViewPager.OnPageChangeListener pagerListener : pagerListeners) {
+ pagerListener.onPageScrolled(i, v, i2);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int i) {
+ for (ViewPager.OnPageChangeListener pagerListener : pagerListeners) {
+ pagerListener.onPageSelected(i);
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int i) {
+ for (ViewPager.OnPageChangeListener pagerListener : pagerListeners) {
+ pagerListener.onPageScrollStateChanged(i);
+ }
+ }
+ });
+ populateTabStrip();
+ }
+ }
+
+ /**
+ * Create a default view to be used for tabs. This is called if a custom tab view is not set via
+ * {@link #setCustomTabView(int, int)}.
+ */
+ protected TextView createDefaultTabView(Context context) {
+ TextView textView = new TextView(context);
+ textView.setGravity(Gravity.CENTER);
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
+ textView.setTypeface(Typeface.DEFAULT_BOLD);
+ textView.setTextAppearance(context, R.style.SlidingTextViewStyle);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ // If we're running on Honeycomb or newer, then we can use the Theme's
+ // selectableItemBackground to ensure that the View has a pressed state
+ TypedValue outValue = new TypedValue();
+ getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
+ outValue, true);
+ textView.setBackgroundResource(outValue.resourceId);
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
+ textView.setAllCaps(true);
+ }
+
+ int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
+ textView.setPadding(padding, padding, padding, padding);
+
+ return textView;
+ }
+
+ private void populateTabStrip() {
+ final PagerAdapter adapter = mViewPager.getAdapter();
+ final OnClickListener tabClickListener = new TabClickListener();
+
+ for (int i = 0; i < adapter.getCount(); i++) {
+ View tabView = null;
+ TextView tabTitleView = null;
+
+ if (mTabViewLayoutId != 0) {
+ // If there is a custom tab view layout id set, try and inflate it
+ tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
+ false);
+ tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
+ }
+
+ if (tabView == null) {
+ tabView = createDefaultTabView(getContext());
+ }
+
+ if (tabTitleView == null && TextView.class.isInstance(tabView)) {
+ tabTitleView = (TextView) tabView;
+ }
+
+ tabTitleView.setText(adapter.getPageTitle(i));
+ tabView.setOnClickListener(tabClickListener);
+
+ mTabStrip.addView(tabView);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (mViewPager != null) {
+ scrollToTab(mViewPager.getCurrentItem(), 0);
+ }
+ }
+
+ private void scrollToTab(int tabIndex, int positionOffset) {
+ final int tabStripChildCount = mTabStrip.getChildCount();
+ if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
+ return;
+ }
+
+ View selectedChild = mTabStrip.getChildAt(tabIndex);
+ if (selectedChild != null) {
+ int targetScrollX = selectedChild.getLeft() + positionOffset;
+
+ if (tabIndex > 0 || positionOffset > 0) {
+ // If we're not at the first child and are mid-scroll, make sure we obey the offset
+ targetScrollX -= mTitleOffset;
+ }
+
+ scrollTo(targetScrollX, 0);
+ }
+ }
+
+ private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
+ private int mScrollState;
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ int tabStripChildCount = mTabStrip.getChildCount();
+ if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+ return;
+ }
+
+ mTabStrip.onViewPagerPageChanged(position, positionOffset);
+
+ View selectedTitle = mTabStrip.getChildAt(position);
+ int extraOffset = (selectedTitle != null)
+ ? (int) (positionOffset * selectedTitle.getWidth())
+ : 0;
+ scrollToTab(position, extraOffset);
+
+ if (mViewPagerPageChangeListener != null) {
+ mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
+ positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ mScrollState = state;
+
+ if (mViewPagerPageChangeListener != null) {
+ mViewPagerPageChangeListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+ mTabStrip.onViewPagerPageChanged(position, 0f);
+ scrollToTab(position, 0);
+ }
+
+ if (mViewPagerPageChangeListener != null) {
+ mViewPagerPageChangeListener.onPageSelected(position);
+ }
+ }
+
+ }
+
+ private class TabClickListener implements OnClickListener {
+ @Override
+ public void onClick(View v) {
+ for (int i = 0; i < mTabStrip.getChildCount(); i++) {
+ if (v == mTabStrip.getChildAt(i)) {
+ mViewPager.setCurrentItem(i);
+ return;
+ }
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/saulmm/material/views/widgets/SlidingTabStrip.java b/app/src/main/java/com/saulmm/material/views/widgets/SlidingTabStrip.java
new file mode 100644
index 0000000..50084af
--- /dev/null
+++ b/app/src/main/java/com/saulmm/material/views/widgets/SlidingTabStrip.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.saulmm.material.views.widgets;
+
+import android.R;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+class SlidingTabStrip extends LinearLayout {
+
+ private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
+ private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
+ private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 3;
+ private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
+
+ private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
+ private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
+ private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
+
+ private final int mBottomBorderThickness;
+ private final Paint mBottomBorderPaint;
+
+ private final int mSelectedIndicatorThickness;
+ private final Paint mSelectedIndicatorPaint;
+
+ private final int mDefaultBottomBorderColor;
+
+ private final Paint mDividerPaint;
+ private final float mDividerHeight;
+
+ private int mSelectedPosition;
+ private float mSelectionOffset;
+
+ private SlidingTabLayout.TabColorizer mCustomTabColorizer;
+ private final SimpleTabColorizer mDefaultTabColorizer;
+
+ SlidingTabStrip(Context context) {
+ this(context, null);
+ }
+
+ SlidingTabStrip(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setWillNotDraw(false);
+
+ final float density = getResources().getDisplayMetrics().density;
+
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
+ final int themeForegroundColor = outValue.data;
+
+ TypedValue backgroundValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.colorPrimary, outValue, true);
+ final int themeBackground = outValue.data;
+
+ TypedValue accentValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.colorAccent, outValue, true);
+ final int accentColor = outValue.data;
+
+ mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
+ DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
+
+ mDefaultTabColorizer = new SimpleTabColorizer();
+ mDefaultTabColorizer.setIndicatorColors(accentColor);
+ mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor,
+ DEFAULT_DIVIDER_COLOR_ALPHA));
+
+ mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
+ mBottomBorderPaint = new Paint();
+ mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
+
+ mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
+ mSelectedIndicatorPaint = new Paint();
+
+ mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
+ mDividerPaint = new Paint();
+ mDividerPaint.setStrokeWidth((int) (0));
+
+ setBackgroundColor(themeBackground);
+ }
+
+ void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
+ mCustomTabColorizer = customTabColorizer;
+ invalidate();
+ }
+
+ void setSelectedIndicatorColors(int... colors) {
+ // Make sure that the custom colorizer is removed
+ mCustomTabColorizer = null;
+ mDefaultTabColorizer.setIndicatorColors(colors);
+ invalidate();
+ }
+
+ void setDividerColors(int... colors) {
+ // Make sure that the custom colorizer is removed
+ mCustomTabColorizer = null;
+ mDefaultTabColorizer.setDividerColors(colors);
+ invalidate();
+ }
+
+ void onViewPagerPageChanged(int position, float positionOffset) {
+ mSelectedPosition = position;
+ mSelectionOffset = positionOffset;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ final int height = getHeight();
+ final int childCount = getChildCount();
+ final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
+ final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
+ ? mCustomTabColorizer
+ : mDefaultTabColorizer;
+
+ // Thick colored underline below the current selection
+ if (childCount > 0) {
+ View selectedTitle = getChildAt(mSelectedPosition);
+ int left = selectedTitle.getLeft();
+ int right = selectedTitle.getRight();
+ int color = tabColorizer.getIndicatorColor(mSelectedPosition);
+
+ if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
+ int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
+ if (color != nextColor) {
+ color = blendColors(nextColor, color, mSelectionOffset);
+ }
+
+ // Draw the selection partway between the tabs
+ View nextTitle = getChildAt(mSelectedPosition + 1);
+ left = (int) (mSelectionOffset * nextTitle.getLeft() +
+ (1.0f - mSelectionOffset) * left);
+ right = (int) (mSelectionOffset * nextTitle.getRight() +
+ (1.0f - mSelectionOffset) * right);
+ }
+
+ mSelectedIndicatorPaint.setColor(color);
+
+ canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
+ height, mSelectedIndicatorPaint);
+ }
+
+ // Thin underline along the entire bottom edge
+ canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
+
+ // Vertical separators between the titles
+ int separatorTop = (height - dividerHeightPx) / 2;
+ for (int i = 0; i < childCount - 1; i++) {
+ View child = getChildAt(i);
+ mDividerPaint.setColor(tabColorizer.getDividerColor(i));
+ canvas.drawLine(child.getRight(), separatorTop, child.getRight(),
+ separatorTop + dividerHeightPx, mDividerPaint);
+ }
+ }
+
+ /**
+ * Set the alpha value of the {@code color} to be the given {@code alpha} value.
+ */
+ private static int setColorAlpha(int color, byte alpha) {
+ return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
+ }
+
+ /**
+ * Blend {@code color1} and {@code color2} using the given ratio.
+ *
+ * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
+ * 0.0 will return {@code color2}.
+ */
+ private static int blendColors(int color1, int color2, float ratio) {
+ final float inverseRation = 1f - ratio;
+ float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
+ float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
+ float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
+ return Color.rgb((int) r, (int) g, (int) b);
+ }
+
+ private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
+ private int[] mIndicatorColors;
+ private int[] mDividerColors;
+
+ @Override
+ public final int getIndicatorColor(int position) {
+ return mIndicatorColors[position % mIndicatorColors.length];
+ }
+
+ @Override
+ public final int getDividerColor(int position) {
+ return mDividerColors[position % mDividerColors.length];
+ }
+
+ void setIndicatorColors(int... colors) {
+ mIndicatorColors = colors;
+ }
+
+ void setDividerColors(int... colors) {
+ mDividerColors = colors;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/anim/translate_down_off.xml b/app/src/main/res/anim/translate_down_off.xml
new file mode 100644
index 0000000..79302d0
--- /dev/null
+++ b/app/src/main/res/anim/translate_down_off.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/anim/translate_down_on.xml b/app/src/main/res/anim/translate_down_on.xml
new file mode 100644
index 0000000..b534991
--- /dev/null
+++ b/app/src/main/res/anim/translate_down_on.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..236bff5
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_drawer.png b/app/src/main/res/drawable-hdpi/ic_drawer.png
new file mode 100644
index 0000000..c59f601
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_drawer.png differ
diff --git a/app/src/main/res/drawable-mdpi/drawer_shadow.9.png b/app/src/main/res/drawable-mdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..ffe3a28
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/drawer_shadow.9.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_drawer.png b/app/src/main/res/drawable-mdpi/ic_drawer.png
new file mode 100644
index 0000000..1ed2c56
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_drawer.png differ
diff --git a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..fabe9d9
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer.png b/app/src/main/res/drawable-xhdpi/ic_drawer.png
new file mode 100644
index 0000000..a5fa74d
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_drawer.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..b91e9d7
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_drawer.png b/app/src/main/res/drawable-xxhdpi/ic_drawer.png
new file mode 100644
index 0000000..9c4685d
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_drawer.png differ
diff --git a/app/src/main/res/drawable/color1.xml b/app/src/main/res/drawable/color1.xml
new file mode 100644
index 0000000..b336be9
--- /dev/null
+++ b/app/src/main/res/drawable/color1.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/color2.xml b/app/src/main/res/drawable/color2.xml
new file mode 100644
index 0000000..12e117e
--- /dev/null
+++ b/app/src/main/res/drawable/color2.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/color3.xml b/app/src/main/res/drawable/color3.xml
new file mode 100644
index 0000000..c0cf05c
--- /dev/null
+++ b/app/src/main/res/drawable/color3.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/color4.xml b/app/src/main/res/drawable/color4.xml
new file mode 100644
index 0000000..445b2ca
--- /dev/null
+++ b/app/src/main/res/drawable/color4.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ripple_dialer_call.xml b/app/src/main/res/drawable/ripple_dialer_call.xml
new file mode 100644
index 0000000..87d6c96
--- /dev/null
+++ b/app/src/main/res/drawable/ripple_dialer_call.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ripple_dialer_idle.xml b/app/src/main/res/drawable/ripple_dialer_idle.xml
new file mode 100644
index 0000000..ead7fa8
--- /dev/null
+++ b/app/src/main/res/drawable/ripple_dialer_idle.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/translation_selector.xml b/app/src/main/res/drawable/translation_selector.xml
new file mode 100644
index 0000000..dc4a668
--- /dev/null
+++ b/app/src/main/res/drawable/translation_selector.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_color.xml b/app/src/main/res/layout/activity_color.xml
new file mode 100644
index 0000000..78816d1
--- /dev/null
+++ b/app/src/main/res/layout/activity_color.xml
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_dialer.xml b/app/src/main/res/layout/activity_dialer.xml
new file mode 100755
index 0000000..e595ce6
--- /dev/null
+++ b/app/src/main/res/layout/activity_dialer.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_elevation_sample.xml b/app/src/main/res/layout/activity_elevation_sample.xml
new file mode 100644
index 0000000..6b9e48f
--- /dev/null
+++ b/app/src/main/res/layout/activity_elevation_sample.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_my.xml b/app/src/main/res/layout/activity_my.xml
deleted file mode 100644
index e0a627d..0000000
--- a/app/src/main/res/layout/activity_my.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_my2.xml b/app/src/main/res/layout/activity_my2.xml
deleted file mode 100644
index 3059b30..0000000
--- a/app/src/main/res/layout/activity_my2.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_my_activity2.xml b/app/src/main/res/layout/activity_my_activity2.xml
deleted file mode 100644
index 8b01e38..0000000
--- a/app/src/main/res/layout/activity_my_activity2.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_sliding.xml b/app/src/main/res/layout/activity_sliding.xml
new file mode 100755
index 0000000..32abd55
--- /dev/null
+++ b/app/src/main/res/layout/activity_sliding.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_transition_first.xml b/app/src/main/res/layout/activity_transition_first.xml
new file mode 100644
index 0000000..82083ee
--- /dev/null
+++ b/app/src/main/res/layout/activity_transition_first.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_transition_second.xml b/app/src/main/res/layout/activity_transition_second.xml
new file mode 100644
index 0000000..fa8ab6a
--- /dev/null
+++ b/app/src/main/res/layout/activity_transition_second.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_dialer_sample_page.xml b/app/src/main/res/layout/fragment_dialer_sample_page.xml
new file mode 100644
index 0000000..238367c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_dialer_sample_page.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_dialer_sliding.xml b/app/src/main/res/layout/fragment_dialer_sliding.xml
new file mode 100644
index 0000000..e38448a
--- /dev/null
+++ b/app/src/main/res/layout/fragment_dialer_sliding.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_navigation_drawer.xml b/app/src/main/res/layout/fragment_navigation_drawer.xml
new file mode 100644
index 0000000..cd17273
--- /dev/null
+++ b/app/src/main/res/layout/fragment_navigation_drawer.xml
@@ -0,0 +1,8 @@
+
diff --git a/app/src/main/res/layout/list_item_dialer.xml b/app/src/main/res/layout/list_item_dialer.xml
new file mode 100644
index 0000000..bcf13aa
--- /dev/null
+++ b/app/src/main/res/layout/list_item_dialer.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/view_circle.xml b/app/src/main/res/layout/view_circle.xml
new file mode 100644
index 0000000..26b0e02
--- /dev/null
+++ b/app/src/main/res/layout/view_circle.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_fab_button.xml b/app/src/main/res/layout/view_fab_button.xml
index cdabffa..7b21d56 100644
--- a/app/src/main/res/layout/view_fab_button.xml
+++ b/app/src/main/res/layout/view_fab_button.xml
@@ -2,16 +2,15 @@
diff --git a/app/src/main/res/layout/view_sample_row.xml b/app/src/main/res/layout/view_sample_row.xml
index b4af4fc..a1b0e5f 100644
--- a/app/src/main/res/layout/view_sample_row.xml
+++ b/app/src/main/res/layout/view_sample_row.xml
@@ -1,10 +1,11 @@
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/color.xml b/app/src/main/res/menu/color.xml
new file mode 100644
index 0000000..3428565
--- /dev/null
+++ b/app/src/main/res/menu/color.xml
@@ -0,0 +1,8 @@
+
diff --git a/app/src/main/res/menu/menu_elevation_sample.xml b/app/src/main/res/menu/menu_elevation_sample.xml
new file mode 100644
index 0000000..31e169c
--- /dev/null
+++ b/app/src/main/res/menu/menu_elevation_sample.xml
@@ -0,0 +1,8 @@
+
diff --git a/app/src/main/res/menu/my_activity2.xml b/app/src/main/res/menu/my_activity2.xml
index 7ef86c1..84b1d89 100644
--- a/app/src/main/res/menu/my_activity2.xml
+++ b/app/src/main/res/menu/my_activity2.xml
@@ -1,6 +1,6 @@
diff --git a/app/src/main/res/transition/circular_reveal.xml b/app/src/main/res/transition/circular_reveal.xml
new file mode 100644
index 0000000..b80d24b
--- /dev/null
+++ b/app/src/main/res/transition/circular_reveal.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/transition/move_resize_image.xml b/app/src/main/res/transition/move_resize_image.xml
new file mode 100644
index 0000000..e2df150
--- /dev/null
+++ b/app/src/main/res/transition/move_resize_image.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
index 5333630..3a30fbe 100644
--- a/app/src/main/res/values-v21/styles.xml
+++ b/app/src/main/res/values-v21/styles.xml
@@ -1,17 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 7af9704..409abcc 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -2,9 +2,32 @@
- #00BCD4
- #0097A7
+ #F48FB1
+ #EC407A#2A2A2A#EEFF41
+ #ff515252
+
+
+
+ #00C853
+ #0277BD
+ #0288D1
+ #FFF
+
+
+ #4fc3f7
+ #009688
+
+ #42bd41
+ #673AB7
+
+ #ffb74d
+ #E91E63
+
+ #ff8a65
+ #d500f9
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 29405a1..d4bacff 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -5,6 +5,27 @@
SettingsMyActivity2Example action
- Hello world!
+ NavDrawerActivity
+ ColorActivity
+ Open
+ Close
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ *
+ 0
+ #
+
+
+ ElevationSampleActivity
diff --git a/build.gradle b/build.gradle
index 9b8abe4..d3ff69d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:0.12.2'
+ classpath 'com.android.tools.build:gradle:1.1.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/gradle.properties b/gradle.properties
index 5d08ba7..1d3591c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,8 +1,8 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
-# Settings specified in this file will override any Gradle settings
-# configured through the IDE.
+# 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
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
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 0000000..0c71e76
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,164 @@
+#!/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
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# 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\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+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"`
+
+ # 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 0000000..8a0b282
--- /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