summaryrefslogtreecommitdiffstats
path: root/lib/screen/widgets/gauges
diff options
context:
space:
mode:
Diffstat (limited to 'lib/screen/widgets/gauges')
-rw-r--r--lib/screen/widgets/gauges/gauge_props.dart48
-rw-r--r--lib/screen/widgets/gauges/gauge_widget.dart109
-rw-r--r--lib/screen/widgets/gauges/rpm_gauge_animation_wrapper.dart50
-rw-r--r--lib/screen/widgets/gauges/speed_gauge_animation_wrapper.dart65
4 files changed, 272 insertions, 0 deletions
diff --git a/lib/screen/widgets/gauges/gauge_props.dart b/lib/screen/widgets/gauges/gauge_props.dart
new file mode 100644
index 0000000..51dba51
--- /dev/null
+++ b/lib/screen/widgets/gauges/gauge_props.dart
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:math';
+import 'package:flutter/material.dart';
+
+class GaugeProps {
+ static GaugeColors normalModeColor = GaugeColors(
+ inPrimary: const Color.fromARGB(255, 67, 67, 67),
+ outPrimary: const Color.fromARGB(255, 120, 120, 120),
+ secondary: const Color.fromARGB(156, 226, 226, 200),
+ );
+ static GaugeColors sportModeColor = GaugeColors(
+ inPrimary: Colors.deepPurple,
+ outPrimary: Colors.blue,
+ secondary: const Color.fromARGB(214, 202, 202, 202));
+ static GaugeColors ecoModeColor = GaugeColors(
+ inPrimary: const Color.fromARGB(255, 85, 165, 87),
+ outPrimary: const Color.fromARGB(255, 40, 92, 42),
+ secondary: const Color.fromARGB(202, 194, 238, 195));
+ static double majorAngle = 260;
+ static double majorAngleRad = 260 * (pi / 180);
+ static double minorAngle = 360 - majorAngle;
+ static Color bgColor = const Color.fromARGB(255, 0, 0, 0);
+ static const leftLowColor = Color(0x000000ff);
+ static const leftHighColor = Color(0x00ff0000);
+
+ static double degToRad(double deg) => deg * (pi / 180.0);
+ static TextStyle gearIconStyle(screenHeight) {
+ return TextStyle(
+ color: const Color.fromARGB(255, 84, 83, 83),
+ fontSize: (20 * screenHeight) / 480,
+ fontWeight: FontWeight.bold);
+ }
+
+ static TextStyle activeGearIconStyle(screenHeight) {
+ return TextStyle(
+ color: Colors.white,
+ fontSize: (20 * screenHeight) / 480,
+ fontWeight: FontWeight.bold);
+ }
+}
+
+class GaugeColors {
+ Color? inPrimary;
+ Color? outPrimary;
+ Color? secondary;
+ GaugeColors({this.inPrimary, this.outPrimary, this.secondary});
+}
diff --git a/lib/screen/widgets/gauges/gauge_widget.dart b/lib/screen/widgets/gauges/gauge_widget.dart
new file mode 100644
index 0000000..c302953
--- /dev/null
+++ b/lib/screen/widgets/gauges/gauge_widget.dart
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:math';
+import 'package:flutter/material.dart';
+import 'package:flutter_cluster_dashboard/screen/paints/gauge_paint.dart';
+import 'package:flutter_cluster_dashboard/screen/widgets/gauges/gauge_props.dart';
+
+class CustomGauge extends StatelessWidget {
+ const CustomGauge({
+ Key? key,
+ required this.mainValue,
+ required this.low,
+ required this.high,
+ required this.label,
+ this.zeroTickLabel,
+ this.maxTickLabel,
+ this.distanceBWTicks,
+ this.size,
+ this.distLabelTop,
+ this.distMainTop,
+ this.distTicksBottom,
+ this.inPrimaryColor,
+ this.outPrimaryColor,
+ this.secondaryColor,
+ }) : super(key: key);
+
+ final double mainValue;
+ final double low;
+ final double high;
+ final String label;
+ final String? zeroTickLabel;
+ final String? maxTickLabel;
+ final double? distanceBWTicks;
+ final double? distTicksBottom;
+ final double? distMainTop;
+ final double? distLabelTop;
+ final double? size;
+ final Color? outPrimaryColor;
+ final Color? inPrimaryColor;
+ final Color? secondaryColor;
+
+ @override
+ Widget build(BuildContext context) {
+ TextStyle tickStyle = TextStyle(
+ color: Colors.white,
+ fontSize: ((26 / 400) * (size ?? 400)),
+ fontWeight: FontWeight.bold); //20
+ TextStyle mainValueTextStyle = TextStyle(
+ color: Colors.white,
+ fontSize: ((85 / 400) * (size ?? 400)),
+ fontWeight: FontWeight.bold); //65
+ TextStyle labelTextStyle = TextStyle(
+ color: Colors.white,
+ fontSize: ((26 / 400) * (size ?? 400)),
+ fontWeight: FontWeight.normal); //20
+ return SizedBox(
+ width: size ?? 400,
+ height: size ?? 400,
+ child: Stack(
+ alignment: Alignment.topCenter,
+ children: [
+ // Gauge painter
+ Positioned(
+ top: 0,
+ child: Transform.rotate(
+ angle: (pi / 2) + (GaugeProps.minorAngle * (pi / 360.0)),
+ child: CustomPaint(
+ size: Size(size ?? 400, size ?? 400),
+ painter: GaugePainter(
+ low: low,
+ high: high,
+ currentSpeed: mainValue,
+ inPrimaryColor: inPrimaryColor,
+ outPrimaryColor: outPrimaryColor,
+ secondaryColor: secondaryColor,
+ ),
+ ),
+ ),
+ ),
+ // Gauge Label
+ Positioned(
+ top: distLabelTop ?? ((100 / 400) * (size ?? 400)),
+ child: Text(label, style: labelTextStyle),
+ ),
+ // Gauge Main Value
+ Positioned(
+ top: distMainTop ?? ((150 / 400) * (size ?? 400)),
+ child: Text("${mainValue.toInt()}", style: mainValueTextStyle),
+ ),
+ // Gauge Ticks value
+ Positioned(
+ bottom: distTicksBottom ?? ((80 / 400) * (size ?? 400)),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(zeroTickLabel ?? "", style: tickStyle),
+ SizedBox(
+ width: (size != null)
+ ? ((180 * size!) / 400)
+ : (distanceBWTicks ?? 180)),
+ Text(maxTickLabel ?? "", style: tickStyle)
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/screen/widgets/gauges/rpm_gauge_animation_wrapper.dart b/lib/screen/widgets/gauges/rpm_gauge_animation_wrapper.dart
new file mode 100644
index 0000000..fa76bd8
--- /dev/null
+++ b/lib/screen/widgets/gauges/rpm_gauge_animation_wrapper.dart
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:flutter_cluster_dashboard/screen/widgets/gauges/gauge_props.dart';
+import 'package:flutter_cluster_dashboard/screen/widgets/gauges/gauge_widget.dart';
+import 'package:flutter_cluster_dashboard/vehicle-signals/vehicle_status_provider.dart';
+
+class RPMGauge extends HookConsumerWidget {
+ final double screenHeight;
+ final GaugeColors? gaugeColor;
+ const RPMGauge({Key? key, required this.screenHeight, this.gaugeColor})
+ : super(key: key);
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final double rpm = ref.watch(vehicleStatusProvider.select((p) => p.rpm));
+
+ const double minRPM = 0;
+ const double maxRPM = 8000;
+ const Duration sweepDuration = Duration(milliseconds: 200);
+
+ final animationController = useAnimationController(
+ lowerBound: minRPM,
+ upperBound: maxRPM,
+ )..animateTo(rpm,
+ duration: sweepDuration, curve: Curves.linearToEaseOut);
+ return AnimatedBuilder(
+ animation: animationController,
+ builder: (context, child) {
+ return Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: CustomGauge(
+ size: (248 * screenHeight) / 480,
+ low: minRPM,
+ high: maxRPM,
+ mainValue: animationController.value,
+ label: "rpm",
+ zeroTickLabel: minRPM.toInt().toString(),
+ maxTickLabel: maxRPM.toInt().toString(),
+ inPrimaryColor: gaugeColor?.inPrimary,
+ outPrimaryColor: gaugeColor?.outPrimary,
+ secondaryColor: gaugeColor?.secondary,
+ ),
+ );
+ });
+ }
+}
diff --git a/lib/screen/widgets/gauges/speed_gauge_animation_wrapper.dart b/lib/screen/widgets/gauges/speed_gauge_animation_wrapper.dart
new file mode 100644
index 0000000..dfa4277
--- /dev/null
+++ b/lib/screen/widgets/gauges/speed_gauge_animation_wrapper.dart
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter/material.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:flutter_cluster_dashboard/screen/widgets/gauges/gauge_props.dart';
+import 'package:flutter_cluster_dashboard/screen/widgets/gauges/gauge_widget.dart';
+import 'package:flutter_cluster_dashboard/vehicle-signals/vehicle_status_provider.dart';
+
+class SpeedGauge extends HookConsumerWidget {
+ final double screenHeight;
+ final GaugeColors? gaugeColor;
+ const SpeedGauge({Key? key, required this.screenHeight, this.gaugeColor})
+ : super(key: key);
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final double speed = ref.watch(vehicleStatusProvider.select((p) => p.speed));
+ final String units = ref.watch(vehicleStatusProvider.select((p) => p.vehicleDistanceUnit));
+
+ const double minSpeed = 0;
+ const double maxSpeed = 240;
+ const Duration sweepDuration = Duration(milliseconds: 200);
+ double speedScaling = (units == "mi") ? 0.621504 : 1.0;
+
+ final animationController = useAnimationController(
+ lowerBound: minSpeed,
+ upperBound: maxSpeed,
+ )..animateTo(speedScaling * speed,
+ duration: sweepDuration, curve: Curves.linearToEaseOut);
+
+ return AnimatedBuilder(
+ animation: animationController,
+ builder: (context, child) {
+ return Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: CustomGauge(
+ size: (248 * screenHeight) / 480,
+ low: minSpeed,
+ high: maxSpeed,
+ mainValue: animationController.value,
+ label: (units == "mi") ? "mph" : "Km/h",
+ zeroTickLabel: minSpeed.toInt().toString(),
+ maxTickLabel: maxSpeed.toInt().toString(),
+ inPrimaryColor: gaugeColor?.inPrimary,
+ outPrimaryColor: gaugeColor?.outPrimary,
+ secondaryColor: gaugeColor?.secondary,
+ ),
+ );
+ });
+ }
+}
+
+final gaugeColorProvider = Provider.family<GaugeColors, String>((ref, mode) {
+ switch (mode) {
+ case "normal":
+ return GaugeColors(inPrimary: Colors.red);
+ case "sports":
+ return GaugeColors(inPrimary: Colors.blue);
+ case "eco":
+ return GaugeColors(inPrimary: Colors.green);
+ default:
+ return GaugeColors();
+ }
+});