Merge 58a5c119cdf5de44d89aef10ffa747128243b3ea into 8b28bd1a184e912b55847b4c31bd6c3e1af4049c

This commit is contained in:
C 2026-02-19 06:02:45 -08:00 committed by GitHub
commit 9466aefe13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 118 additions and 0 deletions

View File

@ -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

View File

@ -231,6 +231,11 @@ public final class PlayerHelper {
.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);

View File

@ -440,6 +440,30 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
//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
//////////////////////////////////////////////////////////////////////////*/

View File

@ -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>

View File

@ -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>

View File

@ -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>