advanced_device_info 0.0.2 copy "advanced_device_info: ^0.0.2" to clipboard
advanced_device_info: ^0.0.2 copied to clipboard

Advanced device, hardware, security, anti-fraud, thermal, DRM, biometrics, sensors, and live system information for Flutter on Android & iOS.

example/lib/main.dart

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

void main() => runApp(const MyApp());

/// Root application widget configuring dark theme and app shell.
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Advanced Device Info',
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(useMaterial3: true).copyWith(
        scaffoldBackgroundColor: const Color(0xFF0B132B),
        colorScheme: const ColorScheme.dark(
          primary: Color(0xFF6366F1),
          surface: Color(0xFF1C2541),
        ),
        cardTheme: CardThemeData(
          color: const Color(0xFF1C2541),
          elevation: 2,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
        ),
      ),
      home: const DeviceInfoDashboard(),
    );
  }
}

/// Dashboard demonstrating senior-level asynchronous data fetching,
/// reusable UI components, and complete hardware & security inspection.
class DeviceInfoDashboard extends StatefulWidget {
  const DeviceInfoDashboard({super.key});

  @override
  State<DeviceInfoDashboard> createState() => _DeviceInfoDashboardState();
}

class _DeviceInfoDashboardState extends State<DeviceInfoDashboard> {
  late Future<SystemInfo> _deviceInfoFuture;

  @override
  void initState() {
    super.initState();
    _fetchData();
  }

  void _fetchData() {
    setState(() {
      _deviceInfoFuture = AdvancedDeviceInfo.getSystemInfo();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'DEVICE METRICS & SECURITY',
          style: TextStyle(fontWeight: FontWeight.w900, letterSpacing: 1.5, fontSize: 16),
        ),
        centerTitle: true,
        backgroundColor: Colors.transparent,
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh, color: Color(0xFF818CF8)),
            tooltip: 'Refresh Metrics',
            onPressed: _fetchData,
          ),
        ],
      ),
      body: FutureBuilder<SystemInfo>(
        future: _deviceInfoFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(
              child: CircularProgressIndicator(color: Color(0xFF6366F1)),
            );
          }

          if (snapshot.hasError) {
            return _ErrorView(
              errorMessage: snapshot.error.toString(),
              onRetry: _fetchData,
            );
          }

          if (!snapshot.hasData) {
            return const Center(child: Text('No system information available.'));
          }

          final info = snapshot.data!;
          return RefreshIndicator(
            onRefresh: () async => _fetchData(),
            color: const Color(0xFF6366F1),
            child: ListView(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
              children: [
                _HeaderBanner(device: info.deviceInfo),
                const SizedBox(height: 14),
                _LiveHardwareCard(live: info.liveHardwareInfo),
                const SizedBox(height: 14),
                _ThermalCard(thermal: info.thermalInfo),
                const SizedBox(height: 14),
                _DisplayCapabilitiesCard(caps: info.displayCapabilitiesInfo),
                const SizedBox(height: 14),
                _PeripheralsCard(peripherals: info.peripheralsInfo),
                const SizedBox(height: 14),
                _AudioVolumeCard(audio: info.audioVolumeInfo),
                const SizedBox(height: 14),
                _LocaleThemeCard(locale: info.localeThemeInfo),
                const SizedBox(height: 14),
                _SecurityOverviewCard(security: info.securityInfo),
                const SizedBox(height: 14),
                _DrmAndBiometricCard(drm: info.drmInfo, biometric: info.biometricInfo),
                const SizedBox(height: 14),
                _SensorsCard(sensors: info.sensorsInfo),
                const SizedBox(height: 14),
                _BatteryOverviewCard(battery: info.batteryInfo),
                const SizedBox(height: 14),
                _NetworkOverviewCard(network: info.networkInfo),
                const SizedBox(height: 14),
                _SpecsGrid(cpu: info.cpuInfo, screen: info.screenInfo),
                const SizedBox(height: 14),
                _ResourceUsageCard(
                  title: 'STORAGE USAGE',
                  icon: Icons.storage_rounded,
                  accentColor: Colors.orangeAccent,
                  usedDisplay: info.storageInfo.formattedUsedStorage,
                  totalDisplay: info.storageInfo.formattedTotalStorage,
                  freeDisplay: info.storageInfo.formattedFreeStorage,
                  usagePercent: info.storageInfo.usagePercentage,
                ),
                const SizedBox(height: 14),
                _ResourceUsageCard(
                  title: 'SYSTEM RAM',
                  icon: Icons.memory_rounded,
                  accentColor: Colors.tealAccent,
                  usedDisplay: info.memoryInfo.formattedUsedRam,
                  totalDisplay: info.memoryInfo.formattedTotalRam,
                  freeDisplay: info.memoryInfo.formattedAvailableRam,
                  usagePercent: info.memoryInfo.usagePercentage,
                ),
                if (info.deviceInfo.buildInfo.isNotEmpty) ...[
                  const SizedBox(height: 14),
                  _BuildInfoCard(device: info.deviceInfo),
                ],
              ],
            ),
          );
        },
      ),
    );
  }
}

