water heater and timer and schedule ui and api ,

Circulate ui and Inching ui
This commit is contained in:
mohammad
2024-09-20 11:50:39 +03:00
parent 26833cf215
commit f0feb4021f
22 changed files with 1830 additions and 15 deletions

View File

@ -0,0 +1,10 @@
<svg width="26" height="25" viewBox="0 0 26 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.5253 22.6799C15.3191 22.7313 15.1089 22.7769 14.9003 22.8154C14.355 22.9168 13.9944 23.4413 14.0953 23.9871C14.1451 24.2557 14.2976 24.4793 14.5047 24.6253C14.7181 24.7755 14.9897 24.8434 15.2665 24.7919C15.5149 24.7458 15.7653 24.6915 16.011 24.6302C16.5495 24.4962 16.8776 23.9506 16.7432 23.4124C16.6092 22.8736 16.0641 22.5458 15.5253 22.6799Z" fill="black"/>
<path d="M22.9574 9.20888C23.0278 9.42105 23.1622 9.59425 23.332 9.71393C23.5837 9.89122 23.9131 9.95087 24.2274 9.84694C24.7544 9.67196 25.0399 9.10371 24.8656 8.577C24.7862 8.33689 24.698 8.09602 24.6042 7.8615C24.398 7.34613 23.8134 7.09522 23.2978 7.30137C22.7827 7.50741 22.5317 8.09216 22.738 8.60769C22.8169 8.80481 22.8907 9.00714 22.9574 9.20888Z" fill="black"/>
<path d="M18.791 21.2451C18.6137 21.3621 18.4307 21.4754 18.2464 21.5815C17.7655 21.8589 17.6008 22.4737 17.8781 22.9544C17.9533 23.0851 18.0536 23.192 18.1691 23.2737C18.4791 23.4918 18.9002 23.5245 19.2507 23.3226C19.4699 23.1962 19.6878 23.0617 19.899 22.9221C20.3619 22.6162 20.4893 21.9927 20.1833 21.5296C19.8774 21.0663 19.2541 20.939 18.791 21.2451Z" fill="black"/>
<path d="M25.4904 12.0161C25.4686 11.4614 25.0013 11.0297 24.4465 11.0513C23.8923 11.0732 23.4602 11.5406 23.482 12.0951C23.4903 12.3071 23.4925 12.5222 23.4876 12.734C23.4798 13.0819 23.6499 13.392 23.9143 13.5784C24.0718 13.6893 24.263 13.7564 24.4703 13.7611C25.025 13.7734 25.4847 13.3335 25.497 12.7785C25.5025 12.5254 25.5004 12.269 25.4904 12.0161Z" fill="black"/>
<path d="M22.7934 18.6011C22.3486 18.2673 21.7193 18.3579 21.3862 18.8019C21.2586 18.972 21.1243 19.1399 20.9867 19.3016C20.6272 19.724 20.678 20.3585 21.1004 20.7183C21.1244 20.7387 21.1488 20.7574 21.174 20.7751C21.594 21.0711 22.1776 21.0031 22.5171 20.6047C22.6814 20.4117 22.8415 20.2111 22.994 20.008C23.3272 19.564 23.237 18.9343 22.7934 18.6011Z" fill="black"/>
<path d="M24.2707 14.9682C23.741 14.8021 23.177 15.0969 23.0111 15.6265C22.9476 15.8289 22.8772 16.0322 22.8012 16.2313C22.6343 16.6696 22.7942 17.1519 23.1607 17.4103C23.2279 17.4575 23.302 17.4976 23.3824 17.528C23.901 17.7259 24.4816 17.4657 24.6793 16.9469C24.7695 16.7102 24.8533 16.4683 24.929 16.2278C25.0948 15.6981 24.8002 15.1342 24.2707 14.9682Z" fill="black"/>
<path d="M11.1405 22.8243C10.242 22.663 9.38004 22.3883 8.56271 22.0051C8.55303 22 8.54438 21.9943 8.53422 21.9897C8.34162 21.899 8.14933 21.8019 7.96296 21.7004C7.96232 21.6997 7.96113 21.6992 7.96011 21.6988C7.61816 21.5105 7.28444 21.3021 6.96022 21.0739C2.23257 17.7436 1.09585 11.1879 4.42636 6.46031C5.15057 5.43269 6.02696 4.57537 7.00402 3.89587C7.01606 3.88749 7.02809 3.87916 7.04002 3.87072C10.483 1.49841 15.158 1.33853 18.814 3.7763L18.0288 4.91082C17.8105 5.22659 17.9448 5.45671 18.3269 5.42232L21.7376 5.11696C22.1203 5.08257 22.3491 4.75158 22.2462 4.38206L21.3303 1.08208C21.2278 0.712132 20.9652 0.66785 20.7467 0.983575L19.9597 2.12078C17.2768 0.319774 14.0588 -0.366975 10.8649 0.186874C10.5432 0.242549 10.226 0.310691 9.9132 0.390012C9.91078 0.390442 9.90885 0.390711 9.90691 0.391141C9.89482 0.394097 9.88257 0.39802 9.8708 0.401298C7.1166 1.10858 4.7136 2.71493 2.99891 5.00685C2.98445 5.02399 2.96957 5.04076 2.95592 5.05941C2.8989 5.1362 2.84231 5.21477 2.7869 5.29334C2.6963 5.4221 2.60698 5.55409 2.52153 5.68607C2.51084 5.70198 2.50267 5.71816 2.49332 5.73423C1.07833 7.92689 0.395831 10.4618 0.512877 13.0425C0.513146 13.051 0.512662 13.0596 0.512877 13.0683C0.524217 13.3204 0.544208 13.576 0.571347 13.8276C0.572798 13.8438 0.576398 13.8592 0.579139 13.8754C0.607192 14.1284 0.642392 14.382 0.686513 14.6356C1.13492 17.2225 2.35526 19.5504 4.18388 21.3617C4.18813 21.366 4.19254 21.3706 4.19683 21.375C4.19834 21.3767 4.20001 21.3775 4.20146 21.3791C4.69275 21.8637 5.22715 22.3118 5.80254 22.7171C7.30835 23.7782 8.9851 24.4795 10.7858 24.8027C11.3322 24.9008 11.8541 24.5371 11.9522 23.991C12.0501 23.4445 11.6867 22.9222 11.1405 22.8243Z" fill="black"/>
<path d="M12.3833 4.38037C11.9339 4.38037 11.5698 4.74473 11.5698 5.19352V13.2947L18.979 17.1249C19.0983 17.1866 19.2259 17.2157 19.3516 17.2157C19.6459 17.2157 19.9301 17.0554 20.0746 16.7758C20.2807 16.3767 20.1248 15.8865 19.7257 15.6804L13.1958 12.3045V5.19352C13.1958 4.74473 12.8322 4.38037 12.3833 4.38037Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,12 @@
<svg width="26" height="25" viewBox="0 0 26 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.0488 11.1084H14.2695C14.674 11.1084 15.002 10.7805 15.002 10.376C15.002 9.97148 14.674 9.64355 14.2695 9.64355H13.0488C12.6443 9.64355 12.3164 9.97148 12.3164 10.376C12.3164 10.7805 12.6443 11.1084 13.0488 11.1084Z" fill="black"/>
<path d="M9.92383 9.64355H8.70312C8.29863 9.64355 7.9707 9.97148 7.9707 10.376C7.9707 10.7805 8.29863 11.1084 8.70312 11.1084H9.92383C10.3283 11.1084 10.6562 10.7805 10.6562 10.376C10.6562 9.97148 10.3283 9.64355 9.92383 9.64355Z" fill="black"/>
<path d="M17.3945 11.1084H18.6152C19.0197 11.1084 19.3477 10.7805 19.3477 10.376C19.3477 9.97148 19.0197 9.64355 18.6152 9.64355H17.3945C16.99 9.64355 16.6621 9.97148 16.6621 10.376C16.6621 10.7805 16.99 11.1084 17.3945 11.1084Z" fill="black"/>
<path d="M5.57812 12.9395H4.35742C3.95293 12.9395 3.625 13.2674 3.625 13.6719C3.625 14.0764 3.95293 14.4043 4.35742 14.4043H5.57812C5.98262 14.4043 6.31055 14.0764 6.31055 13.6719C6.31055 13.2674 5.98262 12.9395 5.57812 12.9395Z" fill="black"/>
<path d="M9.92383 12.9395H8.70312C8.29863 12.9395 7.9707 13.2674 7.9707 13.6719C7.9707 14.0764 8.29863 14.4043 8.70312 14.4043H9.92383C10.3283 14.4043 10.6562 14.0764 10.6562 13.6719C10.6562 13.2674 10.3283 12.9395 9.92383 12.9395Z" fill="black"/>
<path d="M15.002 13.6719C15.002 13.2674 14.674 12.9395 14.2695 12.9395H13.0488C12.6443 12.9395 12.3164 13.2674 12.3164 13.6719C12.3164 14.0764 12.6443 14.4043 13.0488 14.4043H14.2695C14.674 14.4043 15.002 14.0764 15.002 13.6719Z" fill="black"/>
<path d="M5.57812 16.2354H4.35742C3.95293 16.2354 3.625 16.5633 3.625 16.9678C3.625 17.3723 3.95293 17.7002 4.35742 17.7002H5.57812C5.98262 17.7002 6.31055 17.3723 6.31055 16.9678C6.31055 16.5633 5.98262 16.2354 5.57812 16.2354Z" fill="black"/>
<path d="M9.92383 16.2354H8.70312C8.29863 16.2354 7.9707 16.5633 7.9707 16.9678C7.9707 17.3723 8.29863 17.7002 8.70312 17.7002H9.92383C10.3283 17.7002 10.6562 17.3723 10.6562 16.9678C10.6562 16.5633 10.3283 16.2354 9.92383 16.2354Z" fill="black"/>
<path d="M22.4727 13.6268V4.15039C22.4727 2.66958 21.2679 1.46484 19.7871 1.46484H18.3711V0.732422C18.3711 0.32793 18.0432 0 17.6387 0C17.2342 0 16.9062 0.32793 16.9062 0.732422V1.46484H14.2695V0.732422C14.2695 0.32793 13.9416 0 13.5371 0C13.1326 0 12.8047 0.32793 12.8047 0.732422V1.46484H10.168V0.732422C10.168 0.32793 9.84004 0 9.43555 0C9.03105 0 8.70312 0.32793 8.70312 0.732422V1.46484H6.06641V0.732422C6.06641 0.32793 5.73848 0 5.33398 0C4.92949 0 4.60156 0.32793 4.60156 0.732422V1.46484H3.18555C1.70474 1.46484 0.5 2.66958 0.5 4.15039V18.7988C0.5 20.0104 1.48569 20.9961 2.69727 20.9961H13.6651C14.523 23.3303 16.7684 25 19.3965 25C22.762 25 25.5 22.262 25.5 18.8965C25.5 16.6521 24.2821 14.6871 22.4727 13.6268ZM1.96484 4.15039C1.96484 3.47729 2.51245 2.92969 3.18555 2.92969H4.60156V3.66211C4.60156 4.0666 4.92949 4.39453 5.33398 4.39453C5.73848 4.39453 6.06641 4.0666 6.06641 3.66211V2.92969H8.70312V3.66211C8.70312 4.0666 9.03105 4.39453 9.43555 4.39453C9.84004 4.39453 10.168 4.0666 10.168 3.66211V2.92969H12.8047V3.66211C12.8047 4.0666 13.1326 4.39453 13.5371 4.39453C13.9416 4.39453 14.2695 4.0666 14.2695 3.66211V2.92969H16.9062V3.66211C16.9062 4.0666 17.2342 4.39453 17.6387 4.39453C18.0432 4.39453 18.3711 4.0666 18.3711 3.66211V2.92969H19.7871C20.4602 2.92969 21.0078 3.47729 21.0078 4.15039V6.34766H1.96484V4.15039ZM2.69727 19.5312C2.29341 19.5312 1.96484 19.2027 1.96484 18.7988V7.8125H21.0078V13.0093C20.4943 12.8686 19.9541 12.793 19.3965 12.793C16.031 12.793 13.293 15.531 13.293 18.8965C13.293 19.1108 13.3042 19.3226 13.3259 19.5312H2.69727ZM19.3965 23.5352C16.8387 23.5352 14.7578 21.4542 14.7578 18.8965C14.7578 16.3387 16.8387 14.2578 19.3965 14.2578C21.9542 14.2578 24.0352 16.3387 24.0352 18.8965C24.0352 21.4542 21.9542 23.5352 19.3965 23.5352Z" fill="black"/>
<path d="M21.8379 18.1641H20.1289V16.4551C20.1289 16.0506 19.801 15.7227 19.3965 15.7227C18.992 15.7227 18.6641 16.0506 18.6641 16.4551V18.8965C18.6641 19.301 18.992 19.6289 19.3965 19.6289H21.8379C22.2424 19.6289 22.5703 19.301 22.5703 18.8965C22.5703 18.492 22.2424 18.1641 21.8379 18.1641Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1,4 @@
<svg width="26" height="21" viewBox="0 0 26 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24.0448 15.9465L20.2012 13.7273C19.4253 13.2794 18.4517 13.84 18.4517 14.7374V16.0844H7.87586C4.77052 16.0844 2.24415 13.558 2.24415 10.4526C2.24415 9.971 1.85367 9.58057 1.37207 9.58057C0.890431 9.58057 0.5 9.97105 0.5 10.4526C0.5 14.5197 3.80885 17.8285 7.87591 17.8285H18.4517V19.1756C18.4517 20.0714 19.424 20.6344 20.2012 20.1856L24.0448 17.9665C24.8207 17.5187 24.822 16.3952 24.0448 15.9465Z" fill="black"/>
<path d="M18.1241 2.5148H7.54828V1.16772C7.54828 0.271867 6.57596 -0.291075 5.79881 0.157658L1.95519 2.37676C1.17936 2.82466 1.17799 3.94815 1.95519 4.39688L5.79881 6.61603C6.57469 7.06398 7.54828 6.50329 7.54828 5.60597V4.25894H18.1241C21.2295 4.25894 23.7559 6.78527 23.7559 9.89065C23.7559 10.3723 24.1463 10.7627 24.6279 10.7627C25.1096 10.7627 25.5 10.3722 25.5 9.89065C25.5001 5.8236 22.1912 2.5148 18.1241 2.5148Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 965 B

