Skip to content

Commit

Permalink
feat: add pagination to dearrow in feed
Browse files Browse the repository at this point in the history
  • Loading branch information
Bnyro committed May 6, 2024
1 parent ccaedfa commit 800d670
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,14 @@ import com.github.libretube.util.TextUtils

class VideosAdapter(
private val streamItems: MutableList<StreamItem>,
private val showAllAtOnce: Boolean = true,
private val forceMode: LayoutMode = LayoutMode.RESPECT_PREF
) : RecyclerView.Adapter<VideosViewHolder>() {

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<StreamItem>) {
val feedSize = streamItems.size
streamItems.addAll(newItems)
Expand All @@ -69,7 +53,7 @@ class VideosAdapter(
it.url?.toID() == videoId
}.takeIf { it > 0 } ?: return
streamItems.removeAt(index)
visibleCount--

notifyItemRemoved(index)
notifyItemRangeChanged(index, itemCount)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<StreamItem> = mutableListOf()

private var channelsAdapter: SubscriptionChannelAdapter? = null
private var selectedSortOrder = PreferenceHelper.getInt(PreferenceKeys.FEED_SORT_ORDER, 0)
set(value) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Check failure on line 218 in app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt

View workflow job for this annotation

GitHub Actions / Check Code Quality

[ktlint] reported by reviewdog 🐶 A multiline expression should start on a new line Raw Output: app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt:218:43: error: A multiline expression should start on a new line (standard:multiline-expression-wrapping)
.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
Expand Down Expand Up @@ -332,9 +354,11 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
DatabaseHelper.filterByStatusAndWatchPosition(it, hideWatched)
}

val sortedFeed = feed
val sorted = feed

Check failure on line 357 in app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt

View workflow job for this annotation

GitHub Actions / Check Code Quality

[ktlint] reported by reviewdog 🐶 A multiline expression should start on a new line Raw Output: app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt:357:22: error: A multiline expression should start on a new line (standard:multiline-expression-wrapping)
.sortedBySelectedOrder()
.toMutableList()
sortedFeed.clear()
sortedFeed.addAll(sorted)

// add an "all caught up item"
if (selectedSortOrder == 0) {
Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
Expand Down

0 comments on commit 800d670

Please sign in to comment.