/// Top gradient banner presenting core device branding and emulator status.
class _HeaderBanner extends StatelessWidget {
  final DeviceInfo device;

  const _HeaderBanner({required this.device});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        gradient: const LinearGradient(
          colors: [Color(0xFF6366F1), Color(0xFFEC4899)],
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
        ),
        borderRadius: BorderRadius.circular(20),
        boxShadow: [
          BoxShadow(
            color: const Color(0xFF6366F1).withAlpha(80),
            blurRadius: 14,
            offset: const Offset(0, 6),
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Expanded(
                child: Text(
                  device.deviceName,
                  style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white),
                  overflow: TextOverflow.ellipsis,
                ),
              ),
              if (device.isEmulator)
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
                  decoration: BoxDecoration(
                    color: Colors.black45,
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: const Text(
                    'EMULATOR',
                    style: TextStyle(fontSize: 10, fontWeight: FontWeight.w700, color: Colors.amberAccent),
                  ),
                ),
            ],
          ),
          const SizedBox(height: 6),
          Text(
            '${device.manufacturer.toUpperCase()} • ${device.model}',
            style: const TextStyle(fontSize: 13, color: Colors.white70, fontWeight: FontWeight.w500),
          ),
          const SizedBox(height: 10),
          Row(
            children: [
              const Icon(Icons.info_outline, size: 14, color: Colors.white60),
              const SizedBox(width: 6),
              Text('Brand: ${device.brand}', style: const TextStyle(fontSize: 12, color: Colors.white60)),
            ],
          ),
        ],
      ),
    );
  }
}

/// Live hardware signals: Screen, Wi-Fi, In-call, Headphones, and SIM slots.
class _LiveHardwareCard extends StatelessWidget {
  final LiveHardwareInfo live;

  const _LiveHardwareCard({required this.live});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Row(
              children: [
                Icon(Icons.sensors_rounded, color: Colors.cyanAccent, size: 20),
                SizedBox(width: 8),
                Text(
                  'LIVE HARDWARE & PERIPHERALS',
                  style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                ),
              ],
            ),
            const SizedBox(height: 14),
            _LiveSignalRow(
              icon: Icons.phone_android_rounded,
              label: 'Screen Display State',
              value: live.isScreenOn ? 'SCREEN ON (INTERACTIVE)' : 'SCREEN OFF',
              isHighlighted: live.isScreenOn,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.wifi_rounded,
              label: 'Wi-Fi Radio Adapter',
              value: live.isWifiEnabled ? 'ENABLED' : 'DISABLED',
              isHighlighted: live.isWifiEnabled,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.call_rounded,
              label: 'Voice / VoIP Call Status',
              value: live.isCallActive ? 'CALL IN PROGRESS' : 'IDLE',
              isHighlighted: live.isCallActive,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.headphones_rounded,
              label: 'Headphones / Audio Route',
              value: live.isHeadphonesConnected ? 'CONNECTED' : 'DISCONNECTED',
              isHighlighted: live.isHeadphonesConnected,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.sim_card_rounded,
              label: 'Cellular SIM Slots',
              value: '${live.simSlotCount} ${live.simSlotCount > 1 ? "Slots (Dual SIM)" : "Slot (Single SIM)"}',
              isHighlighted: false,
            ),
          ],
        ),
      ),
    );
  }
}

class _LiveSignalRow extends StatelessWidget {
  final IconData icon;
  final String label;
  final String value;
  final bool isHighlighted;

  const _LiveSignalRow({
    required this.icon,
    required this.label,
    required this.value,
    required this.isHighlighted,
  });

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Icon(icon, size: 16, color: Colors.white54),
        const SizedBox(width: 8),
        Expanded(
          child: Text(
            label,
            style: const TextStyle(fontSize: 12, color: Colors.white70),
          ),
        ),
        Text(
          value,
          style: TextStyle(
            fontSize: 11,
            fontWeight: FontWeight.bold,
            color: isHighlighted ? Colors.cyanAccent : Colors.white60,
          ),
        ),
      ],
    );
  }
}

/// Thermal & Power Saver status card.
class _ThermalCard extends StatelessWidget {
  final ThermalInfo thermal;

  const _ThermalCard({required this.thermal});

  @override
  Widget build(BuildContext context) {
    final isWarn = thermal.isThrottling;
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Row(
                  children: [
                    Icon(Icons.thermostat_rounded, color: Colors.deepOrangeAccent, size: 20),
                    SizedBox(width: 8),
                    Text(
                      'THERMAL & POWER MODES',
                      style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                    ),
                  ],
                ),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
                  decoration: BoxDecoration(
                    color: isWarn ? Colors.red.withAlpha(50) : Colors.green.withAlpha(50),
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(
                      color: isWarn ? Colors.redAccent : Colors.greenAccent,
                      width: 1,
                    ),
                  ),
                  child: Text(
                    thermal.thermalStatus,
                    style: TextStyle(
                      fontSize: 10,
                      fontWeight: FontWeight.bold,
                      color: isWarn ? Colors.redAccent : Colors.greenAccent,
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 14),
            _LiveSignalRow(
              icon: Icons.speed_rounded,
              label: 'Thermal Throttling State',
              value: isWarn ? 'ACTIVE THROTTLING (${thermal.thermalStatus})' : 'NORMAL / NOMINAL',
              isHighlighted: isWarn,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.battery_saver_rounded,
              label: 'System Battery Saver Mode',
              value: thermal.isPowerSaveMode ? 'ENABLED (POWER SAVER)' : 'OFF',
              isHighlighted: thermal.isPowerSaveMode,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.bedtime_rounded,
              label: 'Device Doze / Idle State',
              value: thermal.isDeviceIdleMode ? 'DOZING (IDLE)' : 'ACTIVE',
              isHighlighted: thermal.isDeviceIdleMode,
            ),
          ],
        ),
      ),
    );
  }
}

