flutter_resilience 1.0.2
flutter_resilience: ^1.0.2 copied to clipboard
A production-ready Flutter/Dart package for network resilience.
import 'package:flutter/material.dart';
import 'package:flutter_resilience/flutter_resilience.dart';
import 'dart:async';
void main() {
runApp(const ResilienceExampleApp());
}
class ResilienceExampleApp extends StatelessWidget {
const ResilienceExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Resilience Demo',
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
brightness: Brightness.dark,
),
home: const ResilienceHomePage(),
);
}
}
class ResilienceHomePage extends StatefulWidget {
const ResilienceHomePage({super.key});
@override
State<ResilienceHomePage> createState() => _ResilienceHomePageState();
}
class _ResilienceHomePageState extends State<ResilienceHomePage> {
final List<String> _logs = [];
bool _isLoading = false;
late ResilientClient _client;
late CircuitBreaker _circuitBreaker;
@override
void initState() {
super.initState();
_circuitBreaker = CircuitBreaker(
failureThreshold: 3,
resetTimeout: const Duration(seconds: 5),
onStateChanged: (state) =>
_addLog('Circuit State: ${state.name.toUpperCase()}'),
);
_client = ResilientClient(
retries: 3,
strategy: RetryStrategy.exponential,
retryDelay: const Duration(seconds: 1),
circuitBreaker: _circuitBreaker,
timeout: const Duration(seconds: 2),
retryIf: (error) => error is Exception,
);
}
void _addLog(String message) {
setState(() {
_logs.insert(0,
'${DateTime.now().toIso8601String().split('T').last.substring(0, 8)}: $message');
});
}
Future<void> _simulateRequest(bool shouldFail) async {
setState(() => _isLoading = true);
_addLog('Executing Request (Should Fail: $shouldFail)...');
try {
final result = await _client.execute(
() async {
_addLog('Attempting request...');
await Future<void>.delayed(const Duration(milliseconds: 500));
if (shouldFail) {
throw Exception('Simulated API Failure');
}
return 'Success Data from API';
},
fallback: () => 'Fallback Data (Offline Cache)',
);
_addLog('RESULT: $result');
} catch (e) {
_addLog('ERROR: $e');
} finally {
setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Resilience Demo'),
actions: [
IconButton(
onPressed: () {
setState(_logs.clear);
_circuitBreaker.reset();
},
icon: const Icon(Icons.refresh),
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const _InfoCard(),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed:
_isLoading ? null : () => _simulateRequest(false),
icon: const Icon(Icons.check_circle),
label: const Text('Success Request'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green.withAlpha(51),
),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
onPressed: _isLoading ? null : () => _simulateRequest(true),
icon: const Icon(Icons.error),
label: const Text('Failing Request'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red.withAlpha(51),
),
),
),
],
),
const SizedBox(height: 16),
const Text('Logs',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
const SizedBox(height: 8),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.black26,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.white10),
),
child: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: _logs.length,
separatorBuilder: (_, __) =>
const Divider(height: 1, color: Colors.white10),
itemBuilder: (context, index) {
final log = _logs[index];
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Text(
log,
style: TextStyle(
fontFamily: 'Courier',
color: log.contains('ERROR')
? Colors.redAccent
: (log.contains('Success')
? Colors.greenAccent
: Colors.white70),
),
),
);
},
),
),
),
],
),
),
);
}
}
class _InfoCard extends StatelessWidget {
const _InfoCard();
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Configuration:',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 4),
const Text('• Retries: 3 with Exponential Backoff'),
const Text('• Timeout: 2 seconds'),
const Text('• Circuit Breaker Threshold: 3 failures'),
const Text('• Reset Timeout: 5 seconds'),
const SizedBox(height: 8),
Text(
'Watch the logs to see retry attempts and circuit state transitions.',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontStyle: FontStyle.italic),
),
],
),
),
);
}
}