nexora_sdk 1.0.0
nexora_sdk: ^1.0.0 copied to clipboard
A high-performance Flutter SDK providing native-level hardware access (Camera, Bluetooth, GPS) with responsive UI system and zero-lag architecture.
example/lib/main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:nexora_sdk/nexora_sdk.dart';
void main() {
HardwarePlugin.initialise();
runApp(const HardwareExampleApp());
}
class HardwareExampleApp extends StatelessWidget {
const HardwareExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hardware SDK Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6C63FF),
brightness: Brightness.dark,
),
useMaterial3: true,
fontFamily: 'monospace',
),
home: const DashboardPage(),
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
// DASHBOARD
// ─────────────────────────────────────────────────────────────────────────────
class DashboardPage extends StatefulWidget {
const DashboardPage({super.key});
@override
State<DashboardPage> createState() => _DashboardPageState();
}
class _DashboardPageState extends State<DashboardPage> {
// ── BLE State ─────────────────────────────────────────
bool _bleScanning = false;
final List<BluetoothDevice> _devices = [];
StreamSubscription<BluetoothDevice>? _bleSub;
// ── GPS State ─────────────────────────────────────────
bool _gpsRunning = false;
GpsLocation? _lastLocation;
StreamSubscription<GpsLocation>? _gpsSub;
// ── Sensor State ──────────────────────────────────────
bool _sensorsRunning = false;
SensorSample? _lastSample;
StreamSubscription<SensorSample>? _sensorSub;
// ── Camera State ──────────────────────────────────────
bool _cameraRunning = false;
int _frameCount = 0;
int _frameBytes = 0;
StreamSubscription<CameraFrame>? _cameraSub;
// ── WiFi ──────────────────────────────────────────────
WifiInfo? _wifi;
// ── Error ─────────────────────────────────────────────
String? _errorMsg;
@override
void dispose() {
_bleSub?.cancel();
_gpsSub?.cancel();
_sensorSub?.cancel();
_cameraSub?.cancel();
super.dispose();
}
void _showError(Object e) {
setState(() => _errorMsg = e.toString());
}
// ── Actions ───────────────────────────────────────────
Future<void> _toggleBle() async {
setState(() => _errorMsg = null);
try {
if (_bleScanning) {
await HardwarePlugin.bluetooth.stopScan();
await _bleSub?.cancel();
setState(() { _bleScanning = false; });
} else {
_devices.clear();
await HardwarePlugin.bluetooth.startScan(timeout: const Duration(seconds: 15));
_bleSub = HardwarePlugin.bluetooth.deviceStream.listen((d) {
if (!_devices.any((x) => x.id == d.id)) {
setState(() => _devices.add(d));
}
});
setState(() => _bleScanning = true);
}
} catch (e) { _showError(e); }
}
Future<void> _toggleGps() async {
setState(() => _errorMsg = null);
try {
if (_gpsRunning) {
await HardwarePlugin.gps.stop();
await _gpsSub?.cancel();
setState(() => _gpsRunning = false);
} else {
await HardwarePlugin.gps.start(config: const GpsConfig(
accuracy: GpsAccuracy.high,
intervalMs: 1000,
));
_gpsSub = HardwarePlugin.gps.locationStream.listen((loc) {
setState(() => _lastLocation = loc);
});
setState(() => _gpsRunning = true);
}
} catch (e) { _showError(e); }
}
Future<void> _toggleSensors() async {
setState(() => _errorMsg = null);
try {
if (_sensorsRunning) {
await HardwarePlugin.sensors.stop();
await _sensorSub?.cancel();
setState(() => _sensorsRunning = false);
} else {
await HardwarePlugin.sensors.start(config: const SensorConfig(
type: SensorType.accelerometer,
samplingRateHz: 60,
));
_sensorSub = HardwarePlugin.sensors.sampleStream.listen((s) {
setState(() => _lastSample = s);
});
setState(() => _sensorsRunning = true);
}
} catch (e) { _showError(e); }
}
Future<void> _toggleCamera() async {
setState(() => _errorMsg = null);
try {
if (_cameraRunning) {
await HardwarePlugin.camera.stop();
await _cameraSub?.cancel();
setState(() { _cameraRunning = false; _frameCount = 0; });
} else {
await HardwarePlugin.camera.start();
_cameraSub = HardwarePlugin.camera.frameStream.listen((f) {
setState(() { _frameCount++; _frameBytes = f.sizeBytes; });
});
setState(() => _cameraRunning = true);
}
} catch (e) { _showError(e); }
}
Future<void> _loadWifi() async {
setState(() => _errorMsg = null);
try {
final info = await HardwarePlugin.wifi.getInfo();
setState(() => _wifi = info);
} catch (e) { _showError(e); }
}
Future<void> _requestPermissions() async {
setState(() => _errorMsg = null);
try {
final ok = await HardwarePlugin.requestPermissions();
setState(() => _errorMsg = ok ? '✅ Permissions granted' : '⚠️ Some permissions denied');
} catch (e) { _showError(e); }
}
// ── Build ─────────────────────────────────────────────
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Scaffold(
backgroundColor: const Color(0xFF0F0F1A),
appBar: AppBar(
backgroundColor: const Color(0xFF1A1A2E),
title: const Text('⚡ Hardware SDK', style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold,
)),
actions: [
IconButton(
icon: const Icon(Icons.security, color: Color(0xFF6C63FF)),
tooltip: 'Request Permissions',
onPressed: _requestPermissions,
),
],
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
if (_errorMsg != null) _ErrorBanner(_errorMsg!),
// ── Bluetooth ─────────────────────────────────
_SectionCard(
icon: Icons.bluetooth,
iconColor: const Color(0xFF6C63FF),
title: 'Bluetooth LE',
active: _bleScanning,
onToggle: _toggleBle,
statusText: _bleScanning
? 'Scanning… ${_devices.length} device(s)'
: '${_devices.length} device(s) found',
child: _devices.isEmpty
? const _EmptyHint('Start scan to discover BLE devices')
: Column(
children: _devices.take(5).map((d) => _DeviceTile(
name: d.name,
subtitle: '${d.id} • ${d.rssi} dBm',
)).toList(),
),
),
// ── GPS ───────────────────────────────────────
_SectionCard(
icon: Icons.gps_fixed,
iconColor: const Color(0xFF43B89C),
title: 'GPS Location',
active: _gpsRunning,
onToggle: _toggleGps,
statusText: _gpsRunning ? 'Tracking…' : 'Idle',
child: _lastLocation == null
? const _EmptyHint('Start GPS to see live coordinates')
: _DataGrid([
('Lat', _lastLocation!.latitude.toStringAsFixed(6)),
('Lng', _lastLocation!.longitude.toStringAsFixed(6)),
('Alt', '${_lastLocation!.altitude.toStringAsFixed(1)} m'),
('Acc', '±${_lastLocation!.accuracy.toStringAsFixed(1)} m'),
('Spd', '${(_lastLocation!.speed * 3.6).toStringAsFixed(1)} km/h'),
]),
),
// ── Sensors ───────────────────────────────────
_SectionCard(
icon: Icons.sensors,
iconColor: const Color(0xFFFF6B6B),
title: 'Accelerometer',
active: _sensorsRunning,
onToggle: _toggleSensors,
statusText: _sensorsRunning ? '60 Hz' : 'Idle',
child: _lastSample == null
? const _EmptyHint('Start sensors to see live X/Y/Z values')
: _DataGrid([
('X', _lastSample!.x.toStringAsFixed(3)),
('Y', _lastSample!.y.toStringAsFixed(3)),
('Z', _lastSample!.z.toStringAsFixed(3)),
]),
),
// ── Camera ────────────────────────────────────
_SectionCard(
icon: Icons.videocam,
iconColor: const Color(0xFFFFD93D),
title: 'Camera Frame Stream',
active: _cameraRunning,
onToggle: _toggleCamera,
statusText: _cameraRunning
? '$_frameCount frames • $_frameBytes B/frame'
: 'Idle',
child: _cameraRunning
? _DataGrid([
('Frames', '$_frameCount'),
('Payload', '${(_frameBytes / 1024).toStringAsFixed(1)} KB'),
])
: const _EmptyHint('Start camera to receive binary frames'),
),
// ── WiFi ──────────────────────────────────────
_SectionCard(
icon: Icons.wifi,
iconColor: const Color(0xFF4ECDC4),
title: 'WiFi Info',
active: false,
onToggle: _loadWifi,
toggleLabel: 'REFRESH',
statusText: _wifi?.ssid ?? 'Tap REFRESH',
child: _wifi == null
? const _EmptyHint('Tap REFRESH to load network info')
: _DataGrid([
('SSID', _wifi!.ssid),
('BSSID', _wifi!.bssid),
('Signal', '${_wifi!.signalStrength} dBm'),
('IP', _wifi!.ipAddress),
]),
),
const SizedBox(height: 24),
],
),
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
// REUSABLE WIDGETS
// ─────────────────────────────────────────────────────────────────────────────
class _SectionCard extends StatelessWidget {
final IconData icon;
final Color iconColor;
final String title;
final bool active;
final VoidCallback onToggle;
final String statusText;
final Widget child;
final String toggleLabel;
const _SectionCard({
required this.icon,
required this.iconColor,
required this.title,
required this.active,
required this.onToggle,
required this.statusText,
required this.child,
this.toggleLabel = '',
});
@override
Widget build(BuildContext context) {
final label = toggleLabel.isNotEmpty
? toggleLabel
: active ? 'STOP' : 'START';
return Container(
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: const Color(0xFF1A1A2E),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: active ? iconColor.withAlpha(120) : Colors.white12,
width: 1.5,
),
),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 12, 8),
child: Row(children: [
Icon(icon, color: iconColor, size: 22),
const SizedBox(width: 10),
Expanded(child: Text(title, style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
))),
ElevatedButton(
onPressed: onToggle,
style: ElevatedButton.styleFrom(
backgroundColor: active ? Colors.red.shade800 : iconColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
textStyle: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: Text(label),
),
]),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 4),
child: Text(statusText, style: TextStyle(
color: active ? iconColor : Colors.white38,
fontSize: 12,
)),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 4, 16, 16),
child: child,
),
]),
);
}
}
class _DataGrid extends StatelessWidget {
final List<(String, String)> rows;
const _DataGrid(this.rows);
@override
Widget build(BuildContext context) {
return Wrap(
spacing: 12,
runSpacing: 8,
children: rows.map((r) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(r.$1, style: const TextStyle(color: Colors.white38, fontSize: 10)),
Text(r.$2, style: const TextStyle(
color: Colors.cyanAccent,
fontSize: 13,
fontFamily: 'monospace',
)),
],
)).toList(),
);
}
}
class _DeviceTile extends StatelessWidget {
final String name;
final String subtitle;
const _DeviceTile({required this.name, required this.subtitle});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(children: [
const Icon(Icons.bluetooth_connected, size: 14, color: Color(0xFF6C63FF)),
const SizedBox(width: 8),
Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(name, style: const TextStyle(color: Colors.white, fontSize: 13)),
Text(subtitle, style: const TextStyle(color: Colors.white38, fontSize: 11, fontFamily: 'monospace')),
])),
]),
);
}
}
class _EmptyHint extends StatelessWidget {
final String text;
const _EmptyHint(this.text);
@override
Widget build(BuildContext context) {
return Text(text, style: const TextStyle(color: Colors.white24, fontSize: 12));
}
}
class _ErrorBanner extends StatelessWidget {
final String message;
const _ErrorBanner(this.message);
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.red.shade900.withAlpha(180),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.red.shade700),
),
child: Text(message, style: const TextStyle(color: Colors.white, fontSize: 12)),
);
}
}