package agency.tango.materialintroscreen;
import android.animation.ArgbEvaluator;
import android.content.res.ColorStateList;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import agency.tango.materialintroscreen.adapter.SlidesAdapter;
import agency.tango.materialintroscreen.animations.ViewTranslationWrapper;
import agency.tango.materialintroscreen.animations.wrappers.BackButtonTranslationWrapper;
import agency.tango.materialintroscreen.animations.wrappers.NextButtonTranslationWrapper;
import agency.tango.materialintroscreen.animations.wrappers.PageIndicatorTranslationWrapper;
import agency.tango.materialintroscreen.animations.wrappers.SkipButtonTranslationWrapper;
import agency.tango.materialintroscreen.animations.wrappers.ViewPagerTranslationWrapper;
import agency.tango.materialintroscreen.listeners.IFinishListener;
import agency.tango.materialintroscreen.listeners.IPageScrolledListener;
import agency.tango.materialintroscreen.listeners.IPageSelectedListener;
import agency.tango.materialintroscreen.listeners.MessageButtonBehaviourOnPageSelected;
import agency.tango.materialintroscreen.listeners.ViewBehavioursOnPageChangeListener;
import agency.tango.materialintroscreen.listeners.clickListeners.PermissionNotGrantedClickListener;
import agency.tango.materialintroscreen.listeners.scrollListeners.ParallaxScrollListener;
import agency.tango.materialintroscreen.widgets.InkPageIndicator;
import agency.tango.materialintroscreen.widgets.OverScrollViewPager;
import agency.tango.materialintroscreen.widgets.SwipeableViewPager;
import static android.view.View.GONE;
public abstract class MaterialIntroActivity extends AppCompatActivity {
private SwipeableViewPager viewPager;
private InkPageIndicator pageIndicator;
private SlidesAdapter adapter;
private ImageButton backButton;
private ImageButton skipButton;
private ImageButton nextButton;
private CoordinatorLayout coordinatorLayout;
private Button messageButton;
private LinearLayout navigationView;
private OverScrollViewPager overScrollLayout;
private ArgbEvaluator argbEvaluator = new ArgbEvaluator();
private ViewTranslationWrapper nextButtonTranslationWrapper;
private ViewTranslationWrapper backButtonTranslationWrapper;
private ViewTranslationWrapper pageIndicatorTranslationWrapper;
private ViewTranslationWrapper viewPagerTranslationWrapper;
private ViewTranslationWrapper skipButtonTranslationWrapper;
private MessageButtonBehaviourOnPageSelected messageButtonBehaviourOnPageSelected;
private View.OnClickListener permissionNotGrantedClickListener;
private View.OnClickListener finishScreenClickListener;
private SparseArray<MessageButtonBehaviour> messageButtonBehaviours = new SparseArray<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window window = getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
setContentView(R.layout.activity_material_intro);
overScrollLayout = (OverScrollViewPager) findViewById(R.id.view_pager_slides);
viewPager = overScrollLayout.getOverScrollView();
pageIndicator = (InkPageIndicator) findViewById(R.id.indicator);
backButton = (ImageButton) findViewById(R.id.button_back);
nextButton = (ImageButton) findViewById(R.id.button_next);
skipButton = (ImageButton) findViewById(R.id.button_skip);
messageButton = (Button) findViewById(R.id.button_message);
coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinator_layout_slide);
navigationView = (LinearLayout) findViewById(R.id.navigation_view);
adapter = new SlidesAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(2);
pageIndicator.setViewPager(viewPager);
nextButtonTranslationWrapper = new NextButtonTranslationWrapper(nextButton);
initOnPageChangeListeners();
permissionNotGrantedClickListener = new PermissionNotGrantedClickListener(this, nextButtonTranslationWrapper);
finishScreenClickListener = new FinishScreenClickListener();
setBackButtonVisible();
viewPager.post(new Runnable() {
@Override
public void run() {
if (adapter.getCount() == 0) {
finish();
} else {
int currentItem = viewPager.getCurrentItem();
messageButtonBehaviourOnPageSelected.pageSelected(currentItem);
nextButtonBehaviour(currentItem, adapter.getItem(currentItem));
}
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
SlideFragment fragment = adapter.getItem(viewPager.getCurrentItem());
boolean hasPermissionToGrant = fragment.hasNeededPermissionsToGrant();
if (!hasPermissionToGrant) {
viewPager.setSwipingRightAllowed(true);
nextButtonBehaviour(viewPager.getCurrentItem(), fragment);
messageButtonBehaviourOnPageSelected.pageSelected(viewPager.getCurrentItem());
} else {
showPermissionsNotGrantedError();
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onBackPressed() {
moveBack();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
if (messageButtonBehaviours.get(viewPager.getCurrentItem()) != null) {
messageButton.performClick();
}
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
int position = viewPager.getCurrentItem();
if (adapter.isLastSlide(position) && adapter.getItem(position).canMoveFurther()) {
performFinish();
} else if (adapter.shouldLockSlide(position)) {
errorOccurred(adapter.getItem(position));
} else {
viewPager.moveToNextPage();
}
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
moveBack();
break;
default:
return super.onKeyDown(keyCode, event);
}
return super.onKeyDown(keyCode, event);
}
public void showPermissionsNotGrantedError() {
showError(getString(R.string.please_grant_permissions));
}
/**
* Add SlideFragment to IntroScreen
*
* @param slideFragment Fragment to add
*/
@SuppressWarnings("unused")
public void addSlide(SlideFragment slideFragment) {
adapter.addItem(slideFragment);
}
/**
* Add SlideFragment to IntroScreen
*
* @param slideFragment Fragment to add
* @param messageButtonBehaviour Add behaviour for message button
*/
@SuppressWarnings("unused")
public void addSlide(SlideFragment slideFragment, MessageButtonBehaviour messageButtonBehaviour) {
adapter.addItem(slideFragment);
messageButtonBehaviours.put(adapter.getLastItemPosition(), messageButtonBehaviour);
}
/**
* Set skip button instead of back button
*/
@SuppressWarnings("unused")
public void setSkipButtonVisible() {
backButton.setVisibility(GONE);
skipButton.setVisibility(View.VISIBLE);
skipButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (int position = viewPager.getCurrentItem(); position < adapter.getCount(); position++) {
if (!adapter.getItem(position).canMoveFurther()) {
viewPager.setCurrentItem(position, true);
showError(adapter.getItem(position).cantMoveFurtherErrorMessage());
return;
}
}
viewPager.setCurrentItem(adapter.getLastItemPosition(), true);
}
});
}
/**
* Set back button visible
*/
public void setBackButtonVisible() {
skipButton.setVisibility(GONE);
backButton.setVisibility(View.VISIBLE);
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewPager.setCurrentItem(viewPager.getPreviousItem(), true);
}
});
}
/**
* Hides any back button
*/
@SuppressWarnings("unused")
public void hideBackButton() {
backButton.setVisibility(View.INVISIBLE);
skipButton.setVisibility(View.GONE);
}
/**
* Get translation wrapper for next button
*
* @return ViewTranslationWrapper
*/
public ViewTranslationWrapper getNextButtonTranslationWrapper() {
return nextButtonTranslationWrapper;
}
/**
* Get translation wrapper for back button
*
* @return ViewTranslationWrapper
*/
@SuppressWarnings("unused")
public ViewTranslationWrapper getBackButtonTranslationWrapper() {
return backButtonTranslationWrapper;
}
/**
* Get translation wrapper for page indicator
*
* @return ViewTranslationWrapper
*/
@SuppressWarnings("unused")
public ViewTranslationWrapper getPageIndicatorTranslationWrapper() {
return pageIndicatorTranslationWrapper;
}
/**
* Get translation wrapper for view pager
*
* @return ViewTranslationWrapper
*/
@SuppressWarnings("unused")
public ViewTranslationWrapper getViewPagerTranslationWrapper() {
return viewPagerTranslationWrapper;
}
/**
* Get translation wrapper for skip button
*
* @return ViewTranslationWrapper
*/
@SuppressWarnings("unused")
public ViewTranslationWrapper getSkipButtonTranslationWrapper() {
return skipButtonTranslationWrapper;
}
/**
* Set if last screen should be able to exit with alpha transition
*
* @param enableAlphaExitTransition should enable alpha exit transition
*/
@SuppressWarnings("unused")
public void enableLastSlideAlphaExitTransition(boolean enableAlphaExitTransition) {
viewPager.alphaExitTransitionEnabled(enableAlphaExitTransition);
}
/**
* Show snackbar message
*
* @param message Message which will be visible to user
*/
public void showMessage(String message) {
showError(message);
}
/**
* Override to execute this method on finish intro activity
*/
public void onFinish() {
}
private void initOnPageChangeListeners() {
messageButtonBehaviourOnPageSelected = new MessageButtonBehaviourOnPageSelected(messageButton, adapter, messageButtonBehaviours);
backButtonTranslationWrapper = new BackButtonTranslationWrapper(backButton);
pageIndicatorTranslationWrapper = new PageIndicatorTranslationWrapper(pageIndicator);
viewPagerTranslationWrapper = new ViewPagerTranslationWrapper(viewPager);
skipButtonTranslationWrapper = new SkipButtonTranslationWrapper(skipButton);
overScrollLayout.registerFinishListener(new IFinishListener() {
@Override
public void doOnFinish() {
performFinish();
}
});
viewPager.addOnPageChangeListener(new ViewBehavioursOnPageChangeListener(adapter)
.registerViewTranslationWrapper(nextButtonTranslationWrapper)
.registerViewTranslationWrapper(backButtonTranslationWrapper)
.registerViewTranslationWrapper(pageIndicatorTranslationWrapper)
.registerViewTranslationWrapper(viewPagerTranslationWrapper)
.registerViewTranslationWrapper(skipButtonTranslationWrapper)
.registerOnPageScrolled(new IPageScrolledListener() {
@Override
public void pageScrolled(final int position, float offset) {
viewPager.post(new Runnable() {
@Override
public void run() {
if (adapter.getItem(position).hasNeededPermissionsToGrant() || !adapter.getItem(position).canMoveFurther()) {
viewPager.setCurrentItem(position, true);
pageIndicator.clearJoiningFractions();
}
}
});
}
})
.registerOnPageScrolled(new ColorTransitionScrollListener())
.registerOnPageScrolled(new ParallaxScrollListener(adapter))
.registerPageSelectedListener(messageButtonBehaviourOnPageSelected)
.registerPageSelectedListener(new IPageSelectedListener() {
@Override
public void pageSelected(int position) {
nextButtonBehaviour(position, adapter.getItem(position));
if (adapter.shouldFinish(position)) {
performFinish();
}
}
}));
}
@SuppressWarnings("PointlessBooleanExpression")
private void nextButtonBehaviour(final int position, final SlideFragment fragment) {
boolean hasPermissionToGrant = fragment.hasNeededPermissionsToGrant();
if (hasPermissionToGrant) {
nextButton.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_next));
nextButton.setOnClickListener(permissionNotGrantedClickListener);
} else if (adapter.isLastSlide(position)) {
nextButton.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_finish));
nextButton.setOnClickListener(finishScreenClickListener);
} else {
nextButton.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_next));
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (fragment.canMoveFurther() == false) {
errorOccurred(fragment);
} else {
viewPager.moveToNextPage();
}
}
});
}
}
private void performFinish() {
onFinish();
finish();
}
private void moveBack() {
if (viewPager.getCurrentItem() == 0) {
finish();
} else {
viewPager.setCurrentItem(viewPager.getPreviousItem(), true);
}
}
private void errorOccurred(SlideFragment slideFragment) {
nextButtonTranslationWrapper.error();
showError(slideFragment.cantMoveFurtherErrorMessage());
}
private void showError(String error) {
Snackbar.make(coordinatorLayout, error, Snackbar.LENGTH_SHORT).setCallback(new Snackbar.Callback() {
@Override
public void onDismissed(Snackbar snackbar, int event) {
navigationView.setTranslationY(0f);
super.onDismissed(snackbar, event);
}
}).show();
}
private Integer getBackgroundColor(int position, float positionOffset) {
return (Integer) argbEvaluator.evaluate(positionOffset, color(adapter.getItem(position).backgroundColor()), color(adapter.getItem(position + 1).backgroundColor()));
}
private Integer getButtonsColor(int position, float positionOffset) {
return (Integer) argbEvaluator.evaluate(positionOffset, color(adapter.getItem(position).buttonsColor()), color(adapter.getItem(position + 1).buttonsColor()));
}
private int color(@ColorRes int color) {
return ContextCompat.getColor(this, color);
}
private class ColorTransitionScrollListener implements IPageScrolledListener {
@Override
public void pageScrolled(int position, float offset) {
if (position < adapter.getCount() - 1) {
setViewsColor(position, offset);
} else if (adapter.getCount() == 1) {
viewPager.setBackgroundColor(adapter.getItem(position).backgroundColor());
messageButton.setTextColor(adapter.getItem(position).backgroundColor());
tintButtons(ColorStateList.valueOf(adapter.getItem(position).buttonsColor()));
}
}
private void setViewsColor(int position, float offset) {
int backgroundColor = getBackgroundColor(position, offset);
viewPager.setBackgroundColor(backgroundColor);
messageButton.setTextColor(backgroundColor);
int buttonsColor = getButtonsColor(position, offset);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(buttonsColor);
}
pageIndicator.setPageIndicatorColor(buttonsColor);
tintButtons(ColorStateList.valueOf(buttonsColor));
}
private void tintButtons(ColorStateList color) {
ViewCompat.setBackgroundTintList(nextButton, color);
ViewCompat.setBackgroundTintList(backButton, color);
ViewCompat.setBackgroundTintList(skipButton, color);
}
}
private class FinishScreenClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
SlideFragment slideFragment = adapter.getItem(adapter.getLastItemPosition());
if (!slideFragment.canMoveFurther()) {
errorOccurred(slideFragment);
} else {
performFinish();
}
}
}
}