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 49e72328e40..555cf380883 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -176,6 +176,10 @@ public final class Player implements PlaybackListener, Listener { public static final int RENDERER_UNAVAILABLE = -1; private static final String PICASSO_PLAYER_THUMBNAIL_TAG = "PICASSO_PLAYER_THUMBNAIL_TAG"; + public static final int DEFAULT_PREV_NEXT_MODE = 0; + public static final int SMART_PREV_NEXT_MODE = 1; + public static final int SEEK_PREV_NEXT_MODE = 2; + /*////////////////////////////////////////////////////////////////////////// // Playback //////////////////////////////////////////////////////////////////////////*/ @@ -222,6 +226,8 @@ public final class Player implements PlaybackListener, Listener { private PlayerType playerType = PlayerType.MAIN; private int currentState = STATE_PREFLIGHT; + private int queueActionsArePrevNext = DEFAULT_PREV_NEXT_MODE; + // audio only mode does not mean that player type is background, but that the player was // minimized to background but will resume automatically to the original player type private boolean isAudioOnly = false; @@ -1719,6 +1725,40 @@ public void fastRewind() { seekBy(-retrieveSeekDurationFromPreferences(this)); triggerProgressUpdate(); } + + public void playerActionNext() { + switch (queueActionsArePrevNext) { + case SMART_PREV_NEXT_MODE: + if (playQueue != null && playQueue.size() > 1) { + playNext(); + } else { + fastForward(); + } + break; + case SEEK_PREV_NEXT_MODE: + fastForward(); + break; + default: + playNext(); + } + } + + public void playerActionPrevious() { + switch (queueActionsArePrevNext) { + case SMART_PREV_NEXT_MODE: + if (playQueue != null && playQueue.size() > 1) { + playPrevious(); + } else { + fastRewind(); + } + break; + case SEEK_PREV_NEXT_MODE: + fastRewind(); + break; + default: + playPrevious(); + } + } //endregion @@ -2237,6 +2277,9 @@ public void setAudioTrack(@Nullable final String audioTrackId) { reloadPlayQueueManager(); } + public void setQueueActionsPrevNext(final int state) { + queueActionsArePrevNext = state; + } @NonNull public Context getContext() { diff --git a/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java index 737ebc5dd04..47979622fab 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java @@ -42,6 +42,13 @@ public class MediaSessionPlayerUi extends PlayerUi private MediaSessionConnector sessionConnector; private final String ignoreHardwareMediaButtonsKey; + + private final String prevNextButtonModeKey; + + private final String smartModeKey; + + private final String fwRwModeKey; + private boolean shouldIgnoreHardwareMediaButtons = false; // used to check whether any notification action changed, before sending costly updates @@ -52,6 +59,9 @@ public MediaSessionPlayerUi(@NonNull final Player player) { super(player); ignoreHardwareMediaButtonsKey = context.getString(R.string.ignore_hardware_media_buttons_key); + prevNextButtonModeKey = context.getString(R.string.prev_next_button_mode_key); + smartModeKey = context.getString(R.string.prev_next_mode_smart_key); + fwRwModeKey = context.getString(R.string.prev_next_mode_seek_key); } @Override @@ -73,6 +83,7 @@ public void initPlayer() { // listen to changes to ignore_hardware_media_buttons_key updateShouldIgnoreHardwareMediaButtons(player.getPrefs()); + updatePrevNextMode(player.getPrefs()); player.getPrefs().registerOnSharedPreferenceChangeListener(this); sessionConnector.setMetadataDeduplicationEnabled(true); @@ -114,8 +125,14 @@ public void onThumbnailLoaded(@Nullable final Bitmap bitmap) { @Override public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { - if (key == null || key.equals(ignoreHardwareMediaButtonsKey)) { + if (key == null) { + updateShouldIgnoreHardwareMediaButtons(sharedPreferences); + updatePrevNextMode(sharedPreferences); + } else if (key.equals(ignoreHardwareMediaButtonsKey)) { updateShouldIgnoreHardwareMediaButtons(sharedPreferences); + + } else if (key.equals(prevNextButtonModeKey)) { + updatePrevNextMode(sharedPreferences); } } @@ -124,6 +141,18 @@ public void updateShouldIgnoreHardwareMediaButtons(final SharedPreferences share sharedPreferences.getBoolean(ignoreHardwareMediaButtonsKey, false); } + public void updatePrevNextMode(final SharedPreferences sharedPreferences) { + + final var modeString = sharedPreferences.getString(prevNextButtonModeKey, ""); + int prevNextButtonMode = Player.DEFAULT_PREV_NEXT_MODE; + if (modeString.equals(smartModeKey)) { + prevNextButtonMode = Player.SMART_PREV_NEXT_MODE; + } else if (modeString.equals(fwRwModeKey)) { + prevNextButtonMode = Player.SEEK_PREV_NEXT_MODE; + } + player.setQueueActionsPrevNext(prevNextButtonMode); + } + public void handleMediaButtonIntent(final Intent intent) { MediaButtonReceiver.handleIntent(mediaSession, intent); diff --git a/app/src/main/java/org/schabi/newpipe/player/mediasession/PlayQueueNavigator.java b/app/src/main/java/org/schabi/newpipe/player/mediasession/PlayQueueNavigator.java index 3339869c129..7f15f440c79 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediasession/PlayQueueNavigator.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediasession/PlayQueueNavigator.java @@ -73,7 +73,7 @@ public long getActiveQueueItemId( @Override public void onSkipToPrevious(@NonNull final com.google.android.exoplayer2.Player exoPlayer) { - player.playPrevious(); + player.playerActionPrevious(); } @Override @@ -86,7 +86,7 @@ public void onSkipToQueueItem(@NonNull final com.google.android.exoplayer2.Playe @Override public void onSkipToNext(@NonNull final com.google.android.exoplayer2.Player exoPlayer) { - player.playNext(); + player.playerActionNext(); } private void publishFloatingQueueWindow() { diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index fb68a464d5a..69290250738 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -24,6 +24,7 @@ screen_brightness_timestamp_key clear_queue_confirmation_key ignore_hardware_media_buttons_key + prev_next_button_mode_key popup_saved_width popup_saved_x @@ -229,6 +230,22 @@ @string/none_control_key + prev_next_button_mode + @string/prev_next_mode_default_key + default_mode + seek_mode + smart_mode + + @string/prev_next_mode_default + @string/prev_next_mode_seek + @string/prev_next_mode_smart + + + @string/prev_next_mode_default_key + @string/prev_next_mode_seek_key + @string/prev_next_mode_smart_key + + prefer_original_audio prefer_descriptive_audio last_resize_mode diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 56140441cd0..e7afc117351 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -857,4 +857,9 @@ Show more Show less The settings in the export being imported use a vulnerable format that was deprecated since NewPipe 0.27.0. Make sure the export being imported is from a trusted source, and prefer using only exports obtained from NewPipe 0.27.0 or newer in the future. Support for importing settings in this vulnerable format will soon be removed completely, and then old versions of NewPipe will not be able to import settings of exports from new versions anymore. + Previous/Next button behavior + Previous/Next headset and notification mode behavior + Next/Previous track + Smart Next/Prev or Fw/Rw + Forward/Rewind diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml index 727ce4df40a..652124f3648 100644 --- a/app/src/main/res/xml/video_audio_settings.xml +++ b/app/src/main/res/xml/video_audio_settings.xml @@ -144,6 +144,16 @@ app:singleLineTitle="false" app:iconSpaceReserved="false" /> + +