/// Display HDR capabilities, Wide Color Gamut, and Refresh Rate panel.
class _DisplayCapabilitiesCard extends StatelessWidget {
  final DisplayCapabilitiesInfo caps;

  const _DisplayCapabilitiesCard({required this.caps});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Row(
                  children: [
                    Icon(Icons.hdr_on_rounded, color: Colors.purpleAccent, size: 20),
                    SizedBox(width: 8),
                    Text(
                      'DISPLAY HDR & COLOR MODES',
                      style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                    ),
                  ],
                ),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
                  decoration: BoxDecoration(
                    color: caps.isHdrSupported ? Colors.purple.withAlpha(50) : Colors.white10,
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(
                      color: caps.isHdrSupported ? Colors.purpleAccent : Colors.white24,
                      width: 1,
                    ),
                  ),
                  child: Text(
                    caps.isHdrSupported ? 'HDR READY' : 'SDR ONLY',
                    style: TextStyle(
                      fontSize: 10,
                      fontWeight: FontWeight.bold,
                      color: caps.isHdrSupported ? Colors.purpleAccent : Colors.white70,
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 14),
            _LiveSignalRow(
              icon: Icons.tv_rounded,
              label: 'HDR Standards Supported',
              value: caps.supportedHdrTypes.isNotEmpty
                  ? caps.supportedHdrTypes.join(', ')
                  : 'NONE',
              isHighlighted: caps.isHdrSupported,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.palette_rounded,
              label: 'Wide Color Gamut (DCI-P3)',
              value: caps.isWideColorGamut ? 'SUPPORTED (DCI-P3)' : 'sRGB STANDARD',
              isHighlighted: caps.isWideColorGamut,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.refresh_rounded,
              label: 'Panel Refresh Rates',
              value: caps.supportedRefreshRates.isNotEmpty
                  ? caps.supportedRefreshRates.map((r) => '${r.toInt()}Hz').join(' / ')
                  : 'Standard',
              isHighlighted: false,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.brightness_medium_rounded,
              label: 'Brightness & Auto Control',
              value: caps.screenBrightness >= 0
                  ? '${caps.screenBrightness}/255 ${caps.isAutoBrightnessEnabled ? "(Auto ON)" : "(Auto OFF)"}'
                  : (caps.isAutoBrightnessEnabled ? 'Auto ON' : 'Manual'),
              isHighlighted: caps.isAutoBrightnessEnabled,
            ),
          ],
        ),
      ),
    );
  }
}

/// Hardware peripherals (NFC, Bluetooth, Cameras, Torch, Vibrator).
class _PeripheralsCard extends StatelessWidget {
  final PeripheralsInfo peripherals;

  const _PeripheralsCard({required this.peripherals});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Row(
              children: [
                Icon(Icons.devices_other_rounded, color: Colors.lightBlueAccent, size: 20),
                SizedBox(width: 8),
                Text(
                  'PERIPHERALS & CONNECTIVITY',
                  style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                ),
              ],
            ),
            const SizedBox(height: 14),
            _LiveSignalRow(
              icon: Icons.nfc_rounded,
              label: 'NFC Chip Hardware',
              value: peripherals.isNfcAvailable
                  ? (peripherals.isNfcEnabled ? 'AVAILABLE & ENABLED' : 'AVAILABLE (OFF)')
                  : 'NOT AVAILABLE',
              isHighlighted: peripherals.isNfcEnabled,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.bluetooth_rounded,
              label: 'Bluetooth Radio',
              value: peripherals.isBluetoothAvailable
                  ? (peripherals.isBluetoothEnabled ? 'ENABLED' : 'DISABLED')
                  : 'NOT AVAILABLE',
              isHighlighted: peripherals.isBluetoothEnabled,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.flashlight_on_rounded,
              label: 'Camera Flashlight / Torch',
              value: peripherals.hasFlashlight ? 'AVAILABLE' : 'NONE',
              isHighlighted: peripherals.hasFlashlight,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.photo_camera_rounded,
              label: 'Camera Lenses Detected',
              value: 'Total ${peripherals.cameraCount} (${peripherals.backCameraCount} Rear, ${peripherals.frontCameraCount} Front)',
              isHighlighted: false,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.vibration_rounded,
              label: 'Haptic & Vibration Motor',
              value: peripherals.hasVibrator
                  ? (peripherals.hasAmplitudeControl ? 'ADVANCED HAPTICS (AMPLITUDE)' : 'STANDARD VIBRATION')
                  : 'NO VIBRATOR',
              isHighlighted: peripherals.hasAmplitudeControl,
            ),
          ],
        ),
      ),
    );
  }
}

