feat(YouTube - Swipe controls): Add Speed and seek gestures delay setting to defer horizontal swipe gestures to prevent conflict with pinch-to-zoom
The single-finger horizontal swipe gesture for speed and seek was triggering immediately upon scrolling. This created a race condition where a user attempting to perform a multi-touch pinch-to-zoom would inadvertently trigger a horizontal swipe before the second finger was registered. This change introduces a short time-based delay before a horizontal swipe is confirmed. If a second pointer is detected during this delay, the pending swipe is canceled, allowing the native pinch-to-zoom gesture to proceed without interference.
This commit is contained in:
parent
b73819f5d2
commit
8dfd715a3f
6 changed files with 75 additions and 23 deletions
|
|
@ -578,9 +578,12 @@ public class Settings extends BaseSettings {
|
|||
// PreferenceScreen: Swipe controls
|
||||
public static final BooleanSetting SWIPE_BRIGHTNESS = new BooleanSetting("revanced_swipe_brightness", TRUE, true);
|
||||
public static final BooleanSetting SWIPE_VOLUME = new BooleanSetting("revanced_swipe_volume", TRUE, true);
|
||||
|
||||
public static final BooleanSetting SWIPE_SPEED = new BooleanSetting("revanced_swipe_speed", TRUE, true);
|
||||
public static final BooleanSetting SWIPE_SEEK = new BooleanSetting("revanced_swipe_seek", TRUE, true);
|
||||
public static final BooleanSetting SWIPE_SWITCH_SPEED_AND_SEEK = new BooleanSetting("revanced_swipe_switch_speed_and_seek", FALSE, true);
|
||||
public static final BooleanSetting SWIPE_SWITCH_SPEED_AND_SEEK = new BooleanSetting("revanced_swipe_switch_speed_and_seek", FALSE, true, parentsAny(SWIPE_SPEED, SWIPE_SEEK));
|
||||
public static final LongSetting SWIPE_SPEED_AND_SEEK_DELAY = new LongSetting("revanced_swipe_speed_and_seek_delay", 50L, true, parentsAny(SWIPE_SPEED, SWIPE_SEEK));
|
||||
|
||||
public static final BooleanSetting SWIPE_LOWEST_VALUE_ENABLE_AUTO_BRIGHTNESS = new BooleanSetting("revanced_swipe_lowest_value_enable_auto_brightness", TRUE, true,
|
||||
parent(SWIPE_BRIGHTNESS));
|
||||
public static final BooleanSetting SWIPE_PRESS_TO_ENGAGE = new BooleanSetting("revanced_swipe_press_to_engage", FALSE, true,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package app.revanced.extension.youtube.swipecontrols.controller.gesture
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.MotionEvent
|
||||
import app.revanced.extension.youtube.settings.Settings
|
||||
import app.revanced.extension.youtube.shared.PlayerControlsVisibilityObserver
|
||||
import app.revanced.extension.youtube.shared.PlayerControlsVisibilityObserverImpl
|
||||
import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationProvider
|
||||
|
|
@ -15,6 +18,7 @@ import app.revanced.extension.youtube.swipecontrols.misc.toPoint
|
|||
*
|
||||
* @param controller reference to the main swipe controller
|
||||
*/
|
||||
@Suppress("DEPRECATED_SMARTCAST_ON_DELEGATED_PROPERTY")
|
||||
class ClassicSwipeController(
|
||||
private val controller: SwipeControlsHostActivity,
|
||||
private val config: SwipeControlsConfigurationProvider,
|
||||
|
|
@ -26,6 +30,11 @@ class ClassicSwipeController(
|
|||
*/
|
||||
private var lastOnDownEvent: MotionEvent? = null
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private var horizontalSwipeRunnable: Runnable? = null
|
||||
private var isHorizontalSwipeConfirmed = false
|
||||
private val horizontalSwipeDelayMs = Settings.SWIPE_SPEED_AND_SEEK_DELAY.get()
|
||||
|
||||
override val shouldForceInterceptEvents: Boolean
|
||||
get() = currentSwipe == SwipeDetector.SwipeDirection.VERTICAL
|
||||
|
||||
|
|
@ -56,6 +65,10 @@ class ClassicSwipeController(
|
|||
// ignore gestures with more than one pointer
|
||||
// when such a gesture is detected, dispatch the first event of the gesture to downstream
|
||||
if (motionEvent.pointerCount > 1) {
|
||||
// This is a multitouch gesture (like pinch-to-zoom), so cancel any pending swipe action.
|
||||
cancelHorizontalSwipeRunnable()
|
||||
isHorizontalSwipeConfirmed = false
|
||||
|
||||
lastOnDownEvent?.let {
|
||||
controller.dispatchDownstreamTouchEvent(it)
|
||||
it.recycle()
|
||||
|
|
@ -69,6 +82,9 @@ class ClassicSwipeController(
|
|||
}
|
||||
|
||||
override fun onDown(motionEvent: MotionEvent): Boolean {
|
||||
cancelHorizontalSwipeRunnable()
|
||||
isHorizontalSwipeConfirmed = false
|
||||
|
||||
// save the event for later
|
||||
lastOnDownEvent?.recycle()
|
||||
lastOnDownEvent = MotionEvent.obtain(motionEvent)
|
||||
|
|
@ -77,6 +93,12 @@ class ClassicSwipeController(
|
|||
return isInSwipeZone(motionEvent) || isInHorizontalSwipeZone(motionEvent)
|
||||
}
|
||||
|
||||
override fun onUp(motionEvent: MotionEvent) {
|
||||
super.onUp(motionEvent)
|
||||
cancelHorizontalSwipeRunnable()
|
||||
isHorizontalSwipeConfirmed = false
|
||||
}
|
||||
|
||||
override fun onSingleTapUp(motionEvent: MotionEvent): Boolean {
|
||||
MotionEvent.obtain(motionEvent).let {
|
||||
it.action = MotionEvent.ACTION_DOWN
|
||||
|
|
@ -114,6 +136,9 @@ class ClassicSwipeController(
|
|||
// cancel if locked
|
||||
if (!config.enableSwipeControlsLockMode && config.isScreenLocked) return false
|
||||
if (currentSwipe == SwipeDetector.SwipeDirection.VERTICAL) {
|
||||
cancelHorizontalSwipeRunnable()
|
||||
isHorizontalSwipeConfirmed = false
|
||||
|
||||
return when (from.toPoint()) {
|
||||
in controller.zones.volume -> {
|
||||
scrollVolume(distanceY)
|
||||
|
|
@ -122,31 +147,51 @@ class ClassicSwipeController(
|
|||
|
||||
in controller.zones.brightness -> {
|
||||
scrollBrightness(distanceY)
|
||||
true}
|
||||
|
||||
|
||||
else -> false
|
||||
}
|
||||
} else if (currentSwipe == SwipeDetector.SwipeDirection.HORIZONTAL) {
|
||||
return when (from.toPoint()) {
|
||||
in controller.zones.speed -> {
|
||||
if (config.enableSpeedControl) {
|
||||
scrollSpeed(distanceX)
|
||||
true
|
||||
}
|
||||
false
|
||||
true
|
||||
}
|
||||
in controller.zones.seek -> {
|
||||
if (config.enableSeekControl) {
|
||||
scrollSeek(distanceX)
|
||||
true
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
else if (currentSwipe == SwipeDetector.SwipeDirection.HORIZONTAL) {
|
||||
if (isHorizontalSwipeConfirmed) {
|
||||
return processHorizontalSwipe(from, distanceX)
|
||||
}
|
||||
|
||||
if (horizontalSwipeRunnable == null) {
|
||||
horizontalSwipeRunnable = Runnable {
|
||||
isHorizontalSwipeConfirmed = true
|
||||
processHorizontalSwipe(from, distanceX)
|
||||
}
|
||||
handler.postDelayed(horizontalSwipeRunnable!!, horizontalSwipeDelayMs)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun processHorizontalSwipe(from: MotionEvent, distanceX: Double): Boolean {
|
||||
return when (from.toPoint()) {
|
||||
in controller.zones.speed -> {
|
||||
if (config.enableSpeedControl) {
|
||||
scrollSpeed(distanceX)
|
||||
true
|
||||
} else false
|
||||
}
|
||||
in controller.zones.seek -> {
|
||||
if (config.enableSeekControl) {
|
||||
scrollSeek(distanceX)
|
||||
true
|
||||
} else false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelHorizontalSwipeRunnable() {
|
||||
horizontalSwipeRunnable?.let {
|
||||
handler.removeCallbacks(it)
|
||||
}
|
||||
horizontalSwipeRunnable = null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -481,7 +481,6 @@ private val emptyTitles = setOf(
|
|||
"revanced_external_downloader_package_name_playlist",
|
||||
"revanced_external_downloader_package_name_video",
|
||||
"revanced_external_downloader_package_name_video_long_press",
|
||||
"revanced_fix_swipe_tap_and_hold_speed",
|
||||
"revanced_gemini_transcribe_subtitles_font_size",
|
||||
"revanced_gms_show_dialog",
|
||||
"revanced_hide_live_chat_replay_button",
|
||||
|
|
@ -524,6 +523,7 @@ private val emptyTitles = setOf(
|
|||
"revanced_swipe_overlay_progress_speed_color",
|
||||
"revanced_swipe_overlay_progress_volume_color",
|
||||
"revanced_swipe_seek_distance",
|
||||
"revanced_swipe_speed_and_seek_delay",
|
||||
"revanced_swipe_speed_distance",
|
||||
"revanced_swipe_switch_speed_and_seek",
|
||||
"revanced_swipe_volume_distance",
|
||||
|
|
|
|||
|
|
@ -2662,6 +2662,8 @@ Adjust brightness by swiping vertically on the left side of the screen."</string
|
|||
|
||||
Seek the video by swiping horizontally on the top half of the screen."</string>
|
||||
<string name="revanced_swipe_seek_title">Enable seek gesture</string>
|
||||
<string name="revanced_swipe_speed_and_seek_delay_summary">The delay in milliseconds before a horizontal swipe is recognized. Increase this value if it interferes with the pinch-to-zoom gesture.</string>
|
||||
<string name="revanced_swipe_speed_and_seek_delay_title">Speed and seek gestures delay</string>
|
||||
<string name="revanced_swipe_speed_distance_summary">The amount of pixels to swipe to change the video speed. Lower values make the speed change faster, higher values make it slower (1-1000).</string>
|
||||
<string name="revanced_swipe_speed_distance_title">Speed distance</string>
|
||||
<string name="revanced_swipe_speed_summary_off">Fullscreen speed swipe is disabled.</string>
|
||||
|
|
|
|||
|
|
@ -779,6 +779,7 @@
|
|||
<app.revanced.extension.shared.settings.preference.ResettableEditTextPreference android:title="@string/revanced_swipe_seek_distance_title" android:key="revanced_swipe_seek_distance" android:summary="@string/revanced_swipe_seek_distance_summary" android:inputType="number" />
|
||||
|
||||
<SwitchPreference android:title="@string/revanced_swipe_switch_speed_and_seek_title" android:key="revanced_swipe_switch_speed_and_seek" android:summaryOn="@string/revanced_swipe_switch_speed_and_seek_summary_on" android:summaryOff="@string/revanced_swipe_switch_speed_and_seek_summary_off" />
|
||||
<app.revanced.extension.shared.settings.preference.ResettableEditTextPreference android:title="@string/revanced_swipe_speed_and_seek_delay_title" android:key="revanced_swipe_speed_and_seek_delay" android:summary="@string/revanced_swipe_speed_and_seek_delay_summary" android:inputType="number" />
|
||||
|
||||
<SwitchPreference android:title="@string/revanced_swipe_press_to_engage_title" android:key="revanced_swipe_press_to_engage" android:summaryOn="@string/revanced_swipe_press_to_engage_summary_on" android:summaryOff="@string/revanced_swipe_press_to_engage_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_swipe_haptic_feedback_title" android:key="revanced_swipe_haptic_feedback" android:summaryOn="@string/revanced_swipe_haptic_feedback_summary_on" android:summaryOff="@string/revanced_swipe_haptic_feedback_summary_off" />
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ BLACKLIST: set[str] = {
|
|||
"revanced_swipe_seek_sensitivity",
|
||||
"revanced_swipe_show_circular_overlay",
|
||||
"revanced_swipe_speed",
|
||||
"revanced_swipe_speed_and_seek_delay",
|
||||
"revanced_swipe_speed_distance",
|
||||
"revanced_swipe_speed_sensitivity",
|
||||
"revanced_swipe_switch_speed_and_seek",
|
||||
|
|
|
|||
Loading…
Reference in a new issue