mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 07:50:31 +05:30
fix: multiple recyclerview adapter regressions in SubscriptionsFragment (#7085)
* Fix IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder * Fix new videos not being added to feed * Remove obsolete sortedFeed variable * Display items from start
This commit is contained in:
parent
18dd76093c
commit
481828c0f4
@ -18,9 +18,6 @@ import com.github.libretube.ui.viewholders.SubscriptionChannelViewHolder
|
|||||||
|
|
||||||
class SubscriptionChannelAdapter :
|
class SubscriptionChannelAdapter :
|
||||||
ListAdapter<Subscription, SubscriptionChannelViewHolder>(DiffUtilItemCallback()) {
|
ListAdapter<Subscription, SubscriptionChannelViewHolder>(DiffUtilItemCallback()) {
|
||||||
private var visibleCount = 20
|
|
||||||
|
|
||||||
override fun getItemCount() = minOf(visibleCount, currentList.size)
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(
|
override fun onCreateViewHolder(
|
||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
@ -31,13 +28,6 @@ class SubscriptionChannelAdapter :
|
|||||||
return SubscriptionChannelViewHolder(binding)
|
return SubscriptionChannelViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateItems() {
|
|
||||||
val oldSize = visibleCount
|
|
||||||
visibleCount += minOf(10, currentList.size - oldSize)
|
|
||||||
if (visibleCount == oldSize) return
|
|
||||||
notifyItemRangeInserted(oldSize, visibleCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: SubscriptionChannelViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: SubscriptionChannelViewHolder, position: Int) {
|
||||||
val subscription = getItem(holder.bindingAdapterPosition)
|
val subscription = getItem(holder.bindingAdapterPosition)
|
||||||
|
|
||||||
|
@ -65,8 +65,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
private var isAppBarFullyExpanded = true
|
private var isAppBarFullyExpanded = true
|
||||||
|
|
||||||
private var feedAdapter = VideosAdapter()
|
private var feedAdapter = VideosAdapter()
|
||||||
private val sortedFeed: MutableList<StreamItem> = mutableListOf()
|
|
||||||
|
|
||||||
private var selectedSortOrder = PreferenceHelper.getInt(PreferenceKeys.FEED_SORT_ORDER, 0)
|
private var selectedSortOrder = PreferenceHelper.getInt(PreferenceKeys.FEED_SORT_ORDER, 0)
|
||||||
set(value) {
|
set(value) {
|
||||||
PreferenceHelper.putInt(PreferenceKeys.FEED_SORT_ORDER, value)
|
PreferenceHelper.putInt(PreferenceKeys.FEED_SORT_ORDER, value)
|
||||||
@ -175,15 +173,10 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
|
|
||||||
if (viewModel.subscriptions.value != null && isCurrentTabSubChannels) {
|
if (viewModel.subscriptions.value != null && isCurrentTabSubChannels) {
|
||||||
binding.subRefresh.isRefreshing = true
|
binding.subRefresh.isRefreshing = true
|
||||||
channelsAdapter.updateItems()
|
|
||||||
binding.subRefresh.isRefreshing = false
|
binding.subRefresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.subFeed.addOnBottomReachedListener {
|
|
||||||
loadNextFeedItems()
|
|
||||||
}
|
|
||||||
|
|
||||||
// add some extra margin to the subscribed channels while the mini player is visible
|
// add some extra margin to the subscribed channels while the mini player is visible
|
||||||
// otherwise the last channel would be invisible
|
// otherwise the last channel would be invisible
|
||||||
playerModel.isMiniPlayerVisible.observe(viewLifecycleOwner) {
|
playerModel.isMiniPlayerVisible.observe(viewLifecycleOwner) {
|
||||||
@ -192,8 +185,8 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.channelGroups.setOnCheckedStateChangeListener { group, checkedIds ->
|
binding.channelGroups.setOnCheckedStateChangeListener { group, _ ->
|
||||||
selectedFilterGroup = group.children.indexOfFirst { it.id == checkedIds.first() }
|
selectedFilterGroup = group.children.indexOfFirst { it.id == group.checkedChipId }
|
||||||
if (isCurrentTabSubChannels) showSubscriptions() else showFeed()
|
if (isCurrentTabSubChannels) showSubscriptions() else showFeed()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,25 +224,22 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadNextFeedItems() {
|
private fun loadFeedItems(sortedFeed: List<StreamItem>) {
|
||||||
val binding = _binding ?: return
|
val binding = _binding ?: return
|
||||||
|
|
||||||
val hasMore = sortedFeed.size > feedAdapter.itemCount
|
if (viewModel.videoFeed.value != null && !isCurrentTabSubChannels && !binding.subRefresh.isRefreshing) {
|
||||||
if (viewModel.videoFeed.value != null && !isCurrentTabSubChannels && !binding.subRefresh.isRefreshing && hasMore) {
|
|
||||||
binding.subRefresh.isRefreshing = true
|
binding.subRefresh.isRefreshing = true
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val toIndex = minOf(feedAdapter.itemCount + 10, sortedFeed.size)
|
val streamItemsToInsert = sortedFeed.let {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
var streamItemsToInsert = sortedFeed
|
runCatching { it.deArrow() }.getOrDefault(it)
|
||||||
.subList(feedAdapter.itemCount, toIndex)
|
}
|
||||||
.toList()
|
|
||||||
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
runCatching { streamItemsToInsert = streamItemsToInsert.deArrow() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
feedAdapter.insertItems(streamItemsToInsert)
|
feedAdapter.submitList(streamItemsToInsert) {
|
||||||
|
binding.subFeed.scrollToPosition(0)
|
||||||
|
}
|
||||||
binding.subRefresh.isRefreshing = false
|
binding.subRefresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,15 +373,13 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
val sorted = feed
|
val sorted = feed
|
||||||
.sortedBySelectedOrder()
|
.sortedBySelectedOrder()
|
||||||
.toMutableList()
|
.toMutableList()
|
||||||
sortedFeed.clear()
|
|
||||||
sortedFeed.addAll(sorted)
|
|
||||||
|
|
||||||
// add an "all caught up item"
|
// add an "all caught up item"
|
||||||
if (selectedSortOrder == 0) {
|
if (selectedSortOrder == 0) {
|
||||||
val lastCheckedFeedTime = PreferenceHelper.getLastCheckedFeedTime()
|
val lastCheckedFeedTime = PreferenceHelper.getLastCheckedFeedTime()
|
||||||
val caughtUpIndex = feed.indexOfFirst { it.uploaded <= lastCheckedFeedTime && !it.isUpcoming }
|
val caughtUpIndex = feed.indexOfFirst { it.uploaded <= lastCheckedFeedTime && !it.isUpcoming }
|
||||||
if (caughtUpIndex > 0) {
|
if (caughtUpIndex > 0) {
|
||||||
sortedFeed.add(
|
sorted.add(
|
||||||
caughtUpIndex,
|
caughtUpIndex,
|
||||||
StreamItem(type = VideosAdapter.CAUGHT_UP_STREAM_TYPE)
|
StreamItem(type = VideosAdapter.CAUGHT_UP_STREAM_TYPE)
|
||||||
)
|
)
|
||||||
@ -404,13 +392,13 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
val notLoaded = viewModel.videoFeed.value.isNullOrEmpty()
|
val notLoaded = viewModel.videoFeed.value.isNullOrEmpty()
|
||||||
binding.subFeed.isGone = notLoaded
|
binding.subFeed.isGone = notLoaded
|
||||||
binding.emptyFeed.isVisible = notLoaded
|
binding.emptyFeed.isVisible = notLoaded
|
||||||
loadNextFeedItems()
|
loadFeedItems(sorted)
|
||||||
|
|
||||||
binding.toggleSubs.text = getString(R.string.subscriptions)
|
binding.toggleSubs.text = getString(R.string.subscriptions)
|
||||||
|
|
||||||
feed.firstOrNull { !it.isUpcoming }?.uploaded?.let {
|
feed.firstOrNull { !it.isUpcoming }?.uploaded?.let {
|
||||||
PreferenceHelper.setLastFeedWatchedTime(it)
|
PreferenceHelper.setLastFeedWatchedTime(it)
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@ -423,9 +411,13 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (legacySubscriptions) {
|
if (legacySubscriptions) {
|
||||||
legacySubscriptionsAdapter.submitList(subscriptions)
|
legacySubscriptionsAdapter.submitList(subscriptions) {
|
||||||
|
binding.subFeed.scrollToPosition(0)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
channelsAdapter.submitList(subscriptions)
|
channelsAdapter.submitList(subscriptions) {
|
||||||
|
binding.subFeed.scrollToPosition(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.subRefresh.isRefreshing = false
|
binding.subRefresh.isRefreshing = false
|
||||||
@ -442,7 +434,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
|
|
||||||
fun removeItem(videoId: String) {
|
fun removeItem(videoId: String) {
|
||||||
feedAdapter.removeItemById(videoId)
|
feedAdapter.removeItemById(videoId)
|
||||||
sortedFeed.removeAll { it.url?.toID() != videoId }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user