diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 919fc5170..1c74e521f 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -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, diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/ClassicSwipeController.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/ClassicSwipeController.kt index aedff61c9..8d8793197 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/ClassicSwipeController.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/ClassicSwipeController.kt @@ -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 + } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/visual/VisualPreferencesIconsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/visual/VisualPreferencesIconsPatch.kt index 6ab977380..5bd86fa31 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/visual/VisualPreferencesIconsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/visual/VisualPreferencesIconsPatch.kt @@ -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", diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index ecdab1561..70c700422 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -2662,6 +2662,8 @@ Adjust brightness by swiping vertically on the left side of the screen." Enable seek gesture + The delay in milliseconds before a horizontal swipe is recognized. Increase this value if it interferes with the pinch-to-zoom gesture. + Speed and seek gestures delay 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). Speed distance Fullscreen speed swipe is disabled. diff --git a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml index e702d7273..7f72e876b 100644 --- a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -779,6 +779,7 @@ + diff --git a/xml_tools/handlers/check_prefs_reverse.py b/xml_tools/handlers/check_prefs_reverse.py index a9e463183..b0911b81f 100644 --- a/xml_tools/handlers/check_prefs_reverse.py +++ b/xml_tools/handlers/check_prefs_reverse.py @@ -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",