code
Clone this repository
https://tangled.org/bretton.dev/coves-mobile
git@knot.bretton.dev:bretton.dev/coves-mobile
For self-hosted knots, clone URLs may differ based on your setup.
Updates widget tests for the new MultiFeedProvider architecture:
- FakeMultiFeedProvider replaces FakeFeedProvider
- Supports per-feed state management (FeedType parameter)
- Uses sentinel-compatible copyWith for state mutations
- Tests cover both authenticated and unauthenticated flows
- Tests for PageView swipe navigation when authenticated
- Tests for single-feed display when not authenticated
Removes orphaned test/providers/feed_provider_test.dart that
referenced the deleted FeedProvider.
Updates test/widget_test.dart counter test with provider setup.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactors FeedScreen to work with MultiFeedProvider and adds several
UX and reliability improvements:
PageView for feed switching:
- Authenticated users can swipe between Discover and For You
- Unauthenticated users see only Discover (no PageView)
- Per-feed ScrollControllers with position restoration
Auth state synchronization:
- Listens to AuthProvider changes
- Jumps PageController to page 0 on sign-out to match provider state
- Prevents tab/page mismatch after re-authentication
Lazy feed loading (_ensureFeedLoaded):
- Triggers initial load when switching to an unloaded feed
- Handles case where user signs in after app start and taps For You
- Called from both tab tap and swipe navigation
This fixes issues where:
- For You tab showed empty state after signing in mid-session
- PageController stayed on page 1 after sign-out while provider
switched to Discover, causing misalignment on re-auth
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extracts feed rendering logic into a reusable FeedPage widget that
handles all feed states:
- Loading: Centered CircularProgressIndicator
- Error: User-friendly message with Retry button
- Empty: Contextual message based on auth state
- Posts: ListView.builder with pagination support
Key improvements:
- Empty state now wrapped in RefreshIndicator with CustomScrollView
and SliverFillRemaining, allowing pull-to-refresh when feed is empty
- Error messages are user-friendly (maps technical errors to readable text)
- Loading more indicator at list bottom during pagination
- Proper scroll controller integration for infinite scroll
This fixes an issue where unauthenticated users with an empty Discover
feed had no way to retry without restarting the app.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaces FeedProvider with MultiFeedProvider that manages separate
state for Discover and For You feeds. Key improvements:
Architecture:
- Per-feed state management using Map<FeedType, FeedState>
- Centralized _fetchFeed helper eliminates code duplication
- Auth-aware feed switching (For You requires authentication)
- Minute-based time updates for relative timestamps
Security (cross-session data leak prevention):
- Captures session DID before fetch to detect auth changes
- Discards For You responses if session changed during fetch
- Guards both success and error paths to prevent stale data
- Removes feed state entirely on session change (not copyWith)
This prevents scenarios where:
- User signs out during fetch → old data reappears
- User A signs out, User B signs in → User A's feed shown to B
- Fetch errors after sign-out → stale posts restored
Removes the old single-feed FeedProvider.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces FeedState as an immutable state container for per-feed data
(Discover and For You feeds). Key features:
- Holds posts, cursor, loading states, error, scroll position, and
last refresh time
- Uses sentinel pattern for copyWith to distinguish "not provided"
from "explicitly set to null" for nullable fields (cursor, error,
lastRefreshTime)
- Enables proper clearing of fields on refresh/error recovery
The sentinel pattern fixes a bug where nullable fields couldn't be
cleared back to null through copyWith - critical for pagination
cursor handling when reaching the end of a feed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move provider initialization from postFrameCallback to didChangeDependencies
for synchronous access before first build. Create ScrollController with
initialScrollOffset set to cached position, eliminating the visible flash
from loading → content at top → jump to cached position.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
View.of(context) was being called in didChangeMetrics() during widget
deactivation, causing "Looking up a deactivated widget's ancestor"
errors. The context becomes invalid before mounted becomes false.
Fixed by caching the FlutterView reference in didChangeDependencies()
for both _ReplyScreenState and _ReplyToolbarState, then using the
cached reference in didChangeMetrics().
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>