Skip to content

Commit df69602

Browse files
committed
Add long press actions to channels and playlists info items
1 parent 986da07 commit df69602

5 files changed

Lines changed: 155 additions & 40 deletions

File tree

app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import org.schabi.newpipe.R;
2424
import org.schabi.newpipe.error.ErrorUtil;
2525
import org.schabi.newpipe.extractor.InfoItem;
26+
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
27+
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
2628
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
2729
import org.schabi.newpipe.fragments.BaseStateFragment;
2830
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
@@ -258,7 +260,10 @@ protected void initListeners() {
258260
infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<>() {
259261
@Override
260262
public void selected(final StreamInfoItem selectedItem) {
261-
onStreamSelected(selectedItem);
263+
onItemSelected(selectedItem);
264+
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
265+
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName(),
266+
null, false);
262267
}
263268

264269
@Override
@@ -267,23 +272,50 @@ public void held(final StreamInfoItem selectedItem) {
267272
}
268273
});
269274

270-
infoListAdapter.setOnChannelSelectedListener(selectedItem -> {
271-
try {
272-
onItemSelected(selectedItem);
273-
NavigationHelper.openChannelFragment(getFM(), selectedItem.getServiceId(),
274-
selectedItem.getUrl(), selectedItem.getName());
275-
} catch (final Exception e) {
276-
ErrorUtil.showUiErrorSnackbar(this, "Opening channel fragment", e);
275+
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<>() {
276+
@Override
277+
public void selected(final ChannelInfoItem selectedItem) {
278+
try {
279+
onItemSelected(selectedItem);
280+
NavigationHelper.openChannelFragment(getFM(), selectedItem.getServiceId(),
281+
selectedItem.getUrl(), selectedItem.getName());
282+
} catch (final Exception e) {
283+
ErrorUtil.showUiErrorSnackbar(BaseListFragment.this, "Opening channel fragment",
284+
e);
285+
}
286+
}
287+
288+
@Override
289+
public void held(final ChannelInfoItem selectedItem) {
290+
openLongPressMenuInActivity(
291+
requireActivity(),
292+
LongPressable.fromChannelInfoItem(selectedItem),
293+
LongPressAction.fromChannelInfoItem(selectedItem)
294+
);
277295
}
278296
});
279297

280-
infoListAdapter.setOnPlaylistSelectedListener(selectedItem -> {
281-
try {
282-
onItemSelected(selectedItem);
283-
NavigationHelper.openPlaylistFragment(getFM(), selectedItem.getServiceId(),
284-
selectedItem.getUrl(), selectedItem.getName());
285-
} catch (final Exception e) {
286-
ErrorUtil.showUiErrorSnackbar(this, "Opening playlist fragment", e);
298+
infoListAdapter.setOnPlaylistSelectedListener(new OnClickGesture<>() {
299+
@Override
300+
public void selected(final PlaylistInfoItem selectedItem) {
301+
try {
302+
BaseListFragment.this.onItemSelected(selectedItem);
303+
NavigationHelper.openPlaylistFragment(BaseListFragment.this.getFM(),
304+
selectedItem.getServiceId(),
305+
selectedItem.getUrl(), selectedItem.getName());
306+
} catch (final Exception e) {
307+
ErrorUtil.showUiErrorSnackbar(BaseListFragment.this,
308+
"Opening playlist fragment", e);
309+
}
310+
}
311+
312+
@Override
313+
public void held(final PlaylistInfoItem selectedItem) {
314+
openLongPressMenuInActivity(
315+
requireActivity(),
316+
LongPressable.fromPlaylistInfoItem(selectedItem),
317+
LongPressAction.fromPlaylistInfoItem(selectedItem)
318+
);
287319
}
288320
});
289321

@@ -293,6 +325,14 @@ public void held(final StreamInfoItem selectedItem) {
293325
useNormalItemListScrollListener();
294326
}
295327

328+
protected void showInfoItemDialog(final StreamInfoItem item) {
329+
openLongPressMenuInActivity(
330+
requireActivity(),
331+
LongPressable.fromStreamInfoItem(item),
332+
LongPressAction.fromStreamInfoItem(item)
333+
);
334+
}
335+
296336
/**
297337
* Removes all listeners and adds the normal scroll listener to the {@link #itemsList}.
298338
*/
@@ -375,27 +415,12 @@ public void onScrolledDown(final RecyclerView recyclerView) {
375415
}
376416
}
377417

378-
private void onStreamSelected(final StreamInfoItem selectedItem) {
379-
onItemSelected(selectedItem);
380-
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
381-
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName(),
382-
null, false);
383-
}
384-
385418
protected void onScrollToBottom() {
386419
if (hasMoreItems() && !isLoading.get()) {
387420
loadMoreItems();
388421
}
389422
}
390423

391-
protected void showInfoItemDialog(final StreamInfoItem item) {
392-
openLongPressMenuInActivity(
393-
requireActivity(),
394-
LongPressable.fromStreamInfoItem(item),
395-
LongPressAction.fromStreamInfoItem(item)
396-
);
397-
}
398-
399424
/*//////////////////////////////////////////////////////////////////////////
400425
// Menu
401426
//////////////////////////////////////////////////////////////////////////*/

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

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package org.schabi.newpipe.player.playqueue;
22

33

4+
import androidx.annotation.Nullable;
5+
46
import org.schabi.newpipe.extractor.Page;
57
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabInfo;
8+
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
69
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
710
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
11+
import org.schabi.newpipe.util.ChannelTabHelper;
812
import org.schabi.newpipe.util.ExtractorHelper;
913

1014
import java.util.Collections;
@@ -15,7 +19,8 @@
1519

1620
public final class ChannelTabPlayQueue extends AbstractInfoPlayQueue<ChannelTabInfo> {
1721

18-
final ListLinkHandler linkHandler;
22+
@Nullable
23+
ListLinkHandler linkHandler;
1924

2025
public ChannelTabPlayQueue(final int serviceId,
2126
final ListLinkHandler linkHandler,
@@ -31,6 +36,13 @@ public ChannelTabPlayQueue(final int serviceId,
3136
this(serviceId, linkHandler, null, Collections.emptyList(), 0);
3237
}
3338

39+
// Plays the first
40+
public ChannelTabPlayQueue(final int serviceId,
41+
final String channelUrl) {
42+
super(serviceId, channelUrl, null, Collections.emptyList(), 0);
43+
linkHandler = null;
44+
}
45+
3446
@Override
3547
protected String getTag() {
3648
return "ChannelTabPlayQueue@" + Integer.toHexString(hashCode());
@@ -39,10 +51,29 @@ protected String getTag() {
3951
@Override
4052
public void fetch() {
4153
if (isInitial) {
42-
ExtractorHelper.getChannelTab(this.serviceId, this.linkHandler, false)
43-
.subscribeOn(Schedulers.io())
44-
.observeOn(AndroidSchedulers.mainThread())
45-
.subscribe(getHeadListObserver());
54+
if (linkHandler == null) {
55+
ExtractorHelper.getChannelInfo(this.serviceId, this.baseUrl, false)
56+
.flatMap(channelInfo -> {
57+
linkHandler = channelInfo.getTabs()
58+
.stream()
59+
.filter(ChannelTabHelper::isStreamsTab)
60+
.findFirst()
61+
.orElseThrow(() -> new ExtractionException(
62+
"No playable channel tab found"));
63+
64+
return ExtractorHelper
65+
.getChannelTab(this.serviceId, this.linkHandler, false);
66+
})
67+
.subscribeOn(Schedulers.io())
68+
.observeOn(AndroidSchedulers.mainThread())
69+
.subscribe(getHeadListObserver());
70+
71+
} else {
72+
ExtractorHelper.getChannelTab(this.serviceId, this.linkHandler, false)
73+
.subscribeOn(Schedulers.io())
74+
.observeOn(AndroidSchedulers.mainThread())
75+
.subscribe(getHeadListObserver());
76+
}
4677
} else {
4778
ExtractorHelper.getMoreChannelTabItems(this.serviceId, this.linkHandler, this.nextPage)
4879
.subscribeOn(Schedulers.io())

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
66
import org.schabi.newpipe.util.ExtractorHelper;
77

8+
import java.util.Collections;
89
import java.util.List;
910

1011
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
@@ -28,6 +29,11 @@ public PlaylistPlayQueue(final int serviceId,
2829
super(serviceId, url, nextPage, streams, index);
2930
}
3031

32+
public PlaylistPlayQueue(final int serviceId,
33+
final String url) {
34+
this(serviceId, url, null, Collections.emptyList(), 0);
35+
}
36+
3137
@Override
3238
protected String getTag() {
3339
return "PlaylistPlayQueue@" + Integer.toHexString(hashCode());

app/src/main/java/org/schabi/newpipe/ui/components/menu/LongPressAction.kt

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,16 @@ import org.schabi.newpipe.error.ErrorInfo
3333
import org.schabi.newpipe.error.ErrorUtil
3434
import org.schabi.newpipe.error.UserAction
3535
import org.schabi.newpipe.extractor.InfoItem
36+
import org.schabi.newpipe.extractor.channel.ChannelInfoItem
37+
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem
3638
import org.schabi.newpipe.extractor.stream.StreamInfoItem
3739
import org.schabi.newpipe.ktx.findFragmentActivity
3840
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog
3941
import org.schabi.newpipe.local.dialog.PlaylistDialog
4042
import org.schabi.newpipe.local.history.HistoryRecordManager
43+
import org.schabi.newpipe.player.playqueue.ChannelTabPlayQueue
4144
import org.schabi.newpipe.player.playqueue.PlayQueue
45+
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue
4246
import org.schabi.newpipe.player.playqueue.SinglePlayQueue
4347
import org.schabi.newpipe.util.NavigationHelper
4448
import org.schabi.newpipe.util.SparseItemUtil
@@ -258,14 +262,37 @@ data class LongPressAction(
258262
item: PlaylistRemoteEntity,
259263
onDelete: Runnable,
260264
): List<LongPressAction> {
261-
return buildShareActionList(
262-
item.orderingName ?: "",
263-
item.url ?: "",
264-
item.thumbnailUrl
265-
) +
265+
return buildPlayerActionList { PlaylistPlayQueue(item.serviceId, item.url) } +
266+
buildShareActionList(
267+
item.orderingName ?: "",
268+
item.orderingName ?: "",
269+
item.thumbnailUrl
270+
) +
266271
listOf(
267272
Type.Delete.buildAction { onDelete.run() },
268273
)
269274
}
275+
276+
@JvmStatic
277+
fun fromChannelInfoItem(item: ChannelInfoItem): List<LongPressAction> {
278+
return buildPlayerActionList { ChannelTabPlayQueue(item.serviceId, item.url) } +
279+
buildShareActionList(item) +
280+
listOf(
281+
Type.ShowChannelDetails.buildAction { context ->
282+
NavigationHelper.openChannelFragment(
283+
context.findFragmentActivity().supportFragmentManager,
284+
item.serviceId,
285+
item.url,
286+
item.name,
287+
)
288+
},
289+
)
290+
}
291+
292+
@JvmStatic
293+
fun fromPlaylistInfoItem(item: PlaylistInfoItem): List<LongPressAction> {
294+
return buildPlayerActionList { PlaylistPlayQueue(item.serviceId, item.url) } +
295+
buildShareActionList(item)
296+
}
270297
}
271298
}

app/src/main/java/org/schabi/newpipe/ui/components/menu/LongPressable.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry
55
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity
66
import org.schabi.newpipe.database.stream.model.StreamEntity
77
import org.schabi.newpipe.extractor.ListExtractor
8+
import org.schabi.newpipe.extractor.channel.ChannelInfoItem
9+
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem
810
import org.schabi.newpipe.extractor.stream.StreamInfoItem
911
import org.schabi.newpipe.extractor.stream.StreamType
1012
import org.schabi.newpipe.extractor.stream.StreamType.AUDIO_LIVE_STREAM
@@ -92,5 +94,29 @@ data class LongPressable(
9294
item.streamCount ?: ListExtractor.ITEM_COUNT_UNKNOWN
9395
),
9496
)
97+
98+
@JvmStatic
99+
fun fromChannelInfoItem(item: ChannelInfoItem) = LongPressable(
100+
title = item.name,
101+
url = item.url?.takeIf { it.isNotBlank() },
102+
thumbnailUrl = ImageStrategy.choosePreferredImage(item.thumbnails),
103+
uploader = null,
104+
uploaderUrl = item.url?.takeIf { it.isNotBlank() },
105+
viewCount = null,
106+
uploadDate = null,
107+
decoration = null,
108+
)
109+
110+
@JvmStatic
111+
fun fromPlaylistInfoItem(item: PlaylistInfoItem) = LongPressable(
112+
title = item.name,
113+
url = item.url?.takeIf { it.isNotBlank() },
114+
thumbnailUrl = ImageStrategy.choosePreferredImage(item.thumbnails),
115+
uploader = item.uploaderName.takeIf { it.isNotBlank() },
116+
uploaderUrl = item.uploaderUrl?.takeIf { it.isNotBlank() },
117+
viewCount = null,
118+
uploadDate = null,
119+
decoration = Decoration.Playlist(item.streamCount),
120+
)
95121
}
96122
}

0 commit comments

Comments
 (0)