View File

@ -0,0 +1,4 @@
<svg width="26" height="25" viewBox="0 0 26 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.909 4.88394C20.8746 2.23694 17.9317 0.540767 14.6212 0.107633C11.3435 -0.321144 8.0947 0.540068 5.46148 2.53196L4.50937 1.5785C4.2377 1.30651 3.987 1.39746 3.95226 1.77993L3.63971 5.19304C3.60475 5.57551 3.88922 5.86057 4.27201 5.82604L7.68523 5.51763C8.06802 5.48321 8.15914 5.2323 7.8873 4.96031L6.89959 3.97136C9.06784 2.41766 11.7024 1.75282 14.3602 2.10054C17.1384 2.46397 19.6082 3.88751 21.3154 6.10884C23.0224 8.33002 23.7621 11.0829 23.3987 13.8605C23.1404 15.8332 22.3478 17.6507 21.1144 19.1504C20.6111 19.762 20.0345 20.3209 19.3905 20.8156C17.1694 22.5228 14.4165 23.2627 11.6385 22.8992C8.86087 22.5358 6.39126 21.1122 4.68401 18.8912C3.02091 16.7274 2.2727 14.0427 2.57691 11.3316C2.63882 10.7799 2.24183 10.2824 1.68999 10.2207C1.13853 10.1586 0.641285 10.5558 0.579647 11.1074C0.216595 14.3382 1.10846 17.5376 3.09019 20.116C5.12456 22.7629 8.06781 24.4593 11.3779 24.8924C14.6878 25.3253 17.9682 24.4433 20.6156 22.409C21.3823 21.82 22.0698 21.1538 22.6695 20.4247C24.1397 18.638 25.0842 16.4726 25.3919 14.1216C25.8249 10.8114 24.9432 7.53077 22.909 4.88394Z" fill="black"/>
<path d="M12.5089 4.3645C12.0596 4.3645 11.6953 4.72874 11.6953 5.17801V13.2862L19.1104 17.1191C19.23 17.181 19.3577 17.2104 19.4833 17.2102C19.7781 17.2102 20.0624 17.0498 20.207 16.77C20.4135 16.3707 20.2571 15.8799 19.8579 15.6733L13.323 12.2949V5.17806C13.323 4.72879 12.9586 4.3645 12.5089 4.3645Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,29 @@
<svg width="280" height="290" viewBox="0 0 280 290" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_3818_711)">
<rect x="20" y="20" width="250" height="250" rx="100" fill="#EDEDED"/>
<circle cx="128.778" cy="183.972" r="2.77778" stroke="white" stroke-width="3"/>
<circle cx="144.778" cy="183.972" r="2.77778" stroke="white" stroke-width="3"/>
<circle cx="160.778" cy="183.972" r="2.77778" stroke="white" stroke-width="3"/>
<rect x="121" y="149" width="46.5278" height="26.3889" rx="5" stroke="white" stroke-width="3"/>
<path d="M134.184 160.41H134.135C135.619 160.41 136.807 160.833 137.699 161.679C138.598 162.532 139.047 163.697 139.047 165.175C139.047 166.64 138.559 167.831 137.582 168.749C136.605 169.667 135.316 170.126 133.715 170.126C132.953 170.126 132.25 170.019 131.605 169.804C130.967 169.589 130.45 169.329 130.053 169.023C129.675 168.73 129.34 168.427 129.047 168.115C128.76 167.809 128.565 167.551 128.461 167.343L128.275 167.021L129.574 165.839C129.6 165.911 129.649 165.999 129.721 166.103C129.773 166.181 129.926 166.37 130.18 166.669C130.427 166.956 130.684 167.197 130.951 167.392C131.225 167.587 131.605 167.776 132.094 167.958C132.576 168.134 133.09 168.222 133.637 168.222C134.62 168.222 135.421 167.932 136.039 167.353C136.658 166.773 136.967 166.015 136.967 165.078C136.967 164.134 136.654 163.395 136.029 162.861C135.398 162.32 134.542 162.05 133.461 162.05C132.348 162.05 131.212 162.379 130.053 163.036L128.998 162.275L129.994 155.195H137.895V157.031H131.732L131.137 161.035C131.996 160.618 133.012 160.41 134.184 160.41ZM147.387 170.097H147.367C145.466 170.097 143.943 169.384 142.797 167.958C141.658 166.539 141.088 164.719 141.088 162.499C141.088 160.312 141.661 158.509 142.807 157.089C143.952 155.67 145.476 154.96 147.377 154.96C149.258 154.96 150.762 155.673 151.889 157.099C153.015 158.531 153.578 160.331 153.578 162.499C153.578 164.719 153.018 166.539 151.898 167.958C150.779 169.384 149.275 170.097 147.387 170.097ZM147.367 168.134C148.565 168.134 149.545 167.613 150.307 166.572C151.068 165.53 151.449 164.182 151.449 162.529C151.449 160.875 151.068 159.527 150.307 158.486C149.545 157.444 148.565 156.923 147.367 156.923C146.143 156.923 145.147 157.444 144.379 158.486C143.604 159.534 143.217 160.882 143.217 162.529C143.217 164.176 143.604 165.523 144.379 166.572C145.147 167.613 146.143 168.134 147.367 168.134Z" fill="white"/>
<path d="M162.557 158.212L162.572 158.227C162.311 158.865 161.882 159.376 161.283 159.76C160.68 160.147 159.953 160.341 159.1 160.341C157.977 160.341 157.043 159.981 156.297 159.262C155.555 158.546 155.184 157.639 155.184 156.542C155.184 155.461 155.555 154.563 156.297 153.847C157.043 153.127 157.974 152.768 159.09 152.768C159.943 152.768 160.667 152.963 161.263 153.354C161.862 153.744 162.29 154.252 162.547 154.877L161.087 155.468C160.902 155.103 160.638 154.807 160.296 154.579C159.951 154.348 159.551 154.233 159.095 154.233C158.444 154.233 157.896 154.452 157.45 154.892C157.007 155.331 156.786 155.88 156.786 156.537C156.786 157.188 157.009 157.74 157.455 158.193C157.897 158.642 158.444 158.866 159.095 158.866C159.577 158.866 159.992 158.748 160.34 158.51C160.692 158.272 160.941 157.974 161.087 157.616L162.557 158.212Z" fill="white"/>
<mask id="path-8-inside-1_3818_711" fill="white">
<path d="M200.929 217.62C200.929 217.247 200.627 216.945 200.254 216.945C199.882 216.945 199.58 217.247 199.58 217.62C199.58 220.615 197.143 223.051 194.149 223.051C193.776 223.051 193.474 223.353 193.474 223.726C193.474 224.098 193.776 224.4 194.149 224.4C197.887 224.4 200.929 221.358 200.929 217.62Z"/>
</mask>
<path d="M194.149 224.4L194.149 222.4H194.149V224.4ZM202.929 217.62C202.929 216.143 201.731 214.945 200.254 214.945V218.945C199.522 218.945 198.929 218.352 198.929 217.62H202.929ZM200.254 214.945C198.777 214.945 197.58 216.143 197.58 217.62H201.58C201.58 218.352 200.986 218.945 200.254 218.945V214.945ZM197.58 217.62C197.58 219.51 196.039 221.051 194.149 221.051V225.051C198.248 225.051 201.58 221.719 201.58 217.62H197.58ZM194.149 221.051C192.672 221.051 191.474 222.248 191.474 223.726H195.474C195.474 224.458 194.88 225.051 194.149 225.051V221.051ZM191.474 223.726C191.474 225.203 192.672 226.4 194.149 226.4V222.4C194.88 222.4 195.474 222.993 195.474 223.726H191.474ZM194.149 226.4C198.992 226.4 202.929 222.463 202.929 217.62H198.929C198.929 220.254 196.783 222.4 194.149 222.4L194.149 226.4Z" fill="white" mask="url(#path-8-inside-1_3818_711)"/>
<path d="M190.083 206.168L189.798 205.966L190.613 206.545L190.348 206.356L190.348 206.356L190.151 206.217L190.083 206.168ZM190.083 206.168C190.083 206.168 190.083 206.168 190.083 206.168L190.083 206.168ZM194.277 198.891L194.148 198.867L194.542 198.795L195.096 200.467C196.016 203.237 197.822 205.667 199.648 208.124C199.86 208.41 200.073 208.696 200.285 208.983C202.24 211.636 204.18 214.462 204.18 217.62C204.18 217.62 204.18 217.62 204.18 217.62C204.179 223.152 199.68 227.651 194.148 227.651C188.616 227.651 184.117 223.152 184.117 217.62C184.117 217.62 184.117 217.62 184.117 217.62C184.117 214.413 186.117 211.539 188.212 208.711C188.212 208.711 188.212 208.711 188.212 208.711L194.277 198.891ZM194.147 198.867L194.277 198.891C194.276 198.893 194.273 198.904 194.263 198.921C194.251 198.94 194.235 198.958 194.217 198.972C194.183 198.998 194.157 199 194.148 199C194.14 199 194.114 198.998 194.08 198.972C194.062 198.958 194.046 198.94 194.034 198.921C194.024 198.904 194.02 198.893 194.02 198.891L194.147 198.867ZM194.02 198.891C194.02 198.89 194.02 198.89 194.02 198.89C194.02 198.89 194.02 198.89 194.02 198.891L194.02 198.891Z" stroke="white" stroke-width="2"/>
<path d="M194.306 183.891V69.3055C194.306 67.3878 192.751 65.8333 190.833 65.8333H95.0001C93.0824 65.8333 91.5278 67.3878 91.5278 69.3055V215.139C91.5278 217.056 93.0824 218.611 95.0001 218.611H166.438M223.472 212.708C223.472 228.625 210.569 241.528 194.653 241.528C178.736 241.528 165.833 228.625 165.833 212.708C165.833 196.792 178.736 183.889 194.653 183.889C210.569 183.889 223.472 196.792 223.472 212.708Z" stroke="white" stroke-width="3"/>
</g>
<defs>
<filter id="filter0_d_3818_711" 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_3818_711"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3818_711" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,29 @@
<svg width="290" height="290" viewBox="0 0 290 290" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_3800_1033)">
<rect x="20" y="20" width="250" height="250" rx="100" fill="#EDEDED"/>
<circle cx="128.778" cy="183.972" r="2.77778" stroke="#023DFE" stroke-opacity="0.6" stroke-width="3"/>
<circle cx="144.778" cy="183.972" r="2.77778" stroke="#023DFE" stroke-opacity="0.6" stroke-width="3"/>
<circle cx="160.778" cy="183.972" r="2.77778" stroke="#023DFE" stroke-opacity="0.6" stroke-width="3"/>
<rect x="121" y="149" width="46.5278" height="26.3889" rx="5" stroke="#023DFE" stroke-opacity="0.6" stroke-width="3"/>
<path d="M134.184 160.409H134.135C135.619 160.409 136.807 160.833 137.699 161.679C138.598 162.532 139.047 163.697 139.047 165.175C139.047 166.64 138.559 167.831 137.582 168.749C136.605 169.667 135.316 170.126 133.715 170.126C132.953 170.126 132.25 170.019 131.605 169.804C130.967 169.589 130.45 169.329 130.053 169.023C129.675 168.73 129.34 168.427 129.047 168.115C128.76 167.809 128.565 167.551 128.461 167.343L128.275 167.021L129.574 165.839C129.6 165.911 129.649 165.999 129.721 166.103C129.773 166.181 129.926 166.37 130.18 166.669C130.427 166.956 130.684 167.197 130.951 167.392C131.225 167.587 131.605 167.776 132.094 167.958C132.576 168.134 133.09 168.222 133.637 168.222C134.62 168.222 135.421 167.932 136.039 167.353C136.658 166.773 136.967 166.015 136.967 165.077C136.967 164.133 136.654 163.395 136.029 162.861C135.398 162.32 134.542 162.05 133.461 162.05C132.348 162.05 131.212 162.379 130.053 163.036L128.998 162.275L129.994 155.195H137.895V157.031H131.732L131.137 161.034C131.996 160.618 133.012 160.409 134.184 160.409ZM147.387 170.097H147.367C145.466 170.097 143.943 169.384 142.797 167.958C141.658 166.539 141.088 164.719 141.088 162.499C141.088 160.312 141.661 158.508 142.807 157.089C143.952 155.67 145.476 154.96 147.377 154.96C149.258 154.96 150.762 155.673 151.889 157.099C153.015 158.531 153.578 160.331 153.578 162.499C153.578 164.719 153.018 166.539 151.898 167.958C150.779 169.384 149.275 170.097 147.387 170.097ZM147.367 168.134C148.565 168.134 149.545 167.613 150.307 166.572C151.068 165.53 151.449 164.182 151.449 162.529C151.449 160.875 151.068 159.527 150.307 158.486C149.545 157.444 148.565 156.923 147.367 156.923C146.143 156.923 145.147 157.444 144.379 158.486C143.604 159.534 143.217 160.881 143.217 162.529C143.217 164.176 143.604 165.523 144.379 166.572C145.147 167.613 146.143 168.134 147.367 168.134Z" fill="#023DFE" fill-opacity="0.6"/>
<path d="M162.557 158.212L162.572 158.227C162.311 158.865 161.882 159.376 161.283 159.76C160.68 160.147 159.953 160.341 159.1 160.341C157.977 160.341 157.043 159.981 156.297 159.262C155.555 158.546 155.184 157.639 155.184 156.542C155.184 155.461 155.555 154.563 156.297 153.847C157.043 153.127 157.974 152.768 159.09 152.768C159.943 152.768 160.667 152.963 161.263 153.354C161.862 153.744 162.29 154.252 162.547 154.877L161.087 155.468C160.902 155.103 160.638 154.807 160.296 154.579C159.951 154.348 159.551 154.232 159.095 154.232C158.444 154.232 157.896 154.452 157.45 154.892C157.007 155.331 156.786 155.88 156.786 156.537C156.786 157.188 157.009 157.74 157.455 158.192C157.897 158.642 158.444 158.866 159.095 158.866C159.577 158.866 159.992 158.747 160.34 158.51C160.692 158.272 160.941 157.974 161.087 157.616L162.557 158.212Z" fill="#023DFE" fill-opacity="0.6"/>
<mask id="path-8-inside-1_3800_1033" fill="white">
<path d="M200.929 217.62C200.929 217.247 200.627 216.945 200.254 216.945C199.882 216.945 199.58 217.247 199.58 217.62C199.58 220.615 197.143 223.051 194.149 223.051C193.776 223.051 193.474 223.353 193.474 223.726C193.474 224.098 193.776 224.4 194.149 224.4C197.887 224.4 200.929 221.358 200.929 217.62Z"/>
</mask>
<path d="M194.149 224.4L194.149 222.4H194.149V224.4ZM202.929 217.62C202.929 216.143 201.731 214.945 200.254 214.945V218.945C199.522 218.945 198.929 218.352 198.929 217.62H202.929ZM200.254 214.945C198.777 214.945 197.58 216.143 197.58 217.62H201.58C201.58 218.352 200.986 218.945 200.254 218.945V214.945ZM197.58 217.62C197.58 219.51 196.039 221.051 194.149 221.051V225.051C198.248 225.051 201.58 221.719 201.58 217.62H197.58ZM194.149 221.051C192.672 221.051 191.474 222.248 191.474 223.726H195.474C195.474 224.458 194.88 225.051 194.149 225.051V221.051ZM191.474 223.726C191.474 225.203 192.672 226.4 194.149 226.4V222.4C194.88 222.4 195.474 222.993 195.474 223.726H191.474ZM194.149 226.4C198.992 226.4 202.929 222.463 202.929 217.62H198.929C198.929 220.254 196.783 222.4 194.149 222.4L194.149 226.4Z" fill="#023DFE" fill-opacity="0.6" mask="url(#path-8-inside-1_3800_1033)"/>
<path d="M190.083 206.168L189.798 205.966L190.613 206.545L190.348 206.356L190.348 206.356L190.151 206.217L190.083 206.168ZM190.083 206.168C190.083 206.168 190.083 206.168 190.083 206.168L190.083 206.168ZM194.277 198.891L194.148 198.867L194.542 198.795L195.096 200.467C196.016 203.237 197.822 205.667 199.648 208.124C199.86 208.41 200.073 208.696 200.285 208.983C202.24 211.636 204.18 214.462 204.18 217.62C204.18 217.62 204.18 217.62 204.18 217.62C204.179 223.152 199.68 227.651 194.148 227.651C188.616 227.651 184.117 223.152 184.117 217.62C184.117 217.62 184.117 217.62 184.117 217.62C184.117 214.413 186.117 211.539 188.212 208.711C188.212 208.711 188.212 208.711 188.212 208.711L194.277 198.891ZM194.147 198.867L194.277 198.891C194.276 198.893 194.273 198.904 194.263 198.921C194.251 198.94 194.235 198.958 194.217 198.972C194.183 198.998 194.157 199 194.148 199C194.14 199 194.114 198.998 194.08 198.972C194.062 198.958 194.046 198.94 194.034 198.921C194.024 198.904 194.02 198.893 194.02 198.891L194.147 198.867ZM194.02 198.891C194.02 198.89 194.02 198.89 194.02 198.89C194.02 198.89 194.02 198.89 194.02 198.891L194.02 198.891Z" stroke="#023DFE" stroke-opacity="0.6" stroke-width="2"/>
<path d="M194.306 183.891V69.3055C194.306 67.3878 192.751 65.8333 190.833 65.8333H95.0001C93.0824 65.8333 91.5278 67.3878 91.5278 69.3055V215.139C91.5278 217.056 93.0824 218.611 95.0001 218.611H166.438M223.472 212.708C223.472 228.625 210.569 241.528 194.653 241.528C178.736 241.528 165.833 228.625 165.833 212.708C165.833 196.792 178.736 183.889 194.653 183.889C210.569 183.889 223.472 196.792 223.472 212.708Z" stroke="#023DFE" stroke-opacity="0.6" stroke-width="3"/>
</g>
<defs>
<filter id="filter0_d_3800_1033" 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_3800_1033"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3800_1033" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -0,0 +1,311 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_event.dart';
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_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/features/devices/model/water_heater.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
final String whId;
final String switchCode;
WHModel deviceStatus = WHModel(
firstSwitch: false,firstCountDown: 0
);
List<WHModel> deviceStatusList = [];
List<DeviceModel> devicesList = [];
bool allAcsPage = false;
bool allAcsOn = true;
bool allTempSame = true;
int globalTemp = 25;
Timer? _timer;
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
bool createCirculate = false;
List<ScheduleModel> listSchedule = [];
DateTime? selectedTime=DateTime.now();
WaterHeaterBloc({required this.whId,required this.switchCode}) : super(WHInitialState()) {
on<WaterHeaterInitial>(_fetchWaterHeaterStatus);
on<WaterHeaterSwitch>(_changeFirstSwitch);
on<SetCounterValue>(_setCounterValue);
on<GetCounterEvent>(_getCounterValue);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<ScheduleSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleChange);
on<DeleteScheduleEvent>(deleteSchedule);
on<TickTimer>(_onTickTimer);
on<OnClose>(_onClose);
}
void _fetchWaterHeaterStatus(WaterHeaterInitial event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(whId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = WHModel.fromJson(statusModelList, );
emit(UpdateState(whModel: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges();
} catch (e) {
emit(WHFailedState(errorMessage: e.toString()));
return;
}
}
void _changeFirstSwitch(WaterHeaterSwitch event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.whSwitch;
emit(UpdateState(whModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: whId,
code: 'switch_1',
value: deviceStatus.firstSwitch ),
whId);
if (!response['success']) {
// add(InitialEvent(groupScreen: oneGangGroup));
}
});
} catch (_) {
emit(WHFailedState(errorMessage: _.toString()));
}
}
//=====================---------- timer ----------------------------------------
void _setCounterValue(SetCounterValue event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: whId, code: event.deviceCode, value: seconds),
whId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown = seconds;
}
} else {
emit(const WHFailedState(errorMessage: 'Something went wrong'));
return;
}
} catch (e) {
emit(const WHFailedState(errorMessage: 'Something went wrong'));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(GetCounterEvent event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(whId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = WHModel.fromJson(statusModelList);
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown > 0
? _onStartTimer(deviceStatus.firstCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
}
} catch (e) {
WHFailedState(errorMessage: e.toString());
return;
}
}
void _onClose(OnClose event, Emitter<WaterHeaterState> emit) {
_timer?.cancel();
}
void _onStartTimer(int seconds) {
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
add(TickTimer(seconds - timer.tick));
});
}
void _onTickTimer(TickTimer event, Emitter<WaterHeaterState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
//=====================---------- Schedule ----------------------------------------
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> saveSchedule(ScheduleSave event, Emitter<WaterHeaterState> emit,) async {
try {
if(selectedDays.isNotEmpty) {
emit(WHLoadingState());
final response = await DevicesAPI.postSchedule(
category: switchCode,
deviceId: whId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(SaveSchedule());
toggleCreateSchedule();
}else{
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(WHFailedState(errorMessage:e.toString()));
}
}
Future<void> getSchedule(GetScheduleEvent event, Emitter<WaterHeaterState> emit,) async {
try {
emit(WHLoadingState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: whId ,
);
List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(WHInitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(WHFailedState(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<WaterHeaterState> emit) async {
try {
emit(WHLoadingState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: whId, 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(WHFailedState(errorMessage: errorMessage.toString()));
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<WaterHeaterState> emit) async {
try {
emit(WHLoadingState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: whId, );
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(WHFailedState(errorMessage: errorMessage.toString()));
}
}
void toggleCreateSchedule() {
emit(WHLoadingState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime=DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
void toggleCreateCirculate() {
emit(WHLoadingState());
createCirculate = !createCirculate;
selectedDays.clear();
selectedTime=DateTime.now();
emit(UpdateCreateScheduleState(createCirculate));
}
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<WaterHeaterState> emit,
) async {
emit(WHLoadingState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
}
int selectedTabIndex = 0;
void toggleSelectedIndex(index) {
emit(WHLoadingState());
selectedTabIndex = index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
}

View File

@ -0,0 +1,93 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
abstract class WaterHeaterEvent extends Equatable {
const WaterHeaterEvent();
@override
List<Object> get props => [];
}
class WaterHeaterLoading extends WaterHeaterEvent {}
class WaterHeaterSwitch extends WaterHeaterEvent {
final bool whSwitch;
final String deviceId;
final String productId;
const WaterHeaterSwitch({required this.whSwitch, this.deviceId = '', this.productId = ''});
@override
List<Object> get props => [whSwitch, deviceId, productId];
}
class WaterHeaterUpdated extends WaterHeaterEvent {}
class WaterHeaterInitial extends WaterHeaterEvent {
const WaterHeaterInitial();
}
class WaterHeaterChangeStatus extends WaterHeaterEvent {}
class GetCounterEvent extends WaterHeaterEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class SetCounterValue extends WaterHeaterEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends WaterHeaterEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends WaterHeaterEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends WaterHeaterEvent {}
class OnClose extends WaterHeaterEvent {}
//------------------- Schedule ----------=---------
class GetScheduleEvent extends WaterHeaterEvent {}
class ScheduleSave extends WaterHeaterEvent {}
class ToggleScheduleEvent extends WaterHeaterEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle,required this.id});
@override
List<Object> get props => [toggle,id];
}
class ToggleDaySelectionEvent extends WaterHeaterEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
class DeleteScheduleEvent extends WaterHeaterEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@override
List<Object> get props => [id];
}

View File

@ -0,0 +1,131 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/water_heater.dart';
abstract class WaterHeaterState extends Equatable {
const WaterHeaterState();
@override
List<Object> get props => [];
}
class WHInitialState extends WaterHeaterState {}
class WHLoadingState extends WaterHeaterState {}
class WHChangeLoading extends WaterHeaterState {
// final WHStatusModel WHStatusModel;
const WHChangeLoading(
// {required this. WHStatusModel}
);
// @override
// List<Object> get props => [acStatusModel];
}
class WHModifyingState extends WaterHeaterState {
final WHModel whStatusModel;
const WHModifyingState({required this.whStatusModel});
@override
List<Object> get props => [whStatusModel];
}
class GetWHStatusState extends WaterHeaterState {
final WHModel whStatusModel;
const GetWHStatusState({required this.whStatusModel});
@override
List<Object> get props => [whStatusModel];
}
class GetAllAcsStatusState extends WaterHeaterState {
final List<AcStatusModel> allAcsStatues;
final List<DeviceModel> allAcs;
final bool allOn;
final bool allTempSame;
final int temp;
const GetAllAcsStatusState(
{required this.allAcsStatues,
required this.allAcs,
required this.allOn,
required this.allTempSame,
required this.temp});
@override
List<Object> get props => [allAcsStatues, allAcs, allAcs, allTempSame, temp];
}
class WHFailedState extends WaterHeaterState {
final String errorMessage;
const WHFailedState({required this.errorMessage});
@override
List<Object> get props => [errorMessage];
}
class LoadingNewSate extends WaterHeaterState {
final WHModel whModel;
const LoadingNewSate({required this.whModel});
@override
List<Object> get props => [whModel];
}
class TimerRunComplete extends WaterHeaterState {}
class UpdateTimerState extends WaterHeaterState {
final int seconds;
const UpdateTimerState({required this.seconds});
@override
List<Object> get props => [seconds];
}
class TimerRunInProgress extends WaterHeaterState {
final int remainingTime;
const TimerRunInProgress(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class SaveSchedule extends WaterHeaterState {}
class ChangeTimeState extends WaterHeaterState {}
class UpdateCreateScheduleState extends WaterHeaterState {
final bool createSchedule;
UpdateCreateScheduleState(this.createSchedule);
}
class IsToggleState extends WaterHeaterState {
final bool? onOff;
const IsToggleState({this.onOff});
}
class UpdateState extends WaterHeaterState {
final WHModel whModel;
const UpdateState({required this.whModel});
@override
List<Object> get props => [WHModel];
}
class ChangeSwitchStatusEvent extends WaterHeaterState {
final bool value;
final String deviceId;
const ChangeSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeSlidingSegmentState extends WaterHeaterState {
final int value;
const ChangeSlidingSegmentState({required this.value});
@override
List<Object> get props => [value];
}

View File

@ -0,0 +1,141 @@
//
//
// import 'package:syncrow_app/features/devices/model/status_model.dart';
//
// class WHModel {
// final int activeTime;
// final String category;
// final String categoryName;
// final int createTime;
// final String gatewayId;
// final String icon;
// final String ip;
// final String lat;
// final String lon;
// final String localKey;
// final String model;
// final String name;
// final String nodeId;
// final bool online;
// final String ownerId;
// final bool sub;
// final String timeZone;
// final int updateTime;
// final String uuid;
// final String productUuid;
// final String productType;
// final String permissionType;
//
// WHModel({
// required this.activeTime,
// required this.category,
// required this.categoryName,
// required this.createTime,
// required this.gatewayId,
// required this.icon,
// required this.ip,
// required this.lat,
// required this.lon,
// required this.localKey,
// required this.model,
// required this.name,
// required this.nodeId,
// required this.online,
// required this.ownerId,
// required this.sub,
// required this.timeZone,
// required this.updateTime,
// required this.uuid,
// required this.productUuid,
// required this.productType,
// required this.permissionType,
// });
//
// // Factory method to create a SmartDevice object from JSON
// factory WHModel.fromJson(Map<String, dynamic> json, List<StatusModel> statusModelList) {
// return WHModel(
// activeTime: json['activeTime'],
// category: json['category'],
// categoryName: json['categoryName'],
// createTime: json['createTime'],
// gatewayId: json['gatewayId'],
// icon: json['icon'],
// ip: json['ip'],
// lat: json['lat'],
// lon: json['lon'],
// localKey: json['localKey'],
// model: json['model'],
// name: json['name'],
// nodeId: json['nodeId'],
// online: json['online'],
// ownerId: json['ownerId'],
// sub: json['sub'],
// timeZone: json['timeZone'],
// updateTime: json['updateTime'],
// uuid: json['uuid'],
// productUuid: json['productUuid'],
// productType: json['productType'],
// permissionType: json['permissionType'],
// );
// }
//
// // Method to convert SmartDevice object to JSON
// Map<String, dynamic> toJson() {
// return {
// 'activeTime': activeTime,
// 'category': category,
// 'categoryName': categoryName,
// 'createTime': createTime,
// 'gatewayId': gatewayId,
// 'icon': icon,
// 'ip': ip,
// 'lat': lat,
// 'lon': lon,
// 'localKey': localKey,
// 'model': model,
// 'name': name,
// 'nodeId': nodeId,
// 'online': online,
// 'ownerId': ownerId,
// 'sub': sub,
// 'timeZone': timeZone,
// 'updateTime': updateTime,
// 'uuid': uuid,
// 'productUuid': productUuid,
// 'productType': productType,
// 'permissionType': permissionType,
// };
// }
// }
import 'package:syncrow_app/features/devices/model/status_model.dart';
class WHModel {
bool firstSwitch;
int firstCountDown;
WHModel(
{required this.firstSwitch,
required this.firstCountDown,
});
factory WHModel.fromJson(List<StatusModel> jsonList) {
late bool _switch;
late int _count;
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch_1') {
_switch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'countdown_1') {
_count = jsonList[i].value ?? 0;
}
}
return WHModel(
firstSwitch: _switch,
firstCountDown: _count,
);
}
}

View File

@ -14,11 +14,11 @@ import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface
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';
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_screen.dart'; import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/wall_sensor/wall_sensor_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/wall_sensor/wall_sensor_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_heater/water_heater_page.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart'; import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
@ -148,6 +148,14 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
ThreeGangInterface(gangSwitch: device))); ThreeGangInterface(gangSwitch: device)));
case DeviceType.WH:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
WaterHeaterPage(device: device)));
break; break;
default: default:
} }

