From fb362022f732ed81fcc60725b094bb6cf80707aa Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sat, 15 Jan 2022 17:05:40 +0100 Subject: [PATCH 01/10] Load enough initial data into BaseListFragment --- .../fragments/list/BaseListFragment.java | 63 ++++++++++++++++++- .../fragments/list/BaseListInfoFragment.java | 19 ++++-- .../fragments/list/search/SearchFragment.java | 14 ++++- 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index 3c2e65bb7..d0a07ffc4 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -271,7 +271,7 @@ public abstract class BaseListFragment extends BaseStateFragment @Override protected void initListeners() { super.initListeners(); - infoListAdapter.setOnStreamSelectedListener(new OnClickGesture() { + infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<>() { @Override public void selected(final StreamInfoItem selectedItem) { onStreamSelected(selectedItem); @@ -418,7 +418,66 @@ public abstract class BaseListFragment extends BaseStateFragment // Load and handle //////////////////////////////////////////////////////////////////////////*/ - protected abstract void loadMoreItems(); + /** + * If more items are loadable and the itemList is not scrollable -> load more data. + *
+ * Should be called once the initial items inside {@link #startLoading(boolean)} + * has been loaded and added to the {@link #itemsList}. + *
+ * Otherwise the loading indicator is always shown but no data can be loaded + * because the view is not scrollable; see also #1974. + */ + protected void ifMoreItemsLoadableLoadUntilScrollable() { + ifMoreItemsLoadableLoadUntilScrollable(0); + } + + /** + * If more items are loadable and the itemList is not scrollable -> load more data. + * + * @param recursiveCallCount Amount of recursive calls that occurred + * @see #ifMoreItemsLoadableLoadUntilScrollable() + */ + protected void ifMoreItemsLoadableLoadUntilScrollable(final int recursiveCallCount) { + // Try to prevent malfunction / stackoverflow + if (recursiveCallCount > 100) { + Log.w(TAG, "loadEnoughInitialData - Too many recursive calls - Aborting"); + return; + } + if (!hasMoreItems()) { + if (DEBUG) { + Log.d(TAG, "loadEnoughInitialData - OK: No more items to load"); + } + return; + } + if (itemsList.canScrollVertically(1) + || itemsList.canScrollVertically(-1)) { + if (DEBUG) { + Log.d(TAG, "loadEnoughInitial - OK: itemList is scrollable"); + } + return; + } + if (DEBUG) { + Log.d(TAG, "loadEnoughInitialData - View is not scrollable " + + "but it could load more items -> Loading more"); + } + loadMoreItems(() -> + ifMoreItemsLoadableLoadUntilScrollable(recursiveCallCount + 1)); + } + + /** + * Loads more items. + * @param initialDataLoadCallback + * Callback used in {@link #ifMoreItemsLoadableLoadUntilScrollable()}. + *
+ * Execute it once the data was loaded and added to the {@link #itemsList}. + *
+ * Might be null. + */ + protected abstract void loadMoreItems(@Nullable Runnable initialDataLoadCallback); + + protected void loadMoreItems() { + loadMoreItems(null); + } protected abstract boolean hasMoreItems(); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java index e98dc9fda..87f031c12 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java @@ -6,6 +6,7 @@ import android.util.Log; import android.view.View; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.UserAction; @@ -65,7 +66,7 @@ public abstract class BaseListInfoFragment super.onResume(); // Check if it was loading when the fragment was stopped/paused, if (wasLoading.getAndSet(false)) { - if (hasMoreItems() && infoListAdapter.getItemsList().size() > 0) { + if (hasMoreItems() && !infoListAdapter.getItemsList().isEmpty()) { loadMoreItems(); } else { doInitialLoadLogic(); @@ -105,6 +106,7 @@ public abstract class BaseListInfoFragment // Load and handle //////////////////////////////////////////////////////////////////////////*/ + @Override protected void doInitialLoadLogic() { if (DEBUG) { Log.d(TAG, "doInitialLoadLogic() called"); @@ -144,6 +146,7 @@ public abstract class BaseListInfoFragment currentInfo = result; currentNextPage = result.getNextPage(); handleResult(result); + ifMoreItemsLoadableLoadUntilScrollable(); }, throwable -> showError(new ErrorInfo(throwable, errorUserAction, "Start loading: " + url, serviceId))); @@ -158,7 +161,8 @@ public abstract class BaseListInfoFragment */ protected abstract Single loadMoreItemsLogic(); - protected void loadMoreItems() { + @Override + protected void loadMoreItems(@Nullable final Runnable initialDataLoadCallback) { isLoading.set(true); if (currentWorker != null) { @@ -171,9 +175,12 @@ public abstract class BaseListInfoFragment .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doFinally(this::allowDownwardFocusScroll) - .subscribe((@NonNull ListExtractor.InfoItemsPage InfoItemsPage) -> { + .subscribe(infoItemsPage -> { isLoading.set(false); - handleNextItems(InfoItemsPage); + handleNextItems(infoItemsPage); + if (initialDataLoadCallback != null) { + initialDataLoadCallback.run(); + } }, (@NonNull Throwable throwable) -> dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(throwable, errorUserAction, "Loading more items: " + url, serviceId))); @@ -223,7 +230,7 @@ public abstract class BaseListInfoFragment setTitle(name); if (infoListAdapter.getItemsList().isEmpty()) { - if (result.getRelatedItems().size() > 0) { + if (!result.getRelatedItems().isEmpty()) { infoListAdapter.addInfoItemList(result.getRelatedItems()); showListFooter(hasMoreItems()); } else { @@ -240,7 +247,7 @@ public abstract class BaseListInfoFragment final List errors = new ArrayList<>(result.getErrors()); // handling ContentNotSupportedException not to show the error but an appropriate string // so that crashes won't be sent uselessly and the user will understand what happened - errors.removeIf(throwable -> throwable instanceof ContentNotSupportedException); + errors.removeIf(ContentNotSupportedException.class::isInstance); if (!errors.isEmpty()) { dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(result.getErrors(), diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index 055c27733..35bb2c349 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -868,12 +868,15 @@ public class SearchFragment extends BaseListFragment isLoading.set(false)) - .subscribe(this::handleResult, this::onItemError); + .subscribe(result -> { + handleResult(result); + ifMoreItemsLoadableLoadUntilScrollable(); + }, this::onItemError); } @Override - protected void loadMoreItems() { + protected void loadMoreItems(@Nullable final Runnable initialDataLoadCallback) { if (!Page.isValid(nextPage)) { return; } @@ -891,7 +894,12 @@ public class SearchFragment extends BaseListFragment isLoading.set(false)) - .subscribe(this::handleNextItems, this::onItemError); + .subscribe(itemsPage -> { + handleNextItems(itemsPage); + if (initialDataLoadCallback != null) { + initialDataLoadCallback.run(); + } + }, this::onItemError); } @Override From 2c51a7970d0bf3174a25b0c4cde03a4878e7cefa Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sat, 15 Jan 2022 17:28:03 +0100 Subject: [PATCH 02/10] Improved InfoListAdapter * Removed unused code * Cleaned it up * Made code more readable --- .../newpipe/info_list/InfoListAdapter.java | 70 ++++--------------- 1 file changed, 12 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java index 56bc63384..410a65449 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java @@ -145,43 +145,6 @@ public class InfoListAdapter extends RecyclerView.Adapter data) { - infoItemList.clear(); - infoItemList.addAll(data); - notifyDataSetChanged(); - } - - public void addInfoItem(@Nullable final InfoItem data) { - if (data == null) { - return; - } - if (DEBUG) { - Log.d(TAG, "addInfoItem() before > infoItemList.size() = " - + infoItemList.size() + ", thread = " + Thread.currentThread()); - } - - final int positionInserted = sizeConsideringHeaderOffset(); - infoItemList.add(data); - - if (DEBUG) { - Log.d(TAG, "addInfoItem() after > position = " + positionInserted + ", " - + "infoItemList.size() = " + infoItemList.size() + ", " - + "header = " + header + ", footer = " + footer + ", " - + "showFooter = " + showFooter); - } - notifyItemInserted(positionInserted); - - if (footer != null && showFooter) { - final int footerNow = sizeConsideringHeaderOffset(); - notifyItemMoved(positionInserted, footerNow); - - if (DEBUG) { - Log.d(TAG, "addInfoItem() footer from " + positionInserted - + " to " + footerNow); - } - } - } - public void clearStreamItemList() { if (infoItemList.isEmpty()) { return; @@ -226,7 +189,7 @@ public class InfoListAdapter extends RecyclerView.Adapter getItemsList() { + public List getItemsList() { return infoItemList; } @@ -335,29 +298,23 @@ public class InfoListAdapter extends RecyclerView.Adapter payloads) { - if (!payloads.isEmpty() && holder instanceof InfoItemHolder) { - for (final Object payload : payloads) { - if (payload instanceof StreamStateEntity) { - ((InfoItemHolder) holder).updateState(infoItemList - .get(header == null ? position : position - 1), recordManager); - } else if (payload instanceof Boolean) { - ((InfoItemHolder) holder).updateState(infoItemList - .get(header == null ? position : position - 1), recordManager); - } - } - } else { + if (payloads.isEmpty() || !(holder instanceof InfoItemHolder)) { onBindViewHolder(holder, position); + return; + } + + for (final Object payload : payloads) { + if (payload instanceof StreamStateEntity || payload instanceof Boolean) { + ((InfoItemHolder) holder).updateState(infoItemList + .get(header == null ? position : position - 1), recordManager); + } } } @@ -372,11 +329,8 @@ public class InfoListAdapter extends RecyclerView.Adapter Date: Sat, 15 Jan 2022 17:40:08 +0100 Subject: [PATCH 03/10] Removed InfoListAdapter from checkstyle-suppressions because if you modify something in the code the suppressions-file no longer matches --- .../java/org/schabi/newpipe/info_list/InfoListAdapter.java | 2 ++ checkstyle-suppressions.xml | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java index 410a65449..57e6fa380 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java @@ -212,6 +212,7 @@ public class InfoListAdapter extends RecyclerView.Adapter - - From 91c67b085bd6a5553b44a08a296e2c2f72f761c8 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sat, 15 Jan 2022 23:55:19 +0100 Subject: [PATCH 04/10] Code improvements Removed - partial - stupid code. --- .../fragments/list/BaseListFragment.java | 5 ---- .../list/channel/ChannelFragment.java | 23 ++++++++----------- .../list/playlist/PlaylistFragment.java | 2 +- .../list/videos/RelatedItemsFragment.java | 14 +++-------- 4 files changed, 13 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index d0a07ffc4..741729d5b 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -79,11 +79,6 @@ public abstract class BaseListFragment extends BaseStateFragment } } - @Override - public void onDetach() { - super.onDetach(); - } - @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 37954478d..66eb64b82 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -183,13 +183,6 @@ public class ChannelFragment extends BaseListInfoFragment } } - private void openRssFeed() { - final ChannelInfo info = currentInfo; - if (info != null) { - ShareUtils.openUrlInBrowser(requireContext(), info.getFeedUrl(), false); - } - } - @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { @@ -197,7 +190,10 @@ public class ChannelFragment extends BaseListInfoFragment NavigationHelper.openSettings(requireContext()); break; case R.id.menu_item_rss: - openRssFeed(); + if (currentInfo != null) { + ShareUtils.openUrlInBrowser( + requireContext(), currentInfo.getFeedUrl(), false); + } break; case R.id.menu_item_openInBrowser: if (currentInfo != null) { @@ -516,12 +512,11 @@ public class ChannelFragment extends BaseListInfoFragment } private PlayQueue getPlayQueue(final int index) { - final List streamItems = new ArrayList<>(); - for (final InfoItem i : infoListAdapter.getItemsList()) { - if (i instanceof StreamInfoItem) { - streamItems.add((StreamInfoItem) i); - } - } + final List streamItems = infoListAdapter.getItemsList().stream() + .filter(StreamInfoItem.class::isInstance) + .map(StreamInfoItem.class::cast) + .collect(Collectors.toList()); + return new ChannelPlayQueue(currentInfo.getServiceId(), currentInfo.getUrl(), currentInfo.getNextPage(), streamItems, index); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index 640d08064..89ee3980e 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -413,7 +413,7 @@ public class PlaylistFragment extends BaseListInfoFragment { } private Subscriber> getPlaylistBookmarkSubscriber() { - return new Subscriber>() { + return new Subscriber<>() { @Override public void onSubscribe(final Subscription s) { if (bookmarkReactor != null) { diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java index 6532417c0..285024484 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java @@ -26,12 +26,11 @@ import org.schabi.newpipe.util.RelatedItemInfo; import java.io.Serializable; import io.reactivex.rxjava3.core.Single; -import io.reactivex.rxjava3.disposables.CompositeDisposable; public class RelatedItemsFragment extends BaseListInfoFragment implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String INFO_KEY = "related_info_key"; - private final CompositeDisposable disposables = new CompositeDisposable(); + private RelatedItemInfo relatedItemInfo; /*////////////////////////////////////////////////////////////////////////// @@ -54,11 +53,6 @@ public class RelatedItemsFragment extends BaseListInfoFragment // LifeCycle //////////////////////////////////////////////////////////////////////////*/ - @Override - public void onAttach(@NonNull final Context context) { - super.onAttach(context); - } - @Override public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @@ -67,9 +61,6 @@ public class RelatedItemsFragment extends BaseListInfoFragment } @Override - public void onDestroy() { - super.onDestroy(); - disposables.clear(); } @Override @@ -128,7 +119,6 @@ public class RelatedItemsFragment extends BaseListInfoFragment } ViewUtils.slideUp(requireView(), 120, 96, 0.06f); - disposables.clear(); } /*////////////////////////////////////////////////////////////////////////// @@ -137,11 +127,13 @@ public class RelatedItemsFragment extends BaseListInfoFragment @Override public void setTitle(final String title) { + // Nothing to do - override parent } @Override public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) { + // Nothing to do - override parent } private void setInitialData(final StreamInfo info) { From d3cd3d62b4ab542888669492f6da025cc2db2cfd Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sun, 16 Jan 2022 17:08:13 +0100 Subject: [PATCH 05/10] Tried to repair #4475 and #3368 * Always recreate the footer so that it's not possible to attach the same instance twice * Removed support for creating a custom footer as it's never used * Supply the header with an supplier * This might not fix the problem completely as we currently can only create the header once inside Channel, Playlist and RelatedItems-Fragment - allowing creation of multiple headers might be done in the future if the issues still arise * Other minor fixes --- .../fragments/list/BaseListFragment.java | 18 ++---- .../list/channel/ChannelFragment.java | 19 +++---- .../list/playlist/PlaylistFragment.java | 20 +++---- .../list/videos/RelatedItemsFragment.java | 42 +++++++------- .../newpipe/info_list/InfoListAdapter.java | 57 +++++++++++-------- 5 files changed, 78 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index 741729d5b..d1685c5af 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -17,10 +17,8 @@ import androidx.appcompat.app.ActionBar; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import androidx.viewbinding.ViewBinding; import org.schabi.newpipe.R; -import org.schabi.newpipe.databinding.PignateFooterBinding; import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; @@ -44,6 +42,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Queue; +import java.util.function.Supplier; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; import static org.schabi.newpipe.ktx.ViewUtils.animate; @@ -215,14 +214,10 @@ public abstract class BaseListFragment extends BaseStateFragment //////////////////////////////////////////////////////////////////////////*/ @Nullable - protected ViewBinding getListHeader() { + protected Supplier getListHeaderSupplier() { return null; } - protected ViewBinding getListFooter() { - return PignateFooterBinding.inflate(activity.getLayoutInflater(), itemsList, false); - } - protected RecyclerView.LayoutManager getListLayoutManager() { return new SuperScrollLayoutManager(activity); } @@ -247,11 +242,10 @@ public abstract class BaseListFragment extends BaseStateFragment itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager()); infoListAdapter.setUseGridVariant(useGrid); - infoListAdapter.setFooter(getListFooter().getRoot()); - final ViewBinding listHeader = getListHeader(); - if (listHeader != null) { - infoListAdapter.setHeader(listHeader.getRoot()); + final Supplier listHeaderSupplier = getListHeaderSupplier(); + if (listHeaderSupplier != null) { + infoListAdapter.setHeaderSupplier(listHeaderSupplier); } itemsList.setAdapter(infoListAdapter); @@ -447,7 +441,7 @@ public abstract class BaseListFragment extends BaseStateFragment if (itemsList.canScrollVertically(1) || itemsList.canScrollVertically(-1)) { if (DEBUG) { - Log.d(TAG, "loadEnoughInitial - OK: itemList is scrollable"); + Log.d(TAG, "loadEnoughInitialData - OK: itemList is scrollable"); } return; } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 66eb64b82..918facc4e 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -1,5 +1,9 @@ package org.schabi.newpipe.fragments.list.channel; +import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor; +import static org.schabi.newpipe.ktx.ViewUtils.animate; +import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor; + import android.content.Context; import android.os.Bundle; import android.text.TextUtils; @@ -17,7 +21,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.core.content.ContextCompat; -import androidx.viewbinding.ViewBinding; import com.jakewharton.rxbinding4.view.RxView; @@ -29,7 +32,6 @@ import org.schabi.newpipe.databinding.PlaylistControlBinding; import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; -import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; @@ -43,13 +45,14 @@ import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; -import org.schabi.newpipe.util.external_communication.ShareUtils; import org.schabi.newpipe.util.PicassoHelper; import org.schabi.newpipe.util.ThemeHelper; +import org.schabi.newpipe.util.external_communication.ShareUtils; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.stream.Collectors; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.core.Observable; @@ -61,10 +64,6 @@ import io.reactivex.rxjava3.functions.Consumer; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.schedulers.Schedulers; -import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor; -import static org.schabi.newpipe.ktx.ViewUtils.animate; -import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor; - public class ChannelFragment extends BaseListInfoFragment implements View.OnClickListener { @@ -145,12 +144,12 @@ public class ChannelFragment extends BaseListInfoFragment //////////////////////////////////////////////////////////////////////////*/ @Override - protected ViewBinding getListHeader() { + protected Supplier getListHeaderSupplier() { headerBinding = ChannelHeaderBinding .inflate(activity.getLayoutInflater(), itemsList, false); playlistControlBinding = headerBinding.playlistControl; - return headerBinding; + return headerBinding::getRoot; } @Override diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index 89ee3980e..84dcb4fd9 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -1,5 +1,9 @@ package org.schabi.newpipe.fragments.list.playlist; +import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; +import static org.schabi.newpipe.ktx.ViewUtils.animate; +import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling; + import android.app.Activity; import android.content.Context; import android.os.Bundle; @@ -15,7 +19,6 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; -import androidx.viewbinding.ViewBinding; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; @@ -42,17 +45,18 @@ import org.schabi.newpipe.player.helper.PlayerHolder; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue; import org.schabi.newpipe.util.ExtractorHelper; -import org.schabi.newpipe.util.PicassoHelper; -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.external_communication.ShareUtils; +import org.schabi.newpipe.util.PicassoHelper; import org.schabi.newpipe.util.StreamDialogEntry; +import org.schabi.newpipe.util.external_communication.KoreUtils; +import org.schabi.newpipe.util.external_communication.ShareUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.core.Flowable; @@ -60,10 +64,6 @@ import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.disposables.Disposable; -import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; -import static org.schabi.newpipe.ktx.ViewUtils.animate; -import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling; - public class PlaylistFragment extends BaseListInfoFragment { private static final String PICASSO_PLAYLIST_TAG = "PICASSO_PLAYLIST_TAG"; @@ -120,12 +120,12 @@ public class PlaylistFragment extends BaseListInfoFragment { //////////////////////////////////////////////////////////////////////////*/ @Override - protected ViewBinding getListHeader() { + protected Supplier getListHeaderSupplier() { headerBinding = PlaylistHeaderBinding .inflate(activity.getLayoutInflater(), itemsList, false); playlistControlBinding = headerBinding.playlistControl; - return headerBinding; + return headerBinding::getRoot; } @Override diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java index 285024484..7ba6aa2ab 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java @@ -1,6 +1,5 @@ package org.schabi.newpipe.fragments.list.videos; -import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.view.LayoutInflater; @@ -12,7 +11,6 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.PreferenceManager; -import androidx.viewbinding.ViewBinding; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.RelatedItemsHeaderBinding; @@ -24,6 +22,7 @@ import org.schabi.newpipe.ktx.ViewUtils; import org.schabi.newpipe.util.RelatedItemInfo; import java.io.Serializable; +import java.util.function.Supplier; import io.reactivex.rxjava3.core.Single; @@ -60,9 +59,6 @@ public class RelatedItemsFragment extends BaseListInfoFragment return inflater.inflate(R.layout.fragment_related_items, container, false); } - @Override - } - @Override public void onDestroyView() { headerBinding = null; @@ -70,22 +66,23 @@ public class RelatedItemsFragment extends BaseListInfoFragment } @Override - protected ViewBinding getListHeader() { - if (relatedItemInfo != null && relatedItemInfo.getRelatedItems() != null) { - headerBinding = RelatedItemsHeaderBinding - .inflate(activity.getLayoutInflater(), itemsList, false); - - final SharedPreferences pref = PreferenceManager - .getDefaultSharedPreferences(requireContext()); - final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false); - headerBinding.autoplaySwitch.setChecked(autoplay); - headerBinding.autoplaySwitch.setOnCheckedChangeListener((compoundButton, b) -> - PreferenceManager.getDefaultSharedPreferences(requireContext()).edit() - .putBoolean(getString(R.string.auto_queue_key), b).apply()); - return headerBinding; - } else { + protected Supplier getListHeaderSupplier() { + if (relatedItemInfo == null || relatedItemInfo.getRelatedItems() == null) { return null; } + + headerBinding = RelatedItemsHeaderBinding + .inflate(activity.getLayoutInflater(), itemsList, false); + + final SharedPreferences pref = PreferenceManager + .getDefaultSharedPreferences(requireContext()); + final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false); + headerBinding.autoplaySwitch.setChecked(autoplay); + headerBinding.autoplaySwitch.setOnCheckedChangeListener((compoundButton, b) -> + PreferenceManager.getDefaultSharedPreferences(requireContext()).edit() + .putBoolean(getString(R.string.auto_queue_key), b).apply()); + + return headerBinding::getRoot; } @Override @@ -161,11 +158,10 @@ public class RelatedItemsFragment extends BaseListInfoFragment @Override public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String s) { - final SharedPreferences pref = - PreferenceManager.getDefaultSharedPreferences(requireContext()); - final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false); if (headerBinding != null) { - headerBinding.autoplaySwitch.setChecked(autoplay); + headerBinding.autoplaySwitch.setChecked( + sharedPreferences.getBoolean( + getString(R.string.auto_queue_key), false)); } } diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java index 57e6fa380..839125fd1 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java @@ -2,6 +2,7 @@ package org.schabi.newpipe.info_list; import android.content.Context; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,6 +12,7 @@ import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.schabi.newpipe.database.stream.model.StreamStateEntity; +import org.schabi.newpipe.databinding.PignateFooterBinding; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; import org.schabi.newpipe.extractor.comments.CommentsInfoItem; @@ -34,6 +36,7 @@ import org.schabi.newpipe.util.OnClickGesture; import java.util.ArrayList; import java.util.List; +import java.util.function.Supplier; /* * Created by Christian Schabesberger on 01.08.16. @@ -74,6 +77,7 @@ public class InfoListAdapter extends RecyclerView.Adapter infoItemList; private final HistoryRecordManager recordManager; @@ -81,11 +85,12 @@ public class InfoListAdapter extends RecyclerView.Adapter headerSupplier = null; public InfoListAdapter(final Context context) { - this.recordManager = new HistoryRecordManager(context); + layoutInflater = LayoutInflater.from(context); + recordManager = new HistoryRecordManager(context); infoItemBuilder = new InfoItemBuilder(context); infoItemList = new ArrayList<>(); } @@ -129,12 +134,12 @@ public class InfoListAdapter extends RecyclerView.Adapter offsetStart = " + offsetStart + ", " + "infoItemList.size() = " + infoItemList.size() + ", " - + "header = " + header + ", footer = " + footer + ", " + + "header = " + hasHeader() + ", " + "showFooter = " + showFooter); } notifyItemRangeInserted(offsetStart, data.size()); - if (footer != null && showFooter) { + if (showFooter) { final int footerNow = sizeConsideringHeaderOffset(); notifyItemMoved(offsetStart, footerNow); @@ -153,16 +158,16 @@ public class InfoListAdapter extends RecyclerView.Adapter headerSupplier) { + final boolean changed = headerSupplier != this.headerSupplier; + this.headerSupplier = headerSupplier; if (changed) { notifyDataSetChanged(); } } - public void setFooter(final View view) { - this.footer = view; + protected boolean hasHeader() { + return this.headerSupplier != null; } public void showFooter(final boolean show) { @@ -182,7 +187,7 @@ public class InfoListAdapter extends RecyclerView.Adapter Date: Sun, 16 Jan 2022 19:05:51 +0100 Subject: [PATCH 06/10] Reverted to loading behavior of #7638 and improved it The previous/reverted behavior caused unwanted data transmission: * Removed loading via handleResults/loadMoreItems-callback because the RecyclerView is apparently not immediately updated in the UI when the data is set which causes one load of data to much. --- .../fragments/list/BaseListFragment.java | 127 +++++++++--------- .../fragments/list/BaseListInfoFragment.java | 7 +- .../fragments/list/search/SearchFragment.java | 14 +- 3 files changed, 68 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index d1685c5af..279d6d563 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -312,14 +312,74 @@ public abstract class BaseListFragment extends BaseStateFragment }); itemsList.clearOnScrollListeners(); - itemsList.addOnScrollListener(new OnScrollBelowItemsListener() { + + /* + * Add initial scroll listener - which tries to load more items when not enough + * are in the view (not scrollable) and more are available. + * + * Note: This method only works because "This callback will also be called if visible + * item range changes after a layout calculation. In that case, dx and dy will be 0." + * - which might be unexpected because no actual scrolling occurs... + * + * This listener will be replaced by DefaultItemListOnScrolledDownListener when + * * the view was actually scrolled + * * the view is scrollable + * * No more items can be loaded + */ + itemsList.addOnScrollListener(new DefaultItemListOnScrolledDownListener() { @Override - public void onScrolledDown(final RecyclerView recyclerView) { - onScrollToBottom(); + public void onScrolled(final RecyclerView recyclerView, final int dx, final int dy) { + super.onScrolled(recyclerView, dx, dy); + + if (dy != 0) { + log("Vertical scroll occurred"); + + useNormalScrollListener(); + return; + } + if (isLoading.get()) { + log("Still loading data -> Skipping"); + return; + } + if (!hasMoreItems()) { + log("No more items to load"); + + useNormalScrollListener(); + return; + } + if (itemsList.canScrollVertically(1) + || itemsList.canScrollVertically(-1)) { + log("View is scrollable"); + + useNormalScrollListener(); + return; + } + + log("Loading more data"); + loadMoreItems(); + } + + private void useNormalScrollListener() { + log("Unregistering and using normal listener"); + itemsList.removeOnScrollListener(this); + itemsList.addOnScrollListener(new DefaultItemListOnScrolledDownListener()); + } + + private void log(final String msg) { + if (DEBUG) { + Log.d(TAG, "itemListInitScrollListener - " + msg); + } } }); } + class DefaultItemListOnScrolledDownListener extends OnScrollBelowItemsListener { + @Override + public void onScrolledDown(final RecyclerView recyclerView) { + onScrollToBottom(); + } + } + private void onStreamSelected(final StreamInfoItem selectedItem) { onItemSelected(selectedItem); NavigationHelper.openVideoDetailFragment(requireContext(), getFM(), @@ -407,66 +467,7 @@ public abstract class BaseListFragment extends BaseStateFragment // Load and handle //////////////////////////////////////////////////////////////////////////*/ - /** - * If more items are loadable and the itemList is not scrollable -> load more data. - *
- * Should be called once the initial items inside {@link #startLoading(boolean)} - * has been loaded and added to the {@link #itemsList}. - *
- * Otherwise the loading indicator is always shown but no data can be loaded - * because the view is not scrollable; see also #1974. - */ - protected void ifMoreItemsLoadableLoadUntilScrollable() { - ifMoreItemsLoadableLoadUntilScrollable(0); - } - - /** - * If more items are loadable and the itemList is not scrollable -> load more data. - * - * @param recursiveCallCount Amount of recursive calls that occurred - * @see #ifMoreItemsLoadableLoadUntilScrollable() - */ - protected void ifMoreItemsLoadableLoadUntilScrollable(final int recursiveCallCount) { - // Try to prevent malfunction / stackoverflow - if (recursiveCallCount > 100) { - Log.w(TAG, "loadEnoughInitialData - Too many recursive calls - Aborting"); - return; - } - if (!hasMoreItems()) { - if (DEBUG) { - Log.d(TAG, "loadEnoughInitialData - OK: No more items to load"); - } - return; - } - if (itemsList.canScrollVertically(1) - || itemsList.canScrollVertically(-1)) { - if (DEBUG) { - Log.d(TAG, "loadEnoughInitialData - OK: itemList is scrollable"); - } - return; - } - if (DEBUG) { - Log.d(TAG, "loadEnoughInitialData - View is not scrollable " - + "but it could load more items -> Loading more"); - } - loadMoreItems(() -> - ifMoreItemsLoadableLoadUntilScrollable(recursiveCallCount + 1)); - } - - /** - * Loads more items. - * @param initialDataLoadCallback - * Callback used in {@link #ifMoreItemsLoadableLoadUntilScrollable()}. - *
- * Execute it once the data was loaded and added to the {@link #itemsList}. - *
- * Might be null. - */ - protected abstract void loadMoreItems(@Nullable Runnable initialDataLoadCallback); - - protected void loadMoreItems() { - loadMoreItems(null); - } + protected abstract void loadMoreItems(); protected abstract boolean hasMoreItems(); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java index 87f031c12..ebd586e35 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java @@ -6,7 +6,6 @@ import android.util.Log; import android.view.View; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.UserAction; @@ -146,7 +145,6 @@ public abstract class BaseListInfoFragment currentInfo = result; currentNextPage = result.getNextPage(); handleResult(result); - ifMoreItemsLoadableLoadUntilScrollable(); }, throwable -> showError(new ErrorInfo(throwable, errorUserAction, "Start loading: " + url, serviceId))); @@ -162,7 +160,7 @@ public abstract class BaseListInfoFragment protected abstract Single loadMoreItemsLogic(); @Override - protected void loadMoreItems(@Nullable final Runnable initialDataLoadCallback) { + protected void loadMoreItems() { isLoading.set(true); if (currentWorker != null) { @@ -178,9 +176,6 @@ public abstract class BaseListInfoFragment .subscribe(infoItemsPage -> { isLoading.set(false); handleNextItems(infoItemsPage); - if (initialDataLoadCallback != null) { - initialDataLoadCallback.run(); - } }, (@NonNull Throwable throwable) -> dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(throwable, errorUserAction, "Loading more items: " + url, serviceId))); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index 35bb2c349..055c27733 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -868,15 +868,12 @@ public class SearchFragment extends BaseListFragment isLoading.set(false)) - .subscribe(result -> { - handleResult(result); - ifMoreItemsLoadableLoadUntilScrollable(); - }, this::onItemError); + .subscribe(this::handleResult, this::onItemError); } @Override - protected void loadMoreItems(@Nullable final Runnable initialDataLoadCallback) { + protected void loadMoreItems() { if (!Page.isValid(nextPage)) { return; } @@ -894,12 +891,7 @@ public class SearchFragment extends BaseListFragment isLoading.set(false)) - .subscribe(itemsPage -> { - handleNextItems(itemsPage); - if (initialDataLoadCallback != null) { - initialDataLoadCallback.run(); - } - }, this::onItemError); + .subscribe(this::handleNextItems, this::onItemError); } @Override From 85f701b94e8ce730e77bd91024d382d2e0753939 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sun, 16 Jan 2022 19:42:30 +0100 Subject: [PATCH 07/10] Fixed listener not re-registering after e.g. a new search is started --- .../fragments/list/BaseListFragment.java | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index 279d6d563..5b503cb8e 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -304,28 +304,36 @@ public abstract class BaseListFragment extends BaseStateFragment } }); - infoListAdapter.setOnCommentsSelectedListener(new OnClickGesture() { + infoListAdapter.setOnCommentsSelectedListener(new OnClickGesture<>() { @Override public void selected(final CommentsInfoItem selectedItem) { onItemSelected(selectedItem); } }); + } + /** + * Remove all listeners and add the initial scroll listener to the {@link #itemsList}. + *
+ * Which tries to load more items when not enough are in the view (not scrollable) + * and more are available. + *
+ * Note: This method only works because "This callback will also be called if visible + * item range changes after a layout calculation. In that case, dx and dy will be 0." + * - which might be unexpected because no actual scrolling occurs... + *
+ * This listener will be replaced by DefaultItemListOnScrolledDownListener when + *
    + *
  • the view was actually scrolled
  • + *
  • the view is scrollable
  • + *
  • no more items can be loaded
  • + *
+ */ + protected void setItemsListInitialScrollListener() { + if (DEBUG) { + Log.d(TAG, "setItemsListInitialScrollListener called"); + } itemsList.clearOnScrollListeners(); - - /* - * Add initial scroll listener - which tries to load more items when not enough - * are in the view (not scrollable) and more are available. - * - * Note: This method only works because "This callback will also be called if visible - * item range changes after a layout calculation. In that case, dx and dy will be 0." - * - which might be unexpected because no actual scrolling occurs... - * - * This listener will be replaced by DefaultItemListOnScrolledDownListener when - * * the view was actually scrolled - * * the view is scrollable - * * No more items can be loaded - */ itemsList.addOnScrollListener(new DefaultItemListOnScrolledDownListener() { @Override public void onScrolled(final RecyclerView recyclerView, final int dx, final int dy) { @@ -360,7 +368,6 @@ public abstract class BaseListFragment extends BaseStateFragment } private void useNormalScrollListener() { - log("Unregistering and using normal listener"); itemsList.removeOnScrollListener(this); itemsList.addOnScrollListener(new DefaultItemListOnScrolledDownListener()); } @@ -467,6 +474,12 @@ public abstract class BaseListFragment extends BaseStateFragment // Load and handle //////////////////////////////////////////////////////////////////////////*/ + @Override + protected void startLoading(final boolean forceLoad) { + setItemsListInitialScrollListener(); + super.startLoading(forceLoad); + } + protected abstract void loadMoreItems(); protected abstract boolean hasMoreItems(); From 01683aa816b7792bab769b18b0509275b7eed6cc Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Mon, 24 Jan 2022 20:57:23 +0100 Subject: [PATCH 08/10] Code improvements --- .../newpipe/info_list/InfoListAdapter.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java index 839125fd1..718f7004c 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java @@ -79,7 +79,7 @@ public class InfoListAdapter extends RecyclerView.Adapter infoItemList; + private final List infoItemList; private final HistoryRecordManager recordManager; private boolean useMiniVariant = false; @@ -134,7 +134,7 @@ public class InfoListAdapter extends RecyclerView.Adapter offsetStart = " + offsetStart + ", " + "infoItemList.size() = " + infoItemList.size() + ", " - + "header = " + hasHeader() + ", " + + "hasHeader = " + hasHeader() + ", " + "showFooter = " + showFooter); } notifyItemRangeInserted(offsetStart, data.size()); @@ -211,7 +211,7 @@ public class InfoListAdapter extends RecyclerView.Adapter payloads) { + // an empty payload requires a full update (see RecyclerView javadoc) if (payloads.isEmpty() || !(holder instanceof InfoItemHolder)) { onBindViewHolder(holder, position); return; From 9c2cdd251390fab9e4949befe306fd4c7b589a2b Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Thu, 27 Jan 2022 20:41:58 +0100 Subject: [PATCH 09/10] Removed useless code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit → https://github.com/TeamNewPipe/NewPipe/pull/7659#discussion_r793752985 --- .../newpipe/info_list/InfoListAdapter.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java index 718f7004c..fb27593e7 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java @@ -11,7 +11,6 @@ import androidx.annotation.Nullable; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import org.schabi.newpipe.database.stream.model.StreamStateEntity; import org.schabi.newpipe.databinding.PignateFooterBinding; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; @@ -311,24 +310,6 @@ public class InfoListAdapter extends RecyclerView.Adapter payloads) { - // an empty payload requires a full update (see RecyclerView javadoc) - if (payloads.isEmpty() || !(holder instanceof InfoItemHolder)) { - onBindViewHolder(holder, position); - return; - } - - for (final Object payload : payloads) { - if (payload instanceof StreamStateEntity || payload instanceof Boolean) { - ((InfoItemHolder) holder).updateState( - infoItemList.get(hasHeader() ? position - 1 : position), recordManager); - } - } - } - public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int spanCount) { return new GridLayoutManager.SpanSizeLookup() { @Override From 2acaefdb2adce73da19875ec30bb468731ba8904 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Thu, 17 Feb 2022 20:58:53 +0100 Subject: [PATCH 10/10] Fixed scrolling not working when rotating device --- .../fragments/list/BaseListFragment.java | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index 5b503cb8e..6ea0a8a0d 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -310,10 +310,24 @@ public abstract class BaseListFragment extends BaseStateFragment onItemSelected(selectedItem); } }); + + // Ensure that there is always a scroll listener (e.g. when rotating the device) + useNormalItemListScrollListener(); } /** - * Remove all listeners and add the initial scroll listener to the {@link #itemsList}. + * Removes all listeners and adds the normal scroll listener to the {@link #itemsList}. + */ + protected void useNormalItemListScrollListener() { + if (DEBUG) { + Log.d(TAG, "useNormalItemListScrollListener called"); + } + itemsList.clearOnScrollListeners(); + itemsList.addOnScrollListener(new DefaultItemListOnScrolledDownListener()); + } + + /** + * Removes all listeners and adds the initial scroll listener to the {@link #itemsList}. *
* Which tries to load more items when not enough are in the view (not scrollable) * and more are available. @@ -329,9 +343,9 @@ public abstract class BaseListFragment extends BaseStateFragment *
  • no more items can be loaded
  • * */ - protected void setItemsListInitialScrollListener() { + protected void useInitialItemListLoadScrollListener() { if (DEBUG) { - Log.d(TAG, "setItemsListInitialScrollListener called"); + Log.d(TAG, "useInitialItemListLoadScrollListener called"); } itemsList.clearOnScrollListeners(); itemsList.addOnScrollListener(new DefaultItemListOnScrolledDownListener() { @@ -342,7 +356,7 @@ public abstract class BaseListFragment extends BaseStateFragment if (dy != 0) { log("Vertical scroll occurred"); - useNormalScrollListener(); + useNormalItemListScrollListener(); return; } if (isLoading.get()) { @@ -352,14 +366,14 @@ public abstract class BaseListFragment extends BaseStateFragment if (!hasMoreItems()) { log("No more items to load"); - useNormalScrollListener(); + useNormalItemListScrollListener(); return; } if (itemsList.canScrollVertically(1) || itemsList.canScrollVertically(-1)) { log("View is scrollable"); - useNormalScrollListener(); + useNormalItemListScrollListener(); return; } @@ -367,14 +381,9 @@ public abstract class BaseListFragment extends BaseStateFragment loadMoreItems(); } - private void useNormalScrollListener() { - itemsList.removeOnScrollListener(this); - itemsList.addOnScrollListener(new DefaultItemListOnScrolledDownListener()); - } - private void log(final String msg) { if (DEBUG) { - Log.d(TAG, "itemListInitScrollListener - " + msg); + Log.d(TAG, "initItemListLoadScrollListener - " + msg); } } }); @@ -476,7 +485,7 @@ public abstract class BaseListFragment extends BaseStateFragment @Override protected void startLoading(final boolean forceLoad) { - setItemsListInitialScrollListener(); + useInitialItemListLoadScrollListener(); super.startLoading(forceLoad); }