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..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 @@ -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 //////////////////////////////////////////////////////////////////////////*/ 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..8c877cc56d6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -91,6 +91,8 @@ 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 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" /> + +