From b501188c2a9492c0604e3f2515154b65eb0db701 Mon Sep 17 00:00:00 2001 From: Roscoe Rubin-Rottenberg Date: Thu, 18 Jun 2026 18:57:35 -0400 Subject: [PATCH] fix: feed switch stutter --- lib/src/features/feed/ui/pages/feed_page.dart | 20 ++---------- .../features/feed/ui/pages/feeds_page.dart | 31 +++---------------- .../ui/widgets/post/feed_post_widget.dart | 1 + 3 files changed, 8 insertions(+), 44 deletions(-) diff --git a/lib/src/features/feed/ui/pages/feed_page.dart b/lib/src/features/feed/ui/pages/feed_page.dart index 3b94e38b..39399660 100644 --- a/lib/src/features/feed/ui/pages/feed_page.dart +++ b/lib/src/features/feed/ui/pages/feed_page.dart @@ -189,11 +189,7 @@ class _FeedPageState extends ConsumerState itemBuilder: (context, index) { // Handle end of feed if (index == state.length) { - return shouldBeActive - ? const NoMorePosts() - : const DecoratedBox( - decoration: BoxDecoration(color: AppColors.black), - ); + return const NoMorePosts(); } // Handle last item with loading indicator else if (index == state.length - 1 && @@ -216,11 +212,8 @@ class _FeedPageState extends ConsumerState ), ], ); - } else { - return const DecoratedBox( - decoration: BoxDecoration(color: AppColors.black), - ); } + return FeedPostWidget(index: index, feed: widget.feed); } // Handle empty state else if (state.length == 0 && !state.loadingFirstLoad) { @@ -230,14 +223,7 @@ class _FeedPageState extends ConsumerState decoration: BoxDecoration(color: AppColors.black), ); } else { - if (shouldBeActive) { - return FeedPostWidget(index: index, feed: widget.feed); - } else { - // SizedBox to maintain scroll position but hide content - return const DecoratedBox( - decoration: BoxDecoration(color: AppColors.black), - ); - } + return FeedPostWidget(index: index, feed: widget.feed); } }, ), diff --git a/lib/src/features/feed/ui/pages/feeds_page.dart b/lib/src/features/feed/ui/pages/feeds_page.dart index 68c20abf..b69cb334 100644 --- a/lib/src/features/feed/ui/pages/feeds_page.dart +++ b/lib/src/features/feed/ui/pages/feeds_page.dart @@ -1,11 +1,10 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:spark/src/core/network/atproto/data/models/feed_models.dart'; import 'package:spark/src/core/design_system/tokens/colors.dart'; -import 'package:spark/src/features/feed/providers/feed_provider.dart'; -import 'package:spark/src/features/feed/providers/feed_state.dart'; +import 'package:spark/src/core/network/atproto/data/models/feed_models.dart'; import 'package:spark/src/features/feed/ui/pages/feed_page.dart'; +import 'package:spark/src/features/feed/ui/widgets/feed/cacheable_page_view.dart'; import 'package:spark/src/features/feed/ui/widgets/feed/feeds_bar.dart'; import 'package:spark/src/features/settings/providers/settings_provider.dart'; @@ -103,29 +102,6 @@ class _FeedsPageState extends ConsumerState { final feeds = settings.feeds.where((feed) => feed.config.pinned).toList(); final activeFeed = settings.activeFeed; - // Feed providers are watched at MainPage level, but we still need to watch - // them here for the debug overlay to update properly - final feedStates = {}; - for (final feed in feeds) { - feedStates[feed] = ref.watch(feedProvider(feed)); - } - - // Initialize feeds that haven't been loaded yet - WidgetsBinding.instance.addPostFrameCallback((_) { - for (final feed in feeds) { - final state = feedStates[feed]!; - final notifier = ref.read(feedProvider(feed).notifier); - - // Only load if the feed is empty and not already loading and active - if (state.length == 0 && - !state.loadingFirstLoad && - !state.isEndOfNetworkFeed && - feed == activeFeed) { - notifier.loadAndUpdateFirstLoad(); - } - } - }); - // Check if we need to initialize or update the page controller final needsInitialization = !_isInitialized; final activeFeedChanged = _lastActiveFeed != activeFeed; @@ -165,7 +141,8 @@ class _FeedsPageState extends ConsumerState { ? FeedsBar(pageController: _pageController!) : null, body: _pageController != null && feeds.isNotEmpty - ? PageView.builder( + ? CacheablePageView.builder( + cachePageExtent: 1, controller: _pageController, itemCount: feeds.length, onPageChanged: (index) { diff --git a/lib/src/features/feed/ui/widgets/post/feed_post_widget.dart b/lib/src/features/feed/ui/widgets/post/feed_post_widget.dart index 292fa9b5..48a7521c 100644 --- a/lib/src/features/feed/ui/widgets/post/feed_post_widget.dart +++ b/lib/src/features/feed/ui/widgets/post/feed_post_widget.dart @@ -214,6 +214,7 @@ class _FeedPostWidgetState extends ConsumerState { } final isMediaActive = + feedState.active && isOnFeedsTab && feedState.index == widget.index && !feedSettingsVisible && -- 2.51.2