View File

@ -0,0 +1,69 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import '../../../../../utils/resource_manager/color_manager.dart';
class InchingWidget extends StatefulWidget {
const InchingWidget({super.key,this.onDateTimeChanged});
final Function(DateTime)? onDateTimeChanged;
@override
State<InchingWidget> createState() => _InchingWidgetState();
}
class _InchingWidgetState extends State<InchingWidget> {
@override
Widget build(BuildContext context) {
bool isOn = true; // Boolean state for the ON/OFF toggle
return Column(
children: [
DefaultContainer(
child: Container(
padding: EdgeInsets.all(10),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Inching', // Change text based on state
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
CircleAvatar(
backgroundColor: isOn
? ColorsManager.secondaryColor.withOpacity(0.6)
: Colors.red.withOpacity(0.6), // Change background color based on state
child: const Icon(
Icons.power_settings_new,
color: ColorsManager.onPrimaryColor, // Change icon color
),
),
],
),
SizedBox(height: 10,),
Text('Once enabled this feature, each time the device is turned on, it will automatically turn of after a period time as pre-set.'),
],
),
),
),
SizedBox(
height: 110,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.time,
initialDateTime: DateTime.now(),
onDateTimeChanged: (selectedTime) {
}, ),
),
],
);
}
}

View File

