mirror of https://github.com/KokaKiwi/BarInsta
185 lines
8.1 KiB
Java
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);
|
|
}
|
|
}
|
|
|
|
}
|