package com.thebluealliance.androidclient.activities;
import com.thebluealliance.androidclient.R;
import com.thebluealliance.androidclient.TBAAndroid;
import com.thebluealliance.androidclient.Utilities;
import com.thebluealliance.androidclient.accounts.AccountController;
import com.thebluealliance.androidclient.di.components.DaggerMyTbaComponent;
import com.thebluealliance.androidclient.fragments.mytba.MyTBASettingsFragment;
import com.thebluealliance.androidclient.fragments.tasks.UpdateUserModelSettingsTaskFragment;
import com.thebluealliance.androidclient.interfaces.LoadModelSettingsCallback;
import com.thebluealliance.androidclient.interfaces.ModelSettingsCallbacks;
import com.thebluealliance.androidclient.types.ModelType;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.res.ColorStateList;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.StringRes;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import javax.inject.Inject;
/**
* Activity which hosts a FAB that opens a myTBA model settings panel.
*/
public abstract class MyTBASettingsActivity extends DatafeedActivity implements View.OnClickListener, ModelSettingsCallbacks, LoadModelSettingsCallback {
private static final String SETTINGS_PANEL_OPEN = "settings_panel_open";
private static final String SAVE_SETTINGS_TASK_FRAGMENT_TAG = "task_fragment_tag";
@ColorRes private static final int FAB_COLOR = R.color.accent;
@ColorRes private static final int FAB_COLOR_SUCCESS = R.color.green;
@ColorRes private static final int FAB_COLOR_ERROR = R.color.red;
CoordinatorLayout mCoordinatorLayout;
RelativeLayout mSettingsContainer;
FloatingActionButton mToggleSettingsPanelButton;
View mForegroundDim;
Toolbar mSettingsToolbar;
private Handler mFabHandler = new Handler();
private MyTBASettingsFragment mSettingsFragment;
private UpdateUserModelSettingsTaskFragment mSaveSettingsTaskFragment;
private boolean mIsMyTBAEnabled;
private boolean mIsSettingsPanelOpen = false;
private boolean mIsSaveEnalbed = false;
private boolean mSaveInProgress = false;
private boolean mFabVisible = false;
// Track animations so we can cancel them if needed
private AnimatorSet mFabColorAnimator;
private ValueAnimator mRunningFabAnimation;
private AnimatorSet mRunningPanelAnimation;
// In milliseconds
private static final int ANIMATION_DURATION = 500;
private static final int FAB_ANIMATION_DURATION = 250;
private static final int FAB_COLOR_ANIMATION_DURATION = 250;
private static final float UNDIMMED_ALPHA = 0.0f;
private static final float DIMMED_ALPHA = 0.7f;
private Bundle savedPreferenceState;
@Inject AccountController mAccountController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TBAAndroid application = (TBAAndroid) getApplication();
DaggerMyTbaComponent.builder()
.tBAAndroidModule(application.getModule())
.accountModule(application.getAccountModule())
.authModule(application.getAuthModule())
.applicationComponent(application.getComponent())
.build()
.inject(this);
super.setContentView(R.layout.activity_mytba_settings);
mCoordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinator);
mSettingsContainer = (RelativeLayout) findViewById(R.id.settings);
mToggleSettingsPanelButton = (FloatingActionButton) findViewById(R.id.toggle_settings_button);
mForegroundDim = findViewById(R.id.activity_foreground_dim);
mSettingsToolbar = (Toolbar) findViewById(R.id.settings_toolbar);
mToggleSettingsPanelButton.setOnClickListener(this);
mSettingsToolbar.setNavigationIcon(R.drawable.ic_close_black_24dp);
mSettingsToolbar.setTitle("Team Settings");
mSettingsToolbar.setNavigationOnClickListener(v -> onSettingsCloseButtonClick());
mSettingsToolbar.setNavigationContentDescription(R.string.close);
ViewCompat.setElevation(mSettingsToolbar, getResources().getDimension(R.dimen.toolbar_elevation));
// We check this so that we can hide the fab and prevent it from being subsequently shown
// if myTBA is not enabled
mIsMyTBAEnabled = mAccountController.isMyTbaEnabled();
mFabVisible = (mToggleSettingsPanelButton.getVisibility() == View.VISIBLE);
syncFabVisibilityWithMyTbaEnabled(false);
setupFabIconForSettingsPanelOpen(false);
if (savedInstanceState != null) {
mIsSettingsPanelOpen = savedInstanceState.getBoolean(SETTINGS_PANEL_OPEN);
if (mIsSettingsPanelOpen) {
openSettingsPanel(false);
} else {
closeSettingsPanel(false);
}
savedPreferenceState = savedInstanceState.getBundle(MyTBASettingsFragment.SAVED_STATE_BUNDLE);
}
mSaveSettingsTaskFragment = (UpdateUserModelSettingsTaskFragment) getSupportFragmentManager().findFragmentByTag(SAVE_SETTINGS_TASK_FRAGMENT_TAG);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SETTINGS_PANEL_OPEN, mIsSettingsPanelOpen);
// Only save the preference state if they've already been successfully loaded
// Also, only save them if the settings panel is open. Otherwise, clear them on rotate
if (mSettingsFragment != null && mSettingsFragment.arePreferencesLoaded() && mIsSettingsPanelOpen) {
Bundle b = new Bundle();
mSettingsFragment.writeStateToBundle(b);
outState.putBundle(MyTBASettingsFragment.SAVED_STATE_BUNDLE, b);
}
}
@Override
protected void setModelKey(String key, ModelType modelType) {
super.setModelKey(key, modelType);
// Now that we have a model key, we can create a settings fragment for the appropriate model type
mSettingsFragment = MyTBASettingsFragment.newInstance(modelKey, modelType, savedPreferenceState);
getFragmentManager().beginTransaction().replace(R.id.settings_list, mSettingsFragment).commit();
// Disable the submit settings button so we can't hit it before the content is loaded
// This prevents accidentally wiping settings (see #317)
mIsSaveEnalbed = false;
}
@Override
public void setContentView(int layoutResID) {
FrameLayout root = (FrameLayout) findViewById(R.id.activity_content);
LayoutInflater inflater = getLayoutInflater();
inflater.inflate(layoutResID, root);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.toggle_settings_button) {
if (onFabClick()) {
// A subclass handled this click for us, no need to do anything
return;
}
if (!mIsSettingsPanelOpen) {
if (!mSaveInProgress) {
openSettingsPanel(true);
}
} else {
// The user wants to save the preferences
// Always close the panel
mFabHandler.postDelayed(() -> closeSettingsPanel(true), 1);
// If saving is disabled, don't attempt to save
if (!mIsSaveEnalbed) {
return;
}
if (mSaveSettingsTaskFragment == null) {
mSaveSettingsTaskFragment = UpdateUserModelSettingsTaskFragment
.newInstance(mSettingsFragment.getSettings());
getSupportFragmentManager().beginTransaction()
.add(mSaveSettingsTaskFragment,
SAVE_SETTINGS_TASK_FRAGMENT_TAG)
.commit();
mSaveInProgress = true;
final android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
final Fragment settingsFragment = fm.findFragmentByTag(SAVE_SETTINGS_TASK_FRAGMENT_TAG);
mFabHandler.postDelayed(() -> {
if (settingsFragment != null) {
fm.beginTransaction().remove(settingsFragment).commitAllowingStateLoss();
}
mSaveSettingsTaskFragment = null;
}, 1);
}
}
}
}
/**
* Since we reuse the same FAB for both the open and close buttons, we have to toggle the icon
* displayed by the FAB. This method does that. If the panel is closed, the FAB displays a
* star; if it is open, it displays a checkmark (for the "save" action).
*
* @param panelOpen if the settings panel is open
*/
private void setupFabIconForSettingsPanelOpen(boolean panelOpen) {
mToggleSettingsPanelButton.setImageResource(panelOpen ? R.drawable.ic_check_white_24dp : R.drawable.ic_star_white_24dp);
}
/**
* Called when the user chooses to close the settings panel without saving their changes.
*/
private void onSettingsCloseButtonClick() {
closeSettingsPanel(true);
// Cancel any changes made by the user
mSettingsFragment.restoreInitialState();
}
protected void openSettingsPanel(boolean animate) {
mIsSettingsPanelOpen = true;
if (mSettingsFragment != null) {
mSettingsFragment.restoreInitialState();
}
// Reset the color of the button
if (mFabColorAnimator != null) {
mFabColorAnimator.cancel();
}
setFabColor(FAB_COLOR);
if (!animate) {
// Show the panel
mSettingsContainer.setVisibility(View.VISIBLE);
// Set up the status bar
getDrawerLayout().setStatusBarBackgroundColor(getResources().getColor(R.color
.accent_dark));
getDrawerLayout().invalidate();
Utilities.setLightStatusBar(getWindow(), true);
// Dim the activity foreground
mForegroundDim.setAlpha(DIMMED_ALPHA);
// Configure the fab
setupFabIconForSettingsPanelOpen(true);
return;
}
// Hide the button immediately
mToggleSettingsPanelButton.setVisibility(View.GONE);
// this is the center of the button in relation to the main view. This provides the center of the clipping circle for the settings view.
int centerOfButtonOutsideX = (mToggleSettingsPanelButton.getLeft() + mToggleSettingsPanelButton.getRight()) / 2;
int centerOfButtonOutsideY = (mToggleSettingsPanelButton.getTop() + mToggleSettingsPanelButton.getBottom()) / 2;
float finalRadius = (float) Math.sqrt(Math.pow(centerOfButtonOutsideX - mSettingsContainer.getLeft(), 2) + Math.pow(centerOfButtonOutsideY - mSettingsContainer.getTop(), 2));
Animator settingsPanelAnimator;
// Only show the circular reveal on API >= 5.0
mSettingsContainer.setVisibility(View.VISIBLE);
if (Utilities.hasLApis()) {
settingsPanelAnimator = ViewAnimationUtils.createCircularReveal(mSettingsContainer, centerOfButtonOutsideX, centerOfButtonOutsideY, 0, finalRadius);
settingsPanelAnimator.setDuration(ANIMATION_DURATION);
settingsPanelAnimator.setInterpolator(new DecelerateInterpolator());
} else {
settingsPanelAnimator = ValueAnimator.ofFloat(1, 0);
final int settingsContainerHeight = mSettingsContainer.getHeight();
((ValueAnimator) settingsPanelAnimator).addUpdateListener(animation -> mSettingsContainer.setTranslationY((float) settingsContainerHeight * (float) animation.getAnimatedValue()));
settingsPanelAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
settingsPanelAnimator.setDuration(ANIMATION_DURATION);
}
ValueAnimator toggleButtonScaleUpAnimation = ValueAnimator.ofFloat(0, 1).setDuration(ANIMATION_DURATION);
toggleButtonScaleUpAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mToggleSettingsPanelButton.setVisibility(View.VISIBLE);
setupFabIconForSettingsPanelOpen(true);
}
});
toggleButtonScaleUpAnimation.addUpdateListener(animation -> {
ViewCompat.setScaleX(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
ViewCompat.setScaleY(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
});
toggleButtonScaleUpAnimation.setDuration(ANIMATION_DURATION / 2);
// Animate the status bar color change
Integer colorFrom = getResources().getColor(R.color.primary_dark);
Integer colorTo = getResources().getColor(R.color.accent_dark);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(animator -> {
getDrawerLayout().setStatusBarBackgroundColor((Integer) animator.getAnimatedValue());
// We have to invalidate so that the view redraws the background
getDrawerLayout().invalidate();
});
colorAnimation.setDuration(ANIMATION_DURATION);
ValueAnimator dimAnimation = ValueAnimator.ofFloat(UNDIMMED_ALPHA, DIMMED_ALPHA);
dimAnimation.addUpdateListener(animation -> mForegroundDim.setAlpha((float) animation.getAnimatedValue()));
dimAnimation.setDuration(ANIMATION_DURATION);
// Change the system UI color on 6.0+
ValueAnimator systemUiAnimator = ValueAnimator.ofFloat(0, 1).setDuration(1);
systemUiAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
Utilities.setLightStatusBar(getWindow(), true);
}
});
AnimatorSet animationSet = new AnimatorSet();
animationSet.play(settingsPanelAnimator);
animationSet.play(systemUiAnimator).after(ANIMATION_DURATION / 2);
animationSet.play(toggleButtonScaleUpAnimation).after(ANIMATION_DURATION / 2);
animationSet.play(colorAnimation).with(settingsPanelAnimator);
animationSet.play(dimAnimation).with(settingsPanelAnimator);
animationSet.start();
mRunningPanelAnimation = animationSet;
animationSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mRunningPanelAnimation = null;
}
});
}
protected void closeSettingsPanel(boolean animate) {
mIsSettingsPanelOpen = false;
if (!animate) {
// Hide the panel
mSettingsContainer.setVisibility(View.GONE);
// Set up the status bar
getDrawerLayout().setStatusBarBackgroundColor(getResources().getColor(R.color
.primary_dark));
getDrawerLayout().invalidate();
Utilities.setLightStatusBar(getWindow(), false);
// Undim the activity foreground
mForegroundDim.setAlpha(UNDIMMED_ALPHA);
// Configure the fab
setupFabIconForSettingsPanelOpen(false);
return;
}
int centerOfButtonOutsideX = (mToggleSettingsPanelButton.getLeft() + mToggleSettingsPanelButton.getRight()) / 2;
int centerOfButtonOutsideY = (mToggleSettingsPanelButton.getTop() + mToggleSettingsPanelButton.getBottom()) / 2;
float finalRadius = (float) Math.sqrt(Math.pow(centerOfButtonOutsideX - mSettingsContainer.getLeft(), 2) + Math.pow(centerOfButtonOutsideY - mSettingsContainer.getTop(), 2));
Animator settingsPanelAnimator;
if (Utilities.hasLApis()) {
settingsPanelAnimator = ViewAnimationUtils.createCircularReveal(mSettingsContainer, centerOfButtonOutsideX, centerOfButtonOutsideY, finalRadius, 0);
settingsPanelAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mSettingsContainer.setVisibility(View.INVISIBLE);
}
});
settingsPanelAnimator.setDuration(ANIMATION_DURATION);
settingsPanelAnimator.setInterpolator(new AccelerateInterpolator());
} else {
settingsPanelAnimator = ValueAnimator.ofFloat(0, 1);
final int settingsContainerHeight = mSettingsContainer.getHeight();
((ValueAnimator) settingsPanelAnimator).addUpdateListener(animation -> mSettingsContainer.setTranslationY((float) settingsContainerHeight * (float) animation.getAnimatedValue()));
settingsPanelAnimator.setDuration(ANIMATION_DURATION);
settingsPanelAnimator.setInterpolator(new AccelerateInterpolator());
settingsPanelAnimator.start();
}
ValueAnimator toggleButtonScaleDownAnimation = ValueAnimator.ofFloat(1, 0).setDuration(ANIMATION_DURATION);
toggleButtonScaleDownAnimation.addUpdateListener(animation -> {
ViewCompat.setScaleX(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
ViewCompat.setScaleY(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
});
toggleButtonScaleDownAnimation.setDuration(ANIMATION_DURATION / 2);
ValueAnimator toggleButtonScaleUpAnimation = ValueAnimator.ofFloat(0, 1).setDuration(ANIMATION_DURATION);
toggleButtonScaleUpAnimation.addUpdateListener(animation -> {
ViewCompat.setScaleX(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
ViewCompat.setScaleY(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
});
toggleButtonScaleUpAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
setupFabIconForSettingsPanelOpen(false);
}
});
toggleButtonScaleUpAnimation.setDuration(ANIMATION_DURATION / 2);
// Animate the status bar color change
Integer colorFrom = getResources().getColor(R.color.accent_dark);
Integer colorTo = getResources().getColor(R.color.primary_dark);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(animator -> {
getDrawerLayout().setStatusBarBackgroundColor((Integer) animator.getAnimatedValue());
// We have to invalidate so that the view redraws the background
getDrawerLayout().invalidate();
});
colorAnimation.setDuration(ANIMATION_DURATION);
// Undim the foreground
ValueAnimator dimAnimation = ValueAnimator.ofFloat(DIMMED_ALPHA, UNDIMMED_ALPHA);
dimAnimation.addUpdateListener(animation -> mForegroundDim.setAlpha((float) animation.getAnimatedValue()));
dimAnimation.setDuration(ANIMATION_DURATION);
// Change the system UI color on 6.0+
ValueAnimator systemUiAnimator = ValueAnimator.ofFloat(0, 0).setDuration(1);
systemUiAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
Utilities.setLightStatusBar(getWindow(), false);
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(settingsPanelAnimator);
animatorSet.play(systemUiAnimator).after(ANIMATION_DURATION / 3);
animatorSet.play(toggleButtonScaleDownAnimation).after(ANIMATION_DURATION / 2);
animatorSet.play(colorAnimation).with(settingsPanelAnimator);
animatorSet.play(dimAnimation).with(settingsPanelAnimator);
animatorSet.play(toggleButtonScaleUpAnimation).after(settingsPanelAnimator);
animatorSet.start();
mRunningPanelAnimation = animatorSet;
mRunningPanelAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mRunningPanelAnimation = null;
}
});
}
protected void syncFabVisibilityWithMyTbaEnabled(boolean animate) {
if (mIsMyTBAEnabled) {
showFab(animate);
} else {
hideFab(animate);
}
}
protected void showFab(boolean animate) {
if (mFabVisible) {
return;
}
mFabVisible = true;
if (mRunningFabAnimation != null) {
mRunningFabAnimation.cancel();
}
if (!animate) {
mToggleSettingsPanelButton.setVisibility(View.VISIBLE);
mToggleSettingsPanelButton.setScaleX(1.0f);
mToggleSettingsPanelButton.setScaleY(1.0f);
return;
}
ValueAnimator fabScaleUp = ValueAnimator.ofFloat(0, 1);
fabScaleUp.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mToggleSettingsPanelButton.setVisibility(View.VISIBLE);
}
});
fabScaleUp.addUpdateListener(animation -> {
ViewCompat.setScaleX(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
ViewCompat.setScaleY(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
});
fabScaleUp.setDuration(FAB_ANIMATION_DURATION);
fabScaleUp.setInterpolator(new DecelerateInterpolator());
fabScaleUp.start();
mRunningFabAnimation = fabScaleUp;
}
protected void hideFab(boolean animate) {
if (!mFabVisible) {
return;
}
mFabVisible = false;
if (mRunningFabAnimation != null) {
mRunningFabAnimation.cancel();
}
if (!animate) {
mToggleSettingsPanelButton.setVisibility(View.GONE);
return;
}
ValueAnimator fabScaleDown = ValueAnimator.ofFloat(1, 0);
fabScaleDown.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mToggleSettingsPanelButton.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
mToggleSettingsPanelButton.setVisibility(View.GONE);
}
});
fabScaleDown.addUpdateListener(animation -> {
ViewCompat.setScaleX(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
ViewCompat.setScaleY(mToggleSettingsPanelButton, (float) animation.getAnimatedValue());
});
fabScaleDown.setDuration(FAB_ANIMATION_DURATION);
fabScaleDown.setInterpolator(new AccelerateInterpolator());
fabScaleDown.start();
mRunningFabAnimation = fabScaleDown;
}
public void setSettingsToolbarTitle(String title) {
mSettingsToolbar.setTitle(title);
}
@Override
public void onSuccess() {
Runnable runnable = () -> {
showSnackbar(R.string.mytba_settings_updated_successfully);
Integer colorFrom = getResources().getColor(FAB_COLOR);
Integer colorTo = getResources().getColor(FAB_COLOR_SUCCESS);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(animator -> mToggleSettingsPanelButton.setBackgroundTintList(ColorStateList.valueOf((Integer) animator.getAnimatedValue())));
colorAnimation.setDuration(FAB_COLOR_ANIMATION_DURATION);
ValueAnimator reverseColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorTo, colorFrom);
reverseColorAnimation.addUpdateListener(animator -> mToggleSettingsPanelButton.setBackgroundTintList(ColorStateList.valueOf((Integer) animator.getAnimatedValue())));
reverseColorAnimation.setDuration(FAB_COLOR_ANIMATION_DURATION);
mFabColorAnimator = new AnimatorSet();
mFabColorAnimator.play(colorAnimation);
mFabColorAnimator.play(reverseColorAnimation).after(2000);
mFabColorAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
// Reset the FAB to the default color
setFabColor(FAB_COLOR);
}
@Override
public void onAnimationEnd(Animator animation) {
mFabColorAnimator = null;
}
});
mFabColorAnimator.start();
};
runAfterSettingsPanelIsClosed(runnable);
// Tell the settings fragment to reload the now-updated settings
mSettingsFragment.refreshSettingsFromDatabase();
// Save finished
mSaveInProgress = false;
}
@Override
public void onNoOp() {
runAfterSettingsPanelIsClosed(() -> showSnackbar(R.string.mytba_settings_not_changed));
mSaveInProgress = false;
}
@Override
public void onError() {
Runnable runnable = () -> {
showSnackbar(R.string.mytba_settings_error);
// Something went wrong, restore the initial state
mSettingsFragment.restoreInitialState();
Integer colorFrom = getResources().getColor(FAB_COLOR);
Integer colorTo = getResources().getColor(FAB_COLOR_ERROR);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(animator -> mToggleSettingsPanelButton.setBackgroundTintList(ColorStateList.valueOf((Integer) animator.getAnimatedValue())));
colorAnimation.setDuration(FAB_COLOR_ANIMATION_DURATION);
ValueAnimator reverseColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorTo, colorFrom);
reverseColorAnimation.addUpdateListener(animator -> mToggleSettingsPanelButton.setBackgroundTintList(ColorStateList.valueOf((Integer) animator.getAnimatedValue())));
reverseColorAnimation.setDuration(FAB_COLOR_ANIMATION_DURATION);
mFabColorAnimator = new AnimatorSet();
mFabColorAnimator.play(colorAnimation);
mFabColorAnimator.play(reverseColorAnimation).after(2000);
mFabColorAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
// Reset the FAB to the default color
setFabColor(FAB_COLOR);
}
@Override
public void onAnimationEnd(Animator animation) {
mFabColorAnimator = null;
}
});
mFabColorAnimator.start();
};
runAfterSettingsPanelIsClosed(runnable);
mSaveInProgress = false;
}
@Override
public void onBackPressed() {
if (mIsSettingsPanelOpen) {
closeSettingsPanel(true);
return;
}
super.onBackPressed();
}
public void onSettingsLoaded() {
// Re-enable the submit button
mIsSaveEnalbed = true;
}
protected void showSnackbar(@StringRes int messageResId) {
showSnackbar(getString(messageResId));
}
@SuppressWarnings("WrongConstant")
protected void showSnackbar(CharSequence message) {
Snackbar snackbar = Snackbar.make(mCoordinatorLayout, message, 2000);
TextView text = (TextView) snackbar.getView().findViewById(android.support.design.R.id.snackbar_text);
if (text != null) {
text.setTextColor(getResources().getColor(R.color.white));
}
snackbar.show();
}
protected Snackbar createSnackbar(CharSequence message, @Snackbar.Duration int duration) {
Snackbar snackbar = Snackbar.make(mCoordinatorLayout, message == null ? "" : message, duration);
TextView text = (TextView) snackbar.getView().findViewById(android.support.design.R.id.snackbar_text);
if (text != null) {
text.setTextColor(getResources().getColor(R.color.white));
}
return snackbar;
}
/**
* Used to defer an operation until after the settings panel has finished animating closed.
* <p>
* If the panel has already finished animating when this is called, the Runnable will be run
* immediately.
*/
private void runAfterSettingsPanelIsClosed(Runnable runnable) {
if (mRunningPanelAnimation == null) {
runnable.run();
} else {
mRunningPanelAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
runnable.run();
}
});
}
}
/**
* Subclasses should override this if they care about FAB click events. If they handle the
* event, return true; otherwise, return false so the default behavior (opening and closing
* the settings panel) will occur.
*
* @return true if the click was handled by this method
*/
protected boolean onFabClick() {
return false;
}
protected void setFabColor(@ColorRes int color) {
mToggleSettingsPanelButton.setBackgroundTintList(ColorStateList.valueOf(getResources().getColor(color)));
}
protected void setFabDrawable(@DrawableRes int drawable) {
mToggleSettingsPanelButton.setImageResource(drawable);
}
protected void setupFabForMyTbaSettingsTab() {
setupFabIconForSettingsPanelOpen(mIsSettingsPanelOpen);
setFabColor(FAB_COLOR);
}
}