diff options
author | Sergei Kozelko <KozelkoS@yandex.ru> | 2022-10-22 06:37:31 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-22 06:37:31 +0000 |
commit | 5e3eaafe268fc64e8c7d92187e6c2447addc410d (patch) | |
tree | 5f2f1a6aa77d1811083f95e32893d6b27384630d /app/src | |
parent | d11fb884c26c739e9e919ec98c1a0990f0953c93 (diff) | |
download | infinity-for-reddit-5e3eaafe268fc64e8c7d92187e6c2447addc410d.tar infinity-for-reddit-5e3eaafe268fc64e8c7d92187e6c2447addc410d.tar.gz infinity-for-reddit-5e3eaafe268fc64e8c7d92187e6c2447addc410d.tar.bz2 infinity-for-reddit-5e3eaafe268fc64e8c7d92187e6c2447addc410d.tar.lz infinity-for-reddit-5e3eaafe268fc64e8c7d92187e6c2447addc410d.tar.xz infinity-for-reddit-5e3eaafe268fc64e8c7d92187e6c2447addc410d.tar.zst infinity-for-reddit-5e3eaafe268fc64e8c7d92187e6c2447addc410d.zip |
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.
Diffstat (limited to 'app/src')
9 files changed, 114 insertions, 43 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java index 782441dc..2ded838c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java @@ -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(); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java index 8f8e902b..6cb65b28 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java @@ -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(); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java index 1782a0a4..1503a469 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java @@ -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 { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java index feaedc98..df2718cf 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java @@ -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(); } }); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java index 05deb6fb..9c9e4411 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java @@ -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(); } })); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java index ad173262..c7d32b93 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java @@ -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(); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/MarkwonLinearLayoutManager.java b/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/MarkwonLinearLayoutManager.java index 35923fa6..73f904c5 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/MarkwonLinearLayoutManager.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/MarkwonLinearLayoutManager.java @@ -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); } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/SwipeLockScrollView.java b/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/SwipeLockScrollView.java new file mode 100644 index 00000000..4b5fc677 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/SwipeLockScrollView.java @@ -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(); + } +} diff --git a/app/src/main/res/layout/adapter_table_block.xml b/app/src/main/res/layout/adapter_table_block.xml index ab8ddfb1..a4adce5f 100644 --- a/app/src/main/res/layout/adapter_table_block.xml +++ b/app/src/main/res/layout/adapter_table_block.xml @@ -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>
\ No newline at end of file +</ml.docilealligator.infinityforreddit.customviews.SwipeLockScrollView> |