mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 06:10:31 +05:30
feat: add pagination to dearrow in feed
This commit is contained in:
parent
ccaedfafbc
commit
800d6704cf
@ -34,30 +34,14 @@ import com.github.libretube.util.TextUtils
|
|||||||
|
|
||||||
class VideosAdapter(
|
class VideosAdapter(
|
||||||
private val streamItems: MutableList<StreamItem>,
|
private val streamItems: MutableList<StreamItem>,
|
||||||
private val showAllAtOnce: Boolean = true,
|
|
||||||
private val forceMode: LayoutMode = LayoutMode.RESPECT_PREF
|
private val forceMode: LayoutMode = LayoutMode.RESPECT_PREF
|
||||||
) : RecyclerView.Adapter<VideosViewHolder>() {
|
) : RecyclerView.Adapter<VideosViewHolder>() {
|
||||||
|
override fun getItemCount() = streamItems.size
|
||||||
private var visibleCount = minOf(10, streamItems.size)
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
|
||||||
return when {
|
|
||||||
showAllAtOnce -> streamItems.size
|
|
||||||
else -> minOf(streamItems.size, visibleCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return if (streamItems[position].type == CAUGHT_UP_STREAM_TYPE) CAUGHT_UP_TYPE else NORMAL_TYPE
|
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>) {
|
fun insertItems(newItems: List<StreamItem>) {
|
||||||
val feedSize = streamItems.size
|
val feedSize = streamItems.size
|
||||||
streamItems.addAll(newItems)
|
streamItems.addAll(newItems)
|
||||||
@ -69,7 +53,7 @@ class VideosAdapter(
|
|||||||
it.url?.toID() == videoId
|
it.url?.toID() == videoId
|
||||||
}.takeIf { it > 0 } ?: return
|
}.takeIf { it > 0 } ?: return
|
||||||
streamItems.removeAt(index)
|
streamItems.removeAt(index)
|
||||||
visibleCount--
|
|
||||||
notifyItemRemoved(index)
|
notifyItemRemoved(index)
|
||||||
notifyItemRangeChanged(index, itemCount)
|
notifyItemRangeChanged(index, itemCount)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
import com.github.libretube.ui.sheets.FilterSortBottomSheet.Companion.FILTER_SORT_REQUEST_KEY
|
import com.github.libretube.ui.sheets.FilterSortBottomSheet.Companion.FILTER_SORT_REQUEST_KEY
|
||||||
import com.github.libretube.util.PlayingQueue
|
import com.github.libretube.util.PlayingQueue
|
||||||
|
import com.github.libretube.util.deArrow
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
||||||
private var _binding: FragmentSubscriptionsBinding? = null
|
private var _binding: FragmentSubscriptionsBinding? = null
|
||||||
@ -60,7 +62,9 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
private var isCurrentTabSubChannels = false
|
private var isCurrentTabSubChannels = false
|
||||||
private var isAppBarFullyExpanded = true
|
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 channelsAdapter: SubscriptionChannelAdapter? = null
|
||||||
private var selectedSortOrder = PreferenceHelper.getInt(PreferenceKeys.FEED_SORT_ORDER, 0)
|
private var selectedSortOrder = PreferenceHelper.getInt(PreferenceKeys.FEED_SORT_ORDER, 0)
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -153,13 +157,7 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.subFeed.addOnBottomReachedListener {
|
binding.subFeed.addOnBottomReachedListener {
|
||||||
val binding = _binding ?: return@addOnBottomReachedListener
|
loadNextFeedItems()
|
||||||
|
|
||||||
if (viewModel.videoFeed.value != null && !isCurrentTabSubChannels) {
|
|
||||||
binding.subRefresh.isRefreshing = true
|
|
||||||
feedAdapter?.updateItems()
|
|
||||||
binding.subRefresh.isRefreshing = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@ -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() {
|
private fun setupSortAndFilter() {
|
||||||
binding.filterSort.setOnClickListener {
|
binding.filterSort.setOnClickListener {
|
||||||
val activityCompat = context as AppCompatActivity
|
val activityCompat = context as AppCompatActivity
|
||||||
@ -332,9 +354,11 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
DatabaseHelper.filterByStatusAndWatchPosition(it, hideWatched)
|
DatabaseHelper.filterByStatusAndWatchPosition(it, hideWatched)
|
||||||
}
|
}
|
||||||
|
|
||||||
val sortedFeed = 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) {
|
||||||
@ -355,10 +379,9 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
binding.subFeed.isGone = notLoaded
|
binding.subFeed.isGone = notLoaded
|
||||||
binding.emptyFeed.isVisible = notLoaded
|
binding.emptyFeed.isVisible = notLoaded
|
||||||
|
|
||||||
feedAdapter = VideosAdapter(
|
feedAdapter = VideosAdapter(mutableListOf())
|
||||||
sortedFeed.toMutableList(),
|
loadNextFeedItems()
|
||||||
showAllAtOnce = false
|
|
||||||
)
|
|
||||||
binding.subFeed.adapter = feedAdapter
|
binding.subFeed.adapter = feedAdapter
|
||||||
binding.toggleSubs.text = getString(R.string.subscriptions)
|
binding.toggleSubs.text = getString(R.string.subscriptions)
|
||||||
|
|
||||||
@ -401,6 +424,11 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
binding.toggleSubs.text = "${getString(R.string.subscriptions)} ($subCount)"
|
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) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
super.onConfigurationChanged(newConfig)
|
super.onConfigurationChanged(newConfig)
|
||||||
// manually restore the recyclerview state due to https://github.com/material-components/material-components-android/issues/3473
|
// manually restore the recyclerview state due to https://github.com/material-components/material-components-android/issues/3473
|
||||||
|
@ -111,7 +111,7 @@ class VideoOptionsBottomSheet : BaseBottomSheet() {
|
|||||||
// get the current fragment
|
// get the current fragment
|
||||||
val fragment = navHostFragment?.childFragmentManager?.fragments
|
val fragment = navHostFragment?.childFragmentManager?.fragments
|
||||||
?.firstOrNull() as? SubscriptionsFragment
|
?.firstOrNull() as? SubscriptionsFragment
|
||||||
fragment?.feedAdapter?.removeItemById(videoId)
|
fragment?.removeItem(videoId)
|
||||||
}
|
}
|
||||||
setFragmentResult(VIDEO_OPTIONS_SHEET_REQUEST_KEY, bundleOf())
|
setFragmentResult(VIDEO_OPTIONS_SHEET_REQUEST_KEY, bundleOf())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user