/*
* 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.utils.BaseWrapperAdapter;
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils;
class SwipeableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends BaseWrapperAdapter<VH> {
private static final String TAG = "ARVSwipeableWrapper";
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 int mSwipingItemPosition = RecyclerView.NO_POSITION;
public SwipeableItemWrapperAdapter(RecyclerViewSwipeManager manager, RecyclerView.Adapter<VH> adapter) {
super(adapter);
mSwipeableItemAdapter = getSwipeableItemAdapter(adapter);
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;
mSwipingItemPosition = RecyclerView.NO_POSITION;
}
@Override
public void onViewRecycled(VH holder) {
super.onViewRecycled(holder);
// reset SwipeableItemViewHolder state
if (holder instanceof SwipeableItemViewHolder) {
mSwipeManager.cancelPendingAnimations(holder);
((SwipeableItemViewHolder) holder).setSwipeItemSlideAmount(0.0f);
View containerView = ((SwipeableItemViewHolder) holder).getSwipeableContainerView();
if (containerView != null) {
ViewCompat.animate(containerView).cancel();
ViewCompat.setTranslationX(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) {
float prevSwipeItemSlideAmount = 0;
if (holder instanceof SwipeableItemViewHolder) {
prevSwipeItemSlideAmount = ((SwipeableItemViewHolder) holder).getSwipeItemSlideAmount();
}
if (isSwiping()) {
int flags = RecyclerViewSwipeManager.STATE_FLAG_SWIPING;
if (position == mSwipingItemPosition) {
flags |= RecyclerViewSwipeManager.STATE_FLAG_IS_ACTIVE;
}
safeUpdateFlags(holder, flags);
super.onBindViewHolder(holder, position);
} else {
safeUpdateFlags(holder, 0);
super.onBindViewHolder(holder, position);
}
if (holder instanceof SwipeableItemViewHolder) {
final float swipeItemSlideAmount = ((SwipeableItemViewHolder) holder).getSwipeItemSlideAmount();
if ((prevSwipeItemSlideAmount != swipeItemSlideAmount) ||
!(mSwipeManager.isSwiping() || mSwipeManager.isAnimationRunning(holder))) {
mSwipeManager.applySlideItem(holder, position, prevSwipeItemSlideAmount, swipeItemSlideAmount, true);
}
}
}
@Override
protected void onHandleWrappedAdapterChanged() {
if (isSwiping()) {
cancelSwipe();
} else {
super.onHandleWrappedAdapterChanged();
}
}
@Override
protected void onHandleWrappedAdapterItemRangeChanged(int positionStart, int itemCount) {
if (isSwiping()) {
cancelSwipe();
} else {
super.onHandleWrappedAdapterItemRangeChanged(positionStart, itemCount);
}
}
@Override
protected void onHandleWrappedAdapterItemRangeInserted(int positionStart, int itemCount) {
if (isSwiping()) {
cancelSwipe();
} else {
super.onHandleWrappedAdapterItemRangeInserted(positionStart, itemCount);
}
}
@Override
protected void onHandleWrappedAdapterItemRangeRemoved(int positionStart, int itemCount) {
if (isSwiping()) {
cancelSwipe();
} else {
super.onHandleWrappedAdapterItemRangeRemoved(positionStart, itemCount);
}
}
@Override
protected void onHandleWrappedAdapterRangeMoved(int fromPosition, int toPosition, int itemCount) {
if (isSwiping()) {
cancelSwipe();
} else {
super.onHandleWrappedAdapterRangeMoved(fromPosition, toPosition, itemCount);
}
}
private void cancelSwipe() {
if (mSwipeManager != null) {
mSwipeManager.cancelSwipe();
}
}
// NOTE: This method is called from RecyclerViewDragDropManager
/*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 RecyclerViewDragDropManager
/*package*/
@SuppressWarnings("unchecked")
void setSwipeBackgroundDrawable(RecyclerView.ViewHolder holder, int position, int type) {
if (LOCAL_LOGV) {
Log.v(TAG, "setSwipeBackgroundDrawable(holder = " + holder + ", position = " + position + ", type = " + type + ")");
}
mSwipeableItemAdapter.onSetSwipeBackground(holder, position, type);
}
// NOTE: This method is called from RecyclerViewDragDropManager
/*package*/ void onSwipeItemStarted(RecyclerViewSwipeManager manager, RecyclerView.ViewHolder holder, int position) {
if (LOCAL_LOGD) {
Log.d(TAG, "onSwipeItemStarted(holder = " + holder + ", position = " + position + ")");
}
mSwipingItemPosition = position;
notifyDataSetChanged();
}
// NOTE: This method is called from RecyclerViewDragDropManager
/*package*/
@SuppressWarnings("unchecked")
int onSwipeItemFinished(RecyclerView.ViewHolder holder, int position, int result) {
if (LOCAL_LOGD) {
Log.d(TAG, "onSwipeItemFinished(holder = " + holder + ", position = " + position + ", result = " + result + ")");
}
mSwipingItemPosition = RecyclerView.NO_POSITION;
return mSwipeableItemAdapter.onSwipeItem(holder, position, result);
}
/*package*/
@SuppressWarnings("unchecked")
void onSwipeItemFinished2(RecyclerView.ViewHolder holder, int position, int result, int afterReaction) {
((SwipeableItemViewHolder) holder).setSwipeResult(result);
((SwipeableItemViewHolder) holder).setAfterSwipeReaction(afterReaction);
((SwipeableItemViewHolder) holder).setSwipeItemSlideAmount(getSwipeAmountFromAfterReaction(result, afterReaction));
mSwipeableItemAdapter.onPerformAfterSwipeReaction(holder, position, result, afterReaction);
notifyDataSetChanged();
}
protected boolean isSwiping() {
return (mSwipingItemPosition != RecyclerView.NO_POSITION);
}
private static float getSwipeAmountFromAfterReaction(int result, int afterReaction) {
switch (afterReaction) {
case RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_DEFAULT:
return 0.0f;
case RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_MOVE_TO_SWIPED_DIRECTION:
case RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_REMOVE_ITEM:
return (result == RecyclerViewSwipeManager.RESULT_SWIPED_LEFT)
? RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_LEFT
: RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_RIGHT;
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 = ~RecyclerViewSwipeManager.STATE_FLAG_IS_UPDATED;
// append UPDATED flag
if ((curFlags == STATE_FLAG_INITIAL_VALUE) || (((curFlags ^ flags) & mask) != 0)) {
flags |= RecyclerViewSwipeManager.STATE_FLAG_IS_UPDATED;
}
((SwipeableItemViewHolder) holder).setSwipeStateFlags(flags);
}
private static SwipeableItemAdapter getSwipeableItemAdapter(RecyclerView.Adapter adapter) {
return WrapperAdapterUtils.findWrappedAdapter(adapter, SwipeableItemAdapter.class);
}
}