Skip to content

Commit 481828c

Browse files
fix: multiple recyclerview adapter regressions in SubscriptionsFragment (libre-tube#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
1 parent 18dd760 commit 481828c

2 files changed

Lines changed: 20 additions & 39 deletions

File tree

app/src/main/java/com/github/libretube/ui/adapters/SubscriptionChannelAdapter.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ import com.github.libretube.ui.viewholders.SubscriptionChannelViewHolder
1818

1919
class SubscriptionChannelAdapter :
2020
ListAdapter<Subscription, SubscriptionChannelViewHolder>(DiffUtilItemCallback()) {
21-
private var visibleCount = 20
22-
23-
override fun getItemCount() = minOf(visibleCount, currentList.size)
2421

2522
override fun onCreateViewHolder(
2623
parent: ViewGroup,
@@ -31,13 +28,6 @@ class SubscriptionChannelAdapter :
3128
return SubscriptionChannelViewHolder(binding)
3229
}
3330

34-
fun updateItems() {
35-
val oldSize = visibleCount
36-
visibleCount += minOf(10, currentList.size - oldSize)
37-
if (visibleCount == oldSize) return
38-
notifyItemRangeInserted(oldSize, visibleCount)
39-
}
40-
4131
override fun onBindViewHolder(holder: SubscriptionChannelViewHolder, position: Int) {
4232
val subscription = getItem(holder.bindingAdapterPosition)
4333

app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
6565
private var isAppBarFullyExpanded = true
6666

6767
private var feedAdapter = VideosAdapter()
68-
private val sortedFeed: MutableList<StreamItem> = mutableListOf()
69-
7068
private var selectedSortOrder = PreferenceHelper.getInt(PreferenceKeys.FEED_SORT_ORDER, 0)
7169
set(value) {
7270
PreferenceHelper.putInt(PreferenceKeys.FEED_SORT_ORDER, value)
@@ -175,15 +173,10 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
175173

176174
if (viewModel.subscriptions.value != null && isCurrentTabSubChannels) {
177175
binding.subRefresh.isRefreshing = true
178-
channelsAdapter.updateItems()
179176
binding.subRefresh.isRefreshing = false
180177
}
181178
}
182179

183-
binding.subFeed.addOnBottomReachedListener {
184-
loadNextFeedItems()
185-
}
186-
187180
// add some extra margin to the subscribed channels while the mini player is visible
188181
// otherwise the last channel would be invisible
189182
playerModel.isMiniPlayerVisible.observe(viewLifecycleOwner) {
@@ -192,8 +185,8 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
192185
}
193186
}
194187

195-
binding.channelGroups.setOnCheckedStateChangeListener { group, checkedIds ->
196-
selectedFilterGroup = group.children.indexOfFirst { it.id == checkedIds.first() }
188+
binding.channelGroups.setOnCheckedStateChangeListener { group, _ ->
189+
selectedFilterGroup = group.children.indexOfFirst { it.id == group.checkedChipId }
197190
if (isCurrentTabSubChannels) showSubscriptions() else showFeed()
198191
}
199192

@@ -231,25 +224,22 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
231224
}
232225
}
233226

234-
private fun loadNextFeedItems() {
227+
private fun loadFeedItems(sortedFeed: List<StreamItem>) {
235228
val binding = _binding ?: return
236229

237-
val hasMore = sortedFeed.size > feedAdapter.itemCount
238-
if (viewModel.videoFeed.value != null && !isCurrentTabSubChannels && !binding.subRefresh.isRefreshing && hasMore) {
230+
if (viewModel.videoFeed.value != null && !isCurrentTabSubChannels && !binding.subRefresh.isRefreshing) {
239231
binding.subRefresh.isRefreshing = true
240232

241233
lifecycleScope.launch {
242-
val toIndex = minOf(feedAdapter.itemCount + 10, sortedFeed.size)
243-
244-
var streamItemsToInsert = sortedFeed
245-
.subList(feedAdapter.itemCount, toIndex)
246-
.toList()
247-
248-
withContext(Dispatchers.IO) {
249-
runCatching { streamItemsToInsert = streamItemsToInsert.deArrow() }
234+
val streamItemsToInsert = sortedFeed.let {
235+
withContext(Dispatchers.IO) {
236+
runCatching { it.deArrow() }.getOrDefault(it)
237+
}
250238
}
251239

252-
feedAdapter.insertItems(streamItemsToInsert)
240+
feedAdapter.submitList(streamItemsToInsert) {
241+
binding.subFeed.scrollToPosition(0)
242+
}
253243
binding.subRefresh.isRefreshing = false
254244
}
255245
}
@@ -383,15 +373,13 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
383373
val sorted = feed
384374
.sortedBySelectedOrder()
385375
.toMutableList()
386-
sortedFeed.clear()
387-
sortedFeed.addAll(sorted)
388376

389377
// add an "all caught up item"
390378
if (selectedSortOrder == 0) {
391379
val lastCheckedFeedTime = PreferenceHelper.getLastCheckedFeedTime()
392380
val caughtUpIndex = feed.indexOfFirst { it.uploaded <= lastCheckedFeedTime && !it.isUpcoming }
393381
if (caughtUpIndex > 0) {
394-
sortedFeed.add(
382+
sorted.add(
395383
caughtUpIndex,
396384
StreamItem(type = VideosAdapter.CAUGHT_UP_STREAM_TYPE)
397385
)
@@ -404,13 +392,13 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
404392
val notLoaded = viewModel.videoFeed.value.isNullOrEmpty()
405393
binding.subFeed.isGone = notLoaded
406394
binding.emptyFeed.isVisible = notLoaded
407-
loadNextFeedItems()
395+
loadFeedItems(sorted)
408396

409397
binding.toggleSubs.text = getString(R.string.subscriptions)
410398

411399
feed.firstOrNull { !it.isUpcoming }?.uploaded?.let {
412400
PreferenceHelper.setLastFeedWatchedTime(it)
413-
};
401+
}
414402
}
415403

416404
@SuppressLint("SetTextI18n")
@@ -423,9 +411,13 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
423411
)
424412

425413
if (legacySubscriptions) {
426-
legacySubscriptionsAdapter.submitList(subscriptions)
414+
legacySubscriptionsAdapter.submitList(subscriptions) {
415+
binding.subFeed.scrollToPosition(0)
416+
}
427417
} else {
428-
channelsAdapter.submitList(subscriptions)
418+
channelsAdapter.submitList(subscriptions) {
419+
binding.subFeed.scrollToPosition(0)
420+
}
429421
}
430422

431423
binding.subRefresh.isRefreshing = false
@@ -442,7 +434,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
442434

443435
fun removeItem(videoId: String) {
444436
feedAdapter.removeItemById(videoId)
445-
sortedFeed.removeAll { it.url?.toID() != videoId }
446437
}
447438

448439
override fun onConfigurationChanged(newConfig: Configuration) {

0 commit comments

Comments
 (0)