Skip to content
Open
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
49d4d39
Add Either type with left, right and match functions
Stypox Jan 28, 2025
2421ccd
Start implementing LongPressMenu
Stypox Jan 28, 2025
c39f3f5
Calculate button placing in long press menu
Stypox Jan 28, 2025
7037043
Treat decorations better
Stypox Jan 28, 2025
52add9d
Add buttons to long press menu
Stypox Jan 28, 2025
9ee5a9b
Remove button background and make text 2 lines
Stypox Jan 28, 2025
f38c4b9
Add small Edit button in LongPressMenu
Stypox Jan 31, 2025
0cf0e16
Click on long press menu subtitle opens channel details
Stypox Feb 11, 2025
7164725
Initial work on handling many long-press actions
Stypox Feb 11, 2025
81750c7
Make LongPressable a data class
Stypox Feb 11, 2025
2bc4cf3
Move long press menu drag handle to its own composable
Stypox Feb 11, 2025
054dbdf
Improve how long press menu buttons are laid out
Stypox Feb 11, 2025
7d79f69
Dismiss long press menu after click on a button
Stypox Feb 11, 2025
c9f8e14
Add download long press menu action
Stypox Feb 11, 2025
0bc3efd
Move LongPressable builders to LongPressable class
Stypox Feb 11, 2025
820438b
Replace InfoItemDialog with LongPressMenu
Stypox Feb 12, 2025
5278ed8
Remove InfoItemDialog
Stypox Feb 12, 2025
0f37d12
Slight adjustments to long press menu
Stypox Feb 12, 2025
de44a78
Add more previews to LongPressMenu
Stypox Feb 13, 2025
2cf03b6
Use LongPressMenu in BookmarkFragment (wip)
Stypox Feb 14, 2025
ed2a03b
Tune transparencies of decorations in long press menu
Stypox Feb 14, 2025
222bfa5
Use faded marquee text in long press menu header
Stypox Feb 14, 2025
5dba822
Add long press actions to channels and playlists info items
Stypox Mar 14, 2025
2016c2e
Add OpenInNew icon next to channel name
Stypox Aug 17, 2025
47b7f5b
Fix some lints
Stypox Aug 27, 2025
2de8b09
Add icons for play/background/popup from here
Stypox Aug 28, 2025
6cb8767
Uniform localizing view counts
Stypox Aug 28, 2025
fb7afa1
Implement background/popup/play from here
Stypox Aug 28, 2025
937c594
Implement "play from here" for feed fragment
Stypox Aug 28, 2025
1904238
Implement "play from here" for channels
Stypox Aug 28, 2025
476b5f1
Improve icons for background/popup/play from here
Stypox Aug 29, 2025
37b4d8a
Implement long pressing on subscriptions
Stypox Aug 29, 2025
249e265
Consider duration 0 as duration not known
Stypox Oct 19, 2025
ff13219
Address Isira review comment
Stypox Oct 19, 2025
b26ab27
Extract FixedHeightCenteredText from LongPressMenu
Stypox Oct 21, 2025
e225326
Implement LongPressMenuEditor UI (still not persisted)
Stypox Oct 21, 2025
813a4f5
Add Back content description to toolbar back buttons
Stypox Oct 21, 2025
771551c
Access editor from long press menu + fix scrolling
Stypox Oct 21, 2025
8075a43
Rewrite LongPressMenuEditor logic
Stypox Oct 22, 2025
6506d62
Make LongPressMenuEditor work with DPAD / Android TV
Stypox Oct 23, 2025
81c12ac
Fix an edge case on the DragMarker position logic
Stypox Oct 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1379,14 +1379,9 @@ class VideoDetailFragment :
}

