From 800d6704cfc3f9c99400d232ed58508b424559e5 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Mon, 6 May 2024 14:05:50 +0200 Subject: [PATCH] feat: add pagination to dearrow in feed --- .../libretube/ui/adapters/VideosAdapter.kt | 20 +------ .../ui/fragments/SubscriptionsFragment.kt | 54 ++++++++++++++----- .../ui/sheets/VideoOptionsBottomSheet.kt | 2 +- 3 files changed, 44 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt index 8f7360ff0..5fd1cd5f7 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt @@ -34,30 +34,14 @@ import com.github.libretube.util.TextUtils class VideosAdapter( private val streamItems: MutableList, - private val showAllAtOnce: Boolean = true, private val forceMode: LayoutMode = LayoutMode.RESPECT_PREF ) : RecyclerView.Adapter() { - - private var visibleCount = minOf(10, streamItems.size) - - override fun getItemCount(): Int { - return when { - showAllAtOnce -> streamItems.size - else -> minOf(streamItems.size, visibleCount) - } - } + override fun getItemCount() = streamItems.size override fun getItemViewType(position: Int): Int { return if (streamItems[position].type == CAUGHT_UP_STREAM_TYPE) CAUGHT_UP_TYPE else NORMAL_TYPE } - fun updateItems() { - val oldSize = visibleCount - visibleCount += minOf(10, streamItems.size - oldSize) - if (visibleCount == oldSize) return - notifyItemRangeInserted(oldSize, visibleCount) - } - fun insertItems(newItems: List) { val feedSize = streamItems.size streamItems.addAll(newItems) @@ -69,7 +53,7 @@ class VideosAdapter( it.url?.toID() == videoId }.takeIf { it > 0 } ?: return streamItems.removeAt(index) - visibleCount-- + notifyItemRemoved(index) notifyItemRangeChanged(index, itemCount) } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt index ea4081f96..e90de2371 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt @@ -45,9 +45,11 @@ import com.github.libretube.ui.sheets.ChannelGroupsSheet import com.github.libretube.ui.sheets.FilterSortBottomSheet import com.github.libretube.ui.sheets.FilterSortBottomSheet.Companion.FILTER_SORT_REQUEST_KEY import com.github.libretube.util.PlayingQueue +import com.github.libretube.util.deArrow import com.google.android.material.chip.Chip import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class SubscriptionsFragment : DynamicLayoutManagerFragment() { private var _binding: FragmentSubscriptionsBinding? = null @@ -60,7 +62,9 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() { private var isCurrentTabSubChannels = false private var isAppBarFullyExpanded = true - var feedAdapter: VideosAdapter? = null + private var feedAdapter: VideosAdapter? = null + private val sortedFeed: MutableList = mutableListOf() + private var channelsAdapter: SubscriptionChannelAdapter? = null private var selectedSortOrder = PreferenceHelper.getInt(PreferenceKeys.FEED_SORT_ORDER, 0) set(value) { @@ -153,13 +157,7 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() { } binding.subFeed.addOnBottomReachedListener { - val binding = _binding ?: return@addOnBottomReachedListener - - if (viewModel.videoFeed.value != null && !isCurrentTabSubChannels) { - binding.subRefresh.isRefreshing = true - feedAdapter?.updateItems() - binding.subRefresh.isRefreshing = false - } + loadNextFeedItems() } // add some extra margin to the subscribed channels while the mini player is visible @@ -205,6 +203,30 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() { } } + private fun loadNextFeedItems() { + val binding = _binding ?: return + + val feedAdapter = feedAdapter ?: return + + val hasMore = sortedFeed.size > feedAdapter.itemCount + if (viewModel.videoFeed.value != null && !isCurrentTabSubChannels && !binding.subRefresh.isRefreshing && hasMore) { + binding.subRefresh.isRefreshing = true + + lifecycleScope.launch(Dispatchers.IO) { + val toIndex = minOf(feedAdapter.itemCount + 10, sortedFeed.size) + + val streamItemsToInsert = sortedFeed + .subList(feedAdapter.itemCount, toIndex) + .deArrow() + + withContext(Dispatchers.Main) { + feedAdapter.insertItems(streamItemsToInsert) + binding.subRefresh.isRefreshing = false + } + } + } + } + private fun setupSortAndFilter() { binding.filterSort.setOnClickListener { val activityCompat = context as AppCompatActivity @@ -332,9 +354,11 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() { DatabaseHelper.filterByStatusAndWatchPosition(it, hideWatched) } - val sortedFeed = feed + val sorted = feed .sortedBySelectedOrder() .toMutableList() + sortedFeed.clear() + sortedFeed.addAll(sorted) // add an "all caught up item" if (selectedSortOrder == 0) { @@ -355,10 +379,9 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() { binding.subFeed.isGone = notLoaded binding.emptyFeed.isVisible = notLoaded - feedAdapter = VideosAdapter( - sortedFeed.toMutableList(), - showAllAtOnce = false - ) + feedAdapter = VideosAdapter(mutableListOf()) + loadNextFeedItems() + binding.subFeed.adapter = feedAdapter binding.toggleSubs.text = getString(R.string.subscriptions) @@ -401,6 +424,11 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() { binding.toggleSubs.text = "${getString(R.string.subscriptions)} ($subCount)" } + fun removeItem(videoId: String) { + feedAdapter?.removeItemById(videoId) + sortedFeed.removeAll { it.url!!.toID() != videoId } + } + override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // manually restore the recyclerview state due to https://github.com/material-components/material-components-android/issues/3473 diff --git a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt index bd55a58ad..e37f34941 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt @@ -111,7 +111,7 @@ class VideoOptionsBottomSheet : BaseBottomSheet() { // get the current fragment val fragment = navHostFragment?.childFragmentManager?.fragments ?.firstOrNull() as? SubscriptionsFragment - fragment?.feedAdapter?.removeItemById(videoId) + fragment?.removeItem(videoId) } setFragmentResult(VIDEO_OPTIONS_SHEET_REQUEST_KEY, bundleOf()) }