import 'package:flutter/material.dart'; import '../../../../core/models/sensor_defs.dart'; import '../../../../core/models/units.dart'; import '../../../../core/protocol/sensor_state.dart'; import '../../../theme/app_colors.dart'; /// One selectable dashboard value: "unit (name)" caption over a large /// number, as in the requirement layouts. Long-press to change the sensor. class SensorTile extends StatelessWidget { final String sensorId; final SensorState state; final UnitPrefs units; final VoidCallback onLongPress; const SensorTile({ super.key, required this.sensorId, required this.state, required this.units, required this.onLongPress, }); @override Widget build(BuildContext context) { final c = AppColors.of(context); final view = sensorView(sensorId, units); final base = sensorValue(state, sensorId); final fraction = view.fraction(base); final caption = view.unit.isEmpty ? view.name : '${view.unit} (${view.name})'; return GestureDetector( onLongPress: onLongPress, child: LayoutBuilder( builder: (context, box) { final valueText = Text( view.format(base), style: TextStyle( color: fraction > 0.9 ? Colors.red : c.onSurface, fontSize: 26, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic, letterSpacing: -0.5, ), ); final captionText = Text( caption, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( color: c.onSurfaceMuted, fontSize: 10, fontStyle: FontStyle.italic, fontWeight: FontWeight.w600, ), ); // Short tiles (5 per side in landscape): caption beside the value // so the number keeps its size. if (box.maxHeight < 56) { return Container( decoration: BoxDecoration( color: c.surface, borderRadius: BorderRadius.circular(8), border: Border.all(color: c.divider), ), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), child: Row( children: [ Expanded(flex: 4, child: captionText), Expanded( flex: 5, child: FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerRight, child: valueText, ), ), ], ), ); } final showBar = box.maxHeight >= 64; return Container( decoration: BoxDecoration( color: c.surface, borderRadius: BorderRadius.circular(8), border: Border.all(color: c.divider), ), padding: const EdgeInsets.fromLTRB(8, 4, 8, 4), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( caption, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: c.onSurfaceMuted, fontSize: 10, fontStyle: FontStyle.italic, fontWeight: FontWeight.w600, ), ), Expanded( child: FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerRight, child: Text( view.format(base), style: TextStyle( color: fraction > 0.9 ? Colors.red : c.onSurface, fontSize: 26, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic, letterSpacing: -0.5, ), ), ), ), if (showBar) ClipRRect( borderRadius: BorderRadius.circular(2), child: LinearProgressIndicator( value: fraction, minHeight: 3, backgroundColor: c.track, valueColor: AlwaysStoppedAnimation( fraction > 0.9 ? Colors.red : c.accent, ), ), ), ], ), ); }, ), ); } }