all_device_sensors 1.0.1
all_device_sensors: ^1.0.1 copied to clipboard
A Flutter plugin to access all device sensors — accelerometer, gyroscope, magnetometer, linear acceleration, gravity, barometer, proximity, light and step counter. By Bharathwaj.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:all_device_sensors/all_device_sensors.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Device Sensors',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF1A73E8)),
useMaterial3: true,
),
home: const SensorHomePage(),
);
}
}
class SensorHomePage extends StatefulWidget {
const SensorHomePage({super.key});
@override
State<SensorHomePage> createState() => _SensorHomePageState();
}
class _SensorHomePageState extends State<SensorHomePage>
with SingleTickerProviderStateMixin {
final _plugin = AllDeviceSensors();
late TabController _tabController;
// 3-axis
SensorData? _accel, _gyro, _mag, _linear, _gravity;
// single-value
SingleSensorData? _baro, _proximity, _light, _steps;
List<Map<String, dynamic>> _allSensors = [];
int _sensorCount = 0;
final List<StreamSubscription> _subs = [];
@override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this);
_loadSensors();
_startStreams();
}
Future<void> _loadSensors() async {
final sensors = await _plugin.getSensors();
setState(() {
_allSensors = sensors.map((s) => {'name': s.name, 'vendor': s.vendor, 'type': s.type}).toList();
_sensorCount = sensors.length;
});
}
void _startStreams() {
_subs.addAll([
_plugin.accelerometerStream(interval: SensorInterval.ui).listen((d) => setState(() => _accel = d)),
_plugin.gyroscopeStream(interval: SensorInterval.ui).listen((d) => setState(() => _gyro = d)),
_plugin.magnetometerStream(interval: SensorInterval.ui).listen((d) => setState(() => _mag = d)),
_plugin.linearAccelerationStream(interval: SensorInterval.ui).listen((d) => setState(() => _linear = d)),
_plugin.gravityStream(interval: SensorInterval.ui).listen((d) => setState(() => _gravity = d)),
_plugin.barometerStream().listen((d) => setState(() => _baro = d)),
_plugin.proximityStream().listen((d) => setState(() => _proximity = d)),
_plugin.lightStream().listen((d) => setState(() => _light = d)),
_plugin.stepCounterStream().listen((d) => setState(() => _steps = d)),
]);
}
@override
void dispose() {
_tabController.dispose();
for (final s in _subs) { s.cancel(); }
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F7FA),
appBar: AppBar(
backgroundColor: const Color(0xFF1A73E8),
foregroundColor: Colors.white,
elevation: 0,
title: const Text('Device Sensors', style: TextStyle(fontWeight: FontWeight.w600)),
centerTitle: true,
bottom: TabBar(
controller: _tabController,
indicatorColor: Colors.white,
labelColor: Colors.white,
unselectedLabelColor: Colors.white60,
tabs: const [
Tab(icon: Icon(Icons.speed), text: 'Motion'),
Tab(icon: Icon(Icons.sensors), text: 'Environment'),
Tab(icon: Icon(Icons.directions_walk), text: 'Activity'),
Tab(icon: Icon(Icons.list_alt), text: 'All'),
],
),
),
body: Column(
children: [
_buildBanner(),
Expanded(
child: TabBarView(
controller: _tabController,
children: [
_buildMotionTab(),
_buildEnvironmentTab(),
_buildActivityTab(),
_buildAllSensorsTab(),
],
),
),
],
),
);
}
// ── Banner ──────────────────────────────────────────────────────────────────
Widget _buildBanner() {
return Container(
color: const Color(0xFF1A73E8),
padding: const EdgeInsets.only(bottom: 10),
child: Center(
child: Text(
'$_sensorCount sensors detected on this device',
style: const TextStyle(color: Colors.white70, fontSize: 13),
),
),
);
}
// ── Tab 1: Motion (Accel, Gyro, Mag, Linear, Gravity) ──────────────────────
Widget _buildMotionTab() {
return ListView(
padding: const EdgeInsets.all(16),
children: [
_xyzCard('Accelerometer', Icons.speed, const Color(0xFF1A73E8),
'Acceleration incl. gravity (m/s²)', _accel),
_xyzCard('Gyroscope', Icons.rotate_right, const Color(0xFF34A853),
'Rotation rate (rad/s)', _gyro),
_xyzCard('Magnetometer', Icons.explore, const Color(0xFFEA4335),
'Magnetic field (μT)', _mag),
_xyzCard('Linear Acceleration', Icons.trending_up, const Color(0xFFFA7B17),
'Acceleration excl. gravity (m/s²)', _linear),
_xyzCard('Gravity', Icons.arrow_downward, const Color(0xFF9334E6),
'Gravity force (m/s²)', _gravity),
],
);
}
// ── Tab 2: Environment (Baro, Proximity, Light) ─────────────────────────────
Widget _buildEnvironmentTab() {
return ListView(
padding: const EdgeInsets.all(16),
children: [
_singleCard('Barometer', Icons.compress, const Color(0xFF1A73E8),
'Atmospheric pressure (hPa)', _baro, 'hPa'),
_singleCard('Proximity', Icons.sensors, const Color(0xFF34A853),
'0 = near · 1 = far', _proximity,
_proximity != null ? (_proximity!.value == 0 ? 'Near' : 'Far') : null),
_singleCard('Light', Icons.wb_sunny, const Color(0xFFFA7B17),
'Ambient light level (lux)', _light, 'lux'),
],
);
}
// ── Tab 3: Activity (Step Counter) ─────────────────────────────────────────
Widget _buildActivityTab() {
return ListView(
padding: const EdgeInsets.all(16),
children: [
_singleCard('Step Counter', Icons.directions_walk, const Color(0xFF9334E6),
'Steps since last reboot', _steps, 'steps'),
],
);
}
// ── Tab 4: All Sensors list ─────────────────────────────────────────────────
Widget _buildAllSensorsTab() {
if (_allSensors.isEmpty) {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(color: Color(0xFF1A73E8)),
SizedBox(height: 16),
Text('Loading sensors...', style: TextStyle(color: Colors.grey)),
],
),
);
}
return ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
itemCount: _allSensors.length,
separatorBuilder: (_, __) => const SizedBox(height: 8),
itemBuilder: (context, index) {
final s = _allSensors[index];
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.04), blurRadius: 6, offset: const Offset(0, 2))],
),
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
leading: Container(
width: 42, height: 42,
decoration: BoxDecoration(color: const Color(0xFF1A73E8).withOpacity(0.1), shape: BoxShape.circle),
child: Center(
child: Text('${index + 1}',
style: const TextStyle(color: Color(0xFF1A73E8), fontWeight: FontWeight.bold, fontSize: 14)),
),
),
title: Text(s['name'] ?? 'Unknown',
style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 14)),
subtitle: Text(s['vendor'] ?? '', style: const TextStyle(fontSize: 12, color: Colors.grey)),
trailing: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(color: const Color(0xFFF1F3F4), borderRadius: BorderRadius.circular(20)),
child: Text('Type ${s['type']}', style: const TextStyle(fontSize: 11, color: Colors.black54)),
),
),
);
},
);
}
// ── Reusable widgets ────────────────────────────────────────────────────────
Widget _xyzCard(String title, IconData icon, Color color, String subtitle, SensorData? data) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 2))],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
Icon(icon, color: color, size: 20),
const SizedBox(width: 8),
Text(title, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)),
const Spacer(),
_statusDot(data != null),
]),
const SizedBox(height: 4),
Text(subtitle, style: const TextStyle(fontSize: 12, color: Colors.grey)),
const SizedBox(height: 12),
Row(children: [
_axisChip('X', data?.x, color),
const SizedBox(width: 8),
_axisChip('Y', data?.y, color),
const SizedBox(width: 8),
_axisChip('Z', data?.z, color),
]),
],
),
);
}
Widget _singleCard(String title, IconData icon, Color color, String subtitle,
SingleSensorData? data, String? unit) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 2))],
),
child: Row(
children: [
Container(
width: 48, height: 48,
decoration: BoxDecoration(color: color.withOpacity(0.1), shape: BoxShape.circle),
child: Icon(icon, color: color, size: 24),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)),
Text(subtitle, style: const TextStyle(fontSize: 12, color: Colors.grey)),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
data != null ? data.value.toStringAsFixed(1) : '--',
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: color),
),
if (unit != null)
Text(unit, style: const TextStyle(fontSize: 11, color: Colors.grey)),
],
),
],
),
);
}
Widget _axisChip(String label, double? value, Color color) {
return Expanded(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(color: color.withOpacity(0.07), borderRadius: BorderRadius.circular(10)),
child: Column(
children: [
Text(label, style: TextStyle(fontSize: 12, color: color, fontWeight: FontWeight.bold)),
const SizedBox(height: 4),
Text(value != null ? value.toStringAsFixed(2) : '--',
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600)),
],
),
),
);
}
Widget _statusDot(bool active) {
return Container(
width: 8, height: 8,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: active ? Colors.green : Colors.grey.shade300,
),
);
}
}