package odoo.controls.undobar;
import static com.nineoldandroids.view.ViewHelper.setAlpha;
import static com.nineoldandroids.view.ViewPropertyAnimator.animate;
import android.app.Activity;
import android.os.Handler;
import android.os.Parcelable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.view.ViewPropertyAnimator;
import com.odoo.R;
public final class UndoBar {
/**
* Listener for actions of the undo bar.
*/
public static interface UndoBarListener {
/**
* Will be fired when the undo bar disappears without being actioned.
*/
void onHide();
/**
* Will be fired when the undo button is pressed.
*/
void onUndo(Parcelable token);
}
/**
* Default duration in milliseconds the undo bar will be displayed.
*/
public static final int DEFAULT_DURATION = 5000;
/**
* Default duration in milliseconds of the undo bar show and hide animation.
*/
public static final int DEFAULT_ANIMATION_DURATION = 300;
private final Activity mActivity;
private final UndoBarView mView;
private final ViewPropertyAnimator mViewAnimator;
private final Handler mHandler = new Handler();
private final Runnable mHideRunnable = new Runnable() {
@Override
public void run() {
hide(true);
safelyNotifyOnHide();
}
};
private final OnClickListener mOnUndoClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
hide(true);
safelyNotifyOnUndo();
}
};
private UndoBarListener mUndoListener;
private Parcelable mUndoToken;
private CharSequence mUndoMessage;
private int mDuration = DEFAULT_DURATION;
private int mAnimationDuration = DEFAULT_ANIMATION_DURATION;
public UndoBar(Activity activity) {
mActivity = activity;
mView = getView(activity);
mView.setOnUndoClickListener(mOnUndoClickListener);
mViewAnimator = animate(mView);
hide(false);
}
/**
* Sets the message to be displayed on the left of the undo bar.
*/
public void setMessage(CharSequence message) {
mUndoMessage = message;
}
/**
* Sets the message to be displayed on the left of the undo bar.
*/
public void setMessage(int messageResId) {
mUndoMessage = mActivity.getString(messageResId);
}
/**
* Sets the {@link Listener UndoBar.Listener}.
*/
public void setListener(UndoBarListener undoListener) {
mUndoListener = undoListener;
}
/**
* Sets a {@link Parcelable} token to the undo bar which will be returned in
* the {@link Listener UndoBar.Listener}.
*/
public void setUndoToken(Parcelable undoToken) {
mUndoToken = undoToken;
}
/**
* Sets the duration the undo bar will be shown.<br>
* Default is {@link #DEFAULT_DURATION}.
*
* @param duration
* in milliseconds
*/
public void setDuration(int duration) {
mDuration = duration;
}
/**
* Sets the duration of the animation for showing and hiding the undo bar.<br>
* Default is {@link #DEFAULT_DURATION_ANIMATION}.
*
* @param animationDuration
* in milliseconds
*/
public void setAnimationDuration(int animationDuration) {
mAnimationDuration = animationDuration;
}
/**
* Calls {@link #show(boolean)} with {@code shouldAnimate = true}.
*/
public void show() {
show(true);
}
/**
* Shows the {@link UndoBar}.
*
* @param shouldAnimate
* whether the {@link UndoBar} should animate in
*/
public void show(boolean shouldAnimate) {
mView.setMessage(mUndoMessage);
mHandler.removeCallbacks(mHideRunnable);
mHandler.postDelayed(mHideRunnable, mDuration);
mView.setVisibility(View.VISIBLE);
if (shouldAnimate) {
animateIn();
} else {
setAlpha(mView, 1);
}
}
/**
* Calls {@link #hide(boolean)} with {@code shouldAnimate = true}.
*/
public void hide() {
hide(true);
}
/**
* Hides the {@link UndoBar}.
*
* @param shouldAnimate
* whether the {@link UndoBar} should animate out
*/
public void hide(boolean shouldAnimate) {
mHandler.removeCallbacks(mHideRunnable);
if (shouldAnimate) {
animateOut();
} else {
setAlpha(mView, 0);
mView.setVisibility(View.GONE);
mUndoMessage = null;
mUndoToken = null;
}
}
/**
* Performs the actual show animation.
*/
private void animateIn() {
mViewAnimator.cancel();
mViewAnimator.alpha(1)//
.setDuration(mAnimationDuration)//
.setListener(null);
}
/**
* Performs the actual hide animation.
*/
private void animateOut() {
mViewAnimator.cancel();
mViewAnimator.alpha(0)//
.setDuration(mAnimationDuration)//
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mView.setVisibility(View.GONE);
mUndoMessage = null;
mUndoToken = null;
}
});
}
/**
* Notifies listener if available.
*/
private void safelyNotifyOnHide() {
if (mUndoListener != null) {
mUndoListener.onHide();
}
}
/**
* Notifies listener if available.
*/
private void safelyNotifyOnUndo() {
if (mUndoListener != null) {
mUndoListener.onUndo(mUndoToken);
}
}
/**
* Checks if there is already an {@link UndoBarView} instance added to the
* given {@link Activity}.<br>
* If {@code true}, returns that instance.<br>
* If {@code false}, inflates a new {@link UndoBarView} and returns it.
*/
private UndoBarView getView(Activity activity) {
ViewGroup rootView = (ViewGroup) activity
.findViewById(android.R.id.content);
UndoBarView undoBarView = (UndoBarView) rootView
.findViewById(R.id.undoBar);
if (undoBarView == null) {
undoBarView = (UndoBarView) LayoutInflater.from(activity).inflate(
R.layout.undo_bar, rootView, false);
rootView.addView(undoBarView);
}
return undoBarView;
}
public static class Builder {
private final Activity mActivity;
private CharSequence mUndoMessage;
private UndoBarListener mUndoListener;
private Parcelable mUndoToken;
private int mDuration = DEFAULT_DURATION;
private int mAnimationDuration = DEFAULT_ANIMATION_DURATION;
/**
* Constructor using the {@link Activity} in which the undo bar will be
* displayed
*/
public Builder(Activity activity) {
mActivity = activity;
}
/**
* Sets the message to be displayed on the left of the undo bar.
*/
public Builder setMessage(int messageResId) {
mUndoMessage = mActivity.getString(messageResId);
return this;
}
/**
* Sets the message to be displayed on the left of the undo bar.
*/
public Builder setMessage(CharSequence message) {
mUndoMessage = message;
return this;
}
/**
* Sets the {@link Listener UndoBar.Listener}.
*/
public Builder setListener(UndoBarListener undoListener) {
mUndoListener = undoListener;
return this;
}
/**
* Sets a {@link Parcelable} token to the undo bar which will be
* returned in the {@link Listener UndoBar.Listener}.
*/
public Builder setUndoToken(Parcelable undoToken) {
mUndoToken = undoToken;
return this;
}
/**
* Sets the duration the undo bar will be shown.<br>
* Default is {@link #DEFAULT_DURATION}.
*
* @param duration
* in milliseconds
*/
public Builder setDuration(int duration) {
mDuration = duration;
return this;
}
/**
* Sets the duration of the animation for showing and hiding the undo
* bar.<br>
* Default is {@link #DEFAULT_DURATION_ANIMATION}.
*
* @param animationDuration
* in milliseconds
*/
public Builder setAnimationDuration(int animationDuration) {
mAnimationDuration = animationDuration;
return this;
}
/**
* Creates an {@link UndoBar} instance with this Builder's
* configuration.
*/
public UndoBar create() {
UndoBar undoBarController = new UndoBar(mActivity);
undoBarController.setListener(mUndoListener);
undoBarController.setUndoToken(mUndoToken);
undoBarController.setMessage(mUndoMessage);
undoBarController.setDuration(mDuration);
undoBarController.setAnimationDuration(mAnimationDuration);
return undoBarController;
}
/**
* Calls {@link #show(boolean)} with {@code shouldAnimate = true}.
*/
public void show() {
show(true);
}
/**
* Shows the {@link UndoBar} with this Builder's configuration.
*
* @param shouldAnimate
* whether the {@link UndoBar} should animate in and out.
*/
public void show(boolean shouldAnimate) {
create().show(shouldAnimate);
}
}
}