/// Audio volume levels and microphone mute card.
class _AudioVolumeCard extends StatelessWidget {
  final AudioVolumeInfo audio;

  const _AudioVolumeCard({required this.audio});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Row(
                  children: [
                    Icon(Icons.volume_up_rounded, color: Colors.greenAccent, size: 20),
                    SizedBox(width: 8),
                    Text(
                      'AUDIO VOLUMES & CONTROLS',
                      style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                    ),
                  ],
                ),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
                  decoration: BoxDecoration(
                    color: audio.isMicrophoneMute ? Colors.red.withAlpha(50) : Colors.green.withAlpha(50),
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(
                      color: audio.isMicrophoneMute ? Colors.redAccent : Colors.greenAccent,
                      width: 1,
                    ),
                  ),
                  child: Text(
                    audio.isMicrophoneMute ? 'MIC MUTED' : 'MIC ACTIVE',
                    style: TextStyle(
                      fontSize: 10,
                      fontWeight: FontWeight.bold,
                      color: audio.isMicrophoneMute ? Colors.redAccent : Colors.greenAccent,
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 14),
            _LiveSignalRow(
              icon: Icons.music_note_rounded,
              label: 'Media Volume Level',
              value: '${audio.mediaVolume} / ${audio.maxMediaVolume} (${audio.mediaVolumePercentage.round()}%)',
              isHighlighted: audio.mediaVolume > 0,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.notifications_active_rounded,
              label: 'Ringtone & Alert Volume',
              value: '${audio.ringVolume} / ${audio.maxRingVolume}',
              isHighlighted: false,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.phone_in_talk_rounded,
              label: 'Voice Call Volume',
              value: '${audio.callVolume} / ${audio.maxCallVolume}',
              isHighlighted: false,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.alarm_rounded,
              label: 'Alarm Volume',
              value: '${audio.alarmVolume} / ${audio.maxAlarmVolume}',
              isHighlighted: false,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.bluetooth_audio_rounded,
              label: 'Bluetooth Audio (A2DP)',
              value: audio.isBluetoothA2dpOn ? 'STREAMING ACTIVE' : 'INACTIVE',
              isHighlighted: audio.isBluetoothA2dpOn,
            ),
          ],
        ),
      ),
    );
  }
}

/// Regional timezone, preferred languages, and accessibility theme card.
class _LocaleThemeCard extends StatelessWidget {
  final LocaleThemeInfo locale;

  const _LocaleThemeCard({required this.locale});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Row(
              children: [
                Icon(Icons.language_rounded, color: Colors.tealAccent, size: 20),
                SizedBox(width: 8),
                Text(
                  'REGIONAL, THEME & ACCESSIBILITY',
                  style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                ),
              ],
            ),
            const SizedBox(height: 14),
            _LiveSignalRow(
              icon: Icons.schedule_rounded,
              label: 'Device Timezone (UTC Offset)',
              value: '${locale.timezoneId} (${locale.formattedUtcOffset})',
              isHighlighted: false,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.translate_rounded,
              label: 'Preferred System Languages',
              value: locale.preferredLanguages.isNotEmpty
                  ? locale.preferredLanguages.join(', ')
                  : 'Default',
              isHighlighted: false,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.access_time_filled_rounded,
              label: 'Clock Format',
              value: locale.is24HourFormat ? '24-Hour Format' : '12-Hour Format (AM/PM)',
              isHighlighted: false,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.format_size_rounded,
              label: 'System Font Scale Multiplier',
              value: '${locale.fontScale.toStringAsFixed(2)}x Scale',
              isHighlighted: (locale.fontScale - 1.0).abs() > 0.05,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.record_voice_over_rounded,
              label: 'Screen Reader (TalkBack/VoiceOver)',
              value: locale.isScreenReaderActive ? 'ACTIVE' : 'OFF',
              isHighlighted: locale.isScreenReaderActive,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.dark_mode_rounded,
              label: 'System Display Theme',
              value: locale.isDarkMode ? 'DARK MODE' : 'LIGHT MODE',
              isHighlighted: locale.isDarkMode,
            ),
          ],
        ),
      ),
    );
  }
}

/// Security card showing Root, Jailbreak, Developer Mode, ADB, and USB Cable status.
class _SecurityOverviewCard extends StatelessWidget {
  final SecurityInfo security;

