1
0
Fork 0
mirror of https://github.com/TeamNewPipe/NewPipe.git synced 2025-10-03 09:49:21 +02:00

Merge pull request #12615 from Isira-Seneviratne/Player-intent-refactor

Refactor player intent logic
This commit is contained in:
Profpatsch 2025-09-09 10:24:42 +02:00 committed by GitHub
commit 45c22c0db8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 39 additions and 83 deletions

View file

@ -61,6 +61,7 @@ import android.view.LayoutInflater;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.content.IntentCompat;
import androidx.core.math.MathUtils; import androidx.core.math.MathUtils;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@ -127,6 +128,7 @@ import org.schabi.newpipe.util.StreamTypeUtil;
import org.schabi.newpipe.util.image.PicassoHelper; import org.schabi.newpipe.util.image.PicassoHelper;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -351,25 +353,17 @@ public final class Player implements PlaybackListener, Listener {
@SuppressWarnings("MethodLength") @SuppressWarnings("MethodLength")
public void handleIntent(@NonNull final Intent intent) { public void handleIntent(@NonNull final Intent intent) {
final var playerIntentType = IntentCompat.getSerializableExtra(intent, PLAYER_INTENT_TYPE,
final PlayerIntentType playerIntentType = intent.getParcelableExtra(PLAYER_INTENT_TYPE); PlayerIntentType.class);
if (playerIntentType == null) { if (playerIntentType == null) {
return; return;
} }
final PlayerType newPlayerType;
// TODO: this should be in the second switch below, but Im not sure whether I // TODO: this should be in the second switch below, but Im not sure whether I
// can move the initUIs stuff without breaking the setup for edge cases somehow. // can move the initUIs stuff without breaking the setup for edge cases somehow.
switch (playerIntentType) { // when playing from a timestamp, keep the current player as-is.
case TimestampChange -> { if (playerIntentType != PlayerIntentType.TimestampChange) {
// when playing from a timestamp, keep the current player as-is. playerType = IntentCompat.getSerializableExtra(intent, PLAYER_TYPE, PlayerType.class);
newPlayerType = playerType;
}
default -> {
newPlayerType = PlayerType.retrieveFromIntent(intent);
}
} }
playerType = newPlayerType;
initUIsForCurrentPlayerType(); initUIsForCurrentPlayerType();
isAudioOnly = audioPlayerSelected(); isAudioOnly = audioPlayerSelected();
@ -410,15 +404,15 @@ public final class Player implements PlaybackListener, Listener {
break; break;
} }
case TimestampChange -> { case TimestampChange -> {
final TimestampChangeData dat = intent.getParcelableExtra(PLAYER_INTENT_DATA); final var data = Objects.requireNonNull(IntentCompat.getParcelableExtra(intent,
assert dat != null; PLAYER_INTENT_DATA, TimestampChangeData.class));
final Single<StreamInfo> single = final Single<StreamInfo> single =
ExtractorHelper.getStreamInfo(dat.getServiceId(), dat.getUrl(), false); ExtractorHelper.getStreamInfo(data.getServiceId(), data.getUrl(), false);
streamItemDisposable.add(single.subscribeOn(Schedulers.io()) streamItemDisposable.add(single.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(info -> { .subscribe(info -> {
final @Nullable PlayQueue oldPlayQueue = playQueue; final @Nullable PlayQueue oldPlayQueue = playQueue;
info.setStartPosition(dat.getSeconds()); info.setStartPosition(data.getSeconds());
final PlayQueueItem playQueueItem = new PlayQueueItem(info); final PlayQueueItem playQueueItem = new PlayQueueItem(info);
// If the stream is already playing, // If the stream is already playing,
@ -432,7 +426,7 @@ public final class Player implements PlaybackListener, Listener {
simpleExoPlayer.prepare(); simpleExoPlayer.prepare();
} }
simpleExoPlayer.seekTo(oldPlayQueue.getIndex(), simpleExoPlayer.seekTo(oldPlayQueue.getIndex(),
dat.getSeconds() * 1000L); data.getSeconds() * 1000L);
simpleExoPlayer.setPlayWhenReady(playWhenReady); simpleExoPlayer.setPlayWhenReady(playWhenReady);
} else { } else {
@ -456,9 +450,9 @@ public final class Player implements PlaybackListener, Listener {
// This will only show a snackbar if the passed context has a root view: // This will only show a snackbar if the passed context has a root view:
// otherwise it will resort to showing a notification, so we are safe // otherwise it will resort to showing a notification, so we are safe
// here. // here.
ErrorUtil.createNotification(context, final var info = new ErrorInfo(throwable, UserAction.PLAY_ON_POPUP,
new ErrorInfo(throwable, UserAction.PLAY_ON_POPUP, dat.getUrl(), data.getUrl(), null, data.getUrl());
null, dat.getUrl())); ErrorUtil.createNotification(context, info);
})); }));
return; return;
} }

View file

@ -6,9 +6,7 @@ import kotlinx.parcelize.Parcelize
// We model this as an enum class plus one struct for each enum value // We model this as an enum class plus one struct for each enum value
// so we can consume it from Java properly. After converting to Kotlin, // so we can consume it from Java properly. After converting to Kotlin,
// we could switch to a sealed enum class & a proper Kotlin `when` match. // we could switch to a sealed enum class & a proper Kotlin `when` match.
enum class PlayerIntentType {
@Parcelize
enum class PlayerIntentType : Parcelable {
Enqueue, Enqueue,
EnqueueNext, EnqueueNext,
TimestampChange, TimestampChange,

View file

@ -1,32 +1,7 @@
package org.schabi.newpipe.player; package org.schabi.newpipe.player;
import static org.schabi.newpipe.player.Player.PLAYER_TYPE;
import android.content.Intent;
public enum PlayerType { public enum PlayerType {
MAIN, MAIN,
AUDIO, AUDIO,
POPUP; POPUP;
/**
* @return an integer representing this {@link PlayerType}, to be used to save it in intents
* @see #retrieveFromIntent(Intent) Use retrieveFromIntent() to retrieve and convert player type
* integers from an intent
*/
public int valueForIntent() {
return ordinal();
}
/**
* @param intent the intent to retrieve a player type from
* @return the player type integer retrieved from the intent, converted back into a {@link
* PlayerType}, or {@link PlayerType#MAIN} if there is no player type extra in the
* intent
* @throws ArrayIndexOutOfBoundsException if the intent contains an invalid player type integer
* @see #valueForIntent() Use valueForIntent() to obtain valid player type integers
*/
public static PlayerType retrieveFromIntent(final Intent intent) {
return values()[intent.getIntExtra(PLAYER_TYPE, MAIN.valueForIntent())];
}
} }

View file

@ -9,7 +9,6 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Parcelable;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
@ -70,6 +69,7 @@ import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.external_communication.ShareUtils; import org.schabi.newpipe.util.external_communication.ShareUtils;
import java.util.List; import java.util.List;
import java.util.Optional;
public final class NavigationHelper { public final class NavigationHelper {
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag"; public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
@ -89,31 +89,22 @@ public final class NavigationHelper {
@NonNull final Class<T> targetClazz, @NonNull final Class<T> targetClazz,
@Nullable final PlayQueue playQueue, @Nullable final PlayQueue playQueue,
@NonNull final PlayerIntentType playerIntentType) { @NonNull final PlayerIntentType playerIntentType) {
final Intent intent = new Intent(context, targetClazz); final String cacheKey = Optional.ofNullable(playQueue)
.map(queue -> SerializedCache.getInstance().put(queue, PlayQueue.class))
if (playQueue != null) { .orElse(null);
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class); return new Intent(context, targetClazz)
if (cacheKey != null) { .putExtra(Player.PLAY_QUEUE_KEY, cacheKey)
intent.putExtra(Player.PLAY_QUEUE_KEY, cacheKey); .putExtra(Player.PLAYER_TYPE, PlayerType.MAIN)
} .putExtra(PlayerService.SHOULD_START_FOREGROUND_EXTRA, true)
} .putExtra(Player.PLAYER_INTENT_TYPE, playerIntentType);
intent.putExtra(Player.PLAYER_TYPE, PlayerType.MAIN.valueForIntent());
intent.putExtra(PlayerService.SHOULD_START_FOREGROUND_EXTRA, true);
intent.putExtra(Player.PLAYER_INTENT_TYPE, (Parcelable) playerIntentType);
return intent;
} }
@NonNull @NonNull
public static Intent getPlayerTimestampIntent(@NonNull final Context context, public static Intent getPlayerTimestampIntent(@NonNull final Context context,
@NonNull final TimestampChangeData @NonNull final TimestampChangeData data) {
timestampChangeData) { return new Intent(context, PlayerService.class)
final Intent intent = new Intent(context, PlayerService.class); .putExtra(Player.PLAYER_INTENT_TYPE, PlayerIntentType.TimestampChange)
.putExtra(Player.PLAYER_INTENT_DATA, data);
intent.putExtra(Player.PLAYER_INTENT_TYPE, (Parcelable) PlayerIntentType.TimestampChange);
intent.putExtra(Player.PLAYER_INTENT_DATA, timestampChangeData);
return intent;
} }
@NonNull @NonNull
@ -156,9 +147,9 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerIntent(context, PlayerService.class, queue, final var intent = getPlayerIntent(context, PlayerService.class, queue,
PlayerIntentType.AllOthers); PlayerIntentType.AllOthers)
intent.putExtra(Player.PLAYER_TYPE, PlayerType.POPUP.valueForIntent()) .putExtra(Player.PLAYER_TYPE, PlayerType.POPUP)
.putExtra(Player.RESUME_PLAYBACK, resumePlayback); .putExtra(Player.RESUME_PLAYBACK, resumePlayback);
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} }
@ -170,9 +161,9 @@ public final class NavigationHelper {
.show(); .show();
final Intent intent = getPlayerIntent(context, PlayerService.class, queue, final Intent intent = getPlayerIntent(context, PlayerService.class, queue,
PlayerIntentType.AllOthers); PlayerIntentType.AllOthers)
intent.putExtra(Player.PLAYER_TYPE, PlayerType.AUDIO.valueForIntent()); .putExtra(Player.PLAYER_TYPE, PlayerType.AUDIO)
intent.putExtra(Player.RESUME_PLAYBACK, resumePlayback); .putExtra(Player.RESUME_PLAYBACK, resumePlayback);
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} }
@ -195,9 +186,8 @@ public final class NavigationHelper {
// by long pressing the video detail fragment, playlist or channel controls // by long pressing the video detail fragment, playlist or channel controls
final Intent intent = getPlayerIntent(context, PlayerService.class, queue, final Intent intent = getPlayerIntent(context, PlayerService.class, queue,
PlayerIntentType.Enqueue) PlayerIntentType.Enqueue)
.putExtra(Player.RESUME_PLAYBACK, false); .putExtra(Player.RESUME_PLAYBACK, false)
.putExtra(Player.PLAYER_TYPE, playerType);
intent.putExtra(Player.PLAYER_TYPE, playerType.valueForIntent());
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} }
@ -219,9 +209,8 @@ public final class NavigationHelper {
playerType = PlayerType.AUDIO; playerType = PlayerType.AUDIO;
} }
Toast.makeText(context, R.string.enqueued_next, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.enqueued_next, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerEnqueueNextIntent(context, PlayerService.class, queue); final Intent intent = getPlayerEnqueueNextIntent(context, PlayerService.class, queue)
.putExtra(Player.PLAYER_TYPE, playerType);
intent.putExtra(Player.PLAYER_TYPE, playerType.valueForIntent());
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} }