From 6eba36700a389fe85615afe69dd556cc60f71a57 Mon Sep 17 00:00:00 2001 From: Carl Miller Date: Thu, 27 Nov 2025 22:45:56 -0600 Subject: [PATCH 1/2] feat: Add hold-to-fast-forward (2x speed) feature - Add tap and hold gesture to increase playback speed to 2x while held - Add settings toggle in Video & Audio settings to enable/disable the feature - Add visual indicator overlay showing '2x Speed' when feature is active - Feature is enabled by default and respects user preference --- .../gesture/BasePlayerGestureListener.kt | 77 +++++++++++++++++++ .../newpipe/player/helper/PlayerHelper.java | 5 ++ .../newpipe/player/ui/VideoPlayerUi.java | 27 +++++++ app/src/main/res/drawable/ic_fast_forward.xml | 10 +++ app/src/main/res/layout/player.xml | 36 +++++++++ app/src/main/res/values/settings_keys.xml | 2 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/xml/video_audio_settings.xml | 8 ++ 8 files changed, 168 insertions(+) create mode 100644 app/src/main/res/drawable/ic_fast_forward.xml diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt index 0453f297a4f..4c6d658cf88 100644 --- a/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt +++ b/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt @@ -9,6 +9,7 @@ import android.view.View import androidx.core.os.postDelayed import org.schabi.newpipe.databinding.PlayerBinding import org.schabi.newpipe.player.Player +import org.schabi.newpipe.player.helper.PlayerHelper import org.schabi.newpipe.player.ui.VideoPlayerUi /** @@ -24,11 +25,87 @@ abstract class BasePlayerGestureListener( protected val player: Player = playerUi.player protected val binding: PlayerBinding = playerUi.binding + // /////////////////////////////////////////////////////////////////// + // Hold to fast forward (2x speed) + // /////////////////////////////////////////////////////////////////// + + private var isHoldingForFastForward = false + private var originalPlaybackSpeed = 1.0f + private val fastForwardSpeed = 2.0f + override fun onTouch(v: View, event: MotionEvent): Boolean { playerUi.gestureDetector.onTouchEvent(event) + + // Handle touch up to restore original speed when hold-to-fast-forward is active + if (event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL) { + if (isHoldingForFastForward) { + stopHoldToFastForward() + } + } + return false } + override fun onLongPress(e: MotionEvent) { + if (DEBUG) { + Log.d(TAG, "onLongPress called with e = [$e]") + } + + // Check if hold-to-fast-forward is enabled in settings + if (!PlayerHelper.isHoldToFastForwardEnabled(player.context)) { + return + } + + // Only activate if player is playing and not in a popup menu + if (player.currentState != Player.STATE_PLAYING || playerUi.isSomePopupMenuVisible) { + return + } + + // Don't activate during double tap mode + if (isDoubleTapping) { + return + } + + startHoldToFastForward() + } + + private fun startHoldToFastForward() { + if (isHoldingForFastForward) { + return + } + + if (DEBUG) { + Log.d(TAG, "startHoldToFastForward: activating 2x speed") + } + + isHoldingForFastForward = true + originalPlaybackSpeed = player.playbackSpeed + + // Set playback speed to 2x + player.setPlaybackSpeed(fastForwardSpeed) + + // Show visual feedback + playerUi.onHoldToFastForwardStart() + } + + private fun stopHoldToFastForward() { + if (!isHoldingForFastForward) { + return + } + + if (DEBUG) { + Log.d(TAG, "stopHoldToFastForward: restoring original speed $originalPlaybackSpeed") + } + + isHoldingForFastForward = false + + // Restore original playback speed + player.setPlaybackSpeed(originalPlaybackSpeed) + + // Hide visual feedback + playerUi.onHoldToFastForwardEnd() + } + private fun onDoubleTap( event: MotionEvent, portion: DisplayPortion diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java index c335e9b7c60..c02948c1783 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java @@ -231,6 +231,11 @@ public static boolean isAutoQueueEnabled(@NonNull final Context context) { .getBoolean(context.getString(R.string.auto_queue_key), false); } + public static boolean isHoldToFastForwardEnabled(@NonNull final Context context) { + return getPreferences(context) + .getBoolean(context.getString(R.string.hold_to_fast_forward_key), true); + } + public static boolean isClearingQueueConfirmationRequired(@NonNull final Context context) { return getPreferences(context) .getBoolean(context.getString(R.string.clear_queue_confirmation_key), false); diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java index 59be1d67dcc..383c491571f 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java @@ -441,6 +441,33 @@ protected void setupElementsSize(final int buttonsMinWidth, //endregion + /*////////////////////////////////////////////////////////////////////////// + // Hold to fast forward + //////////////////////////////////////////////////////////////////////////*/ + //region Hold to fast forward + + /** + * Called when hold-to-fast-forward is activated (long press detected). + * Shows the visual indicator overlay. + */ + public void onHoldToFastForwardStart() { + animate(binding.holdToFastForwardOverlay, true, DEFAULT_CONTROLS_DURATION); + // Hide controls while fast forwarding + if (isControlsVisible()) { + hideControls(DEFAULT_CONTROLS_DURATION, 0); + } + } + + /** + * Called when hold-to-fast-forward is deactivated (finger released). + * Hides the visual indicator overlay. + */ + public void onHoldToFastForwardEnd() { + animate(binding.holdToFastForwardOverlay, false, DEFAULT_CONTROLS_DURATION); + } + //endregion + + /*////////////////////////////////////////////////////////////////////////// // Broadcast receiver //////////////////////////////////////////////////////////////////////////*/ diff --git a/app/src/main/res/drawable/ic_fast_forward.xml b/app/src/main/res/drawable/ic_fast_forward.xml new file mode 100644 index 00000000000..1e029dd0efa --- /dev/null +++ b/app/src/main/res/drawable/ic_fast_forward.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/player.xml b/app/src/main/res/layout/player.xml index 94c16ad702f..0c4dc6c9c4c 100644 --- a/app/src/main/res/layout/player.xml +++ b/app/src/main/res/layout/player.xml @@ -809,4 +809,40 @@ android:alpha="0" android:visibility="invisible" /> + + + + + + + + + diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index d95d1270cc9..f7b5237ee45 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -25,6 +25,8 @@ clear_queue_confirmation_key ignore_hardware_media_buttons_key + hold_to_fast_forward_key + popup_saved_width popup_saved_x popup_saved_y diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c439f19e272..cd2c27b0e3c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -91,6 +91,9 @@ The active player queue will be replaced Ignore hardware media button events Useful, for instance, if you are using a headset with broken physical buttons + Hold to fast forward + Tap and hold on the video to play at 2x speed while held + 2x Speed Show comments Turn off to hide comments Show \'Next\' and \'Similar\' videos diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml index 727ce4df40a..b24b034beac 100644 --- a/app/src/main/res/xml/video_audio_settings.xml +++ b/app/src/main/res/xml/video_audio_settings.xml @@ -249,5 +249,13 @@ android:title="@string/ignore_hardware_media_buttons_title" app:singleLineTitle="false" app:iconSpaceReserved="false" /> + + From 58a5c119cdf5de44d89aef10ffa747128243b3ea Mon Sep 17 00:00:00 2001 From: Carl Miller Date: Thu, 27 Nov 2025 22:54:55 -0600 Subject: [PATCH 2/2] refactor: Remove 2x speed overlay text from hold-to-fast-forward feature --- .../newpipe/player/ui/VideoPlayerUi.java | 5 +-- app/src/main/res/drawable/ic_fast_forward.xml | 10 ------ app/src/main/res/layout/player.xml | 36 ------------------- app/src/main/res/values/strings.xml | 1 - 4 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 app/src/main/res/drawable/ic_fast_forward.xml diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java index 383c491571f..669193c7ed6 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java @@ -448,10 +448,8 @@ protected void setupElementsSize(final int buttonsMinWidth, /** * Called when hold-to-fast-forward is activated (long press detected). - * Shows the visual indicator overlay. */ public void onHoldToFastForwardStart() { - animate(binding.holdToFastForwardOverlay, true, DEFAULT_CONTROLS_DURATION); // Hide controls while fast forwarding if (isControlsVisible()) { hideControls(DEFAULT_CONTROLS_DURATION, 0); @@ -460,10 +458,9 @@ public void onHoldToFastForwardStart() { /** * Called when hold-to-fast-forward is deactivated (finger released). - * Hides the visual indicator overlay. */ public void onHoldToFastForwardEnd() { - animate(binding.holdToFastForwardOverlay, false, DEFAULT_CONTROLS_DURATION); + // No visual indicator to hide } //endregion diff --git a/app/src/main/res/drawable/ic_fast_forward.xml b/app/src/main/res/drawable/ic_fast_forward.xml deleted file mode 100644 index 1e029dd0efa..00000000000 --- a/app/src/main/res/drawable/ic_fast_forward.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/layout/player.xml b/app/src/main/res/layout/player.xml index 0c4dc6c9c4c..94c16ad702f 100644 --- a/app/src/main/res/layout/player.xml +++ b/app/src/main/res/layout/player.xml @@ -809,40 +809,4 @@ android:alpha="0" android:visibility="invisible" /> - - - - - - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cd2c27b0e3c..8c877cc56d6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -93,7 +93,6 @@ Useful, for instance, if you are using a headset with broken physical buttons Hold to fast forward Tap and hold on the video to play at 2x speed while held - 2x Speed Show comments Turn off to hide comments Show \'Next\' and \'Similar\' videos