  const _SecurityOverviewCard({required this.security});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Row(
                  children: [
                    Icon(Icons.security_rounded, color: Colors.redAccent, size: 20),
                    SizedBox(width: 8),
                    Text(
                      'SECURITY & INTEGRITY',
                      style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                    ),
                  ],
                ),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
                  decoration: BoxDecoration(
                    color: security.isCompromised ? Colors.red.withAlpha(50) : Colors.green.withAlpha(50),
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(
                      color: security.isCompromised ? Colors.redAccent : Colors.greenAccent,
                      width: 1,
                    ),
                  ),
                  child: Text(
                    security.isCompromised ? 'COMPROMISED' : 'SECURE',
                    style: TextStyle(
                      fontSize: 10,
                      fontWeight: FontWeight.bold,
                      color: security.isCompromised ? Colors.redAccent : Colors.greenAccent,
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 14),
            _SecurityBadgeRow(
              label: 'Developer Options',
              value: security.isDeveloperMode ? 'ENABLED' : 'DISABLED',
              isWarning: security.isDeveloperMode,
              icon: Icons.developer_mode_rounded,
            ),
            const SizedBox(height: 8),
            _SecurityBadgeRow(
              label: 'USB Debugging (ADB)',
              value: security.isAdbEnabled ? 'ACTIVE' : 'DISABLED',
              isWarning: security.isAdbEnabled,
              icon: Icons.bug_report_rounded,
            ),
            const SizedBox(height: 8),
            _SecurityBadgeRow(
              label: 'Wireless Debugging (Wi-Fi ADB)',
              value: security.isWirelessDebuggingEnabled ? 'ACTIVE' : 'DISABLED',
              isWarning: security.isWirelessDebuggingEnabled,
              icon: Icons.wifi_tethering_rounded,
            ),
            const SizedBox(height: 8),
            _SecurityBadgeRow(
              label: 'USB Cable Connection',
              value: security.isUsbConnected ? 'CONNECTED' : 'DISCONNECTED',
              isWarning: security.isUsbConnected,
              icon: Icons.usb_rounded,
            ),
            const SizedBox(height: 8),
            _SecurityBadgeRow(
              label: 'Fake GPS / Mock Location',
              value: security.isMockLocation ? 'MOCK ACTIVE' : 'CLEAN',
              isWarning: security.isMockLocation,
              icon: Icons.location_off_rounded,
            ),
            const SizedBox(height: 8),
            _SecurityBadgeRow(
              label: 'Stay Awake on Charge',
              value: security.isStayAwake ? 'ACTIVE' : 'OFF',
              isWarning: security.isStayAwake,
              icon: Icons.visibility_rounded,
            ),
            const SizedBox(height: 8),
            _SecurityBadgeRow(
              label: 'USB App Verification',
              value: security.isVerificationOfAppsOverUsb ? 'ENFORCED' : 'OFF',
              isWarning: !security.isVerificationOfAppsOverUsb,
              icon: Icons.verified_user_rounded,
            ),
            const SizedBox(height: 8),
            _SecurityBadgeRow(
              label: 'Root / Jailbreak',
              value: (security.isRooted || security.isJailbroken) ? 'DETECTED' : 'NOT DETECTED',
              isWarning: security.isRooted || security.isJailbroken,
              icon: Icons.lock_open_rounded,
            ),
            const SizedBox(height: 8),
            _SecurityBadgeRow(
              label: 'Lock Screen / Passcode',
              value: security.isDeviceSecure ? 'CONFIGURED' : 'NOT SET',
              isWarning: !security.isDeviceSecure,
              icon: Icons.lock_outline_rounded,
            ),
            const SizedBox(height: 8),
            _SecurityBadgeRow(
              label: 'Native Debugger Process',
              value: security.isDebuggerAttached ? 'ATTACHED' : 'DETACHED',
              isWarning: security.isDebuggerAttached,
              icon: Icons.terminal_rounded,
            ),
          ],
        ),
      ),
    );
  }
}

class _SecurityBadgeRow extends StatelessWidget {
  final String label;
  final String value;
  final bool isWarning;
  final IconData icon;

  const _SecurityBadgeRow({
    required this.label,
    required this.value,
    required this.isWarning,
    required this.icon,
  });

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Icon(icon, size: 16, color: Colors.white54),
        const SizedBox(width: 8),
        Expanded(
          child: Text(
            label,
            style: const TextStyle(fontSize: 12, color: Colors.white70),
          ),
        ),
        Text(
          value,
          style: TextStyle(
            fontSize: 11,
            fontWeight: FontWeight.bold,
            color: isWarning ? Colors.amberAccent : Colors.tealAccent,
          ),
        ),
      ],
    );
  }
}

/// DRM security and biometric hardware inspection card.
class _DrmAndBiometricCard extends StatelessWidget {
  final DrmInfo drm;
  final BiometricInfo biometric;

