Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to adjust playback speed (tempo) via gesture on main player screen #24

Merged
merged 4 commits into from
Jan 21, 2025
Merged
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
12 changes: 5 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ on:
branches:
- dev
- master
- extended
- '**-feature-**'
paths-ignore:
- 'README.md'
- 'doc/**'
Expand All @@ -36,13 +38,9 @@ jobs:
permissions: write-all

steps:
- name: Checkout branch "${{ github.ref_name }}"
env:
BRANCH: ${{ github.ref_name }}
run: |
git clone --no-checkout https://github.com/MaintainTeam/LastPipeBender.git .
git checkout --progress --force "$BRANCH"

- name: Checkout
uses: actions/checkout@v4

- name: Set up JDK
uses: actions/setup-java@v4
with:
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/org/schabi/newpipe/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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(
Expand Down Expand Up @@ -190,23 +241,35 @@ 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
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +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 = true;

private static final SliderStrategy QUADRATIC_STRATEGY = new SliderStrategy.Quadratic(
MIN_PITCH_OR_SPEED,
Expand Down Expand Up @@ -261,7 +262,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
Expand Down Expand Up @@ -590,6 +591,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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,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 =
Expand Down
28 changes: 28 additions & 0 deletions app/src/main/res/layout/player.xml
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,34 @@
tools:src="@drawable/ic_brightness_high" />
</RelativeLayout>

<RelativeLayout
android:id="@+id/playbackSpeedRelativeLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/background_oval_black_transparent"
android:visibility="gone"
tools:visibility="visible">

<ProgressBar
android:id="@+id/playbackSpeedProgressBar"
style="?android:progressBarStyleHorizontal"
android:layout_width="128dp"
android:layout_height="128dp"
android:indeterminate="false"
android:progressDrawable="@drawable/progress_circular_white" />

<TextView
android:id="@+id/playbackSpeedTextView"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_centerInParent="true"
android:gravity="center"
android:textColor="@color/white"
android:textSize="18sp"
tools:ignore="ContentDescription" />
</RelativeLayout>

<RelativeLayout
android:id="@+id/unskipButton"
android:visibility="gone"
Expand Down
6 changes: 4 additions & 2 deletions app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -729,8 +729,9 @@
<string name="feed_show_upcoming">Demnächst</string>
<string name="feed_show_watched">Vollständig angeschaut</string>
<string name="feed_show_partially_watched">Teilweise angeschaut</string>
<string name="left_gesture_control_summary">Geste für die linke Hälfte des Player-Bildschirms auswählen</string>
<string name="right_gesture_control_summary">Geste für die rechte Hälfte des Player-Bildschirms auswählen</string>
<string name="left_gesture_control_summary">Geste für den linken Teil des Player-Bildschirms auswählen</string>
<string name="middle_gesture_control_title">Mittlere Gestenaktion</string>
asandikci marked this conversation as resolved.
Show resolved Hide resolved
<string name="right_gesture_control_summary">Geste für den rechten Teil des Player-Bildschirms auswählen</string>
<string name="none">Keine</string>
<string name="right_gesture_control_title">Rechte Gestenaktion</string>
<string name="left_gesture_control_title">Linke Gestenaktion</string>
Expand Down Expand Up @@ -826,4 +827,5 @@
\nMöchtest du wirklich fortfahren?</string>
<string name="import_settings_vulnerable_format">Die Einstellungen in dem zu importierenden Export verwenden ein angreifbares Format, das seit NewPipe 0.27.0 veraltet ist. Stellen Sie sicher, dass der zu importierende Export aus einer vertrauenswürdigen Quelle stammt, und verwenden Sie in Zukunft nur noch Exporte, die aus NewPipe 0.27.0 oder neuer stammen. Die Unterstützung für den Import von Einstellungen in diesem angreifbaren Format wird bald vollständig entfernt werden, und dann werden alte Versionen von NewPipe nicht mehr in der Lage sein, Einstellungen von Exporten aus neuen Versionen zu importieren.</string>
<string name="audio_track_type_secondary">Sekundär</string>
<string name="middle_gesture_control_summary">Geste für den mittleren Teil des Player-Bildschirms auswählen</string>
</resources>
24 changes: 22 additions & 2 deletions app/src/main/res/values/settings_keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -204,28 +204,48 @@
<string name="default_left_gesture_control_value">@string/brightness_control_key</string>
<string name="brightness_control_key">brightness_control</string>
<string name="volume_control_key">volume_control</string>
<string name="playback_speed_control_key">playback_speed_control</string>
<string name="none_control_key">none_control</string>
<string-array name="left_gesture_control_description">
<item>@string/brightness</item>
<item>@string/volume</item>
<item>@string/playback_tempo</item>
<item>@string/none</item>
</string-array>
<string-array name="left_gesture_control_values">
<item>@string/brightness_control_key</item>
<item>@string/volume_control_key</item>
<item>@string/playback_speed_control_key</item>
<item>@string/none_control_key</item>
</string-array>

<string name="middle_gesture_control_key">middle_gesture_control</string>
<string name="default_middle_gesture_control_value">@string/playback_speed_control_key</string>
<string-array name="middle_gesture_control_description">
<item>@string/brightness</item>
<item>@string/volume</item>
<item>@string/playback_tempo</item>
<item>@string/none</item>
</string-array>
<string-array name="middle_gesture_control_values">
<item>@string/brightness_control_key</item>
<item>@string/volume_control_key</item>
<item>@string/playback_speed_control_key</item>
<item>@string/none_control_key</item>
</string-array>

<string name="right_gesture_control_key">right_gesture_control</string>
<string name="default_right_gesture_control_value">@string/volume_control_key</string>
<string-array name="right_gesture_control_description">
<item>@string/volume</item>
<item>@string/brightness</item>
<item>@string/volume</item>
<item>@string/playback_tempo</item>
<item>@string/none</item>
</string-array>
<string-array name="right_gesture_control_values">
<item>@string/volume_control_key</item>
<item>@string/brightness_control_key</item>
<item>@string/volume_control_key</item>
<item>@string/playback_speed_control_key</item>
<item>@string/none_control_key</item>
</string-array>

Expand Down
6 changes: 4 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,11 @@
<string name="auto_queue_title">Auto-enqueue next stream</string>
<string name="auto_queue_summary">Continue ending (non-repeating) playback queue by appending a related stream</string>
<string name="auto_queue_toggle">Auto-enqueuing</string>
<string name="left_gesture_control_summary">Choose gesture for left half of player screen</string>
<string name="left_gesture_control_summary">Choose gesture for left part of player screen</string>
<string name="left_gesture_control_title">Left gesture action</string>
<string name="right_gesture_control_summary">Choose gesture for right half of player screen</string>
<string name="middle_gesture_control_summary">Choose gesture for middle part of player screen</string>
<string name="middle_gesture_control_title">Middle gesture action</string>
asandikci marked this conversation as resolved.
Show resolved Hide resolved
<string name="right_gesture_control_summary">Choose gesture for right part of player screen</string>
<string name="right_gesture_control_title">Right gesture action</string>
<string name="brightness">Brightness</string>
<string name="volume">Volume</string>
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/xml/video_audio_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,16 @@
app:singleLineTitle="false"
app:iconSpaceReserved="false" />

<ListPreference
android:defaultValue="@string/default_middle_gesture_control_value"
android:entries="@array/middle_gesture_control_description"
android:entryValues="@array/middle_gesture_control_values"
android:key="@string/middle_gesture_control_key"
android:summary="@string/middle_gesture_control_summary"
android:title="@string/middle_gesture_control_title"
app:singleLineTitle="false"
app:iconSpaceReserved="false" />

<ListPreference
android:defaultValue="@string/default_right_gesture_control_value"
android:entries="@array/right_gesture_control_description"
Expand Down
Loading