package com.kaichunlin.transition.animation;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import android.view.View;
import com.kaichunlin.transition.AbstractTransition;
import com.kaichunlin.transition.AbstractTransitionBuilder;
import com.kaichunlin.transition.Transition;
import com.kaichunlin.transition.TransitionOperation;
import java.util.ArrayList;
import java.util.List;
/**
* Manages a collection of {@link Animation} as a single unit.
*/
@UiThread
public class AnimationManager extends AbstractAnimation {
private final AnimationListener mAnimationListener = new AnimationListener() {
@Override
public void onAnimationStart(Animation animationManager) {
setAnimating(true);
}
@Override
public void onAnimationEnd(Animation animationManager) {
setAnimating(false);
notifyAnimationEnd();
}
@Override
public void onAnimationCancel(Animation animationManager) {
setAnimating(false);
notifyAnimationCancel();
}
@Override
public void onAnimationReset(Animation animationManager) {
setAnimating(false);
notifyAnimationReset();
}
};
private final List<AbstractAnimation> mAnimationList = new ArrayList<>();
private StateController mSharedController;
private boolean mCheckAnimationType;
private boolean mPassAnimationTypeCheck;
/**
* Same as calling addAnimation(transitionBuilder.buildAnimation())
*
* @param transitionBuilder
*/
public void addAnimation(@NonNull AbstractTransitionBuilder transitionBuilder) {
addAnimation(transitionBuilder.buildAnimation());
}
private void processAnimation(AbstractAnimation animation) {
//attempt to merge an animation
boolean merged = false;
//no optimization is taken if the TransitionOption is not an AbstractTransition subclass
if (animation.getTransition() instanceof AbstractTransition) {
TransitionOperation to;
for (int i = 0, size = mAnimationList.size(); i < size; i++) {
to = mAnimationList.get(i).getTransition();
if (to instanceof AbstractTransition) {
merged = ((AbstractTransition) to).merge((AbstractTransition) animation.getTransition());
if (merged) {
break;
}
}
}
}
if (!merged) {
mAnimationList.add(animation);
}
mCheckAnimationType = true;
}
/**
* Adds an animation
*
* @param animation
*/
public void addAnimation(@NonNull Animation animation) {
processAnimation((AbstractAnimation) animation);
}
/**
* @param animationsList
*/
public void addAllAnimations(@NonNull List<Animation> animationsList) {
final int size = animationsList.size();
for (int i = 0; i < size; i++) {
processAnimation((AbstractAnimation) animationsList.get(i));
}
}
/**
* Adds an transition
*
* @param transition
*/
public void addTransition(@NonNull Transition transition) {
processAnimation(new TransitionAnimation(transition));
}
/**
* @param transitionList
*/
public void addAllTransitions(List<Transition> transitionList) {
final int size = transitionList.size();
for (int i = 0; i < size; i++) {
processAnimation(new TransitionAnimation(transitionList.get(i)));
}
}
/**
* Stops and clears all transitions
*/
public void removeAllAnimations() {
for (int i = 0, size = mAnimationList.size(); i < size; i++) {
mAnimationList.get(i).removeAnimationListener(mAnimationListener);
}
mAnimationList.clear();
}
/**
* @return
*/
public List<Animation> getAnimations() {
List<Animation> list = new ArrayList<>(mAnimationList.size());
list.addAll(mAnimationList);
return list;
}
@Override
public int getDuration() {
if (super.getDuration() == -1) {
int maxDuration = 0;
int duration;
for (int i = 0, size = mAnimationList.size(); i < size; i++) {
duration = mAnimationList.get(i).getDuration();
if (maxDuration < duration) {
maxDuration = duration;
}
}
return maxDuration;
} else {
return super.getDuration();
}
}
@Override
public void setReverseAnimation(boolean reverse) {
if (isReverseAnimation() == reverse) {
return;
}
super.setReverseAnimation(reverse);
Animation animation;
for (int i = 0, size = mAnimationList.size(); i < size; i++) {
animation = mAnimationList.get(i);
animation.setReverseAnimation(!animation.isReverseAnimation());
}
}
@Override
public void startAnimation() {
startAnimation(getDuration());
}
@Override
public void startAnimation(@IntRange(from = 0) int duration) {
if (isAnimating()) {
cancelAnimation();
}
if (mAnimationList.size() == 0) {
return;
}
mAnimationList.get(0).addAnimationListener(mAnimationListener);
//call listeners so they can perform their actions first, like modifying this adapter's transitions
notifyAnimationStart();
doStartAnimation(duration);
}
private void doStartAnimation(@IntRange(from = 0) int duration) {
final int size = mAnimationList.size();
if (mCheckAnimationType) {
mPassAnimationTypeCheck = true;
for (int i = 0; i < size; i++) {
if (!(mAnimationList.get(i) instanceof TransitionAnimation)) {
mPassAnimationTypeCheck = false;
break;
}
}
mCheckAnimationType = false;
}
if (mPassAnimationTypeCheck) {
List<TransitionOperation> transitionList = new ArrayList<>();
TransitionOperation transitionOperation;
for (int i = 0; i < size; i++) {
transitionOperation = mAnimationList.get(i).getTransition();
transitionList.add(transitionOperation);
}
//TODO fugly
boolean forceAnimator = false;
View view = null;
for (int i = 0; i < size; i++) {
view = ((AbstractTransition) (mAnimationList.get(i).getTransition())).getTarget();
if (view == null) {
forceAnimator = true;
}
}
if (getStateControllerType() == CONTROLLER_ANIMATOR || forceAnimator) {
mSharedController = new AnimatorController(isReverseAnimation());
} else if (getStateControllerType() == CONTROLLER_ANIMATION) {
mSharedController = new AnimationController(view, isReverseAnimation(), transitionList);
}
mSharedController.setAnimationDuration(duration);
for (int i = 0; i < size; i++) {
((TransitionAnimation) mAnimationList.get(i)).prepareAnimation(mSharedController, -1);
}
mSharedController.startController();
} else {
for (int i = 0; i < size; i++) {
mAnimationList.get(i).startAnimation(duration);
}
}
}
@Override
public void cancelAnimation() {
if (isAnimating()) {
if (mSharedController == null) {
for (int i = 0, size = mAnimationList.size(); i < size; i++) {
mAnimationList.get(i).cancelAnimation();
}
} else {
mSharedController.cancelController();
}
}
}
@Override
public void pauseAnimation() {
if (mSharedController == null) {
for (int i = 0, size = mAnimationList.size(); i < size; i++) {
mAnimationList.get(i).pauseAnimation();
}
} else {
mSharedController.pauseController();
}
}
@Override
public void resumeAnimation() {
if (mSharedController == null) {
for (int i = 0, size = mAnimationList.size(); i < size; i++) {
mAnimationList.get(i).resumeAnimation();
}
} else {
mSharedController.resumeController();
}
}
@Override
public void endAnimation() {
if (mSharedController == null) {
for (int i = 0, size = mAnimationList.size(); i < size; i++) {
mAnimationList.get(i).endAnimation();
}
} else {
mSharedController.endController();
}
}
@Override
public void forceEndState() {
if (isAnimating()) {
endAnimation();
} else {
doStartAnimation(100);
endAnimation();
notifyAnimationEnd();
}
}
@Override
public void resetAnimation() {
if (mSharedController == null) {
for (int i = 0, size = mAnimationList.size(); i < size; i++) {
mAnimationList.get(i).resetAnimation();
}
} else {
mSharedController.resetController();
}
}
}