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