From 1cf670dad95fd6f7c03b613a571885e11c1faa8b Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Mon, 18 Apr 2022 00:35:59 +0800 Subject: [PATCH 1/2] Fix inconsistency between user interaction and database commit order when re-adding videos to the playlist --- .../fragments/detail/VideoDetailFragment.java | 17 +++++++++++++++-- .../local/playlist/LocalPlaylistFragment.java | 9 +++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) 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 0314c2540..fe8845742 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 @@ -54,6 +54,7 @@ import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; import com.google.android.exoplayer2.PlaybackException; @@ -89,6 +90,7 @@ import org.schabi.newpipe.fragments.list.videos.RelatedItemsFragment; import org.schabi.newpipe.ktx.AnimationType; import org.schabi.newpipe.local.dialog.PlaylistDialog; import org.schabi.newpipe.local.history.HistoryRecordManager; +import org.schabi.newpipe.local.playlist.LocalPlaylistFragment; import org.schabi.newpipe.player.Player; import org.schabi.newpipe.player.PlayerService; import org.schabi.newpipe.player.PlayerType; @@ -472,10 +474,21 @@ public final class VideoDetailFragment binding.detailControlsBackground.setOnClickListener(v -> openBackgroundPlayer(false)); binding.detailControlsPopup.setOnClickListener(v -> openPopupPlayer(false)); - binding.detailControlsPlaylistAppend.setOnClickListener(makeOnClickListener(info -> + binding.detailControlsPlaylistAppend.setOnClickListener(makeOnClickListener(info -> { + if (getFM() != null && currentInfo != null) { + final Fragment fragment = getParentFragmentManager(). + findFragmentById(R.id.fragment_holder); + + // commit previous pending changes to database + if (fragment instanceof LocalPlaylistFragment) { + ((LocalPlaylistFragment) fragment).commitChanges(); + } + disposables.add(PlaylistDialog.createCorrespondingDialog(requireContext(), List.of(new StreamEntity(info)), - dialog -> dialog.show(getParentFragmentManager(), TAG))))); + dialog -> dialog.show(getParentFragmentManager(), TAG))); + } + })); binding.detailControlsDownload.setOnClickListener(v -> { if (PermissionHelper.checkStoragePermissions(activity, PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) { diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java index 28711c6fe..9a75c7dbe 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java @@ -158,6 +158,15 @@ public class LocalPlaylistFragment extends BaseLocalListFragment Date: Wed, 16 Aug 2023 23:28:02 +0200 Subject: [PATCH 2/2] Fix inconsistency when LocalPlaylist is used as MainFragment tab --- .../newpipe/fragments/MainFragment.java | 25 ++++++++++++++- .../fragments/detail/VideoDetailFragment.java | 3 ++ .../local/playlist/LocalPlaylistFragment.java | 32 +++++++++++++++---- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java index 023642955..96b13922b 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java @@ -38,6 +38,7 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.FragmentMainBinding; import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.local.playlist.LocalPlaylistFragment; import org.schabi.newpipe.settings.tabs.Tab; import org.schabi.newpipe.settings.tabs.TabsManager; import org.schabi.newpipe.util.NavigationHelper; @@ -217,6 +218,12 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte setTitle(tabsList.get(tabPosition).getTabName(requireContext())); } + public void commitPlaylistTabs() { + pagerAdapter.getLocalPlaylistFragments() + .stream() + .forEach(LocalPlaylistFragment::commitChanges); + } + private void updateTabLayoutPosition() { final ScrollableTabLayout tabLayout = binding.mainTabLayout; final ViewPager viewPager = binding.pager; @@ -268,10 +275,18 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte updateTitleForTab(tab.getPosition()); } - private static final class SelectedTabsPagerAdapter + public static final class SelectedTabsPagerAdapter extends FragmentStatePagerAdapterMenuWorkaround { private final Context context; private final List internalTabsList; + /** + * Keep reference to LocalPlaylistFragments, because their data can be modified by the user + * during runtime and changes are not committed immediately. However, in some cases, + * the changes need to be committed immediately by calling + * {@link LocalPlaylistFragment#commitChanges()}. + * The fragments are removed when {@link LocalPlaylistFragment#onDestroy()} is called. + */ + private final List localPlaylistFragments = new ArrayList<>(); private SelectedTabsPagerAdapter(final Context context, final FragmentManager fragmentManager, @@ -298,9 +313,17 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte ((BaseFragment) fragment).useAsFrontPage(true); } + if (fragment instanceof LocalPlaylistFragment) { + localPlaylistFragments.add((LocalPlaylistFragment) fragment); + } + return fragment; } + public List getLocalPlaylistFragments() { + return localPlaylistFragments; + } + @Override public int getItemPosition(@NonNull final Object object) { // Causes adapter to reload all Fragments when 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 fe8845742..a25d0fae4 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 @@ -85,6 +85,7 @@ import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.EmptyFragment; +import org.schabi.newpipe.fragments.MainFragment; import org.schabi.newpipe.fragments.list.comments.CommentsFragment; import org.schabi.newpipe.fragments.list.videos.RelatedItemsFragment; import org.schabi.newpipe.ktx.AnimationType; @@ -482,6 +483,8 @@ public final class VideoDetailFragment // commit previous pending changes to database if (fragment instanceof LocalPlaylistFragment) { ((LocalPlaylistFragment) fragment).commitChanges(); + } else if (fragment instanceof MainFragment) { + ((MainFragment) fragment).commitPlaylistTabs(); } disposables.add(PlaylistDialog.createCorrespondingDialog(requireContext(), diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java index 9a75c7dbe..51da52ae0 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java @@ -41,6 +41,7 @@ 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.fragments.MainFragment; import org.schabi.newpipe.fragments.list.playlist.PlaylistControlViewHolder; import org.schabi.newpipe.info_list.dialog.InfoItemDialog; import org.schabi.newpipe.info_list.dialog.StreamDialogDefaultEntry; @@ -71,7 +72,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject; public class LocalPlaylistFragment extends BaseLocalListFragment, Void> implements PlaylistControlViewHolder { - // Save the list 10 seconds after the last change occurred + /** Save the list 10 seconds after the last change occurred. */ private static final long SAVE_DEBOUNCE_MILLIS = 10000; private static final int MINIMUM_INITIAL_DRAG_VELOCITY = 12; @State @@ -92,13 +93,20 @@ public class LocalPlaylistFragment extends BaseLocalListFragment debouncedSaveSignal; private CompositeDisposable disposables; - /* Has the playlist been fully loaded from db */ + /** Whether the playlist has been fully loaded from db. */ private AtomicBoolean isLoadingComplete; - /* Has the playlist been modified (e.g. items reordered or deleted) */ + /** Whether the playlist has been modified (e.g. items reordered or deleted) */ private AtomicBoolean isModified; - /* Flag to prevent simultaneous rewrites of the playlist */ + /** Flag to prevent simultaneous rewrites of the playlist. */ private boolean isRewritingPlaylist = false; + /** + * The pager adapter that the fragment is created from when it is used as frontpage, i.e. + * {@link #useAsFrontPage} is {@link true}. + */ + @Nullable + private MainFragment.SelectedTabsPagerAdapter tabsPagerAdapter = null; + public static LocalPlaylistFragment getInstance(final long playlistId, final String name) { final LocalPlaylistFragment instance = new LocalPlaylistFragment(); instance.setInitialData(playlistId, name); @@ -158,9 +166,11 @@ public class LocalPlaylistFragment extends BaseLocalListFragmentCommit changes immediately if the playlist has been modified.

+ * Delete operations and other modifications will be committed to ensure that the database + * is up to date, e.g. when the user adds the just deleted stream from another fragment. + */ public void commitChanges() { if (isModified != null && isModified.get()) { saveImmediate(); @@ -300,6 +310,9 @@ public class LocalPlaylistFragment extends BaseLocalListFragment