network_reachability 0.0.1+1 copy "network_reachability: ^0.0.1+1" to clipboard
network_reachability: ^0.0.1+1 copied to clipboard

An advanced network monitoring and resilience library for Flutter, powered by a high-performance Rust core.

example/lib/main.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:network_reachability/network_reachability.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await RustLib.init();

  final defaultConfig = await NetworkConfiguration.default_();
  final customConfig = NetworkConfiguration(
    targets: defaultConfig.targets,
    checkIntervalMs: BigInt.from(5000),
    cacheValidityMs: BigInt.from(1000),
    qualityThreshold: defaultConfig.qualityThreshold,
    security: const SecurityConfig(blockVpn: true, detectDnsHijack: true),
    resilience: defaultConfig.resilience,
  );

  await NetworkReachability.init(config: customConfig);
  runApp(
    const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: NetworkEngineHub(),
    ),
  );
}

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

  @override
  State<NetworkEngineHub> createState() => _NetworkEngineHubState();
}

class _NetworkEngineHubState extends State<NetworkEngineHub> {
  NetworkReport? _report;
  CaptivePortalStatus? _cpStatus;
  StreamSubscription? _statusSub;
  bool _isBusy = false;

  @override
  void initState() {
    super.initState();
    _fetchReport();
    _statusSub = NetworkReachability.instance.onStatusChange.listen(
      (_) => _fetchReport(),
    );
  }

  @override
  void dispose() {
    _statusSub?.cancel();
    super.dispose();
  }

