mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-16 01:56:19 +00:00
garage door
This commit is contained in:
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"Scheduleapp"
|
||||||
|
]
|
||||||
|
}
|
148
assets/icons/closed_garage_door.svg
Normal file
148
assets/icons/closed_garage_door.svg
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<svg width="290" height="290" viewBox="0 0 290 290" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_4111_484)">
|
||||||
|
<rect x="20" y="20" width="250" height="250" rx="100" fill="#EDEDED"/>
|
||||||
|
<path d="M92.5676 124.459H197.432V204.459H92.5676V124.459Z" fill="url(#paint0_linear_4111_484)"/>
|
||||||
|
<path d="M92.5908 149.353H130.176V205H92.5908V149.353Z" fill="url(#paint1_linear_4111_484)"/>
|
||||||
|
<g clip-path="url(#clip0_4111_484)">
|
||||||
|
<path d="M92.5908 145.541H197.409V177.658H92.5908V145.541Z" fill="url(#paint2_linear_4111_484)"/>
|
||||||
|
<path d="M92.7646 122.838H197.471V135.308H92.7646V122.838Z" fill="url(#paint3_linear_4111_484)"/>
|
||||||
|
<path d="M92.7646 132.72H197.471V145.191H92.7646V132.72Z" fill="url(#paint4_linear_4111_484)"/>
|
||||||
|
<path d="M92.7646 142.838H197.471V155.308H92.7646V142.838Z" fill="url(#paint5_linear_4111_484)"/>
|
||||||
|
<path d="M92.7646 152.568H197.471V165.038H92.7646V152.568Z" fill="url(#paint6_linear_4111_484)"/>
|
||||||
|
<path d="M92.7646 162.45H197.471V174.921H92.7646V162.45Z" fill="url(#paint7_linear_4111_484)"/>
|
||||||
|
<path d="M92.7646 172.568H197.471V185.038H92.7646V172.568Z" fill="url(#paint8_linear_4111_484)"/>
|
||||||
|
<path d="M92.7646 182.45H197.471V194.921H92.7646V182.45Z" fill="url(#paint9_linear_4111_484)"/>
|
||||||
|
<path d="M92.7646 192.332H197.471V204.803H92.7646V192.332Z" fill="url(#paint10_linear_4111_484)"/>
|
||||||
|
</g>
|
||||||
|
<path d="M199.649 114.801L156.765 88.0353C153.522 86.0118 149.261 85 145 85C140.739 85 136.478 86.0118 133.235 88.0353L90.3513 114.801C87.0226 116.879 85 120.525 85 124.449V197.537C85 201.659 88.3412 205 92.4628 205C94.58 205 96.2965 203.284 96.2965 201.166V134.999C96.2965 130.646 99.8252 127.118 104.178 127.118H185.822C190.175 127.118 193.704 130.646 193.704 134.999V201.166C193.704 203.284 195.42 205 197.537 205C201.659 205 205 201.659 205 197.537V124.449C205 120.525 202.977 116.879 199.649 114.801Z" fill="url(#paint11_linear_4111_484)"/>
|
||||||
|
<path d="M199.649 114.801L156.765 88.0353C153.522 86.0118 149.261 85 145 85C140.739 85 136.478 86.0118 133.235 88.0353L90.3513 114.801C87.0226 116.879 85 120.525 85 124.449V135.743C85 131.819 87.0226 128.172 90.3513 126.095L133.235 99.3287C136.478 97.3052 140.739 96.2934 145 96.2934C149.261 96.2934 153.522 97.3052 156.765 99.3287L199.649 126.095C202.977 128.172 205 131.819 205 135.743V124.449C205 120.525 202.977 116.879 199.649 114.801Z" fill="url(#paint12_linear_4111_484)"/>
|
||||||
|
<path d="M131.593 111.677H158.407C159.926 111.677 161.156 110.446 161.156 108.928C161.156 107.41 159.926 106.179 158.407 106.179H131.593C130.074 106.179 128.844 107.41 128.844 108.928C128.844 110.446 130.075 111.677 131.593 111.677Z" fill="url(#paint13_linear_4111_484)"/>
|
||||||
|
<path d="M131.593 121.795H158.407C159.926 121.795 161.156 120.564 161.156 119.046C161.156 117.527 159.926 116.297 158.407 116.297H131.593C130.074 116.297 128.844 117.528 128.844 119.046C128.844 120.564 130.075 121.795 131.593 121.795Z" fill="url(#paint14_linear_4111_484)"/>
|
||||||
|
<path d="M205 135.744V197.536C205 199.598 204.165 201.464 202.814 202.814C201.464 204.165 199.598 205 197.536 205C195.419 205 193.704 203.285 193.704 201.167V134.998C193.704 130.647 190.174 127.118 185.821 127.118H104.179C99.8259 127.118 96.2965 130.647 96.2965 134.998V201.167C96.2965 202.226 95.8682 203.184 95.1741 203.878C94.48 204.572 93.5224 205 92.4635 205C88.3412 205 85 201.659 85 197.536V135.744C85 131.819 87.0235 128.172 90.3506 126.094L133.235 99.3294C136.478 97.3059 140.739 96.2941 145 96.2941C149.261 96.2941 153.522 97.3059 156.765 99.3294L199.649 126.094C202.976 128.172 205 131.819 205 135.744Z" fill="url(#paint15_linear_4111_484)"/>
|
||||||
|
<path d="M145.236 89.7092C138.367 89.7092 131.708 91.6861 125.979 95.4266C124.456 96.4207 124.028 98.4609 125.022 99.9835L130.442 105.42C130.241 106.14 130.336 106.937 130.775 107.613L135.816 112.723C135.627 113.301 135.689 113.956 136.044 114.508L141.425 119.781C141.068 121.102 141.404 122.572 142.442 123.61L145.949 127.118H185.822C190.175 127.118 193.704 130.646 193.704 134.999V174.872L205 186.168V135.955L164.492 95.4266C158.763 91.6864 152.104 89.7092 145.236 89.7092Z" fill="url(#paint16_linear_4111_484)"/>
|
||||||
|
<path d="M153.562 111.378C151.008 109.737 148.047 108.87 145 108.87C141.953 108.87 138.992 109.737 136.438 111.377C135.465 112.003 135.183 113.299 135.808 114.273C136.433 115.246 137.73 115.528 138.703 114.903C140.58 113.697 142.757 113.06 145 113.06C147.243 113.06 149.42 113.697 151.297 114.903C151.647 115.128 152.039 115.236 152.427 115.236C153.117 115.236 153.792 114.896 154.192 114.273C154.817 113.3 154.535 112.003 153.562 111.378Z" fill="url(#paint17_linear_4111_484)"/>
|
||||||
|
<path d="M158.669 103.651C154.599 101.007 149.872 99.6099 145 99.6099C140.128 99.6099 135.401 101.007 131.331 103.651C130.083 104.461 129.729 106.13 130.539 107.377C131.35 108.625 133.018 108.98 134.266 108.169C137.46 106.094 141.172 104.998 145 104.998C148.828 104.998 152.54 106.094 155.734 108.169C156.187 108.464 156.696 108.604 157.199 108.604C158.08 108.604 158.944 108.172 159.46 107.377C160.271 106.13 159.917 104.461 158.669 103.651Z" fill="url(#paint18_linear_4111_484)"/>
|
||||||
|
<path d="M164.256 95.1913C158.528 91.4508 151.869 89.4736 145 89.4736C138.131 89.4736 131.472 91.4506 125.744 95.1911C124.221 96.1852 123.792 98.2254 124.787 99.748C125.781 101.271 127.821 101.699 129.344 100.705C133.999 97.6654 139.413 96.0588 145 96.0588C150.587 96.0588 156.001 97.6654 160.656 100.705C161.212 101.068 161.836 101.241 162.453 101.241C163.528 101.241 164.582 100.716 165.213 99.7482C166.208 98.2256 165.779 96.1854 164.256 95.1913Z" fill="url(#paint19_linear_4111_484)"/>
|
||||||
|
<path d="M145 124.532C147.182 124.532 148.951 122.763 148.951 120.581C148.951 118.399 147.182 116.63 145 116.63C142.818 116.63 141.049 118.399 141.049 120.581C141.049 122.763 142.818 124.532 145 124.532Z" fill="url(#paint20_linear_4111_484)"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_4111_484" x="0" y="0" width="290" height="290" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="10"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4111_484"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4111_484" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="paint0_linear_4111_484" x1="145" y1="154.648" x2="145" y2="196.939" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#62DBFB"/>
|
||||||
|
<stop offset="0.1912" stop-color="#57D5FA"/>
|
||||||
|
<stop offset="0.5232" stop-color="#3BC5F7"/>
|
||||||
|
<stop offset="0.954" stop-color="#0DABF2"/>
|
||||||
|
<stop offset="1" stop-color="#08A9F1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_4111_484" x1="105.706" y1="177.176" x2="93.7059" y2="177.176" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#0593FC" stop-opacity="0"/>
|
||||||
|
<stop offset="0.6831" stop-color="#0389FC" stop-opacity="0.683"/>
|
||||||
|
<stop offset="1" stop-color="#0182FC"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_4111_484" x1="145" y1="164.717" x2="145" y2="148.715" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#0593FC" stop-opacity="0"/>
|
||||||
|
<stop offset="0.6831" stop-color="#0389FC" stop-opacity="0.683"/>
|
||||||
|
<stop offset="1" stop-color="#0182FC"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_4111_484" x1="145.118" y1="127.544" x2="145.118" y2="134.136" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_4111_484" x1="145.118" y1="137.426" x2="145.118" y2="144.019" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_4111_484" x1="145.118" y1="147.544" x2="145.118" y2="154.136" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_4111_484" x1="145.118" y1="157.273" x2="145.118" y2="163.866" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint7_linear_4111_484" x1="145.118" y1="167.156" x2="145.118" y2="173.748" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint8_linear_4111_484" x1="145.118" y1="177.273" x2="145.118" y2="183.866" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint9_linear_4111_484" x1="145.118" y1="187.156" x2="145.118" y2="193.748" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint10_linear_4111_484" x1="145.118" y1="197.038" x2="145.118" y2="203.631" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint11_linear_4111_484" x1="112.144" y1="101.95" x2="168.144" y2="201.715" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EAF9FA"/>
|
||||||
|
<stop offset="1" stop-color="#B3DAFE"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint12_linear_4111_484" x1="145" y1="67.5915" x2="145" y2="137.895" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#7BACDF" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="#7BACDF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint13_linear_4111_484" x1="145" y1="110.944" x2="145" y2="105.881" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EAF9FA"/>
|
||||||
|
<stop offset="1" stop-color="#B3DAFE"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint14_linear_4111_484" x1="145" y1="121.061" x2="145" y2="115.998" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EAF9FA"/>
|
||||||
|
<stop offset="1" stop-color="#B3DAFE"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint15_linear_4111_484" x1="126.473" y1="129.525" x2="115.65" y2="108.113" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#7BACDF" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="#7BACDF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint16_linear_4111_484" x1="175.367" y1="132.235" x2="141.72" y2="85.8824" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#7BACDF" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="#7BACDF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint17_linear_4111_484" x1="143.315" y1="108.32" x2="146.188" y2="116.541" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#AEFFD1"/>
|
||||||
|
<stop offset="0.1201" stop-color="#A3F9CB"/>
|
||||||
|
<stop offset="0.3288" stop-color="#87EAB9"/>
|
||||||
|
<stop offset="0.6012" stop-color="#59D19D"/>
|
||||||
|
<stop offset="0.9235" stop-color="#19AF77"/>
|
||||||
|
<stop offset="1" stop-color="#09A76D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint18_linear_4111_484" x1="142.584" y1="97.1318" x2="145.857" y2="109.025" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#AEFFD1"/>
|
||||||
|
<stop offset="0.1201" stop-color="#A3F9CB"/>
|
||||||
|
<stop offset="0.3288" stop-color="#87EAB9"/>
|
||||||
|
<stop offset="0.6012" stop-color="#59D19D"/>
|
||||||
|
<stop offset="0.9235" stop-color="#19AF77"/>
|
||||||
|
<stop offset="1" stop-color="#09A76D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint19_linear_4111_484" x1="142.471" y1="88.6965" x2="145.983" y2="101.547" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#AEFFD1"/>
|
||||||
|
<stop offset="0.1201" stop-color="#A3F9CB"/>
|
||||||
|
<stop offset="0.3288" stop-color="#87EAB9"/>
|
||||||
|
<stop offset="0.6012" stop-color="#59D19D"/>
|
||||||
|
<stop offset="0.9235" stop-color="#19AF77"/>
|
||||||
|
<stop offset="1" stop-color="#09A76D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint20_linear_4111_484" x1="141.169" y1="116.749" x2="147.514" y2="123.095" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#AEFFD1"/>
|
||||||
|
<stop offset="0.1201" stop-color="#A3F9CB"/>
|
||||||
|
<stop offset="0.3288" stop-color="#87EAB9"/>
|
||||||
|
<stop offset="0.6012" stop-color="#59D19D"/>
|
||||||
|
<stop offset="0.9235" stop-color="#19AF77"/>
|
||||||
|
<stop offset="1" stop-color="#09A76D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="clip0_4111_484">
|
||||||
|
<rect width="104.88" height="81.9651" fill="white" transform="translate(92.5908 122.838)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
29
assets/icons/garage_countdown.svg
Normal file
29
assets/icons/garage_countdown.svg
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<svg width="50" height="49" viewBox="0 0 50 49" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M25.0508 13.2076H14.9395C14.5289 13.2076 14.1961 12.8749 14.1961 12.4643C14.1961 12.0536 14.5288 11.7209 14.9395 11.7209H25.0508C25.4613 11.7209 25.7941 12.0536 25.7941 12.4643C25.7941 12.8749 25.4613 13.2076 25.0508 13.2076ZM9.98643 13.2076H0.743359C0.332812 13.2076 0 12.8749 0 12.4643C0 12.0536 0.332715 11.7209 0.743359 11.7209H9.98643C10.397 11.7209 10.7298 12.0536 10.7298 12.4643C10.7298 12.8749 10.397 13.2076 9.98643 13.2076Z" fill="#D9EEFF"/>
|
||||||
|
<path d="M10.7028 18.4107H3.71571C3.30516 18.4107 2.97235 18.078 2.97235 17.6674C2.97235 17.2568 3.30507 16.924 3.71571 16.924H10.7028C11.1134 16.924 11.4462 17.2567 11.4462 17.6674C11.4461 18.078 11.1134 18.4107 10.7028 18.4107Z" fill="#D9EEFF"/>
|
||||||
|
<path d="M5.97168 28.8144H0.743359C0.332812 28.8144 0 28.4817 0 28.0711C0 27.6604 0.332715 27.3277 0.743359 27.3277H5.97168C6.38223 27.3277 6.71504 27.6604 6.71504 28.0711C6.71504 28.4817 6.38223 28.8144 5.97168 28.8144Z" fill="#D9EEFF"/>
|
||||||
|
<path d="M11.717 34.0177H3.1454C2.73485 34.0177 2.40204 33.685 2.40204 33.2743C2.40204 32.8638 2.73475 32.531 3.1454 32.531H11.717C12.1275 32.531 12.4603 32.8637 12.4603 33.2743C12.4603 33.6849 12.1276 34.0177 11.717 34.0177Z" fill="#D9EEFF"/>
|
||||||
|
<path d="M8.94401 39.2209H5.30299C4.89244 39.2209 4.55963 38.8882 4.55963 38.4775C4.55963 38.067 4.89235 37.7342 5.30299 37.7342H8.94401C9.35455 37.7342 9.68737 38.0669 9.68737 38.4775C9.68727 38.8882 9.35455 39.2209 8.94401 39.2209Z" fill="#D9EEFF"/>
|
||||||
|
<path d="M20.6715 44.4241H9.68855C9.278 44.4241 8.94519 44.0914 8.94519 43.6808C8.94519 43.2702 9.27791 42.9374 9.68855 42.9374H20.6715C21.082 42.9374 21.4148 43.2701 21.4148 43.6808C21.4148 44.0913 21.0821 44.4241 20.6715 44.4241Z" fill="#D9EEFF"/>
|
||||||
|
<path d="M12.6245 23.6139H6.84828C6.43773 23.6139 6.10492 23.2812 6.10492 22.8706C6.10492 22.4599 6.43763 22.1272 6.84828 22.1272H12.6245C13.035 22.1272 13.3678 22.4599 13.3678 22.8706C13.3678 23.2812 13.035 23.6139 12.6245 23.6139Z" fill="#D9EEFF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M35.1365 4.34468L32.7766 11.0594C33.9959 11.2112 35.218 11.4836 36.4288 11.8826C37.6396 12.2815 38.7859 12.7901 39.8563 13.3913L42.2163 6.67652L35.1365 4.34468Z" fill="#EFF6FF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.1587 0.754188L32.2849 3.40634C32.0967 3.97948 32.4086 4.60321 32.9817 4.7914L34.6618 5.34208L41.7387 7.67401L43.416 8.22753C43.9891 8.41581 44.6128 8.10106 44.801 7.52792L45.6748 4.87577C45.863 4.30263 45.5483 3.67889 44.9753 3.49071L34.5437 0.0545788C33.9706 -0.133702 33.3468 0.181044 33.1587 0.754188Z" fill="#375E7D"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M43.4159 8.22741C43.9891 8.41569 44.6127 8.10095 44.801 7.5278L45.6747 4.87566C45.8629 4.30251 45.5482 3.67878 44.9752 3.4906L42.3905 2.63933C42.9637 2.82761 43.2783 3.45124 43.09 4.02439L42.2163 6.67654C42.0281 7.24968 41.4044 7.56433 40.8312 7.37614H40.8369L41.7388 7.674L43.4159 8.22741Z" fill="#2B4D66"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.75 47.3444C34.8387 50.6653 45.7084 45.1811 49.0292 35.0949C51.9538 26.2196 48.0571 16.7375 40.2075 12.3238C39.1371 11.7225 37.9909 11.214 36.78 10.8151C35.569 10.4162 34.347 10.1436 33.1277 9.99197C28.8714 9.46101 24.6545 10.3881 21.0864 12.4643C17.1673 14.7457 14.0319 18.4177 12.5036 23.0646C9.18007 33.1507 14.6641 44.0235 24.75 47.3444Z" fill="#375E7D"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M35.454 14.8466C27.5932 12.2563 19.1228 16.5324 16.5325 24.3934C13.945 32.2545 18.2181 40.7252 26.0789 43.3128C33.9398 45.9031 42.4102 41.6298 45.0005 33.7688L45.0089 33.7407C47.5795 25.8881 43.3064 17.4314 35.454 14.8466Z" fill="#EFF6FF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M35.454 14.8467L31.5488 26.7028C31.0965 28.0739 31.9675 29.3662 33.1249 29.8271L45.0089 33.7407C47.5795 25.8881 43.3063 17.4314 35.454 14.8467Z" fill="#EB5468"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M45.0088 33.7407C47.2621 26.8574 44.2559 19.5106 38.1931 16.0605C39.2579 19.238 39.8451 22.733 39.8451 26.4023C39.8451 28.2847 39.6906 30.1221 39.3956 31.8921L45.0088 33.7407Z" fill="#E5384F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.0292 35.0949C51.9538 26.2196 48.0571 16.7375 40.2075 12.3238C39.4209 11.8799 38.5921 11.4894 37.7267 11.1551C37.4149 11.0343 37.1003 10.9219 36.78 10.8151C36.4035 10.6915 36.027 10.5791 35.6477 10.4808C36.6647 12.189 37.5244 14.0629 38.1931 16.0604C44.2558 19.5105 47.2619 26.8574 45.0088 33.7407C45.0059 33.7491 45.0031 33.7576 45.0004 33.7688C43.3906 38.6518 39.5136 42.1496 34.9229 43.4785C33.6896 45.3271 32.2624 46.9567 30.6779 48.3137C38.7888 48.353 46.3546 43.2172 49.0292 35.0949Z" fill="#2B4D66"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M34.9229 43.4785C39.5135 42.1496 43.3906 38.6517 45.0004 33.7688L45.0088 33.7407L39.3955 31.8921C38.8729 35.0359 37.9121 37.9719 36.5972 40.5931C36.0888 41.6046 35.5297 42.5682 34.9229 43.4785Z" fill="#D9EEFF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.2076 12.3237L41.7387 7.67401L40.8313 7.37616L39.1541 6.82265L37.7268 11.155C38.5921 11.4893 39.4209 11.8799 40.2076 12.3237Z" fill="#D9EEFF"/>
|
||||||
|
<path d="M26.0958 44.0056C26.0188 44.0056 25.9404 43.9935 25.8631 43.968C25.4732 43.8396 25.2612 43.4194 25.3898 43.0295L26.1905 40.5992C26.3188 40.2092 26.7386 39.9971 27.129 40.1258C27.519 40.2543 27.731 40.6745 27.6024 41.0644L26.8017 43.4947C26.6987 43.8075 26.408 44.0056 26.0958 44.0056Z" fill="#375E7D"/>
|
||||||
|
<path d="M18.9963 25.9181C18.9192 25.9181 18.8407 25.906 18.7633 25.8804L16.336 25.0796C15.9461 24.9511 15.7343 24.5308 15.863 24.1408C15.9916 23.7511 16.4114 23.5388 16.8018 23.6679L19.2292 24.4687C19.619 24.5972 19.8308 25.0175 19.7021 25.4074C19.599 25.7199 19.3085 25.9181 18.9963 25.9181Z" fill="#375E7D"/>
|
||||||
|
<path d="M25.1917 18.7256C24.9202 18.7256 24.6586 18.5762 24.5277 18.3175L23.373 16.0333C23.1877 15.667 23.3347 15.2198 23.701 15.0345C24.0674 14.8496 24.5146 14.9963 24.6997 15.3626L25.8545 17.6468C26.0398 18.0131 25.8928 18.4602 25.5265 18.6455C25.419 18.6998 25.3045 18.7256 25.1917 18.7256Z" fill="#375E7D"/>
|
||||||
|
<path d="M37.5139 43.1515C37.2421 43.1515 36.9803 43.0019 36.8496 42.7428L35.6978 40.4586C35.5129 40.0921 35.6602 39.645 36.0268 39.4602C36.3932 39.2753 36.8403 39.4225 37.0251 39.7892L38.177 42.0734C38.3618 42.4399 38.2146 42.887 37.848 43.0718C37.7406 43.1259 37.6264 43.1515 37.5139 43.1515Z" fill="#375E7D"/>
|
||||||
|
<path d="M17.4207 36.5353C17.1489 36.5353 16.8871 36.3857 16.7564 36.1265C16.5716 35.76 16.7188 35.313 17.0854 35.1281L19.3696 33.9762C19.736 33.791 20.1832 33.9385 20.368 34.3052C20.5528 34.6717 20.4056 35.1187 20.0389 35.3035L17.7548 36.4555C17.6474 36.5096 17.5333 36.5353 17.4207 36.5353Z" fill="#375E7D"/>
|
||||||
|
<path d="M28.7476 28.1964C28.5688 28.1964 28.3896 28.1323 28.247 28.0025L22.85 23.0829C22.5467 22.8063 22.5249 22.3362 22.8014 22.0328C23.0779 21.7294 23.548 21.7077 23.8515 21.9842L29.2485 26.9037C29.5518 27.1804 29.5736 27.6504 29.297 27.9538C29.1505 28.1147 28.9494 28.1964 28.7476 28.1964Z" fill="#375E7D"/>
|
||||||
|
<path d="M31.4073 35.0686C31.0354 35.0686 30.7143 34.79 30.67 34.4114L30.3441 31.6216C30.2965 31.2139 30.5884 30.8447 30.9962 30.7971C31.4024 30.7501 31.7731 31.0412 31.8207 31.4491L32.1466 34.239C32.1942 34.6467 31.9023 35.0158 31.4945 35.0635C31.4653 35.0668 31.4362 35.0686 31.4073 35.0686Z" fill="#375E7D"/>
|
||||||
|
<path d="M30.7842 44.8168C29.1281 44.8168 27.4649 44.552 25.8462 44.0187C17.6097 41.3075 13.1147 32.3994 15.8264 24.1612C17.1414 20.1702 19.9313 16.93 23.6818 15.0373C27.4331 13.1443 31.6965 12.8261 35.6866 14.1409C43.9069 16.8469 48.4056 25.7377 45.7183 33.9632L45.7125 33.9826C45.7106 33.989 45.7086 33.9953 45.7066 34.0017C44.3916 37.9922 41.6018 41.2319 37.851 43.1239C35.6214 44.2482 33.2107 44.8168 30.7842 44.8168ZM30.7519 14.8303C28.554 14.8303 26.3711 15.3453 24.3517 16.3644C20.9554 18.0782 18.4292 21.0123 17.2384 24.6261C14.783 32.0855 18.853 40.1517 26.3112 42.6066C29.9246 43.7974 33.785 43.5096 37.1814 41.7964C40.5747 40.0847 43.0995 37.1548 44.2915 33.5454L44.297 33.5271C44.2987 33.5213 44.3006 33.5153 44.3025 33.5096C46.7413 26.0592 42.6677 18.0039 35.2216 15.5527C35.2215 15.5527 35.2214 15.5526 35.2213 15.5526C33.7565 15.0699 32.2507 14.8303 30.7519 14.8303Z" fill="#FFC250"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.5489 26.7028C30.2509 26.2758 28.8518 26.981 28.4247 28.279C27.9977 29.577 28.7029 30.9762 30.0008 31.4032C31.2988 31.8303 32.6979 31.1251 33.1249 29.8271C33.552 28.5291 32.8468 27.1299 31.5489 26.7028Z" fill="#FFE07D"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.1249 29.8271C33.552 28.5291 32.8468 27.1299 31.5489 26.7029C30.8718 26.4809 30.1666 26.5652 29.5851 26.8826C30.7847 27.3658 31.4197 28.706 31.0095 29.9534C30.8044 30.5715 30.3802 31.0575 29.8492 31.3497C29.8998 31.3694 29.9504 31.3863 30.0009 31.4031C31.2989 31.8303 32.698 31.1251 33.1249 29.8271Z" fill="#FFE07D"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.7 KiB |
11
assets/icons/garage_preferences_icon.svg
Normal file
11
assets/icons/garage_preferences_icon.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="46" height="50" viewBox="0 0 46 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M4.15027 2.12148V47.8785C4.15027 49.0502 5.10007 50 6.27175 50C7.44343 50 8.39324 49.0502 8.39324 47.8785V2.12148C8.39314 0.949805 7.44333 0 6.27175 0C5.10017 0 4.15027 0.949805 4.15027 2.12148Z" fill="#655E67"/>
|
||||||
|
<path d="M20.7635 2.12148V47.8785C20.7635 49.0502 21.7134 50 22.885 50C24.0567 50 25.0065 49.0502 25.0065 47.8785V2.12148C25.0065 0.949805 24.0567 0 22.885 0C21.7134 0 20.7635 0.949805 20.7635 2.12148Z" fill="#655E67"/>
|
||||||
|
<path d="M37.3768 2.12148V47.8785C37.3768 49.0502 38.3266 50 39.4983 50C40.67 50 41.6198 49.0502 41.6198 47.8785V2.12148C41.6198 0.949805 40.67 0 39.4983 0C38.3266 0 37.3768 0.949805 37.3768 2.12148Z" fill="#655E67"/>
|
||||||
|
<path d="M0 15.1651V20.7505C0 21.3062 0.450391 21.7566 1.00605 21.7566H11.5375C12.0932 21.7566 12.5436 21.3062 12.5436 20.7505V15.1651C12.5436 14.6094 12.0932 14.159 11.5375 14.159H1.00605C0.450391 14.159 0 14.6094 0 15.1651Z" fill="#717ED4"/>
|
||||||
|
<path d="M16.6133 29.2496V34.835C16.6133 35.3907 17.0637 35.8411 17.6193 35.8411H28.1508C28.7064 35.8411 29.1568 35.3907 29.1568 34.835V29.2496C29.1568 28.6939 28.7064 28.2435 28.1508 28.2435H17.6193C17.0638 28.2436 16.6133 28.694 16.6133 29.2496Z" fill="#F9BF64"/>
|
||||||
|
<path d="M33.2266 15.1651V20.7505C33.2266 21.3062 33.677 21.7566 34.2327 21.7566H44.7641C45.3198 21.7566 45.7702 21.3062 45.7702 20.7505V15.1651C45.7702 14.6094 45.3198 14.159 44.7641 14.159H34.2326C33.677 14.159 33.2266 14.6094 33.2266 15.1651Z" fill="#DF646E"/>
|
||||||
|
<path d="M44.7641 14.159H41.746C42.3017 14.159 42.7521 14.6094 42.7521 15.1651V20.7505C42.7521 21.3061 42.3017 21.7566 41.746 21.7566H44.7641C45.3198 21.7566 45.7702 21.3062 45.7702 20.7505V15.1651C45.7702 14.6094 45.3198 14.159 44.7641 14.159Z" fill="#D82F3C"/>
|
||||||
|
<path d="M28.1508 28.2435H25.1327C25.6884 28.2435 26.1387 28.6939 26.1387 29.2496V34.835C26.1387 35.3907 25.6884 35.8411 25.1327 35.8411H28.1508C28.7064 35.8411 29.1568 35.3907 29.1568 34.835V29.2496C29.1568 28.6939 28.7063 28.2435 28.1508 28.2435Z" fill="#E9A761"/>
|
||||||
|
<path d="M11.5375 14.159H8.51941C9.07507 14.159 9.52546 14.6094 9.52546 15.1651V20.7505C9.52546 21.3061 9.07507 21.7566 8.51941 21.7566H11.5375C12.0931 21.7566 12.5435 21.3062 12.5435 20.7505V15.1651C12.5434 14.6094 12.093 14.159 11.5375 14.159Z" fill="#5766CC"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
28
assets/icons/garage_schedule.svg
Normal file
28
assets/icons/garage_schedule.svg
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M23.8179 47.6354C36.972 47.6354 47.6355 36.9719 47.6355 23.8178C47.6355 10.6636 36.972 9.15527e-05 23.8179 9.15527e-05C10.6637 9.15527e-05 0.000183105 10.6636 0.000183105 23.8178C0.000183105 36.9719 10.6637 47.6354 23.8179 47.6354Z" fill="#F07281"/>
|
||||||
|
<path d="M24.8239 47.6147C24.4909 47.6287 24.1549 47.6357 23.8179 47.6357C10.664 47.6357 0 36.9718 0 23.8179C0 10.664 10.664 0 23.8179 0C24.1549 0 24.4909 0.00703125 24.8239 0.0210938C12.1367 0.548242 2.01201 11.001 2.01201 23.8179C2.01201 36.6348 12.1367 47.0875 24.8239 47.6147Z" fill="#EB5569"/>
|
||||||
|
<path d="M23.8181 44.5108C35.2465 44.5108 44.5111 35.2463 44.5111 23.8178C44.5111 12.3894 35.2465 3.12488 23.8181 3.12488C12.3897 3.12488 3.12512 12.3894 3.12512 23.8178C3.12512 35.2463 12.3897 44.5108 23.8181 44.5108Z" fill="#EAF6FF"/>
|
||||||
|
<path d="M25.3269 44.4567C24.8289 44.4929 24.3248 44.511 23.8178 44.511C12.3892 44.511 3.12463 35.2465 3.12463 23.8178C3.12463 12.3892 12.3893 3.12468 23.8179 3.12468C24.3249 3.12468 24.8289 3.14275 25.327 3.17898C14.6026 3.95173 6.1428 12.8964 6.1428 23.8178C6.1428 34.7393 14.6026 43.6841 25.3269 44.4567Z" fill="#D8ECFE"/>
|
||||||
|
<path d="M22.5243 11.7706L23.448 11.1759C23.6734 11.0308 23.9627 11.0308 24.1881 11.1759L25.1119 11.7706C25.2793 11.8785 25.3806 12.0641 25.3806 12.2633V24.0946H22.2556V12.2633C22.2555 12.0641 22.3568 11.8786 22.5243 11.7706Z" fill="#5680A6"/>
|
||||||
|
<path d="M24.8239 11.5855L24.2675 11.9437V24.0945H22.2554V12.3165C22.2554 12.0841 22.3735 11.8676 22.5689 11.7418L23.4476 11.176C23.673 11.0309 23.9625 11.0309 24.1879 11.176L24.8239 11.5855Z" fill="#497090"/>
|
||||||
|
<path d="M33.5805 24.188L33.0147 25.0668C32.8888 25.2622 32.6724 25.3803 32.44 25.3803H23.8179V22.2556H32.44C32.6724 22.2556 32.8889 22.3737 33.0147 22.5691L33.5805 23.4479C33.7256 23.6733 33.7256 23.9626 33.5805 24.188Z" fill="#5680A6"/>
|
||||||
|
<path d="M28.018 23.8179C28.018 24.3702 27.9114 24.8974 27.7162 25.3803H23.8177V22.2556H27.7162C27.9114 22.7385 28.018 23.2656 28.018 23.8179Z" fill="#497090"/>
|
||||||
|
<path d="M23.818 26.0059C25.0265 26.0059 26.0061 25.0263 26.0061 23.8179C26.0061 22.6094 25.0265 21.6298 23.818 21.6298C22.6096 21.6298 21.6299 22.6094 21.6299 23.8179C21.6299 25.0263 22.6096 26.0059 23.818 26.0059Z" fill="#F07281"/>
|
||||||
|
<path d="M24.8239 25.7606C24.5231 25.9175 24.181 26.0061 23.8178 26.0061C22.6096 26.0061 21.6298 25.0262 21.6298 23.818C21.6298 22.6098 22.6096 21.6299 23.8178 21.6299C24.181 21.6299 24.5231 21.7185 24.8239 21.8754C24.1217 22.2386 23.6418 22.973 23.6418 23.8181C23.6418 24.6632 24.1217 25.3974 24.8239 25.7606Z" fill="#EB5569"/>
|
||||||
|
<path d="M49.3331 41.0217V39.4608C49.3331 39.1491 49.1221 38.8768 48.8203 38.7989L47.1254 38.3615C46.9368 37.6012 46.637 36.8848 46.2431 36.2311L47.1322 34.7235C47.2906 34.455 47.2471 34.1134 47.0267 33.8929L45.923 32.7891C45.7026 32.5687 45.3609 32.5253 45.0923 32.6837L43.5847 33.5727C42.9311 33.1788 42.2147 32.8791 41.4543 32.6904L41.0169 30.9956C40.939 30.6937 40.6667 30.4828 40.355 30.4828H38.7942C38.4825 30.4828 38.2102 30.6937 38.1323 30.9956L37.6949 32.6904C36.9345 32.8791 36.2181 33.1789 35.5645 33.5727L34.0569 32.6837C33.7883 32.5253 33.4467 32.5687 33.2262 32.7891L32.1225 33.8929C31.9021 34.1133 31.8587 34.455 32.017 34.7235L32.9061 36.2311C32.5122 36.8848 32.2124 37.6012 32.0238 38.3615L30.329 38.7989C30.0271 38.8768 29.8162 39.1491 29.8162 39.4608V41.0217C29.8162 41.3334 30.0271 41.6057 30.329 41.6836L32.0238 42.121C32.2124 42.8813 32.5123 43.5977 32.9061 44.2514L32.017 45.759C31.8586 46.0275 31.9021 46.3691 32.1225 46.5896L33.2262 47.6933C33.4466 47.9138 33.7883 47.9571 34.0569 47.7988L35.5645 46.9098C36.2181 47.3037 36.9345 47.6034 37.6949 47.7921L38.1323 49.4869C38.2102 49.7888 38.4825 49.9997 38.7942 49.9997H40.355C40.6667 49.9997 40.939 49.7888 41.0169 49.4869L41.4543 47.7921C42.2147 47.6034 42.9311 47.3036 43.5847 46.9098L45.0923 47.7988C45.3609 47.9572 45.7025 47.9138 45.923 47.6933L47.0267 46.5896C47.2471 46.3692 47.2905 46.0275 47.1322 45.759L46.2431 44.2514C46.6371 43.5977 46.9368 42.8813 47.1254 42.121L48.8203 41.6836C49.1221 41.6057 49.3331 41.3334 49.3331 41.0217Z" fill="#88B4F5"/>
|
||||||
|
<path d="M31.8289 38.9315V41.5513L34.0362 42.1207C34.2243 42.8812 34.5241 43.5976 34.9185 44.2515L33.7606 46.2152L34.8662 47.3209L34.0568 47.7983C33.7882 47.9567 33.4465 47.9134 33.2261 47.6929L32.1229 46.5896C31.9025 46.3692 31.8591 46.0275 32.0174 45.7591L32.9064 44.2515C32.512 43.5976 32.2122 42.8812 32.0241 42.1207L30.3296 41.6836C30.0278 41.6058 29.8168 41.3334 29.8168 41.0217V39.4609C29.8168 39.1493 30.0277 38.877 30.3294 38.7991L32.0242 38.3611C32.2122 37.6016 32.512 36.8843 32.9065 36.2313L32.0174 34.7235C31.8591 34.4551 31.9025 34.1135 32.1228 33.8931L33.2262 32.7891C33.4466 32.5685 33.7884 32.5251 34.057 32.6835L34.8662 33.1608L33.7606 34.2676L34.9185 36.2313C34.5242 36.8843 34.2244 37.6016 34.0362 38.3611L31.8289 38.9315Z" fill="#6EA2F2"/>
|
||||||
|
<path d="M39.7071 47.7918L40.2766 50H38.7941C38.4823 50 38.2101 49.7891 38.1322 49.4871L37.695 47.7918C37.3379 47.7043 36.9897 47.5906 36.6538 47.4538L37.5764 46.9096C38.2303 47.3038 38.9466 47.6036 39.7071 47.7918Z" fill="#6EA2F2"/>
|
||||||
|
<path d="M38.7941 30.4829H40.2766L39.7071 32.6901C38.9466 32.8793 38.2303 33.1791 37.5764 33.5725L36.6538 33.0282C36.9898 32.8924 37.3379 32.7787 37.695 32.6902L38.1321 30.9958C38.2101 30.6938 38.4824 30.4829 38.7941 30.4829Z" fill="#6EA2F2"/>
|
||||||
|
<path d="M39.5747 44.9442C42.1721 44.9442 44.2778 42.8386 44.2778 40.2412C44.2778 37.6438 42.1721 35.5382 39.5747 35.5382C36.9773 35.5382 34.8717 37.6438 34.8717 40.2412C34.8717 42.8386 36.9773 44.9442 39.5747 44.9442Z" fill="#5680A6"/>
|
||||||
|
<path d="M41.0834 44.6971C40.6096 44.8581 40.1015 44.9446 39.5743 44.9446C36.9777 44.9446 34.8721 42.8389 34.8721 40.2414C34.8721 37.6438 36.9777 35.5382 39.5743 35.5382C40.1015 35.5382 40.6095 35.6247 41.0834 35.7856C39.2272 36.4144 37.8902 38.1719 37.8902 40.2414C37.8902 42.3108 39.2272 44.0683 41.0834 44.6971Z" fill="#497090"/>
|
||||||
|
<path d="M23.8181 8.84687C23.4014 8.84687 23.0636 8.50908 23.0636 8.09238V6.14326C23.0636 5.72656 23.4014 5.38876 23.8181 5.38876C24.2348 5.38876 24.5726 5.72656 24.5726 6.14326V8.09228C24.5726 8.50898 24.2348 8.84687 23.8181 8.84687Z" fill="#88B4F5"/>
|
||||||
|
<path d="M23.8181 42.2471C23.4014 42.2471 23.0636 41.9093 23.0636 41.4926V39.5435C23.0636 39.1268 23.4014 38.789 23.8181 38.789C24.2348 38.789 24.5726 39.1268 24.5726 39.5435V41.4926C24.5726 41.9092 24.2348 42.2471 23.8181 42.2471Z" fill="#88B4F5"/>
|
||||||
|
<path d="M8.09249 24.5725H6.14347C5.72677 24.5725 5.38898 24.2347 5.38898 23.818C5.38898 23.4013 5.72677 23.0635 6.14347 23.0635H8.09249C8.50919 23.0635 8.84699 23.4013 8.84699 23.818C8.84699 24.2347 8.50919 24.5725 8.09249 24.5725Z" fill="#88B4F5"/>
|
||||||
|
<path d="M41.4927 24.5725H39.5437C39.1269 24.5725 38.7892 24.2347 38.7892 23.818C38.7892 23.4013 39.127 23.0635 39.5437 23.0635H41.4927C41.9095 23.0635 42.2472 23.4013 42.2472 23.818C42.2472 24.2347 41.9094 24.5725 41.4927 24.5725Z" fill="#88B4F5"/>
|
||||||
|
<path d="M8.51212 33.4099C8.25138 33.4099 7.99777 33.2746 7.85802 33.0325C7.64962 32.6716 7.77325 32.2101 8.13419 32.0018L9.82208 31.0273C10.1827 30.8191 10.6443 30.9425 10.8527 31.3035C11.0611 31.6643 10.9375 32.1258 10.5766 32.3341L8.88868 33.3086C8.76993 33.3773 8.64015 33.4099 8.51212 33.4099Z" fill="#88B4F5"/>
|
||||||
|
<path d="M37.4376 16.7098C37.1769 16.7098 36.9233 16.5744 36.7835 16.3323C36.5751 15.9715 36.6989 15.51 37.0597 15.3017L38.7476 14.3272C39.1083 14.1189 39.5699 14.2424 39.7783 14.6033C39.9867 14.9642 39.8629 15.4257 39.5021 15.634L37.8142 16.6085C37.6954 16.6772 37.5656 16.7098 37.4376 16.7098Z" fill="#88B4F5"/>
|
||||||
|
<path d="M10.1986 16.7097C10.0706 16.7097 9.94093 16.6771 9.82208 16.6085L8.13419 15.634C7.77325 15.4256 7.64962 14.9641 7.85802 14.6033C8.06632 14.2424 8.52775 14.1186 8.88868 14.3271L10.5766 15.3016C10.9375 15.51 11.0611 15.9715 10.8527 16.3323C10.713 16.5744 10.4594 16.7097 10.1986 16.7097Z" fill="#88B4F5"/>
|
||||||
|
<path d="M14.9801 39.8791C14.8521 39.8791 14.7224 39.8465 14.6036 39.7779C14.2426 39.5695 14.119 39.108 14.3274 38.7472L15.3019 37.0593C15.5102 36.6984 15.9717 36.5746 16.3326 36.7831C16.6935 36.9915 16.8171 37.453 16.6087 37.8138L15.6342 39.5017C15.4945 39.7438 15.2409 39.8791 14.9801 39.8791Z" fill="#88B4F5"/>
|
||||||
|
<path d="M31.6802 10.9538C31.5522 10.9538 31.4225 10.9212 31.3037 10.8525C30.9428 10.6442 30.8191 10.1827 31.0275 9.82184L32.002 8.13395C32.2103 7.77301 32.6716 7.64938 33.0327 7.85778C33.3935 8.06608 33.5172 8.5276 33.3088 8.88844L32.3343 10.5763C32.1946 10.8184 31.941 10.9538 31.6802 10.9538Z" fill="#88B4F5"/>
|
||||||
|
<path d="M15.956 10.9538C15.6953 10.9538 15.4416 10.8184 15.3019 10.5763L14.3274 8.88845C14.119 8.52761 14.2426 8.06609 14.6036 7.85779C14.9643 7.64939 15.4259 7.77303 15.6342 8.13396L16.6087 9.82185C16.8171 10.1827 16.6935 10.6442 16.3326 10.8525C16.2138 10.9211 16.084 10.9538 15.956 10.9538Z" fill="#88B4F5"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.7 KiB |
117
assets/icons/open_garage_door.svg
Normal file
117
assets/icons/open_garage_door.svg
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<svg width="290" height="290" viewBox="0 0 290 290" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_4111_515)">
|
||||||
|
<rect x="20" y="20" width="250" height="250" rx="100" fill="#EDEDED"/>
|
||||||
|
<path d="M92.5676 124.459H197.432V204.459H92.5676V124.459Z" fill="url(#paint0_linear_4111_515)"/>
|
||||||
|
<path d="M92.5908 149.353H130.176V205H92.5908V149.353Z" fill="url(#paint1_linear_4111_515)"/>
|
||||||
|
<g clip-path="url(#clip0_4111_515)">
|
||||||
|
<path d="M92.7646 117.568H197.471V130.038H92.7646V117.568Z" fill="url(#paint2_linear_4111_515)"/>
|
||||||
|
<path d="M92.7646 127.45H197.471V139.921H92.7646V127.45Z" fill="url(#paint3_linear_4111_515)"/>
|
||||||
|
<path d="M92.7646 137.332H197.471V149.803H92.7646V137.332Z" fill="url(#paint4_linear_4111_515)"/>
|
||||||
|
</g>
|
||||||
|
<path d="M199.649 114.801L156.765 88.0353C153.522 86.0118 149.261 85 145 85C140.739 85 136.478 86.0118 133.235 88.0353L90.3513 114.801C87.0226 116.879 85 120.525 85 124.449V197.537C85 201.659 88.3412 205 92.4628 205C94.58 205 96.2965 203.284 96.2965 201.166V134.999C96.2965 130.646 99.8252 127.118 104.178 127.118H185.822C190.175 127.118 193.704 130.646 193.704 134.999V201.166C193.704 203.284 195.42 205 197.537 205C201.659 205 205 201.659 205 197.537V124.449C205 120.525 202.977 116.879 199.649 114.801Z" fill="url(#paint5_linear_4111_515)"/>
|
||||||
|
<path d="M199.649 114.801L156.765 88.0353C153.522 86.0118 149.261 85 145 85C140.739 85 136.478 86.0118 133.235 88.0353L90.3513 114.801C87.0226 116.879 85 120.525 85 124.449V135.743C85 131.819 87.0226 128.172 90.3513 126.095L133.235 99.3287C136.478 97.3052 140.739 96.2934 145 96.2934C149.261 96.2934 153.522 97.3052 156.765 99.3287L199.649 126.095C202.977 128.172 205 131.819 205 135.743V124.449C205 120.525 202.977 116.879 199.649 114.801Z" fill="url(#paint6_linear_4111_515)"/>
|
||||||
|
<path d="M131.593 111.677H158.407C159.926 111.677 161.156 110.446 161.156 108.928C161.156 107.41 159.926 106.179 158.407 106.179H131.593C130.074 106.179 128.844 107.41 128.844 108.928C128.844 110.446 130.075 111.677 131.593 111.677Z" fill="url(#paint7_linear_4111_515)"/>
|
||||||
|
<path d="M131.593 121.795H158.407C159.926 121.795 161.156 120.564 161.156 119.046C161.156 117.527 159.926 116.297 158.407 116.297H131.593C130.074 116.297 128.844 117.528 128.844 119.046C128.844 120.564 130.075 121.795 131.593 121.795Z" fill="url(#paint8_linear_4111_515)"/>
|
||||||
|
<path d="M205 135.744V197.536C205 199.598 204.165 201.464 202.814 202.814C201.464 204.165 199.598 205 197.536 205C195.419 205 193.704 203.285 193.704 201.167V134.998C193.704 130.647 190.174 127.118 185.821 127.118H104.179C99.8259 127.118 96.2965 130.647 96.2965 134.998V201.167C96.2965 202.226 95.8682 203.184 95.1741 203.878C94.48 204.572 93.5224 205 92.4635 205C88.3412 205 85 201.659 85 197.536V135.744C85 131.819 87.0235 128.172 90.3506 126.094L133.235 99.3294C136.478 97.3059 140.739 96.2941 145 96.2941C149.261 96.2941 153.522 97.3059 156.765 99.3294L199.649 126.094C202.976 128.172 205 131.819 205 135.744Z" fill="url(#paint9_linear_4111_515)"/>
|
||||||
|
<path d="M145.236 89.7092C138.367 89.7092 131.708 91.6861 125.979 95.4266C124.456 96.4207 124.028 98.4609 125.022 99.9835L130.442 105.42C130.241 106.14 130.336 106.937 130.775 107.613L135.816 112.723C135.627 113.301 135.689 113.956 136.044 114.508L141.425 119.781C141.068 121.102 141.404 122.572 142.442 123.61L145.949 127.118H185.822C190.175 127.118 193.704 130.646 193.704 134.999V174.872L205 186.168V135.955L164.492 95.4266C158.763 91.6864 152.104 89.7092 145.236 89.7092Z" fill="url(#paint10_linear_4111_515)"/>
|
||||||
|
<path d="M153.562 111.378C151.008 109.737 148.047 108.87 145 108.87C141.953 108.87 138.992 109.737 136.438 111.377C135.465 112.003 135.183 113.299 135.808 114.273C136.433 115.246 137.73 115.528 138.703 114.903C140.58 113.697 142.757 113.06 145 113.06C147.243 113.06 149.42 113.697 151.297 114.903C151.647 115.128 152.039 115.236 152.427 115.236C153.117 115.236 153.792 114.896 154.192 114.273C154.817 113.3 154.535 112.003 153.562 111.378Z" fill="url(#paint11_linear_4111_515)"/>
|
||||||
|
<path d="M158.669 103.651C154.599 101.007 149.872 99.6099 145 99.6099C140.128 99.6099 135.401 101.007 131.331 103.651C130.083 104.461 129.729 106.13 130.539 107.377C131.35 108.625 133.018 108.98 134.266 108.169C137.46 106.094 141.172 104.998 145 104.998C148.828 104.998 152.54 106.094 155.734 108.169C156.187 108.464 156.696 108.604 157.199 108.604C158.08 108.604 158.944 108.172 159.46 107.377C160.271 106.13 159.917 104.461 158.669 103.651Z" fill="url(#paint12_linear_4111_515)"/>
|
||||||
|
<path d="M164.256 95.1913C158.528 91.4508 151.869 89.4736 145 89.4736C138.131 89.4736 131.472 91.4506 125.744 95.1911C124.221 96.1852 123.792 98.2254 124.787 99.748C125.781 101.271 127.821 101.699 129.344 100.705C133.999 97.6654 139.413 96.0588 145 96.0588C150.587 96.0588 156.001 97.6654 160.656 100.705C161.212 101.068 161.836 101.241 162.453 101.241C163.528 101.241 164.582 100.716 165.213 99.7482C166.208 98.2256 165.779 96.1854 164.256 95.1913Z" fill="url(#paint13_linear_4111_515)"/>
|
||||||
|
<path d="M145 124.532C147.182 124.532 148.951 122.763 148.951 120.581C148.951 118.399 147.182 116.63 145 116.63C142.818 116.63 141.049 118.399 141.049 120.581C141.049 122.763 142.818 124.532 145 124.532Z" fill="url(#paint14_linear_4111_515)"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_4111_515" x="0" y="0" width="290" height="290" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="10"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4111_515"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4111_515" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="paint0_linear_4111_515" x1="145" y1="154.648" x2="145" y2="196.939" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#62DBFB"/>
|
||||||
|
<stop offset="0.1912" stop-color="#57D5FA"/>
|
||||||
|
<stop offset="0.5232" stop-color="#3BC5F7"/>
|
||||||
|
<stop offset="0.954" stop-color="#0DABF2"/>
|
||||||
|
<stop offset="1" stop-color="#08A9F1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_4111_515" x1="105.706" y1="177.176" x2="93.7059" y2="177.176" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#0593FC" stop-opacity="0"/>
|
||||||
|
<stop offset="0.6831" stop-color="#0389FC" stop-opacity="0.683"/>
|
||||||
|
<stop offset="1" stop-color="#0182FC"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_4111_515" x1="145.118" y1="122.273" x2="145.118" y2="128.866" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_4111_515" x1="145.118" y1="132.156" x2="145.118" y2="138.748" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_4111_515" x1="145.118" y1="142.038" x2="145.118" y2="148.631" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#017297"/>
|
||||||
|
<stop offset="1" stop-color="#024C67"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_4111_515" x1="112.144" y1="101.95" x2="168.144" y2="201.715" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EAF9FA"/>
|
||||||
|
<stop offset="1" stop-color="#B3DAFE"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_4111_515" x1="145" y1="67.5915" x2="145" y2="137.895" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#7BACDF" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="#7BACDF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint7_linear_4111_515" x1="145" y1="110.944" x2="145" y2="105.881" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EAF9FA"/>
|
||||||
|
<stop offset="1" stop-color="#B3DAFE"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint8_linear_4111_515" x1="145" y1="121.061" x2="145" y2="115.998" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EAF9FA"/>
|
||||||
|
<stop offset="1" stop-color="#B3DAFE"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint9_linear_4111_515" x1="126.473" y1="129.525" x2="115.65" y2="108.113" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#7BACDF" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="#7BACDF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint10_linear_4111_515" x1="175.367" y1="132.235" x2="141.72" y2="85.8824" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#7BACDF" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="#7BACDF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint11_linear_4111_515" x1="143.315" y1="108.32" x2="146.188" y2="116.541" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#AEFFD1"/>
|
||||||
|
<stop offset="0.1201" stop-color="#A3F9CB"/>
|
||||||
|
<stop offset="0.3288" stop-color="#87EAB9"/>
|
||||||
|
<stop offset="0.6012" stop-color="#59D19D"/>
|
||||||
|
<stop offset="0.9235" stop-color="#19AF77"/>
|
||||||
|
<stop offset="1" stop-color="#09A76D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint12_linear_4111_515" x1="142.584" y1="97.1318" x2="145.857" y2="109.025" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#AEFFD1"/>
|
||||||
|
<stop offset="0.1201" stop-color="#A3F9CB"/>
|
||||||
|
<stop offset="0.3288" stop-color="#87EAB9"/>
|
||||||
|
<stop offset="0.6012" stop-color="#59D19D"/>
|
||||||
|
<stop offset="0.9235" stop-color="#19AF77"/>
|
||||||
|
<stop offset="1" stop-color="#09A76D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint13_linear_4111_515" x1="142.471" y1="88.6965" x2="145.983" y2="101.547" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#AEFFD1"/>
|
||||||
|
<stop offset="0.1201" stop-color="#A3F9CB"/>
|
||||||
|
<stop offset="0.3288" stop-color="#87EAB9"/>
|
||||||
|
<stop offset="0.6012" stop-color="#59D19D"/>
|
||||||
|
<stop offset="0.9235" stop-color="#19AF77"/>
|
||||||
|
<stop offset="1" stop-color="#09A76D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint14_linear_4111_515" x1="141.169" y1="116.749" x2="147.514" y2="123.095" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#AEFFD1"/>
|
||||||
|
<stop offset="0.1201" stop-color="#A3F9CB"/>
|
||||||
|
<stop offset="0.3288" stop-color="#87EAB9"/>
|
||||||
|
<stop offset="0.6012" stop-color="#59D19D"/>
|
||||||
|
<stop offset="0.9235" stop-color="#19AF77"/>
|
||||||
|
<stop offset="1" stop-color="#09A76D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="clip0_4111_515">
|
||||||
|
<rect width="104.88" height="81.9651" fill="white" transform="translate(92.5908 122.838)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 10 KiB |
411
lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart
Normal file
411
lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/garage_door_model.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/status_model.dart';
|
||||||
|
import 'package:syncrow_app/services/api/devices_api.dart';
|
||||||
|
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||||
|
|
||||||
|
class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||||
|
final String GDId;
|
||||||
|
GarageDoorBloc({
|
||||||
|
required this.GDId,
|
||||||
|
}) : super(const GarageDoorSensorState()) {
|
||||||
|
on<GarageDoorInitial>(_fetchStatus);
|
||||||
|
on<ReportLogsInitial>(fetchLogsForLastMonth);
|
||||||
|
on<ToggleClosingReminderEvent>(_toggleClosingReminder);
|
||||||
|
on<ToggleDoorAlarmEvent>(_toggleDoorAlarm);
|
||||||
|
on<ToggleDaySelectionEvent>(toggleDaySelection);
|
||||||
|
on<ScheduleSaveapp>(saveSchedule);
|
||||||
|
on<GetScheduleEvent>(getSchedule);
|
||||||
|
on<ToggleScheduleEvent>(toggleChange);
|
||||||
|
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
|
||||||
|
on<OnClose>(_onClose);
|
||||||
|
on<SelectSecondsEvent>(selectSeconds);
|
||||||
|
on<ToggleDoorEvent>(openCloseGarageDoor);
|
||||||
|
on<GetCounterEvent>(_getCounterValue);
|
||||||
|
on<SetCounterValue>(_setCounterValue);
|
||||||
|
on<TickTimer>(_onTickTimer);
|
||||||
|
}
|
||||||
|
void _onClose(OnClose event, Emitter<GarageDoorSensorState> emit) {
|
||||||
|
_timer?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer? _timer;
|
||||||
|
bool lowBattery = false;
|
||||||
|
bool closingReminder = false;
|
||||||
|
bool doorAlarm = false;
|
||||||
|
|
||||||
|
GarageDoorModel deviceStatus = GarageDoorModel(
|
||||||
|
tr_timecon: 0,
|
||||||
|
countdown1: 0,
|
||||||
|
countdownAlarm: 0,
|
||||||
|
doorContactState: false,
|
||||||
|
doorControl1: '',
|
||||||
|
doorState1: '',
|
||||||
|
switch1: false,
|
||||||
|
voiceControl1: false,
|
||||||
|
batteryPercentage: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
void _fetchStatus(
|
||||||
|
GarageDoorInitial event, Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
try {
|
||||||
|
var response = await DevicesAPI.getDeviceStatus(GDId);
|
||||||
|
List<StatusModel> statusModelList = [];
|
||||||
|
for (var status in response['status']) {
|
||||||
|
statusModelList.add(StatusModel.fromJson(status));
|
||||||
|
}
|
||||||
|
deviceStatus = GarageDoorModel.fromJson(
|
||||||
|
statusModelList,
|
||||||
|
);
|
||||||
|
secondSelected = deviceStatus.tr_timecon;
|
||||||
|
toggleDoor = deviceStatus.switch1;
|
||||||
|
emit(UpdateState(garageSensor: deviceStatus));
|
||||||
|
Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
_listenToChanges();
|
||||||
|
} catch (e) {
|
||||||
|
emit(GarageDoorFailedState(errorMessage: e.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _toggleClosingReminder(ToggleClosingReminderEvent event,
|
||||||
|
Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||||
|
try {
|
||||||
|
closingReminder = event.isClosingReminderEnabled;
|
||||||
|
emit(UpdateState(garageSensor: deviceStatus));
|
||||||
|
await DevicesAPI.controlDevice(
|
||||||
|
DeviceControlModel(
|
||||||
|
deviceId: GDId,
|
||||||
|
code: 'closing_reminder',
|
||||||
|
value: closingReminder,
|
||||||
|
),
|
||||||
|
GDId,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
emit(GarageDoorFailedState(errorMessage: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _toggleDoorAlarm(
|
||||||
|
ToggleDoorAlarmEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||||
|
try {
|
||||||
|
doorAlarm = event.isDoorAlarmEnabled;
|
||||||
|
emit(UpdateState(garageSensor: deviceStatus));
|
||||||
|
await DevicesAPI.controlDevice(
|
||||||
|
DeviceControlModel(
|
||||||
|
deviceId: GDId,
|
||||||
|
code: 'door_alarm',
|
||||||
|
value: doorAlarm,
|
||||||
|
),
|
||||||
|
GDId,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
emit(GarageDoorFailedState(errorMessage: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceReport recordGroups =
|
||||||
|
DeviceReport(startTime: '0', endTime: '0', data: []);
|
||||||
|
|
||||||
|
Future<void> fetchLogsForLastMonth(
|
||||||
|
ReportLogsInitial event, Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
|
||||||
|
DateTime lastMonth = DateTime(now.year, now.month - 1, now.day);
|
||||||
|
int startTime = lastMonth.millisecondsSinceEpoch;
|
||||||
|
int endTime = now.millisecondsSinceEpoch;
|
||||||
|
try {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
var response = await DevicesAPI.getReportLogs(
|
||||||
|
startTime: startTime.toString(),
|
||||||
|
endTime: endTime.toString(),
|
||||||
|
deviceUuid: GDId,
|
||||||
|
code: 'doorcontact_state',
|
||||||
|
);
|
||||||
|
recordGroups = response;
|
||||||
|
emit(UpdateState(garageSensor: deviceStatus));
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage = errorData['message'];
|
||||||
|
emit(GarageDoorFailedState(errorMessage: errorMessage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_listenToChanges() {
|
||||||
|
try {
|
||||||
|
DatabaseReference ref =
|
||||||
|
FirebaseDatabase.instance.ref('device-status/$GDId');
|
||||||
|
Stream<DatabaseEvent> stream = ref.onValue;
|
||||||
|
|
||||||
|
stream.listen((DatabaseEvent event) async {
|
||||||
|
if (_timer != null) {
|
||||||
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
|
}
|
||||||
|
Map<dynamic, dynamic> usersMap =
|
||||||
|
event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
List<StatusModel> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList.add(StatusModel(code: element['code'], value: true));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus = GarageDoorModel.fromJson(statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
// add(
|
||||||
|
// DoorSensorSwitch(switchD: deviceStatus.doorContactState),
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, String>> days = [
|
||||||
|
{"day": "Sun", "key": "Sun"},
|
||||||
|
{"day": "Mon", "key": "Mon"},
|
||||||
|
{"day": "Tue", "key": "Tue"},
|
||||||
|
{"day": "Wed", "key": "Wed"},
|
||||||
|
{"day": "Thu", "key": "Thu"},
|
||||||
|
{"day": "Fri", "key": "Fri"},
|
||||||
|
{"day": "Sat", "key": "Sat"},
|
||||||
|
];
|
||||||
|
|
||||||
|
Future<void> toggleDaySelection(
|
||||||
|
ToggleDaySelectionEvent event,
|
||||||
|
Emitter<GarageDoorSensorState> emit,
|
||||||
|
) async {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
if (selectedDays.contains(event.key)) {
|
||||||
|
selectedDays.remove(event.key);
|
||||||
|
} else {
|
||||||
|
selectedDays.add(event.key);
|
||||||
|
}
|
||||||
|
emit(ChangeTimeState());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> saveSchedule(
|
||||||
|
ScheduleSaveapp event,
|
||||||
|
Emitter<GarageDoorSensorState> emit,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
if (selectedDays.isNotEmpty) {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
await DevicesAPI.postSchedule(
|
||||||
|
category: 'switch_1',
|
||||||
|
deviceId: GDId,
|
||||||
|
time: getTimeStampWithoutSeconds(selectedTime).toString(),
|
||||||
|
code: 'switch_1',
|
||||||
|
value: toggleSchedule,
|
||||||
|
days: selectedDays);
|
||||||
|
CustomSnackBar.displaySnackBar('Save Successfully');
|
||||||
|
add(GetScheduleEvent());
|
||||||
|
} else {
|
||||||
|
CustomSnackBar.displaySnackBar('Please select days');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
emit(GarageDoorFailedState(errorMessage: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getSchedule(
|
||||||
|
GetScheduleEvent event,
|
||||||
|
Emitter<GarageDoorSensorState> emit,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
final response = await DevicesAPI.getSchedule(
|
||||||
|
category: 'switch_1',
|
||||||
|
deviceId: GDId,
|
||||||
|
);
|
||||||
|
List<dynamic> jsonData = response;
|
||||||
|
listSchedule =
|
||||||
|
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage = errorData['message'];
|
||||||
|
emit(GarageDoorFailedState(errorMessage: errorMessage.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
|
||||||
|
if (dateTime == null) return null;
|
||||||
|
DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
|
||||||
|
dateTime.day, dateTime.hour, dateTime.minute);
|
||||||
|
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future toggleChange(
|
||||||
|
ToggleScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
final response = await DevicesAPI.changeSchedule(
|
||||||
|
scheduleId: event.id, deviceUuid: GDId, enable: event.toggle);
|
||||||
|
if (response == true) {
|
||||||
|
add(GetScheduleEvent());
|
||||||
|
toggleSchedule = event.toggle;
|
||||||
|
return toggleSchedule;
|
||||||
|
}
|
||||||
|
emit(IsToggleState(onOff: toggleSchedule));
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage = errorData['message'];
|
||||||
|
emit(GarageDoorFailedState(errorMessage: errorMessage.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future deleteSchedule(
|
||||||
|
DeleteScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
final response = await DevicesAPI.deleteSchedule(
|
||||||
|
scheduleId: event.id,
|
||||||
|
deviceUuid: GDId,
|
||||||
|
);
|
||||||
|
if (response == true) {
|
||||||
|
add(GetScheduleEvent());
|
||||||
|
return toggleSchedule;
|
||||||
|
}
|
||||||
|
emit(IsToggleState(onOff: toggleSchedule));
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage = errorData['message'];
|
||||||
|
emit(GarageDoorFailedState(errorMessage: errorMessage.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleSelectedIndex(
|
||||||
|
ToggleSelectedEvent event, Emitter<GarageDoorSensorState> emit) {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
selectedTabIndex = event.index;
|
||||||
|
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleCreateSchedule(
|
||||||
|
ToggleCreateScheduleEvent event, Emitter<GarageDoorSensorState> emit) {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
createSchedule = !createSchedule;
|
||||||
|
selectedDays.clear();
|
||||||
|
selectedTime = DateTime.now();
|
||||||
|
emit(UpdateCreateScheduleState(createSchedule));
|
||||||
|
}
|
||||||
|
|
||||||
|
int selectedTabIndex = 0;
|
||||||
|
bool toggleSchedule = true;
|
||||||
|
List<String> selectedDays = [];
|
||||||
|
bool createSchedule = false;
|
||||||
|
List<ScheduleModel> listSchedule = [];
|
||||||
|
DateTime? selectedTime = DateTime.now();
|
||||||
|
|
||||||
|
int secondSelected = 0;
|
||||||
|
bool toggleDoor = false;
|
||||||
|
Future<void> selectSeconds(
|
||||||
|
SelectSecondsEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
secondSelected = event.seconds;
|
||||||
|
|
||||||
|
final response = await DevicesAPI.controlDevice(
|
||||||
|
DeviceControlModel(
|
||||||
|
deviceId: GDId, code: 'tr_timecon', value: secondSelected),
|
||||||
|
GDId);
|
||||||
|
emit(UpdateState(garageSensor: deviceStatus));
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage = errorData['message'];
|
||||||
|
emit(GarageDoorFailedState(errorMessage: errorMessage.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openCloseGarageDoor(
|
||||||
|
ToggleDoorEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
emit(GarageDoorLoadingState());
|
||||||
|
try {
|
||||||
|
toggleDoor = !event.toggle;
|
||||||
|
final response = await DevicesAPI.controlDevice(
|
||||||
|
DeviceControlModel(
|
||||||
|
deviceId: GDId, code: 'switch_1', value: toggleDoor),
|
||||||
|
GDId);
|
||||||
|
add(GarageDoorInitial());
|
||||||
|
emit(UpdateState(garageSensor: deviceStatus));
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage = errorData['message'];
|
||||||
|
emit(GarageDoorFailedState(errorMessage: errorMessage.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setCounterValue(
|
||||||
|
SetCounterValue event, Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||||
|
int seconds = 0;
|
||||||
|
try {
|
||||||
|
seconds = event.duration.inSeconds;
|
||||||
|
final response = await DevicesAPI.controlDevice(
|
||||||
|
DeviceControlModel(
|
||||||
|
deviceId: GDId, code: 'countdown_1', value: seconds),
|
||||||
|
GDId);
|
||||||
|
|
||||||
|
if (response['success'] ?? false) {
|
||||||
|
deviceStatus.countdown1 = seconds;
|
||||||
|
} else {
|
||||||
|
emit(GarageDoorFailedState(errorMessage: 'Something went wrong'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
emit(GarageDoorFailedState(errorMessage: e.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (seconds > 0) {
|
||||||
|
_onStartTimer(seconds);
|
||||||
|
} else {
|
||||||
|
_timer?.cancel();
|
||||||
|
emit(TimerRunComplete());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _getCounterValue(
|
||||||
|
GetCounterEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||||
|
emit(LoadingInitialState());
|
||||||
|
try {
|
||||||
|
var response = await DevicesAPI.getDeviceStatus(GDId);
|
||||||
|
List<StatusModel> statusModelList = [];
|
||||||
|
for (var status in response['status']) {
|
||||||
|
statusModelList.add(StatusModel.fromJson(status));
|
||||||
|
}
|
||||||
|
deviceStatus = GarageDoorModel.fromJson(statusModelList);
|
||||||
|
if (event.deviceCode == 'countdown_1') {
|
||||||
|
deviceStatus.countdown1 > 0
|
||||||
|
? _onStartTimer(deviceStatus.countdown1)
|
||||||
|
: emit(UpdateTimerState(seconds: deviceStatus.countdown1));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
emit(GarageDoorFailedState(errorMessage: e.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStartTimer(int seconds) {
|
||||||
|
_timer?.cancel();
|
||||||
|
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
|
add(TickTimer(remainingTime: seconds - timer.tick));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onTickTimer(TickTimer event, Emitter<GarageDoorSensorState> emit) {
|
||||||
|
if (event.remainingTime > 0) {
|
||||||
|
emit(TimerRunInProgress(event.remainingTime));
|
||||||
|
} else {
|
||||||
|
_timer?.cancel();
|
||||||
|
emit(TimerRunComplete());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
abstract class GarageDoorEvent extends Equatable {
|
||||||
|
const GarageDoorEvent();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class GarageDoorLoading extends GarageDoorEvent {}
|
||||||
|
|
||||||
|
class GarageDoorSwitch extends GarageDoorEvent {
|
||||||
|
final bool switchD;
|
||||||
|
final String deviceId;
|
||||||
|
final String productId;
|
||||||
|
const GarageDoorSwitch(
|
||||||
|
{required this.switchD, this.deviceId = '', this.productId = ''});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [switchD, deviceId, productId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class GarageDoorUpdated extends GarageDoorEvent {}
|
||||||
|
|
||||||
|
class GarageDoorInitial extends GarageDoorEvent {
|
||||||
|
const GarageDoorInitial();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReportLogsInitial extends GarageDoorEvent {
|
||||||
|
const ReportLogsInitial();
|
||||||
|
}
|
||||||
|
|
||||||
|
class GarageDoorChangeStatus extends GarageDoorEvent {}
|
||||||
|
|
||||||
|
class GetCounterEvent extends GarageDoorEvent {
|
||||||
|
final String deviceCode;
|
||||||
|
const GetCounterEvent({required this.deviceCode});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceCode];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleLowBatteryEvent extends GarageDoorEvent {
|
||||||
|
final bool isLowBatteryEnabled;
|
||||||
|
|
||||||
|
const ToggleLowBatteryEvent(this.isLowBatteryEnabled);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [isLowBatteryEnabled];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleClosingReminderEvent extends GarageDoorEvent {
|
||||||
|
final bool isClosingReminderEnabled;
|
||||||
|
|
||||||
|
const ToggleClosingReminderEvent(this.isClosingReminderEnabled);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [isClosingReminderEnabled];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleDoorAlarmEvent extends GarageDoorEvent {
|
||||||
|
final bool isDoorAlarmEnabled;
|
||||||
|
|
||||||
|
const ToggleDoorAlarmEvent(this.isDoorAlarmEnabled);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [isDoorAlarmEnabled];
|
||||||
|
}
|
||||||
|
|
||||||
|
class SetCounterValue extends GarageDoorEvent {
|
||||||
|
final Duration duration;
|
||||||
|
final String deviceCode;
|
||||||
|
const SetCounterValue({required this.duration, required this.deviceCode});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [duration, deviceCode];
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartTimer extends GarageDoorEvent {
|
||||||
|
final int duration;
|
||||||
|
|
||||||
|
const StartTimer(this.duration);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [duration];
|
||||||
|
}
|
||||||
|
|
||||||
|
class TickTimer extends GarageDoorEvent {
|
||||||
|
final int remainingTime;
|
||||||
|
|
||||||
|
const TickTimer({required this.remainingTime});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [remainingTime];
|
||||||
|
}
|
||||||
|
|
||||||
|
class StopTimer extends GarageDoorEvent {}
|
||||||
|
|
||||||
|
class OnClose extends GarageDoorEvent {}
|
||||||
|
|
||||||
|
//------------------- Schedule ----------=---------
|
||||||
|
class GetScheduleEvent extends GarageDoorEvent {}
|
||||||
|
|
||||||
|
class ScheduleSaveapp extends GarageDoorEvent {}
|
||||||
|
|
||||||
|
class ToggleScheduleEvent extends GarageDoorEvent {
|
||||||
|
final String id;
|
||||||
|
final bool toggle;
|
||||||
|
const ToggleScheduleEvent({required this.toggle, required this.id});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [toggle, id];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleDaySelectionEvent extends GarageDoorEvent {
|
||||||
|
final String key;
|
||||||
|
|
||||||
|
const ToggleDaySelectionEvent({required this.key});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [key];
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeleteScheduleEvent extends GarageDoorEvent {
|
||||||
|
final String id;
|
||||||
|
const DeleteScheduleEvent({required this.id});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [id];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleSelectedEvent extends GarageDoorEvent {
|
||||||
|
final int index;
|
||||||
|
const ToggleSelectedEvent({required this.index});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleCreateScheduleEvent extends GarageDoorEvent {
|
||||||
|
final int index;
|
||||||
|
const ToggleCreateScheduleEvent({required this.index});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChangeFirstWizardSwitchStatusEvent extends GarageDoorEvent {
|
||||||
|
final bool value;
|
||||||
|
final String deviceId;
|
||||||
|
const ChangeFirstWizardSwitchStatusEvent(
|
||||||
|
{required this.value, this.deviceId = ''});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [value, deviceId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectSecondsEvent extends GarageDoorEvent {
|
||||||
|
final int seconds;
|
||||||
|
const SelectSecondsEvent({required this.seconds});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [seconds];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleDoorEvent extends GarageDoorEvent {
|
||||||
|
final bool toggle;
|
||||||
|
const ToggleDoorEvent({required this.toggle});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [toggle];
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/garage_door_model.dart';
|
||||||
|
|
||||||
|
class GarageDoorSensorState extends Equatable {
|
||||||
|
const GarageDoorSensorState();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class GarageDoorInitialState extends GarageDoorSensorState {}
|
||||||
|
|
||||||
|
class GarageDoorLoadingState extends GarageDoorSensorState {}
|
||||||
|
|
||||||
|
class GarageDoorFailedState extends GarageDoorSensorState {
|
||||||
|
final String errorMessage;
|
||||||
|
|
||||||
|
const GarageDoorFailedState({required this.errorMessage});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [errorMessage];
|
||||||
|
}
|
||||||
|
|
||||||
|
class UpdateState extends GarageDoorSensorState {
|
||||||
|
final GarageDoorModel garageSensor;
|
||||||
|
const UpdateState({required this.garageSensor});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [garageSensor];
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoadingNewSate extends GarageDoorSensorState {
|
||||||
|
final GarageDoorModel doorSensor;
|
||||||
|
const LoadingNewSate({required this.doorSensor});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [doorSensor];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChangeSlidingSegmentState extends GarageDoorSensorState {
|
||||||
|
final int value;
|
||||||
|
|
||||||
|
const ChangeSlidingSegmentState({required this.value});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [value];
|
||||||
|
}
|
||||||
|
|
||||||
|
class UpdateTimerState extends GarageDoorSensorState {
|
||||||
|
final int seconds;
|
||||||
|
const UpdateTimerState({required this.seconds});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [seconds];
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimerRunInProgress extends GarageDoorSensorState {
|
||||||
|
final int remainingTime;
|
||||||
|
|
||||||
|
const TimerRunInProgress(this.remainingTime);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [remainingTime];
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimerRunComplete extends GarageDoorSensorState {}
|
||||||
|
|
||||||
|
class SaveSchedule extends GarageDoorSensorState {}
|
||||||
|
|
||||||
|
class IsToggleState extends GarageDoorSensorState {
|
||||||
|
final bool? onOff;
|
||||||
|
const IsToggleState({this.onOff});
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChangeTimeState extends GarageDoorSensorState {}
|
||||||
|
|
||||||
|
class LoadingInitialState extends GarageDoorSensorState {}
|
||||||
|
|
||||||
|
class UpdateCreateScheduleState extends GarageDoorSensorState {
|
||||||
|
final bool createSchedule;
|
||||||
|
UpdateCreateScheduleState(this.createSchedule);
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
||||||
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_state.dart';
|
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_state.dart';
|
||||||
|
@ -31,7 +31,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
List<GroupThreeGangModel> groupThreeGangList = [];
|
List<GroupThreeGangModel> groupThreeGangList = [];
|
||||||
bool allSwitchesOn = true;
|
bool allSwitchesOn = true;
|
||||||
|
|
||||||
ThreeGangBloc({required this.threeGangId, required this.switchCode}) : super(InitialState()) {
|
ThreeGangBloc({required this.threeGangId, required this.switchCode})
|
||||||
|
: super(InitialState()) {
|
||||||
on<InitialEvent>(_fetchThreeGangStatus);
|
on<InitialEvent>(_fetchThreeGangStatus);
|
||||||
on<ThreeGangUpdated>(_threeGangUpdated);
|
on<ThreeGangUpdated>(_threeGangUpdated);
|
||||||
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
|
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
|
||||||
@ -57,7 +58,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
|
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _fetchThreeGangStatus(InitialEvent event, Emitter<ThreeGangState> emit) async {
|
void _fetchThreeGangStatus(
|
||||||
|
InitialEvent event, Emitter<ThreeGangState> emit) async {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
try {
|
try {
|
||||||
threeGangGroup = event.groupScreen;
|
threeGangGroup = event.groupScreen;
|
||||||
@ -69,7 +71,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
HomeCubit.getInstance().selectedSpace?.id ?? '', '3G');
|
HomeCubit.getInstance().selectedSpace?.id ?? '', '3G');
|
||||||
|
|
||||||
for (int i = 0; i < devicesList.length; i++) {
|
for (int i = 0; i < devicesList.length; i++) {
|
||||||
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
|
var response =
|
||||||
|
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
|
||||||
List<StatusModel> statusModelList = [];
|
List<StatusModel> statusModelList = [];
|
||||||
for (var status in response['status']) {
|
for (var status in response['status']) {
|
||||||
statusModelList.add(StatusModel.fromJson(status));
|
statusModelList.add(StatusModel.fromJson(status));
|
||||||
@ -86,13 +89,16 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
|
|
||||||
if (groupThreeGangList.isNotEmpty) {
|
if (groupThreeGangList.isNotEmpty) {
|
||||||
groupThreeGangList.firstWhere((element) {
|
groupThreeGangList.firstWhere((element) {
|
||||||
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) {
|
if (!element.firstSwitch ||
|
||||||
|
!element.secondSwitch ||
|
||||||
|
!element.thirdSwitch) {
|
||||||
allSwitchesOn = false;
|
allSwitchesOn = false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: allSwitchesOn));
|
emit(UpdateGroupState(
|
||||||
|
threeGangList: groupThreeGangList, allSwitches: allSwitchesOn));
|
||||||
} else {
|
} else {
|
||||||
var response = await DevicesAPI.getDeviceStatus(threeGangId);
|
var response = await DevicesAPI.getDeviceStatus(threeGangId);
|
||||||
List<StatusModel> statusModelList = [];
|
List<StatusModel> statusModelList = [];
|
||||||
@ -111,18 +117,21 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
|
|
||||||
_listenToChanges() {
|
_listenToChanges() {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$threeGangId');
|
DatabaseReference ref =
|
||||||
|
FirebaseDatabase.instance.ref('device-status/$threeGangId');
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
Stream<DatabaseEvent> stream = ref.onValue;
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) async {
|
stream.listen((DatabaseEvent event) async {
|
||||||
if (_timer != null) {
|
if (_timer != null) {
|
||||||
await Future.delayed(const Duration(seconds: 2));
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
}
|
}
|
||||||
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
|
Map<dynamic, dynamic> usersMap =
|
||||||
|
event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
List<StatusModel> statusList = [];
|
List<StatusModel> statusList = [];
|
||||||
|
|
||||||
usersMap['status'].forEach((element) {
|
usersMap['status'].forEach((element) {
|
||||||
statusList.add(StatusModel(code: element['code'], value: element['value']));
|
statusList
|
||||||
|
.add(StatusModel(code: element['code'], value: element['value']));
|
||||||
});
|
});
|
||||||
|
|
||||||
deviceStatus = ThreeGangModel.fromJson(statusList);
|
deviceStatus = ThreeGangModel.fromJson(statusList);
|
||||||
@ -137,7 +146,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
emit(UpdateState(threeGangModel: deviceStatus));
|
emit(UpdateState(threeGangModel: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<ThreeGangState> emit) async {
|
void _changeFirstSwitch(
|
||||||
|
ChangeFirstSwitchStatusEvent event, Emitter<ThreeGangState> emit) async {
|
||||||
emit(LoadingNewSate(threeGangModel: deviceStatus));
|
emit(LoadingNewSate(threeGangModel: deviceStatus));
|
||||||
try {
|
try {
|
||||||
if (threeGangGroup) {
|
if (threeGangGroup) {
|
||||||
@ -146,11 +156,14 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
if (element.deviceId == event.deviceId) {
|
if (element.deviceId == event.deviceId) {
|
||||||
element.firstSwitch = !event.value;
|
element.firstSwitch = !event.value;
|
||||||
}
|
}
|
||||||
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) {
|
if (!element.firstSwitch ||
|
||||||
|
!element.secondSwitch ||
|
||||||
|
!element.thirdSwitch) {
|
||||||
allSwitchesValue = false;
|
allSwitchesValue = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: allSwitchesValue));
|
emit(UpdateGroupState(
|
||||||
|
threeGangList: groupThreeGangList, allSwitches: allSwitchesValue));
|
||||||
} else {
|
} else {
|
||||||
deviceStatus.firstSwitch = !event.value;
|
deviceStatus.firstSwitch = !event.value;
|
||||||
emit(UpdateState(threeGangModel: deviceStatus));
|
emit(UpdateState(threeGangModel: deviceStatus));
|
||||||
@ -187,11 +200,14 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
if (element.deviceId == event.deviceId) {
|
if (element.deviceId == event.deviceId) {
|
||||||
element.secondSwitch = !event.value;
|
element.secondSwitch = !event.value;
|
||||||
}
|
}
|
||||||
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) {
|
if (!element.firstSwitch ||
|
||||||
|
!element.secondSwitch ||
|
||||||
|
!element.thirdSwitch) {
|
||||||
allSwitchesValue = false;
|
allSwitchesValue = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: allSwitchesValue));
|
emit(UpdateGroupState(
|
||||||
|
threeGangList: groupThreeGangList, allSwitches: allSwitchesValue));
|
||||||
} else {
|
} else {
|
||||||
deviceStatus.secondSwitch = !event.value;
|
deviceStatus.secondSwitch = !event.value;
|
||||||
emit(UpdateState(threeGangModel: deviceStatus));
|
emit(UpdateState(threeGangModel: deviceStatus));
|
||||||
@ -217,7 +233,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _changeThirdSwitch(ChangeThirdSwitchStatusEvent event, Emitter<ThreeGangState> emit) async {
|
void _changeThirdSwitch(
|
||||||
|
ChangeThirdSwitchStatusEvent event, Emitter<ThreeGangState> emit) async {
|
||||||
emit(LoadingNewSate(threeGangModel: deviceStatus));
|
emit(LoadingNewSate(threeGangModel: deviceStatus));
|
||||||
try {
|
try {
|
||||||
if (threeGangGroup) {
|
if (threeGangGroup) {
|
||||||
@ -226,11 +243,14 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
if (element.deviceId == event.deviceId) {
|
if (element.deviceId == event.deviceId) {
|
||||||
element.thirdSwitch = !event.value;
|
element.thirdSwitch = !event.value;
|
||||||
}
|
}
|
||||||
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) {
|
if (!element.firstSwitch ||
|
||||||
|
!element.secondSwitch ||
|
||||||
|
!element.thirdSwitch) {
|
||||||
allSwitchesValue = false;
|
allSwitchesValue = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: allSwitchesValue));
|
emit(UpdateGroupState(
|
||||||
|
threeGangList: groupThreeGangList, allSwitches: allSwitchesValue));
|
||||||
} else {
|
} else {
|
||||||
deviceStatus.thirdSwitch = !event.value;
|
deviceStatus.thirdSwitch = !event.value;
|
||||||
emit(UpdateState(threeGangModel: deviceStatus));
|
emit(UpdateState(threeGangModel: deviceStatus));
|
||||||
@ -269,15 +289,21 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
final response = await Future.wait([
|
final response = await Future.wait([
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: threeGangId, code: 'switch_1', value: deviceStatus.firstSwitch),
|
deviceId: threeGangId,
|
||||||
|
code: 'switch_1',
|
||||||
|
value: deviceStatus.firstSwitch),
|
||||||
threeGangId),
|
threeGangId),
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: threeGangId, code: 'switch_2', value: deviceStatus.secondSwitch),
|
deviceId: threeGangId,
|
||||||
|
code: 'switch_2',
|
||||||
|
value: deviceStatus.secondSwitch),
|
||||||
threeGangId),
|
threeGangId),
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: threeGangId, code: 'switch_3', value: deviceStatus.thirdSwitch),
|
deviceId: threeGangId,
|
||||||
|
code: 'switch_3',
|
||||||
|
value: deviceStatus.thirdSwitch),
|
||||||
threeGangId),
|
threeGangId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -303,15 +329,21 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
final response = await Future.wait([
|
final response = await Future.wait([
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: threeGangId, code: 'switch_1', value: deviceStatus.firstSwitch),
|
deviceId: threeGangId,
|
||||||
|
code: 'switch_1',
|
||||||
|
value: deviceStatus.firstSwitch),
|
||||||
threeGangId),
|
threeGangId),
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: threeGangId, code: 'switch_2', value: deviceStatus.secondSwitch),
|
deviceId: threeGangId,
|
||||||
|
code: 'switch_2',
|
||||||
|
value: deviceStatus.secondSwitch),
|
||||||
threeGangId),
|
threeGangId),
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: threeGangId, code: 'switch_3', value: deviceStatus.thirdSwitch),
|
deviceId: threeGangId,
|
||||||
|
code: 'switch_3',
|
||||||
|
value: deviceStatus.thirdSwitch),
|
||||||
threeGangId),
|
threeGangId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -333,21 +365,28 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
groupThreeGangList[i].secondSwitch = true;
|
groupThreeGangList[i].secondSwitch = true;
|
||||||
groupThreeGangList[i].thirdSwitch = true;
|
groupThreeGangList[i].thirdSwitch = true;
|
||||||
}
|
}
|
||||||
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: true));
|
emit(UpdateGroupState(
|
||||||
|
threeGangList: groupThreeGangList, allSwitches: true));
|
||||||
|
|
||||||
for (int i = 0; i < groupThreeGangList.length; i++) {
|
for (int i = 0; i < groupThreeGangList.length; i++) {
|
||||||
final response = await Future.wait([
|
final response = await Future.wait([
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: groupThreeGangList[i].deviceId, code: 'switch_1', value: true),
|
deviceId: groupThreeGangList[i].deviceId,
|
||||||
|
code: 'switch_1',
|
||||||
|
value: true),
|
||||||
groupThreeGangList[i].deviceId),
|
groupThreeGangList[i].deviceId),
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: groupThreeGangList[i].deviceId, code: 'switch_2', value: true),
|
deviceId: groupThreeGangList[i].deviceId,
|
||||||
|
code: 'switch_2',
|
||||||
|
value: true),
|
||||||
groupThreeGangList[i].deviceId),
|
groupThreeGangList[i].deviceId),
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: groupThreeGangList[i].deviceId, code: 'switch_3', value: true),
|
deviceId: groupThreeGangList[i].deviceId,
|
||||||
|
code: 'switch_3',
|
||||||
|
value: true),
|
||||||
groupThreeGangList[i].deviceId),
|
groupThreeGangList[i].deviceId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -363,7 +402,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _groupAllOff(GroupAllOffEvent event, Emitter<ThreeGangState> emit) async {
|
void _groupAllOff(
|
||||||
|
GroupAllOffEvent event, Emitter<ThreeGangState> emit) async {
|
||||||
emit(LoadingNewSate(threeGangModel: deviceStatus));
|
emit(LoadingNewSate(threeGangModel: deviceStatus));
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < groupThreeGangList.length; i++) {
|
for (int i = 0; i < groupThreeGangList.length; i++) {
|
||||||
@ -371,21 +411,28 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
groupThreeGangList[i].secondSwitch = false;
|
groupThreeGangList[i].secondSwitch = false;
|
||||||
groupThreeGangList[i].thirdSwitch = false;
|
groupThreeGangList[i].thirdSwitch = false;
|
||||||
}
|
}
|
||||||
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: false));
|
emit(UpdateGroupState(
|
||||||
|
threeGangList: groupThreeGangList, allSwitches: false));
|
||||||
|
|
||||||
for (int i = 0; i < groupThreeGangList.length; i++) {
|
for (int i = 0; i < groupThreeGangList.length; i++) {
|
||||||
final response = await Future.wait([
|
final response = await Future.wait([
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: groupThreeGangList[i].deviceId, code: 'switch_1', value: false),
|
deviceId: groupThreeGangList[i].deviceId,
|
||||||
|
code: 'switch_1',
|
||||||
|
value: false),
|
||||||
groupThreeGangList[i].deviceId),
|
groupThreeGangList[i].deviceId),
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: groupThreeGangList[i].deviceId, code: 'switch_2', value: false),
|
deviceId: groupThreeGangList[i].deviceId,
|
||||||
|
code: 'switch_2',
|
||||||
|
value: false),
|
||||||
groupThreeGangList[i].deviceId),
|
groupThreeGangList[i].deviceId),
|
||||||
DevicesAPI.controlDevice(
|
DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(
|
DeviceControlModel(
|
||||||
deviceId: groupThreeGangList[i].deviceId, code: 'switch_3', value: false),
|
deviceId: groupThreeGangList[i].deviceId,
|
||||||
|
code: 'switch_3',
|
||||||
|
value: false),
|
||||||
groupThreeGangList[i].deviceId),
|
groupThreeGangList[i].deviceId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -401,17 +448,20 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _changeSliding(ChangeSlidingSegment event, Emitter<ThreeGangState> emit) async {
|
void _changeSliding(
|
||||||
|
ChangeSlidingSegment event, Emitter<ThreeGangState> emit) async {
|
||||||
emit(ChangeSlidingSegmentState(value: event.value));
|
emit(ChangeSlidingSegmentState(value: event.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setCounterValue(SetCounterValue event, Emitter<ThreeGangState> emit) async {
|
void _setCounterValue(
|
||||||
|
SetCounterValue event, Emitter<ThreeGangState> emit) async {
|
||||||
emit(LoadingNewSate(threeGangModel: deviceStatus));
|
emit(LoadingNewSate(threeGangModel: deviceStatus));
|
||||||
int seconds = 0;
|
int seconds = 0;
|
||||||
try {
|
try {
|
||||||
seconds = event.duration.inSeconds;
|
seconds = event.duration.inSeconds;
|
||||||
final response = await DevicesAPI.controlDevice(
|
final response = await DevicesAPI.controlDevice(
|
||||||
DeviceControlModel(deviceId: threeGangId, code: event.deviceCode, value: seconds),
|
DeviceControlModel(
|
||||||
|
deviceId: threeGangId, code: event.deviceCode, value: seconds),
|
||||||
threeGangId);
|
threeGangId);
|
||||||
|
|
||||||
if (response['success'] ?? false) {
|
if (response['success'] ?? false) {
|
||||||
@ -438,7 +488,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _getCounterValue(GetCounterEvent event, Emitter<ThreeGangState> emit) async {
|
void _getCounterValue(
|
||||||
|
GetCounterEvent event, Emitter<ThreeGangState> emit) async {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
try {
|
try {
|
||||||
var response = await DevicesAPI.getDeviceStatus(threeGangId);
|
var response = await DevicesAPI.getDeviceStatus(threeGangId);
|
||||||
@ -541,6 +592,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
GetScheduleEvent event,
|
GetScheduleEvent event,
|
||||||
Emitter<ThreeGangState> emit,
|
Emitter<ThreeGangState> emit,
|
||||||
) async {
|
) async {
|
||||||
|
print('getSchedule=${switchCode}');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
final response = await DevicesAPI.getSchedule(
|
final response = await DevicesAPI.getSchedule(
|
||||||
@ -548,7 +601,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
deviceId: threeGangId,
|
deviceId: threeGangId,
|
||||||
);
|
);
|
||||||
List<dynamic> jsonData = response;
|
List<dynamic> jsonData = response;
|
||||||
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
|
listSchedule =
|
||||||
|
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
|
||||||
emit(InitialState());
|
emit(InitialState());
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
final errorData = e.response!.data;
|
final errorData = e.response!.data;
|
||||||
@ -559,12 +613,13 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
|
|
||||||
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
|
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
|
||||||
if (dateTime == null) return null;
|
if (dateTime == null) return null;
|
||||||
DateTime dateTimeWithoutSeconds =
|
DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
|
||||||
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute);
|
dateTime.day, dateTime.hour, dateTime.minute);
|
||||||
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
|
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future toggleChange(ToggleScheduleEvent event, Emitter<ThreeGangState> emit) async {
|
Future toggleChange(
|
||||||
|
ToggleScheduleEvent event, Emitter<ThreeGangState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
final response = await DevicesAPI.changeSchedule(
|
final response = await DevicesAPI.changeSchedule(
|
||||||
@ -583,7 +638,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future deleteSchedule(DeleteScheduleEvent event, Emitter<ThreeGangState> emit) async {
|
Future deleteSchedule(
|
||||||
|
DeleteScheduleEvent event, Emitter<ThreeGangState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
final response = await DevicesAPI.deleteSchedule(
|
final response = await DevicesAPI.deleteSchedule(
|
||||||
@ -603,13 +659,15 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<ThreeGangState> emit) {
|
void toggleSelectedIndex(
|
||||||
|
ToggleSelectedEvent event, Emitter<ThreeGangState> emit) {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
selectedTabIndex = event.index;
|
selectedTabIndex = event.index;
|
||||||
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
|
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<ThreeGangState> emit) {
|
void toggleCreateSchedule(
|
||||||
|
ToggleCreateScheduleEvent event, Emitter<ThreeGangState> emit) {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
createSchedule = !createSchedule;
|
createSchedule = !createSchedule;
|
||||||
selectedDays.clear();
|
selectedDays.clear();
|
||||||
|
81
lib/features/devices/model/garage_door_model.dart
Normal file
81
lib/features/devices/model/garage_door_model.dart
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import 'package:syncrow_app/features/devices/model/status_model.dart';
|
||||||
|
|
||||||
|
class GarageDoorModel {
|
||||||
|
bool switch1;
|
||||||
|
bool doorContactState;
|
||||||
|
int countdown1;
|
||||||
|
int countdownAlarm;
|
||||||
|
String doorControl1;
|
||||||
|
bool voiceControl1;
|
||||||
|
String doorState1;
|
||||||
|
int batteryPercentage;
|
||||||
|
int tr_timecon;
|
||||||
|
|
||||||
|
GarageDoorModel({
|
||||||
|
required this.switch1,
|
||||||
|
required this.doorContactState,
|
||||||
|
required this.countdown1,
|
||||||
|
required this.countdownAlarm,
|
||||||
|
required this.doorControl1,
|
||||||
|
required this.voiceControl1,
|
||||||
|
required this.doorState1,
|
||||||
|
required this.batteryPercentage,
|
||||||
|
required this.tr_timecon,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory GarageDoorModel.fromJson(List<StatusModel> jsonList) {
|
||||||
|
late bool _switch1 = false;
|
||||||
|
late bool _doorContactState = false;
|
||||||
|
late int _countdown1 = 0;
|
||||||
|
late int _countdownAlarm = 0;
|
||||||
|
late String _doorControl1 = "closed";
|
||||||
|
late bool _voiceControl1 = false;
|
||||||
|
late String _doorState1 = "closed";
|
||||||
|
late int _batteryPercentage = 0;
|
||||||
|
late int _tr_timecon = 0;
|
||||||
|
|
||||||
|
for (var status in jsonList) {
|
||||||
|
switch (status.code) {
|
||||||
|
case 'tr_timecon':
|
||||||
|
_tr_timecon = status.value ?? "closed";
|
||||||
|
break;
|
||||||
|
case 'switch_1':
|
||||||
|
_switch1 = status.value ?? false;
|
||||||
|
break;
|
||||||
|
case 'doorcontact_state':
|
||||||
|
_doorContactState = status.value ?? false;
|
||||||
|
break;
|
||||||
|
case 'countdown_1':
|
||||||
|
_countdown1 = status.value ?? 0;
|
||||||
|
break;
|
||||||
|
case 'countdown_alarm':
|
||||||
|
_countdownAlarm = status.value ?? 0;
|
||||||
|
break;
|
||||||
|
case 'door_control_1':
|
||||||
|
_doorControl1 = status.value ?? "closed";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'voice_control_1':
|
||||||
|
_voiceControl1 = status.value ?? false;
|
||||||
|
break;
|
||||||
|
case 'door_state_1':
|
||||||
|
_doorState1 = status.value ?? "closed";
|
||||||
|
break;
|
||||||
|
case 'battery_percentage':
|
||||||
|
_batteryPercentage = status.value ?? 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GarageDoorModel(
|
||||||
|
switch1: _switch1,
|
||||||
|
doorContactState: _doorContactState,
|
||||||
|
countdown1: _countdown1,
|
||||||
|
countdownAlarm: _countdownAlarm,
|
||||||
|
doorControl1: _doorControl1,
|
||||||
|
voiceControl1: _voiceControl1,
|
||||||
|
doorState1: _doorState1,
|
||||||
|
batteryPercentage: _batteryPercentage,
|
||||||
|
tr_timecon: _tr_timecon);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,204 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garagedialog.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
|
||||||
|
class CreateGarageSchedule extends StatefulWidget {
|
||||||
|
final List<Map<String, String>> days;
|
||||||
|
final void Function(List<String> selectedDays)?
|
||||||
|
selectDays;
|
||||||
|
final Function(DateTime) onDateTimeChanged;
|
||||||
|
final void Function(bool isOn)? onToggleChanged;
|
||||||
|
|
||||||
|
const CreateGarageSchedule({
|
||||||
|
Key? key,
|
||||||
|
required this.days,
|
||||||
|
required this.selectDays,
|
||||||
|
required this.onDateTimeChanged,
|
||||||
|
this.onToggleChanged,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CreateGarageScheduleState createState() => _CreateGarageScheduleState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CreateGarageScheduleState extends State<CreateGarageSchedule> {
|
||||||
|
List<String> selectedDays = [];
|
||||||
|
bool isOn = true;
|
||||||
|
String selectedControlOption = 'Open';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
const Divider(
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 110,
|
||||||
|
child: CupertinoDatePicker(
|
||||||
|
mode: CupertinoDatePickerMode.time,
|
||||||
|
initialDateTime: DateTime.now(),
|
||||||
|
onDateTimeChanged: widget.onDateTimeChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
SizedBox(
|
||||||
|
height: MediaQuery.of(context).size.height * 0.08,
|
||||||
|
child: ListView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
children: widget.days.map((day) {
|
||||||
|
bool isSelected = selectedDays.contains(day['day']);
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
if (isSelected) {
|
||||||
|
selectedDays.remove(day['day']);
|
||||||
|
} else {
|
||||||
|
selectedDays.add(day['day']!);
|
||||||
|
}
|
||||||
|
if (widget.selectDays != null) {
|
||||||
|
widget.selectDays!(selectedDays);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 50,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 8, horizontal: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: isSelected
|
||||||
|
? Colors.black
|
||||||
|
: ColorsManager.grayColor,
|
||||||
|
),
|
||||||
|
color: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(30),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
day['day']!,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: isSelected
|
||||||
|
? Colors.black
|
||||||
|
: ColorsManager.grayColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
DefaultContainer(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 50,
|
||||||
|
child: ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
leading: const BodyMedium(
|
||||||
|
text: 'Notification',
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
trailing: Transform.scale(
|
||||||
|
scale: .8,
|
||||||
|
child: CupertinoSwitch(
|
||||||
|
value: true,
|
||||||
|
onChanged: (value) {
|
||||||
|
},
|
||||||
|
applyTheme: true,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(
|
||||||
|
color: ColorsManager.graysColor,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 50,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return GarageDialog(
|
||||||
|
label2: 'Close',
|
||||||
|
initialSelectedLabel: selectedControlOption,
|
||||||
|
cancelTab: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
confirmTab: () {
|
||||||
|
setState(() {});
|
||||||
|
if (selectedControlOption == "Open") {
|
||||||
|
widget.onToggleChanged!(true);
|
||||||
|
} else if (selectedControlOption == 'Close') {
|
||||||
|
widget.onToggleChanged!(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
title: 'Control',
|
||||||
|
label1: 'Open',
|
||||||
|
onTapLabel1: (selected) {
|
||||||
|
setState(() {
|
||||||
|
selectedControlOption = 'Open';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onTapLabel2: (selected) {
|
||||||
|
setState(() {
|
||||||
|
selectedControlOption = 'Close';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
leading: const BodyMedium(
|
||||||
|
text: 'Control',
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
trailing: SizedBox(
|
||||||
|
width: 70,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
BodyMedium(
|
||||||
|
fontColor: ColorsManager.textGray,
|
||||||
|
text: selectedControlOption,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
const Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
size: 17,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,428 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/garage_door_model.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_preferences_settings.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_records_screen.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/view/widgets/garage_door/schedule_garage_screen.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/view/widgets/garage_door/timer_page.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||||
|
import 'package:syncrow_app/generated/assets.dart';
|
||||||
|
|
||||||
|
class GarageDoorScreen extends StatelessWidget {
|
||||||
|
final DeviceModel? device;
|
||||||
|
|
||||||
|
const GarageDoorScreen({super.key, this.device});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DefaultScaffold(
|
||||||
|
title: 'Garage Door Opener',
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (context) => GarageDoorBloc(GDId: device?.uuid ?? '')
|
||||||
|
..add(const GarageDoorInitial()),
|
||||||
|
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final garageBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||||
|
GarageDoorModel model = GarageDoorModel(
|
||||||
|
tr_timecon: 0,
|
||||||
|
countdown1: 0,
|
||||||
|
countdownAlarm: 0,
|
||||||
|
doorContactState: false,
|
||||||
|
doorControl1: '',
|
||||||
|
doorState1: '',
|
||||||
|
switch1: false,
|
||||||
|
voiceControl1: false,
|
||||||
|
batteryPercentage: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (state is LoadingNewSate) {
|
||||||
|
model = state.doorSensor;
|
||||||
|
} else if (state is UpdateState) {
|
||||||
|
model = state.garageSensor;
|
||||||
|
}
|
||||||
|
return state is GarageDoorLoadingState
|
||||||
|
? const Center(
|
||||||
|
child: DefaultContainer(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
child: CircularProgressIndicator()),
|
||||||
|
)
|
||||||
|
: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
garageBloc.add(const GarageDoorInitial());
|
||||||
|
},
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: MediaQuery.sizeOf(context).height * 0.8,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: InkWell(
|
||||||
|
overlayColor: WidgetStateProperty.all(
|
||||||
|
Colors.transparent),
|
||||||
|
onTap: () {},
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(890),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.white
|
||||||
|
.withOpacity(0.1),
|
||||||
|
blurRadius: 24,
|
||||||
|
offset: const Offset(-5, -5),
|
||||||
|
blurStyle: BlurStyle.outer,
|
||||||
|
),
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black
|
||||||
|
.withOpacity(0.11),
|
||||||
|
blurRadius: 25,
|
||||||
|
offset: const Offset(5, 5),
|
||||||
|
blurStyle: BlurStyle.outer,
|
||||||
|
),
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black
|
||||||
|
.withOpacity(0.13),
|
||||||
|
blurRadius: 30,
|
||||||
|
offset: const Offset(5, 5),
|
||||||
|
blurStyle: BlurStyle.inner,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
garageBloc.add(ToggleDoorEvent(
|
||||||
|
toggle:
|
||||||
|
garageBloc.toggleDoor));
|
||||||
|
},
|
||||||
|
child: GradientWidget(
|
||||||
|
doorStatus: garageBloc.toggleDoor,
|
||||||
|
seconds:
|
||||||
|
garageBloc.secondSelected,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: DefaultContainer(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) =>
|
||||||
|
TimerScheduleScreen(
|
||||||
|
device: device!,
|
||||||
|
switchCode: 'switch_1',
|
||||||
|
deviceCode: 'countdown_1',
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxHeight: 46, maxWidth: 50),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.garageSchedule),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
const Flexible(
|
||||||
|
child: FittedBox(
|
||||||
|
child: BodySmall(
|
||||||
|
text: 'Schedule',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 10,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: DefaultContainer(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => TimerPage(
|
||||||
|
device: device!,
|
||||||
|
switchCode: 'switch_1',
|
||||||
|
deviceCode: 'countdown_1',
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxHeight: 46, maxWidth: 50),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.garageCountdown),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
const Flexible(
|
||||||
|
child: FittedBox(
|
||||||
|
child: BodySmall(
|
||||||
|
text: 'Countdown',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: DefaultContainer(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) =>
|
||||||
|
GarageRecordsScreen(
|
||||||
|
GDId: device!.uuid!)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxHeight: 46, maxWidth: 50),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.doorRecordsIcon),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
const Flexible(
|
||||||
|
child: FittedBox(
|
||||||
|
child: BodySmall(
|
||||||
|
text: 'Records',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 10,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: DefaultContainer(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) =>
|
||||||
|
PreferencesPage(
|
||||||
|
GDId: device!.uuid!)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxHeight: 46, maxWidth: 50),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.garagePreferencesIcon),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
const Flexible(
|
||||||
|
child: FittedBox(
|
||||||
|
child: BodySmall(
|
||||||
|
text: 'Preferences',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GradientWidget extends StatefulWidget {
|
||||||
|
const GradientWidget({required this.seconds, required this.doorStatus});
|
||||||
|
final int seconds;
|
||||||
|
final bool doorStatus;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GradientWidget> createState() => _GradientWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GradientWidgetState extends State<GradientWidget>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late ScrollController _scrollController;
|
||||||
|
late AnimationController _animationController;
|
||||||
|
late Animation<double> _itemExtentAnimation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_scrollController = ScrollController();
|
||||||
|
_animationController = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: Duration(seconds: widget.seconds),
|
||||||
|
);
|
||||||
|
_itemExtentAnimation = Tween<double>(
|
||||||
|
begin: widget.doorStatus ? 0 : 15, end: widget.doorStatus ? 15 : 0)
|
||||||
|
.animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: _animationController,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
)..addListener(() {
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (widget.doorStatus) {
|
||||||
|
_openAnimation();
|
||||||
|
} else {
|
||||||
|
_closeAnimation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _openAnimation() {
|
||||||
|
_animationController.forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _closeAnimation() {
|
||||||
|
_animationController.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
_animationController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: 300,
|
||||||
|
height: 300,
|
||||||
|
padding: EdgeInsets.only(right: 10),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
Assets.openGarageIcon,
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(child: Container()),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Center(
|
||||||
|
child: Container(
|
||||||
|
height: 104,
|
||||||
|
child: ListView.builder(
|
||||||
|
itemExtent: _itemExtentAnimation.value,
|
||||||
|
controller: _scrollController,
|
||||||
|
itemCount: 4,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Center(child: GradientWidget1());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GradientWidget1 extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: 97,
|
||||||
|
height: 15,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: [
|
||||||
|
Color(0xFF017297),
|
||||||
|
Color(0xFF024C67),
|
||||||
|
],
|
||||||
|
stops: [0.0, 1.0],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,341 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
|
||||||
|
class PreferencesPage extends StatelessWidget {
|
||||||
|
final String GDId;
|
||||||
|
const PreferencesPage({super.key, required this.GDId});
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DefaultScaffold(
|
||||||
|
title: 'Preferences',
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (context) =>
|
||||||
|
GarageDoorBloc(GDId: GDId)..add(const GarageDoorInitial()),
|
||||||
|
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final garageDoorBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||||
|
|
||||||
|
return state is GarageDoorLoadingState
|
||||||
|
? const Center(
|
||||||
|
child: DefaultContainer(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
child: CircularProgressIndicator()),
|
||||||
|
)
|
||||||
|
: Column(
|
||||||
|
children: [
|
||||||
|
const Row(
|
||||||
|
children: [
|
||||||
|
BodyMedium(
|
||||||
|
text: 'Warnings',
|
||||||
|
fontColor: ColorsManager.grayColor,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
DefaultContainer(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 50,
|
||||||
|
child: ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
leading: const BodyMedium(
|
||||||
|
text: 'Alarm when door is open',
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
trailing: Container(
|
||||||
|
width: 100,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 30,
|
||||||
|
width: 1,
|
||||||
|
color: ColorsManager.graysColor,
|
||||||
|
),
|
||||||
|
Transform.scale(
|
||||||
|
scale: .8,
|
||||||
|
child: CupertinoSwitch(
|
||||||
|
value:
|
||||||
|
garageDoorBloc.lowBattery,
|
||||||
|
onChanged: (value) {
|
||||||
|
// context
|
||||||
|
// .read<GarageDoorBloc>()
|
||||||
|
// .add(
|
||||||
|
// ToggleLowBatteryEvent(
|
||||||
|
// value));
|
||||||
|
},
|
||||||
|
applyTheme: true,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
const Row(
|
||||||
|
children: [
|
||||||
|
BodyMedium(
|
||||||
|
text: 'Other Settings',
|
||||||
|
fontColor: ColorsManager.grayColor,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
DefaultContainer(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return SecondDialog(
|
||||||
|
label2: 'Close',
|
||||||
|
initialSelectedLabel: garageDoorBloc
|
||||||
|
.secondSelected
|
||||||
|
.toString(),
|
||||||
|
cancelTab: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
confirmTab: (v) {
|
||||||
|
garageDoorBloc
|
||||||
|
.add(SelectSecondsEvent(seconds: v));
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
title: 'Control',
|
||||||
|
label1: 'Open',
|
||||||
|
onTapLabel1: (selected) {},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: SizedBox(
|
||||||
|
child: ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
leading: const BodyMedium(
|
||||||
|
text: 'Opening and Closing Time',
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
trailing: Container(
|
||||||
|
height: 90,
|
||||||
|
width: 120,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
BodyMedium(
|
||||||
|
fontColor: ColorsManager.textGray,
|
||||||
|
text:
|
||||||
|
'${garageDoorBloc.secondSelected.toString()} Seconds',
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
const Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
size: 15,
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SecondDialog extends StatefulWidget {
|
||||||
|
final String label1;
|
||||||
|
final String label2;
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
final Function(String)? onTapLabel1;
|
||||||
|
final Function()? cancelTab;
|
||||||
|
final Function(int selectedSecond)? confirmTab;
|
||||||
|
|
||||||
|
final String? initialSelectedLabel;
|
||||||
|
|
||||||
|
SecondDialog({
|
||||||
|
required this.label1,
|
||||||
|
required this.label2,
|
||||||
|
required this.title,
|
||||||
|
this.onTapLabel1,
|
||||||
|
required this.cancelTab,
|
||||||
|
required this.confirmTab,
|
||||||
|
this.initialSelectedLabel,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SecondDialogState createState() => _SecondDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SecondDialogState extends State<SecondDialog> {
|
||||||
|
late String _selectedOption;
|
||||||
|
late int selectedSecond;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
// Parse the initialSelectedLabel as an integer. Default to 10 if invalid or not provided.
|
||||||
|
selectedSecond = int.tryParse(widget.initialSelectedLabel ?? '10') ?? 10;
|
||||||
|
_selectedOption = widget.initialSelectedLabel ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
BodyLarge(
|
||||||
|
text: widget.title,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontColor: ColorsManager.primaryColor,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(left: 15, right: 15),
|
||||||
|
child: Divider(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 15, right: 15, bottom: 10),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 100,
|
||||||
|
child: CupertinoPicker(
|
||||||
|
itemExtent: 40.0,
|
||||||
|
scrollController: FixedExtentScrollController(
|
||||||
|
// Set the initial position based on selectedSecond
|
||||||
|
initialItem: selectedSecond - 10,
|
||||||
|
),
|
||||||
|
onSelectedItemChanged: (int index) {
|
||||||
|
setState(() {
|
||||||
|
selectedSecond = index + 10;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
children: List<Widget>.generate(111, (int index) {
|
||||||
|
return Center(
|
||||||
|
child: BodyLarge(
|
||||||
|
text: (index + 10).toString().padLeft(2, '0'),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 30,
|
||||||
|
color: Colors.blue),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Text('Sec'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
right: BorderSide(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
|
top: BorderSide(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
child: SizedBox(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: widget.cancelTab,
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(15),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'Cancel',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
left: BorderSide(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
|
top: BorderSide(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
widget.confirmTab?.call(selectedSecond);
|
||||||
|
},
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(15),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'Confirm',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorsManager.primaryColor,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
|
||||||
|
class GarageRecordsScreen extends StatelessWidget {
|
||||||
|
final String GDId;
|
||||||
|
const GarageRecordsScreen({super.key, required this.GDId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DefaultScaffold(
|
||||||
|
title: 'Records',
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (context) =>
|
||||||
|
GarageDoorBloc(GDId: GDId)..add(const ReportLogsInitial()),
|
||||||
|
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final garageDoorBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||||
|
final Map<String, List<DeviceEvent>> groupedRecords = {};
|
||||||
|
|
||||||
|
if (state is GarageDoorLoadingState) {
|
||||||
|
return const Center(
|
||||||
|
child: DefaultContainer(
|
||||||
|
width: 50, height: 50, child: CircularProgressIndicator()),
|
||||||
|
);
|
||||||
|
} else if (state is UpdateState) {
|
||||||
|
for (var record in garageDoorBloc.recordGroups.data!) {
|
||||||
|
final DateTime eventDateTime =
|
||||||
|
DateTime.fromMillisecondsSinceEpoch(record.eventTime!);
|
||||||
|
final String formattedDate =
|
||||||
|
DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime);
|
||||||
|
|
||||||
|
// Group by formatted date
|
||||||
|
if (groupedRecords.containsKey(formattedDate)) {
|
||||||
|
groupedRecords[formattedDate]!.add(record);
|
||||||
|
} else {
|
||||||
|
groupedRecords[formattedDate] = [record];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: groupedRecords.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final String date = groupedRecords.keys.elementAt(index);
|
||||||
|
final List<DeviceEvent> recordsForDate = groupedRecords[date]!;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 5, top: 10),
|
||||||
|
child: Text(
|
||||||
|
date,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DefaultContainer(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
...recordsForDate.asMap().entries.map((entry) {
|
||||||
|
final int idx = entry.key;
|
||||||
|
final DeviceEvent record = entry.value;
|
||||||
|
final DateTime eventDateTime =
|
||||||
|
DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
record.eventTime!);
|
||||||
|
final String formattedTime =
|
||||||
|
DateFormat('HH:mm:ss').format(eventDateTime);
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
record.value == 'true'
|
||||||
|
? Icons.radio_button_checked
|
||||||
|
: Icons.radio_button_unchecked,
|
||||||
|
color: record.value == 'true'
|
||||||
|
? Colors.blue
|
||||||
|
: Colors.grey,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
record.value == 'true'
|
||||||
|
? "Opened"
|
||||||
|
: "Closed",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: Text('$formattedTime'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (idx != recordsForDate.length - 1)
|
||||||
|
const Divider(
|
||||||
|
color: ColorsManager.graysColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
221
lib/features/devices/view/widgets/garage_door/garagedialog.dart
Normal file
221
lib/features/devices/view/widgets/garage_door/garagedialog.dart
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
|
||||||
|
class GarageDialog extends StatefulWidget {
|
||||||
|
final String label1;
|
||||||
|
final String label2;
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
final Function(String)? onTapLabel1;
|
||||||
|
final Function(String)? onTapLabel2;
|
||||||
|
final Function()? cancelTab;
|
||||||
|
final Function()? confirmTab;
|
||||||
|
|
||||||
|
final String? initialSelectedLabel;
|
||||||
|
|
||||||
|
GarageDialog({
|
||||||
|
required this.label1,
|
||||||
|
required this.label2,
|
||||||
|
required this.title,
|
||||||
|
this.onTapLabel1,
|
||||||
|
this.onTapLabel2,
|
||||||
|
required this.cancelTab,
|
||||||
|
required this.confirmTab,
|
||||||
|
this.initialSelectedLabel,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_GarageDialogState createState() => _GarageDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GarageDialogState extends State<GarageDialog> {
|
||||||
|
late String _selectedOption;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_selectedOption = widget.initialSelectedLabel ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
BodyLarge(
|
||||||
|
text: widget.title,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontColor: ColorsManager.primaryColor,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(left: 15, right: 15),
|
||||||
|
child: Divider(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildCheckboxOption(
|
||||||
|
label: widget.label1,
|
||||||
|
onTap: widget.onTapLabel1,
|
||||||
|
),
|
||||||
|
_buildCheckboxOption(
|
||||||
|
label: widget.label2,
|
||||||
|
onTap: widget.onTapLabel2,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
right: BorderSide(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
|
top: BorderSide(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
child: SizedBox(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: widget.cancelTab,
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(15),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'Cancel',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
left: BorderSide(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
|
top: BorderSide(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: widget.confirmTab,
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(15),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'Confirm',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorsManager.primaryColor,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCheckboxOption(
|
||||||
|
{required String label, Function(String)? onTap}) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 10, top: 10),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
BodyMedium(
|
||||||
|
text: label,
|
||||||
|
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
CircularCheckbox(
|
||||||
|
value: _selectedOption == label,
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
if (value == true) {
|
||||||
|
setState(() {
|
||||||
|
_selectedOption = label;
|
||||||
|
});
|
||||||
|
if (onTap != null) {
|
||||||
|
onTap(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CircularCheckbox extends StatefulWidget {
|
||||||
|
final bool value;
|
||||||
|
final ValueChanged<bool?> onChanged;
|
||||||
|
|
||||||
|
CircularCheckbox({required this.value, required this.onChanged});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CircularCheckboxState createState() => _CircularCheckboxState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CircularCheckboxState extends State<CircularCheckbox> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
widget.onChanged(!widget.value);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: Border.all(
|
||||||
|
color: widget.value
|
||||||
|
? ColorsManager.primaryColorWithOpacity.withOpacity(0.01)
|
||||||
|
: Colors.grey,
|
||||||
|
width: 2.0,
|
||||||
|
),
|
||||||
|
color: widget.value
|
||||||
|
? ColorsManager.primaryColorWithOpacity
|
||||||
|
: Colors.transparent,
|
||||||
|
),
|
||||||
|
width: 24.0,
|
||||||
|
height: 24.0,
|
||||||
|
child: widget.value
|
||||||
|
? const Icon(
|
||||||
|
Icons.check,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 16.0,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,163 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/view/widgets/garage_door/create_schedule_garage.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/schedule_list.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||||
|
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
|
||||||
|
|
||||||
|
class TimerScheduleScreen extends StatelessWidget {
|
||||||
|
final DeviceModel device;
|
||||||
|
final String deviceCode;
|
||||||
|
final String switchCode;
|
||||||
|
const TimerScheduleScreen(
|
||||||
|
{required this.device,
|
||||||
|
required this.deviceCode,
|
||||||
|
required this.switchCode,
|
||||||
|
super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnnotatedRegion(
|
||||||
|
value: SystemUiOverlayStyle(
|
||||||
|
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
|
||||||
|
statusBarIconBrightness: Brightness.light,
|
||||||
|
),
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (context) =>
|
||||||
|
GarageDoorBloc(GDId: device.uuid ?? '')..add(GetScheduleEvent()),
|
||||||
|
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final garageBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||||
|
Duration duration = Duration.zero;
|
||||||
|
int countNum = 0;
|
||||||
|
if (state is UpdateTimerState) {
|
||||||
|
countNum = state.seconds;
|
||||||
|
} else if (state is TimerRunInProgress) {
|
||||||
|
countNum = state.remainingTime;
|
||||||
|
} else if (state is TimerRunComplete) {
|
||||||
|
countNum = 0;
|
||||||
|
} else if (state is LoadingNewSate) {
|
||||||
|
countNum = 0;
|
||||||
|
}
|
||||||
|
return PopScope(
|
||||||
|
canPop: false,
|
||||||
|
onPopInvoked: (didPop) {
|
||||||
|
if (!didPop) {
|
||||||
|
garageBloc.add(OnClose());
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: DefaultTabController(
|
||||||
|
length: 2,
|
||||||
|
child: DefaultScaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
centerTitle: true,
|
||||||
|
title: const BodyLarge(
|
||||||
|
text: 'Schedule',
|
||||||
|
fontColor: ColorsManager.primaryColor,
|
||||||
|
fontWeight: FontsManager.bold,
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
garageBloc.createSchedule == true
|
||||||
|
? TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
garageBloc.add(ScheduleSaveapp());
|
||||||
|
},
|
||||||
|
child: const Text('Save'))
|
||||||
|
: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
garageBloc.add(
|
||||||
|
const ToggleCreateScheduleEvent(
|
||||||
|
index: 1));
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: state is GarageDoorLoading
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
decoration: const ShapeDecoration(
|
||||||
|
color: ColorsManager.onPrimaryColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.all(Radius.circular(30)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: SizedBox(
|
||||||
|
child: garageBloc.createSchedule == true
|
||||||
|
? CreateGarageSchedule(
|
||||||
|
|
||||||
|
onToggleChanged: (bool value) {
|
||||||
|
garageBloc.toggleSchedule = value;
|
||||||
|
},
|
||||||
|
onDateTimeChanged:
|
||||||
|
(DateTime dateTime) {
|
||||||
|
garageBloc.selectedTime =
|
||||||
|
dateTime;
|
||||||
|
},
|
||||||
|
days: garageBloc.days,
|
||||||
|
selectDays:
|
||||||
|
(List<String> selectedDays) {
|
||||||
|
garageBloc.selectedDays =
|
||||||
|
selectedDays;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(top: 10),
|
||||||
|
child: ScheduleListView(
|
||||||
|
listSchedule:
|
||||||
|
garageBloc.listSchedule,
|
||||||
|
onDismissed: (scheduleId) {
|
||||||
|
garageBloc.listSchedule
|
||||||
|
.removeWhere((schedule) =>
|
||||||
|
schedule.scheduleId ==
|
||||||
|
scheduleId);
|
||||||
|
garageBloc.add(
|
||||||
|
DeleteScheduleEvent(
|
||||||
|
id: scheduleId));
|
||||||
|
},
|
||||||
|
onToggleSchedule:
|
||||||
|
(scheduleId, isEnabled) {
|
||||||
|
garageBloc
|
||||||
|
.add(ToggleScheduleEvent(
|
||||||
|
id: scheduleId,
|
||||||
|
toggle: isEnabled,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatDuration(int seconds) {
|
||||||
|
final hours = (seconds ~/ 3600).toString().padLeft(2, '0');
|
||||||
|
final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0');
|
||||||
|
final secs = (seconds % 60).toString().padLeft(2, '0');
|
||||||
|
return '$hours:$minutes:$secs';
|
||||||
|
}
|
||||||
|
}
|
148
lib/features/devices/view/widgets/garage_door/timer_page.dart
Normal file
148
lib/features/devices/view/widgets/garage_door/timer_page.dart
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||||
|
import 'package:syncrow_app/generated/assets.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
|
||||||
|
|
||||||
|
class TimerPage extends StatelessWidget {
|
||||||
|
final DeviceModel device;
|
||||||
|
final String deviceCode;
|
||||||
|
final String switchCode;
|
||||||
|
const TimerPage(
|
||||||
|
{required this.device,
|
||||||
|
required this.deviceCode,
|
||||||
|
required this.switchCode,
|
||||||
|
super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnnotatedRegion(
|
||||||
|
value: SystemUiOverlayStyle(
|
||||||
|
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
|
||||||
|
statusBarIconBrightness: Brightness.light,
|
||||||
|
),
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (context) => GarageDoorBloc(GDId: device.uuid ?? '')
|
||||||
|
..add(GetCounterEvent(deviceCode: deviceCode)),
|
||||||
|
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final oneGangBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||||
|
Duration duration = Duration.zero;
|
||||||
|
int countNum = 0;
|
||||||
|
if (state is UpdateTimerState) {
|
||||||
|
countNum = state.seconds;
|
||||||
|
} else if (state is TimerRunInProgress) {
|
||||||
|
countNum = state.remainingTime;
|
||||||
|
} else if (state is TimerRunComplete) {
|
||||||
|
countNum = 0;
|
||||||
|
} else if (state is LoadingNewSate) {
|
||||||
|
countNum = 0;
|
||||||
|
}
|
||||||
|
return PopScope(
|
||||||
|
canPop: false,
|
||||||
|
onPopInvoked: (didPop) {
|
||||||
|
if (!didPop) {
|
||||||
|
oneGangBloc.add(OnClose());
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: DefaultTabController(
|
||||||
|
length: 2,
|
||||||
|
child: DefaultScaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
centerTitle: true,
|
||||||
|
title: const BodyLarge(
|
||||||
|
text: 'Countdown',
|
||||||
|
fontColor: ColorsManager.primaryColor,
|
||||||
|
fontWeight: FontsManager.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: state is GarageDoorLoadingState
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
decoration: const ShapeDecoration(
|
||||||
|
color: ColorsManager.onPrimaryColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.all(Radius.circular(30)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
countNum > 0
|
||||||
|
? BodyLarge(
|
||||||
|
text: _formatDuration(countNum),
|
||||||
|
fontColor: ColorsManager
|
||||||
|
.slidingBlueColor,
|
||||||
|
fontSize: 40,
|
||||||
|
)
|
||||||
|
: CupertinoTimerPicker(
|
||||||
|
mode:
|
||||||
|
CupertinoTimerPickerMode.hm,
|
||||||
|
onTimerDurationChanged:
|
||||||
|
(Duration newDuration) {
|
||||||
|
duration = newDuration;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if (state is LoadingNewSate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (countNum > 0) {
|
||||||
|
oneGangBloc.add(
|
||||||
|
const SetCounterValue(
|
||||||
|
deviceCode:
|
||||||
|
'countdown_1',
|
||||||
|
duration:
|
||||||
|
Duration.zero));
|
||||||
|
} else if (duration !=
|
||||||
|
Duration.zero) {
|
||||||
|
oneGangBloc.add(SetCounterValue(
|
||||||
|
deviceCode: 'countdown_1',
|
||||||
|
duration: duration));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: SvgPicture.asset(countNum > 0
|
||||||
|
? Assets.pauseIcon
|
||||||
|
: Assets.playIcon)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatDuration(int seconds) {
|
||||||
|
final hours = (seconds ~/ 3600).toString().padLeft(2, '0');
|
||||||
|
final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0');
|
||||||
|
final secs = (seconds % 60).toString().padLeft(2, '0');
|
||||||
|
return '$hours:$minutes:$secs';
|
||||||
|
}
|
||||||
|
}
|
@ -142,8 +142,7 @@ class OneTouchSetting extends StatelessWidget {
|
|||||||
bottom: 10, top: 10),
|
bottom: 10, top: 10),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
oneTouchBloc.optionSelected =
|
oneTouchBloc.optionSelected = 'light_mode';
|
||||||
'light_mode';
|
|
||||||
final result = await showDialog(
|
final result = await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
|
@ -10,6 +10,7 @@ import 'package:syncrow_app/features/devices/model/device_model.dart';
|
|||||||
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart';
|
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart';
|
||||||
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
|
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
|
||||||
import 'package:syncrow_app/features/devices/view/widgets/door_sensor/door_sensor_screen.dart';
|
import 'package:syncrow_app/features/devices/view/widgets/door_sensor/door_sensor_screen.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_door_screen.dart';
|
||||||
import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart';
|
import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart';
|
||||||
import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart';
|
import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart';
|
||||||
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart';
|
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart';
|
||||||
@ -187,6 +188,14 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
|
|||||||
PageRouteBuilder(
|
PageRouteBuilder(
|
||||||
pageBuilder: (context, animation1, animation2) =>
|
pageBuilder: (context, animation1, animation2) =>
|
||||||
ThreeTouchInterface(touchSwitch: device)));
|
ThreeTouchInterface(touchSwitch: device)));
|
||||||
|
|
||||||
|
case DeviceType.GarageDoor:
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
PageRouteBuilder(
|
||||||
|
pageBuilder: (context, animation1, animation2) =>
|
||||||
|
GarageDoorScreen(device: device)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
@ -137,3 +137,5 @@ class _CreateScheduleState extends State<CreateSchedule> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1059,4 +1059,10 @@ class Assets {
|
|||||||
"assets/icons/door_notification_setting_icon.svg";
|
"assets/icons/door_notification_setting_icon.svg";
|
||||||
static const String doorRecordsIcon = "assets/icons/door_records_icon.svg";
|
static const String doorRecordsIcon = "assets/icons/door_records_icon.svg";
|
||||||
static const String doorSensorIcon = "assets/icons/door_sensor_icon.svg";
|
static const String doorSensorIcon = "assets/icons/door_sensor_icon.svg";
|
||||||
|
static const String closedGarageIcon = "assets/icons/closed_garage_door.svg";
|
||||||
|
static const String openGarageIcon = "assets/icons/open_garage_door.svg";
|
||||||
|
static const String garageCountdown = "assets/icons/garage_countdown.svg";
|
||||||
|
static const String garagePreferencesIcon = "assets/icons/garage_preferences_icon.svg";
|
||||||
|
static const String garageSchedule = "assets/icons/garage_schedule.svg";
|
||||||
|
//open_garage_door.svg
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ enum DeviceType {
|
|||||||
OneTouch,
|
OneTouch,
|
||||||
TowTouch,
|
TowTouch,
|
||||||
ThreeTouch,
|
ThreeTouch,
|
||||||
|
GarageDoor,
|
||||||
|
|
||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
@ -83,6 +84,7 @@ Map<String, DeviceType> devicesTypesMap = {
|
|||||||
"1GT": DeviceType.OneTouch,
|
"1GT": DeviceType.OneTouch,
|
||||||
"2GT": DeviceType.TowTouch,
|
"2GT": DeviceType.TowTouch,
|
||||||
"3GT": DeviceType.ThreeTouch,
|
"3GT": DeviceType.ThreeTouch,
|
||||||
|
"GD": DeviceType.GarageDoor,
|
||||||
};
|
};
|
||||||
Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
|
Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
|
||||||
DeviceType.AC: [
|
DeviceType.AC: [
|
||||||
@ -370,7 +372,6 @@ Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
|
|||||||
"range": ['power_off', 'power_on', 'last']
|
"range": ['power_off', 'power_on', 'last']
|
||||||
})),
|
})),
|
||||||
],
|
],
|
||||||
|
|
||||||
DeviceType.ThreeTouch: [
|
DeviceType.ThreeTouch: [
|
||||||
FunctionModel(
|
FunctionModel(
|
||||||
code: 'switch_1',
|
code: 'switch_1',
|
||||||
@ -430,6 +431,43 @@ Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
|
|||||||
"range": ['power_off', 'power_on', 'last']
|
"range": ['power_off', 'power_on', 'last']
|
||||||
})),
|
})),
|
||||||
],
|
],
|
||||||
|
DeviceType.GarageDoor: [
|
||||||
|
FunctionModel(
|
||||||
|
code: 'switch_1',
|
||||||
|
type: functionTypesMap['Boolean'],
|
||||||
|
values: ValueModel.fromJson({})),
|
||||||
|
FunctionModel(
|
||||||
|
code: 'countdown_1',
|
||||||
|
type: functionTypesMap['Integer'],
|
||||||
|
values: ValueModel.fromJson(
|
||||||
|
{"unit": "s", "min": 0, "max": 86400, "scale": 0, "step": 1})),
|
||||||
|
FunctionModel(
|
||||||
|
code: 'tr_timecon',
|
||||||
|
type: functionTypesMap['Integer'],
|
||||||
|
values: ValueModel.fromJson(
|
||||||
|
{"unit": "s", "min": 0, "max": 120, "scale": 0, "step": 1})),
|
||||||
|
FunctionModel(
|
||||||
|
code: 'countdown_alarm',
|
||||||
|
type: functionTypesMap['Integer'],
|
||||||
|
values: ValueModel.fromJson(
|
||||||
|
{"unit": "s", "min": 0, "max": 86400, "scale": 0, "step": 1})),
|
||||||
|
FunctionModel(
|
||||||
|
code: 'door_control_1',
|
||||||
|
type: functionTypesMap['Enum'],
|
||||||
|
values: ValueModel.fromJson({
|
||||||
|
"range": ['open', 'open']
|
||||||
|
})),
|
||||||
|
FunctionModel(
|
||||||
|
code: 'voice_control_1',
|
||||||
|
type: functionTypesMap['Boolean'],
|
||||||
|
values: ValueModel.fromJson({})),
|
||||||
|
FunctionModel(
|
||||||
|
code: 'door_state_1',
|
||||||
|
type: functionTypesMap['Enum'],
|
||||||
|
values: ValueModel.fromJson({
|
||||||
|
"range": ["unclosed_time", "close_time_alarm", "none"]
|
||||||
|
})),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TempModes { hot, cold, wind }
|
enum TempModes { hot, cold, wind }
|
||||||
|
@ -5,7 +5,7 @@ description: This is the mobile application project, developed with Flutter for
|
|||||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
# 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
|
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
version: 1.0.3+22
|
version: 1.0.3+25
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.6 <4.0.0"
|
sdk: ">=3.0.6 <4.0.0"
|
||||||
|
Reference in New Issue
Block a user