diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java
index edb768524..ac6c9f7bc 100644
--- a/app/src/main/java/org/schabi/newpipe/player/Player.java
+++ b/app/src/main/java/org/schabi/newpipe/player/Player.java
@@ -893,6 +893,10 @@ public float getPlaybackPitch() {
return getPlaybackParameters().pitch;
}
+ public void setPlaybackPitch(final float pitch) {
+ setPlaybackParameters(getPlaybackSpeed(), pitch, getPlaybackSkipSilence());
+ }
+
public boolean getPlaybackSkipSilence() {
return !exoPlayerIsNull() && simpleExoPlayer.getSkipSilenceEnabled();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt
index ff0bb269d..f96713633 100644
--- a/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt
@@ -14,10 +14,13 @@ import org.schabi.newpipe.ktx.AnimationType
import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.player.Player
import org.schabi.newpipe.player.helper.AudioReactor
+import org.schabi.newpipe.player.helper.PlaybackParameterDialog
import org.schabi.newpipe.player.helper.PlayerHelper
+import org.schabi.newpipe.player.helper.PlayerSemitoneHelper
import org.schabi.newpipe.player.ui.MainPlayerUi
import org.schabi.newpipe.util.ThemeHelper.getAndroidDimenPx
import kotlin.math.abs
+import kotlin.math.roundToInt
/**
* GestureListener for the player
@@ -102,6 +105,7 @@ class MainPlayerGestureListener(
binding.volumeRelativeLayout.animate(true, 200, AnimationType.SCALE_AND_ALPHA)
}
binding.brightnessRelativeLayout.isVisible = false
+ binding.playbackSpeedRelativeLayout.isVisible = false
}
private fun onScrollBrightness(distanceY: Float) {
@@ -147,6 +151,50 @@ class MainPlayerGestureListener(
binding.brightnessRelativeLayout.animate(true, 200, AnimationType.SCALE_AND_ALPHA)
}
binding.volumeRelativeLayout.isVisible = false
+ binding.playbackSpeedRelativeLayout.isVisible = false
+ }
+
+ private fun onScrollPlaybackSpeed(distanceY: Float) {
+ val bar: ProgressBar = binding.playbackSpeedProgressBar
+ val maxPlaybackSpeed: Float = PlaybackParameterDialog.getMaxPitchOrSpeed()
+ val minPlaybackSpeed: Float = PlaybackParameterDialog.getMinPitchOrSpeed()
+ val playbackSpeedStep: Float = PlaybackParameterDialog.getCurrentStepSize(player.context) / maxPlaybackSpeed
+
+ // If we just started sliding, change the progress bar to match the current playback speed
+ if (!binding.playbackSpeedRelativeLayout.isVisible) {
+ val playbackSpeedPercent: Float = player.playbackSpeed / maxPlaybackSpeed
+ bar.progress = (playbackSpeedPercent * bar.max).toInt()
+ }
+
+ // Update progress bar
+ bar.incrementProgressBy(distanceY.toInt())
+
+ // Update playback speed
+ val currentProgressPercent: Float = (bar.progress / bar.max.toFloat() / playbackSpeedStep).roundToInt() * playbackSpeedStep
+ val currentPlaybackSpeed: Float = (currentProgressPercent * maxPlaybackSpeed).coerceIn(minPlaybackSpeed, maxPlaybackSpeed)
+
+ player.playbackSpeed = currentPlaybackSpeed
+ if (!PlaybackParameterDialog.getPlaybackUnhooked(player.context)) {
+ if (!PlaybackParameterDialog.getPitchControlModeSemitone(player.context)) {
+ player.playbackPitch = currentPlaybackSpeed
+ } else {
+ player.playbackPitch = PlayerSemitoneHelper.semitonesToPercent(PlayerSemitoneHelper.percentToSemitones(currentPlaybackSpeed.toDouble())).toFloat()
+ }
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "onScroll().playbackSpeedControl, currentPlaybackSpeed = $currentPlaybackSpeed")
+ }
+
+ // Update player center image
+ binding.playbackSpeedTextView.text = PlayerHelper.formatSpeed(currentPlaybackSpeed.toDouble())
+
+ // Make sure the correct layout is visible
+ if (!binding.playbackSpeedRelativeLayout.isVisible) {
+ binding.playbackSpeedRelativeLayout.animate(true, 200, AnimationType.SCALE_AND_ALPHA)
+ }
+ binding.brightnessRelativeLayout.isVisible = false
+ binding.volumeRelativeLayout.isVisible = false
}
override fun onScrollEnd(event: MotionEvent) {
@@ -157,6 +205,9 @@ class MainPlayerGestureListener(
if (binding.brightnessRelativeLayout.isVisible) {
binding.brightnessRelativeLayout.animate(false, 200, AnimationType.SCALE_AND_ALPHA, 200)
}
+ if (binding.playbackSpeedRelativeLayout.isVisible) {
+ binding.playbackSpeedRelativeLayout.animate(false, 200, AnimationType.SCALE_AND_ALPHA, 200)
+ }
}
override fun onScroll(
@@ -190,30 +241,42 @@ class MainPlayerGestureListener(
isMoving = true
- // -- Brightness and Volume control --
- if (getDisplayHalfPortion(initialEvent) == DisplayPortion.RIGHT_HALF) {
+ // -- Brightness Volume and Tempo control --
+ if (getDisplayPortion(initialEvent) == DisplayPortion.RIGHT) {
when (PlayerHelper.getActionForRightGestureSide(player.context)) {
player.context.getString(R.string.volume_control_key) ->
onScrollVolume(distanceY)
player.context.getString(R.string.brightness_control_key) ->
onScrollBrightness(distanceY)
+ player.context.getString(R.string.playback_speed_control_key) ->
+ onScrollPlaybackSpeed(distanceY)
}
- } else {
+ } else if (getDisplayPortion(initialEvent) == DisplayPortion.LEFT) {
when (PlayerHelper.getActionForLeftGestureSide(player.context)) {
player.context.getString(R.string.volume_control_key) ->
onScrollVolume(distanceY)
player.context.getString(R.string.brightness_control_key) ->
onScrollBrightness(distanceY)
+ player.context.getString(R.string.playback_speed_control_key) ->
+ onScrollPlaybackSpeed(distanceY)
+ }
+ } else {
+ when (PlayerHelper.getActionForMiddleGestureSide(player.context)) {
+ player.context.getString(R.string.volume_control_key) ->
+ onScrollVolume(distanceY)
+ player.context.getString(R.string.brightness_control_key) ->
+ onScrollBrightness(distanceY)
+ player.context.getString(R.string.playback_speed_control_key) ->
+ onScrollPlaybackSpeed(distanceY)
}
}
-
return true
}
override fun getDisplayPortion(e: MotionEvent): DisplayPortion {
return when {
- e.x < binding.root.width / 3.0 -> DisplayPortion.LEFT
- e.x > binding.root.width * 2.0 / 3.0 -> DisplayPortion.RIGHT
+ e.x < binding.root.width * 0.3 -> DisplayPortion.LEFT
+ e.x > binding.root.width * 0.7 -> DisplayPortion.RIGHT
else -> DisplayPortion.MIDDLE
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java
index 7e74c3848..06fc64074 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java
@@ -60,7 +60,7 @@ public class PlaybackParameterDialog extends DialogFragment {
private static final double DEFAULT_PITCH_PERCENT = 1.00f;
private static final double DEFAULT_STEP = STEP_25_PERCENT_VALUE;
private static final boolean DEFAULT_SKIP_SILENCE = false;
-
+ private static final boolean DEFAULT_PLAYBACK_UNHOOK = false;
private static final SliderStrategy QUADRATIC_STRATEGY = new SliderStrategy.Quadratic(
MIN_PITCH_OR_SPEED,
MAX_PITCH_OR_SPEED,
@@ -261,7 +261,7 @@ private void initUI() {
bindCheckboxWithBoolPref(
binding.unhookCheckbox,
R.string.playback_unhook_key,
- true,
+ DEFAULT_PLAYBACK_UNHOOK,
isChecked -> {
if (!isChecked) {
// when unchecked, slide back to the minimum of current tempo or pitch
@@ -590,6 +590,32 @@ private static String getPercentString(final double percent) {
return PlayerHelper.formatPitch(percent);
}
+
+ public static boolean getPlaybackUnhooked(final Context context) {
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getBoolean(context.getString(R.string.playback_unhook_key),
+ DEFAULT_PLAYBACK_UNHOOK);
+ }
+
+ public static boolean getPitchControlModeSemitone(final Context context) {
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getBoolean(context.getString(R.string.playback_adjust_by_semitones_key),
+ PITCH_CTRL_MODE_PERCENT);
+ }
+
+ public static float getCurrentStepSize(final Context context) {
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getFloat(context.getString(R.string.adjustment_step_key), (float) DEFAULT_STEP);
+ }
+
+ public static float getMinPitchOrSpeed() {
+ return (float) MIN_PITCH_OR_SPEED;
+ }
+
+ public static float getMaxPitchOrSpeed() {
+ return (float) MAX_PITCH_OR_SPEED;
+ }
+
public interface Callback {
void onPlaybackParameterChanged(float playbackTempo, float playbackPitch,
boolean playbackSkipSilence);
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 a110a80d6..6a51bdbea 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
@@ -234,6 +234,12 @@ public static String getActionForRightGestureSide(@NonNull final Context context
context.getString(R.string.default_right_gesture_control_value));
}
+ public static String getActionForMiddleGestureSide(@NonNull final Context context) {
+ return getPreferences(context)
+ .getString(context.getString(R.string.middle_gesture_control_key),
+ context.getString(R.string.default_middle_gesture_control_value));
+ }
+
public static String getActionForLeftGestureSide(@NonNull final Context context) {
return getPreferences(context)
.getString(context.getString(R.string.left_gesture_control_key),
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
index d8efb30df..065f019a9 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
@@ -551,6 +551,7 @@ public void onLayoutChange(final View view, final int l, final int t, final int
binding.volumeProgressBar.setMax(maxGestureLength);
binding.brightnessProgressBar.setMax(maxGestureLength);
+ binding.playbackSpeedProgressBar.setMax(maxGestureLength);
setInitialGestureValues();
binding.itemsListPanel.getLayoutParams().height =
diff --git a/app/src/main/res/layout/player.xml b/app/src/main/res/layout/player.xml
index bad22dd1e..d491d03a2 100644
--- a/app/src/main/res/layout/player.xml
+++ b/app/src/main/res/layout/player.xml
@@ -758,6 +758,34 @@
tools:src="@drawable/ic_brightness_high" />
+
+
+
+
+
+
+