From 5d65725ead66a50570e9ba9ae19e495b0ede997b Mon Sep 17 00:00:00 2001 From: Ankur Date: Tue, 6 Feb 2024 16:17:52 -0800 Subject: [PATCH 1/5] Fix [ChannelFragment]: resolve stuttering at bottom of scroll -Removed ScrollView. RecyclerView itself handles scrolling, nesting it inside a ScrollView is possibly leading to conflicting scrolling behavior effecting performance(i.e stuttering when scrolling at bottom and updating list with new data items). -Used AppBarLayout and CollapsingToolbarLayout as containers for content(banner etc) above list of videos items. Together with CoordinatorLayout, these components streamline scrolling behavior and UI interactions with each other and RecyclerView. --- .../libretube/ui/fragments/ChannelFragment.kt | 5 +- app/src/main/res/layout/fragment_channel.xml | 298 +++++++++--------- 2 files changed, 155 insertions(+), 148 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 0a6d27b7c..eeee9f711 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 @@ -90,10 +90,10 @@ class ChannelFragment : DynamicLayoutManagerFragment() { fetchChannel() } - binding.channelScrollView.viewTreeObserver.addOnScrollChangedListener { + binding.channelRecView.viewTreeObserver.addOnScrollChangedListener { val binding = _binding ?: return@addOnScrollChangedListener - if (binding.channelScrollView.canScrollVertically(1) || isLoading) return@addOnScrollChangedListener + if (binding.channelRecView.canScrollVertically(1) || isLoading) return@addOnScrollChangedListener loadNextPage() } @@ -199,7 +199,6 @@ class ChannelFragment : DynamicLayoutManagerFragment() { isLoading = false binding.channelRefresh.isRefreshing = false - binding.channelScrollView.isVisible = true binding.channelName.text = response.name if (response.verified) { binding.channelName diff --git a/app/src/main/res/layout/fragment_channel.xml b/app/src/main/res/layout/fragment_channel.xml index 77c26fb09..c033d726c 100644 --- a/app/src/main/res/layout/fragment_channel.xml +++ b/app/src/main/res/layout/fragment_channel.xml @@ -6,165 +6,173 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:layout_height="match_parent"> - + android:layout_height="wrap_content"> - - - - - + android:layout_height="wrap_content" + app:layout_scrollFlags="scroll" + app:titleCollapseMode="scale"> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_collapseMode="pin"> - + - + + + + + + + + + + + + + + + + + + + + + android:layout_marginHorizontal="5dp" + android:autoLink="web" + android:padding="10dp" /> + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + From 277ad0d62ddad3db020e6861757eac33d9b71941 Mon Sep 17 00:00:00 2001 From: Ankur Date: Tue, 6 Feb 2024 17:15:29 -0800 Subject: [PATCH 2/5] Fix [ChannelFragment]: swipe refresh only at top of scroll Implemented listeners to provide distinction between scrolling upward and swiping to refresh layout. When a user scrolls up, the refresh layout is only triggered once they are at the top of the scroll. --- .../github/libretube/ui/fragments/ChannelFragment.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 eeee9f711..0c6aa7071 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 @@ -59,6 +59,8 @@ class ChannelFragment : DynamicLayoutManagerFragment() { private var nextPages = Array(5) { null } private var searchChannelAdapter: SearchChannelAdapter? = null + private var isAppBarFullyExpanded: Boolean = true + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) channelName = args.channelName @@ -86,6 +88,16 @@ class ChannelFragment : DynamicLayoutManagerFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + // Check if the AppBarLayout is fully expanded + binding.channelAppBar.addOnOffsetChangedListener { _, verticalOffset -> + isAppBarFullyExpanded = verticalOffset == 0 + } + + // Determine if the child can scroll up + binding.channelRefresh.setOnChildScrollUpCallback { _, _ -> + !isAppBarFullyExpanded + } + binding.channelRefresh.setOnRefreshListener { fetchChannel() } From b6986996797d52af7f70c42e1d4741ba7af832c2 Mon Sep 17 00:00:00 2001 From: Ankur Date: Tue, 6 Feb 2024 20:22:50 -0800 Subject: [PATCH 3/5] Fix [PlaylistFragment]: resolve stuttering at bottom of scroll -Removed ScrollView. RecyclerView itself handles scrolling, nesting it inside a ScrollView is possibly leading to conflicting scrolling behavior effecting performance(i.e stuttering when scrolling at bottom and updating list with new data items). -Used AppBarLayout and CollapsingToolbarLayout as containers for content(image etc) above list of video items. Together with CoordinatorLayout, these components streamline scrolling behavior and UI interactions with each other and RecyclerView. --- .../ui/fragments/PlaylistFragment.kt | 6 +- app/src/main/res/layout/fragment_playlist.xml | 247 +++++++++--------- 2 files changed, 129 insertions(+), 124 deletions(-) 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 e351e99cf..762d558df 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 @@ -123,7 +123,6 @@ class PlaylistFragment : DynamicLayoutManagerFragment() { } private fun fetchPlaylist() { - binding.playlistScrollview.isGone = true lifecycleScope.launch { val response = try { withContext(Dispatchers.IO) { @@ -136,7 +135,6 @@ class PlaylistFragment : DynamicLayoutManagerFragment() { val binding = _binding ?: return@launch playlistFeed = response.relatedStreams.toMutableList() - binding.playlistScrollview.isVisible = true nextPage = response.nextpage playlistName = response.name isLoading = false @@ -312,8 +310,8 @@ class PlaylistFragment : DynamicLayoutManagerFragment() { } }) - binding.playlistScrollview.viewTreeObserver.addOnScrollChangedListener { - if (_binding?.playlistScrollview?.canScrollVertically(1) == false && + binding.playlistRecView.viewTreeObserver.addOnScrollChangedListener { + if (_binding?.playlistRecView?.canScrollVertically(1) == false && !isLoading ) { // append more playlists to the recycler view diff --git a/app/src/main/res/layout/fragment_playlist.xml b/app/src/main/res/layout/fragment_playlist.xml index 630c993fa..fcebef61f 100644 --- a/app/src/main/res/layout/fragment_playlist.xml +++ b/app/src/main/res/layout/fragment_playlist.xml @@ -1,157 +1,164 @@ - - - + android:layout_height="match_parent" + android:clipToPadding="false" + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> - + + - - + app:layout_scrollFlags="scroll" + app:titleCollapseMode="scale"> + android:orientation="vertical"> - + android:layout_marginHorizontal="20dp" + android:layout_marginVertical="10dp" + android:adjustViewBounds="true" + android:scaleType="fitCenter" + app:shapeAppearanceOverlay="@style/ShapeAppearance.Material3.Corner.Small" + tools:src="@tools:sample/backgrounds/scenic" /> + android:layout_marginTop="8dp" + android:orientation="horizontal"> - + + + android:layout_gravity="center" + android:layout_marginEnd="8dp" + android:background="@drawable/rounded_ripple" + android:padding="5dp" + android:visibility="gone" + tools:visibility="visible"> + + + + + + + android:layout_marginEnd="20dp" + android:background="?selectableItemBackgroundBorderless" + android:src="@drawable/ic_three_dots" /> - - - - - - - - - - - - - - - - - - - - + android:paddingHorizontal="15dp" + android:paddingBottom="5dp" + android:textStyle="bold" /> - + - + - \ No newline at end of file + + + + + + + + + + + + + + + + + + \ No newline at end of file From 0d7750528577542451593eed45a8c9eb9d5c6437 Mon Sep 17 00:00:00 2001 From: Ankur Date: Mon, 12 Feb 2024 18:16:21 -0800 Subject: [PATCH 4/5] Fix [ChannelFragment]: main layout becomes visible after data fetched --- .../java/com/github/libretube/ui/fragments/ChannelFragment.kt | 2 ++ app/src/main/res/layout/fragment_channel.xml | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) 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 0c6aa7071..0cd9dcafb 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 @@ -211,6 +211,8 @@ class ChannelFragment : DynamicLayoutManagerFragment() { isLoading = false binding.channelRefresh.isRefreshing = false + binding.channelCoordinator.isVisible = true + binding.channelName.text = response.name if (response.verified) { binding.channelName diff --git a/app/src/main/res/layout/fragment_channel.xml b/app/src/main/res/layout/fragment_channel.xml index c033d726c..94d9665aa 100644 --- a/app/src/main/res/layout/fragment_channel.xml +++ b/app/src/main/res/layout/fragment_channel.xml @@ -7,8 +7,10 @@ android:layout_height="match_parent"> + android:layout_height="match_parent" + android:visibility="gone"> Date: Tue, 20 Feb 2024 14:59:32 -0800 Subject: [PATCH 5/5] Fix [PlaylistFragment]: main layout becomes visible after data fetched --- .../libretube/ui/fragments/PlaylistFragment.kt | 2 ++ app/src/main/res/layout/fragment_playlist.xml | 17 +++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) 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 762d558df..331516dc2 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 @@ -140,6 +140,8 @@ class PlaylistFragment : DynamicLayoutManagerFragment() { isLoading = false ImageHelper.loadImage(response.thumbnailUrl, binding.thumbnail) binding.playlistProgress.isGone = true + binding.playlistAppBar.isVisible = true + binding.playlistRecView.isVisible = true binding.playlistName.text = response.name binding.playlistInfo.text = getChannelAndVideoString(response, response.videos) diff --git a/app/src/main/res/layout/fragment_playlist.xml b/app/src/main/res/layout/fragment_playlist.xml index fcebef61f..e0aa04c50 100644 --- a/app/src/main/res/layout/fragment_playlist.xml +++ b/app/src/main/res/layout/fragment_playlist.xml @@ -6,18 +6,26 @@ android:layout_height="match_parent" tools:context=".ui.fragments.PlaylistFragment"> + + android:layout_height="wrap_content" + android:visibility="gone"> -