Skip to content

Commit abfde87

Browse files
authored
Merge pull request #12623 from Isira-Seneviratne/Merge-dev-to-refactor
2 parents 759342f + c98f56b commit abfde87

File tree

14 files changed

+268
-244
lines changed

14 files changed

+268
-244
lines changed

app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ import org.schabi.newpipe.local.dialog.PlaylistDialog
8888
import org.schabi.newpipe.local.history.HistoryRecordManager
8989
import org.schabi.newpipe.local.playlist.LocalPlaylistFragment
9090
import org.schabi.newpipe.player.Player
91+
import org.schabi.newpipe.player.PlayerIntentType
9192
import org.schabi.newpipe.player.PlayerService
9293
import org.schabi.newpipe.player.PlayerType
9394
import org.schabi.newpipe.player.event.OnKeyDownListener
@@ -1044,8 +1045,10 @@ class VideoDetailFragment :
10441045
tryAddVideoPlayerView()
10451046

10461047
val playerIntent = NavigationHelper.getPlayerIntent(
1047-
requireContext(), PlayerService::class.java, queue, true, autoPlayEnabled
1048+
requireContext(), PlayerService::class.java, queue, PlayerIntentType.AllOthers
10481049
)
1050+
.putExtra(Player.PLAY_WHEN_READY, autoPlayEnabled)
1051+
.putExtra(Player.RESUME_PLAYBACK, true)
10491052
ContextCompat.startForegroundService(activity, playerIntent)
10501053
}
10511054

app/src/main/java/org/schabi/newpipe/player/Player.java

Lines changed: 155 additions & 57 deletions
Large diffs are not rendered by default.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.schabi.newpipe.player
2+
3+
import android.os.Parcelable
4+
import kotlinx.parcelize.Parcelize
5+
6+
// We model this as an enum class plus one struct for each enum value
7+
// so we can consume it from Java properly. After converting to Kotlin,
8+
// we could switch to a sealed enum class & a proper Kotlin `when` match.
9+
enum class PlayerIntentType {
10+
Enqueue,
11+
EnqueueNext,
12+
TimestampChange,
13+
AllOthers
14+
}
15+
16+
/**
17+
* A timestamp on the given was clicked and we should switch the playing stream to it.
18+
*/
19+
@Parcelize
20+
data class TimestampChangeData(
21+
val serviceId: Int,
22+
val url: String,
23+
val seconds: Int
24+
) : Parcelable

app/src/main/java/org/schabi/newpipe/player/PlayerService.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,9 @@ class PlayerService : MediaBrowserServiceCompat() {
151151
}
152152

153153
if (p != null) {
154+
val oldPlayerType = p.playerType
154155
p.handleIntent(intent)
156+
p.handleIntentPost(oldPlayerType)
155157
p.UIs().get(MediaSessionPlayerUi::class)
156158
?.handleMediaButtonIntent(intent)
157159
}
Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,7 @@
11
package org.schabi.newpipe.player;
22

3-
import static org.schabi.newpipe.player.Player.PLAYER_TYPE;
4-
5-
import android.content.Intent;
6-
73
public enum PlayerType {
84
MAIN,
95
AUDIO,
106
POPUP;
11-
12-
/**
13-
* @return an integer representing this {@link PlayerType}, to be used to save it in intents
14-
* @see #retrieveFromIntent(Intent) Use retrieveFromIntent() to retrieve and convert player type
15-
* integers from an intent
16-
*/
17-
public int valueForIntent() {
18-
return ordinal();
19-
}
20-
21-
/**
22-
* @param intent the intent to retrieve a player type from
23-
* @return the player type integer retrieved from the intent, converted back into a {@link
24-
* PlayerType}, or {@link PlayerType#MAIN} if there is no player type extra in the
25-
* intent
26-
* @throws ArrayIndexOutOfBoundsException if the intent contains an invalid player type integer
27-
* @see #valueForIntent() Use valueForIntent() to obtain valid player type integers
28-
*/
29-
public static PlayerType retrieveFromIntent(final Intent intent) {
30-
return values()[intent.getIntExtra(PLAYER_TYPE, MAIN.valueForIntent())];
31-
}
327
}