  Future<void> _fetchReport() async {
    final report = await NetworkReachability.instance.check(forceRefresh: true);
    if (mounted) setState(() => _report = report);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF020617),
      appBar: _buildAppBar(),
      body: _report == null
          ? const Center(
              child: CircularProgressIndicator(color: Colors.cyanAccent),
            )
          : _buildBody(),
    );
  }

  PreferredSizeWidget _buildAppBar() {
    return AppBar(
      backgroundColor: Colors.transparent,
      scrolledUnderElevation: 0,
      elevation: 0,
      title: const Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'NETWORK REACHABILITY',
            style: TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.bold,
              letterSpacing: 1.5,
              color: Colors.cyanAccent,
            ),
          ),
          Text(
            'CORE ENGINE v0.0.1',
            style: TextStyle(fontSize: 10, color: Colors.white38),
          ),
        ],
      ),
      actions: [
        if (_isBusy)
          const Center(
            child: Padding(
              padding: EdgeInsets.all(16.0),
              child: SizedBox(
                width: 16,
                height: 16,
                child: CircularProgressIndicator(
                  strokeWidth: 2,
                  color: Colors.cyanAccent,
                ),
              ),
            ),
          ),
        IconButton(
          icon: const Icon(Icons.refresh, color: Colors.white70),
          onPressed: _fetchReport,
        ),
      ],
    );
  }

  Widget _buildBody() {
    final status = _report!.status;
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildMainStatusCard(status),
          const SizedBox(height: 24),
          _buildSectionHeader('SIMULATION & TOOLS'),
          _buildToolGrid(),
          const SizedBox(height: 24),
          _buildSectionHeader('LATENCY DASHBOARD'),
          _buildLatencyGrid(status.latencyStats),
          const SizedBox(height: 24),
          _buildSectionHeader('TARGET ANALYSIS (GRANULAR)'),
          ..._report!.targetReports.map((t) => _buildTargetDetailedCard(t)),
          const SizedBox(height: 24),
          _buildSectionHeader('SECURITY & SYSTEM INTERFACE'),
          _buildSecurityInfo(),
          const SizedBox(height: 50),
        ],
      ),
    );
  }

  Widget _buildMainStatusCard(NetworkStatus status) {
    final color = _getQualityColor(status.quality);
    return Container(
      padding: const EdgeInsets.all(24),
      decoration: BoxDecoration(
        color: const Color(0xFF1E293B).withAlpha(0x50),
        borderRadius: BorderRadius.circular(24),
        border: Border.all(color: color.withAlpha(0x30), width: 2),
      ),
      child: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    status.quality.name.toUpperCase(),
                    style: TextStyle(
                      color: color,
                      fontSize: 32,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(height: 4),
                  Row(
                    children: [
                      Icon(
                        status.isConnected ? Icons.check_circle : Icons.error,
                        color: status.isConnected ? Colors.green : Colors.red,
                        size: 14,
                      ),
                      const SizedBox(width: 6),
                      Text(
                        status.isConnected ? 'SYSTEM ONLINE' : 'SYSTEM OFFLINE',
                        style: const TextStyle(
                          color: Colors.white60,
                          fontSize: 12,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ],
                  ),
                ],
              ),
              _buildStabilityRing(status.latencyStats.stabilityScore),
            ],
          ),
          const Divider(height: 40, color: Colors.white10),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              _buildMiniInfo(
                'WINNER TARGET',
                status.winnerTarget.isEmpty
                    ? 'NONE'
                    : status.winnerTarget.toUpperCase(),
              ),
              _buildMiniInfo(
                'TYPE',
                _report!.connectionType.name.toUpperCase(),
              ),
              _buildMiniInfo('LATENCY', '${status.latencyStats.latencyMs}ms'),
            ],
          ),
        ],
      ),
    );
  }

  Widget _buildTargetDetailedCard(TargetReport t) {
    final bool isFailed = !t.success;
    return Container(
      margin: const EdgeInsets.only(bottom: 12),
      decoration: BoxDecoration(
        color: const Color(0xFF0F172A),
        borderRadius: BorderRadius.circular(16),
        border: Border.all(
          color: isFailed
              ? Colors.red.withAlpha(0x30)
              : Colors.white.withAlpha(0x05),
        ),
      ),
      child: ExpansionTile(
        leading: Icon(
          isFailed ? Icons.dangerous : Icons.check_circle,
          color: isFailed ? Colors.redAccent : Colors.greenAccent,
        ),
        title: Text(
          t.label,
          style: const TextStyle(
            color: Colors.white,
            fontWeight: FontWeight.bold,
            fontSize: 14,
          ),
        ),
        subtitle: Text(
          isFailed ? 'FAILED PROBE' : 'RESPONSE: ${t.latencyMs}ms',
          style: TextStyle(
            color: isFailed ? Colors.redAccent : Colors.white38,
            fontSize: 11,
          ),
        ),
        trailing: t.isEssential
            ? Container(
                padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
                decoration: BoxDecoration(
                  color: Colors.cyanAccent.withAlpha(0x10),
                  borderRadius: BorderRadius.circular(4),
                ),
                child: const Text(
                  'ESSENTIAL',
                  style: TextStyle(
                    color: Colors.cyanAccent,
                    fontSize: 9,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              )
            : null,
        childrenPadding: const EdgeInsets.all(16),
        expandedCrossAxisAlignment: CrossAxisAlignment.start,
        children: [
          if (isFailed) ...[
            const Text(
              'ERROR LOG:',
              style: TextStyle(
                color: Colors.redAccent,
                fontSize: 10,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 4),
            Container(
              width: double.infinity,
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.black26,
                borderRadius: BorderRadius.circular(8),
              ),
              child: Text(
                t.error ?? 'Unknown connection timeout or DNS failure',
                style: const TextStyle(
                  color: Colors.white70,
                  fontSize: 12,
                  fontFamily: 'monospace',
                ),
              ),
            ),
            const SizedBox(height: 12),
          ],
          _buildRowDetail('Success State', t.success ? 'TRUE' : 'FALSE'),
          _buildRowDetail('Response Time', '${t.latencyMs}ms'),
          _buildRowDetail(
            'Criticality',
            t.isEssential ? 'HIGH (Essential)' : 'LOW (Redundant)',
          ),
          _buildRowDetail('Internal ID', t.hashCode.toString()),
        ],
      ),
    );
  }

  Widget _buildLatencyGrid(LatencyStats s) {
    return GridView.count(
      shrinkWrap: true,
      physics: const NeverScrollableScrollPhysics(),
      crossAxisCount: 2,
      childAspectRatio: 2.2,
      mainAxisSpacing: 12,
      crossAxisSpacing: 12,
      children: [
        _buildStatCard('AVG LATENCY', '${s.latencyMs}ms', Icons.timer),
        _buildStatCard(
          'JITTER (STD DEV)',
          '${s.jitterMs}ms',
          Icons.timelapse_rounded,
        ),
        _buildStatCard(
          'PACKET LOSS',
          '${s.packetLossPercent}%',
          Icons.trending_down,
        ),
        _buildStatCard('P95 PEAK', '${s.maxLatencyMs ?? 0}ms', Icons.speed),
      ],
    );
  }

  Widget _buildSecurityInfo() {
    final f = _report!.securityFlagsResult;
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: const Color(0xFF1E293B).withAlpha(0x30),
        borderRadius: BorderRadius.circular(20),
      ),
      child: Column(
        children: [
          _buildSecurityRow('Interface', f.interfaceName, Icons.lan),
          _buildSecurityRow(
            'VPN Access',
            f.isVpnDetected ? 'DETECTION ACTIVE' : 'NONE',
            Icons.vpn_lock,
            active: f.isVpnDetected,
            alert: true,
          ),
          _buildSecurityRow(
            'DNS Status',
            f.isDnsSpoofed ? 'SPOOFING SUSPECTED' : 'TRUSTED/VERIFIED',
            Icons.security,
            active: f.isDnsSpoofed,
            alert: true,
          ),
          _buildSecurityRow(
            'System Proxy',
            f.isProxyDetected ? 'REDIRECTED' : 'DIRECT CONNECTION',
            Icons.router,
            active: f.isProxyDetected,
          ),
          if (_cpStatus != null)
            _buildSecurityRow(
              'Captive Portal',
              _cpStatus!.isCaptivePortal ? 'AUTH REQUIRED' : 'FREE ACCESS',
              Icons.web,
              active: _cpStatus!.isCaptivePortal,
            ),
        ],
      ),
    );
  }

  // --- Helpers & UI Components ---

  Widget _buildSectionHeader(String title) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 12, left: 4),
      child: Text(
        title,
        style: const TextStyle(
          color: Colors.cyanAccent,
          fontSize: 11,
          fontWeight: FontWeight.bold,
          letterSpacing: 1.5,
        ),
      ),
    );
  }

  Widget _buildStatCard(String label, String value, IconData icon) {
    return Container(
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: const Color(0xFF1E293B).withAlpha(0x30),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: Colors.white.withAlpha(0x05)),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Row(
            children: [
              Icon(icon, size: 10, color: Colors.cyanAccent),
              const SizedBox(width: 4),
              Text(
                label,
                style: const TextStyle(
                  color: Colors.white38,
                  fontSize: 9,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ],
          ),
          const SizedBox(height: 4),
          Text(
            value,
            style: const TextStyle(
              overflow: TextOverflow.fade,
              color: Colors.white,
              fontSize: 18,
              fontWeight: FontWeight.bold,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildSecurityRow(
    String label,
    String value,
    IconData icon, {
    bool active = false,
    bool alert = false,
  }) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Row(
        children: [
          Icon(
            icon,
            size: 16,
            color: active && alert ? Colors.redAccent : Colors.white24,
          ),
          const SizedBox(width: 12),
          Text(
            label,
            style: const TextStyle(color: Colors.white70, fontSize: 13),
          ),
          const Spacer(),
          Text(
            value,
            style: TextStyle(
              color: active && alert
                  ? Colors.redAccent
                  : (active ? Colors.orangeAccent : Colors.cyanAccent),
              fontSize: 12,
              fontWeight: FontWeight.bold,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildRowDetail(String label, String value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(
            label,
            style: const TextStyle(color: Colors.white38, fontSize: 12),
          ),
          Text(
            value,
            style: const TextStyle(
              color: Colors.white70,
              fontSize: 12,
              fontWeight: FontWeight.w500,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildStabilityRing(int score) {
    return Stack(
      alignment: Alignment.center,
      children: [
        SizedBox(
          width: 50,
          height: 50,
          child: CircularProgressIndicator(
            value: score / 100,
            backgroundColor: Colors.white10,
            color: Colors.cyanAccent,
            strokeWidth: 4,
          ),
        ),
        Text(
          '$score',
          style: const TextStyle(
            color: Colors.white,
            fontWeight: FontWeight.bold,
            fontSize: 16,
          ),
        ),
      ],
    );
  }

  Widget _buildMiniInfo(String label, String value) {
    return Column(
      children: [
        Text(
          label,
          style: const TextStyle(
            color: Colors.white24,
            fontSize: 9,
            fontWeight: FontWeight.bold,
          ),
        ),
        const SizedBox(height: 2),
        Text(
          value,
          style: const TextStyle(
            color: Colors.white,
            fontSize: 13,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }

  Widget _buildToolGrid() {
    return Wrap(
      spacing: 10,
      runSpacing: 10,
      children: [
        _toolButton('GUARD: ACTION', _runGuardDemo, Icons.shield),
        _toolButton('PORTAL CHECK', _runPortalCheck, Icons.web),
      ],
    );
  }

  Widget _toolButton(String label, VoidCallback action, IconData icon) {
    return InkWell(
      onTap: _isBusy ? null : action,
      child: Container(
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
        decoration: BoxDecoration(
          color: Colors.cyanAccent.withAlpha(0x05),
          borderRadius: BorderRadius.circular(12),
          border: Border.all(color: Colors.cyanAccent.withAlpha(0x10)),
        ),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Icon(icon, size: 14, color: Colors.cyanAccent),
            const SizedBox(width: 8),
            Text(
              label,
              style: const TextStyle(
                color: Colors.cyanAccent,
                fontSize: 11,
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
    );
  }

  // --- Logic Execution ---

  Future<void> _runGuardDemo() async {
    setState(() => _isBusy = true);
    try {
      final res = await NetworkReachability.instance.guard(
        minQuality: ConnectionQuality.good,
        action: () async => "SUCCESS: Critical Logic Executed",
      );
      _showSnack(res, Colors.green);
    } catch (e) {
      _showSnack(e.toString(), Colors.redAccent);
    } finally {
      setState(() => _isBusy = false);
    }
  }

  Future<void> _runPortalCheck() async {
    setState(() => _isBusy = true);
    final status = await NetworkReachability.instance.checkForCaptivePortal(
      timeoutMs: BigInt.from(2000),
    );
    setState(() {
      _cpStatus = status;
      _isBusy = false;
    });
    _showSnack(
      status.isCaptivePortal
          ? "PORTAL DETECTED: Authentication needed"
          : "CLEAN: Direct Internet Access",
      status.isCaptivePortal ? Colors.orange : Colors.blue,
    );
  }

  void _showSnack(String msg, Color color) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(
          msg,
          style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
        ),
        backgroundColor: color,
        behavior: SnackBarBehavior.floating,
      ),
    );
  }

  Color _getQualityColor(ConnectionQuality q) {
    switch (q) {
      case ConnectionQuality.excellent:
        return Colors.cyanAccent;
      case ConnectionQuality.great:
        return Colors.greenAccent;
      case ConnectionQuality.good:
        return Colors.yellowAccent;
      case ConnectionQuality.moderate:
        return Colors.orangeAccent;
      case ConnectionQuality.poor:
        return Colors.redAccent;
      default:
        return Colors.white24;
    }
  }
}
0
likes
150
points
59
downloads

Publisher

unverified uploader

Weekly Downloads

An advanced network monitoring and resilience library for Flutter, powered by a high-performance Rust core.

Repository (GitHub)
View/report issues
Contributing

Topics

#network #reachability #connectivity #utils

Documentation

API reference

Funding

Consider supporting this project:

github.com
buymeacoffee.com
ipn.eg

License

GPL-3.0 (license)

Dependencies

flutter, flutter_rust_bridge, plugin_platform_interface

More

Packages that depend on network_reachability

Packages that implement network_reachability