Skip to content

Commit

Permalink
Reduce horizontal swipe sensitivity in timelines (#3148)
Browse files Browse the repository at this point in the history
* Reduce horizontal swipe sensitivity in timelines

Fixes #2725, fixes #2112, fixes #2530, fixes #2200, fixes #2176, fixes #2112, fixes #1912, fixes #1718, fixes #1336

* Set scale factor to 4

* Catch exceptions, just in case
  • Loading branch information
Nik Clayton committed Jan 13, 2023
1 parent e5e076b commit d6e7905
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 0 deletions.
3 changes: 3 additions & 0 deletions app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import com.keylesspalace.tusky.util.deleteStaleCachedMedia
import com.keylesspalace.tusky.util.emojify
import com.keylesspalace.tusky.util.getDimension
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.reduceSwipeSensitivity
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.updateShortcut
import com.keylesspalace.tusky.util.viewBinding
Expand Down Expand Up @@ -253,6 +254,8 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
}
}

binding.viewPager.reduceSwipeSensitivity()

setupDrawer(savedInstanceState, addSearchButton = hideTopToolbar)

/* Fetch user info while we're doing other things. This has to be done after setting up the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import com.keylesspalace.tusky.util.getDomain
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.loadAvatar
import com.keylesspalace.tusky.util.parseAsMastodonHtml
import com.keylesspalace.tusky.util.reduceSwipeSensitivity
import com.keylesspalace.tusky.util.setClickableText
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.viewBinding
Expand Down Expand Up @@ -235,6 +236,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
// Setup the tabs and timeline pager.
adapter = AccountPagerAdapter(this, viewModel.accountId)

binding.accountFragmentViewPager.reduceSwipeSensitivity()
binding.accountFragmentViewPager.adapter = adapter
binding.accountFragmentViewPager.offscreenPageLimit = 2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.keylesspalace.tusky.components.search.adapter.SearchPagerAdapter
import com.keylesspalace.tusky.databinding.ActivitySearchBinding
import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.reduceSwipeSensitivity
import com.keylesspalace.tusky.util.viewBinding
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
Expand Down Expand Up @@ -62,6 +63,7 @@ class SearchActivity : BottomSheetActivity(), HasAndroidInjector {
}

private fun setupPages() {
binding.pages.reduceSwipeSensitivity()
binding.pages.adapter = SearchPagerAdapter(this)

val enableSwipeForTabs = preferences.getBoolean(PrefKeys.ENABLE_SWIPE_FOR_TABS, true)
Expand Down
37 changes: 37 additions & 0 deletions app/src/main/java/com/keylesspalace/tusky/util/ViewExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ package com.keylesspalace.tusky.util

import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.View
import android.widget.EditText
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2

fun View.show() {
this.visibility = View.VISIBLE
Expand Down Expand Up @@ -63,3 +66,37 @@ inline fun EditText.afterTextChanged(
}
})
}

/**
* Reduce ViewPager2's sensitivity to horizontal swipes.
*/
fun ViewPager2.reduceSwipeSensitivity() {
// ViewPager2 is very sensitive to horizontal motion when swiping vertically, and will
// trigger a page transition if the user's swipe is only a few tens of degrees off from
// vertical. This is a problem if the underlying content is a list that the user wants
// to scroll vertically -- it's far too easy to trigger an accidental horizontal swipe.
//
// One way to stop this is to reach in to ViewPager2's RecyclerView and adjust the amount
// of touch slop it has. Scaling by 2 appears to work well.
//
// See https://issuetracker.google.com/issues/139867645 and
// https://bladecoder.medium.com/fixing-recyclerview-nested-scrolling-in-opposite-direction-f587be5c1a04
// for more (the approach in that Medium article works, but is still quite sensitive to
// horizontal movement while scrolling).
try {
val recyclerViewField = ViewPager2::class.java.getDeclaredField("mRecyclerView")
recyclerViewField.isAccessible = true
val recyclerView = recyclerViewField.get(this) as RecyclerView

val touchSlopField = RecyclerView::class.java.getDeclaredField("mTouchSlop")
touchSlopField.isAccessible = true
val touchSlop = touchSlopField.get(recyclerView) as Int
// 4 seems to be a sweet-spot. 2-3 still causes a horizontal swipe right if the user drags
// down-left at ~ 45 degree angle. Experimentally, 4 requires the swipe to be +/- ~ 10 degrees
// from horizontal to register as a horizontal and not a vertical swipe.
val scaleFactor = 4
touchSlopField.set(recyclerView, touchSlop * scaleFactor)
} catch (e: Exception) {
Log.w("reduceSwipeSensitivity", e)
}
}

1 comment on commit d6e7905

@fin-w
Copy link
Contributor

@fin-w fin-w commented on d6e7905 Feb 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this has made the swipe left/right need to be very close to horizontal (+/- 10 degrees according to the comments in the code)

on v21 beta 2, this is too restrictive to use naturally and i frequently struggle to switch tabs as a result

can i recommend increasing the angle to +/- 25 degrees or so? i can understand preferring swipe up/down over left/right, but this change seems too far the other way for my use case

Please sign in to comment.