  const _DrmAndBiometricCard({required this.drm, required this.biometric});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Row(
                  children: [
                    Icon(Icons.video_library_rounded, color: Colors.pinkAccent, size: 20),
                    SizedBox(width: 8),
                    Text(
                      'DRM & BIOMETRIC CAPABILITIES',
                      style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                    ),
                  ],
                ),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
                  decoration: BoxDecoration(
                    color: drm.isHdCapable ? Colors.pink.withAlpha(50) : Colors.white10,
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(
                      color: drm.isHdCapable ? Colors.pinkAccent : Colors.white24,
                      width: 1,
                    ),
                  ),
                  child: Text(
                    'WIDEVINE ${drm.widevineSecurityLevel}',
                    style: TextStyle(
                      fontSize: 10,
                      fontWeight: FontWeight.bold,
                      color: drm.isHdCapable ? Colors.pinkAccent : Colors.white70,
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 14),
            _LiveSignalRow(
              icon: Icons.hd_rounded,
              label: 'HD / 4K Streaming Certification',
              value: drm.isHdCapable ? 'SUPPORTED (L1)' : 'STANDARD DEF (${drm.widevineSecurityLevel})',
              isHighlighted: drm.isHdCapable,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.fingerprint_rounded,
              label: 'Biometric Hardware',
              value: biometric.hasBiometrics
                  ? 'AVAILABLE (${biometric.supportedTypes.join(", ").toUpperCase()})'
                  : 'NONE',
              isHighlighted: biometric.hasBiometrics,
            ),
            const SizedBox(height: 8),
            _LiveSignalRow(
              icon: Icons.lock_person_rounded,
              label: 'Biometrics Enrolled by User',
              value: biometric.isEnrolled ? 'ENROLLED' : 'NOT ENROLLED',
              isHighlighted: biometric.isEnrolled,
            ),
          ],
        ),
      ),
    );
  }
}

/// Hardware sensors present on the device.
class _SensorsCard extends StatelessWidget {
  final SensorsInfo sensors;

  const _SensorsCard({required this.sensors});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Row(
                  children: [
                    Icon(Icons.explore_rounded, color: Colors.amberAccent, size: 20),
                    SizedBox(width: 8),
                    Text(
                      'HARDWARE SENSORS',
                      style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                    ),
                  ],
                ),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
                  decoration: BoxDecoration(
                    color: Colors.amber.withAlpha(40),
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(color: Colors.amberAccent, width: 1),
                  ),
                  child: Text(
                    '${sensors.totalSensorCount} SENSORS FOUND',
                    style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold, color: Colors.amberAccent),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 14),
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                _SensorChip(label: 'Accelerometer', isPresent: sensors.hasAccelerometer),
                _SensorChip(label: 'Gyroscope', isPresent: sensors.hasGyroscope),
                _SensorChip(label: 'Magnetometer (Compass)', isPresent: sensors.hasMagnetometer),
                _SensorChip(label: 'Barometer', isPresent: sensors.hasBarometer),
                _SensorChip(label: 'Proximity', isPresent: sensors.hasProximity),
                _SensorChip(label: 'Step Counter', isPresent: sensors.hasStepCounter),
                _SensorChip(label: 'Light Sensor', isPresent: sensors.hasLight),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class _SensorChip extends StatelessWidget {
  final String label;
  final bool isPresent;

  const _SensorChip({required this.label, required this.isPresent});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
      decoration: BoxDecoration(
        color: isPresent ? const Color(0xFF1E293B) : Colors.white.withAlpha(5),
        borderRadius: BorderRadius.circular(20),
        border: Border.all(
          color: isPresent ? Colors.amberAccent.withAlpha(120) : Colors.white10,
        ),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(
            isPresent ? Icons.check_circle_rounded : Icons.cancel_outlined,
            size: 13,
            color: isPresent ? Colors.amberAccent : Colors.white30,
          ),
          const SizedBox(width: 5),
          Text(
            label,
            style: TextStyle(
              fontSize: 11,
              fontWeight: isPresent ? FontWeight.w600 : FontWeight.normal,
              color: isPresent ? Colors.white : Colors.white38,
            ),
          ),
        ],
      ),
    );
  }
}

/// Battery Card showing level, power source, charging state, temperature, and power-saver mode.
class _BatteryOverviewCard extends StatelessWidget {
  final BatteryInfo battery;

  const _BatteryOverviewCard({required this.battery});

