Skip to content

Commit 80a12bd

Browse files
committed
Add long press actions to channels and playlists info items
1 parent 29a5e5a commit 80a12bd

File tree

5 files changed

+151
-36
lines changed

5 files changed

+151
-36
lines changed

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: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@ import org.schabi.newpipe.database.stream.StreamStatisticsEntry
3030
import org.schabi.newpipe.database.stream.model.StreamEntity
3131
import org.schabi.newpipe.download.DownloadDialog
3232
import org.schabi.newpipe.extractor.InfoItem
33+
import org.schabi.newpipe.extractor.channel.ChannelInfoItem
34+
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem
3335
import org.schabi.newpipe.extractor.stream.StreamInfoItem
3436
import org.schabi.newpipe.ktx.findFragmentActivity
3537
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog
3638
import org.schabi.newpipe.local.dialog.PlaylistDialog
3739
import org.schabi.newpipe.local.history.HistoryRecordManager
40+
import org.schabi.newpipe.player.playqueue.ChannelTabPlayQueue
3841
import org.schabi.newpipe.player.playqueue.PlayQueue
42+
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue
3943
import org.schabi.newpipe.player.playqueue.SinglePlayQueue
4044
import org.schabi.newpipe.util.NavigationHelper
4145
import org.schabi.newpipe.util.SparseItemUtil
@@ -245,10 +249,33 @@ data class LongPressAction(
245249
item: PlaylistRemoteEntity,
246250
onDelete: Runnable,
247251
): List<LongPressAction> {
248-
return buildShareActionList(item.name, item.url, item.thumbnailUrl) +
252+
return buildPlayerActionList { PlaylistPlayQueue(item.serviceId, item.url) } +
253+
buildShareActionList(item.name, item.url, item.thumbnailUrl) +
249254
listOf(
250255
Type.Delete.buildAction { onDelete.run() },
251256
)
252257
}
258+
259+
@JvmStatic
260+
fun fromChannelInfoItem(item: ChannelInfoItem): List<LongPressAction> {
261+
return buildPlayerActionList { ChannelTabPlayQueue(item.serviceId, item.url) } +
262+
buildShareActionList(item) +
263+
listOf(
264+
Type.ShowChannelDetails.buildAction { context ->
265+
NavigationHelper.openChannelFragment(
266+
context.findFragmentActivity().supportFragmentManager,
267+
item.serviceId,
268+
item.url,
269+
item.name,
270+
)
271+
},
272+
)
273+
}
274+
275+
@JvmStatic
276+
fun fromPlaylistInfoItem(item: PlaylistInfoItem): List<LongPressAction> {
277+
return buildPlayerActionList { PlaylistPlayQueue(item.serviceId, item.url) } +
278+
buildShareActionList(item)
279+
}
253280
}
254281
}

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
@@ -4,6 +4,8 @@ import androidx.compose.runtime.Stable
44
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
7+
import org.schabi.newpipe.extractor.channel.ChannelInfoItem
8+
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem
79
import org.schabi.newpipe.extractor.stream.StreamInfoItem
810
import org.schabi.newpipe.extractor.stream.StreamType
911
import org.schabi.newpipe.extractor.stream.StreamType.AUDIO_LIVE_STREAM
@@ -89,5 +91,29 @@ data class LongPressable(
8991
uploadDate = null,
9092
decoration = Decoration.Playlist(item.streamCount),
9193
)
94+
95+
@JvmStatic
96+
fun fromChannelInfoItem(item: ChannelInfoItem) = LongPressable(
97+
title = item.name,
98+
url = item.url?.takeIf { it.isNotBlank() },
99+
thumbnailUrl = ImageStrategy.choosePreferredImage(item.thumbnails),
100+
uploader = null,
101+
uploaderUrl = item.url?.takeIf { it.isNotBlank() },
102+
viewCount = null,
103+
uploadDate = null,
104+
decoration = null,
105+
)
106+
107+
@JvmStatic
108+
fun fromPlaylistInfoItem(item: PlaylistInfoItem) = LongPressable(
109+
title = item.name,
110+
url = item.url?.takeIf { it.isNotBlank() },
111+
thumbnailUrl = ImageStrategy.choosePreferredImage(item.thumbnails),
112+
uploader = item.uploaderName.takeIf { it.isNotBlank() },
113+
uploaderUrl = item.uploaderUrl?.takeIf { it.isNotBlank() },
114+
viewCount = null,
115+
uploadDate = null,
116+
decoration = Decoration.Playlist(item.streamCount),
117+
)
92118
}
93119
}

0 commit comments

Comments
 (0)