mirror of
https://codeberg.org/Bazsalanszky/Infinity-For-Lemmy.git
synced 2024-11-06 18:57:26 +01:00
Add view that can lock swipe-to-close gesture (#1140)
Slidr works by adding its own view in the hierarchy and listening to touch events in `onInterceptTouchEvent`. Once it detects movement in the correct direction, it returns `true` and handles all the events itself. Adding scrollable view detection to Slidr would solve the problem, but it is not possible and would probably have performance impact. Fortunately Slidr does not intercept the very first event, which is ACTION_DOWN, and it reaches scrollable view. So the scrollable view itself can decide if it should disallow the swipe. This also has a performance benefit over `OnScrollChangedListener` because the listener is triggered for every scroll of every view even if the child we are interested in did not scroll. On the other hand `on(Intercept)TouchEvent` is triggered only when the view is touched. There is a possibility that swipe won't be unlocked if view never receives ACTION_UP or ACTION_CANCEL. However the docs say nothing about the probability of this happening. Anyways, one possible solution is to post a runnable that will unlock swipe soon after locking.
This commit is contained in:
parent
d11fb884c2
commit
5e3eaafe26
@ -42,6 +42,7 @@ import ml.docilealligator.infinityforreddit.R;
|
||||
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
|
||||
import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed;
|
||||
import ml.docilealligator.infinityforreddit.customviews.MarkwonLinearLayoutManager;
|
||||
import ml.docilealligator.infinityforreddit.customviews.SwipeLockScrollView;
|
||||
import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent;
|
||||
import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils;
|
||||
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
|
||||
@ -150,16 +151,16 @@ public class FullMarkdownActivity extends BaseActivity {
|
||||
miscPlugin, markdownColor, spoilerBackgroundColor, null);
|
||||
|
||||
MarkwonAdapter markwonAdapter = MarkdownUtils.createTablesAdapter();
|
||||
LinearLayoutManagerBugFixed linearLayoutManager = new MarkwonLinearLayoutManager(this, new MarkwonLinearLayoutManager.HorizontalScrollViewScrolledListener() {
|
||||
LinearLayoutManagerBugFixed linearLayoutManager = new MarkwonLinearLayoutManager(this, new SwipeLockScrollView.SwipeLockInterface() {
|
||||
@Override
|
||||
public void onScrolledLeft() {
|
||||
public void lockSwipe() {
|
||||
if (mSlidrInterface != null) {
|
||||
mSlidrInterface.lock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolledRight() {
|
||||
public void unlockSwipe() {
|
||||
if (mSlidrInterface != null) {
|
||||
mSlidrInterface.unlock();
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ import ml.docilealligator.infinityforreddit.bottomsheetfragments.UrlMenuBottomSh
|
||||
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
|
||||
import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed;
|
||||
import ml.docilealligator.infinityforreddit.customviews.MarkwonLinearLayoutManager;
|
||||
import ml.docilealligator.infinityforreddit.customviews.SwipeLockScrollView;
|
||||
import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent;
|
||||
import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils;
|
||||
import ml.docilealligator.infinityforreddit.utils.JSONUtils;
|
||||
@ -183,16 +184,16 @@ public class WikiActivity extends BaseActivity {
|
||||
miscPlugin, markdownColor, spoilerBackgroundColor, onLinkLongClickListener);
|
||||
|
||||
markwonAdapter = MarkdownUtils.createTablesAdapter();
|
||||
LinearLayoutManagerBugFixed linearLayoutManager = new MarkwonLinearLayoutManager(this, new MarkwonLinearLayoutManager.HorizontalScrollViewScrolledListener() {
|
||||
LinearLayoutManagerBugFixed linearLayoutManager = new MarkwonLinearLayoutManager(this, new SwipeLockScrollView.SwipeLockInterface() {
|
||||
@Override
|
||||
public void onScrolledLeft() {
|
||||
public void lockSwipe() {
|
||||
if (mSlidrInterface != null) {
|
||||
mSlidrInterface.lock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolledRight() {
|
||||
public void unlockSwipe() {
|
||||
if (mSlidrInterface != null) {
|
||||
mSlidrInterface.unlock();
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ import ml.docilealligator.infinityforreddit.customviews.CustomMarkwonAdapter;
|
||||
import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed;
|
||||
import ml.docilealligator.infinityforreddit.customviews.MarkwonLinearLayoutManager;
|
||||
import ml.docilealligator.infinityforreddit.customviews.SpoilerOnClickTextView;
|
||||
import ml.docilealligator.infinityforreddit.customviews.SwipeLockScrollView;
|
||||
import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils;
|
||||
import ml.docilealligator.infinityforreddit.utils.APIUtils;
|
||||
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
|
||||
@ -507,9 +508,9 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment
|
||||
});
|
||||
|
||||
commentMarkdownView.setRecycledViewPool(recycledViewPool);
|
||||
LinearLayoutManagerBugFixed linearLayoutManager = new MarkwonLinearLayoutManager(mActivity, new MarkwonLinearLayoutManager.HorizontalScrollViewScrolledListener() {
|
||||
LinearLayoutManagerBugFixed linearLayoutManager = new MarkwonLinearLayoutManager(mActivity, new SwipeLockScrollView.SwipeLockInterface() {
|
||||
@Override
|
||||
public void onScrolledLeft() {
|
||||
public void lockSwipe() {
|
||||
if (mActivity instanceof AccountSavedThingActivity) {
|
||||
((AccountSavedThingActivity) mActivity).lockSwipeRightToGoBack();
|
||||
} else {
|
||||
@ -518,7 +519,7 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolledRight() {
|
||||
public void unlockSwipe() {
|
||||
if (mActivity instanceof AccountSavedThingActivity) {
|
||||
((AccountSavedThingActivity) mActivity).unlockSwipeRightToGoBack();
|
||||
} else {
|
||||
|
@ -64,6 +64,7 @@ import ml.docilealligator.infinityforreddit.customviews.CustomMarkwonAdapter;
|
||||
import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed;
|
||||
import ml.docilealligator.infinityforreddit.customviews.MarkwonLinearLayoutManager;
|
||||
import ml.docilealligator.infinityforreddit.customviews.SpoilerOnClickTextView;
|
||||
import ml.docilealligator.infinityforreddit.customviews.SwipeLockScrollView;
|
||||
import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment;
|
||||
import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils;
|
||||
import ml.docilealligator.infinityforreddit.post.Post;
|
||||
@ -1240,14 +1241,14 @@ public class CommentsRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerVi
|
||||
}
|
||||
|
||||
commentMarkdownView.setRecycledViewPool(recycledViewPool);
|
||||
LinearLayoutManagerBugFixed linearLayoutManager = new MarkwonLinearLayoutManager(mActivity, new MarkwonLinearLayoutManager.HorizontalScrollViewScrolledListener() {
|
||||
LinearLayoutManagerBugFixed linearLayoutManager = new MarkwonLinearLayoutManager(mActivity, new SwipeLockScrollView.SwipeLockInterface() {
|
||||
@Override
|
||||
public void onScrolledLeft() {
|
||||
public void lockSwipe() {
|
||||
((ViewPostDetailActivity) mActivity).lockSwipeRightToGoBack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolledRight() {
|
||||
public void unlockSwipe() {
|
||||
((ViewPostDetailActivity) mActivity).unlockSwipeRightToGoBack();
|
||||
}
|
||||
});
|
||||
|
@ -89,6 +89,7 @@ import ml.docilealligator.infinityforreddit.bottomsheetfragments.UrlMenuBottomSh
|
||||
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
|
||||
import ml.docilealligator.infinityforreddit.customviews.AspectRatioGifImageView;
|
||||
import ml.docilealligator.infinityforreddit.customviews.MarkwonLinearLayoutManager;
|
||||
import ml.docilealligator.infinityforreddit.customviews.SwipeLockScrollView;
|
||||
import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment;
|
||||
import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils;
|
||||
import ml.docilealligator.infinityforreddit.post.Post;
|
||||
@ -1194,14 +1195,14 @@ public class PostDetailRecyclerViewAdapter extends RecyclerView.Adapter<Recycler
|
||||
mActivity.startActivity(intent);
|
||||
});
|
||||
|
||||
mContentMarkdownView.setLayoutManager(new MarkwonLinearLayoutManager(mActivity, new MarkwonLinearLayoutManager.HorizontalScrollViewScrolledListener() {
|
||||
mContentMarkdownView.setLayoutManager(new MarkwonLinearLayoutManager(mActivity, new SwipeLockScrollView.SwipeLockInterface() {
|
||||
@Override
|
||||
public void onScrolledLeft() {
|
||||
public void lockSwipe() {
|
||||
((ViewPostDetailActivity) mActivity).lockSwipeRightToGoBack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolledRight() {
|
||||
public void unlockSwipe() {
|
||||
((ViewPostDetailActivity) mActivity).unlockSwipeRightToGoBack();
|
||||
}
|
||||
}));
|
||||
|
@ -33,6 +33,7 @@ import ml.docilealligator.infinityforreddit.bottomsheetfragments.UrlMenuBottomSh
|
||||
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
|
||||
import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed;
|
||||
import ml.docilealligator.infinityforreddit.customviews.MarkwonLinearLayoutManager;
|
||||
import ml.docilealligator.infinityforreddit.customviews.SwipeLockScrollView;
|
||||
import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils;
|
||||
import ml.docilealligator.infinityforreddit.utils.Utils;
|
||||
|
||||
@ -146,16 +147,16 @@ public class RulesRecyclerViewAdapter extends RecyclerView.Adapter<RulesRecycler
|
||||
}
|
||||
markwonAdapter = MarkdownUtils.createTablesAdapter();
|
||||
LinearLayoutManagerBugFixed linearLayoutManager = new MarkwonLinearLayoutManager(activity,
|
||||
new MarkwonLinearLayoutManager.HorizontalScrollViewScrolledListener() {
|
||||
new SwipeLockScrollView.SwipeLockInterface() {
|
||||
@Override
|
||||
public void onScrolledLeft() {
|
||||
public void lockSwipe() {
|
||||
if (slidrInterface != null) {
|
||||
slidrInterface.lock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolledRight() {
|
||||
public void unlockSwipe() {
|
||||
if (slidrInterface != null) {
|
||||
slidrInterface.unlock();
|
||||
}
|
||||
|
@ -2,39 +2,25 @@ package ml.docilealligator.infinityforreddit.customviews;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.HorizontalScrollView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class MarkwonLinearLayoutManager extends LinearLayoutManagerBugFixed {
|
||||
public interface HorizontalScrollViewScrolledListener {
|
||||
void onScrolledLeft();
|
||||
void onScrolledRight();
|
||||
}
|
||||
|
||||
private HorizontalScrollViewScrolledListener horizontalScrollViewScrolledListener;
|
||||
@Nullable
|
||||
private final SwipeLockScrollView.SwipeLockInterface swipeLockInterface;
|
||||
|
||||
public MarkwonLinearLayoutManager(Context context, HorizontalScrollViewScrolledListener horizontalScrollViewScrolledListener) {
|
||||
public MarkwonLinearLayoutManager(Context context,
|
||||
@Nullable SwipeLockScrollView.SwipeLockInterface swipeLockInterface) {
|
||||
super(context);
|
||||
this.horizontalScrollViewScrolledListener = horizontalScrollViewScrolledListener;
|
||||
this.swipeLockInterface = swipeLockInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View child) {
|
||||
super.addView(child);
|
||||
if (child instanceof HorizontalScrollView) {
|
||||
child.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
|
||||
private int x = 0;
|
||||
@Override
|
||||
public void onScrollChanged() {
|
||||
if (child.getScrollX() < x) {
|
||||
horizontalScrollViewScrolledListener.onScrolledLeft();
|
||||
} else {
|
||||
horizontalScrollViewScrolledListener.onScrolledRight();
|
||||
}
|
||||
|
||||
x = child.getScrollX();
|
||||
}
|
||||
});
|
||||
if (child instanceof SwipeLockScrollView) {
|
||||
((SwipeLockScrollView) child).setSwipeLockInterface(swipeLockInterface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
package ml.docilealligator.infinityforreddit.customviews;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.HorizontalScrollView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/** {@link HorizontalScrollView} that listens for touch events and locks swipes
|
||||
* if it can be scrolled to the right. {@link SwipeLockInterface} must be set for
|
||||
* locking to work.
|
||||
*/
|
||||
public class SwipeLockScrollView extends HorizontalScrollView {
|
||||
@Nullable
|
||||
private SwipeLockInterface swipeLockInterface = null;
|
||||
private boolean locked = false;
|
||||
|
||||
public SwipeLockScrollView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public SwipeLockScrollView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public SwipeLockScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public void setSwipeLockInterface(@Nullable SwipeLockInterface swipeLockInterface) {
|
||||
this.swipeLockInterface = swipeLockInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
updateSwipeLock(ev);
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility") // we are just listening to touch events
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
updateSwipeLock(ev);
|
||||
return super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks swipe if the view cannot be scrolled right anymore or if {@code ev} is
|
||||
* {@link MotionEvent#ACTION_UP} or {@link MotionEvent#ACTION_CANCEL}
|
||||
*/
|
||||
private void updateSwipeLock(MotionEvent ev) {
|
||||
if (swipeLockInterface != null) {
|
||||
int action = ev.getAction();
|
||||
if (action == MotionEvent.ACTION_UP ||
|
||||
action == MotionEvent.ACTION_CANCEL ||
|
||||
getScrollX() == 0) {
|
||||
// calling SlidrInterface#unlock aborts the swipe
|
||||
// so don't call unlock if it is already unlocked
|
||||
if (locked) {
|
||||
swipeLockInterface.unlockSwipe();
|
||||
locked = false;
|
||||
}
|
||||
} else {
|
||||
if (!locked) {
|
||||
swipeLockInterface.lockSwipe();
|
||||
locked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface SwipeLockInterface {
|
||||
void lockSwipe();
|
||||
void unlockSwipe();
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ml.docilealligator.infinityforreddit.customviews.SwipeLockScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
@ -12,4 +13,4 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:stretchColumns="*" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
</ml.docilealligator.infinityforreddit.customviews.SwipeLockScrollView>
|
||||
|
Loading…
Reference in New Issue
Block a user