@ -0,0 +1,125 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/empty_schedule.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/generated/assets.dart';
class CirculateListView extends StatelessWidget {
final List<ScheduleModel> listSchedule;
final Function(String) onDismissed;
final Function(String, bool) onToggleSchedule;
const CirculateListView({
super.key,
required this.listSchedule,
required this.onDismissed,
required this.onToggleSchedule,
});
@override
Widget build(BuildContext context) {
return Center(
child: listSchedule.isNotEmpty
? SizedBox(
child: ListView.builder(
shrinkWrap: true,
itemCount: listSchedule.length,
itemBuilder: (context, index) {
return Dismissible(
key: Key(listSchedule[index].scheduleId),
background: Container(
padding: const EdgeInsets.only(right: 10),
alignment: AlignmentDirectional.centerEnd,
decoration: const ShapeDecoration(
color: Color(0xFFFF0000),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
),
),
child: Padding(
padding: const EdgeInsets.only(bottom: 10, right: 10),
child: SvgPicture.asset(
Assets.assetsDeleteIcon,
width: 20,
height: 22,
),
),
),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
onDismissed(listSchedule[index].scheduleId);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Schedule removed')),
);
},
child: InkWell(
onTap: () {
},
child: DefaultContainer(
padding: const EdgeInsets.all(20),
height: MediaQuery.of(context).size.height / 6.4,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
BodyLarge(
text: '12:30 AM - 01:30 PM',
// text: listSchedule[index].time,
fontWeight: FontWeight.w500,
fontColor: Colors.black,
fontSize: 22,
),
Text(listSchedule[index].days.join(' ')),
// Text('Function ${listSchedule[index].function.value ? "ON" : "OFF"}'),
Text('Start Duration: 0h 10m End Duration: 0h 15m'),
],
),
),
Expanded(
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyMedium(
text: '',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: listSchedule[index].enable,
onChanged: (value) {
onToggleSchedule(
listSchedule[index].scheduleId,
value,
);
},
applyTheme: true,
),
),
),
),
],
),
),
),
);
},
),
)
: const EmptySchedule()
);
}
}

