reach 0.0.1
reach: ^0.0.1 copied to clipboard
A reliable internet connection checking package for Flutter and Dart applications that validates active socket connections.
import 'package:flutter/material.dart';
import 'package:reach/reach.dart';
void main() {
runApp(const ReachExampleApp());
}
class ReachExampleApp extends StatelessWidget {
const ReachExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Reach Example',
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
home: const ReachHomePage(),
);
}
}
class ReachHomePage extends StatefulWidget {
const ReachHomePage({super.key});
@override
State<ReachHomePage> createState() => _ReachHomePageState();
}
class _ReachHomePageState extends State<ReachHomePage> {
late final Reach _reach;
final List<String> _logs = [];
bool _isCheckingManual = false;
@override
void initState() {
super.initState();
// Initialize Reach with a 15-second recheck interval
_reach = Reach(
host: '1.1.1.1',
port: 443,
timeout: const Duration(seconds: 3),
retryGap: const Duration(seconds: 4),
debounce: const Duration(milliseconds: 500),
recheckInterval: const Duration(seconds: 15),
);
// Start listening to connectivity events
_reach.start();
// Log status updates received through the stream
_reach.stream.listen((isOnline) {
_addLog('Stream update: ${isOnline ? "ONLINE" : "OFFLINE"}');
});
}
@override
void dispose() {
// Always dispose Reach to cancel active timers and stream subscriptions
_reach.dispose();
super.dispose();
}
void _addLog(String message) {
if (!mounted) return;
setState(() {
final timestamp = TimeOfDay.now().format(context);
_logs.insert(0, '[$timestamp] $message');
});
}
Future<void> _performManualCheck() async {
setState(() => _isCheckingManual = true);
_addLog('Initiating manual probe...');
final isOnline = await _reach.check();
if (mounted) {
setState(() => _isCheckingManual = false);
_addLog('Manual probe result: ${isOnline ? "ONLINE 🌐" : "OFFLINE 🔴"}');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Reach Connectivity Monitor'),
centerTitle: true,
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Real-time connection status banner
StreamBuilder<bool>(
stream: _reach.stream,
initialData: _reach.current,
builder: (context, snapshot) {
final isOnline = snapshot.data;
return Card(
elevation: 2,
color: _getStatusColor(isOnline),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Icon(
_getStatusIcon(isOnline),
size: 48,
color: Colors.white,
),
const SizedBox(height: 12),
Text(
_getStatusText(isOnline),
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 4),
Text(
isOnline == null
? 'Initializing probe...'
: 'Cached status (Reach.current): ${_reach.current}',
style: const TextStyle(
color: Colors.white70,
fontSize: 13,
),
),
],
),
),
);
},
),
const SizedBox(height: 16),
// Action Bar
Row(
children: [
Expanded(
child: FilledButton.icon(
onPressed: _isCheckingManual ? null : _performManualCheck,
icon: _isCheckingManual
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: const Icon(Icons.refresh),
label: Text(
_isCheckingManual ? 'Probing...' : 'Check Now',
),
),
),
const SizedBox(width: 12),
OutlinedButton.icon(
onPressed: () => setState(() => _logs.clear()),
icon: const Icon(Icons.delete_outline),
label: const Text('Clear Log'),
),
],
),
const SizedBox(height: 20),
// Activity Log Header
const Text(
'Activity Log',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
// Activity Log List
Expanded(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.surfaceContainerHighest,
borderRadius: BorderRadius.circular(12),
),
child: _logs.isEmpty
? const Center(
child: Text(
'No events logged yet.',
style: TextStyle(color: Colors.grey),
),
)
: ListView.separated(
padding: const EdgeInsets.all(12),
itemCount: _logs.length,
separatorBuilder: (_, _) => const Divider(height: 8),
itemBuilder: (context, index) {
return Text(
_logs[index],
style: const TextStyle(
fontFamily: 'monospace',
fontSize: 13,
),
);
},
),
),
),
],
),
),
),
);
}
Color _getStatusColor(bool? isOnline) {
if (isOnline == null) return Colors.orange;
return isOnline ? Colors.green.shade700 : Colors.red.shade700;
}
IconData _getStatusIcon(bool? isOnline) {
if (isOnline == null) return Icons.sync;
return isOnline ? Icons.wifi : Icons.wifi_off;
}
String _getStatusText(bool? isOnline) {
if (isOnline == null) return 'Checking Connection...';
return isOnline ? 'Internet Connected' : 'No Internet Access';
}
}