diff --git a/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java b/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java index 9105ff992..ef24937fe 100644 --- a/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java +++ b/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java @@ -9,8 +9,8 @@ import android.widget.PopupMenu; import androidx.fragment.app.FragmentManager; -import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; -import org.schabi.newpipe.local.dialog.PlaylistCreationDialog; +import org.schabi.newpipe.database.stream.model.StreamEntity; +import org.schabi.newpipe.local.dialog.PlaylistDialog; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.util.NavigationHelper; @@ -47,13 +47,15 @@ public final class QueueItemMenuUtil { false); return true; case R.id.menu_item_append_playlist: - final PlaylistAppendDialog d = PlaylistAppendDialog.fromPlayQueueItems( - Collections.singletonList(item) + PlaylistDialog.createCorrespondingDialog( + context, + Collections.singletonList(new StreamEntity(item)), + dialog -> dialog.show( + fragmentManager, + "QueueItemMenuUtil@append_playlist" + ) ); - PlaylistAppendDialog.onPlaylistFound(context, - () -> d.show(fragmentManager, "QueueItemMenuUtil@append_playlist"), - () -> PlaylistCreationDialog.newInstance(d) - .show(fragmentManager, "QueueItemMenuUtil@append_playlist")); + return true; case R.id.menu_item_share: shareText(context, item.getTitle(), item.getUrl(), diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java index eba080e62..e3e97d570 100644 --- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java +++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java @@ -33,6 +33,7 @@ import androidx.core.widget.TextViewCompat; import androidx.fragment.app.FragmentManager; import androidx.preference.PreferenceManager; +import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.databinding.ListRadioIconItemBinding; import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding; import org.schabi.newpipe.download.DownloadDialog; @@ -59,8 +60,7 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.ktx.ExceptionUtils; -import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; -import org.schabi.newpipe.local.dialog.PlaylistCreationDialog; +import org.schabi.newpipe.local.dialog.PlaylistDialog; import org.schabi.newpipe.player.MainPlayer; import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHolder; @@ -82,6 +82,7 @@ import org.schabi.newpipe.views.FocusOverlayView; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import icepick.Icepick; @@ -593,31 +594,26 @@ public class RouterActivity extends AppCompatActivity { disposables.add(ExtractorHelper.getStreamInfo(currentServiceId, currentUrl, false) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(info -> { - final FragmentManager fm = getSupportFragmentManager(); - final PlaylistAppendDialog playlistAppendDialog = PlaylistAppendDialog - .fromStreamInfo(info); + .subscribe( + info -> PlaylistDialog.createCorrespondingDialog( + getThemeWrapperContext(), + Collections.singletonList(new StreamEntity(info)), + playlistDialog -> { + playlistDialog.setOnDismissListener(dialog -> finish()); - playlistAppendDialog.setOnDismissListener(dialog -> finish()); - - PlaylistAppendDialog.onPlaylistFound(getThemeWrapperContext(), - () -> { - playlistAppendDialog.show(fm, "addToPlaylistDialog"); - fm.executePendingTransactions(); - }, - () -> { - final PlaylistCreationDialog playlistCreationDialog = - PlaylistCreationDialog.newInstance(playlistAppendDialog); - playlistCreationDialog.show(fm, "addToPlaylistDialog"); - - fm.executePendingTransactions(); - - }); - - }, throwable -> handleError(this, - new ErrorInfo(throwable, UserAction.REQUESTED_STREAM, + playlistDialog.show( + this.getSupportFragmentManager(), + "addToPlaylistDialog" + ); + } + ), + throwable -> handleError(this, new ErrorInfo( + throwable, + UserAction.REQUESTED_STREAM, "Tried to add " + currentUrl + " to a playlist", - currentService.getServiceId()))) + currentService.getServiceId()) + ) + ) ); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 5a30ea0f3..bda16849a 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -52,6 +52,7 @@ import com.squareup.picasso.Callback; import org.schabi.newpipe.App; import org.schabi.newpipe.R; +import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.databinding.FragmentVideoDetailBinding; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.error.ErrorActivity; @@ -73,8 +74,7 @@ import org.schabi.newpipe.fragments.EmptyFragment; import org.schabi.newpipe.fragments.list.comments.CommentsFragment; import org.schabi.newpipe.fragments.list.videos.RelatedItemsFragment; import org.schabi.newpipe.ktx.AnimationType; -import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; -import org.schabi.newpipe.local.dialog.PlaylistCreationDialog; +import org.schabi.newpipe.local.dialog.PlaylistDialog; import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.player.MainPlayer; import org.schabi.newpipe.player.MainPlayer.PlayerType; @@ -99,6 +99,7 @@ import org.schabi.newpipe.util.external_communication.KoreUtils; import org.schabi.newpipe.util.external_communication.ShareUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -444,12 +445,11 @@ public final class VideoDetailFragment break; case R.id.detail_controls_playlist_append: if (getFM() != null && currentInfo != null) { - - final PlaylistAppendDialog d = PlaylistAppendDialog.fromStreamInfo(currentInfo); disposables.add( - PlaylistAppendDialog.onPlaylistFound(getContext(), - () -> d.show(getFM(), TAG), - () -> PlaylistCreationDialog.newInstance(d).show(getFM(), TAG) + PlaylistDialog.createCorrespondingDialog( + getContext(), + Collections.singletonList(new StreamEntity(currentInfo)), + dialog -> dialog.show(getFM(), TAG) ) ); } diff --git a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java index 268848818..2db7e0153 100644 --- a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java +++ b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java @@ -1,8 +1,5 @@ package org.schabi.newpipe.local.dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnDismissListener; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -19,20 +16,14 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry; import org.schabi.newpipe.database.stream.model.StreamEntity; -import org.schabi.newpipe.extractor.stream.StreamInfo; -import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.local.LocalItemListAdapter; import org.schabi.newpipe.local.playlist.LocalPlaylistManager; -import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.util.OnClickGesture; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.disposables.CompositeDisposable; -import io.reactivex.rxjava3.disposables.Disposable; public final class PlaylistAppendDialog extends PlaylistDialog { private static final String TAG = PlaylistAppendDialog.class.getCanonicalName(); @@ -42,58 +33,8 @@ public final class PlaylistAppendDialog extends PlaylistDialog { private final CompositeDisposable playlistDisposables = new CompositeDisposable(); - @Nullable - private OnDismissListener onDismissListener = null; - - public static Disposable onPlaylistFound( - final Context context, final Runnable onSuccess, final Runnable onFailed - ) { - final LocalPlaylistManager playlistManager = - new LocalPlaylistManager(NewPipeDatabase.getInstance(context)); - - return playlistManager.hasPlaylists() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(hasPlaylists -> { - if (hasPlaylists) { - onSuccess.run(); - } else { - onFailed.run(); - } - }); - } - - public static PlaylistAppendDialog fromStreamInfo(final StreamInfo info) { - final PlaylistAppendDialog dialog = new PlaylistAppendDialog(); - dialog.setInfo(Collections.singletonList(new StreamEntity(info))); - return dialog; - } - - public static PlaylistAppendDialog fromStreamInfoItems(final List items) { - final PlaylistAppendDialog dialog = new PlaylistAppendDialog(); - final List entities = new ArrayList<>(items.size()); - for (final StreamInfoItem item : items) { - entities.add(new StreamEntity(item)); - } - dialog.setInfo(entities); - return dialog; - } - - public static PlaylistAppendDialog fromPlayQueueItems(final List items) { - final PlaylistAppendDialog dialog = new PlaylistAppendDialog(); - final List entities = new ArrayList<>(items.size()); - for (final PlayQueueItem item : items) { - entities.add(new StreamEntity(item)); - } - dialog.setInfo(entities); - return dialog; - } - - public void setOnDismissListener(@Nullable final OnDismissListener onDismissListener) { - this.onDismissListener = onDismissListener; - } - - public OnDismissListener getOnDismissListener() { - return onDismissListener; + public PlaylistAppendDialog(final List streamEntities) { + super(streamEntities); } /*////////////////////////////////////////////////////////////////////////// @@ -117,11 +58,15 @@ public final class PlaylistAppendDialog extends PlaylistDialog { playlistAdapter.setSelectedListener(new OnClickGesture() { @Override public void selected(final LocalItem selectedItem) { - if (!(selectedItem instanceof PlaylistMetadataEntry) || getStreams() == null) { + if (!(selectedItem instanceof PlaylistMetadataEntry) + || getStreamEntities() == null) { return; } - onPlaylistSelected(playlistManager, (PlaylistMetadataEntry) selectedItem, - getStreams()); + onPlaylistSelected( + playlistManager, + (PlaylistMetadataEntry) selectedItem, + getStreamEntities() + ); } }); @@ -154,29 +99,22 @@ public final class PlaylistAppendDialog extends PlaylistDialog { playlistAdapter = null; } - @Override - public void onDismiss(@NonNull final DialogInterface dialog) { - super.onDismiss(dialog); - if (onDismissListener != null) { - onDismissListener.onDismiss(dialog); - } - } - /*////////////////////////////////////////////////////////////////////////// // Helper //////////////////////////////////////////////////////////////////////////*/ public void openCreatePlaylistDialog() { - if (getStreams() == null || !isAdded()) { + if (getStreamEntities() == null || !isAdded()) { return; } - final PlaylistCreationDialog dialog = PlaylistCreationDialog.newInstance(getStreams()); + final PlaylistCreationDialog playlistCreationDialog = + new PlaylistCreationDialog(getStreamEntities()); // Move the dismissListener to the new dialog. - dialog.setOnDismissListener(this.onDismissListener); - this.onDismissListener = null; + playlistCreationDialog.setOnDismissListener(this.getOnDismissListener()); + this.setOnDismissListener(null); - dialog.show(getParentFragmentManager(), TAG); + playlistCreationDialog.show(getParentFragmentManager(), TAG); requireDialog().dismiss(); } @@ -191,7 +129,7 @@ public final class PlaylistAppendDialog extends PlaylistDialog { private void onPlaylistSelected(@NonNull final LocalPlaylistManager manager, @NonNull final PlaylistMetadataEntry playlist, @NonNull final List streams) { - if (getStreams() == null) { + if (getStreamEntities() == null) { return; } diff --git a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java index b27b7c454..0f71e54d9 100644 --- a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java +++ b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java @@ -1,8 +1,6 @@ package org.schabi.newpipe.local.dialog; import android.app.Dialog; -import android.content.DialogInterface; -import android.content.DialogInterface.OnDismissListener; import android.os.Bundle; import android.text.InputType; import android.widget.Toast; @@ -23,32 +21,8 @@ import java.util.List; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; public final class PlaylistCreationDialog extends PlaylistDialog { - @Nullable - private OnDismissListener onDismissListener = null; - - public static PlaylistCreationDialog newInstance(final List streams) { - final PlaylistCreationDialog dialog = new PlaylistCreationDialog(); - dialog.setInfo(streams); - return dialog; - } - - public static PlaylistCreationDialog newInstance(final PlaylistAppendDialog appendDialog) { - final PlaylistCreationDialog dialog = new PlaylistCreationDialog(); - dialog.setInfo(appendDialog.getStreams()); - dialog.setOnDismissListener(appendDialog.getOnDismissListener()); - return dialog; - } - - public void setOnDismissListener(@Nullable final OnDismissListener onDismissListener) { - this.onDismissListener = onDismissListener; - } - - @Override - public void onDismiss(@NonNull final DialogInterface dialog) { - super.onDismiss(dialog); - if (onDismissListener != null) { - onDismissListener.onDismiss(dialog); - } + public PlaylistCreationDialog(final List streamEntities) { + super(streamEntities); } /*////////////////////////////////////////////////////////////////////////// @@ -58,7 +32,7 @@ public final class PlaylistCreationDialog extends PlaylistDialog { @NonNull @Override public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { - if (getStreams() == null) { + if (getStreamEntities() == null) { return super.onCreateDialog(savedInstanceState); } @@ -81,7 +55,7 @@ public final class PlaylistCreationDialog extends PlaylistDialog { R.string.playlist_creation_success, Toast.LENGTH_SHORT); - playlistManager.createPlaylist(name, getStreams()) + playlistManager.createPlaylist(name, getStreamEntities()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(longs -> successToast.show()); }); diff --git a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java index 2c2987e95..c2d4474f8 100644 --- a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java +++ b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java @@ -1,6 +1,8 @@ package org.schabi.newpipe.local.dialog; import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; import android.view.Window; @@ -8,23 +10,29 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; +import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.database.stream.model.StreamEntity; +import org.schabi.newpipe.local.playlist.LocalPlaylistManager; import org.schabi.newpipe.util.StateSaver; import java.util.List; import java.util.Queue; +import java.util.function.Consumer; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.disposables.Disposable; public abstract class PlaylistDialog extends DialogFragment implements StateSaver.WriteRead { + + @Nullable + private DialogInterface.OnDismissListener onDismissListener = null; + private List streamEntities; private org.schabi.newpipe.util.SavedState savedState; - protected void setInfo(final List entities) { - this.streamEntities = entities; - } - - protected List getStreams() { - return streamEntities; + public PlaylistDialog(final List streamEntities) { + this.streamEntities = streamEntities; } /*////////////////////////////////////////////////////////////////////////// @@ -43,6 +51,10 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave StateSaver.onDestroy(savedState); } + public List getStreamEntities() { + return streamEntities; + } + @NonNull @Override public Dialog onCreateDialog(final Bundle savedInstanceState) { @@ -55,6 +67,14 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave return dialog; } + @Override + public void onDismiss(@NonNull final DialogInterface dialog) { + super.onDismiss(dialog); + if (onDismissListener != null) { + onDismissListener.onDismiss(dialog); + } + } + /*////////////////////////////////////////////////////////////////////////// // State Saving //////////////////////////////////////////////////////////////////////////*/ @@ -84,4 +104,47 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave savedState, outState, this); } } + + /*////////////////////////////////////////////////////////////////////////// + // Getter + Setter + //////////////////////////////////////////////////////////////////////////*/ + + @Nullable + public DialogInterface.OnDismissListener getOnDismissListener() { + return onDismissListener; + } + + public void setOnDismissListener( + @Nullable final DialogInterface.OnDismissListener onDismissListener + ) { + this.onDismissListener = onDismissListener; + } + + /*////////////////////////////////////////////////////////////////////////// + // Dialog creation + //////////////////////////////////////////////////////////////////////////*/ + + /** + * Creates a {@link PlaylistAppendDialog} when playlists exists, + * otherwise a {@link PlaylistCreationDialog}. + * + * @param context context used for accessing the database + * @param streamEntities used for crating the dialog + * @param onExec execution that should occur after a dialog got created, e.g. showing it + * @return Disposable + */ + public static Disposable createCorrespondingDialog( + final Context context, + final List streamEntities, + final Consumer onExec + ) { + return new LocalPlaylistManager(NewPipeDatabase.getInstance(context)) + .hasPlaylists() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(hasPlaylists -> + onExec.accept(hasPlaylists + ? new PlaylistAppendDialog(streamEntities) + : new PlaylistCreationDialog(streamEntities)) + ); + } } diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java index 0976aa4fb..e0c5ab083 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java +++ b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java @@ -23,11 +23,11 @@ import androidx.recyclerview.widget.RecyclerView; import com.google.android.exoplayer2.PlaybackParameters; import org.schabi.newpipe.R; +import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.databinding.ActivityPlayerQueueControlBinding; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; -import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; -import org.schabi.newpipe.local.dialog.PlaylistCreationDialog; +import org.schabi.newpipe.local.dialog.PlaylistDialog; import org.schabi.newpipe.player.event.PlayerEventListener; import org.schabi.newpipe.player.helper.PlaybackParameterDialog; import org.schabi.newpipe.player.playqueue.PlayQueue; @@ -43,6 +43,7 @@ import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.ThemeHelper; import java.util.List; +import java.util.stream.Collectors; import static org.schabi.newpipe.QueueItemMenuUtil.openPopupMenu; import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed; @@ -452,12 +453,12 @@ public final class PlayQueueActivity extends AppCompatActivity } } - private void openPlaylistAppendDialog(final List playlist) { - final PlaylistAppendDialog d = PlaylistAppendDialog.fromPlayQueueItems(playlist); - - PlaylistAppendDialog.onPlaylistFound(getApplicationContext(), - () -> d.show(getSupportFragmentManager(), TAG), - () -> PlaylistCreationDialog.newInstance(d).show(getSupportFragmentManager(), TAG)); + private void openPlaylistAppendDialog(final List playQueueItems) { + PlaylistDialog.createCorrespondingDialog( + getApplicationContext(), + playQueueItems.stream().map(StreamEntity::new).collect(Collectors.toList()), + dialog -> dialog.show(getSupportFragmentManager(), TAG) + ); } //////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/util/StreamDialogEntry.java b/app/src/main/java/org/schabi/newpipe/util/StreamDialogEntry.java index 11cc4daba..e33c4da87 100644 --- a/app/src/main/java/org/schabi/newpipe/util/StreamDialogEntry.java +++ b/app/src/main/java/org/schabi/newpipe/util/StreamDialogEntry.java @@ -8,9 +8,10 @@ import androidx.fragment.app.Fragment; import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.R; +import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; -import org.schabi.newpipe.local.dialog.PlaylistCreationDialog; +import org.schabi.newpipe.local.dialog.PlaylistDialog; import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.player.playqueue.SinglePlayQueue; import org.schabi.newpipe.util.external_communication.KoreUtils; @@ -82,13 +83,15 @@ public enum StreamDialogEntry { }), // has to be set manually append_playlist(R.string.add_to_playlist, (fragment, item) -> { - final PlaylistAppendDialog d = PlaylistAppendDialog - .fromStreamInfoItems(Collections.singletonList(item)); - - PlaylistAppendDialog.onPlaylistFound(fragment.getContext(), - () -> d.show(fragment.getParentFragmentManager(), "StreamDialogEntry@append_playlist"), - () -> PlaylistCreationDialog.newInstance(d) - .show(fragment.getParentFragmentManager(), "StreamDialogEntry@create_playlist") + PlaylistDialog.createCorrespondingDialog( + fragment.getContext(), + Collections.singletonList(new StreamEntity(item)), + dialog -> dialog.show( + fragment.getParentFragmentManager(), + "StreamDialogEntry@" + + (dialog instanceof PlaylistAppendDialog ? "append" : "create") + + "_playlist" + ) ); }),