View File

@ -0,0 +1,168 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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 CirculateWidget extends StatelessWidget {
final bool isStartEndTime;
final DateTime startTime;
final DateTime endTime;
final List<Map<String, String>> days;
final List<String> selectedDays;
// Callback functions to handle user interactions
final Function(bool) onToggleStartEndTime;
final Function(DateTime, bool) onTimeChanged;
final Function(String) onDaySelected;
const CirculateWidget({
Key? key,
required this.isStartEndTime,
required this.startTime,
required this.endTime,
required this.days,
required this.selectedDays,
required this.onToggleStartEndTime,
required this.onTimeChanged,
required this.onDaySelected,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
child: Column(
children: <Widget>[
// Start/End time toggle buttons
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
onToggleStartEndTime(true); // Toggle to Start Time
},
child: BodyMedium(
text: 'Start',
fontColor: !isStartEndTime ? Colors.black : Colors.blue,
fontSize: 18,
),
),
InkWell(
onTap: () {
onToggleStartEndTime(false); // Toggle to End Time
},
child: BodyMedium(
text: 'End',
fontColor: isStartEndTime ? Colors.black : Colors.blue,
fontSize: 18,
),
),
],
),
),
const Divider(
color: ColorsManager.graysColor,
),
// Time picker based on start/end toggle
SizedBox(
height: 110,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.time,
initialDateTime: isStartEndTime ? startTime : endTime,
onDateTimeChanged: (selectedTime) {
onTimeChanged(selectedTime, isStartEndTime); // Notify parent of time change
},
),
),
const Divider(
color: ColorsManager.graysColor,
),
const SizedBox(height: 20),
Text('Select days to use Smart Mode'),
const SizedBox(height: 20),
// Days selection as horizontal list
SizedBox(
height: MediaQuery.of(context).size.height * 0.10,
child: ListView(
scrollDirection: Axis.horizontal,
children: days.map((day) {
bool isSelected = selectedDays.contains(day['key']);
return Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () {
onDaySelected(day['key']!); // Notify parent of day selection
},
child: Container(
width: 70,
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(55),
),
child: Center(
child: Text(
day['day']!,
style: TextStyle(
fontSize: 18,
color: isSelected ? Colors.black : ColorsManager.grayColor,
),
),
),
),
),
);
}).toList(),
),
),
const SizedBox(height: 20),
const DefaultContainer(child:
Column(
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Start Duration'),
Row(
children: [
Text('0h 0m'),
Icon(Icons.arrow_forward_ios_sharp,color:ColorsManager.graysColor,)
],
),
],),
),
Divider(color: ColorsManager.graysColor,),
Padding(
padding: EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('End Duration'),
Row(
children: [
Text('0h 0m'),
Icon(Icons.arrow_forward_ios_sharp,color:ColorsManager.graysColor,)
],
),
],),
),
],
)
)
],
),
);
}
}

