mirror of
https://github.com/TeamNewPipe/NewPipe.git
synced 2025-10-03 17:59:41 +02:00
Merge pull request #12615 from Isira-Seneviratne/Player-intent-refactor
Refactor player intent logic
This commit is contained in:
commit
45c22c0db8
4 changed files with 39 additions and 83 deletions
|
@ -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 I’m not sure whether I
|
// TODO: this should be in the second switch below, but I’m 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) {
|
|
||||||
case TimestampChange -> {
|
|
||||||
// when playing from a timestamp, keep the current player as-is.
|
// when playing from a timestamp, keep the current player as-is.
|
||||||
newPlayerType = playerType;
|
if (playerIntentType != PlayerIntentType.TimestampChange) {
|
||||||
|
playerType = IntentCompat.getSerializableExtra(intent, PLAYER_TYPE, PlayerType.class);
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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())];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue