mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 23:40:33 +05:30
fix: subscriptions feed scroll state reset after switching tabs
This commit is contained in:
parent
dd84281bf9
commit
9318a2b277
@ -1,9 +1,7 @@
|
|||||||
package com.github.libretube.ui.fragments
|
package com.github.libretube.ui.fragments
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
@ -61,7 +59,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
set(value) = PreferenceHelper.putInt(PreferenceKeys.SELECTED_CHANNEL_GROUP, value)
|
set(value) = PreferenceHelper.putInt(PreferenceKeys.SELECTED_CHANNEL_GROUP, value)
|
||||||
get() = PreferenceHelper.getInt(PreferenceKeys.SELECTED_CHANNEL_GROUP, 0)
|
get() = PreferenceHelper.getInt(PreferenceKeys.SELECTED_CHANNEL_GROUP, 0)
|
||||||
|
|
||||||
private var isCurrentTabSubChannels = false
|
|
||||||
private var isAppBarFullyExpanded = true
|
private var isAppBarFullyExpanded = true
|
||||||
|
|
||||||
private var feedAdapter = VideosAdapter()
|
private var feedAdapter = VideosAdapter()
|
||||||
@ -85,9 +82,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private var subChannelsRecyclerViewState: Parcelable? = null
|
|
||||||
private var subFeedRecyclerViewState: Parcelable? = null
|
|
||||||
|
|
||||||
private val legacySubscriptionsAdapter = LegacySubscriptionAdapter()
|
private val legacySubscriptionsAdapter = LegacySubscriptionAdapter()
|
||||||
private val channelsAdapter = SubscriptionChannelAdapter()
|
private val channelsAdapter = SubscriptionChannelAdapter()
|
||||||
|
|
||||||
@ -144,11 +138,11 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.videoFeed.observe(viewLifecycleOwner) {
|
viewModel.videoFeed.observe(viewLifecycleOwner) {
|
||||||
if (!isCurrentTabSubChannels && it != null) showFeed()
|
if (!viewModel.isCurrentTabSubChannels && it != null) showFeed()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.subscriptions.observe(viewLifecycleOwner) {
|
viewModel.subscriptions.observe(viewLifecycleOwner) {
|
||||||
if (isCurrentTabSubChannels && it != null) showSubscriptions()
|
if (viewModel.isCurrentTabSubChannels && it != null) showSubscriptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.feedProgress.observe(viewLifecycleOwner) { progress ->
|
viewModel.feedProgress.observe(viewLifecycleOwner) { progress ->
|
||||||
@ -172,18 +166,18 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
binding.toggleSubs.setOnClickListener {
|
binding.toggleSubs.setOnClickListener {
|
||||||
binding.subProgress.isVisible = true
|
binding.subProgress.isVisible = true
|
||||||
binding.subRefresh.isRefreshing = true
|
binding.subRefresh.isRefreshing = true
|
||||||
isCurrentTabSubChannels = !isCurrentTabSubChannels
|
viewModel.isCurrentTabSubChannels = !viewModel.isCurrentTabSubChannels
|
||||||
|
|
||||||
if (isCurrentTabSubChannels) showSubscriptions() else showFeed()
|
if (viewModel.isCurrentTabSubChannels) showSubscriptions() else showFeed()
|
||||||
|
|
||||||
binding.subChannels.isVisible = isCurrentTabSubChannels
|
binding.subChannels.isVisible = viewModel.isCurrentTabSubChannels
|
||||||
binding.subFeed.isGone = isCurrentTabSubChannels
|
binding.subFeed.isGone = viewModel.isCurrentTabSubChannels
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.subChannels.addOnBottomReachedListener {
|
binding.subChannels.addOnBottomReachedListener {
|
||||||
val binding = _binding ?: return@addOnBottomReachedListener
|
val binding = _binding ?: return@addOnBottomReachedListener
|
||||||
|
|
||||||
if (viewModel.subscriptions.value != null && isCurrentTabSubChannels) {
|
if (viewModel.subscriptions.value != null && viewModel.isCurrentTabSubChannels) {
|
||||||
binding.subRefresh.isRefreshing = true
|
binding.subRefresh.isRefreshing = true
|
||||||
binding.subRefresh.isRefreshing = false
|
binding.subRefresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
@ -199,7 +193,7 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
|
|
||||||
binding.channelGroups.setOnCheckedStateChangeListener { group, _ ->
|
binding.channelGroups.setOnCheckedStateChangeListener { group, _ ->
|
||||||
selectedFilterGroup = group.children.indexOfFirst { it.id == group.checkedChipId }
|
selectedFilterGroup = group.children.indexOfFirst { it.id == group.checkedChipId }
|
||||||
if (isCurrentTabSubChannels) showSubscriptions() else showFeed()
|
if (viewModel.isCurrentTabSubChannels) showSubscriptions() else showFeed()
|
||||||
}
|
}
|
||||||
|
|
||||||
channelGroupsModel.groups.observe(viewLifecycleOwner) {
|
channelGroupsModel.groups.observe(viewLifecycleOwner) {
|
||||||
@ -214,14 +208,18 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
binding.subChannels.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
binding.subChannels.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
super.onScrollStateChanged(recyclerView, newState)
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
subChannelsRecyclerViewState = binding.subChannels.layoutManager?.onSaveInstanceState()
|
viewModel.subChannelsRecyclerViewState = binding.subChannels.layoutManager?.onSaveInstanceState()?.takeIf {
|
||||||
|
binding.subChannels.computeVerticalScrollOffset() != 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.subFeed.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
binding.subFeed.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
super.onScrollStateChanged(recyclerView, newState)
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
subFeedRecyclerViewState = binding.subFeed.layoutManager?.onSaveInstanceState()
|
viewModel.subFeedRecyclerViewState = binding.subFeed.layoutManager?.onSaveInstanceState()?.takeIf {
|
||||||
|
binding.subFeed.computeVerticalScrollOffset() != 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -239,7 +237,7 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
private fun loadFeedItems(sortedFeed: List<StreamItem>) {
|
private fun loadFeedItems(sortedFeed: List<StreamItem>) {
|
||||||
val binding = _binding ?: return
|
val binding = _binding ?: return
|
||||||
|
|
||||||
if (viewModel.videoFeed.value != null && !isCurrentTabSubChannels && !binding.subRefresh.isRefreshing) {
|
if (viewModel.videoFeed.value != null && !viewModel.isCurrentTabSubChannels && !binding.subRefresh.isRefreshing) {
|
||||||
binding.subRefresh.isRefreshing = true
|
binding.subRefresh.isRefreshing = true
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
@ -250,7 +248,9 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
}
|
}
|
||||||
|
|
||||||
feedAdapter.submitList(streamItemsToInsert) {
|
feedAdapter.submitList(streamItemsToInsert) {
|
||||||
binding.subFeed.scrollToPosition(0)
|
// manually restore the previous feed state
|
||||||
|
binding.subFeed.layoutManager?.onRestoreInstanceState(viewModel.subFeedRecyclerViewState)
|
||||||
|
binding.subscriptionsAppBar.setExpanded(viewModel.subFeedRecyclerViewState == null)
|
||||||
}
|
}
|
||||||
binding.subRefresh.isRefreshing = false
|
binding.subRefresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
@ -422,14 +422,10 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
if (legacySubscriptions) {
|
val adapter = if (legacySubscriptions) legacySubscriptionsAdapter else channelsAdapter
|
||||||
legacySubscriptionsAdapter.submitList(subscriptions) {
|
adapter.submitList(subscriptions) {
|
||||||
binding.subFeed.scrollToPosition(0)
|
binding.subFeed.layoutManager?.onRestoreInstanceState(viewModel.subChannelsRecyclerViewState)
|
||||||
}
|
binding.subscriptionsAppBar.setExpanded(viewModel.subChannelsRecyclerViewState == null)
|
||||||
} else {
|
|
||||||
channelsAdapter.submitList(subscriptions) {
|
|
||||||
binding.subFeed.scrollToPosition(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.subRefresh.isRefreshing = false
|
binding.subRefresh.isRefreshing = false
|
||||||
@ -447,11 +443,4 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
|||||||
fun removeItem(videoId: String) {
|
fun removeItem(videoId: String) {
|
||||||
feedAdapter.removeItemById(videoId)
|
feedAdapter.removeItemById(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
|
|
||||||
binding.subChannels.layoutManager?.onRestoreInstanceState(subChannelsRecyclerViewState)
|
|
||||||
binding.subFeed.layoutManager?.onRestoreInstanceState(subFeedRecyclerViewState)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.github.libretube.ui.models
|
package com.github.libretube.ui.models
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Parcelable
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@ -23,6 +24,10 @@ class SubscriptionsViewModel : ViewModel() {
|
|||||||
var subscriptions = MutableLiveData<List<Subscription>?>()
|
var subscriptions = MutableLiveData<List<Subscription>?>()
|
||||||
val feedProgress = MutableLiveData<FeedProgress?>()
|
val feedProgress = MutableLiveData<FeedProgress?>()
|
||||||
|
|
||||||
|
var isCurrentTabSubChannels = false
|
||||||
|
var subChannelsRecyclerViewState: Parcelable? = null
|
||||||
|
var subFeedRecyclerViewState: Parcelable? = null
|
||||||
|
|
||||||
fun fetchFeed(context: Context, forceRefresh: Boolean) {
|
fun fetchFeed(context: Context, forceRefresh: Boolean) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val videoFeed = try {
|
val videoFeed = try {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user