/*
* Copyright (C) 2015 Haruki Hasegawa
*
* 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.h6ah4i.android.widget.advrecyclerview.swipeable;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction;
import com.h6ah4i.android.widget.advrecyclerview.utils.BaseWrapperAdapter;
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils;
import java.util.List;
class SwipeableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends BaseWrapperAdapter<VH> {
private static final String TAG = "ARVSwipeableWrapper";
private interface Constants extends SwipeableItemConstants {
}
private static final int STATE_FLAG_INITIAL_VALUE = -1;
private static final boolean LOCAL_LOGV = false;
private static final boolean LOCAL_LOGD = false;
private SwipeableItemAdapter mSwipeableItemAdapter;
private RecyclerViewSwipeManager mSwipeManager;
private long mSwipingItemId = RecyclerView.NO_ID;
public SwipeableItemWrapperAdapter(RecyclerViewSwipeManager manager, RecyclerView.Adapter<VH> adapter) {
super(adapter);
mSwipeableItemAdapter = WrapperAdapterUtils.findWrappedAdapter(adapter, SwipeableItemAdapter.class);
if (mSwipeableItemAdapter == null) {
throw new IllegalArgumentException("adapter does not implement SwipeableItemAdapter");
}
if (manager == null) {
throw new IllegalArgumentException("manager cannot be null");
}
mSwipeManager = manager;
}
@Override
protected void onRelease() {
super.onRelease();
mSwipeableItemAdapter = null;
mSwipeManager = null;
mSwipingItemId = RecyclerView.NO_ID;
}
@Override
public void onViewRecycled(VH holder, int viewType) {
super.onViewRecycled(holder, viewType);
if ((mSwipingItemId != RecyclerView.NO_ID) && (mSwipingItemId == holder.getItemId())) {
mSwipeManager.cancelSwipe();
}
// reset SwipeableItemViewHolder state
if (holder instanceof SwipeableItemViewHolder) {
if (mSwipeManager != null) {
mSwipeManager.cancelPendingAnimations(holder);
}
SwipeableItemViewHolder swipeableHolder = (SwipeableItemViewHolder) holder;
// reset result and reaction (#262)
swipeableHolder.setSwipeResult(SwipeableItemConstants.RESULT_NONE);
swipeableHolder.setAfterSwipeReaction(SwipeableItemConstants.AFTER_SWIPE_REACTION_DEFAULT);
swipeableHolder.setSwipeItemHorizontalSlideAmount(0);
swipeableHolder.setSwipeItemVerticalSlideAmount(0);
swipeableHolder.setProportionalSwipeAmountModeEnabled(true);
View containerView = SwipeableViewHolderUtils.getSwipeableContainerView(swipeableHolder);
if (containerView != null) {
ViewCompat.animate(containerView).cancel();
ViewCompat.setTranslationX(containerView, 0.0f);
ViewCompat.setTranslationY(containerView, 0.0f);
}
}
}
@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
final VH holder = super.onCreateViewHolder(parent, viewType);
if (holder instanceof SwipeableItemViewHolder) {
((SwipeableItemViewHolder) holder).setSwipeStateFlags(STATE_FLAG_INITIAL_VALUE);
}
return holder;
}
@Override
public void onBindViewHolder(VH holder, int position, List<Object> payloads) {
float prevSwipeItemSlideAmount = 0;
SwipeableItemViewHolder swipeableHolder = (holder instanceof SwipeableItemViewHolder) ? (((SwipeableItemViewHolder) holder)) : null;
if (swipeableHolder != null) {
prevSwipeItemSlideAmount = getSwipeItemSlideAmount(((SwipeableItemViewHolder) holder), swipeHorizontal());
}
if (isSwiping()) {
int flags = Constants.STATE_FLAG_SWIPING;
if (holder.getItemId() == mSwipingItemId) {
flags |= Constants.STATE_FLAG_IS_ACTIVE;
}
safeUpdateFlags(holder, flags);
super.onBindViewHolder(holder, position, payloads);
} else {
safeUpdateFlags(holder, 0);
super.onBindViewHolder(holder, position, payloads);
}
if (swipeableHolder != null) {
final float swipeItemSlideAmount = getSwipeItemSlideAmount(swipeableHolder, swipeHorizontal());
final boolean proportionalAmount = swipeableHolder.isProportionalSwipeAmountModeEnabled();
final boolean isSwiping = mSwipeManager.isSwiping();
final boolean isAnimationRunning = mSwipeManager.isAnimationRunning(holder);
if ((prevSwipeItemSlideAmount != swipeItemSlideAmount) || !(isSwiping || isAnimationRunning)) {
mSwipeManager.applySlideItem(
holder, position,
prevSwipeItemSlideAmount, swipeItemSlideAmount, proportionalAmount,
swipeHorizontal(), true, isSwiping);
}
}
}
@Override
protected void onHandleWrappedAdapterChanged() {
if (isSwiping()) {
cancelSwipe();
}
super.onHandleWrappedAdapterChanged();
}
@Override
protected void onHandleWrappedAdapterItemRangeChanged(int positionStart, int itemCount) {
super.onHandleWrappedAdapterItemRangeChanged(positionStart, itemCount);
}
@Override
protected void onHandleWrappedAdapterItemRangeChanged(int positionStart, int itemCount, Object payload) {
super.onHandleWrappedAdapterItemRangeChanged(positionStart, itemCount, payload);
}
@Override
protected void onHandleWrappedAdapterItemRangeInserted(int positionStart, int itemCount) {
if (isSwiping()) {
int pos = mSwipeManager.getSwipingItemPosition();
if (pos >= positionStart) {
mSwipeManager.syncSwipingItemPosition(pos + itemCount);
}
}
super.onHandleWrappedAdapterItemRangeInserted(positionStart, itemCount);
}
@Override
protected void onHandleWrappedAdapterItemRangeRemoved(int positionStart, int itemCount) {
if (isSwiping()) {
int pos = mSwipeManager.getSwipingItemPosition();
if (checkInRange(pos, positionStart, itemCount)) {
cancelSwipe();
} else if (positionStart < pos) {
mSwipeManager.syncSwipingItemPosition(pos - itemCount);
}
}
super.onHandleWrappedAdapterItemRangeRemoved(positionStart, itemCount);
}
@Override
protected void onHandleWrappedAdapterRangeMoved(int fromPosition, int toPosition, int itemCount) {
if (isSwiping()) {
mSwipeManager.syncSwipingItemPosition();
}
super.onHandleWrappedAdapterRangeMoved(fromPosition, toPosition, itemCount);
}
private void cancelSwipe() {
if (mSwipeManager != null) {
mSwipeManager.cancelSwipe();
}
}
// NOTE: This method is called from RecyclerViewSwipeManager
/*package*/
@SuppressWarnings("unchecked")
int getSwipeReactionType(RecyclerView.ViewHolder holder, int position, int x, int y) {
if (LOCAL_LOGV) {
Log.v(TAG, "getSwipeReactionType(holder = " + holder + ", position = " + position + ", x = " + x + ", y = " + y + ")");
}
return mSwipeableItemAdapter.onGetSwipeReactionType(holder, position, x, y);
}
// NOTE: This method is called from RecyclerViewSwipeManager
/*package*/
@SuppressWarnings("unchecked")
void onUpdateSlideAmount(RecyclerView.ViewHolder holder, int position, float amount, boolean proportionalAmount, boolean horizontal, boolean isSwiping, int type) {
if (LOCAL_LOGV) {
Log.v(TAG, "onUpdateSlideAmount(holder = " + holder +
", position = " + position +
", amount = " + amount +
", proportionalAmount = " + proportionalAmount +
", horizontal = " + horizontal +
", isSwiping = " + isSwiping +
", type = " + type + ")");
}
mSwipeableItemAdapter.onSetSwipeBackground(holder, position, type);
onUpdateSlideAmount(holder, position, amount, proportionalAmount, horizontal, isSwiping);
}
// NOTE: This method is called from ItemSlidingAnimator
/*package*/
@SuppressWarnings("unchecked")
void onUpdateSlideAmount(RecyclerView.ViewHolder holder, int position, float amount, boolean proportionalAmount, boolean horizontal, boolean isSwiping) {
if (LOCAL_LOGV) {
Log.v(TAG, "onUpdateSlideAmount(holder = " + holder +
", position = " + position +
", amount = " + amount +
", proportionalAmount = " + proportionalAmount +
", horizontal = " + horizontal +
", isSwiping = " + isSwiping + ")");
}
SwipeableItemViewHolder holder2 = (SwipeableItemViewHolder) holder;
boolean isItemExpectsProportionalAmount = holder2.isProportionalSwipeAmountModeEnabled();
float adaptedAmount = RecyclerViewSwipeManager.adaptAmount(holder2, horizontal, amount, proportionalAmount, isItemExpectsProportionalAmount);
holder2.onSlideAmountUpdated(
(horizontal ? adaptedAmount : 0.0f), (horizontal ? 0.0f : adaptedAmount), isSwiping);
}
// NOTE: This method is called from RecyclerViewSwipeManager
/*package*/ void onSwipeItemStarted(RecyclerViewSwipeManager manager, RecyclerView.ViewHolder holder, long id) {
if (LOCAL_LOGD) {
Log.d(TAG, "onSwipeItemStarted(holder = " + holder + ", id = " + id + ")");
}
mSwipingItemId = id;
notifyDataSetChanged();
}
// NOTE: This method is called from RecyclerViewSwipeManager
/*package*/
@SuppressWarnings("unchecked")
SwipeResultAction onSwipeItemFinished(RecyclerView.ViewHolder holder, int position, int result) {
if (LOCAL_LOGD) {
Log.d(TAG, "onSwipeItemFinished(holder = " + holder + ", position = " + position + ", result = " + result + ")");
}
mSwipingItemId = RecyclerView.NO_ID;
return mSwipeableItemAdapter.onSwipeItem(holder, position, result);
}
/*package*/
@SuppressWarnings("unchecked")
void onSwipeItemFinished2(RecyclerView.ViewHolder holder, int position, int result, int afterReaction, SwipeResultAction resultAction) {
((SwipeableItemViewHolder) holder).setSwipeResult(result);
((SwipeableItemViewHolder) holder).setAfterSwipeReaction(afterReaction);
if (afterReaction != RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_DO_NOTHING) {
setSwipeItemSlideAmount(
((SwipeableItemViewHolder) holder),
getSwipeAmountFromAfterReaction(result, afterReaction),
swipeHorizontal());
}
resultAction.performAction();
notifyDataSetChanged();
}
protected boolean isSwiping() {
return (mSwipingItemId != RecyclerView.NO_ID);
}
private static boolean checkInRange(int pos, int start, int count) {
return (pos >= start) && (pos < (start + count));
}
private boolean swipeHorizontal() {
return mSwipeManager.swipeHorizontal();
}
private static float getSwipeItemSlideAmount(SwipeableItemViewHolder holder, boolean horizontal) {
if (horizontal) {
return holder.getSwipeItemHorizontalSlideAmount();
} else {
return holder.getSwipeItemVerticalSlideAmount();
}
}
private static void setSwipeItemSlideAmount(SwipeableItemViewHolder holder, float amount, boolean horizontal) {
if (horizontal) {
holder.setSwipeItemHorizontalSlideAmount(amount);
} else {
holder.setSwipeItemVerticalSlideAmount(amount);
}
}
private static float getSwipeAmountFromAfterReaction(int result, int afterReaction) {
switch (afterReaction) {
case RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_MOVE_TO_ORIGIN:
return 0.0f;
case RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_MOVE_TO_SWIPED_DIRECTION:
case RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_REMOVE_ITEM:
switch (result) {
case RecyclerViewSwipeManager.RESULT_SWIPED_LEFT:
return RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_LEFT;
case RecyclerViewSwipeManager.RESULT_SWIPED_RIGHT:
return RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_RIGHT;
case RecyclerViewSwipeManager.RESULT_SWIPED_UP:
return RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_TOP;
case RecyclerViewSwipeManager.RESULT_SWIPED_DOWN:
return RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_BOTTOM;
default:
return 0.0f;
}
default:
return 0.0f;
}
}
private static void safeUpdateFlags(RecyclerView.ViewHolder holder, int flags) {
if (!(holder instanceof SwipeableItemViewHolder)) {
return;
}
final SwipeableItemViewHolder holder2 = (SwipeableItemViewHolder) holder;
final int curFlags = holder2.getSwipeStateFlags();
final int mask = ~Constants.STATE_FLAG_IS_UPDATED;
// append UPDATED flag
if ((curFlags == STATE_FLAG_INITIAL_VALUE) || (((curFlags ^ flags) & mask) != 0)) {
flags |= Constants.STATE_FLAG_IS_UPDATED;
}
((SwipeableItemViewHolder) holder).setSwipeStateFlags(flags);
}
}