import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import '../../../../core/models/sensor_defs.dart'; import '../../../../core/providers/sensor_history_provider.dart'; class SensorGraphPanel extends StatelessWidget { final String sensorId; final SensorHistory history; final int windowSeconds; final Color accentColor; final VoidCallback onRemove; const SensorGraphPanel({ super.key, required this.sensorId, required this.history, required this.windowSeconds, required this.accentColor, required this.onRemove, }); @override Widget build(BuildContext context) { final def = sensorDefs.firstWhere( (d) => d.id == sensorId, orElse: () => sensorDefs.first, ); final allSpots = history.get(sensorId); // Slice to window final spots = _window(allSpots, windowSeconds.toDouble()); return Container( margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), padding: const EdgeInsets.fromLTRB(8, 10, 12, 8), decoration: BoxDecoration( color: const Color(0xFF1A1A1A), borderRadius: BorderRadius.circular(10), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row( children: [ Text( def.displayName.toUpperCase(), style: TextStyle( color: accentColor, fontSize: 11, letterSpacing: 1.5, fontWeight: FontWeight.w600, ), ), const SizedBox(width: 6), Text( def.unit, style: const TextStyle(color: Colors.grey, fontSize: 11), ), const Spacer(), if (spots.isNotEmpty) Text( _fmt(spots.last.y), style: const TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold, ), ), const SizedBox(width: 8), GestureDetector( onTap: onRemove, child: const Icon(Icons.close, size: 16, color: Colors.white38), ), ], ), const SizedBox(height: 8), // Chart SizedBox( height: 90, child: spots.length < 2 ? const Center( child: Text('Waiting for data…', style: TextStyle(color: Colors.white30, fontSize: 12))) : LineChart( LineChartData( gridData: FlGridData( show: true, drawVerticalLine: false, getDrawingHorizontalLine: (_) => FlLine( color: Colors.white10, strokeWidth: 1, ), ), borderData: FlBorderData(show: false), titlesData: const FlTitlesData(show: false), minY: def.min.toDouble(), maxY: def.max.toDouble(), lineBarsData: [ LineChartBarData( spots: spots, isCurved: true, curveSmoothness: 0.2, color: accentColor, barWidth: 1.5, dotData: const FlDotData(show: false), belowBarData: BarAreaData( show: true, color: accentColor.withAlpha(25), ), ), ], ), duration: Duration.zero, ), ), ], ), ); } List _window(List spots, double windowSec) { if (spots.isEmpty) return spots; final maxX = spots.last.x; final minX = maxX - windowSec; return spots.where((s) => s.x >= minX).toList(); } String _fmt(double v) => v.abs() >= 100 ? v.toStringAsFixed(1) : v.toStringAsFixed(2); }