View File

@ -0,0 +1,188 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_event.dart';
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/water_heater.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.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/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import '../../../../../generated/assets.dart';
class WaterHeaterPage extends StatelessWidget {
final DeviceModel? device;
const WaterHeaterPage({super.key, this.device});
@override
Widget build(BuildContext context) {
bool value = false;
return DefaultScaffold(
child: BlocProvider(
create: (context) =>
WaterHeaterBloc(switchCode: 'switch_1', whId: device?.uuid ?? '')
..add(const WaterHeaterInitial()),
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
builder: (context, state) {
final waterHeaterBloc = BlocProvider.of<WaterHeaterBloc>(context);
WHModel whModel = WHModel(firstCountDown: 0, firstSwitch: false);
if (state is LoadingNewSate) {
whModel = state.whModel;
} else if (state is UpdateState) {
whModel = state.whModel;
}
return state is WHLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
waterHeaterBloc.add(WaterHeaterInitial(
// groupScreen: device != null ? false : true
));
},
child: Center(
child: ListView(
shrinkWrap: true,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
overlayColor: MaterialStateProperty.all(
Colors.transparent),
onTap: () {
waterHeaterBloc.add(
WaterHeaterSwitch(
whSwitch:whModel.firstSwitch
),);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
decoration: BoxDecoration(
// color: Colors.white.withOpacity(0.1),
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: SvgPicture.asset(
whModel.firstSwitch
? Assets.waterHeaterOn
: Assets.waterHeaterOff,
fit: BoxFit.fill,
),
),
],
),
),
const SizedBox(height: 80),
SizedBox(
child: Column(
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(100),
),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
WHTimerScheduleScreen(
switchCode: 'switch_1', device: device!, deviceCode: 'countdown_1',
)));
},
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius:
BorderRadius.circular(100),
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.circular(100),
),
child: Center(
child: Icon(
Icons.access_time,
color: ColorsManager
.primaryColorWithOpacity,
size: 25,
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "Timer",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
)
],
),
],
),
),
);
},
),
),
);
}
}