  @override
  Widget build(BuildContext context) {
    final level = battery.batteryLevel;
    final levelPercent = (level >= 0 ? level / 100.0 : 0.0).clamp(0.0, 1.0);

    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Row(
                  children: [
                    Icon(
                      battery.isCharging ? Icons.battery_charging_full_rounded : Icons.battery_std_rounded,
                      color: Colors.greenAccent,
                      size: 20,
                    ),
                    const SizedBox(width: 8),
                    const Text(
                      'BATTERY & POWER',
                      style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                    ),
                  ],
                ),
                if (battery.isLowPowerMode)
                  Container(
                    padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
                    decoration: BoxDecoration(
                      color: Colors.amber.withAlpha(40),
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: const Text(
                      'BATTERY SAVER ON',
                      style: TextStyle(fontSize: 9, fontWeight: FontWeight.bold, color: Colors.amberAccent),
                    ),
                  ),
              ],
            ),
            const SizedBox(height: 14),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  level >= 0 ? '$level% Charge' : 'Unavailable',
                  style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                ),
                Text(
                  '${battery.batteryStatus.toUpperCase()} • ${battery.powerSource.toUpperCase()}',
                  style: const TextStyle(fontSize: 12, color: Colors.white70),
                ),
              ],
            ),
            const SizedBox(height: 10),
            ClipRRect(
              borderRadius: BorderRadius.circular(8),
              child: LinearProgressIndicator(
                value: levelPercent,
                minHeight: 10,
                backgroundColor: const Color(0xFF334155),
                valueColor: AlwaysStoppedAnimation<Color>(
                  level > 20 ? Colors.greenAccent : Colors.redAccent,
                ),
              ),
            ),
            const SizedBox(height: 8),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  'Health: ${battery.batteryHealth.toUpperCase()}',
                  style: const TextStyle(fontSize: 11, color: Colors.white60),
                ),
                if (battery.batteryTemperature > 0)
                  Text(
                    'Temp: ${battery.batteryTemperature.toStringAsFixed(1)}°C',
                    style: const TextStyle(fontSize: 11, color: Colors.white60),
                  ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

/// Network Card displaying internet state, connection type, and active VPN warning.
class _NetworkOverviewCard extends StatelessWidget {
  final NetworkInfo network;

  const _NetworkOverviewCard({required this.network});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Row(
              children: [
                Icon(
                  network.isConnected ? Icons.wifi_rounded : Icons.wifi_off_rounded,
                  color: network.isConnected ? const Color(0xFF38BDF8) : Colors.redAccent,
                  size: 24,
                ),
                const SizedBox(width: 12),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      network.isConnected ? 'ONLINE (${network.connectionType.toUpperCase()})' : 'OFFLINE',
                      style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
                    ),
                    const SizedBox(height: 2),
                    Text(
                      network.isVpnActive ? 'VPN Active (Tunnel detected)' : 'No VPN Active',
                      style: TextStyle(
                        fontSize: 11,
                        color: network.isVpnActive ? Colors.amberAccent : Colors.white60,
                        fontWeight: network.isVpnActive ? FontWeight.bold : FontWeight.normal,
                      ),
                    ),
                  ],
                ),
              ],
            ),
            if (network.isVpnActive)
              const Icon(Icons.vpn_key_rounded, color: Colors.amberAccent, size: 20),
          ],
        ),
      ),
    );
  }
}

/// Dual-column grid displaying CPU and Display specifications.
class _SpecsGrid extends StatelessWidget {
  final CpuInfo cpu;
  final ScreenInfo screen;

  const _SpecsGrid({required this.cpu, required this.screen});

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
          child: _StatCard(
            title: 'CPU',
            icon: Icons.developer_board_rounded,
            iconColor: const Color(0xFF60A5FA),
            value: '${cpu.cores} Cores',
            subtitle: cpu.architecture,
          ),
        ),
        const SizedBox(width: 14),
        Expanded(
          child: _StatCard(
            title: 'DISPLAY',
            icon: Icons.screenshot_monitor_rounded,
            iconColor: const Color(0xFF34D399),
            value: '${screen.width} × ${screen.height}',
            subtitle: '${screen.refreshRate.toInt()} Hz • @${screen.scale.toStringAsFixed(1)}x',
          ),
        ),
      ],
    );
  }
}

/// Reusable stat card for quick key-value metrics.
class _StatCard extends StatelessWidget {
  final String title;
  final String value;
  final String subtitle;
  final IconData icon;
  final Color iconColor;

  const _StatCard({
    required this.title,
    required this.value,
    required this.subtitle,
    required this.icon,
    required this.iconColor,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  title,
                  style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w700, color: Colors.white54, letterSpacing: 1.1),
                ),
                Icon(icon, color: iconColor, size: 24),
              ],
            ),
            const SizedBox(height: 12),
            Text(value, style: const TextStyle(fontSize: 17, fontWeight: FontWeight.bold, color: Colors.white)),
            const SizedBox(height: 4),
            Text(subtitle, style: const TextStyle(fontSize: 12, color: Colors.white60)),
          ],
        ),
      ),
    );
  }
}

/// Generic, highly reusable resource card handling both Storage and RAM metrics.
class _ResourceUsageCard extends StatelessWidget {
  final String title;
  final IconData icon;
  final Color accentColor;
  final String usedDisplay;
  final String totalDisplay;
  final String freeDisplay;
  final double usagePercent;

  const _ResourceUsageCard({
    required this.title,
    required this.icon,
    required this.accentColor,
    required this.usedDisplay,
    required this.totalDisplay,
    required this.freeDisplay,
    required this.usagePercent,
  });

  @override
  Widget build(BuildContext context) {
    final normalizedUsage = (usagePercent / 100.0).clamp(0.0, 1.0);

    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Icon(icon, color: accentColor, size: 20),
                const SizedBox(width: 8),
                Text(
                  title,
                  style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                ),
              ],
            ),
            const SizedBox(height: 14),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  '${usagePercent.toStringAsFixed(1)}% Used',
                  style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
                ),
                Text(
                  '$usedDisplay / $totalDisplay',
                  style: const TextStyle(fontSize: 12, color: Colors.white70),
                ),
              ],
            ),
            const SizedBox(height: 10),
            ClipRRect(
              borderRadius: BorderRadius.circular(8),
              child: LinearProgressIndicator(
                value: normalizedUsage,
                minHeight: 10,
                backgroundColor: const Color(0xFF334155),
                valueColor: AlwaysStoppedAnimation<Color>(accentColor),
              ),
            ),
            const SizedBox(height: 8),
            Text(
              'Available: $freeDisplay',
              style: const TextStyle(fontSize: 11, color: Colors.white60),
            ),
          ],
        ),
      ),
    );
  }
}