if (info.viewCount >= 0) {
binding.detailViewCountView.text =
if (info.streamType == StreamType.AUDIO_LIVE_STREAM) {
Localization.listeningCount(activity, info.viewCount)
} else if (info.streamType == StreamType.LIVE_STREAM) {
Localization.localizeWatchingCount(activity, info.viewCount)
} else {
Localization.localizeViewCount(activity, info.viewCount)
}
binding.detailViewCountView.text = Localization.localizeViewCount(
activity, false, info.streamType, info.viewCount
)
binding.detailViewCountView.visibility = View.VISIBLE
} else {
binding.detailViewCountView.visibility = View.GONE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
import static org.schabi.newpipe.ui.components.menu.LongPressMenuKt.openLongPressMenuInActivity;

import android.content.Context;
import android.content.SharedPreferences;
Expand All @@ -22,12 +23,15 @@
import org.schabi.newpipe.R;
import org.schabi.newpipe.error.ErrorUtil;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.info_list.ItemViewMode;
import org.schabi.newpipe.info_list.dialog.InfoItemDialog;
import org.schabi.newpipe.ui.components.menu.LongPressAction;
import org.schabi.newpipe.ui.components.menu.LongPressable;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture;
import org.schabi.newpipe.util.StateSaver;
Expand Down Expand Up @@ -256,7 +260,10 @@ protected void initListeners() {
infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<>() {
@Override
public void selected(final StreamInfoItem selectedItem) {
onStreamSelected(selectedItem);
onItemSelected(selectedItem);
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName(),
null, false);
}

@Override
Expand All @@ -265,23 +272,50 @@ public void held(final StreamInfoItem selectedItem) {
}
});

