Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand All @@ -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)
Copy link

Choose a reason for hiding this comment

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

Wouldn't it be more generally helpful if it didn't set the speed to 2.0, but to twice the originalPlaybackSpeed? I'm thinking about cases like this:
I'm playing a video on 2.5 speed and then use this feature. I would be very confused if this led to a slower temporary playback speed of 2.0.
For the majority of people only ever watching on 1.0 speed, it would be the exact same behavior as your current PR has.

Copy link
Author

Choose a reason for hiding this comment

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

This is just a copy paste from how the YouTube functionality works and other video services. I think there is some benefit to doing a 2x original source but may be too fast if you're watching at 1.5x and hold to get 3x instead of 2x.

I think just going with the industry standard would be fine imo

Copy link

Choose a reason for hiding this comment

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

On YouTube, the case I mentioned can't occur, though, because their max speed is 2.0.

Copy link
Author

@Car-Role Car-Role Jan 14, 2026

Choose a reason for hiding this comment

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

They just recently added higher speed for premium users. It makes sense too, wanting to increase speed momentarily while above 2x Speed would be exceedingly rare. There is value too in having a consistent known value too I know I will always get 2x speed regardless of which speed I'm currently watching at

Screenshot_20260114-105750.png

Copy link

@graue70 graue70 Jan 14, 2026

Choose a reason for hiding this comment

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

So you're saying that YouTube actually slows down when you do this while being on 3x speed? 😮

Copy link
Author

Choose a reason for hiding this comment

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

I have not verified if it slows down or does nothing but I think this is a pretty extreme edge case


// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,30 @@ 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).
*/
public void onHoldToFastForwardStart() {
// Hide controls while fast forwarding
if (isControlsVisible()) {
hideControls(DEFAULT_CONTROLS_DURATION, 0);
}
}

/**
* Called when hold-to-fast-forward is deactivated (finger released).
*/
public void onHoldToFastForwardEnd() {
// No visual indicator to hide
}
//endregion


/*//////////////////////////////////////////////////////////////////////////
// Broadcast receiver
//////////////////////////////////////////////////////////////////////////*/
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/settings_keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
<string name="clear_queue_confirmation_key">clear_queue_confirmation_key</string>
<string name="ignore_hardware_media_buttons_key">ignore_hardware_media_buttons_key</string>

<string name="hold_to_fast_forward_key">hold_to_fast_forward_key</string>

<string name="popup_saved_width_key">popup_saved_width</string>
<string name="popup_saved_x_key">popup_saved_x</string>
<string name="popup_saved_y_key">popup_saved_y</string>
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@
<string name="clear_queue_confirmation_description">The active player queue will be replaced</string>
<string name="ignore_hardware_media_buttons_title">Ignore hardware media button events</string>
<string name="ignore_hardware_media_buttons_summary">Useful, for instance, if you are using a headset with broken physical buttons</string>
<string name="hold_to_fast_forward_title">Hold to fast forward</string>
<string name="hold_to_fast_forward_summary">Tap and hold on the video to play at 2x speed while held</string>
<string name="show_comments_title">Show comments</string>
<string name="show_comments_summary">Turn off to hide comments</string>
<string name="show_next_and_similar_title">Show \'Next\' and \'Similar\' videos</string>
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/res/xml/video_audio_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,13 @@
android:title="@string/ignore_hardware_media_buttons_title"
app:singleLineTitle="false"
app:iconSpaceReserved="false" />

<SwitchPreferenceCompat
android:defaultValue="true"
android:key="@string/hold_to_fast_forward_key"
android:summary="@string/hold_to_fast_forward_summary"
android:title="@string/hold_to_fast_forward_title"
app:singleLineTitle="false"
app:iconSpaceReserved="false" />
</PreferenceCategory>
</PreferenceScreen>