···
Widget build(BuildContext context) {
61
-
// Use select to only rebuild when specific fields change
61
+
// Optimized: Use select to only rebuild when specific fields change
62
+
// This prevents unnecessary rebuilds when unrelated provider fields change
final isAuthenticated = context.select<AuthProvider, bool>(
(p) => p.isAuthenticated,
65
-
final feedProvider = Provider.of<FeedProvider>(context);
66
+
final isLoading = context.select<FeedProvider, bool>((p) => p.isLoading);
67
+
final error = context.select<FeedProvider, String?>((p) => p.error);
68
+
final posts = context.select<FeedProvider, List<FeedViewPost>>(
71
+
final isLoadingMore = context.select<FeedProvider, bool>(
72
+
(p) => p.isLoadingMore,
backgroundColor: const Color(0xFF0B0F14),
···
title: Text(isAuthenticated ? 'Feed' : 'Explore'),
automaticallyImplyLeading: false,
75
-
body: SafeArea(child: _buildBody(feedProvider, isAuthenticated)),
85
+
isLoading: isLoading,
88
+
isLoadingMore: isLoadingMore,
89
+
isAuthenticated: isAuthenticated,
79
-
Widget _buildBody(FeedProvider feedProvider, bool isAuthenticated) {
96
+
required bool isLoading,
97
+
required String? error,
98
+
required List<FeedViewPost> posts,
99
+
required bool isLoadingMore,
100
+
required bool isAuthenticated,
81
-
if (feedProvider.isLoading) {
child: CircularProgressIndicator(color: Color(0xFFFF6B35)),
88
-
if (feedProvider.error != null) {
110
+
if (error != null) {
padding: const EdgeInsets.all(24),
···
const SizedBox(height: 8),
111
-
feedProvider.error!,
133
+
_getUserFriendlyError(error),
style: const TextStyle(fontSize: 14, color: Color(0xFFB6C2D2)),
textAlign: TextAlign.center,
const SizedBox(height: 24),
117
-
onPressed: () => feedProvider.retry(),
140
+
final feedProvider = Provider.of<FeedProvider>(
144
+
feedProvider.retry();
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFF6B35),
···
130
-
if (feedProvider.posts.isEmpty) {
158
+
if (posts.isEmpty) {
padding: const EdgeInsets.all(24),
···
color: const Color(0xFFFF6B35),
controller: _scrollController,
168
-
feedProvider.posts.length + (feedProvider.isLoadingMore ? 1 : 0),
195
+
itemCount: posts.length + (isLoadingMore ? 1 : 0),
itemBuilder: (context, index) {
170
-
if (index == feedProvider.posts.length) {
197
+
if (index == posts.length) {
padding: EdgeInsets.all(16),
···
179
-
final post = feedProvider.posts[index];
206
+
final post = posts[index];
'Feed post in ${post.post.community.name} by ${post.post.author.displayName ?? post.post.author.handle}. ${post.post.title ?? ""}',
···
218
+
/// Transform technical error messages into user-friendly ones
219
+
String _getUserFriendlyError(String error) {
220
+
final lowerError = error.toLowerCase();
222
+
if (lowerError.contains('socketexception') ||
223
+
lowerError.contains('network') ||
224
+
lowerError.contains('connection refused')) {
225
+
return 'Please check your internet connection';
226
+
} else if (lowerError.contains('timeoutexception') ||
227
+
lowerError.contains('timeout')) {
228
+
return 'Request timed out. Please try again';
229
+
} else if (lowerError.contains('401') ||
230
+
lowerError.contains('unauthorized')) {
231
+
return 'Authentication failed. Please sign in again';
232
+
} else if (lowerError.contains('404') || lowerError.contains('not found')) {
233
+
return 'Content not found';
234
+
} else if (lowerError.contains('500') ||
235
+
lowerError.contains('internal server')) {
236
+
return 'Server error. Please try again later';
239
+
// Fallback to generic message for unknown errors
240
+
return 'Something went wrong. Please try again';