summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorHritik Chouhan <hritikc3961@gmail.com>2022-09-01 19:15:56 +0200
committerHritik Chouhan <hritikc3961@gmail.com>2022-09-16 17:25:01 +0200
commit5559cdb261cfd3e69daa2349906f071dc2491c0d (patch)
tree12a530a7ab6b8f5fc758f228bf1729e733db9aa8 /lib
parentb7ba5e78b0ca5245cd9c09313d40561e75d0b120 (diff)
Upload Flutter-HVAC application for IVI
Flutter hvac app which sets value to KUKSA.VAL like Fan speed,left and right zone climate temperature, AC vent direction, Air circulation,Front and Rear Wind shield defrost. Update UI and removed Unused code. Bug-AGL: SPEC-4546 Change-Id: I57f7a9a2954520f4bb781a5ec02be612d72cf404 Signed-off-by: Hritik Chouhan <hritikc3961@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Buttons/AC.dart124
-rw-r--r--lib/Buttons/ac_on_face.dart145
-rw-r--r--lib/Buttons/ac_on_foot.dart146
-rw-r--r--lib/Buttons/auto.dart116
-rw-r--r--lib/Buttons/defrost_recirculate.dart178
-rw-r--r--lib/Buttons/fresh_air.dart110
-rw-r--r--lib/config.dart111
-rw-r--r--lib/home_page.dart181
-rw-r--r--lib/kuksa-server/intial_connection.dart44
-rw-r--r--lib/kuksa-server/on_boarding_page.dart65
-rw-r--r--lib/kuksa-server/vehicle-class.dart53
-rw-r--r--lib/kuksa-server/vehicle-provider.dart47
-rw-r--r--lib/kuksa-server/vehicle_config.dart39
-rw-r--r--lib/kuksa-server/vehicle_methods.dart97
-rw-r--r--lib/kuksa-server/vehicle_server_path.dart36
-rw-r--r--lib/main.dart23
-rw-r--r--lib/provider.dart37
-rw-r--r--lib/size.dart50
-rw-r--r--lib/slider/Climate_slider.dart38
-rw-r--r--lib/slider/Right_climate_slider.dart36
-rw-r--r--lib/slider/slider.dart44
-rw-r--r--lib/widgets/Right_climate.dart115
-rw-r--r--lib/widgets/left_climate.dart112
23 files changed, 1947 insertions, 0 deletions
diff --git a/lib/Buttons/AC.dart b/lib/Buttons/AC.dart
new file mode 100644
index 0000000..e0c610a
--- /dev/null
+++ b/lib/Buttons/AC.dart
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle-provider.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle_methods.dart';
+
+import '../size.dart';
+
+class AC extends ConsumerStatefulWidget {
+ WebSocket socket;
+ String serverPath;
+ AC({
+ Key? key,
+ required this.serverPath,
+ required this.socket,
+ }) : super(key: key);
+
+ @override
+ _ACState createState() => _ACState();
+}
+
+class _ACState extends ConsumerState<AC> with SingleTickerProviderStateMixin {
+ late AnimationController _controller;
+ late bool isAcActive;
+ late Animation<Color?> _colorAnimation;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _controller = AnimationController(
+ duration: Duration(milliseconds: 500),
+ vsync: this,
+ );
+
+ _colorAnimation =
+ ColorTween(begin: Colors.lightBlueAccent, end: Colors.green)
+ .animate(_controller);
+
+ _controller.addListener(() {
+
+ });
+
+ _controller.addStatusListener((status) {
+ if (status == AnimationStatus.completed) {
+ VISS.set(widget.socket, ref,widget.serverPath, isAcActive.toString());
+ }
+ if (status == AnimationStatus.dismissed) {
+ VISS.set(widget.socket, ref,widget.serverPath, isAcActive.toString());
+ }
+ });
+ }
+
+ // dismiss the animation when widget exits screen
+ @override
+ void dispose() {
+ super.dispose();
+ _controller.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ isAcActive = ref.watch(vehicleProvider).isAcActive;
+ return AnimatedBuilder(
+ animation: _controller,
+ builder: (BuildContext context, _) {
+ return InkWell(
+ child: AnimatedContainer(
+ constraints: BoxConstraints(
+ maxHeight: SizeConfig.screenHeight*0.10,
+ maxWidth: SizeConfig.screenWidth*0.15,
+ ),
+
+
+ decoration: BoxDecoration(
+ gradient: isAcActive
+ ? RadialGradient(
+ colors: [Colors.black, Colors.lightBlue],
+ radius: 2,
+ )
+ : null,
+
+
+ border: Border.all(
+ color: Colors.white,
+ width: 2,
+ ),
+ borderRadius: BorderRadius.circular(SizeConfig.blockSizeVertical*2),
+ ),
+ duration: Duration(seconds: 1),
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 100),
+ margin: EdgeInsets.all(SizeConfig.blockSizeVertical*2),
+ child: Container(
+ width: SizeConfig.screenWidth*0.15,
+ height: SizeConfig.screenHeight*0.10,
+ child: FittedBox(
+ fit: BoxFit.fill,
+ child: Text(
+ 'A/C',
+ style: TextStyle(
+ color: _colorAnimation.value,
+ fontWeight: FontWeight.w700,
+
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ onTap: () {
+ isAcActive ? _controller.reverse() : _controller.forward();
+ ref
+ .read(vehicleProvider.notifier)
+ .update(isAcActive: !isAcActive);
+ },
+ );
+
+ });
+ }
+}
diff --git a/lib/Buttons/ac_on_face.dart b/lib/Buttons/ac_on_face.dart
new file mode 100644
index 0000000..f0c0f41
--- /dev/null
+++ b/lib/Buttons/ac_on_face.dart
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg_provider/flutter_svg_provider.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle-provider.dart';
+
+import '../kuksa-server/vehicle-class.dart';
+import '../kuksa-server/vehicle_methods.dart';
+import '../size.dart';
+
+class AcOnFace extends ConsumerStatefulWidget {
+ final String img;
+ WebSocket socket;
+ AcOnFace({
+ Key? key,
+ required this.img,
+ required this.socket,
+ }) : super(key: key);
+
+ @override
+ _AcOnFaceState createState() => _AcOnFaceState();
+}
+
+class _AcOnFaceState extends ConsumerState<AcOnFace>
+ with SingleTickerProviderStateMixin {
+ late AnimationController _controller;
+ late Animation<Color?> _colorAnimation;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _controller = AnimationController(
+ duration: Duration(milliseconds: 500),
+ vsync: this,
+ );
+
+ _colorAnimation =
+ ColorTween(begin: Colors.lightBlueAccent, end: Colors.green)
+ .animate(_controller);
+
+ _controller.addListener(() {});
+
+ _controller.addStatusListener((status) {
+ if (status == AnimationStatus.completed) {
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row1.Left.AirDistribution", 'up');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row1.Right.AirDistribution", 'up');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row2.Left.AirDistribution", 'up');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row2.Right.AirDistribution", 'up');
+ }
+
+ if (status == AnimationStatus.dismissed) {
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row1.Left.AirDistribution", 'middle');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row1.Right.AirDistribution", 'middle');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row2.Left.AirDistribution", 'middle');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row2.Right.AirDistribution", 'middle');
+ }
+ });
+ }
+
+ // dismiss the animation when widget exits screen
+ @override
+ void dispose() {
+ super.dispose();
+ _controller.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ vehicle vehicledata = ref.watch(vehicleProvider);
+ if (vehicledata.isAcDirectionUp == false) {
+ _controller.reverse();
+ }
+
+ return AnimatedBuilder(
+ animation: _controller,
+ builder: (BuildContext context, _) {
+ return InkWell(
+ child: AnimatedContainer(
+ constraints: BoxConstraints(
+ maxHeight: SizeConfig.screenHeight*0.10,
+ maxWidth: SizeConfig.screenWidth*0.15,
+ ),
+
+
+ decoration: BoxDecoration(
+ gradient: vehicledata.isAcDirectionUp
+ ? RadialGradient(
+ colors: [Colors.black, Colors.lightBlue],
+ radius: 2,
+ )
+ : null,
+
+
+ border: Border.all(
+ color: Colors.white,
+ width: 2,
+ ),
+ borderRadius: BorderRadius.circular(SizeConfig.safeBlockVertical*2),
+ ),
+ duration: const Duration(milliseconds: 500),
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 100),
+ margin: const EdgeInsets.all(10),
+ child: Image(
+ width: SizeConfig.screenWidth*0.15,
+ height: SizeConfig.screenHeight*0.10,
+ image: Svg(widget.img),
+ color: _colorAnimation.value,
+ ),
+ ),
+ ),
+ onTap: () {
+ if (vehicledata.isAcDirectionDown) {
+ ref
+ .watch(vehicleProvider.notifier)
+ .update(isAcDirectionDown: !vehicledata.isAcDirectionDown);
+ }
+ Future.delayed(Duration(milliseconds: 500),(){
+ vehicledata.isAcDirectionUp
+ ? _controller.reverse()
+ : _controller.forward();
+
+ ref.watch(vehicleProvider.notifier).update(
+ isAcDirectionUp: !vehicledata.isAcDirectionUp,
+ );
+ });
+
+ },
+ );
+
+ });
+ }
+}
diff --git a/lib/Buttons/ac_on_foot.dart b/lib/Buttons/ac_on_foot.dart
new file mode 100644
index 0000000..41e2569
--- /dev/null
+++ b/lib/Buttons/ac_on_foot.dart
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg_provider/flutter_svg_provider.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle-provider.dart';
+
+import '../kuksa-server/vehicle-class.dart';
+import '../kuksa-server/vehicle_methods.dart';
+import '../size.dart';
+
+class AcOnFoot extends ConsumerStatefulWidget {
+ final String img;
+ WebSocket socket;
+ AcOnFoot({
+ Key? key,
+ required this.img,
+ required this.socket,
+ }) : super(key: key);
+
+ @override
+ _AcOnFootState createState() => _AcOnFootState();
+}
+
+class _AcOnFootState extends ConsumerState<AcOnFoot>
+ with SingleTickerProviderStateMixin {
+ late AnimationController _controller;
+ late Animation<Color?> _colorAnimation;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _controller = AnimationController(
+ duration: Duration(milliseconds: 500),
+ vsync: this,
+ );
+
+ _colorAnimation =
+ ColorTween(begin: Colors.lightBlueAccent, end: Colors.green)
+ .animate(_controller);
+
+ _controller.addListener(() {});
+
+ _controller.addStatusListener((status) {
+ if (status == AnimationStatus.completed) {
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row1.Left.AirDistribution", 'down');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row1.Right.AirDistribution", 'down');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row2.Left.AirDistribution", 'down');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row2.Right.AirDistribution", 'down');
+
+ }
+
+ if (status == AnimationStatus.dismissed) {
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row1.Left.AirDistribution", 'middle');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row1.Right.AirDistribution", 'middle');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row2.Left.AirDistribution", 'middle');
+ VISS.set(widget.socket,ref,
+ "Vehicle.Cabin.HVAC.Station.Row2.Right.AirDistribution", 'middle');
+ }
+ });
+ }
+
+ // dismiss the animation when widget exits screen
+ @override
+ void dispose() {
+ super.dispose();
+ _controller.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ vehicle vehicledata = ref.watch(vehicleProvider);
+ if (vehicledata.isAcDirectionDown == false) {
+ _controller.reverse();
+ }
+
+ return AnimatedBuilder(
+ animation: _controller,
+ builder: (BuildContext context, _) {
+ return InkWell(
+ child: AnimatedContainer(
+ constraints: BoxConstraints(
+ maxHeight: SizeConfig.screenHeight*0.10,
+ maxWidth: SizeConfig.screenWidth*0.15,
+ ),
+
+
+ decoration: BoxDecoration(
+ gradient: vehicledata.isAcDirectionDown
+ ? RadialGradient(
+ colors: [Colors.black, Colors.lightBlue],
+ radius: 2,
+ )
+ : null,
+
+
+ border: Border.all(
+ color: Colors.white,
+ width: 2,
+ ),
+ borderRadius: BorderRadius.circular(SizeConfig.safeBlockVertical*2),
+ ),
+ duration: const Duration(milliseconds: 500),
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 100),
+ margin: const EdgeInsets.all(10),
+ child: Image(
+ width: SizeConfig.screenWidth*0.15,
+ height: SizeConfig.screenHeight*0.10,
+ image: Svg(widget.img),
+ color: _colorAnimation.value,
+ ),
+ ),
+ ),
+ onTap: () {
+ if (vehicledata.isAcDirectionUp == true) {
+ ref
+ .watch(vehicleProvider.notifier)
+ .update(isAcDirectionUp: !vehicledata.isAcDirectionUp);
+ }
+ Future.delayed(Duration(milliseconds: 500),(){
+ vehicledata.isAcDirectionDown
+ ? _controller.reverse()
+ : _controller.forward();
+
+ ref.watch(vehicleProvider.notifier).update(
+ isAcDirectionDown: !vehicledata.isAcDirectionDown,
+ );
+ });
+
+ },
+ );
+
+ });
+ }
+}
diff --git a/lib/Buttons/auto.dart b/lib/Buttons/auto.dart
new file mode 100644
index 0000000..536a117
--- /dev/null
+++ b/lib/Buttons/auto.dart
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle-provider.dart';
+
+import '../size.dart';
+
+class Auto extends ConsumerStatefulWidget {
+ WebSocket socket;
+ String serverPath;
+ Auto({
+ Key? key,
+ required this.serverPath,
+ required this.socket,
+ }) : super(key: key);
+
+ @override
+ _AutoState createState() => _AutoState();
+}
+
+class _AutoState extends ConsumerState<Auto> with SingleTickerProviderStateMixin {
+ late AnimationController _controller;
+ late bool isAutoActive;
+ late Animation<Color?> _colorAnimation;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _controller = AnimationController(
+ duration: Duration(milliseconds: 500),
+ vsync: this,
+ );
+
+ _colorAnimation =
+ ColorTween(begin: Colors.lightBlueAccent, end: Colors.green)
+ .animate(_controller);
+
+ _controller.addListener(() {
+
+ });
+
+
+ }
+
+ // dismiss the animation when widget exits screen
+ @override
+ void dispose() {
+ super.dispose();
+ _controller.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ isAutoActive = ref.watch(vehicleProvider).isAutoActive;
+ return AnimatedBuilder(
+ animation: _controller,
+ builder: (BuildContext context, _) {
+ return InkWell(
+ child: AnimatedContainer(
+ constraints: BoxConstraints(
+ maxHeight: SizeConfig.screenHeight*0.10,
+ maxWidth: SizeConfig.screenWidth*0.15,
+ ),
+
+
+ decoration: BoxDecoration(
+ gradient: isAutoActive
+ ? RadialGradient(
+ colors: [Colors.black, Colors.lightBlue],
+ radius: 2,
+ )
+ : null,
+
+
+ border: Border.all(
+ color: Colors.white,
+ width: 2,
+ ),
+ borderRadius: BorderRadius.circular(SizeConfig.safeBlockVertical*2),
+ ),
+ duration: Duration(seconds: 1),
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 100),
+ margin: EdgeInsets.all(SizeConfig.blockSizeVertical*2),
+ child: Container(
+ width: SizeConfig.screenWidth*0.15,
+ height: SizeConfig.screenHeight*0.10,
+ child: FittedBox(
+ fit: BoxFit.fill,
+ child: Text(
+ 'AUTO',
+ style: TextStyle(
+ color: _colorAnimation.value,
+ fontWeight: FontWeight.w700,
+ // fontSize: SizeConfig.fontsize*4,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ onTap: () {
+ isAutoActive ? _controller.reverse() : _controller.forward();
+ ref
+ .read(vehicleProvider.notifier)
+ .update(isAutoActive: !isAutoActive);
+ },
+ );
+
+ });
+ }
+}
diff --git a/lib/Buttons/defrost_recirculate.dart b/lib/Buttons/defrost_recirculate.dart
new file mode 100644
index 0000000..30ac40d
--- /dev/null
+++ b/lib/Buttons/defrost_recirculate.dart
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg_provider/flutter_svg_provider.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle-class.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle-provider.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle_methods.dart';
+import 'package:flutter_hvac/size.dart';
+
+class CaustomButton extends ConsumerStatefulWidget {
+ WebSocket socket;
+ String serverPath;
+ String img;
+ String type;
+ CaustomButton({
+ Key? key,
+ required this.serverPath,
+ required this.socket,
+ required this.img,
+ required this.type,
+ }) : super(key: key);
+
+ @override
+ _CaustomButtonState createState() => _CaustomButtonState();
+}
+
+class _CaustomButtonState extends ConsumerState<CaustomButton>
+ with SingleTickerProviderStateMixin {
+ late AnimationController _controller;
+ late vehicle vehicledata;
+ late Animation<Color?> _colorAnimation;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _controller = AnimationController(
+ duration: Duration(milliseconds: 500),
+ vsync: this,
+ );
+
+ _colorAnimation =
+ ColorTween(begin: Colors.blue, end: Colors.green)
+ .animate(_controller);
+
+ _controller.addListener(() {
+
+ });
+
+ _controller.addStatusListener((status) {
+ if (status == AnimationStatus.completed) {
+ if (widget.type == 'Front_defrost') {
+ VISS.set(widget.socket,ref, widget.serverPath,
+ vehicledata.isFrontDefrosterActive.toString());
+ }
+ if (widget.type == "Rear_defrost") {
+ VISS.set(widget.socket,ref, widget.serverPath,
+ vehicledata.isRearDefrosterActive.toString());
+ }
+ if (widget.type == "Recirculation") {
+ VISS.set(widget.socket,ref, widget.serverPath,
+ vehicledata.isRecirculationActive.toString());
+ }
+
+
+
+ }
+ if (status == AnimationStatus.dismissed) {
+ if (widget.type == 'Front_defrost') {
+ VISS.set(widget.socket, ref,widget.serverPath,
+ vehicledata.isFrontDefrosterActive.toString());
+ }
+ if (widget.type == "Rear_defrost") {
+ VISS.set(widget.socket, ref,widget.serverPath,
+ vehicledata.isRearDefrosterActive.toString());
+ }
+ if (widget.type == "Recirculation") {
+ VISS.set(widget.socket, ref,widget.serverPath,
+ vehicledata.isRecirculationActive.toString());
+ }
+ }
+ });
+ }
+
+ // dismiss the animation when widget exits screen
+ @override
+ void dispose() {
+ super.dispose();
+ _controller.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ vehicledata = ref.watch(vehicleProvider);
+ return AnimatedBuilder(
+ animation: _controller,
+ builder: (BuildContext context, _) {
+ return InkWell(
+ child: AnimatedContainer(
+ constraints: BoxConstraints(
+ maxHeight: SizeConfig.screenHeight*0.10,
+ maxWidth: SizeConfig.screenWidth*0.15,
+ ),
+
+
+ decoration: BoxDecoration(
+ gradient: widget.type == "Front_defrost"
+ ? vehicledata.isFrontDefrosterActive
+ ? RadialGradient(
+ colors: [Colors.black, Colors.lightBlue],
+ radius: 2,
+ )
+ : null
+ : widget.type == "Rear_defrost"
+ ? vehicledata.isRearDefrosterActive
+ ? RadialGradient(
+ colors: [Colors.black, Colors.lightBlue],
+ radius: 2,
+ )
+ : null
+ : vehicledata.isRecirculationActive
+ ? RadialGradient(
+ colors: [Colors.black, Colors.lightBlue],
+ radius: 2,
+ )
+ : null,
+
+
+ border: Border.all(
+ color: Colors.white,
+ width: 2,
+ ),
+ borderRadius: BorderRadius.circular(SizeConfig.safeBlockVertical*2),
+ ),
+ duration: Duration(milliseconds: 100),
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 100),
+ margin: EdgeInsets.all(SizeConfig.blockSizeVertical),
+ child: Image(
+ width: SizeConfig.screenWidth*0.15,
+ height: SizeConfig.screenHeight*0.10,
+ image: Svg(widget.img),
+ color: _colorAnimation.value,
+ ),
+ ),
+ ),
+ onTap: () {
+ if (widget.type == "Front_defrost") {
+ vehicledata.isFrontDefrosterActive
+ ? _controller.reverse()
+ : _controller.forward();
+ ref.read(vehicleProvider.notifier).update(
+ isFrontDefrosterActive:
+ !vehicledata.isFrontDefrosterActive);
+ }
+ if (widget.type == "Rear_defrost") {
+ vehicledata.isRearDefrosterActive
+ ? _controller.reverse()
+ : _controller.forward();
+ ref.read(vehicleProvider.notifier).update(
+ isRearDefrosterActive: !vehicledata.isRearDefrosterActive);
+ }
+ if (widget.type == "Recirculation") {
+ vehicledata.isRecirculationActive
+ ? _controller.reverse()
+ : _controller.forward();
+ ref.read(vehicleProvider.notifier).update(
+ isRecirculationActive: !vehicledata.isRecirculationActive);
+ }
+ },
+ );
+
+ });
+ }
+}
diff --git a/lib/Buttons/fresh_air.dart b/lib/Buttons/fresh_air.dart
new file mode 100644
index 0000000..3858cba
--- /dev/null
+++ b/lib/Buttons/fresh_air.dart
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg_provider/flutter_svg_provider.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle-provider.dart';
+
+import '../size.dart';
+
+class FreshAir extends ConsumerStatefulWidget {
+ WebSocket socket;
+ String serverPath;
+ String img;
+ FreshAir({
+ Key? key,
+ required this.serverPath,
+ required this.socket,
+ required this.img,
+ }) : super(key: key);
+
+ @override
+ _FreshAirState createState() => _FreshAirState();
+}
+
+class _FreshAirState extends ConsumerState<FreshAir> with SingleTickerProviderStateMixin {
+ late AnimationController _controller;
+ late bool isFreshAirCirculateActive;
+ late Animation<Color?> _colorAnimation;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _controller = AnimationController(
+ duration: Duration(milliseconds: 500),
+ vsync: this,
+ );
+
+ _colorAnimation =
+ ColorTween(begin: Colors.lightBlueAccent, end: Colors.green)
+ .animate(_controller);
+
+ _controller.addListener(() {
+
+ });
+
+
+ }
+
+ // dismiss the animation when widget exits screen
+ @override
+ void dispose() {
+ super.dispose();
+ _controller.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ isFreshAirCirculateActive = ref.watch(vehicleProvider).isFreshAirCirculateActive;
+ return AnimatedBuilder(
+ animation: _controller,
+ builder: (BuildContext context, _) {
+ return InkWell(
+ child: AnimatedContainer(
+ constraints: BoxConstraints(
+ maxHeight: SizeConfig.screenHeight*0.10,
+ maxWidth: SizeConfig.screenWidth*0.15,
+ ),
+
+
+ decoration: BoxDecoration(
+ gradient: isFreshAirCirculateActive
+ ? RadialGradient(
+ colors: [Colors.black, Colors.lightBlue],
+ radius: 2,
+ )
+ : null,
+
+ // color: _colorAnimation2.value,
+ border: Border.all(
+ color: Colors.white,
+ width: 2,
+ ),
+ borderRadius: BorderRadius.circular(SizeConfig.safeBlockVertical*2),
+ ),
+ duration: const Duration(milliseconds: 500),
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 100),
+ margin: const EdgeInsets.all(10),
+ child: Image(
+ width: SizeConfig.screenWidth*0.15,
+ height: SizeConfig.screenHeight*0.10,
+ image: Svg(widget.img),
+ color: _colorAnimation.value,
+ ),
+ ),
+ ),
+ onTap: () {
+ isFreshAirCirculateActive ? _controller.reverse() : _controller.forward();
+ ref
+ .read(vehicleProvider.notifier)
+ .update(isFreshAirCirculateActive: !isFreshAirCirculateActive);
+ },
+ );
+
+ });
+ }
+}
diff --git a/lib/config.dart b/lib/config.dart
new file mode 100644
index 0000000..db7266e
--- /dev/null
+++ b/lib/config.dart
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:flutter_hvac/kuksa-server/intial_connection.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:yaml/yaml.dart';
+
+
+class GetConfig extends ConsumerStatefulWidget {
+ const GetConfig({Key? key, required this.client}) : super(key: key);
+ final HttpClient client;
+
+ @override
+ ConsumerState<GetConfig> createState() => _GetConfigState();
+}
+
+class _GetConfigState extends ConsumerState<GetConfig> {
+ @override
+ void initState() {
+ super.initState();
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+ final configStateProvider = ref.read(ConfigStateprovider.notifier);
+
+ String configFilePath = '/etc/xdg/AGL/HVAC_config.yaml';
+
+
+ final configFile = File(configFilePath);
+ configFile.readAsString().then((content) {
+ final dynamic yamlMap = loadYaml(content);
+ configStateProvider.update(
+ hostname: yamlMap['hostname'],
+ port: yamlMap['port'],
+ kuksaAuthToken: yamlMap['kuskaAuthToken'],
+ );
+ });
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final config = ref.watch(ConfigStateprovider);
+ if (config.hostname == "" ||
+ config.port == 0 ||
+ config.kuksaAuthToken == ""
+ ) {
+ return Scaffold(
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: const [
+ Text("ERROR",
+ style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
+ Text(
+ "Something Wrong with config file! Check config.yaml file and restart"),
+ ],
+ )),
+ );
+ }
+ return InitialScreen(client: widget.client);
+ }
+}
+
+class Config {
+ Config({
+ required this.hostname,
+ required this.port,
+ required this.kuksaAuthToken,
+
+ });
+ final String hostname;
+ final int port;
+ final String kuksaAuthToken;
+
+ Config copywith({
+ String? hostname,
+ int? port,
+ String? kuksaAuthToken,
+ String? mapboxAccessToken,
+ }) =>
+ Config(
+ hostname: hostname ?? this.hostname,
+ port: port ?? this.port,
+ kuksaAuthToken: kuksaAuthToken ?? this.kuksaAuthToken,
+ );
+}
+
+final ConfigStateprovider =
+StateNotifierProvider<ConfigStateNotifier, Config>(
+ (ref) => ConfigStateNotifier());
+
+class ConfigStateNotifier extends StateNotifier<Config> {
+ ConfigStateNotifier() : super(_initialValue);
+ static final Config _initialValue = Config(
+ hostname: "",
+ port: 0,
+ kuksaAuthToken: "",
+ );
+ void update({
+ String? hostname,
+ int? port,
+ String? kuksaAuthToken,
+ }) {
+ state = state.copywith(
+ hostname: hostname,
+ port: port,
+ kuksaAuthToken: kuksaAuthToken,
+ );
+ }
+}
diff --git a/lib/home_page.dart b/lib/home_page.dart
new file mode 100644
index 0000000..481fef0
--- /dev/null
+++ b/lib/home_page.dart
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: Apache-2.0
+
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_hvac/Buttons/fresh_air.dart';
+import 'package:flutter_svg_provider/flutter_svg_provider.dart';
+import 'package:flutter_hvac/Buttons/AC.dart';
+import 'package:flutter_hvac/Buttons/ac_on_face.dart';
+import 'package:flutter_hvac/Buttons/ac_on_foot.dart';
+import 'package:flutter_hvac/Buttons/defrost_recirculate.dart';
+import 'package:flutter_hvac/size.dart';
+import 'package:flutter_hvac/slider/Climate_slider.dart';
+import 'package:flutter_hvac/slider/Right_climate_slider.dart';
+
+import 'Buttons/auto.dart';
+import 'widgets/Right_climate.dart';
+import 'widgets/left_climate.dart';
+import 'slider/slider.dart';
+
+class MyHome_Page extends StatelessWidget {
+ final WebSocket socket;
+ MyHome_Page({Key? key, required this.socket}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ SizeConfig().init(context);
+
+ return Scaffold(
+ backgroundColor: Colors.black54,
+ body: Flex(direction: Axis.vertical,
+ children: [
+ Flexible(
+ flex: 4,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Row(
+ children: [
+
+ ClimateSliderControlLeft(),
+ SizedBox(width: SizeConfig.blockSizeHorizontal*4,),
+
+
+ Column(
+ children: [
+ Text(
+ 'L CLIMATE',
+ style: TextStyle(
+ fontSize: SizeConfig.fontsize*4,
+ fontWeight: FontWeight.w700,
+ color: Colors.lightBlueAccent,
+ ),
+ ),
+
+ SizedBox(
+ height: SizeConfig.screenHeight/10,
+ width: SizeConfig.screenWidth/10,
+ child: Image.asset('images/left_climate.PNG')),
+
+ ScrollContainerLeft(
+ socket: socket,
+ ),
+ ],
+ ),
+
+
+ ],
+ ),
+ Row(
+ // mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+
+ Column(
+ children: [
+ Text(
+ 'R CLIMATE',
+ style: TextStyle(
+ fontSize: SizeConfig.fontsize*4,
+ fontWeight: FontWeight.w700,
+ color: Colors.lightBlueAccent,
+ ),
+ ),
+ SizedBox(
+ height: SizeConfig.screenHeight/10,
+ width: SizeConfig.screenWidth/10,
+ child: Image.asset('images/right_climate.PNG')),
+
+ ScrollContainerRight(
+ socket: socket,
+ ),
+ ],
+ ),
+ SizedBox(width: SizeConfig.blockSizeHorizontal*4,),
+
+ ClimateSliderControlRight(),
+ ],
+ ),
+
+ ],
+ )),
+ Flexible(
+ flex: 2,
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Image(
+ width: SizeConfig.screenWidth*0.20,
+ height: SizeConfig.screenHeight*0.25,
+ image: Svg('images/fan.svg'),
+ color: Colors.lightBlueAccent,
+ ),
+ SliderControl(
+ socket: socket,
+ )
+ ],
+ )),
+ Flexible(
+ flex: 3,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Column(
+ children: [
+ AC(
+ socket: socket,
+ serverPath: 'Vehicle.Cabin.HVAC.IsAirConditioningActive'),
+ SizedBox(height: SizeConfig.safeBlockVertical,),
+
+ AcOnFoot(
+ img: 'images/ac_on_foot.svg',
+ socket: socket,
+ ),
+ SizedBox(height: SizeConfig.safeBlockVertical,),
+
+ AcOnFace(
+ img: 'images/ac_on_face.svg',
+ socket: socket,
+ ),
+ ],
+ ),
+ Row(
+ children: [
+ Auto(serverPath: '', socket: socket),
+ SizedBox(width: SizeConfig.safeBlockHorizontal,),
+ FreshAir(serverPath: '', socket: socket, img: 'images/wind_in.svg'),
+ ],
+ ),
+ Column(
+ children: [
+ CaustomButton(
+ serverPath: 'Vehicle.Cabin.HVAC.IsRecirculationActive',
+ socket: socket,
+ img: 'images/in_out.svg',
+ type: 'Recirculation'),
+ SizedBox(height: SizeConfig.safeBlockVertical,),
+ CaustomButton(
+ serverPath: 'Vehicle.Cabin.HVAC.IsRearDefrosterActive',
+ socket: socket,
+ img: 'images/rear_ws.svg',
+ type: 'Rear_defrost'),
+ SizedBox(height: SizeConfig.safeBlockVertical,),
+
+ CaustomButton(
+ serverPath: 'Vehicle.Cabin.HVAC.IsFrontDefrosterActive',
+ socket: socket,
+ img: 'images/wind_shield.svg',
+ type: 'Front_defrost'),
+ ],
+ ),
+ ],
+ )),
+ ],
+
+
+ ),
+ );
+ }
+}
diff --git a/lib/kuksa-server/intial_connection.dart b/lib/kuksa-server/intial_connection.dart
new file mode 100644
index 0000000..0ba4e9f
--- /dev/null
+++ b/lib/kuksa-server/intial_connection.dart
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle_config.dart';
+
+import 'on_boarding_page.dart';
+
+class InitialScreen extends ConsumerWidget {
+ InitialScreen({Key? key, required this.client}) : super(key: key);
+ final HttpClient client;
+ late WebSocket socket;
+
+ @override
+ Widget build(BuildContext context, ref) {
+ final sockConnect = ref.watch(sockConnectprovider(client));
+
+ return sockConnect.when(
+ data: (socket) {
+ this.socket = socket;
+ this.socket.pingInterval = const Duration(seconds: 2);
+ return OnBoardingPage(client: client, socket: this.socket);
+ },
+ error: (e, stk) {
+ print(e);
+ ref.refresh(sockConnectprovider(client));
+ return const Scaffold(
+ backgroundColor: Colors.black,
+ body: Center(
+ child: Text(
+ 'error',
+ style: TextStyle(color: Colors.white),
+ )),
+ );
+ },
+ loading: () => const Scaffold(
+ backgroundColor: Colors.black,
+ body: Center(
+ child: Text('loading', style: TextStyle(color: Colors.white))),
+ ),
+ );
+ }
+}
diff --git a/lib/kuksa-server/on_boarding_page.dart b/lib/kuksa-server/on_boarding_page.dart
new file mode 100644
index 0000000..a14145c
--- /dev/null
+++ b/lib/kuksa-server/on_boarding_page.dart
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle_config.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle_methods.dart';
+
+import '../home_page.dart';
+
+class OnBoardingPage extends ConsumerStatefulWidget {
+ const OnBoardingPage({Key? key, required this.client, required this.socket})
+ : super(key: key);
+ final WebSocket socket;
+ final HttpClient client;
+
+ @override
+ ConsumerState<OnBoardingPage> createState() => _OnBoardingPageState();
+}
+
+class _OnBoardingPageState extends ConsumerState<OnBoardingPage> {
+ late Timer _timer;
+ late WebSocket _socket;
+
+
+ @override
+ void initState() {
+ super.initState();
+ _socket = widget.socket;
+ VISS.init(widget.socket,ref);
+ _timer = Timer.periodic(const Duration(seconds: 2), (timer) {
+
+ if (widget.socket.readyState == 3) {
+ ref.refresh(sockConnectprovider(widget.client));
+ }
+ });
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+ widget.socket.listen(
+ (data) {
+
+ },
+ onError: (e, stk) {
+ print(e.toString());
+ ref.refresh(sockConnectprovider(widget.client));
+ },
+ );
+ });
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ _timer.cancel();
+ widget.socket.close(786887, "Connection lost with server!");
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return MyHome_Page(
+ socket: _socket,
+ );
+ }
+}
diff --git a/lib/kuksa-server/vehicle-class.dart b/lib/kuksa-server/vehicle-class.dart
new file mode 100644
index 0000000..a04ad90
--- /dev/null
+++ b/lib/kuksa-server/vehicle-class.dart
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: Apache-2.0
+
+class vehicle {
+ late bool isAcActive;
+ late bool isFrontDefrosterActive;
+ late bool isRearDefrosterActive;
+ late bool isAcDirectionUp;
+ late bool isAcDirectionDown;
+ late bool isAcDirectionMiddle;
+ late bool isRecirculationActive;
+ late bool isAutoActive;
+ late bool isFreshAirCirculateActive;
+
+ vehicle({
+ required this.isAcActive,
+ required this.isAcDirectionDown,
+ required this.isAcDirectionMiddle,
+ required this.isAcDirectionUp,
+ required this.isFrontDefrosterActive,
+ required this.isRearDefrosterActive,
+ required this.isRecirculationActive,
+ required this.isAutoActive,
+ required this.isFreshAirCirculateActive,
+ });
+
+ vehicle copywith({
+ bool? isAcActive,
+ bool? isAcDirectionDown,
+ bool? isAcDirectionMiddle,
+ bool? isAcDirectionUp,
+ bool? isFrontDefrosterActive,
+ bool? isRearDefrosterActive,
+ bool? isRecirculationActive,
+ bool? isAutoActive,
+ bool? isFreshAirCirculateActive,
+ }) {
+ return vehicle(
+ isAcActive: isAcActive ?? this.isAcActive,
+ isAcDirectionDown: isAcDirectionDown ?? this.isAcDirectionDown,
+ isAcDirectionMiddle: isAcDirectionMiddle ?? this.isAcDirectionMiddle,
+ isAcDirectionUp: isAcDirectionUp ?? this.isAcDirectionUp,
+ isFrontDefrosterActive:
+ isFrontDefrosterActive ?? this.isFrontDefrosterActive,
+ isRearDefrosterActive:
+ isRearDefrosterActive ?? this.isRearDefrosterActive,
+ isRecirculationActive:
+ isRecirculationActive ?? this.isRecirculationActive,
+ isAutoActive: isAutoActive ?? this.isAutoActive,
+ isFreshAirCirculateActive: isFreshAirCirculateActive ?? this.isFreshAirCirculateActive,
+
+ );
+ }
+}
diff --git a/lib/kuksa-server/vehicle-provider.dart b/lib/kuksa-server/vehicle-provider.dart
new file mode 100644
index 0000000..f070a53
--- /dev/null
+++ b/lib/kuksa-server/vehicle-provider.dart
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle-class.dart';
+
+final vehicleProvider = StateNotifierProvider<VehicleSignal, vehicle>(
+ (ref) => VehicleSignal(),
+);
+
+class VehicleSignal extends StateNotifier<vehicle> {
+ static vehicle intial_value = vehicle(
+ isAcActive: false,
+ isAcDirectionDown: false,
+ isAcDirectionMiddle: false,
+ isAcDirectionUp: false,
+ isFrontDefrosterActive: false,
+ isRearDefrosterActive: false,
+ isRecirculationActive: false,
+ isAutoActive: false,
+ isFreshAirCirculateActive : false,
+ );
+ VehicleSignal() : super(intial_value);
+
+ void update({
+ bool? isAcActive,
+ bool? isAcDirectionDown,
+ bool? isAcDirectionUp,
+ bool? isAcDirectionMiddle,
+ bool? isFrontDefrosterActive,
+ bool? isRearDefrosterActive,
+ bool? isRecirculationActive,
+ bool? isAutoActive,
+ bool? isFreshAirCirculateActive,
+ }) {
+ state = state.copywith(
+ isAcActive: isAcActive,
+ isAcDirectionDown: isAcDirectionDown,
+ isAcDirectionMiddle: isAcDirectionMiddle,
+ isAcDirectionUp: isAcDirectionUp,
+ isFrontDefrosterActive: isFrontDefrosterActive,
+ isRearDefrosterActive: isRearDefrosterActive,
+ isRecirculationActive: isRecirculationActive,
+ isAutoActive : isAutoActive,
+ isFreshAirCirculateActive : isFreshAirCirculateActive,
+ );
+ }
+}
diff --git a/lib/kuksa-server/vehicle_config.dart b/lib/kuksa-server/vehicle_config.dart
new file mode 100644
index 0000000..6eff800
--- /dev/null
+++ b/lib/kuksa-server/vehicle_config.dart
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: Apache-2.0
+
+
+import 'dart:io';
+import 'package:flutter_hvac/config.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:http/http.dart' as http;
+
+
+
+final sockConnectprovider = FutureProvider.family<WebSocket, HttpClient>(
+ (ref, client) => connect(client,ref));
+
+
+
+// load certificates and set context and returns http client
+Future<HttpClient> initializeClient() async {
+
+
+ SecurityContext ctx = SecurityContext.defaultContext;
+
+ HttpClient client = HttpClient(context: ctx)
+ ..findProxy = null
+ ..badCertificateCallback = (cert, host, port) {
+ return true;
+ };
+ return client;
+}
+
+
+
+Future<WebSocket> connect(HttpClient client, ref) async {
+ final config = ref.read(ConfigStateprovider);
+ WebSocket socket = await WebSocket.connect(
+ "wss://${config.hostname}:${config.port}",
+ customClient: client);
+ return socket;
+}
+
diff --git a/lib/kuksa-server/vehicle_methods.dart b/lib/kuksa-server/vehicle_methods.dart
new file mode 100644
index 0000000..2dda79f
--- /dev/null
+++ b/lib/kuksa-server/vehicle_methods.dart
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:flutter_hvac/config.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle_server_path.dart';
+
+
+class VISS {
+ static const requestId = "test-id";
+ static void init(WebSocket socket,WidgetRef ref) {
+ authorize(socket,ref);
+
+ subscribe(socket,ref, VSPath.vehicleFrontLeftTier);
+ subscribe(socket,ref, VSPath.vehicleFrontRightTier);
+ subscribe(socket,ref, VSPath.vehicleRearLeftTier);
+ subscribe(socket,ref, VSPath.vehicleRearRightTier);
+ subscribe(socket,ref, VSPath.vehicleIsChildLockActiveLeft);
+ subscribe(socket,ref, VSPath.vehicleIsChildLockActiveRight);
+ subscribe(socket,ref, VSPath.vehicleCurrentLatitude);
+ subscribe(socket,ref, VSPath.vehicleCurrentLongitude);
+ subscribe(socket,ref, VSPath.vehicleInsideTemperature);
+ subscribe(socket,ref, VSPath.vehicleAmbientAirTemperature);
+ }
+
+ static void update(WebSocket socket,WidgetRef ref) {
+ get(socket,ref, VSPath.vehicleAmbientAirTemperature);
+ get(socket,ref, VSPath.vehicleTrunkLocked);
+ get(socket, ref,VSPath.vehicleTrunkOpen);
+
+ get(socket,ref, VSPath.vehicleFrontLeftTier);
+ get(socket,ref, VSPath.vehicleFrontRightTier);
+ get(socket,ref, VSPath.vehicleRearLeftTier);
+ get(socket,ref, VSPath.vehicleRearRightTier);
+ get(socket,ref, VSPath.vehicleIsChildLockActiveLeft);
+ get(socket,ref, VSPath.vehicleIsChildLockActiveRight);
+ get(socket,ref, VSPath.vehicleCurrentLatitude);
+ get(socket,ref, VSPath.vehicleCurrentLongitude);
+ get(socket,ref, VSPath.vehicleInsideTemperature);
+ }
+
+ static void authorize(WebSocket socket,WidgetRef ref) {
+ final config = ref.read(ConfigStateprovider);
+ Map<String, dynamic> map = {
+ "action": "authorize",
+ "tokens": config.kuksaAuthToken,
+ "requestId": requestId
+ };
+ socket.add(jsonEncode(map));
+ }
+
+ static void get(WebSocket socket,WidgetRef ref ,String path) {
+ final config = ref.read(ConfigStateprovider);
+
+ Map<String, dynamic> map = {
+ "action": "get",
+ "tokens": config.kuksaAuthToken,
+ "path": path,
+ "requestId": requestId
+ };
+ socket.add(jsonEncode(map));
+ }
+
+ static void set(
+ WebSocket socket,
+ WidgetRef ref,
+ String path,
+ String value,
+ ) {
+ final config = ref.read(ConfigStateprovider);
+
+ Map<String, dynamic> map = {
+ "action": "set",
+ "tokens": config.kuksaAuthToken,
+ "path": path,
+ "requestId": requestId,
+ "value": value
+ };
+ socket.add(jsonEncode(map));
+ }
+
+ static void subscribe(WebSocket socket,WidgetRef ref, String path) {
+ final config = ref.read(ConfigStateprovider);
+
+ Map<String, dynamic> map = {
+ "action": "subscribe",
+ "tokens": config.kuksaAuthToken,
+ "path": path,
+ "requestId": requestId
+ };
+ socket.add(jsonEncode(map));
+ }
+
+
+}
diff --git a/lib/kuksa-server/vehicle_server_path.dart b/lib/kuksa-server/vehicle_server_path.dart
new file mode 100644
index 0000000..c61c3ca
--- /dev/null
+++ b/lib/kuksa-server/vehicle_server_path.dart
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: Apache-2.0
+
+
+class VSPath {
+
+
+ static const String vehicleTrunkLocked = "Vehicle.Body.Trunk.IsLocked";
+ static const String vehicleTrunkOpen = "Vehicle.Body.Trunk.IsOpen";
+
+
+ static const String vehicleAmbientAirTemperature =
+ "Vehicle.AmbientAirTemperature";
+
+ static const String vehicleFrontLeftTier =
+ "Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.Pressure";
+ static const String vehicleFrontRightTier =
+ "Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.Pressure";
+ static const String vehicleRearLeftTier =
+ "Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.Pressure";
+
+ static const String vehicleRearRightTier =
+ "Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.Pressure";
+ static const String vehicleIsChildLockActiveLeft =
+ "Vehicle.Cabin.Door.Row2.Left.IsChildLockActive";
+ static const String vehicleIsChildLockActiveRight =
+ "Vehicle.Cabin.Door.Row2.Right.IsChildLockActive";
+ static const String vehicleCurrentLongitude =
+ "Vehicle.CurrentLocation.Longitude";
+ static const String vehicleCurrentLatitude =
+ "Vehicle.CurrentLocation.Latitude";
+
+ static const String vehicleInsideTemperature =
+ "Vehicle.Cabin.HVAC.AmbientAirTemperature";
+ static const String vehicleFrontLeftAc =
+ "Vehicle.Cabin.HVAC.Station.Row1.Left.AirDistribution";
+}
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 0000000..b2758de
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_hvac/config.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'kuksa-server/vehicle_config.dart';
+
+
+
+Future<void> main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ HttpClient client = await initializeClient();
+
+ runApp(
+ ProviderScope(
+ child: MaterialApp(
+ home: GetConfig(client: client),
+ ),
+ ),
+ );
+}
diff --git a/lib/provider.dart b/lib/provider.dart
new file mode 100644
index 0000000..c933fdd
--- /dev/null
+++ b/lib/provider.dart
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+final LeftSlider = StateNotifierProvider<leftclimate, int>(
+ (ref) => leftclimate(),
+);
+
+class leftclimate extends StateNotifier<int> {
+ leftclimate() : super(0);
+
+ Future<void> update(value) async {
+ state = value;
+ }
+}
+
+final RightSlider = StateNotifierProvider<Rightclimate, int>(
+ (ref) => Rightclimate(),
+);
+
+class Rightclimate extends StateNotifier<int> {
+ Rightclimate() : super(0);
+
+ Future<void> update(value) async {
+ state = value;
+ }
+}
+
+final fanSpeedProvider =
+ StateNotifierProvider<fanslider, int>((ref) => fanslider());
+
+class fanslider extends StateNotifier<int> {
+ fanslider() : super(30);
+ void update(value) {
+ state = value;
+ }
+}
diff --git a/lib/size.dart b/lib/size.dart
new file mode 100644
index 0000000..a572ad2
--- /dev/null
+++ b/lib/size.dart
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+
+class SizeConfig {
+ static late MediaQueryData _mediaQueryData;
+ static late double screenWidth;
+ static late double screenHeight;
+ static late double blockSizeHorizontal;
+ static late double blockSizeVertical;
+ static late double _safeAreaHorizontal;
+ static late double _safeAreaVertical;
+ static late double safeBlockHorizontal;
+ static late double safeBlockVertical;
+ static late double fontsize;
+ static late TextStyle normalfont;
+ static late TextStyle smallnormalfont;
+ static late TextStyle smallnormalfont2;
+
+ void init(BuildContext context) {
+ _mediaQueryData = MediaQuery.of(context);
+ screenWidth = _mediaQueryData.size.width;
+ screenHeight = _mediaQueryData.size.height;
+ blockSizeHorizontal = screenWidth / 100;
+ blockSizeVertical = screenHeight / 100;
+ _safeAreaHorizontal =
+ _mediaQueryData.padding.left + _mediaQueryData.padding.right;
+ _safeAreaVertical =
+ _mediaQueryData.padding.top + _mediaQueryData.padding.bottom;
+ safeBlockHorizontal = (screenWidth - _safeAreaHorizontal) / 100;
+ safeBlockVertical = (screenHeight - _safeAreaVertical) / 100;
+ fontsize = screenHeight * screenWidth * 0.01 * 0.01 * 0.1;
+ // fontsize= blockSizeVertical*2;
+ normalfont = TextStyle(
+ fontSize: fontsize,
+ fontWeight: FontWeight.w700,
+ color: Colors.white,
+ );
+ smallnormalfont = TextStyle(
+ fontSize: fontsize / 2,
+ fontWeight: FontWeight.w700,
+ color: Colors.white,
+ );
+ smallnormalfont2 = TextStyle(
+ fontSize: fontsize * 0.4,
+ color: Colors.white,
+ );
+ }
+}
diff --git a/lib/slider/Climate_slider.dart b/lib/slider/Climate_slider.dart
new file mode 100644
index 0000000..b0a0d6f
--- /dev/null
+++ b/lib/slider/Climate_slider.dart
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_hvac/provider.dart';
+
+import '../size.dart';
+
+class ClimateSliderControlLeft extends ConsumerWidget {
+ const ClimateSliderControlLeft({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context,ref) {
+ int val = ref.watch(LeftSlider).toInt();
+
+ return SizedBox(
+ height: SizeConfig.screenHeight*0.35,
+ width: SizeConfig.blockSizeHorizontal*3,
+ child: RotatedBox(
+ quarterTurns: 3,
+ child: Slider(
+ min: 0,
+ max: 15,
+ value: val.toDouble(),
+ divisions: 15,
+ onChanged: (value) {
+ ref.read(LeftSlider.notifier).update(value.toInt());
+ },
+ activeColor: Colors.green,
+ inactiveColor: Colors.white,
+ thumbColor: Colors.grey,
+ ),
+
+ ),
+ );
+
+ }
+}
diff --git a/lib/slider/Right_climate_slider.dart b/lib/slider/Right_climate_slider.dart
new file mode 100644
index 0000000..536d11c
--- /dev/null
+++ b/lib/slider/Right_climate_slider.dart
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_hvac/provider.dart';
+
+import '../size.dart';
+
+class ClimateSliderControlRight extends ConsumerWidget {
+ const ClimateSliderControlRight({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context, ref) {
+ int val = ref.watch(RightSlider).toInt();
+ return SizedBox(
+ height: SizeConfig.screenHeight*0.35,
+ width: SizeConfig.blockSizeHorizontal*3,
+ child: RotatedBox(
+ quarterTurns: 3,
+ child: Slider(
+ min: 0,
+ max: 15,
+ value: val.toDouble(),
+ divisions: 15,
+ onChanged: (value) {
+ ref.read(RightSlider.notifier).update(value.toInt());
+ },
+ activeColor: Colors.green,
+ inactiveColor: Colors.white,
+ thumbColor: Colors.grey,
+ ),
+
+ ),
+ );
+ }
+}
diff --git a/lib/slider/slider.dart b/lib/slider/slider.dart
new file mode 100644
index 0000000..1d2de82
--- /dev/null
+++ b/lib/slider/slider.dart
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_hvac/provider.dart';
+
+import '../kuksa-server/vehicle_methods.dart';
+import '../size.dart';
+
+class SliderControl extends ConsumerWidget {
+ WebSocket socket;
+ SliderControl({Key? key, required this.socket}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context, ref) {
+ return SizedBox(
+ height: SizeConfig.safeBlockVertical*2,
+ width: SizeConfig.screenWidth*0.5,
+
+ child: Slider(
+ value: ref.watch(fanSpeedProvider).toDouble(),
+ onChanged: (value) {
+ ref.read(fanSpeedProvider.notifier).update(value.toInt());
+ VISS.set(socket, ref,'Vehicle.Cabin.HVAC.Station.Row1.Left.FanSpeed',
+ value.toInt().toString());
+ VISS.set(socket, ref,'Vehicle.Cabin.HVAC.Station.Row1.Right.FanSpeed',
+ value.toInt().toString());
+ VISS.set(socket, ref,'Vehicle.Cabin.HVAC.Station.Row2.Left.FanSpeed',
+ value.toInt().toString());
+ VISS.set(socket,ref, 'Vehicle.Cabin.HVAC.Station.Row2.Right.FanSpeed',
+ value.toInt().toString());
+ },
+ min: 0,
+ max: 100,
+ activeColor: Colors.green,
+ inactiveColor: Colors.white70,
+ thumbColor: Colors.grey,
+ label: 'fan speed',
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/Right_climate.dart b/lib/widgets/Right_climate.dart
new file mode 100644
index 0000000..d47a659
--- /dev/null
+++ b/lib/widgets/Right_climate.dart
@@ -0,0 +1,115 @@
+
+// SPDX-License-Identifier: Apache-2.0
+
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
+import 'package:flutter_hvac/kuksa-server/vehicle_methods.dart';
+import 'package:flutter_hvac/provider.dart';
+import 'package:flutter_hvac/size.dart';
+
+class ScrollContainerRight extends ConsumerWidget {
+ WebSocket socket;
+ ScrollContainerRight({Key? key, required this.socket}) : super(key: key);
+
+ List<int> mylist = [
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ ];
+
+
+ final ItemScrollController itemScrollController = ItemScrollController();
+ final ItemPositionsListener itemPositionsListener =
+ ItemPositionsListener.create();
+
+ @override
+ Widget build(BuildContext context, ref) {
+ int val = ref.watch(RightSlider).toInt();
+
+ VISS.set(socket,ref, 'Vehicle.Cabin.HVAC.Station.Row1.Right.Temperature',
+ mylist[val].toString());
+ VISS.set(socket, ref,'Vehicle.Cabin.HVAC.Station.Row2.Right.Temperature',
+ mylist[val].toString());
+
+ if (itemScrollController.isAttached) {
+ itemScrollController.scrollTo(
+ index: val.toInt()+2,
+ duration: Duration(milliseconds: 500),
+ curve: Curves.easeInOutCubic,
+ alignment: 1);
+ }
+
+
+ return SingleChildScrollView(
+ child: SizedBox(
+ height: SizeConfig.screenHeight*0.30,
+ width: SizeConfig.screenWidth*0.25,
+ child: AnimatedContainer(
+ // color: Colors.red,
+ duration: Duration(milliseconds: 300),
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: Colors.white,
+ width: 2,
+ ),
+ borderRadius: BorderRadius.circular(12),
+ ),
+ child: ScrollablePositionedList.builder(
+ physics: NeverScrollableScrollPhysics(),
+ scrollDirection: Axis.vertical,
+ itemCount: mylist.length,
+ itemScrollController: itemScrollController,
+ itemPositionsListener: itemPositionsListener,
+ itemBuilder: (context, index) {
+ return Container(
+ decoration: BoxDecoration(
+
+ gradient: index == val
+ ? RadialGradient(
+ colors: [Colors.white54, Colors.black], radius: SizeConfig.safeBlockVertical*0.7)
+ : null,
+ ),
+ child: ListTile(
+ subtitle: Center(
+ child: Text(
+ '' + mylist[index].toString() + '°',
+ style: index == val ? TextStyle(
+ color: Colors.lightBlueAccent,
+ fontWeight: FontWeight.w700,
+ fontSize: SizeConfig.fontsize*4,
+ ):TextStyle(
+ color: Colors.white54,
+ fontWeight: FontWeight.w700,
+ fontSize: SizeConfig.fontsize*4,
+ ),
+ ),
+ ),
+
+ minVerticalPadding: 5,
+
+ ),
+ );
+ }),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/left_climate.dart b/lib/widgets/left_climate.dart
new file mode 100644
index 0000000..2fb30a0
--- /dev/null
+++ b/lib/widgets/left_climate.dart
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
+import 'package:flutter_hvac/provider.dart';
+import 'dart:io';
+
+import '../kuksa-server/vehicle_methods.dart';
+import '../size.dart';
+
+class ScrollContainerLeft extends ConsumerWidget {
+ WebSocket socket;
+ ScrollContainerLeft({Key? key, required this.socket}) : super(key: key);
+
+ List<int> mylist = [
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32
+ ];
+
+
+ final ItemScrollController itemScrollController = ItemScrollController();
+ final ItemPositionsListener itemPositionsListener =
+ ItemPositionsListener.create();
+ @override
+ Widget build(BuildContext context, ref) {
+ int val = ref.watch(LeftSlider).toInt();
+
+ VISS.set(socket,ref, 'Vehicle.Cabin.HVAC.Station.Row1.Left.Temperature',
+ mylist[val].toString());
+ VISS.set(socket,ref, 'Vehicle.Cabin.HVAC.Station.Row2.Left.Temperature',
+ mylist[val].toString());
+
+
+ if (itemScrollController.isAttached) {
+ itemScrollController.scrollTo(
+ index: val.toInt() + 2,
+ duration: Duration(milliseconds: 500),
+ curve: Curves.easeInOutCubic,
+ alignment: 1);
+ }
+
+ return SingleChildScrollView(
+ child: SizedBox(
+ height: SizeConfig.screenHeight*0.30,
+ width: SizeConfig.screenWidth*0.25,
+ child: AnimatedContainer(
+ // color: Colors.red,
+ duration: Duration(milliseconds: 500),
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: Colors.white,
+ width: 2,
+ ),
+ borderRadius: BorderRadius.circular(12),
+ ),
+ child: ScrollablePositionedList.builder(
+ physics: NeverScrollableScrollPhysics(),
+ scrollDirection: Axis.vertical,
+ itemCount: mylist.length,
+ itemScrollController: itemScrollController,
+ itemPositionsListener: itemPositionsListener,
+ itemBuilder: (context, index) {
+ return Container(
+ decoration: BoxDecoration(
+
+ gradient: index == val
+ ? RadialGradient(
+ colors: [Colors.white54, Colors.black], radius: SizeConfig.safeBlockVertical*0.7)
+ : null,
+ ),
+ child: ListTile(
+ subtitle: Center(
+ child: Text(
+ '' + mylist[index].toString() + '°',
+ style: index == val ? TextStyle(
+ color: Colors.lightBlueAccent,
+ fontWeight: FontWeight.w700,
+ fontSize: SizeConfig.fontsize*4,
+ ):TextStyle(
+ color: Colors.white54,
+ fontWeight: FontWeight.w700,
+ fontSize: SizeConfig.fontsize*4,
+ ),
+ ),
+ ),
+ // tileColor: Colors.red,
+ minVerticalPadding: 5,
+ // selectedTileColor: ,
+ ),
+ );
+ }),
+ ),
+ ),
+ );
+ }
+}