mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +00:00 
			
		
		
		
	* 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
This commit is contained in:
		| @@ -17,10 +17,8 @@ import androidx.appcompat.app.ActionBar; | |||||||
| import androidx.preference.PreferenceManager; | import androidx.preference.PreferenceManager; | ||||||
| import androidx.recyclerview.widget.GridLayoutManager; | import androidx.recyclerview.widget.GridLayoutManager; | ||||||
| import androidx.recyclerview.widget.RecyclerView; | import androidx.recyclerview.widget.RecyclerView; | ||||||
| import androidx.viewbinding.ViewBinding; |  | ||||||
|  |  | ||||||
| import org.schabi.newpipe.R; | import org.schabi.newpipe.R; | ||||||
| import org.schabi.newpipe.databinding.PignateFooterBinding; |  | ||||||
| import org.schabi.newpipe.error.ErrorUtil; | import org.schabi.newpipe.error.ErrorUtil; | ||||||
| import org.schabi.newpipe.extractor.InfoItem; | import org.schabi.newpipe.extractor.InfoItem; | ||||||
| import org.schabi.newpipe.extractor.channel.ChannelInfoItem; | import org.schabi.newpipe.extractor.channel.ChannelInfoItem; | ||||||
| @@ -44,6 +42,7 @@ import java.util.ArrayList; | |||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Queue; | import java.util.Queue; | ||||||
|  | import java.util.function.Supplier; | ||||||
|  |  | ||||||
| import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; | import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; | ||||||
| import static org.schabi.newpipe.ktx.ViewUtils.animate; | import static org.schabi.newpipe.ktx.ViewUtils.animate; | ||||||
| @@ -215,14 +214,10 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> | |||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     @Nullable |     @Nullable | ||||||
|     protected ViewBinding getListHeader() { |     protected Supplier<View> getListHeaderSupplier() { | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     protected ViewBinding getListFooter() { |  | ||||||
|         return PignateFooterBinding.inflate(activity.getLayoutInflater(), itemsList, false); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     protected RecyclerView.LayoutManager getListLayoutManager() { |     protected RecyclerView.LayoutManager getListLayoutManager() { | ||||||
|         return new SuperScrollLayoutManager(activity); |         return new SuperScrollLayoutManager(activity); | ||||||
|     } |     } | ||||||
| @@ -247,11 +242,10 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> | |||||||
|         itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager()); |         itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager()); | ||||||
|  |  | ||||||
|         infoListAdapter.setUseGridVariant(useGrid); |         infoListAdapter.setUseGridVariant(useGrid); | ||||||
|         infoListAdapter.setFooter(getListFooter().getRoot()); |  | ||||||
|  |  | ||||||
|         final ViewBinding listHeader = getListHeader(); |         final Supplier<View> listHeaderSupplier = getListHeaderSupplier(); | ||||||
|         if (listHeader != null) { |         if (listHeaderSupplier != null) { | ||||||
|             infoListAdapter.setHeader(listHeader.getRoot()); |             infoListAdapter.setHeaderSupplier(listHeaderSupplier); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         itemsList.setAdapter(infoListAdapter); |         itemsList.setAdapter(infoListAdapter); | ||||||
| @@ -447,7 +441,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> | |||||||
|         if (itemsList.canScrollVertically(1) |         if (itemsList.canScrollVertically(1) | ||||||
|                 || itemsList.canScrollVertically(-1)) { |                 || itemsList.canScrollVertically(-1)) { | ||||||
|             if (DEBUG) { |             if (DEBUG) { | ||||||
|                 Log.d(TAG, "loadEnoughInitial - OK: itemList is scrollable"); |                 Log.d(TAG, "loadEnoughInitialData - OK: itemList is scrollable"); | ||||||
|             } |             } | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,5 +1,9 @@ | |||||||
| package org.schabi.newpipe.fragments.list.channel; | 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.content.Context; | ||||||
| import android.os.Bundle; | import android.os.Bundle; | ||||||
| import android.text.TextUtils; | import android.text.TextUtils; | ||||||
| @@ -17,7 +21,6 @@ import androidx.annotation.NonNull; | |||||||
| import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||||
| import androidx.appcompat.app.ActionBar; | import androidx.appcompat.app.ActionBar; | ||||||
| import androidx.core.content.ContextCompat; | import androidx.core.content.ContextCompat; | ||||||
| import androidx.viewbinding.ViewBinding; |  | ||||||
|  |  | ||||||
| import com.jakewharton.rxbinding4.view.RxView; | 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.ErrorInfo; | ||||||
| import org.schabi.newpipe.error.ErrorUtil; | import org.schabi.newpipe.error.ErrorUtil; | ||||||
| import org.schabi.newpipe.error.UserAction; | import org.schabi.newpipe.error.UserAction; | ||||||
| import org.schabi.newpipe.extractor.InfoItem; |  | ||||||
| import org.schabi.newpipe.extractor.ListExtractor; | import org.schabi.newpipe.extractor.ListExtractor; | ||||||
| import org.schabi.newpipe.extractor.channel.ChannelInfo; | import org.schabi.newpipe.extractor.channel.ChannelInfo; | ||||||
| import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; | 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.ExtractorHelper; | ||||||
| import org.schabi.newpipe.util.Localization; | import org.schabi.newpipe.util.Localization; | ||||||
| import org.schabi.newpipe.util.NavigationHelper; | 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.PicassoHelper; | ||||||
| import org.schabi.newpipe.util.ThemeHelper; | 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.List; | ||||||
| import java.util.concurrent.TimeUnit; | 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.android.schedulers.AndroidSchedulers; | ||||||
| import io.reactivex.rxjava3.core.Observable; | 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.functions.Function; | ||||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | 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<ChannelInfo> | public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | ||||||
|         implements View.OnClickListener { |         implements View.OnClickListener { | ||||||
|  |  | ||||||
| @@ -145,12 +144,12 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected ViewBinding getListHeader() { |     protected Supplier<View> getListHeaderSupplier() { | ||||||
|         headerBinding = ChannelHeaderBinding |         headerBinding = ChannelHeaderBinding | ||||||
|                 .inflate(activity.getLayoutInflater(), itemsList, false); |                 .inflate(activity.getLayoutInflater(), itemsList, false); | ||||||
|         playlistControlBinding = headerBinding.playlistControl; |         playlistControlBinding = headerBinding.playlistControl; | ||||||
|  |  | ||||||
|         return headerBinding; |         return headerBinding::getRoot; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -1,5 +1,9 @@ | |||||||
| package org.schabi.newpipe.fragments.list.playlist; | 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.app.Activity; | ||||||
| import android.content.Context; | import android.content.Context; | ||||||
| import android.os.Bundle; | import android.os.Bundle; | ||||||
| @@ -15,7 +19,6 @@ import android.view.ViewGroup; | |||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
| import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||||
| import androidx.appcompat.content.res.AppCompatResources; | import androidx.appcompat.content.res.AppCompatResources; | ||||||
| import androidx.viewbinding.ViewBinding; |  | ||||||
|  |  | ||||||
| import org.reactivestreams.Subscriber; | import org.reactivestreams.Subscriber; | ||||||
| import org.reactivestreams.Subscription; | 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.PlayQueue; | ||||||
| import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue; | import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue; | ||||||
| import org.schabi.newpipe.util.ExtractorHelper; | 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.Localization; | ||||||
| import org.schabi.newpipe.util.NavigationHelper; | 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.StreamDialogEntry; | ||||||
|  | import org.schabi.newpipe.util.external_communication.KoreUtils; | ||||||
|  | import org.schabi.newpipe.util.external_communication.ShareUtils; | ||||||
|  |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.concurrent.atomic.AtomicBoolean; | import java.util.concurrent.atomic.AtomicBoolean; | ||||||
|  | import java.util.function.Supplier; | ||||||
|  |  | ||||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||||
| import io.reactivex.rxjava3.core.Flowable; | 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.CompositeDisposable; | ||||||
| import io.reactivex.rxjava3.disposables.Disposable; | 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<PlaylistInfo> { | public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | ||||||
|  |  | ||||||
|     private static final String PICASSO_PLAYLIST_TAG = "PICASSO_PLAYLIST_TAG"; |     private static final String PICASSO_PLAYLIST_TAG = "PICASSO_PLAYLIST_TAG"; | ||||||
| @@ -120,12 +120,12 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | |||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected ViewBinding getListHeader() { |     protected Supplier<View> getListHeaderSupplier() { | ||||||
|         headerBinding = PlaylistHeaderBinding |         headerBinding = PlaylistHeaderBinding | ||||||
|                 .inflate(activity.getLayoutInflater(), itemsList, false); |                 .inflate(activity.getLayoutInflater(), itemsList, false); | ||||||
|         playlistControlBinding = headerBinding.playlistControl; |         playlistControlBinding = headerBinding.playlistControl; | ||||||
|  |  | ||||||
|         return headerBinding; |         return headerBinding::getRoot; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| package org.schabi.newpipe.fragments.list.videos; | package org.schabi.newpipe.fragments.list.videos; | ||||||
|  |  | ||||||
| import android.content.Context; |  | ||||||
| import android.content.SharedPreferences; | import android.content.SharedPreferences; | ||||||
| import android.os.Bundle; | import android.os.Bundle; | ||||||
| import android.view.LayoutInflater; | import android.view.LayoutInflater; | ||||||
| @@ -12,7 +11,6 @@ import android.view.ViewGroup; | |||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
| import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||||
| import androidx.preference.PreferenceManager; | import androidx.preference.PreferenceManager; | ||||||
| import androidx.viewbinding.ViewBinding; |  | ||||||
|  |  | ||||||
| import org.schabi.newpipe.R; | import org.schabi.newpipe.R; | ||||||
| import org.schabi.newpipe.databinding.RelatedItemsHeaderBinding; | import org.schabi.newpipe.databinding.RelatedItemsHeaderBinding; | ||||||
| @@ -24,6 +22,7 @@ import org.schabi.newpipe.ktx.ViewUtils; | |||||||
| import org.schabi.newpipe.util.RelatedItemInfo; | import org.schabi.newpipe.util.RelatedItemInfo; | ||||||
|  |  | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
|  | import java.util.function.Supplier; | ||||||
|  |  | ||||||
| import io.reactivex.rxjava3.core.Single; | import io.reactivex.rxjava3.core.Single; | ||||||
|  |  | ||||||
| @@ -60,9 +59,6 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo> | |||||||
|         return inflater.inflate(R.layout.fragment_related_items, container, false); |         return inflater.inflate(R.layout.fragment_related_items, container, false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void onDestroyView() { |     public void onDestroyView() { | ||||||
|         headerBinding = null; |         headerBinding = null; | ||||||
| @@ -70,8 +66,11 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo> | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected ViewBinding getListHeader() { |     protected Supplier<View> getListHeaderSupplier() { | ||||||
|         if (relatedItemInfo != null && relatedItemInfo.getRelatedItems() != null) { |         if (relatedItemInfo == null || relatedItemInfo.getRelatedItems() == null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         headerBinding = RelatedItemsHeaderBinding |         headerBinding = RelatedItemsHeaderBinding | ||||||
|                 .inflate(activity.getLayoutInflater(), itemsList, false); |                 .inflate(activity.getLayoutInflater(), itemsList, false); | ||||||
|  |  | ||||||
| @@ -82,10 +81,8 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo> | |||||||
|         headerBinding.autoplaySwitch.setOnCheckedChangeListener((compoundButton, b) -> |         headerBinding.autoplaySwitch.setOnCheckedChangeListener((compoundButton, b) -> | ||||||
|                 PreferenceManager.getDefaultSharedPreferences(requireContext()).edit() |                 PreferenceManager.getDefaultSharedPreferences(requireContext()).edit() | ||||||
|                         .putBoolean(getString(R.string.auto_queue_key), b).apply()); |                         .putBoolean(getString(R.string.auto_queue_key), b).apply()); | ||||||
|             return headerBinding; |  | ||||||
|         } else { |         return headerBinding::getRoot; | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -161,11 +158,10 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo> | |||||||
|     @Override |     @Override | ||||||
|     public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, |     public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, | ||||||
|                                           final String s) { |                                           final String s) { | ||||||
|         final SharedPreferences pref = |  | ||||||
|                 PreferenceManager.getDefaultSharedPreferences(requireContext()); |  | ||||||
|         final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false); |  | ||||||
|         if (headerBinding != null) { |         if (headerBinding != null) { | ||||||
|             headerBinding.autoplaySwitch.setChecked(autoplay); |             headerBinding.autoplaySwitch.setChecked( | ||||||
|  |                     sharedPreferences.getBoolean( | ||||||
|  |                             getString(R.string.auto_queue_key), false)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package org.schabi.newpipe.info_list; | |||||||
|  |  | ||||||
| import android.content.Context; | import android.content.Context; | ||||||
| import android.util.Log; | import android.util.Log; | ||||||
|  | import android.view.LayoutInflater; | ||||||
| import android.view.View; | import android.view.View; | ||||||
| import android.view.ViewGroup; | import android.view.ViewGroup; | ||||||
|  |  | ||||||
| @@ -11,6 +12,7 @@ import androidx.recyclerview.widget.GridLayoutManager; | |||||||
| import androidx.recyclerview.widget.RecyclerView; | import androidx.recyclerview.widget.RecyclerView; | ||||||
|  |  | ||||||
| import org.schabi.newpipe.database.stream.model.StreamStateEntity; | 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.InfoItem; | ||||||
| import org.schabi.newpipe.extractor.channel.ChannelInfoItem; | import org.schabi.newpipe.extractor.channel.ChannelInfoItem; | ||||||
| import org.schabi.newpipe.extractor.comments.CommentsInfoItem; | import org.schabi.newpipe.extractor.comments.CommentsInfoItem; | ||||||
| @@ -34,6 +36,7 @@ import org.schabi.newpipe.util.OnClickGesture; | |||||||
|  |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.function.Supplier; | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Created by Christian Schabesberger on 01.08.16. |  * Created by Christian Schabesberger on 01.08.16. | ||||||
| @@ -74,6 +77,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|     private static final int MINI_COMMENT_HOLDER_TYPE = 0x400; |     private static final int MINI_COMMENT_HOLDER_TYPE = 0x400; | ||||||
|     private static final int COMMENT_HOLDER_TYPE = 0x401; |     private static final int COMMENT_HOLDER_TYPE = 0x401; | ||||||
|  |  | ||||||
|  |     private final LayoutInflater layoutInflater; | ||||||
|     private final InfoItemBuilder infoItemBuilder; |     private final InfoItemBuilder infoItemBuilder; | ||||||
|     private final ArrayList<InfoItem> infoItemList; |     private final ArrayList<InfoItem> infoItemList; | ||||||
|     private final HistoryRecordManager recordManager; |     private final HistoryRecordManager recordManager; | ||||||
| @@ -81,11 +85,12 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|     private boolean useMiniVariant = false; |     private boolean useMiniVariant = false; | ||||||
|     private boolean useGridVariant = false; |     private boolean useGridVariant = false; | ||||||
|     private boolean showFooter = false; |     private boolean showFooter = false; | ||||||
|     private View header = null; |  | ||||||
|     private View footer = null; |     private Supplier<View> headerSupplier = null; | ||||||
|  |  | ||||||
|     public InfoListAdapter(final Context context) { |     public InfoListAdapter(final Context context) { | ||||||
|         this.recordManager = new HistoryRecordManager(context); |         layoutInflater = LayoutInflater.from(context); | ||||||
|  |         recordManager = new HistoryRecordManager(context); | ||||||
|         infoItemBuilder = new InfoItemBuilder(context); |         infoItemBuilder = new InfoItemBuilder(context); | ||||||
|         infoItemList = new ArrayList<>(); |         infoItemList = new ArrayList<>(); | ||||||
|     } |     } | ||||||
| @@ -129,12 +134,12 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|         if (DEBUG) { |         if (DEBUG) { | ||||||
|             Log.d(TAG, "addInfoItemList() after > offsetStart = " + offsetStart + ", " |             Log.d(TAG, "addInfoItemList() after > offsetStart = " + offsetStart + ", " | ||||||
|                     + "infoItemList.size() = " + infoItemList.size() + ", " |                     + "infoItemList.size() = " + infoItemList.size() + ", " | ||||||
|                     + "header = " + header + ", footer = " + footer + ", " |                     + "header = " + hasHeader() + ", " | ||||||
|                     + "showFooter = " + showFooter); |                     + "showFooter = " + showFooter); | ||||||
|         } |         } | ||||||
|         notifyItemRangeInserted(offsetStart, data.size()); |         notifyItemRangeInserted(offsetStart, data.size()); | ||||||
|  |  | ||||||
|         if (footer != null && showFooter) { |         if (showFooter) { | ||||||
|             final int footerNow = sizeConsideringHeaderOffset(); |             final int footerNow = sizeConsideringHeaderOffset(); | ||||||
|             notifyItemMoved(offsetStart, footerNow); |             notifyItemMoved(offsetStart, footerNow); | ||||||
|  |  | ||||||
| @@ -153,16 +158,16 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|         notifyDataSetChanged(); |         notifyDataSetChanged(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setHeader(final View header) { |     public void setHeaderSupplier(@Nullable final Supplier<View> headerSupplier) { | ||||||
|         final boolean changed = header != this.header; |         final boolean changed = headerSupplier != this.headerSupplier; | ||||||
|         this.header = header; |         this.headerSupplier = headerSupplier; | ||||||
|         if (changed) { |         if (changed) { | ||||||
|             notifyDataSetChanged(); |             notifyDataSetChanged(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setFooter(final View view) { |     protected boolean hasHeader() { | ||||||
|         this.footer = view; |         return this.headerSupplier != null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void showFooter(final boolean show) { |     public void showFooter(final boolean show) { | ||||||
| @@ -182,7 +187,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     private int sizeConsideringHeaderOffset() { |     private int sizeConsideringHeaderOffset() { | ||||||
|         final int i = infoItemList.size() + (header != null ? 1 : 0); |         final int i = infoItemList.size() + (hasHeader() ? 1 : 0); | ||||||
|         if (DEBUG) { |         if (DEBUG) { | ||||||
|             Log.d(TAG, "sizeConsideringHeaderOffset() called → " + i); |             Log.d(TAG, "sizeConsideringHeaderOffset() called → " + i); | ||||||
|         } |         } | ||||||
| @@ -196,17 +201,17 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|     @Override |     @Override | ||||||
|     public int getItemCount() { |     public int getItemCount() { | ||||||
|         int count = infoItemList.size(); |         int count = infoItemList.size(); | ||||||
|         if (header != null) { |         if (hasHeader()) { | ||||||
|             count++; |             count++; | ||||||
|         } |         } | ||||||
|         if (footer != null && showFooter) { |         if (showFooter) { | ||||||
|             count++; |             count++; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (DEBUG) { |         if (DEBUG) { | ||||||
|             Log.d(TAG, "getItemCount() called with: " |             Log.d(TAG, "getItemCount() called with: " | ||||||
|                     + "count = " + count + ", infoItemList.size() = " + infoItemList.size() + ", " |                     + "count = " + count + ", infoItemList.size() = " + infoItemList.size() + ", " | ||||||
|                     + "header = " + header + ", footer = " + footer + ", " |                     + "header = " + hasHeader() + ", " | ||||||
|                     + "showFooter = " + showFooter); |                     + "showFooter = " + showFooter); | ||||||
|         } |         } | ||||||
|         return count; |         return count; | ||||||
| @@ -219,12 +224,12 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|             Log.d(TAG, "getItemViewType() called with: position = [" + position + "]"); |             Log.d(TAG, "getItemViewType() called with: position = [" + position + "]"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (header != null && position == 0) { |         if (hasHeader() && position == 0) { | ||||||
|             return HEADER_TYPE; |             return HEADER_TYPE; | ||||||
|         } else if (header != null) { |         } else if (hasHeader()) { | ||||||
|             position--; |             position--; | ||||||
|         } |         } | ||||||
|         if (footer != null && position == infoItemList.size() && showFooter) { |         if (position == infoItemList.size() && showFooter) { | ||||||
|             return FOOTER_TYPE; |             return FOOTER_TYPE; | ||||||
|         } |         } | ||||||
|         final InfoItem item = infoItemList.get(position); |         final InfoItem item = infoItemList.get(position); | ||||||
| @@ -254,10 +259,16 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|                     + "parent = [" + parent + "], type = [" + type + "]"); |                     + "parent = [" + parent + "], type = [" + type + "]"); | ||||||
|         } |         } | ||||||
|         switch (type) { |         switch (type) { | ||||||
|  |             // #4475 and #3368 | ||||||
|  |             // Always create a new instance otherwise the same instance | ||||||
|  |             // is sometimes reused which causes a crash | ||||||
|             case HEADER_TYPE: |             case HEADER_TYPE: | ||||||
|                 return new HFHolder(header); |                 return new HFHolder(headerSupplier.get()); | ||||||
|             case FOOTER_TYPE: |             case FOOTER_TYPE: | ||||||
|                 return new HFHolder(footer); |                 return new HFHolder(PignateFooterBinding | ||||||
|  |                         .inflate(layoutInflater, parent, false) | ||||||
|  |                         .getRoot() | ||||||
|  |                 ); | ||||||
|             case MINI_STREAM_HOLDER_TYPE: |             case MINI_STREAM_HOLDER_TYPE: | ||||||
|                 return new StreamMiniInfoItemHolder(infoItemBuilder, parent); |                 return new StreamMiniInfoItemHolder(infoItemBuilder, parent); | ||||||
|             case STREAM_HOLDER_TYPE: |             case STREAM_HOLDER_TYPE: | ||||||
| @@ -295,7 +306,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|         } |         } | ||||||
|         if (holder instanceof InfoItemHolder) { |         if (holder instanceof InfoItemHolder) { | ||||||
|             // If header isn't null, offset the items by -1 |             // If header isn't null, offset the items by -1 | ||||||
|             if (header != null) { |             if (hasHeader()) { | ||||||
|                 position--; |                 position--; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -314,8 +325,8 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|  |  | ||||||
|         for (final Object payload : payloads) { |         for (final Object payload : payloads) { | ||||||
|             if (payload instanceof StreamStateEntity || payload instanceof Boolean) { |             if (payload instanceof StreamStateEntity || payload instanceof Boolean) { | ||||||
|                 ((InfoItemHolder) holder).updateState(infoItemList |                 ((InfoItemHolder) holder).updateState( | ||||||
|                         .get(header == null ? position : position - 1), recordManager); |                         infoItemList.get(hasHeader() ? position - 1 : position), recordManager); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -330,7 +341,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static class HFHolder extends RecyclerView.ViewHolder { |     static class HFHolder extends RecyclerView.ViewHolder { | ||||||
|         HFHolder(final View v) { |         HFHolder(final View v) { | ||||||
|             super(v); |             super(v); | ||||||
|         } |         } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 litetex
					litetex