import 'sensor_def.dart'; import 'sensor_defs.dart'; enum SpeedUnit { kmh, mph } enum TempUnit { celsius, fahrenheit } enum PressureUnit { kpa, bar, psi } /// User's display units. Values are always stored and logged in the base /// (metric) units of [sensorDefs]; conversion happens only for display. class UnitPrefs { final SpeedUnit speed; final TempUnit temp; final PressureUnit pressure; const UnitPrefs({ this.speed = SpeedUnit.kmh, this.temp = TempUnit.celsius, this.pressure = PressureUnit.kpa, }); UnitPrefs copyWith({ SpeedUnit? speed, TempUnit? temp, PressureUnit? pressure, }) => UnitPrefs( speed: speed ?? this.speed, temp: temp ?? this.temp, pressure: pressure ?? this.pressure, ); @override bool operator ==(Object other) => other is UnitPrefs && other.speed == speed && other.temp == temp && other.pressure == pressure; @override int get hashCode => Object.hash(speed, temp, pressure); } /// How one sensor is displayed under the current [UnitPrefs]: unit label, /// converted range, and value conversion/formatting. class SensorView { final SensorDef def; final String unit; final double min; final double max; final int decimals; final double Function(double base) _convert; const SensorView._( this.def, this.unit, this.min, this.max, this.decimals, this._convert); String get name => def.displayName; /// Converts a base-unit value to the display unit. double convert(double base) => _convert(base); /// Converted and formatted, without unit. String format(double base) => convert(base).toStringAsFixed(decimals); /// 0..1 position of [base] within the sensor's range. double fraction(double base) => ((convert(base) - min) / (max - min)).clamp(0.0, 1.0); } double _id(double v) => v; SensorView sensorView(String id, UnitPrefs u) { final d = sensorDef(id); SensorView view(String unit, double Function(double) f, {int? decimals}) => SensorView._(d, unit, f(d.min), f(d.max), decimals ?? d.decimals, f); switch (id) { case 'vss': return u.speed == SpeedUnit.mph ? view('mph', (v) => v * 0.621371) : view(d.unit, _id); case 'ect': case 'iat': return u.temp == TempUnit.fahrenheit ? view('°F', (v) => v * 9 / 5 + 32) : view(d.unit, _id); case 'map': case 'pa': switch (u.pressure) { case PressureUnit.bar: return view('bar', (v) => v / 100, decimals: 2); case PressureUnit.psi: return view('psi', (v) => v * 0.145038); case PressureUnit.kpa: return view(d.unit, _id); } default: return view(d.unit, _id); } }