View File

@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/generated/assets.dart';
class WaterHeaterSwitchIcon extends StatelessWidget {
const WaterHeaterSwitchIcon({super.key, required this.value, required this.action});
final bool value;
final Function action;
@override
Widget build(BuildContext context) {
return InkWell(
overlayColor: MaterialStateProperty.all(Colors.transparent),
onTap: () {
action();
},
child: ClipRRect(
borderRadius: BorderRadius.circular(190.0),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
blurStyle: BlurStyle.inner,
color: Colors.black.withOpacity(0.1),
spreadRadius: 9,
blurRadius: 2,
offset: const Offset(3, 1),
),
],
),
child: SvgPicture.asset(
value ? Assets.waterHeaterOn : Assets.waterHeaterOff,
fit: BoxFit.fill,
),
),
),
);
}
}

View File

@ -0,0 +1,411 @@
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/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_heater/Inching_widget.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_heater/circulate_list_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_heater/circulate_widget.dart';
import 'package:syncrow_app/features/shared_widgets/create_schedule.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/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
import '../../../bloc/water_heater_bloc/water_heater_event.dart';
class WHTimerScheduleScreen extends StatelessWidget {
final DeviceModel device;
final String deviceCode;
final String switchCode;
const WHTimerScheduleScreen(
{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) =>
WaterHeaterBloc(switchCode: switchCode, whId: device.uuid ?? '')
..add(GetCounterEvent(deviceCode: deviceCode))
..add(GetScheduleEvent()),
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
builder: (context, state) {
final waterHeaterBloc = BlocProvider.of<WaterHeaterBloc>(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) {
waterHeaterBloc.add(OnClose());
Navigator.pop(context);
}
},
child: DefaultTabController(
length: 4,
child: DefaultScaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Schedule',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
actions: [
waterHeaterBloc.createSchedule == true
&& waterHeaterBloc.selectedTabIndex == 1 ? TextButton(
onPressed: () {
waterHeaterBloc.add(ScheduleSave());
},
child: const Text('Save'))
: waterHeaterBloc.selectedTabIndex == 1
? IconButton(
onPressed: () {
waterHeaterBloc.toggleCreateSchedule();
},
icon: const Icon(Icons.add),
)
: const SizedBox(),
waterHeaterBloc.createCirculate == true
&&waterHeaterBloc.selectedTabIndex==2 ? TextButton(
onPressed: () {
waterHeaterBloc.add(ScheduleSave());
},
child: const Text('Save'))
: waterHeaterBloc.selectedTabIndex == 2
? IconButton(
onPressed: () {
waterHeaterBloc.toggleCreateCirculate();
},
icon: const Icon(Icons.add),
)
: const SizedBox(),
],
),
child: state is WHLoadingState
? 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)),
),
),
child: TabBar(
indicatorPadding: EdgeInsets.zero,
padding: EdgeInsets.zero,
labelPadding: EdgeInsets.zero,
onTap: (value) {
if (value == 0) {
if (waterHeaterBloc.createSchedule == true) {
waterHeaterBloc.toggleCreateSchedule();
}
waterHeaterBloc.toggleSelectedIndex(value);
} else if (value == 2) {
if (waterHeaterBloc.createCirculate == true) {
waterHeaterBloc.toggleCreateCirculate();
}
waterHeaterBloc.toggleSelectedIndex(value);
} else {
waterHeaterBloc.toggleSelectedIndex(value);
}
},
indicatorColor: Colors.white,
dividerHeight: 0,
indicatorSize: TabBarIndicatorSize.tab,
indicator: const ShapeDecoration(
color: ColorsManager.slidingBlueColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(20)),
),
),
isScrollable: false,
labelColor: Colors.white, // Text color when selected
unselectedLabelColor: ColorsManager.blackColor, // Text color when not selected
tabs: [
Tab(
icon: SvgPicture.asset(
Assets.scheduleTimeIcon,
color: waterHeaterBloc.selectedTabIndex == 0
? Colors.white
: ColorsManager.blackColor, // Change icon color based on selectedIndex
),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: BodySmall(
text: 'Countdown',
style: context.bodySmall.copyWith(
color: waterHeaterBloc.selectedTabIndex == 0
? Colors.white
: ColorsManager
.blackColor, // Text color based on selectedTabIndex
fontSize: 8,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
icon: SvgPicture.asset(
Assets.scheduleCelenderIcon,
color: waterHeaterBloc.selectedTabIndex == 1
? Colors.white
: ColorsManager.blackColor,
),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: Text(
'Schedule',
style: context.bodySmall.copyWith(
color: waterHeaterBloc.selectedTabIndex == 1
? Colors.white
: ColorsManager.blackColor,
fontSize: 8,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
icon: SvgPicture.asset(
Assets.scheduleCirculateIcon,
color: waterHeaterBloc.selectedTabIndex == 2
? Colors.white
: ColorsManager.blackColor,
),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: Text(
'Circulate',
style: context.bodySmall.copyWith(
color: waterHeaterBloc
.selectedTabIndex ==
2
? Colors.white
: ColorsManager.blackColor,
fontSize: 8,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
icon: SvgPicture.asset(
Assets.scheduleInchingIcon,
color: waterHeaterBloc
.selectedTabIndex ==
3
? Colors.white
: ColorsManager.blackColor,
),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: Text(
'Inching',
style: context.bodySmall.copyWith(
color: waterHeaterBloc
.selectedTabIndex ==
3
? Colors.white
: ColorsManager.blackColor,
fontSize: 8,
fontWeight: FontWeight.w400,
),
),
),
),
],
)),
Expanded(
child: TabBarView(
physics:
const NeverScrollableScrollPhysics(), // Disable swiping
children: [
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) {
waterHeaterBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration: Duration
.zero));
} else if (duration !=
Duration.zero) {
waterHeaterBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration:
duration));
}
},
child: SvgPicture.asset(
countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
),
),
),
Column(
mainAxisAlignment: waterHeaterBloc
.listSchedule.isNotEmpty
? MainAxisAlignment.start
: MainAxisAlignment.center,
children: [
SizedBox(
child: waterHeaterBloc.createSchedule == true
? CreateSchedule(
onToggleChanged: (bool isOn) {
waterHeaterBloc.toggleSchedule = isOn;
},
onDateTimeChanged: (DateTime dateTime) {
waterHeaterBloc.selectedTime = dateTime;
},
days: waterHeaterBloc.days,
selectDays: (List<String>
selectedDays) {
waterHeaterBloc
.selectedDays =
selectedDays;
},
)
: Padding(
padding: const EdgeInsets.only(top: 10),
child: ScheduleListView(
listSchedule: waterHeaterBloc.listSchedule, // Pass the schedule list here
onDismissed:
(scheduleId) {
waterHeaterBloc.listSchedule.removeWhere(
(schedule) => schedule.scheduleId == scheduleId);
waterHeaterBloc.add(
DeleteScheduleEvent(id: scheduleId));
},
onToggleSchedule: (scheduleId, isEnabled) {
waterHeaterBloc.add(ToggleScheduleEvent(
id: scheduleId, toggle: isEnabled,
));
},
),
),
),
],
),
Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
waterHeaterBloc.createCirculate == true
?
CirculateWidget(
isStartEndTime: true,
startTime: DateTime.now(),
endTime: DateTime.now(),
days: waterHeaterBloc.days,
selectedDays: [],
onToggleStartEndTime: (c) {},
onTimeChanged: (x, f) {},
onDaySelected: (p0) {},
):CirculateListView(
listSchedule: waterHeaterBloc.listSchedule, // Pass the schedule list here
onDismissed: (scheduleId) {
waterHeaterBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId);
waterHeaterBloc.add(DeleteScheduleEvent(id: scheduleId));
},
onToggleSchedule: (scheduleId, isEnabled) {
waterHeaterBloc.add(ToggleScheduleEvent(
id: scheduleId, toggle: isEnabled,
));
},
)
],
),
),
Column(children: [
SizedBox(height: 20),
Container(child: InchingWidget(),),],)
],
),
),
],
),
)));
},
),
),
);
}
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';
}
}

