advanced_device_info 0.0.2
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.
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'),
),
],
),
),
);
}
}