flutter_network_toolkit 1.0.0 copy "flutter_network_toolkit: ^1.0.0" to clipboard
flutter_network_toolkit: ^1.0.0 copied to clipboard

A comprehensive Flutter toolkit for real-time network connectivity monitoring, reliable HTTP client with automatic retry, ping diagnostics, and ready-to-use offline UI widgets.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_network_toolkit/flutter_network_toolkit.dart';

void main() {
  runApp(const ToolkitExampleApp());
}

class ToolkitExampleApp extends StatelessWidget {
  const ToolkitExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Network Toolkit Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.indigo,
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.indigo,
        brightness: Brightness.dark,
      ),
      home: const OfflineBanner(
        position: BannerPosition.top,
        child: HomeScreen(),
      ),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final NetworkDiagnostics _diagnostics = NetworkDiagnostics();
  late final NetworkClient _client;

  DiagnosticReport? _latestReport;
  bool _isDiagnosing = false;

  String _apiResult = 'No request sent yet.';
  bool _isLoadingApi = false;

  @override
  void initState() {
    super.initState();
    _client = NetworkClient(
      baseUrl: Uri.parse('https://jsonplaceholder.typicode.com'),
      interceptors: [NetworkLoggingInterceptor()],
      retryPolicy: const RetryPolicy(
        maxRetries: 3,
        initialDelay: Duration(milliseconds: 500),
      ),
    );
  }

  @override
  void dispose() {
    _client.dispose();
    super.dispose();
  }

  Future<void> _runDiagnostics() async {
    setState(() => _isDiagnosing = true);
    try {
      final report = await _diagnostics.runDiagnosticReport();
      setState(() => _latestReport = report);
    } finally {
      if (mounted) setState(() => _isDiagnosing = false);
    }
  }

  Future<void> _fetchData() async {
    setState(() {
      _isLoadingApi = true;
      _apiResult = 'Sending request...';
    });

    try {
      final response = await _client.get('/todos/1');
      setState(() {
        _apiResult = 'Status: ${response.statusCode}\n\n${response.data}';
      });
    } on NetworkException catch (e) {
      setState(() {
        _apiResult = 'Caught NetworkException:\n$e';
      });
    } catch (e) {
      setState(() {
        _apiResult = 'Unexpected error: $e';
      });
    } finally {
      if (mounted) setState(() => _isLoadingApi = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Network Toolkit'),
        centerTitle: true,
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            tooltip: 'Check Network',
            onPressed: () => NetworkWatcher.instance.checkNetwork(),
          ),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          // Live status card
          _buildStatusCard(),
          const SizedBox(height: 16),

          // Latency & Diagnostics
          _buildDiagnosticsCard(),
          const SizedBox(height: 16),

          // Resilient HTTP Client card
          _buildHttpClientCard(),
          const SizedBox(height: 16),

          // Full Screen Offline Preview
          _buildOfflinePreviewCard(),
        ],
      ),
    );
  }

  Widget _buildStatusCard() {
    return NetworkStatusBuilder(
      builder: (context, info, _) {
        final isConnected = info.isConnected;
        final color = isConnected ? Colors.green : Colors.red;

        return Card(
          elevation: 2,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16),
            side: BorderSide(color: color.withValues(alpha: 0.3), width: 1.5),
          ),
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Row(
                  children: [
                    Container(
                      padding: const EdgeInsets.all(8),
                      decoration: BoxDecoration(
                        color: color.withValues(alpha: 0.15),
                        shape: BoxShape.circle,
                      ),
                      child: Icon(
                        isConnected ? Icons.wifi : Icons.wifi_off,
                        color: color,
                        size: 24,
                      ),
                    ),
                    const SizedBox(width: 12),
                    Expanded(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            isConnected ? 'Online & Connected' : 'Offline / No Access',
                            style: TextStyle(
                              fontSize: 17,
                              fontWeight: FontWeight.bold,
                              color: color,
                            ),
                          ),
                          Text(
                            'Quality: ${info.quality.name.toUpperCase()}',
                            style: Theme.of(context).textTheme.bodySmall,
                          ),
                        ],
                      ),
                    ),
                    Chip(
                      label: Text(
                        info.status.name.toUpperCase(),
                        style: TextStyle(
                          color: color,
                          fontSize: 11,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      backgroundColor: color.withValues(alpha: 0.1),
                      side: BorderSide.none,
                    ),
                  ],
                ),
                const Divider(height: 24),
                Wrap(
                  spacing: 8,
                  runSpacing: 8,
                  children: [
                    _buildInfoChip(
                      Icons.router,
                      'Types: ${info.connectionTypes.map((t) => t.name).join(", ")}',
                    ),
                    _buildInfoChip(
                      Icons.speed,
                      info.latencyMs != null
                          ? '${info.latencyMs} ms'
                          : 'Latency unmeasured',
                    ),
                    _buildInfoChip(
                      Icons.cloud_done,
                      info.hasInternetAccess
                          ? 'Internet Verified'
                          : 'No Internet WAN',
                    ),
                  ],
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  Widget _buildDiagnosticsCard() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Text(
                  'Network Diagnostics',
                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                ),
                ElevatedButton.icon(
                  onPressed: _isDiagnosing ? null : _runDiagnostics,
                  icon: _isDiagnosing
                      ? const SizedBox(
                          width: 14,
                          height: 14,
                          child: CircularProgressIndicator(strokeWidth: 2),
                        )
                      : const Icon(Icons.play_arrow, size: 18),
                  label: const Text('Run Ping Test'),
                ),
              ],
            ),
            const SizedBox(height: 12),
            if (_latestReport != null) ...[
              Text(
                'Average: ${_latestReport!.averageLatencyMs}ms | Min: ${_latestReport!.minLatencyMs}ms | Max: ${_latestReport!.maxLatencyMs}ms',
                style: const TextStyle(fontWeight: FontWeight.w600),
              ),
              const SizedBox(height: 4),
              Text(
                'Jitter: ${_latestReport!.jitterMs}ms | Loss: ${(_latestReport!.packetLossRate * 100).toStringAsFixed(0)}% | Quality: ${_latestReport!.quality.name}',
                style: Theme.of(context).textTheme.bodySmall,
              ),
            ] else
              const Text(
                'Tap "Run Ping Test" to measure latency and packet stability.',
                style: TextStyle(color: Colors.grey),
              ),
          ],
        ),
      ),
    );
  }

  Widget _buildHttpClientCard() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              'Resilient HTTP Client with Retry',
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 6),
            const Text(
              'Sends request with automatic exponential backoff retries & interceptor logging.',
              style: TextStyle(fontSize: 13, color: Colors.grey),
            ),
            const SizedBox(height: 12),
            Row(
              children: [
                ElevatedButton.icon(
                  onPressed: _isLoadingApi ? null : _fetchData,
                  icon: _isLoadingApi
                      ? const SizedBox(
                          width: 14,
                          height: 14,
                          child: CircularProgressIndicator(strokeWidth: 2),
                        )
                      : const Icon(Icons.send, size: 18),
                  label: const Text('Fetch Todo Item'),
                ),
                const SizedBox(width: 12),
                ConnectivityAware(
                  onTap: () {
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(content: Text('Action allowed! Device is online.')),
                    );
                  },
                  child: OutlinedButton(
                    onPressed: null, // Handled by ConnectivityAware
                    child: const Text('Guarded Action'),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),
            Container(
              width: double.infinity,
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Theme.of(context).colorScheme.surfaceContainerHighest,
                borderRadius: BorderRadius.circular(8),
              ),
              child: SelectableText(
                _apiResult,
                style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildOfflinePreviewCard() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: ListTile(
        leading: const Icon(Icons.screen_lock_portrait_outlined),
        title: const Text('Preview "No Internet" Screen'),
        subtitle: const Text('View the full-screen empty state widget'),
        trailing: const Icon(Icons.chevron_right),
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (screenContext) => NoInternetScreen(
                onRetry: () async {
                  await Future<void>.delayed(const Duration(seconds: 1));
                  if (screenContext.mounted) Navigator.pop(screenContext);
                },
              ),
            ),
          );
        },
      ),
    );
  }

  Widget _buildInfoChip(IconData icon, String text) {
    return Chip(
      avatar: Icon(icon, size: 16),
      label: Text(text, style: const TextStyle(fontSize: 12)),
      visualDensity: VisualDensity.compact,
    );
  }
}
0
likes
160
points
64
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter toolkit for real-time network connectivity monitoring, reliable HTTP client with automatic retry, ping diagnostics, and ready-to-use offline UI widgets.

Repository (GitHub)
View/report issues

Topics

#networking #connectivity #offline #http #network-status

License

MIT (license)

Dependencies

connectivity_plus, flutter, http

More

Packages that depend on flutter_network_toolkit