diff options
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 Binary files differnew file mode 100644 index 0000000..ad1e6ba --- /dev/null +++ b/images/left_climate.PNG 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 Binary files differnew file mode 100644 index 0000000..410d160 --- /dev/null +++ b/images/right_climate.PNG 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 |