infoListAdapter.setOnChannelSelectedListener(selectedItem -> {
try {
onItemSelected(selectedItem);
NavigationHelper.openChannelFragment(getFM(), selectedItem.getServiceId(),
selectedItem.getUrl(), selectedItem.getName());
} catch (final Exception e) {
ErrorUtil.showUiErrorSnackbar(this, "Opening channel fragment", e);
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<>() {
@Override
public void selected(final ChannelInfoItem selectedItem) {
try {
onItemSelected(selectedItem);
NavigationHelper.openChannelFragment(getFM(), selectedItem.getServiceId(),
selectedItem.getUrl(), selectedItem.getName());
} catch (final Exception e) {
ErrorUtil.showUiErrorSnackbar(BaseListFragment.this, "Opening channel fragment",
e);
}
}

@Override
public void held(final ChannelInfoItem selectedItem) {
openLongPressMenuInActivity(
requireActivity(),
LongPressable.fromChannelInfoItem(selectedItem),
LongPressAction.fromChannelInfoItem(selectedItem, null)
);
}
});

infoListAdapter.setOnPlaylistSelectedListener(selectedItem -> {
try {
onItemSelected(selectedItem);
NavigationHelper.openPlaylistFragment(getFM(), selectedItem.getServiceId(),
selectedItem.getUrl(), selectedItem.getName());
} catch (final Exception e) {
ErrorUtil.showUiErrorSnackbar(this, "Opening playlist fragment", e);
infoListAdapter.setOnPlaylistSelectedListener(new OnClickGesture<>() {
@Override
public void selected(final PlaylistInfoItem selectedItem) {
try {
BaseListFragment.this.onItemSelected(selectedItem);
NavigationHelper.openPlaylistFragment(BaseListFragment.this.getFM(),
selectedItem.getServiceId(),
selectedItem.getUrl(), selectedItem.getName());
} catch (final Exception e) {
ErrorUtil.showUiErrorSnackbar(BaseListFragment.this,
"Opening playlist fragment", e);
}
}

@Override
public void held(final PlaylistInfoItem selectedItem) {
openLongPressMenuInActivity(
requireActivity(),
LongPressable.fromPlaylistInfoItem(selectedItem),
LongPressAction.fromPlaylistInfoItem(selectedItem)
);
}
});

Expand All @@ -291,6 +325,15 @@ public void held(final StreamInfoItem selectedItem) {
useNormalItemListScrollListener();
}

protected void showInfoItemDialog(final StreamInfoItem item) {
openLongPressMenuInActivity(
requireActivity(),
LongPressable.fromStreamInfoItem(item),
// TODO generalize obtaining queue from here when fully migrating to Compose
LongPressAction.fromStreamInfoItem(item, null)
);
}

/**
* Removes all listeners and adds the normal scroll listener to the {@link #itemsList}.
*/
Expand Down Expand Up @@ -373,27 +416,12 @@ public void onScrolledDown(final RecyclerView recyclerView) {
}
}

private void onStreamSelected(final StreamInfoItem selectedItem) {
onItemSelected(selectedItem);
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName(),
null, false);
}

protected void onScrollToBottom() {
if (hasMoreItems() && !isLoading.get()) {
loadMoreItems();
}
}

protected void showInfoItemDialog(final StreamInfoItem item) {
try {
new InfoItemDialog.Builder(getActivity(), getContext(), this, item).create().show();
} catch (final IllegalArgumentException e) {
InfoItemDialog.Builder.reportErrorDuringInitialization(e, item);
}
}

/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.schabi.newpipe.fragments.list.channel;

import static org.schabi.newpipe.ui.components.menu.LongPressMenuKt.openLongPressMenuInActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
Expand All @@ -26,12 +28,15 @@
import org.schabi.newpipe.fragments.list.playlist.PlaylistControlViewHolder;
import org.schabi.newpipe.player.playqueue.ChannelTabPlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.ui.components.menu.LongPressAction;
import org.schabi.newpipe.ui.components.menu.LongPressable;
import org.schabi.newpipe.ui.emptystate.EmptyStateUtil;
import org.schabi.newpipe.util.ChannelTabHelper;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.PlayButtonHelper;

import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -165,13 +170,30 @@ public void handleResult(@NonNull final ChannelTabInfo result) {
}

@Override
public PlayQueue getPlayQueue() {
protected void showInfoItemDialog(final StreamInfoItem item) {
openLongPressMenuInActivity(
requireActivity(),
LongPressable.fromStreamInfoItem(item),
LongPressAction.fromStreamInfoItem(item, () -> getPlayQueueStartingAt(item))
);
}

private PlayQueue getPlayQueueStartingAt(final StreamInfoItem infoItem) {
return getPlayQueue(streamItems -> Math.max(streamItems.indexOf(infoItem), 0));
}

public PlayQueue getPlayQueue(final Function<List<StreamInfoItem>, Integer> index) {
final List<StreamInfoItem> streamItems = infoListAdapter.getItemsList().stream()
.filter(StreamInfoItem.class::isInstance)
.map(StreamInfoItem.class::cast)
.collect(Collectors.toList());

return new ChannelTabPlayQueue(currentInfo.getServiceId(), tabHandler,
currentInfo.getNextPage(), streamItems, 0);
currentInfo.getNextPage(), streamItems, index.apply(streamItems));
}

@Override
public PlayQueue getPlayQueue() {
return getPlayQueue(streamItems -> 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
import static org.schabi.newpipe.ui.components.menu.LongPressMenuKt.openLongPressMenuInActivity;
import static org.schabi.newpipe.util.ServiceHelper.getServiceById;

import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
Expand Down Expand Up @@ -42,12 +42,12 @@
import org.schabi.newpipe.extractor.stream.Description;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.info_list.dialog.InfoItemDialog;
import org.schabi.newpipe.info_list.dialog.StreamDialogDefaultEntry;
import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
import org.schabi.newpipe.ui.components.menu.LongPressAction;
import org.schabi.newpipe.ui.components.menu.LongPressable;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
Expand Down Expand Up @@ -150,21 +150,11 @@ private PlayQueue getPlayQueueStartingAt(final StreamInfoItem infoItem) {

@Override
protected void showInfoItemDialog(final StreamInfoItem item) {
final Context context = getContext();
try {
final InfoItemDialog.Builder dialogBuilder =
new InfoItemDialog.Builder(getActivity(), context, this, item);

dialogBuilder
.setAction(
StreamDialogDefaultEntry.START_HERE_ON_BACKGROUND,
(f, infoItem) -> NavigationHelper.playOnBackgroundPlayer(
context, getPlayQueueStartingAt(infoItem), true))
.create()
.show();
} catch (final IllegalArgumentException e) {
InfoItemDialog.Builder.reportErrorDuringInitialization(e, item);
}
openLongPressMenuInActivity(
activity,
LongPressable.fromStreamInfoItem(item),
LongPressAction.fromStreamInfoItem(item, () -> getPlayQueueStartingAt(item))
);
}

@Override
Expand Down
Loading
Loading