BarInsta/app/src/main/java/awais/instagrabber/customviews/helpers/SwipeAndRestoreItemTouchHel...

185 lines
8.1 KiB
Java

package awais.instagrabber.customviews.helpers;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import awais.instagrabber.R;
import awais.instagrabber.utils.Utils;
/**
* Thanks to https://github.com/izjumovfs/SwipeToReply/blob/master/swipetoreply/src/main/java/com/capybaralabs/swipetoreply/SwipeController.java
*/
public class SwipeAndRestoreItemTouchHelperCallback extends ItemTouchHelper.Callback {
private static final String TAG = "SwipeRestoreCallback";
private final float swipeThreshold;
private final float swipeAutoCancelThreshold;
private final OnSwipeListener onSwipeListener;
private final Drawable replyIcon;
// private final Drawable replyIconBackground;
private final int replyIconShowThreshold;
private final float replyIconMaxTranslation;
private final Rect replyIconBounds = new Rect();
private final float replyIconXOffset;
private final int replyIconSize;
private boolean mSwipeBack = false;
private boolean hasVibrated;
public SwipeAndRestoreItemTouchHelperCallback(final Context context, final OnSwipeListener onSwipeListener) {
this.onSwipeListener = onSwipeListener;
swipeThreshold = Utils.displayMetrics.widthPixels * 0.25f;
swipeAutoCancelThreshold = swipeThreshold + Utils.convertDpToPx(5);
replyIcon = AppCompatResources.getDrawable(context, R.drawable.ic_round_reply_24);
if (replyIcon == null) {
throw new IllegalArgumentException("reply icon is null");
}
replyIcon.setTint(context.getResources().getColor(R.color.white)); //todo need to update according to theme
replyIconShowThreshold = Utils.convertDpToPx(24);
replyIconMaxTranslation = swipeThreshold - replyIconShowThreshold;
// Log.d(TAG, "replyIconShowThreshold: " + replyIconShowThreshold + ", swipeThreshold: " + swipeThreshold);
replyIconSize = replyIconShowThreshold; // Utils.convertDpToPx(24);
replyIconXOffset = swipeThreshold * 0.25f /*Utils.convertDpToPx(20)*/;
}
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
if (!(viewHolder instanceof SwipeableViewHolder)) {
return makeMovementFlags(ItemTouchHelper.ACTION_STATE_IDLE, ItemTouchHelper.ACTION_STATE_IDLE);
}
return makeMovementFlags(ItemTouchHelper.ACTION_STATE_IDLE, ((SwipeableViewHolder) viewHolder).getSwipeDirection());
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull RecyclerView.ViewHolder viewHolder1) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {}
@Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
if (mSwipeBack) {
mSwipeBack = false;
return 0;
}
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
@Override
public void onChildDraw(@NonNull Canvas c,
@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder,
float dX,
float dY,
int actionState,
boolean isCurrentlyActive) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
setTouchListener(recyclerView, viewHolder);
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
drawReplyButton(c, viewHolder);
}
@SuppressLint("ClickableViewAccessibility")
private void setTouchListener(RecyclerView recyclerView, final RecyclerView.ViewHolder viewHolder) {
recyclerView.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (Math.abs(viewHolder.itemView.getTranslationX()) >= swipeAutoCancelThreshold) {
if (!hasVibrated) {
viewHolder.itemView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
hasVibrated = true;
}
// MotionEvent cancelEvent = MotionEvent.obtain(event);
// cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
// recyclerView.dispatchTouchEvent(cancelEvent);
// cancelEvent.recycle();
}
}
mSwipeBack = event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP;
if (mSwipeBack) {
hasVibrated = false;
if (Math.abs(viewHolder.itemView.getTranslationX()) >= swipeThreshold) {
if (onSwipeListener != null) {
onSwipeListener.onSwipe(viewHolder.getBindingAdapterPosition(), viewHolder);
}
}
}
return false;
});
}
public interface SwipeableViewHolder {
int getSwipeDirection();
}
public interface OnSwipeListener {
void onSwipe(final int adapterPosition, final RecyclerView.ViewHolder viewHolder);
}
private void drawReplyButton(Canvas canvas, final RecyclerView.ViewHolder viewHolder) {
if (!(viewHolder instanceof SwipeableViewHolder)) return;
final int swipeDirection = ((SwipeableViewHolder) viewHolder).getSwipeDirection();
if (swipeDirection != ItemTouchHelper.START && swipeDirection != ItemTouchHelper.END) return;
final View view = viewHolder.itemView;
float translationX = view.getTranslationX();
boolean show = false;
float progress;
final float translationXAbs = Math.abs(translationX);
if (translationXAbs >= replyIconShowThreshold) {
show = true;
}
if (show) {
// replyIconShowThreshold -> swipeThreshold <=> progress 0 -> 1
final float replyIconTranslation = translationXAbs - replyIconShowThreshold;
progress = replyIconTranslation / replyIconMaxTranslation;
if (progress > 1) {
progress = 1f;
}
if (progress < 0) {
progress = 0;
}
// Log.d(TAG, /*"translationX: " + translationX + ", replyIconTranslation: " + replyIconTranslation +*/ "progress: " + progress);
} else {
progress = 0f;
// Log.d(TAG, /*"translationX: " + translationX + ", replyIconTranslation: " + 0 +*/ "progress: " + progress);
}
if (progress > 0) {
// calculate the reply icon y position, then offset top, bottom with icon size
final int y = view.getTop() + (view.getMeasuredHeight() / 2);
final int tempIconSize = (int) (replyIconSize * progress);
final int tempIconSizeHalf = tempIconSize / 2;
final int xOffset = (int) (replyIconXOffset * progress);
final int left;
if (swipeDirection == ItemTouchHelper.END) {
// draw arrow of left side
left = xOffset;
} else {
// draw arrow of right side
left = view.getMeasuredWidth() - xOffset - tempIconSize;
}
final int right = tempIconSize + left;
replyIconBounds.set(left, y - tempIconSizeHalf, right, y + tempIconSizeHalf);
replyIcon.setBounds(replyIconBounds);
replyIcon.draw(canvas);
}
}
}