From 3d5a8af52b6baebec559d5ee6e01b0bc428b3227 Mon Sep 17 00:00:00 2001 From: TobiGr Date: Wed, 16 Aug 2023 23:28:02 +0200 Subject: [PATCH] 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