From d40e4eb9fa9b784b84348b1fd2007769b3947108 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 1 May 2024 17:26:36 +0200 Subject: [PATCH] fix: scroll state not preserved after rotation change at some places Affected fragments: SubscriptionsFragment, WatchHistoryFragment, ChannelFragment, PlaylistFragment --- .../libretube/ui/fragments/ChannelFragment.kt | 18 ++++++++++++ .../ui/fragments/PlaylistFragment.kt | 17 +++++++++++ .../ui/fragments/SubscriptionsFragment.kt | 28 +++++++++++++++++++ .../ui/fragments/WatchHistoryFragment.kt | 18 ++++++++++++ .../res/layout/fragment_watch_history.xml | 4 +-- 5 files changed, 83 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt index c6a54dff5..163362714 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt @@ -1,6 +1,8 @@ package com.github.libretube.ui.fragments +import android.content.res.Configuration import android.os.Bundle +import android.os.Parcelable import android.util.Log import android.view.LayoutInflater import android.view.View @@ -12,6 +14,7 @@ import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.obj.ChannelTab @@ -61,6 +64,7 @@ class ChannelFragment : DynamicLayoutManagerFragment() { private var searchChannelAdapter: SearchChannelAdapter? = null private var isAppBarFullyExpanded: Boolean = true + private var recyclerViewState: Parcelable? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -109,6 +113,13 @@ class ChannelFragment : DynamicLayoutManagerFragment() { loadNextPage() } + binding.channelRecView.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + recyclerViewState = binding.channelRecView.layoutManager?.onSaveInstanceState() + } + }) + fetchChannel() } @@ -338,4 +349,11 @@ class ChannelFragment : DynamicLayoutManagerFragment() { return newContent.nextpage } + + + 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.channelRecView.layoutManager?.onRestoreInstanceState(recyclerViewState) + } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt index 713976f1a..6398fddc1 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt @@ -1,7 +1,9 @@ package com.github.libretube.ui.fragments import android.annotation.SuppressLint +import android.content.res.Configuration import android.os.Bundle +import android.os.Parcelable import android.util.Log import android.view.LayoutInflater import android.view.View @@ -72,6 +74,7 @@ class PlaylistFragment : DynamicLayoutManagerFragment() { field = value } private val sortOptions by lazy { resources.getStringArray(R.array.playlistSortOptions) } + private var recyclerViewState: Parcelable? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -106,6 +109,14 @@ class PlaylistFragment : DynamicLayoutManagerFragment() { binding.playlistRecView.updatePadding(bottom = if (it) 64f.dpToPx() else 0) } + // manually restore the recyclerview state due to https://github.com/material-components/material-components-android/issues/3473 + binding.playlistRecView.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + recyclerViewState = binding.playlistRecView.layoutManager?.onSaveInstanceState() + } + }) + fetchPlaylist() } @@ -402,4 +413,10 @@ class PlaylistFragment : DynamicLayoutManagerFragment() { isLoading = false } } + + 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.playlistRecView.layoutManager?.onRestoreInstanceState(recyclerViewState) + } } 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 97f0db01a..ea4081f96 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 @@ -1,7 +1,9 @@ package com.github.libretube.ui.fragments import android.annotation.SuppressLint +import android.content.res.Configuration import android.os.Bundle +import android.os.Parcelable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -16,6 +18,7 @@ import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R import com.github.libretube.api.obj.StreamItem import com.github.libretube.api.obj.Subscription @@ -72,6 +75,9 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() { field = value } + private var subChannelsRecyclerViewState: Parcelable? = null + private var subFeedRecyclerViewState: Parcelable? = null + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -177,6 +183,21 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() { ChannelGroupsSheet().show(childFragmentManager, null) } + // manually restore the recyclerview state due to https://github.com/material-components/material-components-android/issues/3473 + binding.subChannels.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + subChannelsRecyclerViewState = binding.subChannels.layoutManager?.onSaveInstanceState() + } + }) + + binding.subFeed.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + subFeedRecyclerViewState = binding.subFeed.layoutManager?.onSaveInstanceState() + } + }) + lifecycleScope.launch(Dispatchers.IO) { val groups = DatabaseHolder.Database.subscriptionGroupsDao().getAll() .sortedBy { it.index } @@ -379,4 +400,11 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() { val subCount = subscriptions.size.toLong().formatShort() binding.toggleSubs.text = "${getString(R.string.subscriptions)} ($subCount)" } + + 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) + } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/WatchHistoryFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/WatchHistoryFragment.kt index 79b383a45..2a09a67f7 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/WatchHistoryFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/WatchHistoryFragment.kt @@ -1,8 +1,11 @@ package com.github.libretube.ui.fragments +import android.content.res.Configuration import android.os.Bundle import android.os.Handler import android.os.Looper +import android.os.Parcelable +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -46,6 +49,7 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment() { private val handler = Handler(Looper.getMainLooper()) private val playerViewModel: PlayerViewModel by activityViewModels() private var isLoading = false + private var recyclerViewState: Parcelable? = null private var selectedStatusFilter = PreferenceHelper.getInt( PreferenceKeys.SELECTED_HISTORY_STATUS_FILTER, @@ -143,6 +147,14 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment() { }.show(childFragmentManager) } + // manually restore the recyclerview state due to https://github.com/material-components/material-components-android/issues/3473 + binding.watchHistoryRecView.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + recyclerViewState = binding.watchHistoryRecView.layoutManager?.onSaveInstanceState() + } + }) + showWatchHistory(allHistory) } @@ -256,6 +268,12 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment() { } } + 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.watchHistoryRecView.layoutManager?.onRestoreInstanceState(recyclerViewState) + } + override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/app/src/main/res/layout/fragment_watch_history.xml b/app/src/main/res/layout/fragment_watch_history.xml index 974331cfa..69aac96aa 100644 --- a/app/src/main/res/layout/fragment_watch_history.xml +++ b/app/src/main/res/layout/fragment_watch_history.xml @@ -36,12 +36,12 @@ android:visibility="gone">