package com.reactnativenavigation.views.sharedElementTransition;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.support.annotation.NonNull;
import android.view.View;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.view.DraweeView;
import com.reactnativenavigation.params.InterpolationParams;
import com.reactnativenavigation.params.PathInterpolationParams;
import com.reactnativenavigation.params.parsers.SharedElementTransitionParams;
import com.reactnativenavigation.views.utils.AnimatorPath;
import com.reactnativenavigation.views.utils.ClipBoundsEvaluator;
import com.reactnativenavigation.views.utils.ColorUtils;
import com.reactnativenavigation.views.utils.LabColorEvaluator;
import com.reactnativenavigation.views.utils.PathEvaluator;
import java.util.ArrayList;
import java.util.List;
import static android.animation.ObjectAnimator.ofFloat;
class SharedElementAnimatorCreator {
private final SharedElementTransition from;
private final SharedElementTransition to;
SharedElementAnimatorCreator(SharedElementTransition from, SharedElementTransition to) {
this.from = from;
this.to = to;
}
List<Animator> createShow() {
return create(new AnimatorValuesResolver(from, to, to.showTransitionParams), to.showTransitionParams);
}
List<Animator> createHide() {
return create(new ReversedAnimatorValuesResolver(to, from, to.hideTransitionParams), to.hideTransitionParams);
}
@NonNull
private List<Animator> create(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
List<Animator> result = new ArrayList<>();
if (shouldAddCurvedMotionAnimator(resolver, params.interpolation)) {
result.add(createCurvedMotionAnimator(resolver, params));
} else {
if (shouldAddLinearMotionXAnimator(resolver)) {
result.add(createXAnimator(resolver, params));
}
if (shouldAddLinearMotionYAnimator(resolver)) {
result.add(createYAnimator(resolver, params));
}
}
if (shouldAddScaleXAnimator(resolver, params)) {
result.add(createScaleXAnimator(resolver, params));
}
if (shouldAddScaleYAnimator(resolver, params)) {
result.add(createScaleYAnimator(resolver, params));
}
if (shouldAddColorAnimator(resolver)) {
result.add(createColorAnimator(resolver, params.duration));
}
if (shouldAddImageClipBoundsAnimator(params)) {
result.add(createImageClipBoundsAnimator(resolver, params));
result.add(createImageTransformAnimator(resolver, params));
}
return result;
}
private boolean shouldAddScaleYAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
return resolver.startScaleY != resolver.endScaleY && !params.animateClipBounds;
}
private boolean shouldAddScaleXAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
return resolver.startScaleX != resolver.endScaleX && !params.animateClipBounds;
}
private boolean shouldAddLinearMotionXAnimator(AnimatorValuesResolver resolver) {
return resolver.dx != 0;
}
private boolean shouldAddLinearMotionYAnimator(AnimatorValuesResolver resolver) {
return resolver.dy != 0;
}
private boolean shouldAddCurvedMotionAnimator(AnimatorValuesResolver resolver, InterpolationParams interpolation) {
return interpolation instanceof PathInterpolationParams && (resolver.dx != 0 || resolver.dy != 0);
}
private boolean shouldAddColorAnimator(AnimatorValuesResolver resolver) {
return resolver.startColor != resolver.endColor;
}
private boolean shouldAddImageClipBoundsAnimator(SharedElementTransitionParams params) {
return params.animateClipBounds;
}
private ObjectAnimator createCurvedMotionAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
AnimatorPath path = new AnimatorPath();
path.moveTo(resolver.startX, resolver.startY);
path.curveTo(resolver.controlX1, resolver.controlY1, resolver.controlX2, resolver.controlY2, resolver.endX, resolver.endY);
ObjectAnimator animator = ObjectAnimator.ofObject(
to,
"curvedMotion",
new PathEvaluator(),
path.getPoints().toArray());
animator.setInterpolator(params.interpolation.easing.getInterpolator());
animator.setDuration(params.duration);
return animator;
}
private ObjectAnimator createXAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
ObjectAnimator animator = ofFloat(to.getSharedView(), View.TRANSLATION_X, resolver.startX, resolver.endX)
.setDuration(params.duration);
animator.setInterpolator(params.interpolation.easing.getInterpolator());
return animator;
}
private ObjectAnimator createYAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
ObjectAnimator animator = ofFloat(to.getSharedView(), View.TRANSLATION_Y, resolver.startY, resolver.endY)
.setDuration(params.duration);
animator.setInterpolator(params.interpolation.easing.getInterpolator());
return animator;
}
private ObjectAnimator createScaleXAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
to.getSharedView().setPivotX(0);
ObjectAnimator animator =
ofFloat(to.getSharedView(), View.SCALE_X, resolver.startScaleX, resolver.endScaleX)
.setDuration(params.duration);
animator.setInterpolator(params.interpolation.easing.getInterpolator());
return animator;
}
private ObjectAnimator createScaleYAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
to.getSharedView().setPivotY(0);
ObjectAnimator animator =
ofFloat(to.getSharedView(), View.SCALE_Y, resolver.startScaleY, resolver.endScaleY)
.setDuration(params.duration);
animator.setInterpolator(params.interpolation.easing.getInterpolator());
return animator;
}
private ObjectAnimator createColorAnimator(AnimatorValuesResolver resolver, int duration) {
return ObjectAnimator.ofObject(
to,
"textColor",
new LabColorEvaluator(),
ColorUtils.colorToLAB(resolver.startColor),
ColorUtils.colorToLAB(resolver.endColor))
.setDuration(duration);
}
private ObjectAnimator createImageClipBoundsAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
ObjectAnimator animator = ObjectAnimator.ofObject(
to,
"clipBounds",
new ClipBoundsEvaluator(),
resolver.startDrawingRect,
resolver.endDrawingRect)
.setDuration(params.duration);
animator.setInterpolator(params.interpolation.easing.getInterpolator());
return animator;
}
private Animator createImageTransformAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) {
ScalingUtils.InterpolatingScaleType ist = new ScalingUtils.InterpolatingScaleType(
resolver.fromScaleType,
resolver.toScaleType,
resolver.fromBounds,
resolver.toBounds
);
((DraweeView<GenericDraweeHierarchy>) to.getSharedView()).getHierarchy().setActualImageScaleType(ist);
ObjectAnimator animator = ObjectAnimator.ofFloat(to, "matrixTransform", 0, 1).setDuration(params.duration);
animator.setInterpolator(params.interpolation.easing.getInterpolator());
return animator;
}
}