/// Card detailing full "About Phone" properties and platform-specific build specifications.
class _BuildInfoCard extends StatelessWidget {
  final DeviceInfo device;

  const _BuildInfoCard({required this.device});

  @override
  Widget build(BuildContext context) {
    final buildInfo = device.buildInfo;
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Row(
                  children: [
                    Icon(Icons.phone_android_rounded, color: Colors.purpleAccent, size: 20),
                    SizedBox(width: 8),
                    Text(
                      'ABOUT PHONE & SYSTEM SPECS',
                      style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, letterSpacing: 1.0),
                    ),
                  ],
                ),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
                  decoration: BoxDecoration(
                    color: Colors.purple.withAlpha(50),
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(color: Colors.purpleAccent, width: 1),
                  ),
                  child: Row(
                    children: [
                      const Icon(Icons.timer_outlined, size: 11, color: Colors.purpleAccent),
                      const SizedBox(width: 4),
                      Text(
                        'UPTIME: ${device.formattedUptime}',
                        style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold, color: Colors.purpleAccent),
                      ),
                    ],
                  ),
                ),
              ],
            ),
            const SizedBox(height: 14),
            _BuildInfoRow(label: 'OS Release / Version', value: device.osVersion, icon: Icons.terminal_rounded),
            _BuildInfoRow(label: 'Security Patch Level', value: device.securityPatch, icon: Icons.verified_user_outlined),
            _BuildInfoRow(label: 'Kernel Version', value: device.kernelVersion, icon: Icons.memory_rounded),
            _BuildInfoRow(label: 'Supported Architectures', value: device.supportedAbis, icon: Icons.developer_board_rounded),
            _BuildInfoRow(label: 'Baseband / Radio', value: device.radioVersion, icon: Icons.cell_tower_rounded),
            _BuildInfoRow(label: 'Bootloader', value: device.bootloader, icon: Icons.power_settings_new_rounded),
            _BuildInfoRow(label: 'Hardware & Board', value: '${device.buildInfo['hardware'] ?? device.manufacturer} (${device.board})', icon: Icons.precision_manufacturing_rounded),
            _BuildInfoRow(label: 'Display / Build ID', value: '${device.buildInfo['display'] ?? device.buildInfo['id'] ?? 'N/A'}', icon: Icons.fingerprint_rounded),
            if (device.buildInfo.containsKey('thermalState'))
              _BuildInfoRow(label: 'Thermal State', value: device.buildInfo['thermalState'].toString().toUpperCase(), icon: Icons.thermostat_rounded),
            const SizedBox(height: 8),
            const Divider(color: Colors.white12),
            const SizedBox(height: 8),
            const Text(
              'ALL RAW BUILD PROPERTIES',
              style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: Colors.white38, letterSpacing: 0.8),
            ),
            const SizedBox(height: 8),
            ...buildInfo.entries.map(
              (entry) => Padding(
                padding: const EdgeInsets.symmetric(vertical: 3),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Expanded(
                      flex: 2,
                      child: Text(
                        entry.key,
                        style: const TextStyle(fontWeight: FontWeight.w600, color: Colors.white54, fontSize: 11),
                      ),
                    ),
                    Expanded(
                      flex: 3,
                      child: Text(
                        entry.value?.toString() ?? 'N/A',
                        style: const TextStyle(color: Colors.white, fontSize: 11),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _BuildInfoRow extends StatelessWidget {
  final String label;
  final String value;
  final IconData icon;

  const _BuildInfoRow({
    required this.label,
    required this.value,
    required this.icon,
  });

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Icon(icon, size: 15, color: Colors.white54),
          const SizedBox(width: 8),
          Expanded(
            flex: 2,
            child: Text(
              label,
              style: const TextStyle(fontWeight: FontWeight.w500, color: Colors.white70, fontSize: 12),
            ),
          ),
          Expanded(
            flex: 3,
            child: Text(
              value,
              textAlign: TextAlign.end,
              style: const TextStyle(fontWeight: FontWeight.w600, color: Colors.white, fontSize: 12),
            ),
          ),
        ],
      ),
    );
  }
}

/// Error view with retry action.
class _ErrorView extends StatelessWidget {
  final String errorMessage;
  final VoidCallback onRetry;

  const _ErrorView({required this.errorMessage, required this.onRetry});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.error_outline_rounded, size: 56, color: Colors.redAccent),
            const SizedBox(height: 16),
            Text(
              'Failed to load metrics:\n$errorMessage',
              textAlign: TextAlign.center,
              style: const TextStyle(color: Colors.redAccent, fontSize: 14),
            ),
            const SizedBox(height: 20),
            ElevatedButton.icon(
              onPressed: onRetry,
              icon: const Icon(Icons.refresh_rounded),
              label: const Text('Try Again'),
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
160
points
40
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Advanced device, hardware, security, anti-fraud, thermal, DRM, biometrics, sensors, and live system information for Flutter on Android & iOS.

Repository (GitHub)
View/report issues

Topics

#device-info #security #anti-fraud #hardware #system-info

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on advanced_device_info

Packages that implement advanced_device_info