- Implemented RawFrameDebugScreen for displaying ECU frame data and diagnostics. - Created DtcScreen to show active Diagnostic Trouble Codes (DTCs) with detailed descriptions. - Added DtcRow widget for individual DTC representation. - Introduced GraphScreen for visualizing sensor data over time with customizable time windows. - Developed SensorListScreen to display available sensors and their current values. - Enhanced SettingsScreen with options for Bluetooth connection, ECU protocol selection, polling interval, and theme settings. - Added AppColors and AppTheme for consistent theming across the application. - Implemented BtStatusChip to show Bluetooth connection status in the app bar. - Created RecordFab for starting and stopping data recording sessions.
129 lines
3.8 KiB
Dart
129 lines
3.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../../../../core/models/sensor_defs.dart';
|
|
import '../../../../core/protocol/sensor_state.dart';
|
|
|
|
class SensorTile extends StatelessWidget {
|
|
final int slotIndex;
|
|
final String sensorId;
|
|
final SensorState state;
|
|
final Color accentColor;
|
|
final VoidCallback onTap;
|
|
|
|
const SensorTile({
|
|
super.key,
|
|
required this.slotIndex,
|
|
required this.sensorId,
|
|
required this.state,
|
|
required this.accentColor,
|
|
required this.onTap,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final def = sensorDefs.firstWhere(
|
|
(d) => d.id == sensorId,
|
|
orElse: () => sensorDefs.first,
|
|
);
|
|
final value = _getValue(state, sensorId);
|
|
final normalized =
|
|
((value - def.min) / (def.max - def.min)).clamp(0.0, 1.0);
|
|
|
|
return GestureDetector(
|
|
onLongPress: onTap,
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF1A1A1A),
|
|
borderRadius: BorderRadius.circular(10),
|
|
border: Border.all(color: Colors.white10),
|
|
),
|
|
padding: const EdgeInsets.fromLTRB(10, 8, 10, 6),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
def.displayName.toUpperCase(),
|
|
style: const TextStyle(
|
|
color: Colors.grey,
|
|
fontSize: 10,
|
|
letterSpacing: 1,
|
|
),
|
|
),
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
children: [
|
|
Text(
|
|
_format(value, sensorId),
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 22,
|
|
fontWeight: FontWeight.bold,
|
|
letterSpacing: -0.5,
|
|
),
|
|
),
|
|
const SizedBox(width: 3),
|
|
Padding(
|
|
padding: const EdgeInsets.only(bottom: 2),
|
|
child: Text(
|
|
def.unit,
|
|
style: TextStyle(color: accentColor, fontSize: 11),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
// Bar gauge
|
|
ClipRRect(
|
|
borderRadius: BorderRadius.circular(2),
|
|
child: LinearProgressIndicator(
|
|
value: normalized,
|
|
minHeight: 4,
|
|
backgroundColor: Colors.white10,
|
|
valueColor: AlwaysStoppedAnimation<Color>(
|
|
normalized > 0.8 ? Colors.red : accentColor,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
String _format(double v, String id) {
|
|
if (id == 'gear') return v.toStringAsFixed(0);
|
|
if (id == 'rpm') return v.toStringAsFixed(0);
|
|
if (v.abs() >= 100) return v.toStringAsFixed(1);
|
|
return v.toStringAsFixed(2);
|
|
}
|
|
}
|
|
|
|
double _getValue(SensorState s, String id) {
|
|
switch (id) {
|
|
case 'rpm': return s.rpm;
|
|
case 'vss': return s.vss;
|
|
case 'map': return s.map;
|
|
case 'tps': return s.tps;
|
|
case 'inj': return s.inj;
|
|
case 'ign': return s.ign;
|
|
case 'ect': return s.ect;
|
|
case 'iat': return s.iat;
|
|
case 'bat': return s.bat;
|
|
case 'o2': return s.o2;
|
|
case 'gear': return s.gear.toDouble();
|
|
case 'eth': return s.eth;
|
|
case 'pa': return s.pa;
|
|
case 'afr': return s.afr;
|
|
case 'strim': return s.strim;
|
|
case 'ltrim': return s.ltrim;
|
|
case 'ain0': return s.ain0;
|
|
case 'ain1': return s.ain1;
|
|
case 'ain2': return s.ain2;
|
|
case 'ain3': return s.ain3;
|
|
case 'ain4': return s.ain4;
|
|
case 'ain5': return s.ain5;
|
|
case 'ain6': return s.ain6;
|
|
case 'ain7': return s.ain7;
|
|
default: return 0;
|
|
}
|
|
}
|