summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitreview5
-rw-r--r--License.md201
-rw-r--r--images/ac_on_face.svg52
-rw-r--r--images/ac_on_foot.svg52
-rw-r--r--images/face_foot.svg76
-rw-r--r--images/fan.svg1
-rw-r--r--images/in_out.svg85
-rw-r--r--images/left_climate.PNGbin0 -> 26668 bytes
-rw-r--r--images/rear_ws.svg61
-rw-r--r--images/right_climate.PNGbin0 -> 27493 bytes
-rw-r--r--images/wind_in.svg81
-rw-r--r--images/wind_shield.svg67
-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
-rw-r--r--pubspec.yaml95
36 files changed, 2723 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..6f9dc04
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.automotivelinux.org
+port=29418
+project=apps/flutter-hvac
+defaultbranch=master
diff --git a/License.md b/License.md
new file mode 100644
index 0000000..a0b7d15
--- /dev/null
+++ b/License.md
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [2022] [Hritik Chouhan]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/images/ac_on_face.svg b/images/ac_on_face.svg
new file mode 100644
index 0000000..3ab2d40
--- /dev/null
+++ b/images/ac_on_face.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 454.521 454.521" style="enable-background:new 0 0 454.521 454.521;" xml:space="preserve">
+<g>
+ <path d="M360.778,127.298L360.778,127.298c-13.676-3.736-27.988-1.925-40.3,5.104c-12.313,7.028-21.151,18.43-24.888,32.104
+ l-27.318,99.971H165.363c-3.979,0-7.794,1.58-10.606,4.394l-95.048,95.048c-10.024,10.024-15.546,23.353-15.546,37.529
+ s5.521,27.505,15.546,37.529s23.353,15.545,37.529,15.545s27.505-5.521,37.528-15.545l68.352-68.352h86.295
+ c35.266,0,66.387-23.759,75.682-57.775l32.891-120.364c3.736-13.676,1.925-27.987-5.103-40.3
+ C385.854,139.874,374.453,131.035,360.778,127.298z M289.413,340.625h-92.508c-3.979,0-7.794,1.58-10.606,4.394l-72.746,72.745
+ c-4.357,4.358-10.151,6.758-16.314,6.758s-11.958-2.399-16.316-6.758s-6.759-10.153-6.759-16.316s2.4-11.957,6.759-16.315
+ l90.654-90.655h108.147c6.762,0,12.688-4.523,14.47-11.046l30.337-111.018c3.353-12.273,16.063-19.531,28.341-16.176h-0.001
+ c12.273,3.354,19.53,16.067,16.176,28.34l-32.891,120.365C330.415,325.951,311.194,340.625,289.413,340.625z"/>
+ <path d="M352.856,115.006c31.707,0,57.503-25.796,57.503-57.503S384.563,0,352.856,0s-57.503,25.796-57.503,57.503
+ S321.149,115.006,352.856,115.006z M352.856,30c15.165,0,27.503,12.338,27.503,27.503s-12.338,27.503-27.503,27.503
+ s-27.503-12.338-27.503-27.503S337.691,30,352.856,30z"/>
+ <path d="M93.468,73.292H214.89c0.115,0,0.226-0.015,0.34-0.017v18.417c0,6.919,8.365,10.384,13.257,5.492l33.427-33.427
+ c3.033-3.033,3.033-7.95,0-10.983l-33.427-33.427c-4.892-4.893-13.257-1.427-13.257,5.491v18.472
+ c-0.114-0.002-0.225-0.017-0.34-0.017H93.468c-8.284,0-15,6.716-15,15S85.184,73.292,93.468,73.292z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/images/ac_on_foot.svg b/images/ac_on_foot.svg
new file mode 100644
index 0000000..29425aa
--- /dev/null
+++ b/images/ac_on_foot.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 454.521 454.521" style="enable-background:new 0 0 454.521 454.521;" xml:space="preserve">
+<g>
+ <path d="M402.126,127.298L402.126,127.298c-28.227-7.713-57.473,8.978-65.188,37.208l-27.317,99.971H206.712
+ c-3.979,0-7.794,1.58-10.606,4.394l-95.048,95.048c-10.024,10.024-15.546,23.353-15.546,37.529s5.521,27.505,15.545,37.529
+ c10.024,10.024,23.353,15.545,37.529,15.545s27.505-5.521,37.529-15.545l68.352-68.352h86.294
+ c35.265,0,66.387-23.758,75.683-57.775l32.89-120.364c3.736-13.676,1.925-27.987-5.103-40.3
+ C427.203,139.874,415.801,131.035,402.126,127.298z M238.254,340.625c-3.979,0-7.794,1.58-10.606,4.394l-72.745,72.745
+ c-8.998,8.996-23.638,8.996-32.632,0c-8.997-8.997-8.997-23.636,0-32.632l90.654-90.655h108.147c6.762,0,12.688-4.523,14.47-11.046
+ l30.336-111.017c3.354-12.272,16.065-19.527,28.341-16.177c5.944,1.625,10.901,5.468,13.957,10.819
+ c3.055,5.354,3.843,11.575,2.218,17.521l-32.89,120.364c-5.741,21.01-24.963,35.684-46.743,35.684H238.254z"/>
+ <path d="M394.205,115.006c31.707,0,57.503-25.796,57.503-57.503S425.912,0,394.205,0c-31.708,0-57.504,25.796-57.504,57.503
+ S362.497,115.006,394.205,115.006z M394.205,30c15.165,0,27.503,12.338,27.503,27.503s-12.338,27.503-27.503,27.503
+ c-15.166,0-27.504-12.338-27.504-27.503S379.039,30,394.205,30z"/>
+ <path d="M133.06,277.247c4.289,0,7.766-3.477,7.766-7.766v-47.273c0-6.919-8.365-10.384-13.257-5.492l-13.062,13.062
+ c-0.079-0.082-0.147-0.171-0.228-0.252L28.42,143.668c-5.857-5.857-15.355-5.857-21.213,0c-5.858,5.857-5.858,15.355,0,21.213
+ l85.858,85.858c0.081,0.081,0.17,0.149,0.252,0.228L80.295,263.99c-4.892,4.892-1.427,13.257,5.491,13.257H133.06z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/images/face_foot.svg b/images/face_foot.svg
new file mode 100644
index 0000000..e2bee93
--- /dev/null
+++ b/images/face_foot.svg
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<g>
+ <g>
+ <path style="fill:#34485C;" d="M507.586,44.138c0,24.373-19.765,44.138-44.138,44.138c-24.373,0-44.138-19.765-44.138-44.138
+ S439.075,0,463.448,0C487.821,0,507.586,19.765,507.586,44.138"/>
+ <path style="fill:#34485C;" d="M367.802,151.257l-48.87,141.639c-3.24,9.384-12.57,15.263-22.44,14.124l-89.538-10.284
+ c-8.766-1.095-16.993,4.414-19.315,12.932l-58.73,170.178c-2.18,7.998-0.468,16.87,5.411,22.713
+ c17.373,17.276,41.498,8.925,47.289-9.613l49.646-121.706c2.622-8.404,11.008-13.603,19.694-12.235l133.438,18.22
+ c10.037,1.368,19.633-4.555,22.908-14.133l60.646-177.443c9.869-28.866-6.638-60.072-36.043-68.167l0,0
+ C404.966,110.068,376.912,124.854,367.802,151.257"/>
+ </g>
+ <polygon style="fill:#74B73E;" points="313.379,79.448 233.931,0 233.931,44.138 92.69,44.138 92.69,114.759 233.931,114.759
+ 233.931,158.897 "/>
+ <path style="fill:#94CAFF;" d="M189.793,264.827L189.793,264.827c-60.195-11.847-119.305-11.697-176.552,0l0,0l-8.828-88.276
+ c54.175-11.794,141.506-11.75,194.207,0L189.793,264.827z"/>
+ <g>
+ <path style="fill:#4897F7;" d="M136.827,335.447c-2.348,0-4.687-0.927-6.426-2.772c-3.337-3.549-3.178-9.137,0.371-12.482
+ c3.858-3.637,14.883-16.746,14.883-28.884c0-6.126-3.046-12.332-5.738-17.805c-0.927-1.88-1.792-3.646-2.463-5.226
+ c-0.115-0.291-0.23-0.583-0.318-0.874c-0.477-1.05-1.033-2.18-1.615-3.381c-3.169-6.497-7.521-15.413-7.521-25.679
+ c0-10.266,4.343-19.165,7.521-25.662c0.759-1.545,1.457-2.975,2.013-4.273c1.898-4.484,7.071-6.594,11.573-4.67
+ c4.484,1.907,6.577,7.089,4.67,11.573c-0.653,1.554-1.492,3.275-2.392,5.12c-2.684,5.5-5.729,11.732-5.729,17.911
+ c0,6.188,3.046,12.429,5.729,17.938c0.9,1.845,1.739,3.566,2.392,5.111c0.124,0.291,0.23,0.574,0.318,0.865
+ c0.494,1.077,1.059,2.233,1.668,3.46c3.178,6.479,7.548,15.351,7.548,25.591c0,22.237-19.597,40.951-20.427,41.737
+ C141.179,334.653,138.999,335.447,136.827,335.447"/>
+ <path style="fill:#4897F7;" d="M92.69,335.447c-2.348,0-4.687-0.927-6.426-2.772c-3.337-3.549-3.178-9.137,0.371-12.482
+ c3.858-3.637,14.883-16.746,14.883-28.884c0-6.126-3.046-12.332-5.738-17.805c-0.927-1.88-1.792-3.646-2.463-5.226
+ c-0.115-0.291-0.23-0.583-0.318-0.874c-0.477-1.05-1.033-2.18-1.615-3.381c-3.169-6.497-7.521-15.413-7.521-25.679
+ c0-10.266,4.343-19.165,7.521-25.662c0.75-1.545,1.457-2.975,2.013-4.273c1.898-4.484,7.08-6.594,11.573-4.67
+ c4.484,1.907,6.577,7.089,4.67,11.573c-0.653,1.554-1.492,3.275-2.392,5.12c-2.684,5.5-5.729,11.732-5.729,17.911
+ c0,6.188,3.046,12.429,5.729,17.938c0.9,1.845,1.739,3.566,2.392,5.111c0.124,0.291,0.23,0.574,0.318,0.865
+ c0.494,1.077,1.059,2.233,1.668,3.46c3.178,6.479,7.548,15.351,7.548,25.591c0,22.237-19.597,40.951-20.427,41.737
+ C97.042,334.653,94.861,335.447,92.69,335.447"/>
+ <path style="fill:#4897F7;" d="M48.552,335.447c-2.348,0-4.687-0.927-6.426-2.772c-3.337-3.549-3.178-9.137,0.371-12.482
+ c3.858-3.637,14.883-16.746,14.883-28.884c0-6.126-3.046-12.332-5.738-17.805c-0.927-1.88-1.792-3.646-2.463-5.226
+ c-0.115-0.291-0.23-0.583-0.318-0.874c-0.477-1.05-1.033-2.18-1.615-3.381c-3.169-6.497-7.521-15.413-7.521-25.679
+ c0-10.266,4.343-19.165,7.521-25.662c0.75-1.545,1.457-2.975,2.013-4.273c1.898-4.484,7.071-6.594,11.573-4.67
+ c4.484,1.907,6.577,7.089,4.67,11.573c-0.653,1.554-1.492,3.275-2.392,5.12c-2.684,5.5-5.729,11.732-5.729,17.911
+ c0,6.188,3.046,12.429,5.729,17.938c0.9,1.845,1.739,3.566,2.392,5.111c0.124,0.291,0.23,0.574,0.318,0.865
+ c0.494,1.077,1.059,2.233,1.668,3.46c3.178,6.479,7.548,15.351,7.548,25.591c0,22.237-19.597,40.951-20.427,41.737
+ C52.904,334.653,50.723,335.447,48.552,335.447"/>
+ </g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/images/fan.svg b/images/fan.svg
new file mode 100644
index 0000000..4f0d6c0
--- /dev/null
+++ b/images/fan.svg
@@ -0,0 +1 @@
+<svg class="svg-icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M457.085 459.284c1.929-1.916 19.923-21.075 26.705-27.66 14.06-13.655 27.832-24.354 43.571-32.82 19.096-10.27 36.569-30.294 46.56-52.11 4.225-9.226 6.559-17.722 6.855-23.683-15.19-10.698-38.455-18.393-61.105-19.65-25.435-1.413-45.52 5.208-56.305 18.15-13.068 15.682-20.816 45.463-20.13 78.19 0.525 25.07 6.072 47.618 13.277 60.148 0.188-0.184 0.378-0.372 0.572-0.565z m-17.67-157.732c38.406-46.087 125.21-32.103 165.034 0 22.53 18.162-7.576 95.266-62.32 124.71-54.743 29.444-73.753 91.316-102.714 62.355-33.394-33.394-39.538-139.62 0-187.065z m125.3 155.533c1.917 1.929 21.076 19.923 27.662 26.705 13.654 14.06 24.353 27.832 32.819 43.571 10.27 19.096 30.294 36.569 52.11 46.56 9.226 4.225 17.722 6.559 23.683 6.855 10.698-15.19 18.393-38.455 19.65-61.105 1.413-25.435-5.208-45.52-18.15-56.305-15.682-13.068-45.463-20.816-78.19-20.13-25.07 0.525-47.618 6.072-60.148 13.277 0.184 0.188 0.372 0.378 0.565 0.572z m157.733-17.67c46.087 38.406 32.103 125.21 0 165.034-18.162 22.53-95.266-7.576-124.71-62.32-29.444-54.743-91.316-73.753-62.355-102.714 33.394-33.394 139.62-39.538 187.065 0z m-155.533 125.3c-1.929 1.917-19.923 21.076-26.705 27.662-14.06 13.654-27.832 24.353-43.571 32.819-19.096 10.27-36.569 30.294-46.56 52.11-4.225 9.226-6.559 17.722-6.855 23.683 15.19 10.698 38.455 18.393 61.105 19.65 25.435 1.413 45.52-5.208 56.305-18.15 13.068-15.682 20.816-45.463 20.13-78.19-0.525-25.07-6.072-47.618-13.277-60.148-0.188 0.184-0.378 0.372-0.572 0.565z m17.67 157.733c-38.406 46.087-125.21 32.103-165.034 0-22.53-18.162 7.576-95.266 62.32-124.71 54.743-29.444 73.753-91.316 102.714-62.355 33.394 33.394 39.538 139.62 0 187.065z m-125.3-155.533c-1.917-1.929-21.076-19.923-27.662-26.705-13.654-14.06-24.353-27.832-32.819-43.571-10.27-19.096-30.294-36.569-52.11-46.56-9.226-4.225-17.722-6.559-23.683-6.855-10.698 15.19-18.393 38.455-19.65 61.105-1.413 25.435 5.208 45.52 18.15 56.305 15.682 13.068 45.463 20.816 78.19 20.13 25.07-0.525 47.618-6.072 60.148-13.277a142.54 142.54 0 0 0-0.565-0.572z m-157.733 17.67c-46.087-38.406-32.103-125.21 0-165.034 18.162-22.53 95.266 7.576 124.71 62.32 29.444 54.743 91.316 73.753 62.355 102.714-33.394 33.394-139.62 39.538-187.065 0z" /></svg> \ No newline at end of file
diff --git a/images/in_out.svg b/images/in_out.svg
new file mode 100644
index 0000000..eac2657
--- /dev/null
+++ b/images/in_out.svg
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 295.239 295.239" style="enable-background:new 0 0 295.239 295.239;" xml:space="preserve">
+<g>
+ <g>
+ <g>
+ <path d="M66.667,247.62c-7.876,0-14.286,6.41-14.286,14.286c0,7.876,6.41,14.286,14.286,14.286
+ c7.876,0,14.286-6.41,14.286-14.286C80.952,254.03,74.543,247.62,66.667,247.62z M66.667,266.668
+ c-2.629,0-4.762-2.133-4.762-4.762c0-2.629,2.133-4.762,4.762-4.762c2.629,0,4.762,2.133,4.762,4.762
+ C71.429,264.535,69.295,266.668,66.667,266.668z"/>
+ <path d="M280.953,266.668c11.805,0,14.286-7.771,14.286-14.286v-38.095c0-12.095-6.481-22.852-16.919-28.071l-0.967-0.357
+ c-0.171-0.043-17.2-4.486-25.614-16.833l-14.148-28.295c-5.81-11.629-18.624-16.919-28.067-16.919h-59.786
+ c7.733-12.686,12.167-27.471,12.167-42.857h-9.524c0,26.805-15.062,51.605-38.095,63.9v-16.281h-9.524v28.571h28.571v-9.524
+ h-5.51c5.662-4.09,10.729-8.914,15.148-14.286h66.552c6.824,0,15.729,4.005,19.548,11.652l14.286,28.571l0.3,0.51
+ c9.586,14.376,27.343,19.91,30.81,20.876c6.952,3.671,11.248,11.038,11.248,19.343v38.095c0,4.09-0.671,4.762-4.762,4.762
+ h-19.429c-2.324-16.124-16.195-28.571-32.952-28.571c-16.757,0-30.629,12.448-32.952,28.571h-96
+ c-2.324-16.124-16.195-28.571-32.952-28.571c-16.757,0-30.629,12.448-32.952,28.571H19.048c-5.071,0-9.524-4.452-9.524-9.524
+ v-33.333c0-11.781,7.881-17.614,15.067-19.114l28.724-4.79c6.219-1.248,11.281-4.557,17.162-11.338l20-26.662h-9.524
+ c-26.805,0-51.605-15.062-63.9-38.095h16.281v-9.524H4.762v28.571h9.524v-5.543c13.367,18.505,34.395,30.976,57.533,33.6
+ l-8.748,11.676c-4.276,4.924-7.538,7.162-11.471,7.952l-28.762,4.795C9.181,188.658,0,200.1,0,214.287v33.333
+ c0,10.324,8.724,19.048,19.048,19.048h14.667c2.324,16.124,16.195,28.571,32.952,28.571h90.476v-9.524H89.948
+ c5.114-5.005,8.605-11.638,9.671-19.048h96c1.067,7.41,4.557,14.043,9.671,19.048h-19.576v9.524h109.524v-9.524h-43.386
+ c5.119-5.004,8.605-11.638,9.672-19.047H280.953z M66.667,285.715c-13.129,0-23.81-10.681-23.81-23.81
+ c0-13.129,10.681-23.81,23.81-23.81c13.129,0,23.81,10.681,23.81,23.81C90.477,275.033,79.795,285.715,66.667,285.715z
+ M228.572,285.715c-13.129,0-23.81-10.682-23.81-23.81c0-13.129,10.681-23.81,23.81-23.81c13.129,0,23.81,10.681,23.81,23.81
+ C252.382,275.035,241.701,285.715,228.572,285.715z"/>
+ <path d="M228.571,247.62c-7.876,0-14.286,6.41-14.286,14.286c0,7.876,6.41,14.286,14.286,14.286
+ c7.876,0,14.286-6.41,14.286-14.286C242.857,254.03,236.448,247.62,228.571,247.62z M228.571,266.668
+ c-2.629,0-4.762-2.133-4.762-4.762c0-2.629,2.133-4.762,4.762-4.762c2.629,0,4.762,2.133,4.762,4.762
+ C233.333,264.535,231.2,266.668,228.571,266.668z"/>
+ <rect x="166.667" y="285.715" width="9.524" height="9.524"/>
+ <rect x="23.81" y="285.715" width="9.524" height="9.524"/>
+ <rect x="4.762" y="285.715" width="9.524" height="9.524"/>
+ <path d="M223.81,195.238v-4.762c0-13.129-10.681-23.81-23.81-23.81h-61.905c-13.129,0-23.81,10.681-23.81,23.81h9.524
+ c0-7.876,6.41-14.286,14.286-14.286H200c7.876,0,14.286,6.41,14.286,14.286v4.762c0,7.876-6.41,14.286-14.286,14.286h-45.648
+ l10.919-10.919l-6.733-6.733l-22.414,22.414l22.414,22.414l6.733-6.733l-10.919-10.919H200
+ C213.129,219.048,223.81,208.368,223.81,195.238z"/>
+ <path d="M47.619,17.053v16.281h9.524V4.763H28.571v9.524h5.51C13.176,29.396,0,54.311,0,80.953h9.524
+ C9.524,54.149,24.586,29.349,47.619,17.053z"/>
+ <path d="M144.852,47.62h-16.281v9.524h28.571V28.572h-9.524v5.51C132.51,13.177,107.595,0.001,80.952,0.001v9.524
+ C107.757,9.525,132.557,24.587,144.852,47.62z"/>
+ <polygon points="52.381,52.382 52.381,57.482 45.381,53.105 40.333,61.181 46.671,65.139 41.352,66.915 44.362,75.944
+ 57.143,71.686 71.967,80.953 57.143,90.22 44.362,85.962 41.352,94.991 46.671,96.767 40.333,100.725 45.381,108.801
+ 52.381,104.425 52.381,109.525 61.905,109.525 61.905,98.472 76.19,89.543 76.19,98.415 62.857,116.191 70.476,121.905
+ 76.19,114.282 76.19,128.572 85.714,128.572 85.714,114.282 91.429,121.905 99.048,116.191 85.714,98.415 85.714,89.543
+ 100,98.472 100,109.525 109.524,109.525 109.524,104.425 116.524,108.801 121.571,100.725 115.233,96.767 120.552,94.991
+ 117.543,85.962 104.762,90.22 89.938,80.953 104.762,71.686 117.543,75.944 120.552,66.915 115.233,65.139 121.571,61.181
+ 116.524,53.105 109.524,57.482 109.524,52.382 100,52.382 100,63.434 85.714,72.363 85.714,63.491 99.048,45.715 91.429,40.001
+ 85.714,47.625 85.714,33.334 76.19,33.334 76.19,47.625 70.476,40.001 62.857,45.715 76.19,63.491 76.19,72.363 61.905,63.434
+ 61.905,52.382 "/>
+ </g>
+ </g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/images/left_climate.PNG b/images/left_climate.PNG
new file mode 100644
index 0000000..ad1e6ba
--- /dev/null
+++ b/images/left_climate.PNG
Binary files differ
diff --git a/images/rear_ws.svg b/images/rear_ws.svg
new file mode 100644
index 0000000..d246ec1
--- /dev/null
+++ b/images/rear_ws.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:svg="http://www.w3.org/2000/svg" id="svg2" viewBox="0 0 81.786 59.286" version="1.1">
+ <g id="layer1" transform="translate(-175.59 -219.84)">
+ <rect id="rect4577" style="color:#000000" rx="1.3393" ry="1.0714" height="34.464" width="66.786" stroke="#327dc8" stroke-linecap="round" y="227.34" x="183.09" stroke-width="5" fill="none"/>
+ <g id="g5273">
+ <g id="g5228" transform="translate(.22628)">
+ <g id="g5224" stroke="#327dc8">
+ <path id="path5216" stroke-width="5" fill="none" d="m218.14 244.22c-6.9199 8.9459 3.4253 17.17 1.014 24.731-0.28791 0.90275-0.7577 1.796-1.4605 2.68"/>
+ <path id="path5222" stroke-width="1px" stroke-linecap="round" fill="#327dc8" d="m216.17 236.18-5.1786 11.071h10.268z"/>
+ </g>
+ </g>
+ <g id="g5228-1" transform="translate(15.539)">
+ <g id="g5224-5" stroke="#327dc8">
+ <path id="path5216-4" stroke-width="5" fill="none" d="m218.14 244.22c-6.9199 8.9459 3.4253 17.17 1.014 24.731-0.28791 0.90275-0.7577 1.796-1.4605 2.68"/>
+ <path id="path5222-2" stroke-width="1px" stroke-linecap="round" fill="#327dc8" d="m216.17 236.18-5.1786 11.071h10.268z"/>
+ </g>
+ </g>
+ <g id="g5228-0" transform="translate(-15.086)">
+ <g id="g5224-9" stroke="#327dc8">
+ <path id="path5216-7" stroke-width="5" fill="none" d="m218.14 244.22c-6.9199 8.9459 3.4253 17.17 1.014 24.731-0.28791 0.90275-0.7577 1.796-1.4605 2.68"/>
+ <path id="path5222-3" stroke-width="1px" stroke-linecap="round" fill="#327dc8" d="m216.17 236.18-5.1786 11.071h10.268z"/>
+ </g>
+ </g>
+ </g>
+ </g>
+ <metadata>
+ <rdf:RDF>
+ <cc:Work>
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ <cc:license rdf:resource="http://creativecommons.org/licenses/publicdomain/"/>
+ <dc:publisher>
+ <cc:Agent rdf:about="http://openclipart.org/">
+ <dc:title>Openclipart</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:title>rear window heating</dc:title>
+ <dc:date>2013-05-07T09:13:11</dc:date>
+ <dc:description>Icon for rear window heating like found in cars</dc:description>
+ <dc:source>http://openclipart.org/detail/177851/rear-window-heating-by-dblade82-177851</dc:source>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>DBlade82</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>car</rdf:li>
+ <rdf:li>icon</rdf:li>
+ <rdf:li>rear window heating</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ </cc:Work>
+ <cc:License rdf:about="http://creativecommons.org/licenses/publicdomain/">
+ <cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
+ <cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
+ <cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+</svg>
diff --git a/images/right_climate.PNG b/images/right_climate.PNG
new file mode 100644
index 0000000..410d160
--- /dev/null
+++ b/images/right_climate.PNG
Binary files differ
diff --git a/images/wind_in.svg b/images/wind_in.svg
new file mode 100644
index 0000000..5608ff1
--- /dev/null
+++ b/images/wind_in.svg
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 512.853 512.853" style="enable-background:new 0 0 512.853 512.853;" xml:space="preserve">
+<g transform="translate(1 1)">
+ <g>
+ <path d="M471.747,217.88c-22.187-1.707-40.107-11.947-50.347-28.16l-2.56-4.267c-13.653-23.04-38.4-36.693-64.853-36.693H242.2
+ c-21.333,0-41.813,9.387-56.32,25.6l-11.947,11.947c-7.787,8.686-16.524,16.315-26.019,22.751
+ c-28.247-21.901-46.514-56.134-46.514-94.431c0-5.12-3.413-8.533-8.533-8.533c-5.12,0-8.533,3.413-8.533,8.533
+ c0,41.337,18.623,78.532,47.888,103.624c-13.526,6.763-28.206,11.307-43.621,13.283l-52.053,6.827
+ C15.213,241.773-1,259.693-1,281.027v38.4c0,23.893,18.773,42.667,42.667,42.667H76.53c4.095,24.134,25.217,42.667,50.47,42.667
+ s46.375-18.533,50.47-42.667h172.127c4.095,24.134,25.217,42.667,50.47,42.667c25.253,0,46.375-18.533,50.47-42.667h17.797
+ c23.893,0,42.667-18.773,43.52-41.813v-59.733C511.853,238.36,493.933,219.587,471.747,217.88z M127,387.693
+ c-18.773,0-34.133-15.36-34.133-34.133c0-18.773,15.36-34.133,34.133-34.133c18.773,0,34.133,15.36,34.133,34.133
+ C161.133,372.333,145.773,387.693,127,387.693z M400.067,387.693c-18.773,0-34.133-15.36-34.133-34.133
+ c0-18.773,15.36-34.133,34.133-34.133c18.773,0,34.133,15.36,34.133,34.133C434.2,372.333,418.84,387.693,400.067,387.693z
+ M493.933,319.427c0,14.507-11.093,25.6-25.6,25.6h-17.797c-2.881-16.98-14.192-31.177-29.444-38.106
+ c-0.338-0.155-0.674-0.314-1.017-0.462c-0.214-0.092-0.432-0.175-0.648-0.264c-0.553-0.229-1.109-0.453-1.672-0.662
+ c-0.152-0.056-0.306-0.108-0.459-0.163c-0.625-0.226-1.256-0.442-1.893-0.644c-0.138-0.044-0.276-0.085-0.415-0.127
+ c-0.648-0.199-1.302-0.387-1.962-0.56c-0.146-0.038-0.292-0.076-0.439-0.113c-0.648-0.164-1.301-0.316-1.96-0.455
+ c-0.166-0.035-0.331-0.071-0.497-0.104c-0.636-0.128-1.277-0.242-1.922-0.346c-0.191-0.031-0.381-0.064-0.573-0.093
+ c-0.621-0.093-1.248-0.17-1.877-0.24c-0.213-0.024-0.425-0.052-0.639-0.074c-0.629-0.062-1.263-0.107-1.899-0.146
+ c-0.21-0.013-0.417-0.033-0.628-0.043c-0.837-0.041-1.68-0.065-2.529-0.065c-0.849,0-1.692,0.024-2.529,0.065
+ c-0.21,0.01-0.418,0.03-0.628,0.043c-0.636,0.039-1.27,0.084-1.899,0.146c-0.214,0.021-0.426,0.05-0.639,0.074
+ c-0.629,0.07-1.256,0.148-1.877,0.24c-0.192,0.029-0.382,0.062-0.574,0.093c-0.645,0.104-1.285,0.218-1.921,0.345
+ c-0.167,0.034-0.332,0.069-0.498,0.104c-0.658,0.139-1.311,0.291-1.959,0.455c-0.146,0.037-0.293,0.074-0.439,0.113
+ c-0.66,0.174-1.314,0.361-1.962,0.561c-0.138,0.042-0.276,0.083-0.414,0.127c-0.638,0.202-1.268,0.418-1.894,0.644
+ c-0.152,0.055-0.305,0.107-0.457,0.163c-0.564,0.21-1.121,0.434-1.675,0.664c-0.215,0.089-0.432,0.172-0.645,0.263
+ c-0.343,0.148-0.68,0.308-1.019,0.463c-15.25,6.93-26.561,21.126-29.441,38.105H177.47c-2.881-16.979-14.19-31.174-29.439-38.104
+ c-0.34-0.156-0.677-0.316-1.021-0.464c-0.213-0.091-0.43-0.174-0.645-0.263c-0.554-0.229-1.111-0.453-1.675-0.664
+ c-0.151-0.056-0.305-0.108-0.457-0.163c-0.626-0.226-1.257-0.442-1.894-0.644c-0.137-0.043-0.276-0.084-0.414-0.127
+ c-0.648-0.199-1.302-0.387-1.962-0.561c-0.146-0.038-0.292-0.076-0.439-0.113c-0.648-0.164-1.301-0.316-1.96-0.455
+ c-0.166-0.035-0.331-0.071-0.497-0.104c-0.636-0.128-1.277-0.242-1.922-0.346c-0.191-0.031-0.381-0.064-0.573-0.093
+ c-0.621-0.093-1.248-0.17-1.877-0.24c-0.213-0.024-0.425-0.052-0.639-0.074c-0.629-0.062-1.263-0.107-1.899-0.146
+ c-0.21-0.013-0.417-0.033-0.628-0.043c-0.837-0.041-1.68-0.065-2.529-0.065c-0.849,0-1.692,0.024-2.529,0.065
+ c-0.21,0.01-0.418,0.03-0.628,0.043c-0.636,0.039-1.27,0.084-1.899,0.146c-0.214,0.021-0.426,0.05-0.639,0.074
+ c-0.629,0.07-1.256,0.148-1.877,0.24c-0.192,0.029-0.382,0.062-0.573,0.093c-0.645,0.104-1.286,0.218-1.922,0.346
+ c-0.166,0.033-0.332,0.069-0.497,0.104c-0.659,0.139-1.312,0.291-1.96,0.455c-0.146,0.037-0.293,0.074-0.439,0.113
+ c-0.66,0.174-1.313,0.361-1.962,0.56c-0.138,0.042-0.277,0.083-0.415,0.127c-0.637,0.202-1.267,0.418-1.893,0.644
+ c-0.153,0.055-0.307,0.107-0.459,0.163c-0.563,0.21-1.119,0.433-1.672,0.662c-0.216,0.089-0.434,0.172-0.648,0.264
+ c-0.342,0.148-0.678,0.307-1.017,0.462c-15.252,6.929-26.563,21.126-29.444,38.106H41.667c-14.507,0-25.6-11.093-25.6-25.6v-38.4
+ c0-12.8,9.387-23.893,22.187-24.747l52.053-6.827c20.828-2.367,40.602-8.941,58.31-19.128
+ c20.99,13.186,45.769,20.835,72.25,20.835h30.72l-19.627,19.627c-3.413,3.413-3.413,8.533,0,11.947
+ c1.707,1.707,3.413,2.56,5.973,2.56s4.267-0.853,5.973-2.56l32.673-32.673c2.51-1.395,4.02-4.034,4.02-7.434
+ s-1.511-6.038-4.02-7.434l-32.673-32.673c-3.413-3.413-8.533-3.413-11.947,0s-3.413,8.533,0,11.947l19.627,19.627h-30.72
+ c-20.371,0-39.592-5.171-56.42-14.26c8.048-6.099,15.52-13.027,22.287-20.727l11.947-13.653
+ c11.093-12.8,26.453-19.627,43.52-19.627h111.787c20.48,0,39.253,11.093,49.493,27.307l2.56,4.267
+ c12.8,21.333,36.693,34.987,64,36.693c13.653,0.853,23.893,11.947,23.893,25.6V319.427z"/>
+ </g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/images/wind_shield.svg b/images/wind_shield.svg
new file mode 100644
index 0000000..bca6032
--- /dev/null
+++ b/images/wind_shield.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 490.001 490.001" style="enable-background:new 0 0 490.001 490.001;" xml:space="preserve">
+<g>
+ <path d="M485.607,150.221c-31.245-31.245-67.633-55.777-108.154-72.916c-41.959-17.747-86.523-26.746-132.452-26.746
+ c-45.93,0-90.494,8.999-132.454,26.746c-40.521,17.14-76.909,41.673-108.154,72.918c-4.85,4.851-5.792,12.373-2.288,18.27
+ l116,195.195c2.704,4.549,7.604,7.337,12.895,7.337h14.386c1.864,6.991,4.364,13.725,6.786,20.24
+ c2.314,6.224,4.5,12.103,5.995,17.789c1.464,5.566,2.175,10.6,2.175,15.388c0,8.284,6.716,15,15,15s15-6.716,15-15
+ c0-7.397-1.034-14.927-3.162-23.016c-1.872-7.122-4.423-13.982-6.89-20.616c-1.247-3.354-2.453-6.606-3.538-9.785l46.124,0
+ c1.862,6.987,4.363,13.724,6.786,20.241c2.314,6.224,4.5,12.103,5.995,17.788c1.464,5.568,2.175,10.603,2.175,15.389
+ c0,8.284,6.716,15,15,15c8.284,0,15-6.716,15-15c0-7.396-1.034-14.924-3.162-23.016c-1.872-7.122-4.423-13.982-6.89-20.616
+ c-1.248-3.355-2.454-6.607-3.538-9.786l46.124,0c1.862,6.988,4.363,13.725,6.786,20.241c2.313,6.222,4.499,12.099,5.995,17.788
+ c1.464,5.568,2.175,10.603,2.175,15.389c0,8.284,6.716,15,15,15s15-6.716,15-15c0-7.396-1.034-14.924-3.162-23.017
+ c-1.874-7.126-4.424-13.983-6.89-20.615c-1.248-3.355-2.454-6.607-3.538-9.786H359c5.292,0,10.191-2.788,12.895-7.337l116-195.196
+ C491.4,162.594,490.457,155.072,485.607,150.221z M327.544,341.024c0.356-2.797,0.927-5.704,1.736-8.778
+ c1.494-5.684,3.68-11.563,5.995-17.788c2.466-6.632,5.016-13.489,6.89-20.616c2.127-8.092,3.162-15.62,3.162-23.016
+ c0-7.395-1.034-14.923-3.162-23.017c-0.958-3.643-2.094-7.216-3.304-10.726h12.42c5.694,0,8.546-6.884,4.519-10.911l-27.511-27.511
+ c-2.496-2.496-6.543-2.496-9.039,0l-27.511,27.511c-4.026,4.026-1.175,10.911,4.519,10.911h10.719
+ c0.062,0.188,0.109,0.379,0.179,0.566c2.314,6.224,4.5,12.102,5.995,17.787c1.464,5.569,2.176,10.604,2.176,15.389
+ c0,4.786-0.711,9.82-2.175,15.388c-1.497,5.69-3.682,11.567-5.995,17.789c-2.467,6.635-5.019,13.497-6.89,20.616
+ c-1.498,5.699-2.443,11.115-2.877,16.405l-47.335,0c0.356-2.797,0.927-5.704,1.736-8.779c1.494-5.684,3.68-11.563,5.995-17.788
+ c2.467-6.634,5.018-13.494,6.89-20.616c2.127-8.092,3.162-15.62,3.162-23.016c0-7.395-1.034-14.923-3.162-23.016
+ c-0.957-3.642-2.093-7.215-3.304-10.727h11.143c5.694,0,8.546-6.884,4.519-10.911l-27.511-27.511c-2.496-2.496-6.543-2.496-9.039,0
+ l-27.511,27.511c-4.026,4.026-1.175,10.911,4.519,10.911h11.996c0.062,0.188,0.109,0.379,0.179,0.566
+ c2.315,6.226,4.501,12.105,5.995,17.787c1.464,5.569,2.176,10.604,2.176,15.389c0,4.786-0.711,9.82-2.175,15.389
+ c-1.495,5.686-3.681,11.563-5.995,17.788c-2.467,6.635-5.019,13.497-6.89,20.616c-1.498,5.699-2.443,11.116-2.877,16.406l-47.335,0
+ c0.356-2.797,0.927-5.704,1.735-8.778c1.496-5.688,3.681-11.566,5.995-17.789c2.467-6.634,5.018-13.494,6.89-20.615
+ c2.127-8.09,3.162-15.619,3.162-23.017c0-7.396-1.034-14.926-3.162-23.016c-0.957-3.642-2.093-7.215-3.304-10.727h9.866
+ c5.694,0,8.546-6.884,4.519-10.911l-27.511-27.511c-2.496-2.496-6.543-2.496-9.039,0l-27.511,27.511
+ c-4.026,4.026-1.175,10.911,4.519,10.911h13.272c0.062,0.188,0.109,0.379,0.179,0.566c2.315,6.226,4.501,12.105,5.995,17.788
+ c1.464,5.567,2.175,10.601,2.175,15.388c0,4.788-0.711,9.821-2.175,15.389c-1.495,5.686-3.681,11.563-5.995,17.788
+ c-2.466,6.633-5.017,13.491-6.89,20.616c-1.498,5.699-2.443,11.116-2.877,16.406h-2.87L33.964,163.378
+ c57.552-53.497,132.041-82.819,211.038-82.819c78.995,0,153.482,29.321,211.035,82.817L350.466,341.024H327.544z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
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: ,
+ ),
+ );
+ }),
+ ),
+ ),
+ );
+ }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..5f0b20e
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,95 @@
+name: flutter_hvac
+description: A new Flutter project.
+
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+
+# The following defines the version and build number for your application.
+# A version number is three numbers separated by dots, like 1.2.43
+# followed by an optional build number separated by a +.
+# Both the version and the builder number may be overridden in flutter
+# build by specifying --build-name and --build-number, respectively.
+# In Android, build-name is used as versionName while build-number used as versionCode.
+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
+# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+version: 1.0.0+1
+
+environment:
+ sdk: ">=2.12.0 <3.0.0"
+
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+ flutter:
+ sdk: flutter
+
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^1.0.2
+ flutter_svg_provider: ^1.0.3
+ flutter_hooks: ^0.18.3
+ slider_controller: ^0.0.3
+ scrollable_positioned_list: ^0.3.1
+ flutter_riverpod: ^1.0.3
+ yaml: ^3.1.1
+
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^1.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter.
+flutter:
+
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # To add assets to your application, add an assets section, like this:
+ assets:
+ - images/
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/assets-and-images/#resolution-aware.
+
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.dev/assets-and-images/#from-packages
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/custom-fonts/#from-packages