smart_fetch 1.0.7
smart_fetch: ^1.0.7 copied to clipboard
Beautiful full-screen error pages for server side errors and no internet connection state.
SmartFetch #
A Flutter package that provides beautiful full-screen error pages and intelligent handling for server-side errors, no internet connection states, and timeouts. SmartFetch simplifies error handling in your Flutter applications with ready-to-use widgets and utilities.
Screenshots #
No Internet #
[No Internet Screen]
Server Error #
[Server Error Screen]
Features #
✨ Automatic Error Detection: Distinguishes between no internet, server errors, and timeouts
🎨 Beautiful Error Screens: Pre-built, animated full-screen error pages using Lottie animations
🔄 Easy Integration: Simple API with both programmatic and widget-based approaches
🎯 Type-Safe Results: Strongly-typed result objects for clean error handling
📱 Accessible Error Screens: Use predefined screens directly or via helper methods
🌐 Connectivity Aware: Real-time internet connectivity checking
🚀 Flexible Usage: Three ways to use error screens - automatic, helper methods, or direct access
Getting Started #
Step 1: Add Dependency #
Add smart_fetch to your pubspec.yaml:
dependencies:
smart_fetch: ^1.0.7
http: ^1.6.0
Step 2: Declare Assets (Required for Lottie Animations) #
The package includes Lottie animations for error screens. You must declare the assets in your pubspec.yaml:
flutter:
assets:
- packages/smart_fetch/assets/animations/
Important: Without this declaration, the Lottie animations won't load and you'll see asset loading errors.
Step 3: Install #
Run:
flutter pub get
Note: The assets are bundled with the package, so you only need to declare them in your app's pubspec.yaml - you don't need to copy the files.
Quick Start #
Method 1: Automatic Error Screens (Easiest) #
Error screens are shown automatically with SmartFetch.builder():
import 'package:smart_fetch/smart_fetch.dart';
import 'package:http/http.dart' as http;
SmartFetch.builder(
future: () => http.get(Uri.parse('https://api.example.com/data')),
onSuccess: (context, response) => Text('Success: ${response.body}'),
loadingWidget: CircularProgressIndicator(),
)
// Error screens show automatically!
Method 2: Using Helper Methods (Recommended) #
Use SmartFetchNavigator for easy navigation to error screens:
import 'package:smart_fetch/smart_fetch.dart';
import 'package:http/http.dart' as http;
final result = await SmartFetch.call(
() => http.get(Uri.parse('https://api.example.com/data')),
);
// One line to show the correct error screen
SmartFetchNavigator.showErrorScreen(context, result);
// Or show specific screens
SmartFetchNavigator.showNoInternet(context);
SmartFetchNavigator.showServerError(context);
SmartFetchNavigator.showTimeout(context);
Method 3: Direct Screen Access #
Import and use error screens directly:
import 'package:smart_fetch/smart_fetch.dart';
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const NoInternetScreen()),
);
Usage Examples #
Basic API Call with Error Handling #
Option 1: When you have BuildContext (in a Widget)
import 'package:smart_fetch/smart_fetch.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
class MyWidget extends StatelessWidget {
Future<void> fetchData(BuildContext context) async {
final result = await SmartFetch.call(
() => http.get(Uri.parse('https://api.example.com/data')),
timeout: const Duration(seconds: 10),
context: context,
errorSnackBar: const SnackBar(
content: Text('Request failed. Please try again.'),
backgroundColor: Colors.red,
),
);
if (result.isSuccess) {
print('Success: ${result.response?.body}');
} else {
// Use helper method - automatically shows correct screen
SmartFetchNavigator.showErrorScreen(context, result);
}
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => fetchData(context),
child: Text('Fetch Data'),
);
}
}
Option 2: When you don't have BuildContext (Service Classes)
Use a global navigator key and pass it to the helper methods:
// In main.dart
final navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey, // Add this
home: HomeScreen(),
);
}
}
// In your service class
import 'package:smart_fetch/smart_fetch.dart';
import 'package:http/http.dart' as http;
import 'main.dart'; // Import to access navigatorKey
class ApiService {
static Future<void> fetchData() async {
final result = await SmartFetch.call(
() => http.get(Uri.parse('https://api.example.com/data')),
);
if (result.isSuccess) {
print('Success: ${result.response?.body}');
} else {
// Use navigator key to show error screen
SmartFetchNavigator.showErrorScreenWithKey(navigatorKey, result);
}
}
}
Widget-Based Integration with Custom Error Handling #
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:smart_fetch/smart_fetch.dart';
import 'package:http/http.dart' as http;
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final emailController = TextEditingController();
final passwordController = TextEditingController();
bool shouldLogin = false;
int loginTrigger = 0;
@override
void dispose() {
emailController.dispose();
passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: emailController,
decoration: const InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextField(
controller: passwordController,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 30),
if (!shouldLogin)
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: () {
setState(() {
shouldLogin = true;
loginTrigger++;
});
},
child: const Text('Login'),
),
)
else
SizedBox(
height: 200,
child: SmartFetch.builder(
key: ValueKey('login_fetch_$loginTrigger'),
future: () {
final body = {
"email": emailController.text,
"password": passwordController.text,
};
final headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
return http.post(
Uri.parse('https://api.example.com/login'),
headers: headers,
body: jsonEncode(body),
);
},
loadingWidget: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('Logging in...'),
],
),
),
onSuccess: (context, response) {
if (response.statusCode == 200) {
// Handle successful login
return const Center(
child: Icon(
Icons.check_circle,
color: Colors.green,
size: 48,
),
);
} else {
// Handle error response
setState(() {
shouldLogin = false;
});
return Center(
child: Text('Login failed: ${response.statusCode}'),
);
}
},
timeout: const Duration(seconds: 10),
errorSnackBar: const SnackBar(
content: Text('Login failed. Please check your connection and try again.'),
backgroundColor: Colors.orange,
duration: Duration(seconds: 4),
),
onError: (context, error) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
final errorScreen = error.isTimeout
? const TimeoutScreen()
: error.isNoInternet
? const NoInternetScreen()
: const ServerErrorScreen();
await Navigator.push(
context,
MaterialPageRoute(builder: (_) => errorScreen),
);
if (mounted) {
setState(() {
shouldLogin = false;
});
}
});
return const SizedBox.shrink();
},
),
),
],
),
),
);
}
}
Using Error Screens in Service Classes (No Context Needed!) #
Perfect for service classes where you don't have BuildContext:
Step 1: Create navigator key in main.dart
final navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
home: HomeScreen(),
);
}
}
Step 2: Use in service class with navigator key
// In your service class
import 'main.dart'; // Import to access navigatorKey
final result = await SmartFetch.call(
() => http.post(Uri.parse(apiUrl), body: body),
);
if (result.isSuccess) {
// Handle success
} else {
// Show error screen using navigator key
SmartFetchNavigator.showErrorScreenWithKey(navigatorKey, result);
}
Manual Connectivity Check #
import 'package:smart_fetch/smart_fetch.dart';
final hasInternet = await InternetChecker.hasInternet();
if (hasInternet) {
// Proceed with API call
} else {
SmartFetchNavigator.showNoInternet(context);
}
Asset Configuration #
Lottie Animations #
The package includes Lottie animations for error screens. You must declare the assets in your app's pubspec.yaml:
flutter:
assets:
- packages/smart_fetch/assets/animations/
Important Notes:
- Use the
packages/smart_fetch/prefix to access package assets - The assets are bundled with the package - you don't need to copy them
- After adding assets, run
flutter pub getand restart your app - If assets fail to load, the screens will show fallback icons automatically
Troubleshooting Asset Loading #
If you see "Unable to load asset" or "Asset not found" errors:
-
Check your
pubspec.yaml- Make sure assets are declared:flutter: assets: - packages/smart_fetch/assets/animations/ -
Run
flutter pub getafter adding assets -
Restart your app completely (hot reload won't pick up asset changes)
-
Try
flutter cleanif issues persist:flutter clean flutter pub get flutter run
The screens include fallback icons if Lottie assets fail to load, so your app will still work even if there are asset issues.
Available Error Screens #
The package provides three pre-built error screens:
NoInternetScreen- Shown when device has no internet connectivityServerErrorScreen- Shown when server returns an errorTimeoutScreen- Shown when request exceeds timeout duration
All screens include:
- Beautiful Lottie animations
- Clear error messages
- "Try Again" button for easy retry
API Reference #
SmartFetch.call() #
Makes an HTTP request with automatic error handling.
Parameters:
request: A function that returns a Future of http.Responsetimeout: Optional timeout duration (default: 10 seconds)context: Optional BuildContext to show error SnackBar when error occurserrorSnackBar: Optional SnackBar widget to show when error occurs (requires context)
Returns: SmartFetchResult with status and response data
SmartFetch.builder() #
A widget builder that automatically handles loading, success, and error states.
Parameters:
key: Optional key for the FutureBuilder widget (useful for rebuilding)future: A function that returns a Future of http.ResponseonSuccess: Widget builder called when request succeedsloadingWidget: Optional custom loading widgettimeout: Optional timeout duration (default: 10 seconds)showErrorOnSamePage: If true, shows error screens inline on the same page. If false (default), uses onError callback to navigate to error screenonError: Callback called when an error occurs and showErrorOnSamePage is false (default behavior)errorSnackBar: Optional SnackBar widget to show when error occursnoInternetTitle: Optional custom title for no internet screennoInternetDescription: Optional custom description for no internet screentimeoutTitle: Optional custom title for timeout screentimeoutDescription: Optional custom description for timeout screenserverErrorTitle: Optional custom title for server error screenserverErrorDescription: Optional custom description for server error screen
SmartFetchNavigator #
Helper class with static methods for navigating to error screens:
showNoInternet(context)- Show no internet screenshowServerError(context)- Show server error screenshowTimeout(context)- Show timeout screenshowErrorScreen(context, result)- Automatically show correct screenshowErrorScreenWithKey(navigatorKey, result)- Use with global navigator key
All methods support an optional replace parameter to replace the current route.
Error Screens #
Direct access to error screen widgets:
NoInternetScreen()- No internet connection screenServerErrorScreen()- Server error screenTimeoutScreen()- Timeout screen
Example #
Check out the complete example in the /example folder:
cd example
flutter run
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments #
- Uses Lottie for beautiful animations
- Uses connectivity_plus for network detection
- Built with ❤️ for the Flutter community