app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package org.schabi.newpipe.player.helper;
22

3-
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
4-
import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
5-
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
63
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS;
74
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER;
85
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI;
@@ -25,7 +22,6 @@
2522
import androidx.preference.PreferenceManager;
2623

2724
import com.google.android.exoplayer2.PlaybackParameters;
28-
import com.google.android.exoplayer2.Player.RepeatMode;
2925
import com.google.android.exoplayer2.SeekParameters;
3026
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
3127
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
@@ -410,23 +406,9 @@ private static SinglePlayQueue getAutoQueuedSinglePlayQueue(
410406
return singlePlayQueue;
411407
}
412408

413-
414409
// endregion
415410
// region Utils used by player
416411

417-
@RepeatMode
418-
public static int nextRepeatMode(@RepeatMode final int repeatMode) {
419-
switch (repeatMode) {
420-
case REPEAT_MODE_OFF:
421-
return REPEAT_MODE_ONE;
422-
case REPEAT_MODE_ONE:
423-
return REPEAT_MODE_ALL;
424-
case REPEAT_MODE_ALL:
425-
default:
426-
return REPEAT_MODE_OFF;
427-
}
428-
}
429-
430412
@ResizeMode
431413
public static int retrieveResizeModeFromPrefs(final Player player) {
432414
return player.getPrefs().getInt(player.getContext().getString(R.string.last_resize_mode),

app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.schabi.newpipe.MainActivity;
2424
import org.schabi.newpipe.R;
2525
import org.schabi.newpipe.player.Player;
26+
import org.schabi.newpipe.player.PlayerIntentType;
2627
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
2728
import org.schabi.newpipe.util.NavigationHelper;
2829

@@ -254,7 +255,9 @@ private Intent getIntentForNotification() {
254255
} else {
255256
// We are playing in fragment. Don't open another activity just show fragment. That's it
256257
final Intent intent = NavigationHelper.getPlayerIntent(
257-
player.getContext(), MainActivity.class, null, true);
258+
player.getContext(), MainActivity.class, null,
259+
PlayerIntentType.AllOthers);
260+
intent.putExtra(Player.RESUME_PLAYBACK, true);
258261
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
259262
intent.setAction(Intent.ACTION_MAIN);
260263
intent.addCategory(Intent.CATEGORY_LAUNCHER);

app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,22 @@ abstract class PlayQueue internal constructor(
254254
broadcast(AppendEvent(itemList.size))
255255
}
256256

257+
/**
258+
* Add the given item after the current stream.
259+
*
260+
* @param item item to add.
261+
* @param skipIfSame if set, skip adding if the next stream is the same stream.
262+
*/
263+
fun enqueueNext(item: PlayQueueItem, skipIfSame: Boolean) {
264+
val currentIndex = index
265+
// if the next item is the same item as the one we want to enqueue, skip if flag is true
266+
if (skipIfSame && item == getItem(currentIndex + 1)) {
267+
return
268+
}
269+
append(listOf(item))
270+
move(size() - 1, currentIndex + 1)
271+
}
272+
257273
/**
258274
* Removes the item at the given index from the play queue.
259275
*

app/src/main/java/org/schabi/newpipe/player/playqueue/SinglePlayQueue.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ public SinglePlayQueue(final StreamInfoItem item) {
1616
public SinglePlayQueue(final StreamInfo info) {
1717
super(0, List.of(new PlayQueueItem(info)));
1818
}
19-
19+
public SinglePlayQueue(final PlayQueueItem item) {
20+
super(0, List.of(item));
21+
}
2022
public SinglePlayQueue(final StreamInfo info, final long startPosition) {
2123
super(0, List.of(new PlayQueueItem(info)));
2224
getItem().setRecoveryPosition(startPosition);

app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java

Lines changed: 41 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@
5858
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
5959
import org.schabi.newpipe.player.PlayQueueActivity;
6060
import org.schabi.newpipe.player.Player;
61+
import org.schabi.newpipe.player.PlayerIntentType;
6162
import org.schabi.newpipe.player.PlayerService;
6263
import org.schabi.newpipe.player.PlayerType;
64+
import org.schabi.newpipe.player.TimestampChangeData;
6365
import org.schabi.newpipe.player.helper.PlayerHelper;
6466
import org.schabi.newpipe.player.helper.PlayerHolder;
6567
import org.schabi.newpipe.player.playqueue.PlayQueue;
@@ -69,6 +71,7 @@
6971
import org.schabi.newpipe.util.external_communication.ShareUtils;
7072

7173
import java.util.List;
74+
import java.util.Optional;
7275

7376
public final class NavigationHelper {
7477
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
@@ -87,54 +90,32 @@ private NavigationHelper() {
8790
public static <T> Intent getPlayerIntent(@NonNull final Context context,
8891
@NonNull final Class<T> targetClazz,
8992
@Nullable final PlayQueue playQueue,
90-
final boolean resumePlayback) {
91-
final Intent intent = new Intent(context, targetClazz);
92-
93-
if (playQueue != null) {
94-
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
95-
if (cacheKey != null) {
96-
intent.putExtra(Player.PLAY_QUEUE_KEY, cacheKey);
97-
}
98-
}
99-
intent.putExtra(Player.PLAYER_TYPE, PlayerType.MAIN.valueForIntent());
100-
intent.putExtra(Player.RESUME_PLAYBACK, resumePlayback);
101-
intent.putExtra(PlayerService.SHOULD_START_FOREGROUND_EXTRA, true);
102-
103-
return intent;
104-
}
105-
106-
@NonNull
107-
public static <T> Intent getPlayerIntent(@NonNull final Context context,
108-
@NonNull final Class<T> targetClazz,
109-
@Nullable final PlayQueue playQueue,
110-
final boolean resumePlayback,
111-
final boolean playWhenReady) {
112-
return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
113-
.putExtra(Player.PLAY_WHEN_READY, playWhenReady);
93+
@NonNull final PlayerIntentType playerIntentType) {
94+
final String cacheKey = Optional.ofNullable(playQueue)
95+
.map(queue -> SerializedCache.getInstance().put(queue, PlayQueue.class))
96+
.orElse(null);
97+
return new Intent(context, targetClazz)
98+
.putExtra(Player.PLAY_QUEUE_KEY, cacheKey)
99+
.putExtra(Player.PLAYER_TYPE, PlayerType.MAIN)
100+
.putExtra(PlayerService.SHOULD_START_FOREGROUND_EXTRA, true)
101+
.putExtra(Player.PLAYER_INTENT_TYPE, playerIntentType);
114102
}
115103

116104
@NonNull
117-
public static <T> Intent getPlayerEnqueueIntent(@NonNull final Context context,
118-
@NonNull final Class<T> targetClazz,
119-
@Nullable final PlayQueue playQueue) {
120-
// when enqueueing `resumePlayback` is always `false` since:
121-
// - if there is a video already playing, the value of `resumePlayback` just doesn't make
122-
// any difference.
123-
// - if there is nothing already playing, it is useful for the enqueue action to have a
124-
// slightly different behaviour than the normal play action: the latter resumes playback,
125-
// the former doesn't. (note that enqueue can be triggered when nothing is playing only
126-
// by long pressing the video detail fragment, playlist or channel controls
127-
return getPlayerIntent(context, targetClazz, playQueue, false)
128-
.putExtra(Player.ENQUEUE, true);
105+
public static Intent getPlayerTimestampIntent(@NonNull final Context context,
106+
@NonNull final TimestampChangeData data) {
107+
return new Intent(context, PlayerService.class)
108+
.putExtra(Player.PLAYER_INTENT_TYPE, PlayerIntentType.TimestampChange)
109+
.putExtra(Player.PLAYER_INTENT_DATA, data);
129110
}
130111

131112
@NonNull
132113
public static <T> Intent getPlayerEnqueueNextIntent(@NonNull final Context context,
133114
@NonNull final Class<T> targetClazz,
134115
@Nullable final PlayQueue playQueue) {
135-
// see comment in `getPlayerEnqueueIntent` as to why `resumePlayback` is false
136-
return getPlayerIntent(context, targetClazz, playQueue, false)
137-
.putExtra(Player.ENQUEUE_NEXT, true);
116+
return getPlayerIntent(context, targetClazz, playQueue, PlayerIntentType.EnqueueNext)
117+
// see comment in `getPlayerEnqueueIntent` as to why `resumePlayback` is false
118+
.putExtra(Player.RESUME_PLAYBACK, false);
138119
}
139120

140121
/* PLAY */
@@ -168,8 +149,10 @@ public static void playOnPopupPlayer(final Context context,
168149

169150
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
170151

171-
final Intent intent = getPlayerIntent(context, PlayerService.class, queue, resumePlayback);
172-
intent.putExtra(Player.PLAYER_TYPE, PlayerType.POPUP.valueForIntent());
152+
final var intent = getPlayerIntent(context, PlayerService.class, queue,
153+
PlayerIntentType.AllOthers)
154+
.putExtra(Player.PLAYER_TYPE, PlayerType.POPUP)
155+
.putExtra(Player.RESUME_PLAYBACK, resumePlayback);
173156
ContextCompat.startForegroundService(context, intent);
174157
}
175158

@@ -179,8 +162,10 @@ public static void playOnBackgroundPlayer(final Context context,
179162
Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT)
180163
.show();
181164

182-
final Intent intent = getPlayerIntent(context, PlayerService.class, queue, resumePlayback);
183-
intent.putExtra(Player.PLAYER_TYPE, PlayerType.AUDIO.valueForIntent());
165+
final Intent intent = getPlayerIntent(context, PlayerService.class, queue,
166+
PlayerIntentType.AllOthers)
167+
.putExtra(Player.PLAYER_TYPE, PlayerType.AUDIO)
168+
.putExtra(Player.RESUME_PLAYBACK, resumePlayback);
184169
ContextCompat.startForegroundService(context, intent);
185170
}
186171

@@ -193,9 +178,18 @@ public static void enqueueOnPlayer(final Context context,
193178
}
194179

195180
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
196-
final Intent intent = getPlayerEnqueueIntent(context, PlayerService.class, queue);
197181

198-
intent.putExtra(Player.PLAYER_TYPE, playerType.valueForIntent());
182+
// when enqueueing `resumePlayback` is always `false` since:
183+
// - if there is a video already playing, the value of `resumePlayback` just doesn't make
184+
// any difference.
185+
// - if there is nothing already playing, it is useful for the enqueue action to have a
186+
// slightly different behaviour than the normal play action: the latter resumes playback,
187+
// the former doesn't. (note that enqueue can be triggered when nothing is playing only
188+
// by long pressing the video detail fragment, playlist or channel controls
189+
final Intent intent = getPlayerIntent(context, PlayerService.class, queue,
190+
PlayerIntentType.Enqueue)
191+
.putExtra(Player.RESUME_PLAYBACK, false)
192+
.putExtra(Player.PLAYER_TYPE, playerType);
199193
ContextCompat.startForegroundService(context, intent);
200194
}
201195

@@ -217,9 +211,8 @@ public static void enqueueNextOnPlayer(final Context context, final PlayQueue qu
217211
playerType = PlayerType.AUDIO;
218212
}
219213
Toast.makeText(context, R.string.enqueued_next, Toast.LENGTH_SHORT).show();
220-
final Intent intent = getPlayerEnqueueNextIntent(context, PlayerService.class, queue);
221-
222-
intent.putExtra(Player.PLAYER_TYPE, playerType.valueForIntent());
214+
final Intent intent = getPlayerEnqueueNextIntent(context, PlayerService.class, queue)
215+
.putExtra(Player.PLAYER_TYPE, playerType);
223216
ContextCompat.startForegroundService(context, intent);
224217
}
225218

0 commit comments

Comments
 (0)