///* // * Copyright 2015. Appsi Mobile // * // * Licensed under the Apache License, Version 2.0 (the "License"); // * you may not use this file except in compliance with the License. // * You may obtain a copy of the License at // * // * http://www.apache.org/licenses/LICENSE-2.0 // * // * Unless required by applicable law or agreed to in writing, software // * distributed under the License is distributed on an "AS IS" BASIS, // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * See the License for the specific language governing permissions and // * limitations under the License. // */ //package com.appsimobile.appsii.module.appsiagenda; // //import android.support.v4.view.ViewCompat; //import android.support.v4.view.ViewPropertyAnimatorCompat; //import android.support.v4.view.ViewPropertyAnimatorListener; //import android.support.v7.widget.RecyclerView; //import android.support.v7.widget.RecyclerView.ViewHolder; //import android.view.View; // //import java.util.ArrayList; //import java.util.List; // ///** // * This implementation of {@link RecyclerView.ItemAnimator} provides basic // * animations on remove, add, and move events that happen to the items in // * a RecyclerView. RecyclerView uses a DefaultItemAnimator by default. // * // * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator) // */ //public class AgendaItemAnimator extends RecyclerView.ItemAnimator { // // private static final boolean DEBUG = false; // // final ArrayList<ArrayList<ViewHolder>> mAdditionsList = // new ArrayList<ArrayList<ViewHolder>>(); // // final ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>(); // // final ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>(); // // final ArrayList<ViewHolder> mAddAnimations = new ArrayList<>(); // // final ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>(); // // final ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>(); // // final ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>(); // // private final ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>(); // // private final ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>(); // // private final ArrayList<MoveInfo> mPendingMoves = new ArrayList<>(); // // private final ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>(); // // @Override // public void runPendingAnimations() { // boolean removalsPending = !mPendingRemovals.isEmpty(); // boolean movesPending = !mPendingMoves.isEmpty(); // boolean changesPending = !mPendingChanges.isEmpty(); // boolean additionsPending = !mPendingAdditions.isEmpty(); // if (!removalsPending && !movesPending && !additionsPending && !changesPending) { // // nothing to animate // return; // } // // First, remove stuff // int N = mPendingRemovals.size(); // for (int i = 0; i < N; i++) { // ViewHolder holder = mPendingRemovals.get(i); // animateRemoveImpl(holder); // } // mPendingRemovals.clear(); // // Next, move stuff // if (movesPending) { // final ArrayList<MoveInfo> moves = new ArrayList<>(); // moves.addAll(mPendingMoves); // mMovesList.add(moves); // mPendingMoves.clear(); // Runnable mover = new Runnable() { // @Override // public void run() { // for (int i = 0; i < moves.size(); i++) { // MoveInfo moveInfo = moves.get(i); // animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, // moveInfo.toX, moveInfo.toY); // } // moves.clear(); // mMovesList.remove(moves); // } // }; // if (removalsPending) { // View view = moves.get(0).holder.itemView; // ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration()); // } else { // mover.run(); // } // } // // Next, change stuff, to run in parallel with move animations // if (changesPending) { // final ArrayList<ChangeInfo> changes = new ArrayList<>(); // changes.addAll(mPendingChanges); // mChangesList.add(changes); // mPendingChanges.clear(); // Runnable changer = new Runnable() { // @Override // public void run() { // for (ChangeInfo change : changes) { // animateChangeImpl(change); // } // changes.clear(); // mChangesList.remove(changes); // } // }; // if (removalsPending) { // ViewHolder holder = changes.get(0).oldHolder; // ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration()); // } else { // changer.run(); // } // } // // Next, add stuff // if (additionsPending) { // final ArrayList<ViewHolder> additions = new ArrayList<>(); // additions.addAll(mPendingAdditions); // mAdditionsList.add(additions); // mPendingAdditions.clear(); // Runnable adder = new Runnable() { // public void run() { // for (int i = 0; i < additions.size(); i++) { // ViewHolder holder = additions.get(i); // animateAddImpl(holder); // } // additions.clear(); // mAdditionsList.remove(additions); // } // }; // if (removalsPending || movesPending || changesPending) { // long removeDuration = removalsPending ? getRemoveDuration() : 0; // long moveDuration = movesPending ? getMoveDuration() : 0; // long changeDuration = changesPending ? getChangeDuration() : 0; // long totalDelay = removeDuration + Math.max(moveDuration, changeDuration); // View view = additions.get(0).itemView; // ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); // } else { // adder.run(); // } // } // } // // @Override // public boolean animateRemove(final ViewHolder holder) { // endAnimation(holder); // mPendingRemovals.add(holder); // return true; // } // // @Override // public boolean animateAdd(final ViewHolder holder) { // endAnimation(holder); // ViewCompat.setAlpha(holder.itemView, 0); // if (holder instanceof ItemAgendaViewHolder) { // ViewCompat.setScaleX(holder.itemView, .3f); // ViewCompat.setScaleY(holder.itemView, .3f); // } // mPendingAdditions.add(holder); // return true; // } // // @Override // public boolean animateMove(final ViewHolder holder, int fromX, int fromY, // int toX, int toY) { // final View view = holder.itemView; // fromX += ViewCompat.getTranslationX(holder.itemView); // fromY += ViewCompat.getTranslationY(holder.itemView); // endAnimation(holder); // int deltaX = toX - fromX; // int deltaY = toY - fromY; // if (deltaX == 0 && deltaY == 0) { // dispatchMoveFinished(holder); // return false; // } // if (deltaX != 0) { // ViewCompat.setTranslationX(view, -deltaX); // } // if (deltaY != 0) { // ViewCompat.setTranslationY(view, -deltaY); // } // mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY)); // return true; // } // // @Override // public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, // int fromX, int fromY, int toX, int toY) { // final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView); // final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView); // final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView); // endAnimation(oldHolder); // int deltaX = (int) (toX - fromX - prevTranslationX); // int deltaY = (int) (toY - fromY - prevTranslationY); // // recover prev translation state after ending animation // ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX); // ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY); // ViewCompat.setAlpha(oldHolder.itemView, prevAlpha); // if (newHolder != null && newHolder.itemView != null) { // // carry over translation values // endAnimation(newHolder); // ViewCompat.setTranslationX(newHolder.itemView, -deltaX); // ViewCompat.setTranslationY(newHolder.itemView, -deltaY); // ViewCompat.setAlpha(newHolder.itemView, 0); // } // mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)); // return true; // } // // @Override // public void endAnimation(ViewHolder item) { // final View view = item.itemView; // // this will trigger end callback which should set properties to their target values. // ViewCompat.animate(view).cancel(); // // TODO if some other animations are chained to end, how do we cancel them as well? // for (int i = mPendingMoves.size() - 1; i >= 0; i--) { // MoveInfo moveInfo = mPendingMoves.get(i); // if (moveInfo.holder == item) { // ViewCompat.setTranslationY(view, 0); // ViewCompat.setTranslationX(view, 0); // dispatchMoveFinished(item); // mPendingMoves.remove(item); // } // } // endChangeAnimation(mPendingChanges, item); // if (mPendingRemovals.remove(item)) { // ViewCompat.setAlpha(view, 1); // dispatchRemoveFinished(item); // } // if (mPendingAdditions.remove(item)) { // ViewCompat.setAlpha(view, 1); // dispatchAddFinished(item); // } // // for (int i = mChangesList.size() - 1; i >= 0; i--) { // ArrayList<ChangeInfo> changes = mChangesList.get(i); // endChangeAnimation(changes, item); // if (changes.isEmpty()) { // mChangesList.remove(changes); // } // } // for (int i = mMovesList.size() - 1; i >= 0; i--) { // ArrayList<MoveInfo> moves = mMovesList.get(i); // for (int j = moves.size() - 1; j >= 0; j--) { // MoveInfo moveInfo = moves.get(j); // if (moveInfo.holder == item) { // ViewCompat.setTranslationY(view, 0); // ViewCompat.setTranslationX(view, 0); // dispatchMoveFinished(item); // moves.remove(j); // if (moves.isEmpty()) { // mMovesList.remove(moves); // } // break; // } // } // } // for (int i = mAdditionsList.size() - 1; i >= 0; i--) { // ArrayList<ViewHolder> additions = mAdditionsList.get(i); // if (additions.remove(item)) { // ViewCompat.setAlpha(view, 1); // dispatchAddFinished(item); // if (additions.isEmpty()) { // mAdditionsList.remove(additions); // } // } // } // // // animations should be ended by the cancel above. // if (mRemoveAnimations.remove(item) && DEBUG) { // throw new IllegalStateException("after animation is cancelled, item should not be in " // + "mRemoveAnimations list"); // } // // if (mAddAnimations.remove(item) && DEBUG) { // throw new IllegalStateException("after animation is cancelled, item should not be in " // + "mAddAnimations list"); // } // // if (mChangeAnimations.remove(item) && DEBUG) { // throw new IllegalStateException("after animation is cancelled, item should not be in " // + "mChangeAnimations list"); // } // // if (mMoveAnimations.remove(item) && DEBUG) { // throw new IllegalStateException("after animation is cancelled, item should not be in " // + "mMoveAnimations list"); // } // dispatchFinishedWhenDone(); // } //// //// void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { //// final View view = holder.itemView; //// final int deltaX = toX - fromX; //// final int deltaY = toY - fromY; //// if (deltaX != 0) { //// ViewCompat.animate(view).translationX(0); //// } //// if (deltaY != 0) { //// ViewCompat.animate(view).translationY(0); //// } //// // TODO: make EndActions end listeners instead, since end actions aren't called when //// // vpas are canceled (and can't end them. why?) //// // need listener functionality in VPACompat for this. Ick. //// mMoveAnimations.add(holder); //// final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); //// animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() { //// @Override //// public void onAnimationStart(View view) { //// dispatchMoveStarting(holder); //// } //// //// @Override //// public void onAnimationCancel(View view) { //// if (deltaX != 0) { //// ViewCompat.setTranslationX(view, 0); //// } //// if (deltaY != 0) { //// ViewCompat.setTranslationY(view, 0); //// } //// } //// //// @Override //// public void onAnimationEnd(View view) { //// animation.setListener(null); //// dispatchMoveFinished(holder); //// mMoveAnimations.remove(holder); //// dispatchFinishedWhenDone(); //// } //// }).start(); //// } // // @Override // public void endAnimations() { // int count = mPendingMoves.size(); // for (int i = count - 1; i >= 0; i--) { // MoveInfo item = mPendingMoves.get(i); // View view = item.holder.itemView; // ViewCompat.setTranslationY(view, 0); // ViewCompat.setTranslationX(view, 0); // dispatchMoveFinished(item.holder); // mPendingMoves.remove(i); // } // count = mPendingRemovals.size(); // for (int i = count - 1; i >= 0; i--) { // ViewHolder item = mPendingRemovals.get(i); // dispatchRemoveFinished(item); // mPendingRemovals.remove(i); // } // count = mPendingAdditions.size(); // for (int i = count - 1; i >= 0; i--) { // ViewHolder item = mPendingAdditions.get(i); // View view = item.itemView; // ViewCompat.setAlpha(view, 1); // dispatchAddFinished(item); // mPendingAdditions.remove(i); // } // count = mPendingChanges.size(); // for (int i = count - 1; i >= 0; i--) { // endChangeAnimationIfNecessary(mPendingChanges.get(i)); // } // mPendingChanges.clear(); // if (!isRunning()) { // return; // } // // int listCount = mMovesList.size(); // for (int i = listCount - 1; i >= 0; i--) { // ArrayList<MoveInfo> moves = mMovesList.get(i); // count = moves.size(); // for (int j = count - 1; j >= 0; j--) { // MoveInfo moveInfo = moves.get(j); // ViewHolder item = moveInfo.holder; // View view = item.itemView; // ViewCompat.setTranslationY(view, 0); // ViewCompat.setTranslationX(view, 0); // dispatchMoveFinished(moveInfo.holder); // moves.remove(j); // if (moves.isEmpty()) { // mMovesList.remove(moves); // } // } // } // listCount = mAdditionsList.size(); // for (int i = listCount - 1; i >= 0; i--) { // ArrayList<ViewHolder> additions = mAdditionsList.get(i); // count = additions.size(); // for (int j = count - 1; j >= 0; j--) { // ViewHolder item = additions.get(j); // View view = item.itemView; // ViewCompat.setAlpha(view, 1); // dispatchAddFinished(item); // additions.remove(j); // if (additions.isEmpty()) { // mAdditionsList.remove(additions); // } // } // } // listCount = mChangesList.size(); // for (int i = listCount - 1; i >= 0; i--) { // ArrayList<ChangeInfo> changes = mChangesList.get(i); // count = changes.size(); // for (int j = count - 1; j >= 0; j--) { // endChangeAnimationIfNecessary(changes.get(j)); // if (changes.isEmpty()) { // mChangesList.remove(changes); // } // } // } // // cancelAll(mRemoveAnimations); // cancelAll(mMoveAnimations); // cancelAll(mAddAnimations); // cancelAll(mChangeAnimations); // // dispatchAnimationsFinished(); // } // // private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) { // if (changeInfo.oldHolder != null) { // endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder); // } // if (changeInfo.newHolder != null) { // endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder); // } // } // // void cancelAll(List<ViewHolder> viewHolders) { // for (int i = viewHolders.size() - 1; i >= 0; i--) { // ViewCompat.animate(viewHolders.get(i).itemView).cancel(); // } // } // // @Override // public boolean isRunning() { // return (!mPendingAdditions.isEmpty() || // !mPendingChanges.isEmpty() || // !mPendingMoves.isEmpty() || // !mPendingRemovals.isEmpty() || // !mMoveAnimations.isEmpty() || // !mRemoveAnimations.isEmpty() || // !mAddAnimations.isEmpty() || // !mChangeAnimations.isEmpty() || // !mMovesList.isEmpty() || // !mAdditionsList.isEmpty() || // !mChangesList.isEmpty()); // } // // private void endChangeAnimation(List<ChangeInfo> infoList, ViewHolder item) { // for (int i = infoList.size() - 1; i >= 0; i--) { // ChangeInfo changeInfo = infoList.get(i); // if (endChangeAnimationIfNecessary(changeInfo, item)) { // if (changeInfo.oldHolder == null && changeInfo.newHolder == null) { // infoList.remove(changeInfo); // } // } // } // } // // /** // * Check the state of currently pending and running animations. If there are none // * pending/running, call {@link #dispatchAnimationsFinished()} to notify any // * listeners. // */ // void dispatchFinishedWhenDone() { // if (!isRunning()) { // dispatchAnimationsFinished(); // } // } // // private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) { // boolean oldItem = false; // if (changeInfo.newHolder == item) { // changeInfo.newHolder = null; // } else if (changeInfo.oldHolder == item) { // changeInfo.oldHolder = null; // oldItem = true; // } else { // return false; // } // ViewCompat.setAlpha(item.itemView, 1); // ViewCompat.setTranslationX(item.itemView, 0); // ViewCompat.setTranslationY(item.itemView, 0); // dispatchChangeFinished(item, oldItem); // return true; // } // // private void animateRemoveImpl(final ViewHolder holder) { // final View view = holder.itemView; // final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); // animation.setDuration(getRemoveDuration()) // .alpha(0).setListener(new VpaListenerAdapter() { // @Override // public void onAnimationStart(View view) { // dispatchRemoveStarting(holder); // } // // @Override // public void onAnimationEnd(View view) { // animation.setListener(null); // ViewCompat.setAlpha(view, 1); // dispatchRemoveFinished(holder); // mRemoveAnimations.remove(holder); // dispatchFinishedWhenDone(); // } // }).start(); // mRemoveAnimations.add(holder); // } // // void animateAddImpl(final ViewHolder holder) { // final View view = holder.itemView; // mAddAnimations.add(holder); // final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); // animation.alpha(1).scaleY(1).scaleX(1).setDuration(getAddDuration()). // setListener(new VpaListenerAdapter() { // @Override // public void onAnimationStart(View view) { // dispatchAddStarting(holder); // } // // @Override // public void onAnimationCancel(View view) { // ViewCompat.setAlpha(view, 1); // } // // @Override // public void onAnimationEnd(View view) { // animation.setListener(null); // dispatchAddFinished(holder); // mAddAnimations.remove(holder); // dispatchFinishedWhenDone(); // } // }).start(); // } // // void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { // final View view = holder.itemView; // final int deltaX = toX - fromX; // final int deltaY = toY - fromY; // if (deltaX != 0) { // ViewCompat.animate(view).translationX(0); // } // if (deltaY != 0) { // ViewCompat.animate(view).translationY(0); // } // // TODO: make EndActions end listeners instead, since end actions aren't called when // // vpas are canceled (and can't end them. why?) // // need listener functionality in VPACompat for this. Ick. // mMoveAnimations.add(holder); // final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); // animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() { // @Override // public void onAnimationStart(View view) { // dispatchMoveStarting(holder); // } // // @Override // public void onAnimationCancel(View view) { // if (deltaX != 0) { // ViewCompat.setTranslationX(view, 0); // } // if (deltaY != 0) { // ViewCompat.setTranslationY(view, 0); // } // } // // @Override // public void onAnimationEnd(View view) { // animation.setListener(null); // dispatchMoveFinished(holder); // mMoveAnimations.remove(holder); // dispatchFinishedWhenDone(); // } // }).start(); // } // // void animateChangeImpl(final ChangeInfo changeInfo) { // final ViewHolder holder = changeInfo.oldHolder; // final View view = holder.itemView; // final ViewHolder newHolder = changeInfo.newHolder; // final View newView = newHolder != null ? newHolder.itemView : null; // mChangeAnimations.add(changeInfo.oldHolder); // // final ViewPropertyAnimatorCompat oldViewAnim = ViewCompat.animate(view).setDuration( // getChangeDuration()); // oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX); // oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY); // oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { // @Override // public void onAnimationStart(View view) { // dispatchChangeStarting(changeInfo.oldHolder, true); // } // // @Override // public void onAnimationEnd(View view) { // oldViewAnim.setListener(null); // ViewCompat.setAlpha(view, 1); // ViewCompat.setTranslationX(view, 0); // ViewCompat.setTranslationY(view, 0); // dispatchChangeFinished(changeInfo.oldHolder, true); // mChangeAnimations.remove(changeInfo.oldHolder); // dispatchFinishedWhenDone(); // } // }).start(); // if (newView != null) { // mChangeAnimations.add(changeInfo.newHolder); // final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView); // newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()). // alpha(1).setListener(new VpaListenerAdapter() { // @Override // public void onAnimationStart(View view) { // dispatchChangeStarting(changeInfo.newHolder, false); // } // // @Override // public void onAnimationEnd(View view) { // newViewAnimation.setListener(null); // ViewCompat.setAlpha(newView, 1); // ViewCompat.setTranslationX(newView, 0); // ViewCompat.setTranslationY(newView, 0); // dispatchChangeFinished(changeInfo.newHolder, false); // mChangeAnimations.remove(changeInfo.newHolder); // dispatchFinishedWhenDone(); // } // }).start(); // } // } // // private static class MoveInfo { // // public final ViewHolder holder; // // public final int fromX; // // public final int fromY; // // public final int toX; // // public final int toY; // // MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) { // this.holder = holder; // this.fromX = fromX; // this.fromY = fromY; // this.toX = toX; // this.toY = toY; // } // } // // private static class ChangeInfo { // // public ViewHolder oldHolder, newHolder; // // public int fromX, fromY, toX, toY; // // ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder, // int fromX, int fromY, int toX, int toY) { // this(oldHolder, newHolder); // this.fromX = fromX; // this.fromY = fromY; // this.toX = toX; // this.toY = toY; // } // // private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) { // this.oldHolder = oldHolder; // this.newHolder = newHolder; // } // // @Override // public String toString() { // return "ChangeInfo{" + // "oldHolder=" + oldHolder + // ", newHolder=" + newHolder + // ", fromX=" + fromX + // ", fromY=" + fromY + // ", toX=" + toX + // ", toY=" + toY + // '}'; // } // } // // private static class VpaListenerAdapter implements ViewPropertyAnimatorListener { // // VpaListenerAdapter() { // } // // @Override // public void onAnimationStart(View view) { // } // // @Override // public void onAnimationEnd(View view) { // } // // @Override // public void onAnimationCancel(View view) { // } // } //}