View File

@ -1041,4 +1041,15 @@ class Assets {
static const String twoGang = "assets/icons/2gang.svg"; static const String twoGang = "assets/icons/2gang.svg";
static const String emptySchedule = "assets/icons/emptySchedule.svg"; static const String emptySchedule = "assets/icons/emptySchedule.svg";
static const String waterHeaterOn = "assets/icons/water_heater_on.svg";
static const String waterHeaterOff = "assets/icons/water_heater_off.svg";
static const String scheduleCelenderIcon = "assets/icons/schedule_celender_icon.svg";
static const String scheduleCirculateIcon = "assets/icons/schedule_circulate_icon.svg";
static const String scheduleInchingIcon = "assets/icons/schedule_Inching_icon.svg";
static const String scheduleTimeIcon = "assets/icons/schedule_time_icon.svg";
} }

View File

@ -14,7 +14,7 @@ void main() {
//to catch all the errors in the app and send them to firebase //to catch all the errors in the app and send them to firebase
runZonedGuarded(() async { runZonedGuarded(() async {
//to load the environment variables //to load the environment variables
const environment = String.fromEnvironment('FLAVOR', defaultValue: 'production'); const environment = String.fromEnvironment('FLAVOR', defaultValue: 'development');
await dotenv.load(fileName: '.env.$environment'); await dotenv.load(fileName: '.env.$environment');
// //this is to make the app work with the self-signed certificate // //this is to make the app work with the self-signed certificate

View File

@ -32,14 +32,15 @@ class DevicesAPI {
static Future<Map<String, dynamic>> controlDevice( static Future<Map<String, dynamic>> controlDevice(
DeviceControlModel controlModel, String deviceId) async { DeviceControlModel controlModel, String deviceId) async {
try { try {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.controlDevice.replaceAll('{deviceUuid}', deviceId), path: ApiEndpoints.controlDevice.replaceAll('{deviceUuid}', deviceId),
body: controlModel.toJson(), body: controlModel.toJson(),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
print('controlDevice=$json' );
return json; return json;
}, },
); );
return response; return response;
} catch (e) { } catch (e) {
@ -75,6 +76,8 @@ class DevicesAPI {
path: ApiEndpoints.deviceFunctionsStatus.replaceAll('{deviceUuid}', deviceId), path: ApiEndpoints.deviceFunctionsStatus.replaceAll('{deviceUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
print('json===$json');
return json; return json;
}, },
); );
@ -278,17 +281,7 @@ class DevicesAPI {
required String code, required String code,
required bool value, required bool value,
required List<String> days, required List<String> days,
}) async { }) async {
print( {
"category": category,
"time": time,
"function":{
"code": code,
"value":value,
},
"days": days
});
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.saveSchedule.replaceAll('{deviceUuid}', deviceId), path: ApiEndpoints.saveSchedule.replaceAll('{deviceUuid}', deviceId),
showServerMessage: false, showServerMessage: false,

View File

@ -49,6 +49,7 @@ enum DeviceType {
Gateway, Gateway,
CeilingSensor, CeilingSensor,
WallSensor, WallSensor,
WH,
Other, Other,
} }
@ -73,6 +74,7 @@ Map<String, DeviceType> devicesTypesMap = {
"2G": DeviceType.TwoGang, "2G": DeviceType.TwoGang,
"1G": DeviceType.OneGang, "1G": DeviceType.OneGang,
"CUR": DeviceType.Curtain, "CUR": DeviceType.Curtain,
"WH": DeviceType.WH,
}; };
Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = { Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
DeviceType.AC: [ DeviceType.AC: [
@ -185,7 +187,6 @@ Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1}) values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})
), ),
], ],
DeviceType.ThreeGang: [ DeviceType.ThreeGang: [
FunctionModel( FunctionModel(
code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})),
@ -221,6 +222,43 @@ Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
{"unit": "%", "min": 0, "max": 100, "scale": 0, "step": 1}) {"unit": "%", "min": 0, "max": 100, "scale": 0, "step": 1})
), ),
], ],
DeviceType.WH: [
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": 43200, "scale": 0, "step": 1})
),
FunctionModel(
code: 'relay_status',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson(
{"range": [ "off", "on"]})
),
FunctionModel(
code: 'switch_backlight',
type: functionTypesMap['Boolean'],
values: ValueModel.fromJson(
{})
),
FunctionModel(
code: 'switch_inching',
type: functionTypesMap['String'],
values: ValueModel.fromJson(
{"maxlen": 255,})
),
FunctionModel(
code: 'cycle_timing',
type: functionTypesMap['Raw'],
values: ValueModel.fromJson(
{"maxlen": 255})
),
],
}; };
enum TempModes { hot, cold, wind } enum TempModes { hot, cold, wind }

View File

@ -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+21 version: 1.0.3+22
environment: environment:
sdk: ">=3.0.6 <4.0.0" sdk: ">=3.0.6 <4.0.0"