Refactor generating InfoItemDialog's

This commit refactors the way `InfoItemDialog`s are generated. This is necessary because the old way used  the `StreamDialogEntry` enum for most of the dialogs' content generation process. This required static variables and methods to store the entries which are used for the dialog to be build (See e.g.`enabledEntries` and methods like `generateCommands()`). In other words, `StreamDialogEntry` wasn't an enumeration anymore.

To address this issue, a `Builder` is introduced for the `InfoItemDialog`'s genration. The builder also comes with some default entries and and a specific order. Both can be used, but are not enforced. 

A second problem that introduced a structure which was atypical for an enumeration was the usage of non-final attributes within `StreamDialogEntry` instances. These were needed, because the default actions needed to overriden in some cases.

To address this problem, the `StreamDialogEntry` enumeration was renamed to `StreamDialogDefaultEntry` and a new `StreamDialogEntry` class is used instead.
This commit is contained in:
TobiGr 2021-12-27 16:16:40 +01:00
parent 68abbfc19c
commit 9f3031bc3a
8 changed files with 384 additions and 487 deletions

View file

@ -68,7 +68,6 @@ import org.schabi.newpipe.error.UserAction
import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException
import org.schabi.newpipe.extractor.stream.StreamInfoItem
import org.schabi.newpipe.extractor.stream.StreamType
import org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty
import org.schabi.newpipe.fragments.BaseStateFragment
import org.schabi.newpipe.info_list.InfoItemDialog
@ -78,15 +77,13 @@ import org.schabi.newpipe.ktx.slideUp
import org.schabi.newpipe.local.feed.item.StreamItem
import org.schabi.newpipe.local.feed.service.FeedLoadService
import org.schabi.newpipe.local.subscription.SubscriptionManager
import org.schabi.newpipe.player.helper.PlayerHolder
import org.schabi.newpipe.util.DeviceUtils
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.NavigationHelper
import org.schabi.newpipe.util.StreamDialogEntry
import org.schabi.newpipe.util.StreamDialogDefaultEntry
import org.schabi.newpipe.util.ThemeHelper.getGridSpanCountStreams
import org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout
import java.time.OffsetDateTime
import java.util.ArrayList
import java.util.function.Consumer
class FeedFragment : BaseStateFragment<FeedState>() {
@ -361,48 +358,20 @@ class FeedFragment : BaseStateFragment<FeedState>() {
val activity: Activity? = getActivity()
if (context == null || context.resources == null || activity == null) return
val entries = ArrayList<StreamDialogEntry>()
if (PlayerHolder.getInstance().isPlayQueueReady) {
entries.add(StreamDialogEntry.enqueue)
val dialogBuilder = InfoItemDialog.Builder(activity, this, item)
if (PlayerHolder.getInstance().queueSize > 1) {
entries.add(StreamDialogEntry.enqueue_next)
}
}
dialogBuilder.addEnqueueEntriesIfNeeded()
dialogBuilder.addStartHereEntries()
dialogBuilder.addAllEntries(
StreamDialogDefaultEntry.APPEND_PLAYLIST,
StreamDialogDefaultEntry.SHARE,
StreamDialogDefaultEntry.OPEN_IN_BROWSER
)
dialogBuilder.addPlayWithKodiEntryIfNeeded()
dialogBuilder.addMarkAsWatchedEntryIfNeeded(item.streamType)
dialogBuilder.addChannelDetailsEntryIfPossible()
if (item.streamType == StreamType.AUDIO_STREAM) {
entries.addAll(
listOf(
StreamDialogEntry.start_here_on_background,
StreamDialogEntry.append_playlist,
StreamDialogEntry.share,
StreamDialogEntry.open_in_browser
)
)
} else {
entries.addAll(
listOf(
StreamDialogEntry.start_here_on_background,
StreamDialogEntry.start_here_on_popup,
StreamDialogEntry.append_playlist,
StreamDialogEntry.share,
StreamDialogEntry.open_in_browser
)
)
}
// show "mark as watched" only when watch history is enabled
if (StreamDialogEntry.shouldAddMarkAsWatched(item.streamType, context)) {
entries.add(
StreamDialogEntry.mark_as_watched
)
}
entries.add(StreamDialogEntry.show_channel_details)
StreamDialogEntry.setEnabledEntries(entries)
InfoItemDialog(activity, item, StreamDialogEntry.getCommands(context)) { _, which ->
StreamDialogEntry.clickOn(which, this, item)
}.show()
dialogBuilder.create().show()
}
private val listenerStreamItem = object : OnItemClickListener, OnItemLongClickListener {

View file

@ -29,20 +29,16 @@ import org.schabi.newpipe.databinding.StatisticPlaylistControlBinding;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.local.BaseLocalListFragment;
import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.settings.HistorySettingsFragment;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture;
import org.schabi.newpipe.util.StreamDialogEntry;
import org.schabi.newpipe.util.StreamDialogDefaultEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@ -336,58 +332,29 @@ public class StatisticsPlaylistFragment
}
final StreamInfoItem infoItem = item.toStreamInfoItem();
final ArrayList<StreamDialogEntry> entries = new ArrayList<>();
final InfoItemDialog.Builder dialogBuilder = new InfoItemDialog.Builder(
activity, this, infoItem);
if (PlayerHolder.getInstance().isPlayQueueReady()) {
entries.add(StreamDialogEntry.enqueue);
dialogBuilder.addEnqueueEntriesIfNeeded();
dialogBuilder.addStartHereEntries();
dialogBuilder.addAllEntries(
StreamDialogDefaultEntry.DELETE,
StreamDialogDefaultEntry.APPEND_PLAYLIST,
StreamDialogDefaultEntry.SHARE,
StreamDialogDefaultEntry.OPEN_IN_BROWSER
);
dialogBuilder.addPlayWithKodiEntryIfNeeded();
dialogBuilder.addMarkAsWatchedEntryIfNeeded(infoItem.getStreamType());
dialogBuilder.addChannelDetailsEntryIfPossible();
if (PlayerHolder.getInstance().getQueueSize() > 1) {
entries.add(StreamDialogEntry.enqueue_next);
}
}
if (infoItem.getStreamType() == StreamType.AUDIO_STREAM) {
entries.addAll(Arrays.asList(
StreamDialogEntry.start_here_on_background,
StreamDialogEntry.delete,
StreamDialogEntry.append_playlist,
StreamDialogEntry.share
));
} else {
entries.addAll(Arrays.asList(
StreamDialogEntry.start_here_on_background,
StreamDialogEntry.start_here_on_popup,
StreamDialogEntry.delete,
StreamDialogEntry.append_playlist,
StreamDialogEntry.share
));
}
entries.add(StreamDialogEntry.open_in_browser);
if (KoreUtils.shouldShowPlayWithKodi(context, infoItem.getServiceId())) {
entries.add(StreamDialogEntry.play_with_kodi);
}
// show "mark as watched" only when watch history is enabled
if (StreamDialogEntry.shouldAddMarkAsWatched(
item.getStreamEntity().getStreamType(),
context
)) {
entries.add(
StreamDialogEntry.mark_as_watched
);
}
entries.add(StreamDialogEntry.show_channel_details);
StreamDialogEntry.setEnabledEntries(entries);
StreamDialogEntry.start_here_on_background.setCustomAction((fragment, infoItemDuplicate) ->
NavigationHelper
dialogBuilder.setAction(StreamDialogDefaultEntry.START_HERE_ON_BACKGROUND,
(fragment, infoItemDuplicate) -> NavigationHelper
.playOnBackgroundPlayer(context, getPlayQueueStartingAt(item), true));
StreamDialogEntry.delete.setCustomAction((fragment, infoItemDuplicate) ->
dialogBuilder.setAction(StreamDialogDefaultEntry.DELETE, (fragment, infoItemDuplicate) ->
deleteEntry(Math.max(itemListAdapter.getItemsList().indexOf(item), 0)));
new InfoItemDialog(activity, infoItem, StreamDialogEntry.getCommands(context),
(dialog, which) -> StreamDialogEntry.clickOn(which, this, infoItem)).show();
dialogBuilder.create().show();
}
private void deleteEntry(final int index) {

View file

@ -1,5 +1,8 @@
package org.schabi.newpipe.local.playlist;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
@ -38,22 +41,18 @@ import org.schabi.newpipe.databinding.PlaylistControlBinding;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.local.BaseLocalListFragment;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.player.MainPlayer.PlayerType;
import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture;
import org.schabi.newpipe.util.StreamDialogEntry;
import org.schabi.newpipe.util.StreamDialogDefaultEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@ -68,9 +67,6 @@ import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import io.reactivex.rxjava3.subjects.PublishSubject;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> {
// Save the list 10 seconds after the last change occurred
private static final long SAVE_DEBOUNCE_MILLIS = 10000;
@ -751,62 +747,33 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
}
final StreamInfoItem infoItem = item.toStreamInfoItem();
final ArrayList<StreamDialogEntry> entries = new ArrayList<>();
final InfoItemDialog.Builder dialogBuilder = new InfoItemDialog.Builder(
activity, this, infoItem);
if (PlayerHolder.getInstance().isPlayQueueReady()) {
entries.add(StreamDialogEntry.enqueue);
dialogBuilder.addEnqueueEntriesIfNeeded();
dialogBuilder.addStartHereEntries();
dialogBuilder.addAllEntries(
StreamDialogDefaultEntry.SET_AS_PLAYLIST_THUMBNAIL,
StreamDialogDefaultEntry.DELETE,
StreamDialogDefaultEntry.APPEND_PLAYLIST,
StreamDialogDefaultEntry.SHARE,
StreamDialogDefaultEntry.OPEN_IN_BROWSER
);
dialogBuilder.addPlayWithKodiEntryIfNeeded();
dialogBuilder.addMarkAsWatchedEntryIfNeeded(infoItem.getStreamType());
dialogBuilder.addChannelDetailsEntryIfPossible();
if (PlayerHolder.getInstance().getQueueSize() > 1) {
entries.add(StreamDialogEntry.enqueue_next);
}
}
if (infoItem.getStreamType() == StreamType.AUDIO_STREAM) {
entries.addAll(Arrays.asList(
StreamDialogEntry.start_here_on_background,
StreamDialogEntry.set_as_playlist_thumbnail,
StreamDialogEntry.delete,
StreamDialogEntry.append_playlist,
StreamDialogEntry.share
));
} else {
entries.addAll(Arrays.asList(
StreamDialogEntry.start_here_on_background,
StreamDialogEntry.start_here_on_popup,
StreamDialogEntry.set_as_playlist_thumbnail,
StreamDialogEntry.delete,
StreamDialogEntry.append_playlist,
StreamDialogEntry.share
));
}
entries.add(StreamDialogEntry.open_in_browser);
if (KoreUtils.shouldShowPlayWithKodi(context, infoItem.getServiceId())) {
entries.add(StreamDialogEntry.play_with_kodi);
}
// show "mark as watched" only when watch history is enabled
if (StreamDialogEntry.shouldAddMarkAsWatched(
item.getStreamEntity().getStreamType(),
context
)) {
entries.add(
StreamDialogEntry.mark_as_watched
);
}
entries.add(StreamDialogEntry.show_channel_details);
StreamDialogEntry.setEnabledEntries(entries);
StreamDialogEntry.start_here_on_background.setCustomAction((fragment, infoItemDuplicate) ->
NavigationHelper.playOnBackgroundPlayer(context,
getPlayQueueStartingAt(item), true));
StreamDialogEntry.set_as_playlist_thumbnail.setCustomAction(
// set custom actions
dialogBuilder.setAction(StreamDialogDefaultEntry.START_HERE_ON_BACKGROUND,
(fragment, infoItemDuplicate) -> NavigationHelper.playOnBackgroundPlayer(
context, getPlayQueueStartingAt(item), true));
dialogBuilder.setAction(StreamDialogDefaultEntry.SET_AS_PLAYLIST_THUMBNAIL,
(fragment, infoItemDuplicate) ->
changeThumbnailUrl(item.getStreamEntity().getThumbnailUrl()));
StreamDialogEntry.delete.setCustomAction((fragment, infoItemDuplicate) ->
deleteItem(item));
dialogBuilder.setAction(StreamDialogDefaultEntry.DELETE,
(fragment, infoItemDuplicate) -> deleteItem(item));
new InfoItemDialog(activity, infoItem, StreamDialogEntry.getCommands(context),
(dialog, which) -> StreamDialogEntry.clickOn(which, this, infoItem)).show();
dialogBuilder.create().show();
}
private void setInitialData(final long pid, final String title) {