Compare commits

..

45 Commits

Author SHA1 Message Date
81090d46df auto_settings 2024-10-16 16:34:53 +03:00
0e6b83d9f5 Fixed design issues 2024-10-10 14:29:53 +03:00
5f1c4c5371 Updated the error response body 2024-10-10 13:05:48 +03:00
6efb6dd508 Merge pull request #57 from SyncrowIOT/water_leak
Water leak
2024-10-10 12:52:04 +03:00
8c3df584db pubspec 2024-10-10 10:15:59 +03:00
40ee207623 bugs fixes 2024-10-10 10:00:48 +03:00
82f08ddcd8 garage size 2024-10-09 15:22:11 +03:00
465a2e3108 curtain wizard & bugs fixes 2024-10-09 14:58:08 +03:00
e0049c0aec curtain wizard 2024-10-08 17:02:24 +03:00
f2172bd6e8 garage Alarm 2024-10-08 13:06:32 +03:00
e5af727144 remove real time 2024-10-08 11:00:03 +03:00
978e77c167 remove socket from water heater 2024-10-08 10:27:05 +03:00
4916961d49 garage door Schedule 2024-10-08 10:17:32 +03:00
c8e0aa2aa8 garage door schedule 2024-10-08 10:15:53 +03:00
75b3036e03 water leak 2024-10-08 10:11:08 +03:00
754d869fac water leak 2024-10-07 16:53:50 +03:00
1f904e107a Merge pull request #56 from SyncrowIOT/garage_door
Garage door
2024-10-07 15:28:32 +03:00
b89053c1fb fiz wizard issue 2024-10-07 15:24:06 +03:00
281414ac41 garage wizard 2024-10-07 10:29:42 +03:00
208fbd63f3 garage door wizard 2024-10-07 10:26:08 +03:00
3454f0e28d Updated the curtain design 2024-10-07 01:40:16 +03:00
2d54d52061 Updated the curtain desgin and removed unused code 2024-10-06 22:30:28 +03:00
4b45257aff garage door 2024-10-06 16:59:28 +03:00
8476b51049 garage door 2024-10-06 16:49:36 +03:00
5e046b1deb garage door 2024-10-06 16:48:17 +03:00
487c7c5514 Merge pull request #55 from SyncrowIOT/SP-630
Sp 630
2024-10-03 13:12:44 +03:00
d9761168e6 bugs fixes 2024-10-03 12:46:56 +03:00
cc7af3e4e6 wizard 2024-10-02 13:26:25 +03:00
b5af6add35 touch wizard 1gt and 2 gt and 3gt 2024-10-02 13:02:29 +03:00
0d5492d626 three touch 2024-10-01 17:01:50 +03:00
908533dc9e tow touch and three touch 2024-10-01 16:33:11 +03:00
d75d438106 two touch & three touch 2024-10-01 16:24:36 +03:00
b8b6ec67c7 setting 2024-09-30 17:30:16 +03:00
fed39b7198 setting 2024-09-30 17:02:31 +03:00
5030b3f313 one touch 2024-09-29 16:35:24 +03:00
c4ff19d471 one touch 2024-09-29 16:06:05 +03:00
e1cd9e55c2 Merge pull request #54 from SyncrowIOT/SP-496
Sp 496
2024-09-29 12:08:13 +03:00
3082148e8c Bug fixes 2 2024-09-29 12:03:58 +03:00
2fb18965f4 Bug fixes 2024-09-29 01:52:17 +03:00
8d784f1e95 fixes 2024-09-27 16:58:09 +03:00
bc1b92cd5c fixes 2024-09-26 16:47:19 +03:00
6e32f30970 fixes 2024-09-26 16:36:54 +03:00
781522d4b6 fixes 2024-09-26 16:36:23 +03:00
4e345db842 one gang wizard &two Gang wizard & wh wizard 2024-09-26 16:26:39 +03:00
8508995108 Merge pull request #53 from SyncrowIOT/491
491
2024-09-24 11:51:09 +03:00
152 changed files with 15497 additions and 1585 deletions

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"cSpell.words": [
"Scheduleapp"
]
}

View File

@ -18,6 +18,7 @@
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">

View File

@ -0,0 +1,5 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M38.0142 39.2553L35.3682 40H20.9308H19.9999H19.0691H1.24111C0.555643 40 0 39.4444 0 38.7589V1.24111C0 0.555643 0.555643 0 1.24111 0H19.0682H20.1226H20.9543H35.4255L38.2625 1.24111C38.9479 1.24111 39.5036 1.79675 39.5036 2.48221L39.2553 38.0142C39.2553 38.6997 38.6997 39.2553 38.0142 39.2553Z" fill="#D1D1D1"/>
<path d="M38.7589 0H35.0356C35.721 0 36.2767 0.555643 36.2767 1.24111V38.7589C36.2767 39.4444 35.721 40 35.0356 40H38.7589C39.4444 40 40 39.4444 40 38.7589V1.24111C40 0.555643 39.4444 0 38.7589 0Z" fill="#A0A0A0"/>
<path opacity="0.6" d="M20.875 19.2411V20.7304C20.875 20.9746 20.7996 21.1767 20.7014 21.3067C20.6035 21.4364 20.5053 21.4715 20.4375 21.4715H16.3125C16.2447 21.4715 16.1465 21.4364 16.0486 21.3067C15.9504 21.1767 15.875 20.9746 15.875 20.7304V19.2411C15.875 18.9969 15.9504 18.7949 16.0486 18.6649C16.1465 18.5352 16.2447 18.5 16.3125 18.5H20.4375C20.5053 18.5 20.6035 18.5352 20.7014 18.6649C20.7996 18.7949 20.875 18.9969 20.875 19.2411Z" stroke="#023DFE" stroke-opacity="0.6"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,6 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M38.0142 39.2553L35.3682 40H20.9308H19.9999H19.0691H1.24111C0.555643 40 0 39.4444 0 38.7589V1.24111C0 0.555643 0.555643 0 1.24111 0H19.0682H20.1226H20.9543H35.4255L38.2625 1.24111C38.9479 1.24111 39.5036 1.79675 39.5036 2.48221L39.2553 38.0142C39.2553 38.6997 38.6997 39.2553 38.0142 39.2553Z" fill="#D1D1D1"/>
<path d="M38.7589 0H35.0356C35.721 0 36.2767 0.555643 36.2767 1.24111V38.7589C36.2767 39.4444 35.721 40 35.0356 40H38.7589C39.4444 40 40 39.4444 40 38.7589V1.24111C40 0.555643 39.4444 0 38.7589 0Z" fill="#A0A0A0"/>
<path opacity="0.6" d="M16.5 19.2411V20.7304C16.5 20.9746 16.4246 21.1767 16.3264 21.3067C16.2285 21.4364 16.1303 21.4715 16.0625 21.4715H11.9375C11.8697 21.4715 11.7715 21.4364 11.6736 21.3067C11.5754 21.1767 11.5 20.9746 11.5 20.7304V19.2411C11.5 18.9969 11.5754 18.7949 11.6736 18.6649C11.7715 18.5352 11.8697 18.5 11.9375 18.5H16.0625C16.1303 18.5 16.2285 18.5352 16.3264 18.6649C16.4246 18.7949 16.5 18.9969 16.5 19.2411Z" stroke="#023DFE" stroke-opacity="0.6"/>
<path opacity="0.6" d="M26.5 19.2411V20.7304C26.5 20.9746 26.4246 21.1767 26.3264 21.3067C26.2285 21.4364 26.1303 21.4715 26.0625 21.4715H21.9375C21.8697 21.4715 21.7715 21.4364 21.6736 21.3067C21.5754 21.1767 21.5 20.9746 21.5 20.7304V19.2411C21.5 18.9969 21.5754 18.7949 21.6736 18.6649C21.7715 18.5352 21.8697 18.5 21.9375 18.5H26.0625C26.1303 18.5 26.2285 18.5352 26.3264 18.6649C26.4246 18.7949 26.5 18.9969 26.5 19.2411Z" stroke="#023DFE" stroke-opacity="0.6"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,7 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M38.0142 39.2553L35.3682 40H20.9308H19.9999H19.0691H1.24111C0.555643 40 0 39.4444 0 38.7589V1.24111C0 0.555643 0.555643 0 1.24111 0H19.0682H20.1226H20.9543H35.4255L38.2625 1.24111C38.9479 1.24111 39.5036 1.79675 39.5036 2.48221L39.2553 38.0142C39.2553 38.6997 38.6997 39.2553 38.0142 39.2553Z" fill="#D1D1D1"/>
<path d="M38.7589 0H35.0356C35.721 0 36.2767 0.555643 36.2767 1.24111V38.7589C36.2767 39.4444 35.721 40 35.0356 40H38.7589C39.4444 40 40 39.4444 40 38.7589V1.24111C40 0.555643 39.4444 0 38.7589 0Z" fill="#A0A0A0"/>
<path opacity="0.6" d="M10.5 19.2411V20.7304C10.5 20.9746 10.4246 21.1767 10.3264 21.3067C10.2285 21.4364 10.1303 21.4715 10.0625 21.4715H5.9375C5.86973 21.4715 5.77153 21.4364 5.67355 21.3067C5.57536 21.1767 5.5 20.9746 5.5 20.7304V19.2411C5.5 18.9969 5.57536 18.7949 5.67355 18.6649C5.77153 18.5352 5.86973 18.5 5.9375 18.5H10.0625C10.1303 18.5 10.2285 18.5352 10.3264 18.6649C10.4246 18.7949 10.5 18.9969 10.5 19.2411Z" stroke="#023DFE" stroke-opacity="0.6"/>
<path opacity="0.6" d="M20.5 19.2411V20.7304C20.5 20.9746 20.4246 21.1767 20.3264 21.3067C20.2285 21.4364 20.1303 21.4715 20.0625 21.4715H15.9375C15.8697 21.4715 15.7715 21.4364 15.6736 21.3067C15.5754 21.1767 15.5 20.9746 15.5 20.7304V19.2411C15.5 18.9969 15.5754 18.7949 15.6736 18.6649C15.7715 18.5352 15.8697 18.5 15.9375 18.5H20.0625C20.1303 18.5 20.2285 18.5352 20.3264 18.6649C20.4246 18.7949 20.5 18.9969 20.5 19.2411Z" stroke="#023DFE" stroke-opacity="0.6"/>
<path opacity="0.6" d="M30.5 19.2411V20.7304C30.5 20.9746 30.4246 21.1767 30.3264 21.3067C30.2285 21.4364 30.1303 21.4715 30.0625 21.4715H25.9375C25.8697 21.4715 25.7715 21.4364 25.6736 21.3067C25.5754 21.1767 25.5 20.9746 25.5 20.7304V19.2411C25.5 18.9969 25.5754 18.7949 25.6736 18.6649C25.7715 18.5352 25.8697 18.5 25.9375 18.5H30.0625C30.1303 18.5 30.2285 18.5352 30.3264 18.6649C30.4246 18.7949 30.5 18.9969 30.5 19.2411Z" stroke="#023DFE" stroke-opacity="0.6"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View 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

View File

@ -0,0 +1,14 @@
<svg width="20" height="16" viewBox="0 0 20 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.44697 3.24664C2.55653 1.43525 4.05999 0 5.899 0C7.38201 0 8.64697 0.933692 9.13846 2.2452C10.4156 2.26061 11.4464 3.30004 11.4464 4.58088C11.4464 5.87132 10.4002 6.91747 9.10977 6.91747C8.56961 6.91747 3.06603 6.91747 2.51106 6.91747C1.49695 6.91747 0.674805 6.09532 0.674805 5.08122C0.674805 4.08862 1.46262 3.28051 2.44697 3.24664Z" fill="#F0F5F7"/>
<path d="M11.4458 4.58088C11.4458 5.51442 10.8979 6.32039 10.1063 6.69439C10.2489 6.39211 10.3289 6.05412 10.3289 5.69752C10.3289 4.41669 9.2983 3.3771 8.02113 3.36184C7.52948 2.05019 6.26467 1.11665 4.78151 1.11665C4.11271 1.11665 3.48816 1.30647 2.95898 1.63545C3.56934 0.653539 4.65745 0 5.89846 0C7.38132 0 8.64644 0.93354 9.13777 2.24489C10.4151 2.26045 11.4458 3.30004 11.4458 4.58088Z" fill="#DDE9ED"/>
<path d="M18.0059 7.61715C17.8825 5.57887 16.1907 3.96387 14.1213 3.96387C12.4525 3.96387 11.0291 5.01444 10.476 6.49013C9.03874 6.50753 7.87891 7.67727 7.87891 9.11863C7.87891 10.5708 9.05613 11.7479 10.5082 11.7479H17.9338C19.075 11.7479 20 10.8227 20 9.68168C20 8.56458 19.1136 7.6553 18.0059 7.61715Z" fill="#C4E1E8"/>
<path d="M20.0004 9.68153C20.0004 10.8227 19.0751 11.748 17.9339 11.748H17.7738C17.9237 11.4619 18.0085 11.1363 18.0085 10.7912C18.0085 9.67421 17.1221 8.76478 16.0143 8.72648C15.891 6.68834 14.199 5.07319 12.1297 5.07319C11.8506 5.07319 11.5786 5.10249 11.3164 5.15833C12.0243 4.42209 13.0193 3.96387 14.1216 3.96387C16.191 3.96387 17.8829 5.57872 18.0062 7.61731C19.114 7.65515 20.0004 8.56458 20.0004 9.68153Z" fill="#A4D5DD"/>
<path d="M10.127 7.61715C10.0036 5.57887 8.31183 3.96387 6.24242 3.96387C4.57355 3.96387 3.1502 5.01444 2.59707 6.49013C1.15983 6.50753 0 7.67727 0 9.11863C0 10.5707 1.17722 11.7479 2.62926 11.7479H10.0549C11.1961 11.7479 12.1212 10.8227 12.1212 9.68153C12.1211 8.56458 11.2347 7.6553 10.127 7.61715Z" fill="#C4E1E8"/>
<path d="M12.1215 9.68153C12.1215 10.8227 11.1962 11.748 10.055 11.748H9.89492C10.0448 11.4619 10.1296 11.1363 10.1296 10.7912C10.1296 9.67421 9.24321 8.76478 8.13541 8.72648C8.01212 6.68834 6.32006 5.07319 4.2508 5.07319C3.97171 5.07319 3.69965 5.10249 3.4375 5.15833C4.14536 4.42209 5.14039 3.96387 6.2427 3.96387C8.31211 3.96387 10.004 5.57872 10.1275 7.61731C11.2351 7.65515 12.1215 8.56458 12.1215 9.68153Z" fill="#A4D5DD"/>
<path d="M16.3505 11.2763C16.2272 9.23805 14.5353 7.62305 12.4661 7.62305C10.797 7.62305 9.37368 8.67362 8.82055 10.1493C7.38346 10.1667 6.22363 11.3366 6.22363 12.7778C6.22363 14.23 7.4007 15.4071 8.85289 15.4071H16.2785C17.4195 15.4071 18.3447 14.4819 18.3447 13.3409C18.3447 12.2238 17.4583 11.3145 16.3505 11.2763Z" fill="#F0F5F7"/>
<path d="M18.3453 13.3407C18.3453 14.4819 17.42 15.4072 16.2788 15.4072H16.1187C16.2685 15.1211 16.3534 14.7955 16.3534 14.4503C16.3534 13.3334 15.467 12.424 14.3592 12.3857C14.2359 10.3475 12.5438 8.73237 10.4744 8.73237C10.1953 8.73237 9.92328 8.76167 9.66113 8.81751C10.3691 8.08142 11.3642 7.62305 12.4665 7.62305C14.5359 7.62305 16.2278 9.2379 16.3511 11.2765C17.4589 11.3143 18.3453 12.2238 18.3453 13.3407Z" fill="#DDE9ED"/>
<path d="M15.3204 11.0476C15.1842 11.0476 15.0606 10.9545 15.0273 10.8162C14.9924 10.671 14.9446 10.5277 14.8853 10.3905C14.819 10.2375 14.8894 10.0599 15.0424 9.99364C15.1955 9.92742 15.3731 9.99791 15.4393 10.1508C15.5124 10.3199 15.5712 10.4963 15.6142 10.6751C15.6532 10.8373 15.5533 11.0001 15.3913 11.0392C15.3676 11.0448 15.3438 11.0476 15.3204 11.0476Z" fill="#F0F5F7"/>
<path d="M14.5849 9.70576C14.5055 9.70576 14.4263 9.67463 14.3671 9.61283C13.8645 9.08915 13.1893 8.80076 12.4659 8.80076C12.2993 8.80076 12.1641 8.66571 12.1641 8.49893C12.1641 8.33231 12.2993 8.19727 12.4659 8.19727C13.3552 8.19727 14.1851 8.55158 14.8026 9.19505C14.918 9.31513 14.9142 9.50633 14.7939 9.62168C14.7353 9.67784 14.6601 9.70576 14.5849 9.70576Z" fill="#F0F5F7"/>
<path d="M3.08091 12.4545C3.16911 10.9973 4.37868 9.84277 5.85803 9.84277C7.05128 9.84277 8.06874 10.5938 8.46425 11.6488C9.49179 11.6613 10.321 12.4975 10.321 13.528C10.321 14.5662 9.47943 15.4077 8.44121 15.4077C8.00664 15.4077 3.57912 15.4077 3.13249 15.4077C2.31675 15.4077 1.65527 14.7464 1.65527 13.9305C1.65527 13.132 2.28898 12.4818 3.08091 12.4545Z" fill="#F0F5F7"/>
<path d="M10.3214 13.528C10.3214 14.5572 9.49379 15.3932 8.46762 15.4072C8.77524 15.0723 8.96293 14.6261 8.96293 14.136C8.96293 13.1057 8.13391 12.2694 7.10607 12.2569C6.71071 11.202 5.69325 10.4507 4.49985 10.4507C4.35886 10.4507 4.22046 10.4614 4.08496 10.4817C4.56638 10.0825 5.18437 9.84277 5.8585 9.84277C7.05175 9.84277 8.06921 10.5937 8.46457 11.6488C9.49241 11.6613 10.3214 12.4974 10.3214 13.528Z" fill="#DDE9ED"/>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,6 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.99676 20C15.5178 20 19.9935 15.5228 19.9935 10C19.9935 4.47715 15.5178 0 9.99676 0C4.4757 0 0 4.47715 0 10C0 15.5228 4.4757 20 9.99676 20Z" fill="#00DF76"/>
<path d="M9.99695 0C9.99242 0 9.98793 0.00015623 9.9834 0.00015623V19.9998C9.98793 19.9998 9.99242 20 9.99695 20C15.518 20 19.9937 15.5228 19.9937 9.99996C19.9937 4.4771 15.518 0 9.99695 0Z" fill="#00AB5E"/>
<path d="M4.34516 10.1989L8.38856 14.2423C8.56491 14.4186 8.85085 14.4186 9.02719 14.2423L15.6653 7.60414C15.8417 7.42779 15.8417 7.14185 15.6653 6.96551L14.4571 5.75726C14.2807 5.58091 13.9948 5.58091 13.8184 5.75726L8.99024 10.5854C8.8139 10.7617 8.52796 10.7617 8.35161 10.5854L6.18794 8.42169C6.01507 8.24882 5.736 8.24492 5.55837 8.41286L4.35422 9.55135C4.1694 9.72614 4.1653 10.019 4.34516 10.1989Z" fill="#FFF5F5"/>
<path d="M14.457 5.75726C14.2806 5.58091 13.9947 5.58091 13.8183 5.75726L9.9834 9.59221V13.286L15.6652 7.60418C15.8416 7.42783 15.8416 7.14189 15.6652 6.96551L14.457 5.75726Z" fill="#DFEBF1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,32 @@
<svg width="33" height="319" viewBox="0 0 33 319" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M32.675 6.07198V318.219L30.535 319V5.29102L32.675 6.07198Z" fill="url(#paint0_linear_4847_2158)"/>
<path d="M0.525162 315.619L30.5352 319V5.29102L0.525162 8.68132V315.619Z" fill="url(#paint1_linear_4847_2158)"/>
<path d="M17.9751 0.0722656H13.0851V7.5144C13.0851 8.50669 13.9651 9.31522 15.0451 9.31522H16.0151C17.0951 9.31522 17.9751 8.50669 17.9751 7.5144V0.0722656Z" fill="url(#paint2_linear_4847_2158)"/>
<defs>
<linearGradient id="paint0_linear_4847_2158" x1="82.145" y1="20.5612" x2="-9.30122" y2="323.172" gradientUnits="userSpaceOnUse">
<stop stop-color="#E9E9E9"/>
<stop offset="0.26" stop-color="#E4E4E4"/>
<stop offset="0.51" stop-color="#D8D8D8"/>
<stop offset="0.77" stop-color="#C4C4C4"/>
<stop offset="0.78" stop-color="#C4C4C4"/>
<stop offset="1" stop-color="#C6C6C6"/>
</linearGradient>
<linearGradient id="paint1_linear_4847_2158" x1="30.5352" y1="-18.0001" x2="0.525162" y2="-18.0001" gradientUnits="userSpaceOnUse">
<stop stop-color="#F5F5F5"/>
<stop offset="0.22" stop-color="#F0F0F0"/>
<stop offset="0.45" stop-color="#E4E4E4"/>
<stop offset="0.67" stop-color="#D0D0D0"/>
<stop offset="0.78" stop-color="#C4C4C4"/>
<stop offset="1" stop-color="#C6C6C6"/>
</linearGradient>
<linearGradient id="paint2_linear_4847_2158" x1="17.9751" y1="-18.0002" x2="13.0851" y2="-18.0002" gradientUnits="userSpaceOnUse">
<stop stop-color="#C4C4C4"/>
<stop offset="0.41" stop-color="#F8F8F8"/>
<stop offset="0.49" stop-color="#F0F0F0"/>
<stop offset="0.6" stop-color="#DCDCDC"/>
<stop offset="0.75" stop-color="#BABABA"/>
<stop offset="0.79" stop-color="#AEAEAE"/>
<stop offset="1" stop-color="#BEBEBE"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

10
assets/icons/dry_icon.svg Normal file
View File

@ -0,0 +1,10 @@
<svg width="15" height="20" viewBox="0 0 15 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.4215 9.10771C12.3689 9.09123 11.5782 8.85045 10.6502 8.92217C10.9201 8.37846 11.0308 7.98472 11.0683 7.82656C11.0872 7.76945 11.0968 7.70898 11.094 7.64648C11.0798 7.32902 10.8366 7.06055 10.5081 7.06055C10.2289 7.06055 9.96121 7.28433 9.92629 7.56332C9.86653 7.80531 9.34821 9.62201 6.89781 11.5305C6.6425 11.7294 6.59672 12.0976 6.79558 12.3528C6.91113 12.5012 7.08374 12.5788 7.25823 12.5788C7.38409 12.5788 7.51089 12.5384 7.61788 12.4551C8.51693 11.7548 9.18661 11.0608 9.68446 10.4293C10.6082 9.78853 12.058 10.222 12.0713 10.226C12.3803 10.3229 12.7088 10.1508 12.8055 9.84197C12.9022 9.53314 12.7302 9.20443 12.4215 9.10771Z" fill="#9A4F4F"/>
<path d="M3.78691 3.77187C3.648 3.77187 3.50859 3.72276 3.39683 3.62296C3.15547 3.40737 3.13453 3.03698 3.35008 2.79562C4.12921 1.92312 4.01019 0.788082 4.00878 0.776871C3.96808 0.455817 4.19535 0.162576 4.5164 0.121873C4.83757 0.0813259 5.1307 0.308435 5.17136 0.62945C5.17992 0.696911 5.36757 2.29574 4.22414 3.57616C4.10843 3.70577 3.94796 3.77187 3.78691 3.77187Z" fill="#AD6B5C"/>
<path d="M6.61754 9.15352C3.59093 7.48869 2.50301 5.76597 2.49367 5.75093C2.3259 5.47422 1.96555 5.38601 1.68884 5.55371C1.41212 5.72152 1.32384 6.08187 1.49161 6.35854C1.49681 6.36714 1.51505 6.39671 1.54731 6.4446C1.43454 6.45729 1.32974 6.47679 1.23415 6.50034C0.59416 6.65807 0.174047 7.06815 0.174047 7.06815C0.063657 7.17514 -0.00661577 7.32193 0.000493537 7.48053C0.0147121 7.79798 0.257952 8.06646 0.586425 8.06646C0.739314 8.06646 0.888922 7.99939 0.998804 7.8929C0.998804 7.8929 1.84321 7.16264 3.05808 8.09814C3.76522 8.72696 4.74283 9.45976 6.05274 10.1803C6.14231 10.2296 6.2391 10.253 6.33461 10.253C6.54137 10.253 6.74183 10.1433 6.84855 9.94933C7.00449 9.66578 6.90105 9.30945 6.61754 9.15352Z" fill="#AD6B5C"/>
<path d="M6.21033 12.7834C5.05557 12.4077 4.14369 11.7971 3.50006 10.9684C3.01815 10.348 2.86748 9.82801 2.86748 9.82801C2.79791 9.57785 2.58217 9.38672 2.30518 9.38672C1.9987 9.38672 1.70506 9.65621 1.71924 9.97266C1.72147 10.0225 1.72995 10.0708 1.74288 10.1173C1.74288 10.1173 2.46229 12.7965 5.84779 13.8977C5.90802 13.9173 5.96908 13.9266 6.02916 13.9266C6.27607 13.9266 6.50572 13.7693 6.58623 13.5217C6.68638 13.2141 6.51806 12.8834 6.21033 12.7834Z" fill="#AD6B5C"/>
<path d="M14.776 2.55193C14.5619 2.3092 14.1917 2.28596 13.949 2.49998C13.9474 2.50139 13.7135 2.6592 13.1676 2.79131C12.7467 2.8931 12.1012 2.98927 11.1683 2.98853C11.1605 2.98845 11.1528 2.98814 11.145 2.98814C11.1379 2.98814 11.1306 2.98845 11.1235 2.98853C10.6238 2.9865 10.043 2.95673 9.3713 2.8856C9.04971 2.85205 8.761 3.08482 8.72694 3.40661C8.69287 3.72841 8.92615 4.01692 9.24795 4.05098C9.92298 4.12243 10.5197 4.15473 11.048 4.15899C11.0704 4.16067 11.0931 4.16141 11.1161 4.16051C11.7971 4.13649 12.3037 5.09601 12.3075 5.10363C12.4097 5.31011 12.6173 5.42984 12.8331 5.4298C12.9204 5.4298 13.009 5.41023 13.0926 5.3689C13.3826 5.22535 13.5013 4.87386 13.3578 4.58383C13.3451 4.55813 13.2207 4.3118 12.9909 4.02004C14.1848 3.81403 14.648 3.44599 14.7241 3.37892C14.9668 3.16494 14.99 2.79467 14.776 2.55193Z" fill="#9A4F4F"/>
<path d="M5.20654 3.63366C3.48146 2.44261 1.69537 3.48397 1.69537 3.48397C1.52194 3.58807 1.39741 3.77557 1.40674 3.98397C1.42096 4.30143 1.6642 4.56991 1.99268 4.56991C2.09729 4.56991 2.2001 4.53796 2.28998 4.48397C2.28998 4.48397 3.44389 3.84065 4.54072 4.59795C4.64236 4.66811 4.7583 4.70174 4.8731 4.70174C5.05916 4.70174 5.24209 4.61335 5.3558 4.44866C5.53966 4.18245 5.47287 3.81753 5.20654 3.63366Z" fill="#AD6B5C"/>
<path d="M11.6063 0.0353506C11.3023 -0.0749609 10.966 0.0819126 10.8556 0.386167C10.0675 2.55701 7.52841 4.1516 6.69936 4.62511C5.86987 4.15137 3.33111 2.55689 2.54311 0.386167C2.43268 0.0819517 2.09647 -0.0751171 1.79241 0.0353506C1.48824 0.145779 1.33113 0.48187 1.4416 0.786046C2.35889 3.31294 5.10015 5.06323 6.08374 5.62471L4.93867 19.3654C4.92508 19.5287 4.98047 19.6902 5.0914 19.8108C5.20234 19.9314 5.35871 20 5.52257 20H7.87606C8.03989 20 8.1963 19.9314 8.30723 19.8108C8.41821 19.6902 8.4736 19.5287 8.45996 19.3654L7.3149 5.62471C8.29848 5.06323 11.0397 3.31297 11.957 0.786046C12.0675 0.481831 11.9105 0.145779 11.6063 0.0353506Z" fill="#BE866A"/>
<path d="M7.87597 19.9999C8.03979 19.9999 8.1962 19.9313 8.30713 19.8107C8.41811 19.6901 8.4735 19.5286 8.45987 19.3653L7.3148 5.62465C8.29838 5.06317 11.0396 3.31292 11.9569 0.785988C12.0674 0.481812 11.9103 0.145721 11.6061 0.0352925C11.3021 -0.0750189 10.9658 0.0818546 10.8554 0.386109C10.0674 2.55695 7.52827 4.15154 6.69922 4.62505V19.9999H7.87597Z" fill="#AD6B5C"/>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

135
assets/icons/garageIcon.svg Normal file
View File

@ -0,0 +1,135 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.52252 13.1532H37.4775V39.8199H2.52252V13.1532Z" fill="url(#paint0_linear_4625_5577)"/>
<path d="M2.53027 21.4509H15.0588V39.9999H2.53027V21.4509Z" fill="url(#paint1_linear_4625_5577)"/>
<g clip-path="url(#clip0_4625_5577)">
<path d="M2.53027 20.1802H37.4697V30.8861H2.53027V20.1802Z" fill="url(#paint2_linear_4625_5577)"/>
<path d="M2.5882 12.6127H37.4902V16.7695H2.5882V12.6127Z" fill="url(#paint3_linear_4625_5577)"/>
<path d="M2.5882 15.9067H37.4902V20.0636H2.5882V15.9067Z" fill="url(#paint4_linear_4625_5577)"/>
<path d="M2.5882 19.2793H37.4902V23.4362H2.5882V19.2793Z" fill="url(#paint5_linear_4625_5577)"/>
<path d="M2.5882 22.5226H37.4902V26.6794H2.5882V22.5226Z" fill="url(#paint6_linear_4625_5577)"/>
<path d="M2.5882 25.8167H37.4902V29.9735H2.5882V25.8167Z" fill="url(#paint7_linear_4625_5577)"/>
<path d="M2.5882 29.1892H37.4902V33.3461H2.5882V29.1892Z" fill="url(#paint8_linear_4625_5577)"/>
<path d="M2.5882 32.4834H37.4902V36.6403H2.5882V32.4834Z" fill="url(#paint9_linear_4625_5577)"/>
<path d="M2.5882 35.7775H37.4902V39.9343H2.5882V35.7775Z" fill="url(#paint10_linear_4625_5577)"/>
</g>
<path d="M38.2162 9.93373L23.9216 1.01176C22.8408 0.337255 21.4204 0 20 0C18.5796 0 17.1592 0.337255 16.0784 1.01176L1.78376 9.93373C0.674196 10.6263 0 11.8418 0 13.1498V37.5124C0 38.8863 1.11373 40 2.48761 40C3.19333 40 3.76549 39.4278 3.76549 38.7221V16.6663C3.76549 15.2154 4.94173 14.0392 6.39255 14.0392H33.6075C35.0584 14.0392 36.2345 15.2154 36.2345 16.6663V38.7221C36.2345 39.4278 36.8067 40 37.5124 40C38.8863 40 40 38.8863 40 37.5124V13.1498C40 11.8418 39.3258 10.6263 38.2162 9.93373Z" fill="url(#paint11_linear_4625_5577)"/>
<path d="M38.2162 9.93373L23.9216 1.01177C22.8408 0.337255 21.4204 0 20 0C18.5796 0 17.1592 0.337255 16.0784 1.01177L1.78376 9.93373C0.674196 10.6263 0 11.8418 0 13.1498V16.9144C0 15.6064 0.674196 14.3908 1.78376 13.6983L16.0784 4.77624C17.1592 4.10173 18.5796 3.76447 20 3.76447C21.4204 3.76447 22.8408 4.10173 23.9216 4.77624L38.2162 13.6982C39.3258 14.3908 40 15.6064 40 16.9143V13.1498C40 11.8418 39.3258 10.6263 38.2162 9.93373Z" fill="url(#paint12_linear_4625_5577)"/>
<path d="M15.5309 8.89232H24.4691C24.9752 8.89232 25.3855 8.48205 25.3855 7.97601C25.3855 7.46989 24.9752 7.05969 24.4691 7.05969H15.5309C15.0248 7.05969 14.6146 7.46997 14.6146 7.97601C14.6146 8.48205 15.0248 8.89232 15.5309 8.89232Z" fill="url(#paint13_linear_4625_5577)"/>
<path d="M15.5309 12.2649H24.4691C24.9752 12.2649 25.3855 11.8546 25.3855 11.3486C25.3855 10.8424 24.9752 10.4323 24.4691 10.4323H15.5309C15.0248 10.4323 14.6146 10.8425 14.6146 11.3486C14.6146 11.8546 15.0248 12.2649 15.5309 12.2649Z" fill="url(#paint14_linear_4625_5577)"/>
<path d="M40 16.9145V37.5121C40 38.1992 39.7216 38.8211 39.2714 39.2713C38.8212 39.7215 38.1992 39.9999 37.5122 39.9999C36.8063 39.9999 36.2345 39.4282 36.2345 38.7223V16.6658C36.2345 15.2156 35.058 14.0392 33.6071 14.0392H6.39294C4.94196 14.0392 3.76549 15.2156 3.76549 16.6658V38.7223C3.76549 39.0752 3.62275 39.3945 3.39137 39.6258C3.16 39.8572 2.84078 39.9999 2.48784 39.9999C1.11373 39.9999 0 38.8862 0 37.5121V16.9145C0 15.6062 0.67451 14.3905 1.78353 13.698L16.0784 4.77641C17.1592 4.1019 18.5796 3.76465 20 3.76465C21.4204 3.76465 22.8408 4.1019 23.9216 4.77641L38.2165 13.698C39.3255 14.3905 40 15.6062 40 16.9145Z" fill="url(#paint15_linear_4625_5577)"/>
<path d="M20.0785 1.5697C17.7889 1.5697 15.5693 2.22868 13.6597 3.47551C13.1522 3.80688 13.0093 4.48696 13.3407 4.99449L15.1474 6.8068C15.0804 7.04649 15.112 7.31245 15.2582 7.53755L16.9387 9.24084C16.8755 9.43363 16.8963 9.65206 17.0145 9.83598L18.8084 11.5936C18.6893 12.034 18.8014 12.5241 19.1472 12.8699L20.3165 14.0392H33.6074C35.0583 14.0392 36.2345 15.2154 36.2345 16.6663V29.9572L40 33.7227V16.9851L26.4972 3.47551C24.5877 2.22876 22.3681 1.5697 20.0785 1.5697Z" fill="url(#paint16_linear_4625_5577)"/>
<path d="M22.8539 8.79254C22.0027 8.24564 21.0158 7.95654 20 7.95654C18.9843 7.95654 17.9974 8.24564 17.1461 8.79246C16.8216 9.00101 16.7276 9.43309 16.936 9.75756C17.1445 10.082 17.5766 10.1761 17.9011 9.96768C18.5267 9.5658 19.2525 9.35333 20 9.35333C20.7476 9.35333 21.4734 9.5658 22.0989 9.96768C22.2158 10.0427 22.3465 10.0786 22.4758 10.0786C22.7056 10.0786 22.9306 9.96525 23.064 9.75756C23.2725 9.43317 23.1785 9.00101 22.8539 8.79254Z" fill="url(#paint17_linear_4625_5577)"/>
<path d="M24.5563 6.21705C23.1995 5.3358 21.624 4.87 20 4.87C18.376 4.87 16.8005 5.3358 15.4437 6.21698C15.0278 6.48709 14.9096 7.04325 15.1798 7.45917C15.4499 7.87509 16.0061 7.99321 16.422 7.72309C17.4868 7.03149 18.7241 6.66592 20 6.66592C21.2759 6.66592 22.5133 7.03149 23.578 7.72309C23.7291 7.82121 23.8987 7.86811 24.0663 7.86811C24.3602 7.86811 24.6482 7.72396 24.8202 7.45917C25.0904 7.04325 24.9722 6.48717 24.5563 6.21705Z" fill="url(#paint18_linear_4625_5577)"/>
<path d="M26.4188 3.39709C24.5093 2.15027 22.2897 1.49121 20 1.49121C17.7104 1.49121 15.4908 2.15019 13.5812 3.39702C13.0737 3.72839 12.9308 4.40847 13.2622 4.916C13.5936 5.42353 14.2737 5.56635 14.7812 5.23498C16.333 4.2218 18.1377 3.68627 20 3.68627C21.8624 3.68627 23.667 4.2218 25.2188 5.23505C25.4039 5.35592 25.612 5.41372 25.8178 5.41372C26.1761 5.41372 26.5273 5.23851 26.7378 4.91607C27.0692 4.40854 26.9264 3.72847 26.4188 3.39709Z" fill="url(#paint19_linear_4625_5577)"/>
<path d="M20 13.1773C20.7274 13.1773 21.317 12.5876 21.317 11.8602C21.317 11.1329 20.7274 10.5432 20 10.5432C19.2726 10.5432 18.683 11.1329 18.683 11.8602C18.683 12.5876 19.2726 13.1773 20 13.1773Z" fill="url(#paint20_linear_4625_5577)"/>
<defs>
<linearGradient id="paint0_linear_4625_5577" x1="20" y1="23.2161" x2="20" y2="37.3131" 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_4625_5577" x1="6.90196" y1="30.7254" x2="2.90196" y2="30.7254" 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_4625_5577" x1="20" y1="26.5723" x2="20" y2="21.2385" 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_4625_5577" x1="20.0392" y1="14.1813" x2="20.0392" y2="16.3788" gradientUnits="userSpaceOnUse">
<stop stop-color="#017297"/>
<stop offset="1" stop-color="#024C67"/>
</linearGradient>
<linearGradient id="paint4_linear_4625_5577" x1="20.0392" y1="17.4754" x2="20.0392" y2="19.6729" gradientUnits="userSpaceOnUse">
<stop stop-color="#017297"/>
<stop offset="1" stop-color="#024C67"/>
</linearGradient>
<linearGradient id="paint5_linear_4625_5577" x1="20.0392" y1="20.8479" x2="20.0392" y2="23.0454" gradientUnits="userSpaceOnUse">
<stop stop-color="#017297"/>
<stop offset="1" stop-color="#024C67"/>
</linearGradient>
<linearGradient id="paint6_linear_4625_5577" x1="20.0392" y1="24.0912" x2="20.0392" y2="26.2887" gradientUnits="userSpaceOnUse">
<stop stop-color="#017297"/>
<stop offset="1" stop-color="#024C67"/>
</linearGradient>
<linearGradient id="paint7_linear_4625_5577" x1="20.0392" y1="27.3853" x2="20.0392" y2="29.5828" gradientUnits="userSpaceOnUse">
<stop stop-color="#017297"/>
<stop offset="1" stop-color="#024C67"/>
</linearGradient>
<linearGradient id="paint8_linear_4625_5577" x1="20.0392" y1="30.7578" x2="20.0392" y2="32.9553" gradientUnits="userSpaceOnUse">
<stop stop-color="#017297"/>
<stop offset="1" stop-color="#024C67"/>
</linearGradient>
<linearGradient id="paint9_linear_4625_5577" x1="20.0392" y1="34.052" x2="20.0392" y2="36.2495" gradientUnits="userSpaceOnUse">
<stop stop-color="#017297"/>
<stop offset="1" stop-color="#024C67"/>
</linearGradient>
<linearGradient id="paint10_linear_4625_5577" x1="20.0392" y1="37.3461" x2="20.0392" y2="39.5436" gradientUnits="userSpaceOnUse">
<stop stop-color="#017297"/>
<stop offset="1" stop-color="#024C67"/>
</linearGradient>
<linearGradient id="paint11_linear_4625_5577" x1="9.048" y1="5.64996" x2="27.7147" y2="38.9049" gradientUnits="userSpaceOnUse">
<stop stop-color="#EAF9FA"/>
<stop offset="1" stop-color="#B3DAFE"/>
</linearGradient>
<linearGradient id="paint12_linear_4625_5577" x1="20" y1="-5.80283" x2="20" y2="17.6317" gradientUnits="userSpaceOnUse">
<stop stop-color="#7BACDF" stop-opacity="0"/>
<stop offset="1" stop-color="#7BACDF"/>
</linearGradient>
<linearGradient id="paint13_linear_4625_5577" x1="20" y1="8.64785" x2="20" y2="6.96024" gradientUnits="userSpaceOnUse">
<stop stop-color="#EAF9FA"/>
<stop offset="1" stop-color="#B3DAFE"/>
</linearGradient>
<linearGradient id="paint14_linear_4625_5577" x1="20" y1="12.0204" x2="20" y2="10.3328" gradientUnits="userSpaceOnUse">
<stop stop-color="#EAF9FA"/>
<stop offset="1" stop-color="#B3DAFE"/>
</linearGradient>
<linearGradient id="paint15_linear_4625_5577" x1="13.8244" y1="14.8416" x2="10.2165" y2="7.70434" gradientUnits="userSpaceOnUse">
<stop stop-color="#7BACDF" stop-opacity="0"/>
<stop offset="1" stop-color="#7BACDF"/>
</linearGradient>
<linearGradient id="paint16_linear_4625_5577" x1="30.1222" y1="15.7451" x2="18.9065" y2="0.294096" gradientUnits="userSpaceOnUse">
<stop stop-color="#7BACDF" stop-opacity="0"/>
<stop offset="1" stop-color="#7BACDF"/>
</linearGradient>
<linearGradient id="paint17_linear_4625_5577" x1="19.4383" y1="7.77317" x2="20.3961" y2="10.5136" 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_4625_5577" x1="19.1947" y1="4.04396" x2="20.2856" y2="8.00827" 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_4625_5577" x1="19.157" y1="1.23215" x2="20.3277" y2="5.51576" 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_4625_5577" x1="18.7229" y1="10.5831" x2="20.8381" y2="12.6984" 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_4625_5577">
<rect width="34.9599" height="27.3217" fill="white" transform="translate(2.53027 12.6127)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View 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

View 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

View 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

View File

@ -0,0 +1,9 @@
<svg width="20" height="18" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.8441 3.32657C15.4204 3.32657 14.9979 3.39203 14.5952 3.51852C14.2801 2.62024 13.7254 1.81458 12.9921 1.20255C12.0627 0.427094 10.8871 0 9.68155 0C7.00439 0 4.79218 2.05658 4.50089 4.6936H3.42758C1.53763 4.69376 0 6.25137 0 8.16605C0 10.0807 1.53763 11.6383 3.42758 11.6383H15.9355C16.2102 11.6383 16.4848 11.6048 16.7523 11.5384C17.6587 11.3362 18.4818 10.8263 19.0706 10.1021C19.67 9.36462 20 8.43445 20 7.4826C20 5.19089 18.1357 3.32657 15.8441 3.32657Z" fill="#DEFAFA"/>
<path d="M15.8442 3.32657C15.4205 3.32657 14.998 3.39203 14.5953 3.51852C14.2802 2.62024 13.7255 1.81458 12.9922 1.20255C12.0628 0.427094 10.8872 0 9.68164 0V11.6383H15.9356C16.2101 11.6383 16.4849 11.6046 16.7524 11.5384C17.6588 11.3361 18.4818 10.8263 19.0705 10.1019C19.67 9.36462 20.0001 8.4343 20.0001 7.48245C20.0001 5.19089 18.1358 3.32657 15.8442 3.32657Z" fill="#B5EFFF"/>
<path d="M12.8419 5.28036H11.6572C11.6572 4.19104 10.771 3.30481 9.68164 3.30481V2.12012C11.4242 2.12012 12.8419 3.53781 12.8419 5.28036Z" fill="#80DBFF"/>
<path d="M2.49023 13.3135H17.3099V14.498H2.49023V13.3135Z" fill="#B5EFFF"/>
<path d="M2.49023 16.0059H17.3099V17.1906H2.49023V16.0059Z" fill="#B5EFFF"/>
<path d="M9.68164 16.0059H17.3101V17.1906H9.68164V16.0059Z" fill="#80DBFF"/>
<path d="M9.68164 13.3135H17.3101V14.498H9.68164V13.3135Z" fill="#80DBFF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="7.5" cy="7.5" r="5" stroke="#FF4756" stroke-width="5"/>
</svg>

After

Width:  |  Height:  |  Size: 171 B

View File

@ -0,0 +1,3 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="7.5" cy="7.5" r="5" stroke="#023DFE" stroke-opacity="0.6" stroke-width="5"/>
</svg>

After

Width:  |  Height:  |  Size: 192 B

View File

@ -0,0 +1,4 @@
<svg width="15" height="20" viewBox="0 0 15 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.3259 0.768152C6.06762 1.05318 0 7.80822 0 12.978C0 16.8499 3.15008 20 7.02203 20L8.59528 12.4218L7.02209 0L6.3259 0.768152Z" fill="#A7EAF9"/>
<path d="M7.71761 0.768152L7.02148 0V20C10.8934 20 14.0435 16.8499 14.0435 12.978C14.0435 7.80822 7.9759 1.05318 7.71761 0.768152Z" fill="#72BBFF"/>
</svg>

After

Width:  |  Height:  |  Size: 406 B

View File

@ -0,0 +1,27 @@
<svg width="290" height="290" viewBox="0 0 290 290" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_4096_940)">
<rect x="20" y="20" width="250" height="250" rx="100" fill="#EDEDED"/>
<path d="M188.067 144.007C188.067 169.96 167.01 191 141.034 191C115.058 191 94 169.96 94 144.007C94 121.065 130.751 80.7942 139.281 71.7567C140.233 70.7478 141.835 70.7478 142.787 71.7567C151.317 80.7945 188.067 121.065 188.067 144.007Z" fill="#B3DAFE"/>
<path d="M142.787 71.7567C141.835 70.7478 140.233 70.7478 139.281 71.7567C138.759 72.3096 138.13 72.9809 137.412 73.7562C148.433 85.6575 180.824 122.468 180.824 144.006C180.824 168.743 161.696 189.015 137.412 190.862C138.607 190.953 139.815 191 141.034 191C167.01 191 188.068 169.96 188.068 144.006C188.068 121.065 151.317 80.7945 142.787 71.7567Z" fill="#8AC9FE"/>
<path d="M187.944 147.412C174.836 141.859 160.63 142.943 123.956 150.612C115.699 152.338 106.251 154.41 95.7856 156.876C101.386 176.573 119.524 191 141.034 191C165.864 191 186.197 171.776 187.944 147.412Z" fill="#60B7FF"/>
<path d="M171.214 128.586C184.882 128.586 195.962 117.506 195.962 103.837C195.962 90.1692 184.882 79.0889 171.214 79.0889C157.545 79.0889 146.465 90.1692 146.465 103.837C146.465 117.506 157.545 128.586 171.214 128.586Z" fill="#97D729"/>
<path d="M171.312 79.057C170.081 79.057 168.872 79.1482 167.69 79.3219C179.626 81.0743 188.79 91.356 188.79 103.779C188.79 116.202 179.626 126.484 167.69 128.236C168.872 128.41 170.081 128.501 171.312 128.501C184.965 128.501 196.034 117.433 196.034 103.779C196.034 90.1253 184.965 79.057 171.312 79.057Z" fill="#8BC727"/>
<path d="M168.515 114.479C167.115 114.479 165.798 113.933 164.808 112.943L157.249 105.383C155.713 103.848 155.713 101.359 157.249 99.8238C158.784 98.2886 161.273 98.2881 162.808 99.8238L168.515 105.531L179.816 94.2307C181.351 92.6955 183.84 92.6955 185.375 94.2307C186.911 95.7658 186.911 98.2551 185.375 99.79L172.222 112.943C171.232 113.934 169.915 114.479 168.515 114.479Z" fill="#F9F7F8"/>
<path d="M187.944 147.39C185.707 146.442 183.227 145.694 180.811 145.145C180.706 149.723 179.999 154.036 178.64 158.186L184.447 162.112C185.371 159.949 186.219 157.298 186.921 154.209C187.492 151.698 187.795 149.396 187.944 147.39Z" fill="#26A6FE"/>
<path d="M158.594 154.258C134.004 150.208 121.183 134.478 95.1665 136.178C94.4172 138.944 94 141.573 94 144.007C94 169.96 115.058 191 141.034 191C163.857 191 182.881 174.757 187.163 153.21C175.527 155.808 166.006 155.478 158.594 154.258Z" fill="#0593FC"/>
<path d="M179.633 154.541C175.105 174.288 158.13 189.291 137.395 190.861C138.596 190.953 139.809 191 141.034 191C163.857 191 182.881 174.757 187.163 153.21C184.546 153.794 182.036 154.229 179.633 154.541Z" fill="#0182FC"/>
<path d="M119.354 205.825H122.193V219H119.495L113.571 210.809V219H110.732V205.825H113.431L119.354 214.034V205.825ZM133.602 217.646C132.57 218.684 131.27 219.202 129.699 219.202C128.129 219.202 126.828 218.684 125.797 217.646C124.766 216.604 124.25 215.347 124.25 213.876C124.25 212.405 124.766 211.154 125.797 210.123C126.822 209.098 128.123 208.585 129.699 208.585C131.275 208.585 132.576 209.098 133.602 210.123C134.633 211.154 135.148 212.405 135.148 213.876C135.148 215.347 134.633 216.604 133.602 217.646ZM129.69 211.046V211.055C128.876 211.055 128.223 211.321 127.73 211.854C127.238 212.388 126.992 213.067 126.992 213.894C126.992 214.708 127.238 215.388 127.73 215.933C128.223 216.478 128.876 216.75 129.69 216.75C130.517 216.75 131.176 216.48 131.668 215.941C132.16 215.402 132.406 214.72 132.406 213.894C132.406 213.067 132.16 212.385 131.668 211.846C131.176 211.312 130.517 211.046 129.69 211.046ZM139.815 210.844V210.835C140.694 209.394 141.948 208.673 143.577 208.673V211.573H143.252C142.262 211.573 141.441 211.846 140.791 212.391C140.141 212.936 139.815 213.832 139.815 215.08V219H137.073V208.796H139.815V210.844ZM158.141 208.611H158.149C159.251 208.611 160.136 208.995 160.804 209.763C161.472 210.524 161.806 211.559 161.806 212.865V219H159.072V213.226C159.072 212.563 158.888 212.039 158.519 211.652C158.149 211.266 157.66 211.072 157.051 211.072C156.465 211.072 155.964 211.292 155.548 211.731C155.138 212.165 154.933 212.728 154.933 213.419V219H152.199V213.261C152.199 212.581 152.015 212.048 151.646 211.661C151.276 211.274 150.799 211.081 150.213 211.081C149.604 211.081 149.094 211.327 148.684 211.819C148.273 212.306 148.068 212.851 148.068 213.454V219H145.326V208.796H148.068V210.237C149.053 209.159 150.131 208.614 151.303 208.603C151.994 208.603 152.609 208.77 153.148 209.104C153.688 209.438 154.115 209.903 154.432 210.501C155.539 209.241 156.775 208.611 158.141 208.611ZM170.621 219L170.604 217.84C169.959 218.742 168.913 219.19 167.466 219.185C166.294 219.185 165.359 218.909 164.662 218.358C163.959 217.802 163.607 217.017 163.607 216.003C163.607 214.972 164.023 214.166 164.855 213.586C165.688 213.006 166.663 212.716 167.782 212.716C168.702 212.716 169.616 212.848 170.524 213.111C170.56 211.635 169.798 210.896 168.239 210.896C167.618 210.896 166.982 210.976 166.332 211.134C165.682 211.292 165.172 211.459 164.803 211.635L164.135 209.64C165.594 208.942 167.094 208.594 168.635 208.594C170.217 208.594 171.386 208.98 172.142 209.754C172.897 210.527 173.275 211.702 173.275 213.278V219H170.621ZM168.248 217.225L168.239 217.233C168.884 217.233 169.429 217.078 169.874 216.768C170.313 216.463 170.533 216.018 170.533 215.432V214.755C169.889 214.526 169.203 214.412 168.477 214.412C167.867 214.412 167.357 214.535 166.947 214.781C166.537 215.027 166.332 215.37 166.332 215.81C166.332 216.243 166.514 216.589 166.877 216.847C167.234 217.099 167.691 217.225 168.248 217.225ZM175.657 219V205.034H178.399V219H175.657Z" fill="#0593FC"/>
</g>
<defs>
<filter id="filter0_d_4096_940" 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_4096_940"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4096_940" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View 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

View File

@ -0,0 +1,23 @@
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.5125 10.8906C11.3376 11.2934 10.9552 11.4076 10.6094 11.2579C10.2637 11.1081 10.0857 10.7512 10.2605 10.3484C10.3993 10.0284 10.9923 9.74323 11.2303 9.63948C11.2848 9.61573 11.3475 9.64287 11.3674 9.69881C11.4542 9.9433 11.6513 10.5706 11.5125 10.8906Z" fill="#62DBFB"/>
<path d="M16.7195 6.23104C16.6435 6.23104 16.5683 6.23409 16.4937 6.23936C16.4563 6.24202 16.4245 6.2137 16.4227 6.17628C16.3346 4.43218 14.8946 3.04495 13.1299 3.04495C12.9606 3.04495 12.7946 3.05843 12.6323 3.0832C12.5973 3.08855 12.564 3.06824 12.5527 3.03468C11.9613 1.27086 10.2964 0 8.33467 0C5.8778 0 3.93206 1.99355 3.88616 4.45171C3.88573 4.47378 3.88874 4.49065 3.8721 4.4937C2.85863 4.70288 2.11121 5.59784 2.11121 6.67401C2.11121 6.8626 2.13504 7.04557 2.17918 7.22049C2.18453 7.2417 2.17171 7.2628 2.15046 7.26788C0.917303 7.56147 0 8.67018 0 9.99393C0 11.5419 1.25398 12.7968 2.80081 12.7968H16.7195C18.5313 12.7968 20 11.327 20 9.51393C20 7.70088 18.5312 6.23104 16.7195 6.23104Z" fill="#EAF9FA"/>
<path d="M7.80371 8.20881C7.80371 8.20881 10.4632 6.20752 13.3548 8.98549C13.4109 9.03935 13.5034 8.989 13.4883 8.91271C13.3508 8.21631 12.3918 6.17045 9.99968 6.3985C8.33789 6.5569 7.80371 8.20881 7.80371 8.20881Z" fill="#D4F2F6"/>
<path d="M16.7197 6.23104C16.6438 6.23104 16.5686 6.23409 16.494 6.23936C16.4566 6.24202 16.4248 6.2137 16.4229 6.17628C16.3349 4.43218 14.8949 3.04495 13.1302 3.04495C12.9609 3.04495 12.7949 3.05843 12.6326 3.0832C12.5976 3.08855 12.5642 3.06824 12.553 3.03468C11.9616 1.27086 10.2967 0 8.33496 0C7.84207 0 7.36793 0.0803904 6.9248 0.228515C6.92805 0.228515 6.93129 0.228398 6.93453 0.228398C8.91781 0.228398 11.2847 1.44547 11.6892 3.89534C11.8033 4.44554 12.6123 4.75683 12.7835 4.83999C12.8574 4.54843 12.8822 4.1237 12.7835 3.56316C14.0744 3.61378 15.334 5.98053 15.1079 6.65417C15.6208 6.39842 15.8063 6.33323 15.9055 6.33323C17.7173 6.33323 18.5999 7.92924 18.5999 9.74228C18.5999 11.1306 17.7383 12.3168 16.5213 12.7968H16.7198C18.5316 12.7968 20.0003 11.327 20.0003 9.51393C20.0003 7.70088 18.5315 6.23104 16.7197 6.23104Z" fill="#D4F2F6"/>
<path d="M5.34296 8.88222C5.30507 8.89863 5.26562 8.90644 5.22695 8.90644C5.11367 8.90644 5.00546 8.84003 4.95781 8.72949C4.56015 7.80996 3.65625 7.21582 2.65508 7.21582C2.48711 7.21582 2.31992 7.23223 2.15703 7.26504C2.17422 7.25762 2.18398 7.23848 2.1793 7.21973C2.13555 7.0459 2.11172 6.86465 2.11133 6.67754C2.29023 6.6459 2.47227 6.62988 2.65508 6.62988C3.88984 6.62988 5.00507 7.36269 5.4957 8.49707C5.55976 8.6455 5.4914 8.81777 5.34296 8.88222Z" fill="#CBE5E8"/>
<path d="M16.4858 6.23848C15.9436 6.28926 15.4307 6.48457 14.9909 6.81035C14.9397 6.84824 14.8807 6.86699 14.8218 6.86816C14.7304 6.86972 14.6397 6.82871 14.5811 6.74941C14.4847 6.61933 14.512 6.43613 14.6421 6.33965C15.1487 5.96426 15.7358 5.7334 16.3565 5.66309C16.3917 5.82988 16.4139 6.00098 16.4229 6.17598C16.4249 6.21074 16.4526 6.2373 16.4858 6.23848Z" fill="#CBE5E8"/>
<path d="M13.3189 4.24941C13.3189 4.41113 13.3107 4.57441 13.2943 4.73418C13.2791 4.88496 13.1518 4.99746 13.0033 4.99746C12.9936 4.99746 12.9834 4.99707 12.9732 4.99589C12.8123 4.97949 12.6951 4.83574 12.7115 4.6748C12.7256 4.53457 12.733 4.3916 12.733 4.24941C12.733 3.82637 12.6701 3.41113 12.5459 3.0127C12.5486 3.01973 12.551 3.02715 12.5533 3.03418C12.5646 3.06777 12.5979 3.08809 12.633 3.08301C12.7955 3.05801 12.9615 3.04473 13.1307 3.04473C13.142 3.04473 13.1533 3.04473 13.1646 3.04512C13.2674 3.43613 13.3189 3.83926 13.3189 4.24941Z" fill="#CBE5E8"/>
<path d="M3.86211 5.94746C3.83398 5.95566 3.80586 5.95957 3.77773 5.95957C3.65195 5.95957 3.53516 5.87754 3.49727 5.75058C3.39453 5.40683 3.33125 5.05176 3.30859 4.69199C3.48359 4.60176 3.67266 4.53418 3.87187 4.49316C3.8832 4.49082 3.88555 4.48223 3.88555 4.46973C3.89297 4.84863 3.95117 5.22246 4.05859 5.58262C4.10508 5.73769 4.01719 5.90097 3.86211 5.94746Z" fill="#CBE5E8"/>
<path d="M12.7671 7.16537C12.3661 6.70646 11.8424 6.37838 11.2526 6.2165C10.4528 5.99697 9.61537 6.10236 8.89479 6.5131C8.17416 6.92384 7.65655 7.59076 7.43725 8.39107C7.39448 8.54712 7.48635 8.70829 7.64237 8.75103C7.6683 8.75814 7.69436 8.76154 7.71995 8.76154C7.84869 8.76154 7.96666 8.67607 8.00233 8.54591C8.1803 7.89654 8.60026 7.35537 9.1849 7.02216C9.76951 6.689 10.4487 6.60353 11.0975 6.78154C11.576 6.91287 12.0008 7.17892 12.3259 7.55091C12.4324 7.67283 12.6174 7.68521 12.7393 7.57873C12.8611 7.47224 12.8736 7.2872 12.7671 7.16537Z" fill="#CBE5E8"/>
<path d="M4.05227 15.6521C3.90973 15.5755 3.73211 15.6292 3.65563 15.7717L3.25364 16.5208C3.17712 16.6634 3.23067 16.841 3.37325 16.9175C3.41731 16.9412 3.46477 16.9524 3.51149 16.9524C3.61598 16.9524 3.71708 16.8964 3.76989 16.7979L4.17188 16.0488C4.24844 15.9062 4.19489 15.7286 4.05227 15.6521Z" fill="#62DBFB"/>
<path d="M5.01707 13.8259C4.87442 13.7494 4.69692 13.803 4.62043 13.9455L4.21848 14.6947C4.14196 14.8373 4.19551 15.0148 4.33809 15.0914C4.38219 15.115 4.42961 15.1262 4.47633 15.1262C4.58083 15.1262 4.68192 15.0702 4.73473 14.9717L5.13668 14.2226C5.21321 14.08 5.15965 13.9024 5.01707 13.8259Z" fill="#62DBFB"/>
<path d="M5.89309 15.6521C5.75059 15.5755 5.57293 15.6292 5.49645 15.7717L5.09446 16.5208C5.01794 16.6634 5.07149 16.841 5.21407 16.9175C5.25813 16.9412 5.30559 16.9524 5.35231 16.9524C5.4568 16.9524 5.5579 16.8964 5.61071 16.7979L6.0127 16.0488C6.08926 15.9062 6.03567 15.7286 5.89309 15.6521Z" fill="#62DBFB"/>
<path d="M6.85793 13.8259C6.71543 13.7493 6.53778 13.803 6.46129 13.9455L6.0593 14.6947C5.98278 14.8372 6.03633 15.0148 6.17891 15.0913C6.22297 15.115 6.27043 15.1262 6.31715 15.1262C6.42165 15.1262 6.52274 15.0702 6.57555 14.9717L6.97754 14.2226C7.05411 14.08 7.00055 13.9024 6.85793 13.8259Z" fill="#62DBFB"/>
<path d="M7.73485 15.652C7.59223 15.5756 7.41469 15.6292 7.33821 15.7717L6.93626 16.5208C6.85973 16.6634 6.91329 16.841 7.05586 16.9175C7.09997 16.9411 7.14739 16.9524 7.19411 16.9524C7.2986 16.9524 7.39969 16.8964 7.4525 16.7979L7.85446 16.0487C7.93098 15.9061 7.87743 15.7286 7.73485 15.652Z" fill="#62DBFB"/>
<path d="M8.69969 13.8259C8.55704 13.7494 8.37954 13.803 8.30305 13.9455L7.9011 14.6947C7.82458 14.8373 7.87813 15.0148 8.02071 15.0914C8.06481 15.115 8.11223 15.1262 8.15895 15.1262C8.26344 15.1262 8.36454 15.0702 8.41735 14.9717L8.8193 14.2226C8.89586 14.08 8.84231 13.9024 8.69969 13.8259Z" fill="#62DBFB"/>
<path d="M9.57571 15.6521C9.43317 15.5755 9.25555 15.6292 9.17907 15.7717L8.77708 16.5208C8.70055 16.6634 8.75411 16.841 8.89669 16.9175C8.94075 16.9412 8.98821 16.9524 9.03493 16.9524C9.13942 16.9524 9.24051 16.8964 9.29332 16.7979L9.69532 16.0488C9.77184 15.9062 9.71828 15.7286 9.57571 15.6521Z" fill="#62DBFB"/>
<path d="M10.5405 13.8259C10.3979 13.7494 10.2204 13.803 10.1439 13.9455L9.74192 14.6947C9.6654 14.8373 9.71895 15.0148 9.86153 15.0914C9.90563 15.115 9.95305 15.1262 9.99977 15.1262C10.1043 15.1262 10.2054 15.0702 10.2582 14.9717L10.6601 14.2226C10.7366 14.08 10.6831 13.9024 10.5405 13.8259Z" fill="#62DBFB"/>
<path d="M11.4165 15.652C11.2739 15.5756 11.0963 15.6292 11.0198 15.7717L10.6179 16.5208C10.5414 16.6634 10.5949 16.841 10.7375 16.9175C10.7816 16.9411 10.829 16.9524 10.8757 16.9524C10.9802 16.9524 11.0813 16.8964 11.1341 16.7979L11.5361 16.0487C11.6127 15.9061 11.5591 15.7286 11.4165 15.652Z" fill="#62DBFB"/>
<path d="M12.3814 13.8259C12.2389 13.7493 12.0612 13.803 11.9847 13.9455L11.5827 14.6947C11.5062 14.8372 11.5598 15.0148 11.7023 15.0913C11.7464 15.115 11.7939 15.1262 11.8406 15.1262C11.9451 15.1262 12.0462 15.0702 12.099 14.9717L12.501 14.2226C12.5775 14.08 12.5239 13.9024 12.3814 13.8259Z" fill="#62DBFB"/>
<path d="M8.03101 12.9297C7.8562 13.3325 7.47374 13.4467 7.128 13.2969C6.78226 13.1472 6.60421 12.7903 6.77902 12.3875C6.91788 12.0675 7.51089 11.7823 7.7489 11.6785C7.80335 11.6548 7.86605 11.6819 7.88593 11.7379C7.9728 11.9823 8.16987 12.6097 8.03101 12.9297Z" fill="#62DBFB"/>
<path d="M14.8103 15.7187C14.6355 16.1215 14.253 16.2357 13.9073 16.086C13.5616 15.9363 13.3835 15.5794 13.5583 15.1765C13.6972 14.8565 14.2902 14.5714 14.5282 14.4676C14.5826 14.4439 14.6453 14.471 14.6652 14.5269C14.7521 14.7714 14.9492 15.3987 14.8103 15.7187Z" fill="#62DBFB"/>
</svg>

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.37318 13.8499C-0.790913 10.6858 -0.79085 5.53728 2.37318 2.37312C5.53734 -0.79104 10.6858 -0.79104 13.8499 2.37312C16.5342 5.05748 16.9408 9.0498 15.0706 12.1674C15.0706 12.1674 14.9363 12.3928 15.1177 12.5741C16.1527 13.609 19.2581 16.7144 19.2581 16.7144C20.0822 17.5385 20.2784 18.6908 19.5476 19.4217L19.4217 19.5474C18.6909 20.2784 17.5385 20.0823 16.7145 19.2581C16.7145 19.2581 13.6157 16.1593 12.5828 15.1265C12.3927 14.9363 12.1674 15.0707 12.1674 15.0707C9.04987 16.9408 5.05754 16.5343 2.37318 13.8499ZM12.3516 12.3516C14.6896 10.0137 14.6896 6.20953 12.3516 3.87154C10.0136 1.53361 6.20946 1.53355 3.87154 3.87154C1.53355 6.20946 1.53355 10.0137 3.87154 12.3516C6.20953 14.6895 10.0136 14.6895 12.3516 12.3516Z" fill="#999999" fill-opacity="0.3"/>
<path d="M11.8337 7.62992C11.9425 7.62992 12.0531 7.60853 12.1598 7.56349C12.5857 7.38322 12.785 6.89176 12.6047 6.46576C11.4717 3.78817 8.37155 2.53161 5.69403 3.66465C5.26809 3.84493 5.06881 4.33639 5.24908 4.76239C5.42942 5.18839 5.92075 5.38754 6.34688 5.20734C8.1737 4.43432 10.289 5.29167 11.062 7.11849C11.1972 7.43799 11.5074 7.62992 11.8337 7.62992Z" fill="#999999" fill-opacity="0.3"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,24 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.77584 12.0301C3.64982 11.904 3.44568 11.904 3.31971 12.0301L3.22521 12.1246L3.13072 12.0301C3.00471 11.904 2.80057 11.904 2.67459 12.0301C2.54861 12.1561 2.54857 12.3602 2.67459 12.4862L2.76908 12.5807L2.67459 12.6752C2.54857 12.8012 2.54857 13.0053 2.67459 13.1313C2.7376 13.1943 2.82014 13.2258 2.90268 13.2258C2.98521 13.2258 3.06775 13.1943 3.13076 13.1313L3.22525 13.0368L3.31971 13.1313C3.38271 13.1944 3.46525 13.2258 3.54779 13.2258C3.63033 13.2258 3.71287 13.1944 3.77588 13.1313C3.90189 13.0053 3.90189 12.8012 3.77588 12.6752L3.68139 12.5807L3.77588 12.4862C3.90186 12.3602 3.90186 12.1561 3.77584 12.0301Z" fill="#C3DDFF"/>
<path d="M7.00244 16.5467C6.87643 16.4206 6.67228 16.4206 6.54631 16.5467L6.45178 16.6412L6.35729 16.5467C6.23127 16.4206 6.02713 16.4206 5.90115 16.5467C5.77514 16.6727 5.77514 16.8768 5.90115 17.0028L5.99564 17.0973L5.90115 17.1918C5.77514 17.3178 5.77514 17.5219 5.90115 17.6479C5.96416 17.7109 6.0467 17.7424 6.12924 17.7424C6.21178 17.7424 6.29432 17.7109 6.35732 17.6479L6.45182 17.5534L6.54631 17.6479C6.60932 17.7109 6.69186 17.7424 6.77439 17.7424C6.85693 17.7424 6.93947 17.7109 7.00248 17.6479C7.1285 17.5219 7.1285 17.3178 7.00248 17.1918L6.90799 17.0973L7.00248 17.0028C7.12846 16.8768 7.12846 16.6726 7.00244 16.5467Z" fill="#C3DDFF"/>
<path d="M5.16109 14.5159C5.16109 14.3378 5.0168 14.1934 4.83852 14.1934C4.6602 14.1934 4.51594 14.3378 4.51594 14.5159C4.33762 14.5159 4.19336 14.6604 4.19336 14.8385C4.19336 15.0166 4.33766 15.1611 4.51594 15.1611C4.51594 15.3392 4.66023 15.4837 4.83852 15.4837C5.01684 15.4837 5.16109 15.3392 5.16109 15.1611C5.33941 15.1611 5.48367 15.0166 5.48367 14.8385C5.48367 14.6604 5.33941 14.5159 5.16109 14.5159Z" fill="#DBEAFF"/>
<path d="M8.38766 19.0325C8.38766 18.8544 8.24336 18.71 8.06508 18.71C7.8868 18.71 7.7425 18.8544 7.7425 19.0325C7.56418 19.0325 7.41992 19.177 7.41992 19.3551C7.41992 19.5332 7.56422 19.6777 7.7425 19.6777C7.7425 19.8558 7.8868 20.0003 8.06508 20.0003C8.24336 20.0003 8.38766 19.8558 8.38766 19.6777C8.56598 19.6777 8.71023 19.5332 8.71023 19.3551C8.71023 19.177 8.56594 19.0325 8.38766 19.0325Z" fill="#DBEAFF"/>
<path d="M7.09664 12.2581C7.09664 12.08 6.95234 11.9355 6.77406 11.9355C6.59578 11.9355 6.45148 12.08 6.45148 12.2581C6.27316 12.2581 6.12891 12.4026 6.12891 12.5807C6.12891 12.7588 6.2732 12.9033 6.45148 12.9033C6.45148 13.0814 6.59578 13.2259 6.77406 13.2259C6.95234 13.2259 7.09664 13.0814 7.09664 12.9033C7.27496 12.9033 7.41922 12.7588 7.41922 12.5807C7.41922 12.4026 7.27496 12.2581 7.09664 12.2581Z" fill="#DBEAFF"/>
<path d="M8.93795 14.2879C8.81193 14.1619 8.60779 14.1619 8.48182 14.2879L8.38732 14.3824L8.29283 14.2879C8.16682 14.1619 7.96268 14.1619 7.8367 14.2879C7.71068 14.4139 7.71068 14.618 7.8367 14.744L7.93119 14.8385L7.8367 14.933C7.71068 15.059 7.71068 15.2631 7.8367 15.3891C7.89971 15.4521 7.98225 15.4836 8.06479 15.4836C8.14732 15.4836 8.22986 15.4521 8.29287 15.3891L8.38736 15.2946L8.48186 15.3891C8.54486 15.4521 8.6274 15.4836 8.70994 15.4836C8.79248 15.4836 8.87502 15.4521 8.93803 15.3891C9.06404 15.2631 9.06404 15.059 8.93803 14.933L8.84354 14.8385L8.93803 14.744C9.06396 14.618 9.06396 14.4139 8.93795 14.2879Z" fill="#C3DDFF"/>
<path d="M10.3222 16.7737C10.3222 16.5956 10.1779 16.4512 9.99965 16.4512C9.82137 16.4512 9.67707 16.5956 9.67707 16.7737C9.49875 16.7737 9.35449 16.9182 9.35449 17.0963C9.35449 17.2745 9.49879 17.4189 9.67707 17.4189C9.67707 17.597 9.82137 17.7415 9.99965 17.7415C10.1779 17.7415 10.3222 17.597 10.3222 17.4189C10.5005 17.4189 10.6448 17.2745 10.6448 17.0963C10.6448 16.9182 10.5005 16.7737 10.3222 16.7737Z" fill="#DBEAFF"/>
<path d="M12.1635 18.8045C12.0375 18.6785 11.8334 18.6785 11.7074 18.8045L11.6129 18.899L11.5184 18.8045C11.3924 18.6785 11.1883 18.6785 11.0623 18.8045C10.9363 18.9305 10.9363 19.1346 11.0623 19.2606L11.1568 19.3551L11.0623 19.4496C10.9363 19.5756 10.9363 19.7797 11.0623 19.9057C11.1253 19.9687 11.2078 20.0002 11.2904 20.0002C11.3729 20.0002 11.4554 19.9687 11.5185 19.9057L11.6129 19.8112L11.7074 19.9057C11.7704 19.9687 11.853 20.0002 11.9355 20.0002C12.0181 20.0002 12.1006 19.9687 12.1636 19.9057C12.2896 19.7797 12.2896 19.5756 12.1636 19.4496L12.0691 19.3551L12.1636 19.2606C12.2896 19.1346 12.2896 18.9305 12.1635 18.8045Z" fill="#C3DDFF"/>
<path d="M10.8735 12.6752L10.779 12.5807L10.8735 12.4862C10.9995 12.3602 10.9995 12.156 10.8735 12.0301C10.7475 11.904 10.5433 11.904 10.4174 12.0301L10.3229 12.1246L10.2284 12.0301C10.1024 11.904 9.89822 11.904 9.77225 12.0301C9.64623 12.1561 9.64623 12.3602 9.77225 12.4862L9.86674 12.5807L9.77225 12.6752C9.64623 12.8012 9.64623 13.0053 9.77225 13.1313C9.83525 13.1943 9.91779 13.2258 10.0003 13.2258C10.0829 13.2258 10.1654 13.1943 10.2284 13.1313L10.3229 13.0368L10.4174 13.1313C10.4804 13.1943 10.5629 13.2258 10.6455 13.2258C10.728 13.2258 10.8106 13.1943 10.8736 13.1313C10.9995 13.0053 10.9995 12.8012 10.8735 12.6752Z" fill="#C3DDFF"/>
<path d="M14.0991 16.5467C13.9731 16.4206 13.7689 16.4206 13.6429 16.5467L13.5485 16.6412L13.454 16.5467C13.3279 16.4206 13.1238 16.4206 12.9978 16.5467C12.8718 16.6727 12.8718 16.8768 12.9978 17.0028L13.0923 17.0973L12.9978 17.1918C12.8718 17.3178 12.8718 17.5219 12.9978 17.6479C13.0608 17.7109 13.1434 17.7424 13.2259 17.7424C13.3085 17.7424 13.391 17.7109 13.454 17.6479L13.5485 17.5534L13.643 17.6479C13.706 17.7109 13.7885 17.7424 13.8711 17.7424C13.9536 17.7424 14.0362 17.7109 14.0992 17.6479C14.2252 17.5219 14.2252 17.3178 14.0992 17.1918L14.0047 17.0973L14.0992 17.0028C14.2251 16.8768 14.2251 16.6726 14.0991 16.5467Z" fill="#C3DDFF"/>
<path d="M12.2578 14.5159C12.2578 14.3378 12.1135 14.1934 11.9352 14.1934C11.7569 14.1934 11.6126 14.3378 11.6126 14.5159C11.4343 14.5159 11.29 14.6604 11.29 14.8385C11.29 15.0166 11.4343 15.1611 11.6126 15.1611C11.6126 15.3392 11.7569 15.4837 11.9352 15.4837C12.1135 15.4837 12.2578 15.3392 12.2578 15.1611C12.4361 15.1611 12.5804 15.0166 12.5804 14.8385C12.5804 14.6604 12.4361 14.5159 12.2578 14.5159Z" fill="#DBEAFF"/>
<path d="M15.4843 19.0325C15.4843 18.8544 15.34 18.71 15.1618 18.71C14.9835 18.71 14.8392 18.8544 14.8392 19.0325C14.6609 19.0325 14.5166 19.177 14.5166 19.3551C14.5166 19.5332 14.6609 19.6777 14.8392 19.6777C14.8392 19.8558 14.9835 20.0003 15.1618 20.0003C15.34 20.0003 15.4843 19.8558 15.4843 19.6777C15.6627 19.6777 15.8069 19.5332 15.8069 19.3551C15.8069 19.177 15.6627 19.0325 15.4843 19.0325Z" fill="#DBEAFF"/>
<path d="M14.1933 12.2581C14.1933 12.08 14.049 11.9355 13.8707 11.9355C13.6925 11.9355 13.5482 12.08 13.5482 12.2581C13.3698 12.2581 13.2256 12.4026 13.2256 12.5807C13.2256 12.7588 13.3699 12.9033 13.5482 12.9033C13.5482 13.0814 13.6925 13.2259 13.8707 13.2259C14.049 13.2259 14.1933 13.0814 14.1933 12.9033C14.3716 12.9033 14.5159 12.7588 14.5159 12.5807C14.5159 12.4026 14.3716 12.2581 14.1933 12.2581Z" fill="#DBEAFF"/>
<path d="M16.0346 14.2879C15.9086 14.1619 15.7045 14.1619 15.5785 14.2879L15.484 14.3824L15.3895 14.2879C15.2635 14.1619 15.0594 14.1619 14.9334 14.2879C14.8074 14.4139 14.8074 14.618 14.9334 14.744L15.0279 14.8385L14.9334 14.933C14.8074 15.059 14.8074 15.2631 14.9334 15.3891C14.9964 15.4521 15.0789 15.4836 15.1615 15.4836C15.244 15.4836 15.3265 15.4521 15.3896 15.3891L15.484 15.2946L15.5785 15.3891C15.6415 15.4521 15.7241 15.4836 15.8066 15.4836C15.8892 15.4836 15.9717 15.4521 16.0347 15.3891C16.1607 15.2631 16.1607 15.059 16.0347 14.933L15.9402 14.8385L16.0347 14.744C16.1606 14.618 16.1606 14.4139 16.0346 14.2879Z" fill="#C3DDFF"/>
<path d="M17.4189 16.7737C17.4189 16.5956 17.2746 16.4512 17.0963 16.4512C16.918 16.4512 16.7737 16.5956 16.7737 16.7737C16.5954 16.7737 16.4512 16.9182 16.4512 17.0963C16.4512 17.2745 16.5955 17.4189 16.7737 17.4189C16.7737 17.597 16.918 17.7415 17.0963 17.7415C17.2746 17.7415 17.4189 17.597 17.4189 17.4189C17.5972 17.4189 17.7415 17.2745 17.7415 17.0963C17.7415 16.9182 17.5972 16.7737 17.4189 16.7737Z" fill="#DBEAFF"/>
<path d="M19.2602 18.8045C19.1342 18.6785 18.9301 18.6785 18.8041 18.8045L18.7096 18.899L18.6151 18.8045C18.4891 18.6785 18.2849 18.6785 18.159 18.8045C18.0329 18.9305 18.0329 19.1346 18.159 19.2606L18.2535 19.3551L18.159 19.4496C18.0329 19.5756 18.0329 19.7797 18.159 19.9057C18.222 19.9687 18.3045 20.0002 18.3871 20.0002C18.4696 20.0002 18.5521 19.9687 18.6151 19.9057L18.7096 19.8112L18.8041 19.9057C18.8671 19.9687 18.9497 20.0002 19.0322 20.0002C19.1147 20.0002 19.1973 19.9687 19.2603 19.9057C19.3863 19.7797 19.3863 19.5756 19.2603 19.4496L19.1658 19.3551L19.2603 19.2606C19.3862 19.1346 19.3862 18.9305 19.2602 18.8045Z" fill="#C3DDFF"/>
<path d="M17.9702 12.6752L17.8757 12.5807L17.9702 12.4862C18.0962 12.3602 18.0962 12.156 17.9702 12.0301C17.8442 11.9041 17.64 11.904 17.514 12.0301L17.4196 12.1246L17.3251 12.0301C17.199 11.904 16.9949 11.904 16.8689 12.0301C16.7429 12.1561 16.7429 12.3602 16.8689 12.4862L16.9634 12.5807L16.8689 12.6752C16.7429 12.8012 16.7429 13.0053 16.8689 13.1313C16.9319 13.1943 17.0145 13.2258 17.097 13.2258C17.1796 13.2258 17.2621 13.1943 17.3251 13.1313L17.4196 13.0368L17.5141 13.1313C17.5771 13.1943 17.6596 13.2258 17.7422 13.2258C17.8247 13.2258 17.9072 13.1943 17.9703 13.1313C18.0962 13.0053 18.0962 12.8012 17.9702 12.6752Z" fill="#C3DDFF"/>
<path d="M19.3545 14.5159C19.3545 14.3378 19.2102 14.1934 19.0319 14.1934C18.8536 14.1934 18.7093 14.3378 18.7093 14.5159C18.531 14.5159 18.3867 14.6604 18.3867 14.8385C18.3867 15.0166 18.531 15.1611 18.7093 15.1611C18.7093 15.3392 18.8536 15.4837 19.0319 15.4837C19.2102 15.4837 19.3545 15.3392 19.3545 15.1611C19.5328 15.1611 19.677 15.0166 19.677 14.8385C19.677 14.6604 19.5327 14.5159 19.3545 14.5159Z" fill="#DBEAFF"/>
<path d="M17.0968 4.51613C17.0314 4.51613 16.9675 4.52164 16.9032 4.5259C16.235 3.36453 14.9845 2.58066 13.5484 2.58066C13.1184 2.58066 12.7062 2.65367 12.3197 2.78305C11.4593 1.13039 9.73402 0 7.74195 0C5.10551 0 2.93484 1.97805 2.62305 4.53027C1.15117 4.67129 0 5.91051 0 7.41934C0 9.02273 1.2998 10.3226 2.90324 10.3226H17.0968C18.7002 10.3226 20 9.02273 20 7.41934C20 5.81594 18.7002 4.51613 17.0968 4.51613Z" fill="#DBEAFF"/>
<path d="M9.03227 9.67742C6.35992 9.67742 4.19355 7.51105 4.19355 4.83871C4.19355 2.37824 6.03711 0.350195 8.41406 0.0435156C8.1957 0.0152734 7.96805 0 7.74195 0C5.10551 0 2.93484 1.97805 2.62305 4.53027C1.15117 4.67129 0 5.91051 0 7.41934C0 9.02273 1.2998 10.3226 2.90324 10.3226H17.0968C17.7876 10.3226 18.4233 10.0803 18.9218 9.67742H9.03227Z" fill="#C3DDFF"/>
<path d="M12.7601 3.94703C12.7957 4.09477 12.9277 4.19402 13.0732 4.19402C13.0984 4.19402 13.1236 4.19117 13.1492 4.18504C13.3224 4.14328 13.4289 3.9691 13.387 3.79582C13.288 3.38469 13.1414 2.9941 12.9638 2.62598C12.7438 2.66016 12.5307 2.71328 12.3242 2.78219C12.5118 3.14543 12.6607 3.53453 12.7601 3.94703Z" fill="#C3DDFF"/>
<path d="M17.658 4.57078C17.4758 4.53496 17.2889 4.5166 17.0962 4.5166C17.0317 4.5166 16.963 4.5218 16.8994 4.52598C17.1336 4.92883 17.2991 5.37672 17.3731 5.85621C17.3977 6.01562 17.535 6.12949 17.6916 6.12949C17.708 6.12949 17.7244 6.12824 17.7411 6.1257C17.9171 6.09844 18.0378 5.93371 18.0107 5.75762C17.946 5.33836 17.8248 4.93973 17.658 4.57078Z" fill="#C3DDFF"/>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,16 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.99996 15.6571C13.1243 15.6571 15.6571 13.1243 15.6571 9.99996C15.6571 6.87558 13.1243 4.34277 9.99996 4.34277C6.87558 4.34277 4.34277 6.87558 4.34277 9.99996C4.34277 13.1243 6.87558 15.6571 9.99996 15.6571Z" fill="#FFD347"/>
<path d="M9.99949 2.22066C9.83258 2.22066 9.69727 2.08539 9.69727 1.91844V0.302227C9.69727 0.135273 9.83258 0 9.99949 0C10.1664 0 10.3017 0.135273 10.3017 0.302227V1.91848C10.3017 2.08539 10.1664 2.22066 9.99949 2.22066Z" fill="#FFD347"/>
<path d="M5.95925 3.30301C5.85479 3.30301 5.75323 3.24883 5.69725 3.15188L4.88917 1.75219C4.80573 1.60766 4.85522 1.42281 4.99979 1.33934C5.14436 1.25598 5.32917 1.30535 5.41265 1.44996L6.22073 2.84965C6.30417 2.99418 6.25468 3.17902 6.11011 3.2625C6.06249 3.28996 6.01054 3.30301 5.95925 3.30301Z" fill="#FFD347"/>
<path d="M3.00049 6.26126C2.94924 6.26126 2.89725 6.24821 2.84967 6.22071L1.44998 5.41263C1.30545 5.32919 1.25592 5.14435 1.33936 4.99978C1.42279 4.85521 1.60764 4.80575 1.75221 4.88915L3.15189 5.69724C3.29643 5.78067 3.34596 5.96552 3.26252 6.11009C3.2065 6.20708 3.10494 6.26126 3.00049 6.26126Z" fill="#FFD347"/>
<path d="M1.91844 10.3017H0.302227C0.135312 10.3017 0 10.1664 0 9.99949C0 9.83254 0.135312 9.69727 0.302227 9.69727H1.91848C2.08539 9.69727 2.2207 9.83254 2.2207 9.99949C2.2207 10.1664 2.08535 10.3017 1.91844 10.3017Z" fill="#FFD347"/>
<path d="M1.60136 15.1509C1.4969 15.1509 1.39534 15.0967 1.33936 14.9997C1.25593 14.8552 1.30542 14.6704 1.44999 14.5869L2.84968 13.7788C2.99421 13.6954 3.17905 13.7448 3.26253 13.8894C3.34597 14.0339 3.29647 14.2188 3.1519 14.3023L1.75222 15.1104C1.7046 15.1378 1.65261 15.1509 1.60136 15.1509Z" fill="#FFD347"/>
<path d="M5.15061 18.7005C5.09936 18.7005 5.04736 18.6875 4.99979 18.66C4.85525 18.5765 4.80572 18.3917 4.88916 18.2471L5.69725 16.8474C5.78068 16.7029 5.96553 16.6534 6.1101 16.7368C6.25463 16.8202 6.30416 17.0051 6.22072 17.1497L5.41264 18.5493C5.35662 18.6463 5.25506 18.7005 5.15061 18.7005Z" fill="#FFD347"/>
<path d="M9.99949 20C9.83258 20 9.69727 19.8647 9.69727 19.6978V18.0815C9.69727 17.9146 9.83258 17.7793 9.99949 17.7793C10.1664 17.7793 10.3017 17.9146 10.3017 18.0815V19.6978C10.3017 19.8647 10.1664 20 9.99949 20Z" fill="#FFD347"/>
<path d="M14.8489 18.7014C14.7444 18.7014 14.6429 18.6473 14.5869 18.5503L13.7788 17.1506C13.6954 17.0061 13.7449 16.8213 13.8894 16.7378C14.034 16.6544 14.2188 16.7038 14.3023 16.8484L15.1104 18.2481C15.1938 18.3926 15.1443 18.5775 14.9998 18.6609C14.9521 18.6884 14.9002 18.7014 14.8489 18.7014Z" fill="#FFD347"/>
<path d="M18.3989 15.1509C18.3477 15.1509 18.2957 15.1379 18.2481 15.1104L16.8484 14.3023C16.7039 14.2188 16.6544 14.034 16.7378 13.8894C16.8212 13.7449 17.0061 13.6954 17.1506 13.7788L18.5503 14.5869C18.6949 14.6703 18.7444 14.8552 18.661 14.9997C18.6049 15.0967 18.5034 15.1509 18.3989 15.1509Z" fill="#FFD347"/>
<path d="M19.6978 10.3017H18.0815C17.9146 10.3017 17.7793 10.1664 17.7793 9.99949C17.7793 9.83254 17.9146 9.69727 18.0815 9.69727H19.6978C19.8647 9.69727 20 9.83254 20 9.99949C20 10.1664 19.8647 10.3017 19.6978 10.3017Z" fill="#FFD347"/>
<path d="M16.9998 6.26121C16.8953 6.26121 16.7938 6.20703 16.7378 6.11008C16.6544 5.96555 16.7039 5.7807 16.8484 5.69723L18.2481 4.88914C18.3926 4.80578 18.5775 4.85516 18.661 4.99977C18.7444 5.1443 18.6949 5.32914 18.5503 5.41262L17.1507 6.2207C17.103 6.24817 17.051 6.26121 16.9998 6.26121Z" fill="#FFD347"/>
<path d="M14.0403 3.30306C13.989 3.30306 13.937 3.29001 13.8894 3.26251C13.7449 3.17907 13.6954 2.99423 13.7788 2.84966L14.5869 1.44997C14.6703 1.3054 14.8552 1.25595 14.9997 1.33935C15.1443 1.42278 15.1938 1.60763 15.1104 1.7522L14.3023 3.15189C14.2463 3.24888 14.1447 3.30306 14.0403 3.30306Z" fill="#FFD347"/>
<path d="M9.99965 4.34277C9.79488 4.34277 9.5927 4.35395 9.39355 4.37512C12.2328 4.67758 14.4445 7.08027 14.4445 9.99976C14.4445 12.9193 12.2328 15.322 9.39355 15.6245C9.5927 15.6457 9.79484 15.6568 9.99965 15.6568C13.1239 15.6568 15.6567 13.1241 15.6567 9.99976C15.6567 6.87547 13.124 4.34277 9.99965 4.34277Z" fill="#FFBE31"/>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,8 @@
<svg width="32" height="40" viewBox="0 0 32 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M31.3558 24.3356C31.3558 32.9868 24.3366 40 15.6779 40C7.01928 40 0 32.9868 0 24.3356C0 16.6883 12.2504 3.26474 15.0936 0.252246C15.411 -0.0840819 15.945 -0.0840819 16.2623 0.252246C19.1055 3.26482 31.3558 16.6883 31.3558 24.3356Z" fill="#B3DAFE"/>
<path d="M16.2623 0.252246C15.9449 -0.0840819 15.4109 -0.0840819 15.0936 0.252246C14.9197 0.436542 14.7101 0.660292 14.4707 0.918729C18.1444 4.88583 28.9414 17.156 28.9414 24.3355C28.9414 32.5809 22.5653 39.3383 14.4707 39.9541C14.8691 39.9845 15.2717 39.9999 15.678 39.9999C24.3366 39.9999 31.3559 32.9867 31.3559 24.3355C31.3559 16.6883 19.1055 3.26482 16.2623 0.252246Z" fill="#8AC9FE"/>
<path d="M31.3146 25.4707C26.9452 23.6196 22.2099 23.9811 9.98543 26.5371C7.23286 27.1127 4.08365 27.8032 0.595215 28.6251C2.46216 35.191 8.50794 39.9999 15.678 39.9999C23.9546 39.9999 30.7324 33.5919 31.3146 25.4707Z" fill="#60B7FF"/>
<path d="M31.3146 25.4633C30.5689 25.1473 29.7422 24.8981 28.9369 24.7148C28.902 26.2409 28.6664 27.6787 28.2134 29.0619L30.1492 30.3706C30.4571 29.6496 30.7395 28.766 30.9738 27.7362C31.164 26.8995 31.2649 26.132 31.3146 25.4633Z" fill="#26A6FE"/>
<path d="M21.5314 27.7526C13.3347 26.4026 9.06084 21.1593 0.388828 21.7261C0.139062 22.6479 0 23.5245 0 24.3356C0 32.9868 7.01921 40 15.6779 40C23.2857 40 29.6271 34.5856 31.0545 27.4032C27.1755 28.2694 24.002 28.1595 21.5314 27.7526Z" fill="#0593FC"/>
<path d="M28.5442 27.8469C27.0352 34.4294 21.3767 39.4302 14.465 39.9537C14.8653 39.9844 15.2698 40 15.6779 40C23.2857 40 29.627 34.5855 31.0545 27.4032C30.182 27.598 29.3454 27.7431 28.5442 27.8469Z" fill="#0182FC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,25 @@
<svg width="311" height="345" viewBox="0 0 311 345" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M309.392 1.11133H0.715698V344.077H309.392V1.11133Z" fill="#EBEBEC"/>
<path d="M309.392 344.817H0.715982C0.309099 344.817 0.0131836 344.484 0.0131836 344.114V1.11149C0.0131836 0.741596 0.346088 0.408691 0.715982 0.408691H309.392C309.799 0.408691 310.095 0.741596 310.095 1.11149V344.077C310.095 344.484 309.762 344.78 309.392 344.78V344.817ZM1.45577 343.374H308.689V1.85128H1.45577V343.411V343.374Z" fill="#CCCCCC"/>
<path d="M309.392 344.817H309.244C309.244 344.817 308.911 344.743 308.763 344.632L293.561 331.501L154.481 173.075C154.259 172.816 154.259 172.409 154.481 172.114L293.524 13.799L308.948 0.593798C309.17 0.408851 309.466 0.371862 309.725 0.48283C309.984 0.593798 310.132 0.852723 310.132 1.14864V344.114C310.132 344.521 309.799 344.817 309.429 344.817H309.392ZM156.034 172.631L294.633 330.502L308.726 342.672V2.70219L294.559 14.8347L156.034 172.631Z" fill="#CCCCCC"/>
<path d="M155.072 173.334C154.85 173.334 154.666 173.26 154.518 173.075L15.5115 14.7236L0.271872 1.66633C0.0129463 1.48138 -0.0610325 1.14848 0.0499357 0.889553C0.160904 0.593638 0.419829 0.408691 0.715744 0.408691H309.392C309.688 0.408691 309.947 0.593638 310.058 0.889553C310.169 1.18547 310.058 1.48138 309.836 1.66633L294.485 14.7976L155.553 173.075C155.553 173.075 155.22 173.334 154.998 173.334H155.072ZM2.67618 1.85128L16.5472 13.7249L155.072 171.522L293.524 13.7988L307.469 1.85128H2.67618Z" fill="#CCCCCC"/>
<path d="M0.715982 344.817C0.715982 344.817 0.494045 344.817 0.420067 344.743C0.161141 344.632 0.0131836 344.373 0.0131836 344.077V1.11165C0.0131836 0.852723 0.161141 0.593798 0.420067 0.48283C0.678992 0.371862 0.974907 0.408851 1.19684 0.593798L16.5474 13.725L155.627 172.15C155.849 172.409 155.849 172.816 155.627 173.112L16.5844 331.427L1.15985 344.632C1.15985 344.632 0.863939 344.817 0.678992 344.817H0.715982ZM1.45577 2.70219V342.561L15.6227 330.428L154.148 172.631L15.5117 14.7237L1.45577 2.70219Z" fill="#CCCCCC"/>
<path d="M309.281 344.817H0.71569C0.419775 344.817 0.160849 344.632 0.049881 344.336C-0.0610871 344.04 0.049881 343.744 0.271817 343.559L15.6224 330.428L154.554 172.151C154.813 171.855 155.368 171.855 155.627 172.151L294.633 330.502L309.762 343.559C309.984 343.744 310.058 344.077 309.947 344.336C309.836 344.632 309.577 344.817 309.281 344.817ZM2.67613 343.374H307.358L293.635 331.501L155.109 173.704L16.5841 331.427L2.63914 343.374H2.67613Z" fill="#CCCCCC"/>
<path d="M294.078 14.2798H16.0659V330.983H294.078V14.2798Z" fill="#B2B4B6"/>
<path d="M294.078 331.686H16.0661C15.6592 331.686 15.3633 331.353 15.3633 330.983V14.2799C15.3633 13.8731 15.6962 13.5771 16.0661 13.5771H294.078C294.485 13.5771 294.781 13.9101 294.781 14.2799V330.983C294.781 331.39 294.448 331.686 294.078 331.686ZM16.7689 330.243H293.338V14.9827H16.7689V330.243Z" fill="#CCCCCC"/>
<path d="M290.305 17.8306H19.839V325.952H290.305V17.8306Z" fill="#D8D9DA"/>
<path d="M290.305 326.655H19.8392C19.4323 326.655 19.1364 326.322 19.1364 325.952V17.8307C19.1364 17.4238 19.4693 17.1279 19.8392 17.1279H290.305C290.712 17.1279 291.008 17.4608 291.008 17.8307V325.952C291.008 326.359 290.675 326.655 290.305 326.655ZM20.5419 325.249H289.566V18.5705H20.5419V325.249Z" fill="#9E9FA0"/>
<path d="M285.645 22.269H24.3519V321.772H285.645V22.269Z" fill="white"/>
<path d="M279.985 28.3726H30.2701V315.595H279.985V28.3726Z" fill="url(#paint0_linear_4883_327)" fill-opacity="0.5"/>
<path d="M279.986 316.298H30.2704C29.8635 316.298 29.5676 315.966 29.5676 315.596V28.3732C29.5676 27.9663 29.9005 27.6704 30.2704 27.6704H279.986C280.393 27.6704 280.688 28.0033 280.688 28.3732V315.596C280.688 316.003 280.356 316.298 279.986 316.298ZM30.9732 314.856H279.246V29.076H30.9732V314.856Z" fill="#D5D7D8"/>
<defs>
<linearGradient id="paint0_linear_4883_327" x1="155.109" y1="384.21" x2="155.109" y2="-45.7172" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="0.15" stop-color="#FAFDFD"/>
<stop offset="0.31" stop-color="#ECF7F8"/>
<stop offset="0.49" stop-color="#D5EEF1"/>
<stop offset="0.87" stop-color="#B4E1EB"/>
<stop offset="1" stop-color="#A8DDE9"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -553,7 +553,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 31;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -563,7 +563,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
MARKETING_VERSION = 1.0.5;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -745,7 +745,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 31;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -755,7 +755,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
MARKETING_VERSION = 1.0.5;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -775,7 +775,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 31;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -785,7 +785,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
MARKETING_VERSION = 1.0.5;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -862,7 +862,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 31;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -872,7 +872,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
MARKETING_VERSION = 1.0.5;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -965,7 +965,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 31;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -975,7 +975,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
MARKETING_VERSION = 1.0.5;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1063,7 +1063,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 31;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -1073,7 +1073,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
MARKETING_VERSION = 1.0.5;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

View File

@ -2,8 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photo library to allow you to select and upload photos.</string>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
@ -28,6 +26,8 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photo library to allow you to select and upload photos.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
@ -36,10 +36,7 @@
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
</dict>
</plist>

View File

@ -61,10 +61,11 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = AcStatusModel.fromJson(response['productUuid'], statusModelList);
deviceStatus =
AcStatusModel.fromJson(response['productUuid'], statusModelList);
emit(GetAcStatusState(acStatusModel: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
_listenToChanges();
// _listenToChanges();
}
} catch (e) {
emit(AcsFailedState(errorMessage: e.toString()));
@ -74,18 +75,22 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$acId');
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$acId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) {
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 = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value']));
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = AcStatusModel.fromJson(usersMap['productUuid'], statusList);
deviceStatus =
AcStatusModel.fromJson(usersMap['productUuid'], statusList);
add(AcUpdated());
});
} catch (_) {}
@ -102,12 +107,14 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', 'AC');
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 = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatusList.add(AcStatusModel.fromJson(response['productUuid'], statusModelList));
deviceStatusList.add(
AcStatusModel.fromJson(response['productUuid'], statusModelList));
}
_setAllAcsTempsAndSwitches();
}
@ -129,7 +136,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
emit(AcModifyingState(acStatusModel: deviceStatus));
}
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'switch', value: acSwitchValue);
await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'switch', value: acSwitchValue);
}
void _changeAllAcSwitch(ChangeAllSwitch event, Emitter<AcsState> emit) async {
@ -190,7 +198,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
deviceStatus.childLock = lockValue;
emit(AcModifyingState(acStatusModel: deviceStatus));
await _runDeBouncerForOneDevice(deviceId: acId, code: 'child_lock', value: lockValue);
await _runDeBouncerForOneDevice(
deviceId: acId, code: 'child_lock', value: lockValue);
}
void _increaseCoolTo(IncreaseCoolToTemp event, Emitter<AcsState> emit) async {
@ -218,7 +227,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
emit(AcModifyingState(acStatusModel: deviceStatus));
}
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'temp_set', value: value);
}
void _decreaseCoolTo(DecreaseCoolToTemp event, Emitter<AcsState> emit) async {
@ -246,7 +256,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
emit(AcModifyingState(acStatusModel: deviceStatus));
}
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'temp_set', value: value);
}
void _changeAcMode(ChangeAcMode event, Emitter<AcsState> emit) async {
@ -268,7 +279,9 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
}
await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'mode', value: getACModeString(tempMode));
deviceId: event.deviceId,
code: 'mode',
value: getACModeString(tempMode));
}
void _changeFanSpeed(ChangeFanSpeed event, Emitter<AcsState> emit) async {
@ -281,19 +294,23 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.productId) {
ac.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
ac.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
ac.acFanSpeed =
AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
}
}
_emitAcsStatus(emit);
} else {
emit(AcChangeLoading(acStatusModel: deviceStatus));
deviceStatus.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
deviceStatus.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
deviceStatus.acFanSpeed =
AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
emit(AcModifyingState(acStatusModel: deviceStatus));
}
await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'level', value: getNextFanSpeedKey(fanSpeed));
deviceId: event.deviceId,
code: 'level',
value: getNextFanSpeedKey(fanSpeed));
}
String getACModeString(TempModes value) {
@ -338,7 +355,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
for (int i = 0; i < deviceStatusList.length; i++) {
try {
await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: devicesList[i].uuid, code: code, value: value),
DeviceControlModel(
deviceId: devicesList[i].uuid, code: code, value: value),
devicesList[i].uuid ?? '');
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
@ -360,7 +378,10 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
_timer = Timer(const Duration(seconds: 1), () async {
try {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: allAcsPage ? deviceId : acId, code: code, value: value),
DeviceControlModel(
deviceId: allAcsPage ? deviceId : acId,
code: code,
value: value),
allAcsPage ? deviceId : acId);
if (!response['success']) {
@ -377,7 +398,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
if (value >= 20 && value <= 30) {
return true;
} else {
emit(const AcsFailedState(errorMessage: 'The temperature must be between 20 and 30'));
emit(const AcsFailedState(
errorMessage: 'The temperature must be between 20 and 30'));
emit(GetAllAcsStatusState(
allAcsStatues: deviceStatusList,
allAcs: devicesList,

View File

@ -19,7 +19,8 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
on<CeilingSensorUpdated>(_onCeilingSensorUpdated);
}
void _fetchCeilingSensorStatus(InitialEvent event, Emitter<CeilingSensorState> emit) async {
void _fetchCeilingSensorStatus(
InitialEvent event, Emitter<CeilingSensorState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(deviceId);
@ -29,7 +30,7 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
}
deviceStatus = CeilingSensorModel.fromJson(statusModelList);
emit(UpdateState(ceilingSensorModel: deviceStatus));
_listenToChanges();
// _listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
@ -38,15 +39,18 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) {
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 = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value']));
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = CeilingSensorModel.fromJson(statusList);
@ -55,15 +59,19 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
} catch (_) {}
}
_onCeilingSensorUpdated(CeilingSensorUpdated event, Emitter<CeilingSensorState> emit) {
_onCeilingSensorUpdated(
CeilingSensorUpdated event, Emitter<CeilingSensorState> emit) {
emit(UpdateState(ceilingSensorModel: deviceStatus));
}
void _changeValue(ChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
void _changeValue(
ChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
emit(LoadingNewSate(ceilingSensorModel: deviceStatus));
try {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: deviceId, code: event.code, value: event.value), deviceId);
DeviceControlModel(
deviceId: deviceId, code: event.code, value: event.value),
deviceId);
if (response['success'] ?? false) {
deviceStatus.sensitivity = event.value;

View File

@ -1,7 +1,11 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
import 'package:syncrow_app/features/devices/model/curtain_model.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/group_curtain_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/resource_manager/constants.dart';
@ -22,11 +26,14 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
on<OpenCurtain>(_onOpenCurtain);
on<CloseCurtain>(_onCloseCurtain);
on<PauseCurtain>(_onPauseCurtain);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<InitialWizardEvent>(_fetchWizardStatus);
on<GroupAllOffEvent>(_groupAllOff);
on<GroupAllOnEvent>(_groupAllOn);
}
Future<void> _onOpenCurtain(
OpenCurtain event,
Emitter<CurtainState> emit) async {
OpenCurtain event, Emitter<CurtainState> emit) async {
isMoving = true;
while (openPercentage < 100.0) {
if (state is CurtainsClosing) {
@ -48,7 +55,7 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
_pauseCurtain(emit);
}
});
if (openPercentage >=100.0) {
if (openPercentage >= 100.0) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
@ -132,7 +139,7 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
),
curtainId,
);
await DevicesAPI.controlDevice(
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
code: 'percent_control',
@ -151,25 +158,18 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
));
}
void _fetchStatus(InitCurtain event, Emitter<CurtainState> emit) async {
try {
emit(CurtainLoadingState());
// Fetch the status from the API
var response = await DevicesAPI.getDeviceStatus(curtainId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
// Get the open percentage from the response
openPercentage = double.tryParse(statusModelList[1].value.toString())!;
// Calculate curtain width and blind height based on the open percentage
if (openPercentage != null) {
curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
}
curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
emit(CurtainsOpening(
curtainWidth: curtainWidth,
blindHeight: blindHeight,
@ -181,4 +181,138 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
}
}
List<GroupCurtainModel> groupList = [];
bool allSwitchesOn = true;
List<DeviceModel> devicesList = [];
CurtainModel deviceStatus = CurtainModel(control: 'stop', percent: 0);
void _fetchWizardStatus(
InitialWizardEvent event, Emitter<CurtainState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
groupList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', 'CUR');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = CurtainModel.fromJson(statusModelList);
groupList.add(GroupCurtainModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.control,
percentControl: deviceStatus.percent));
}
if (groupList.isNotEmpty) {
groupList.firstWhere((element) {
if (element.percentControl > 1) {
allSwitchesOn = true;
}
return true;
});
}
emit(
UpdateGroupState(curtainList: groupList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState());
return;
}
}
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<CurtainState> emit) async {
emit(LoadingNewSate(curtainModel: deviceStatus));
try {
bool allSwitchesValue = true;
// Update the firstSwitch value in the groupList based on the deviceId
groupList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.percentControl =
event.value; // Set the new value from the event
}
if (element.percentControl > 1) {
allSwitchesValue = true; // Check if any switch is not 'open'
}
});
final response = await DevicesAPI.deviceBatchController(
code: 'percent_control',
devicesUuid: [event.deviceId],
value: event.value, // Use the value from the event
);
emit(UpdateGroupState(
curtainList: groupList, allSwitches: allSwitchesValue));
if (response['success']) {
// Optionally add an initial event if needed.
}
} catch (_) {
// Handle the error if needed.
}
}
void _groupAllOn(GroupAllOnEvent event, Emitter<CurtainState> emit) async {
emit(LoadingNewSate(curtainModel: deviceStatus));
try {
for (int i = 0; i < groupList.length; i++) {
groupList[i].percentControl = 100;
}
emit(UpdateGroupState(curtainList: groupList, allSwitches: true));
List<String> allDeviceIds =
groupList.map((device) => device.deviceId).toList();
final response2 = await DevicesAPI.deviceBatchController(
code: 'percent_control',
devicesUuid: allDeviceIds,
value: 100,
);
if (response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
}
} catch (_) {
emit(FailedState());
await Future.delayed(const Duration(milliseconds: 500));
// Optionally add an initial event if needed.
}
}
void _groupAllOff(GroupAllOffEvent event, Emitter<CurtainState> emit) async {
emit(LoadingNewSate(curtainModel: deviceStatus));
try {
for (int i = 0; i < groupList.length; i++) {
groupList[i].percentControl = 0;
}
emit(UpdateGroupState(curtainList: groupList, allSwitches: false));
List<String> allDeviceIds =
groupList.map((device) => device.deviceId).toList();
final response2 = await DevicesAPI.deviceBatchController(
code: 'percent_control',
devicesUuid: allDeviceIds,
value: 0,
);
if (response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
}
} catch (_) {
emit(FailedState());
await Future.delayed(const Duration(milliseconds: 500));
}
}
}

View File

@ -31,4 +31,21 @@ class CloseCurtain extends CurtainEvent {
class InitCurtain extends CurtainEvent {}
class PauseCurtain extends CurtainEvent {}
class useCurtainEvent extends CurtainEvent {}
class useCurtainEvent extends CurtainEvent {}
class InitialWizardEvent extends CurtainEvent {}
class ChangeFirstWizardSwitchStatusEvent extends CurtainEvent {
final int value;
final String deviceId;
const ChangeFirstWizardSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class GroupAllOnEvent extends CurtainEvent {}
class GroupAllOffEvent extends CurtainEvent {}

View File

@ -1,5 +1,7 @@
// curtain_state.dart
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/curtain_model.dart';
import 'package:syncrow_app/features/devices/model/group_curtain_model.dart';
abstract class CurtainState extends Equatable {
const CurtainState();
@ -10,8 +12,9 @@ abstract class CurtainState extends Equatable {
class CurtainInitial extends CurtainState {}
class UpdateCurtain extends CurtainState {
class LoadingInitialState extends CurtainState {}
class UpdateCurtain extends CurtainState {
final double curtainWidth;
final double blindHeight;
final double openPercentage;
@ -73,4 +76,23 @@ class CurtainsPaused extends CurtainState {
@override
List<Object?> get props => [curtainWidth, blindHeight, openPercentage];
}
}
class UpdateGroupState extends CurtainState {
final List<GroupCurtainModel> curtainList;
final bool allSwitches;
const UpdateGroupState(
{required this.curtainList, required this.allSwitches});
@override
List<Object> get props => [curtainList, allSwitches];
}
class LoadingNewSate extends CurtainState {
final CurtainModel curtainModel;
const LoadingNewSate({required this.curtainModel});
@override
List<Object> get props => [curtainModel];
}

View File

@ -43,7 +43,7 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
);
emit(UpdateState(doorSensor: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
_listenToChanges();
// _listenToChanges();
} catch (e) {
emit(DoorSensorFailedState(errorMessage: e.toString()));
return;
@ -100,7 +100,6 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
doorAlarm = event.isDoorAlarmEnabled;
emit(UpdateState(doorSensor: deviceStatus));
// API call to update the state, if necessary
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: DSId,
@ -119,33 +118,26 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<DoorSensorState> emit) async {
// Get the current date and time
DateTime now = DateTime.now();
// Calculate the date one month ago
DateTime lastMonth = DateTime(now.year, now.month - 1, now.day);
// Convert the date to milliseconds since epoch (Unix timestamp in milliseconds)
int startTime = lastMonth.millisecondsSinceEpoch;
int endTime = now.millisecondsSinceEpoch;
try {
emit(DoorSensorLoadingState());
var response = await DevicesAPI.getReportLogs(
startTime:
startTime.toString(), // Convert to String if the API expects it
endTime: endTime.toString(), // Convert to String if the API expects it
startTime.toString(),
endTime: endTime.toString(),
deviceUuid: DSId,
code: 'doorcontact_state',
);
print('response======${response}');
recordGroups = response;
// Process response here
emit(UpdateState(doorSensor: deviceStatus));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
// Handle error
print('Error fetching logs: ${errorMessage}');
}
}

View File

@ -0,0 +1,621 @@
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/app_layout/bloc/home_cubit.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_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/group_garage_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<SetTimeOutValue>(_setTimeOutAlarm);
on<TickTimer>(_onTickTimer);
on<InitialWizardEvent>(_fetchWizardStatus);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<ToggleAlarmEvent>(_toggleAlarmEvent);
on<DeleteScheduleEvent>(deleteSchedule);
//_toggleAlarmEvent
}
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 _toggleAlarmEvent(
ToggleAlarmEvent event,
Emitter<GarageDoorSensorState> emit,
) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
deviceStatus.doorState1 = event.isEnabled;
emit(UpdateState(garageSensor: deviceStatus));
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: GDId,
code: 'door_state_1',
value: event.isEnabled,
),
GDId,
);
emit(UpdateState(garageSensor: deviceStatus));
} catch (e) {
emit(GarageDoorFailedState(errorMessage: e.toString()));
}
}
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: 'switch_1',
);
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());
add(const ToggleCreateScheduleEvent(index: 1));
} 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();
emit(UpdateState(garageSensor: deviceStatus));
} 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;
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;
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: GDId, code: 'switch_1', value: toggleDoor),
GDId);
add(const 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(const 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());
}
}
bool oneGangGroup = false;
List<DeviceModel> devicesList = [];
List<GroupGarageModel> groupList = [];
bool allSwitchesOn = true;
void _fetchWizardStatus(
InitialWizardEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
groupList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', 'GD');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = GarageDoorModel.fromJson(statusModelList);
groupList.add(GroupGarageModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.switch1,
));
}
if (groupList.isNotEmpty) {
groupList.firstWhere((element) {
if (!element.firstSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(garageList: groupList, allSwitches: allSwitchesOn));
} catch (e) {
emit(GarageDoorFailedState(errorMessage: e.toString()));
return;
}
}
void _groupAllOn(
GroupAllOnEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
for (int i = 0; i < groupList.length; i++) {
groupList[i].firstSwitch = true;
}
// Emit the state with updated values
emit(UpdateGroupState(garageList: groupList, allSwitches: true));
// Get a list of all device IDs
List<String> allDeviceIds =
groupList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', // Controls first switch for all devices
devicesUuid: allDeviceIds,
value: true, // true (on) or false (off) depending on the event value
);
// Check if either response is unsuccessful, then reset to initial state
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
// In case of an error, delay and reset the screen to initial state
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
void _groupAllOff(
GroupAllOffEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
for (int i = 0; i < groupList.length; i++) {
groupList[i].firstSwitch = false;
}
// Emit the state with updated values
emit(UpdateGroupState(garageList: groupList, allSwitches: false));
// Get a list of all device IDs
List<String> allDeviceIds =
groupList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', // Controls first switch for all devices
devicesUuid: allDeviceIds,
value: false, // true (on) or false (off) depending on the event value
);
// Check if either response is unsuccessful, then reset to initial state
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
// In case of an error, delay and reset the screen to initial state
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
bool allSwitchesValue = true;
groupList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
garageList: groupList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: [event.deviceId],
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialEvent(groupScreen: oneGangGroup));
}
} catch (_) {
add(InitialEvent(groupScreen: oneGangGroup));
}
}
void _setTimeOutAlarm(
SetTimeOutValue 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_alarm', value: seconds),
GDId);
if (response['success'] ?? false) {
deviceStatus.countdownAlarm = seconds;
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
} else {
emit(const GarageDoorFailedState(errorMessage: 'Something went wrong'));
return;
}
} catch (e) {
emit(GarageDoorFailedState(errorMessage: e.toString()));
return;
}
}
}

View File

@ -0,0 +1,183 @@
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 ToggleAlarmEvent extends GarageDoorEvent {
final String isEnabled;
const ToggleAlarmEvent(this.isEnabled);
@override
List<Object> get props => [isEnabled];
}
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 SetTimeOutValue extends GarageDoorEvent {
final Duration duration;
final String deviceCode;
const SetTimeOutValue({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];
}
class InitialWizardEvent extends GarageDoorEvent {}
class GroupAllOnEvent extends GarageDoorEvent {}
class GroupAllOffEvent extends GarageDoorEvent {}
class InitialEvent extends GarageDoorEvent {
final bool groupScreen;
const InitialEvent({required this.groupScreen});
@override
List<Object> get props => [groupScreen];
}

View File

@ -0,0 +1,94 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/garage_door_model.dart';
import 'package:syncrow_app/features/devices/model/group_garage_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);
}
class UpdateGroupState extends GarageDoorSensorState {
final List<GroupGarageModel> garageList;
final bool allSwitches;
const UpdateGroupState(
{required this.garageList, required this.allSwitches});
@override
List<Object> get props => [garageList, allSwitches];
}

View File

@ -2,9 +2,11 @@ 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/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_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/group_one_gang_model.dart';
import 'package:syncrow_app/features/devices/model/one_gang_model.dart';
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
@ -24,7 +26,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
bool oneGangGroup = false;
List<DeviceModel> devicesList = [];
OneGangBloc({required this.oneGangId, required this.switchCode}) : super(InitialState()) {
OneGangBloc({required this.oneGangId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchOneGangStatus);
on<OneGangUpdated>(_oneGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -41,9 +44,14 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<InitialWizardEvent>(_fetchOneGangWizardStatus);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
}
void _fetchOneGangStatus(InitialEvent event, Emitter<OneGangState> emit) async {
void _fetchOneGangStatus(
InitialEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(oneGangId);
@ -53,7 +61,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
}
deviceStatus = OneGangModel.fromJson(statusModelList);
emit(UpdateState(oneGangModel: deviceStatus));
_listenToChanges();
// _listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
@ -62,18 +70,21 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$oneGangId');
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$oneGangId');
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>;
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: element['value']));
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = OneGangModel.fromJson(statusList);
@ -88,7 +99,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
emit(UpdateState(oneGangModel: deviceStatus));
}
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<OneGangState> emit) async {
void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.value;
@ -113,17 +125,20 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
}
}
void _changeSliding(ChangeSlidingSegment event, Emitter<OneGangState> emit) async {
void _changeSliding(
ChangeSlidingSegment event, Emitter<OneGangState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(SetCounterValue event, Emitter<OneGangState> emit) async {
void _setCounterValue(
SetCounterValue event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: oneGangId, code: event.deviceCode, value: seconds),
DeviceControlModel(
deviceId: oneGangId, code: event.deviceCode, value: seconds),
oneGangId);
if (response['success'] ?? false) {
@ -146,7 +161,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
}
}
void _getCounterValue(GetCounterEvent event, Emitter<OneGangState> emit) async {
void _getCounterValue(
GetCounterEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(oneGangId);
@ -215,7 +231,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
add(GetScheduleEvent());
emit(SaveSchedule());
add(const ToggleCreateScheduleEvent(index:1 ));
add(const ToggleCreateScheduleEvent(index: 1));
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
@ -235,7 +251,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
deviceId: oneGangId,
);
List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
@ -246,12 +263,13 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds =
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute);
DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
}
Future toggleChange(ToggleScheduleEvent event, Emitter<OneGangState> emit) async {
Future toggleChange(
ToggleScheduleEvent event, Emitter<OneGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
@ -270,7 +288,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
}
}
Future deleteSchedule(DeleteScheduleEvent event, Emitter<OneGangState> emit) async {
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<OneGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
@ -290,23 +309,14 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
}
}
// void toggleCreateSchedule() {
// emit(LoadingInitialState());
// createSchedule = !createSchedule;
// selectedDays.clear();
// selectedTime = DateTime.now();
// emit(UpdateCreateScheduleState(createSchedule));
// emit(ChangeSlidingSegmentState(value: 1));
// }
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<OneGangState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<OneGangState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
bool toggleSchedule = true;
List<String> selectedDays = [];
@ -324,14 +334,157 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(ChangeSlidingSegment(value: 1));
add(const ChangeSlidingSegment(value: 1));
}
int selectedTabIndex = 0;
void toggleSelectedIndex( ToggleSelectedEvent event, Emitter<OneGangState> emit) {
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<OneGangState> emit) {
emit(LoadingInitialState());
selectedTabIndex =event.index;
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
List<GroupOneGangModel> groupOneGangList = [];
bool allSwitchesOn = true;
void _fetchOneGangWizardStatus(
InitialWizardEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
groupOneGangList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '1G');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = OneGangModel.fromJson(statusModelList);
groupOneGangList.add(GroupOneGangModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
));
}
if (groupOneGangList.isNotEmpty) {
groupOneGangList.firstWhere((element) {
if (!element.firstSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(
oneGangList: groupOneGangList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupOneGangList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
oneGangList: groupOneGangList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: [event.deviceId],
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialEvent(groupScreen: oneGangGroup));
}
} catch (_) {
add(InitialEvent(groupScreen: oneGangGroup));
}
}
void _groupAllOn(GroupAllOnEvent event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
for (int i = 0; i < groupOneGangList.length; i++) {
groupOneGangList[i].firstSwitch = true;
}
// Emit the state with updated values
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: true));
// Get a list of all device IDs
List<String> allDeviceIds =
groupOneGangList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', // Controls first switch for all devices
devicesUuid: allDeviceIds,
value: true, // true (on) or false (off) depending on the event value
);
// Check if either response is unsuccessful, then reset to initial state
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
// In case of an error, delay and reset the screen to initial state
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
void _groupAllOff(GroupAllOffEvent event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
for (int i = 0; i < groupOneGangList.length; i++) {
groupOneGangList[i].firstSwitch = false;
}
// Emit the state with updated values
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: false));
// Get a list of all device IDs
List<String> allDeviceIds =
groupOneGangList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', // Controls first switch for all devices
devicesUuid: allDeviceIds,
value: false, // true (on) or false (off) depending on the event value
);
// Check if either response is unsuccessful, then reset to initial state
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
// In case of an error, delay and reset the screen to initial state
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
}

View File

@ -29,12 +29,12 @@ class ChangeFirstSwitchStatusEvent extends OneGangEvent {
class ChangeSecondSwitchStatusEvent extends OneGangEvent {
final bool value;
final String deviceId;
const ChangeSecondSwitchStatusEvent({required this.value, this.deviceId = ''});
const ChangeSecondSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class AllOffEvent extends OneGangEvent {}
class AllOnEvent extends OneGangEvent {}
@ -87,27 +87,29 @@ class StopTimer extends OneGangEvent {}
class OnClose extends OneGangEvent {}
class InitialWizardEvent extends OneGangEvent {}
//------------------- Schedule ----------=---------
class GetScheduleEvent extends OneGangEvent {}
class ScheduleSave extends OneGangEvent {}
class ToggleScheduleEvent extends OneGangEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle,required this.id});
const ToggleScheduleEvent({required this.toggle, required this.id});
@override
List<Object> get props => [toggle,id];
List<Object> get props => [toggle, id];
}
class ToggleDaySelectionEvent extends OneGangEvent {
class ToggleDaySelectionEvent extends OneGangEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
class DeleteScheduleEvent extends OneGangEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@ -115,7 +117,6 @@ class DeleteScheduleEvent extends OneGangEvent {
List<Object> get props => [id];
}
class ToggleSelectedEvent extends OneGangEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@ -123,10 +124,18 @@ class ToggleSelectedEvent extends OneGangEvent {
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends OneGangEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@override
List<Object> get props => [index];
}
class ChangeFirstWizardSwitchStatusEvent extends OneGangEvent {
final bool value;
final String deviceId;
const ChangeFirstWizardSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}

View File

@ -0,0 +1,539 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.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_event.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/group_one_touch_model.dart';
import 'package:syncrow_app/features/devices/model/one_touch_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';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
final String oneTouchId;
final String switchCode;
OneTouchModel deviceStatus = OneTouchModel(
firstSwitch: false,
firstCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off);
Timer? _timer;
bool oneTouchGroup = false;
List<DeviceModel> devicesList = [];
OneTouchBloc({required this.oneTouchId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchOneTouchStatus);
on<OneTouchUpdated>(_oneTouchUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
on<ChangeSlidingSegment>(_changeSliding);
on<SetCounterValue>(_setCounterValue);
on<GetCounterEvent>(_getCounterValue);
on<TickTimer>(_onTickTimer);
on<OnClose>(_onClose);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<ScheduleSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleChange);
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<InitialWizardEvent>(_fetchOneTouchWizardStatus);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ChangeStatusEvent>(_changeStatus);
}
void _fetchOneTouchStatus(
InitialEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(oneTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = OneTouchModel.fromJson(statusModelList);
emit(UpdateState(oneTouchModel: deviceStatus));
// _listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$oneTouchId');
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: element['value']));
});
deviceStatus = OneTouchModel.fromJson(statusList);
if (!isClosed) {
add(OneTouchUpdated());
}
});
} catch (_) {}
}
_oneTouchUpdated(OneTouchUpdated event, Emitter<OneTouchState> emit) {
emit(UpdateState(oneTouchModel: deviceStatus));
}
void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.value;
emit(UpdateState(oneTouchModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: oneTouchGroup ? event.deviceId : oneTouchId,
code: 'switch_1',
value: !event.value),
oneTouchGroup ? event.deviceId : oneTouchId);
if (!response['success']) {
add(InitialEvent(groupScreen: oneTouchGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: oneTouchGroup));
}
}
void _changeSliding(
ChangeSlidingSegment event, Emitter<OneTouchState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(
SetCounterValue event, Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: oneTouchId, code: event.deviceCode, value: seconds),
oneTouchId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown = seconds;
}
} else {
emit(const FailedState(error: 'Something went wrong'));
return;
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(
GetCounterEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(oneTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = OneTouchModel.fromJson(statusModelList);
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown > 0
? _onStartTimer(deviceStatus.firstCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _onClose(OnClose event, Emitter<OneTouchState> 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<OneTouchState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
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<OneTouchState> emit,
) async {
try {
if (selectedDays.isNotEmpty) {
emit(LoadingInitialState());
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: oneTouchId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(SaveSchedule());
add(const ToggleCreateScheduleEvent(index: 1));
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(FailedState(error: e.toString()));
}
}
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<OneTouchState> emit,
) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: oneTouchId,
);
List<dynamic> jsonData = response;
listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: 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<OneTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: oneTouchId, enable: event.toggle);
if (response == true) {
add(GetScheduleEvent());
toggleSchedule = event.toggle;
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<OneTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: oneTouchId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<OneTouchState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
List<ScheduleModel> listSchedule = [];
DateTime? selectedTime = DateTime.now();
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<OneTouchState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(ChangeSlidingSegment(value: 1));
}
int selectedTabIndex = 0;
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<OneTouchState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
List<GroupOneTouchModel> groupOneTouchList = [];
bool allSwitchesOn = true;
void _fetchOneTouchWizardStatus(
InitialWizardEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
groupOneTouchList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '1GT');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = OneTouchModel.fromJson(statusModelList);
groupOneTouchList.add(GroupOneTouchModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
));
}
if (groupOneTouchList.isNotEmpty) {
groupOneTouchList.firstWhere((element) {
if (!element.firstSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(
oneTouchList: groupOneTouchList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupOneTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch) {
allSwitchesValue = false;
}
});
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: [event.deviceId],
value: !event.value,
);
emit(UpdateGroupState(
oneTouchList: groupOneTouchList, allSwitches: allSwitchesValue));
if (response['success']) {
add(InitialEvent(groupScreen: oneTouchGroup));
}
} catch (_) {
add(InitialEvent(groupScreen: oneTouchGroup));
}
}
void _groupAllOn(GroupAllOnEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus));
try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
for (int i = 0; i < groupOneTouchList.length; i++) {
groupOneTouchList[i].firstSwitch = true;
}
// Emit the state with updated values
emit(
UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: true));
// Get a list of all device IDs
List<String> allDeviceIds =
groupOneTouchList.map((device) => device.deviceId).toList();
// First call for switch_1
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', // Controls first switch for all devices
devicesUuid: allDeviceIds,
value: true, // true (on) or false (off) depending on the event value
);
if (response1['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
emit(FailedState(error: _.toString()));
// In case of an error, delay and reset the screen to initial state
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
void _groupAllOff(GroupAllOffEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus));
try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
for (int i = 0; i < groupOneTouchList.length; i++) {
groupOneTouchList[i].firstSwitch = false;
}
// Emit the state with updated values
emit(UpdateGroupState(
oneTouchList: groupOneTouchList, allSwitches: false));
// Get a list of all device IDs
List<String> allDeviceIds =
groupOneTouchList.map((device) => device.deviceId).toList();
// First call for switch_1
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', // Controls first switch for all devices
devicesUuid: allDeviceIds,
value: false, // true (on) or false (off) depending on the event value
);
// Check if either response is unsuccessful, then reset to initial state
if (response1['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
emit(FailedState(error: _.toString()));
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
String statusSelected = '';
String optionSelected = '';
Future<void> _changeStatus(
ChangeStatusEvent event, Emitter<OneTouchState> emit) async {
try {
emit(LoadingInitialState());
final Map<String, Map<String, String>> controlMap = {
"relay_status": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"light_mode": {
'Off': 'none',
'On/Off Status': 'relay',
'Switch Position': 'pos',
},
"relay_status_1": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
};
final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: oneTouchId,
code: optionSelected,
value: selectedControl),
oneTouchId,
);
} else {
debugPrint('Invalid statusSelected or optionSelected');
}
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
}

View File

@ -0,0 +1,148 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
abstract class OneTouchEvent extends Equatable {
const OneTouchEvent();
@override
List<Object> get props => [];
}
class LoadingEvent extends OneTouchEvent {}
class OneTouchUpdated extends OneTouchEvent {}
class InitialEvent extends OneTouchEvent {
final bool groupScreen;
const InitialEvent({required this.groupScreen});
@override
List<Object> get props => [groupScreen];
}
class ChangeFirstSwitchStatusEvent extends OneTouchEvent {
final bool value;
final String deviceId;
const ChangeFirstSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeSecondSwitchStatusEvent extends OneTouchEvent {
final bool value;
final String deviceId;
const ChangeSecondSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class AllOffEvent extends OneTouchEvent {}
class AllOnEvent extends OneTouchEvent {}
class GroupAllOnEvent extends OneTouchEvent {}
class GroupAllOffEvent extends OneTouchEvent {}
class ChangeSlidingSegment extends OneTouchEvent {
final int value;
const ChangeSlidingSegment({required this.value});
@override
List<Object> get props => [value];
}
class GetCounterEvent extends OneTouchEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class SetCounterValue extends OneTouchEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends OneTouchEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends OneTouchEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends OneTouchEvent {}
class OnClose extends OneTouchEvent {}
class InitialWizardEvent extends OneTouchEvent {}
//------------------- Schedule ----------=---------
class GetScheduleEvent extends OneTouchEvent {}
class ScheduleSave extends OneTouchEvent {}
class ToggleScheduleEvent extends OneTouchEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle, required this.id});
@override
List<Object> get props => [toggle, id];
}
class ToggleDaySelectionEvent extends OneTouchEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
class DeleteScheduleEvent extends OneTouchEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@override
List<Object> get props => [id];
}
class ToggleSelectedEvent extends OneTouchEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@override
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends OneTouchEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@override
List<Object> get props => [index];
}
class ChangeFirstWizardSwitchStatusEvent extends OneTouchEvent {
final bool value;
final String deviceId;
const ChangeFirstWizardSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeStatusEvent extends OneTouchEvent {
final String deviceId;
final BuildContext context;
const ChangeStatusEvent({this.deviceId = '',required this.context});
}

View File

@ -0,0 +1,92 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/group_one_touch_model.dart';
import 'package:syncrow_app/features/devices/model/one_touch_model.dart';
class OneTouchState extends Equatable {
const OneTouchState();
@override
List<Object> get props => [];
}
class InitialState extends OneTouchState {}
class LoadingInitialState extends OneTouchState {}
class UpdateState extends OneTouchState {
final OneTouchModel oneTouchModel;
const UpdateState({required this.oneTouchModel});
@override
List<Object> get props => [oneTouchModel];
}
class LoadingNewSate extends OneTouchState {
final OneTouchModel oneTouchModel;
const LoadingNewSate({required this.oneTouchModel});
@override
List<Object> get props => [OneTouchModel];
}
class UpdateGroupState extends OneTouchState {
final List<GroupOneTouchModel> oneTouchList;
final bool allSwitches;
const UpdateGroupState({required this.oneTouchList, required this.allSwitches});
@override
List<Object> get props => [oneTouchList, allSwitches];
}
class FailedState extends OneTouchState {
final String error;
const FailedState({required this.error});
@override
List<Object> get props => [error];
}
class ChangeSlidingSegmentState extends OneTouchState {
final int value;
const ChangeSlidingSegmentState({required this.value});
@override
List<Object> get props => [value];
}
class UpdateTimerState extends OneTouchState {
final int seconds;
const UpdateTimerState({required this.seconds});
@override
List<Object> get props => [seconds];
}
class TimerRunInProgress extends OneTouchState {
final int remainingTime;
const TimerRunInProgress(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class TimerRunComplete extends OneTouchState {}
class SaveSchedule extends OneTouchState {}
class IsToggleState extends OneTouchState {
final bool? onOff;
const IsToggleState({this.onOff});
}
class ChangeTimeState extends OneTouchState {}
class UpdateCreateScheduleState extends OneTouchState {
final bool createSchedule;
UpdateCreateScheduleState(this.createSchedule);
}

View File

@ -37,7 +37,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
on<SelectTimeEvent>(selectTimeOfLinePassword);
on<SelectTimeOnlinePasswordEvent>(selectTimeOnlinePassword);
on<DeletePasswordEvent>(deletePassword);
on<GenerateAndSavePasswordTimeLimitEvent>(generateAndSavePasswordTimeLimited);
on<GenerateAndSavePasswordTimeLimitEvent>(
generateAndSavePasswordTimeLimited);
on<GenerateAndSavePasswordOneTimeEvent>(generateAndSavePasswordOneTime);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<RenamePasswordEvent>(_renamePassword);
@ -59,7 +60,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
List<OfflinePasswordModel>? oneTimePasswords = [];
List<OfflinePasswordModel>? timeLimitPasswords = [];
Future generate7DigitNumber(GeneratePasswordEvent event, Emitter<SmartDoorState> emit) async {
Future generate7DigitNumber(
GeneratePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(LoadingInitialState());
passwordController.clear();
Random random = Random();
@ -71,7 +73,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
Future generateAndSavePasswordOneTime(
GenerateAndSavePasswordOneTimeEvent event, Emitter<SmartDoorState> emit) async {
GenerateAndSavePasswordOneTimeEvent event,
Emitter<SmartDoorState> emit) async {
try {
if (isSavingPassword) return;
isSavingPassword = true;
@ -92,7 +95,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
}
void _fetchSmartDoorStatus(InitialEvent event, Emitter<SmartDoorState> emit) async {
void _fetchSmartDoorStatus(
InitialEvent event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.getDeviceStatus(deviceId);
@ -102,7 +106,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
deviceStatus = SmartDoorModel.fromJson(statusModelList);
emit(UpdateState(smartDoorModel: deviceStatus));
_listenToChanges();
// _listenToChanges();
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
return;
@ -111,15 +115,18 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) {
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 = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value']));
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = SmartDoorModel.fromJson(statusList);
@ -133,11 +140,14 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
emit(UpdateState(smartDoorModel: deviceStatus));
}
void _renamePassword(RenamePasswordEvent event, Emitter<SmartDoorState> emit) async {
void _renamePassword(
RenamePasswordEvent event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
await DevicesAPI.renamePass(
name: passwordNameController.text, doorLockUuid: deviceId, passwordId: passwordId);
name: passwordNameController.text,
doorLockUuid: deviceId,
passwordId: passwordId);
add(InitialOneTimePassword());
add(InitialTimeLimitPassword());
emit(UpdateState(smartDoorModel: deviceStatus));
@ -147,46 +157,58 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
}
void getTemporaryPasswords(InitialPasswordsPage event, Emitter<SmartDoorState> emit) async {
void getTemporaryPasswords(
InitialPasswordsPage event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.getTemporaryPasswords(
deviceId,
);
if (response is List) {
temporaryPasswords = response.map((item) => TemporaryPassword.fromJson(item)).toList();
} else if (response is Map && response.containsKey('data')) {
temporaryPasswords =
(response['data'] as List).map((item) => TemporaryPassword.fromJson(item)).toList();
response.map((item) => TemporaryPassword.fromJson(item)).toList();
} else if (response is Map && response.containsKey('data')) {
temporaryPasswords = (response['data'] as List)
.map((item) => TemporaryPassword.fromJson(item))
.toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
emit(TemporaryPasswordsLoadedState(
temporaryPassword: temporaryPasswords!));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
}
}
void getOneTimePasswords(InitialOneTimePassword event, Emitter<SmartDoorState> emit) async {
void getOneTimePasswords(
InitialOneTimePassword event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.getOneTimePasswords(deviceId);
if (response is List) {
oneTimePasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList();
oneTimePasswords = response
.map((item) => OfflinePasswordModel.fromJson(item))
.toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
emit(TemporaryPasswordsLoadedState(
temporaryPassword: temporaryPasswords!));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
}
}
void getTimeLimitPasswords(InitialTimeLimitPassword event, Emitter<SmartDoorState> emit) async {
void getTimeLimitPasswords(
InitialTimeLimitPassword event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.getTimeLimitPasswords(deviceId);
if (response is List) {
timeLimitPasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList();
timeLimitPasswords = response
.map((item) => OfflinePasswordModel.fromJson(item))
.toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
emit(TemporaryPasswordsLoadedState(
temporaryPassword: temporaryPasswords!));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
}
@ -207,7 +229,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
return repeat;
}
bool setStartEndTime(SetStartEndTimeEvent event, Emitter<SmartDoorState> emit) {
bool setStartEndTime(
SetStartEndTimeEvent event, Emitter<SmartDoorState> emit) {
emit(LoadingInitialState());
isStartEndTime = event.val;
emit(IsStartEndState(isStartEndTime: isStartEndTime));
@ -230,7 +253,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
emit(UpdateState(smartDoorModel: deviceStatus));
}
Future<void> selectTimeOfLinePassword(SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
Future<void> selectTimeOfLinePassword(
SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState());
final DateTime? picked = await showDatePicker(
context: event.context,
@ -260,20 +284,27 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isEffective) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
if (expirationTimeTimeStamp != null &&
selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
} else {
effectiveTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
effectiveTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
} else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
if (effectiveTimeTimeStamp != null &&
selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else {
expirationTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
}
@ -329,20 +360,27 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isEffective) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
if (expirationTimeTimeStamp != null &&
selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
} else {
effectiveTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
effectiveTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
} else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
if (effectiveTimeTimeStamp != null &&
selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else {
expirationTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
}
@ -351,7 +389,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
}
Future<void> savePassword(SavePasswordEvent event, Emitter<SmartDoorState> emit) async {
Future<void> savePassword(
SavePasswordEvent event, Emitter<SmartDoorState> emit) async {
if (_validateInputs() || isSavingPassword) return;
try {
isSavingPassword = true;
@ -381,7 +420,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
Future<void> generateAndSavePasswordTimeLimited(
GenerateAndSavePasswordTimeLimitEvent event, Emitter<SmartDoorState> emit) async {
GenerateAndSavePasswordTimeLimitEvent event,
Emitter<SmartDoorState> emit) async {
if (timeLimitValidate() || isSavingPassword) return;
try {
isSavingPassword = true;
@ -407,10 +447,12 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
}
Future<void> deletePassword(DeletePasswordEvent event, Emitter<SmartDoorState> emit) async {
Future<void> deletePassword(
DeletePasswordEvent event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
await DevicesAPI.deletePassword(deviceId: deviceId, passwordId: event.passwordId)
await DevicesAPI.deletePassword(
deviceId: deviceId, passwordId: event.passwordId)
.then((value) async {
add(InitialPasswordsPage());
});
@ -445,7 +487,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
if (repeat == true && (endTime == null || startTime == null)) {
CustomSnackBar.displaySnackBar('Start Time and End time and the days required ');
CustomSnackBar.displaySnackBar(
'Start Time and End time and the days required ');
return true;
}
return false;

View File

@ -25,9 +25,6 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
secondCountDown: 0,
thirdCountDown: 0);
Timer? _timer;
// Timer? _firstSwitchTimer;
// Timer? _secondSwitchTimer;
// Timer? _thirdSwitchTimer;
bool threeGangGroup = false;
List<DeviceModel> devicesList = [];
@ -104,7 +101,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
}
deviceStatus = ThreeGangModel.fromJson(statusModelList);
emit(UpdateState(threeGangModel: deviceStatus));
_listenToChanges();
// _listenToChanges();
}
} catch (e) {
emit(FailedState(error: e.toString()));
@ -163,7 +160,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeGangGroup ? event.deviceId : threeGangId,
@ -203,7 +200,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeGangGroup ? event.deviceId : threeGangId,
@ -243,7 +240,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeGangGroup ? event.deviceId : threeGangId,
@ -338,27 +335,29 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
}
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: true));
for (int i = 0; i < groupThreeGangList.length; i++) {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeGangList[i].deviceId, code: 'switch_1', value: true),
groupThreeGangList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeGangList[i].deviceId, code: 'switch_2', value: true),
groupThreeGangList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeGangList[i].deviceId, code: 'switch_3', value: true),
groupThreeGangList[i].deviceId),
]);
List<String> allDeviceIds = groupThreeGangList.map((device) => device.deviceId).toList();
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
break;
}
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: true,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: true,
);
final response3 = await DevicesAPI.deviceBatchController(
code: 'switch_3',
devicesUuid: allDeviceIds,
value: true,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]' ||
response3['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
@ -375,28 +374,29 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
groupThreeGangList[i].thirdSwitch = false;
}
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: false));
List<String> allDeviceIds = groupThreeGangList.map((device) => device.deviceId).toList();
for (int i = 0; i < groupThreeGangList.length; i++) {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeGangList[i].deviceId, code: 'switch_1', value: false),
groupThreeGangList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeGangList[i].deviceId, code: 'switch_2', value: false),
groupThreeGangList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeGangList[i].deviceId, code: 'switch_3', value: false),
groupThreeGangList[i].deviceId),
]);
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: false,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: false,
);
final response3 = await DevicesAPI.deviceBatchController(
code: 'switch_3',
devicesUuid: allDeviceIds,
value: false,
);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
break;
}
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]' ||
response3['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
@ -531,7 +531,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(ThreeGangSaveSchedule());
add(const ToggleCreateScheduleEvent(index:1 ));
add(const ToggleCreateScheduleEvent(index: 1));
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
@ -606,38 +606,19 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
}
}
// void toggleCreateSchedule() {
// emit(LoadingInitialState());
// createSchedule = !createSchedule;
// selectedDays.clear();
// selectedTime = DateTime.now();
// emit(UpdateCreateScheduleState(createSchedule));
// emit(ChangeSlidingSegmentState(value: 1));
// }
// void toggleSelectedIndex(index) {
// emit(LoadingInitialState());
// selectedTabIndex = index;
// emit(ChangeSlidingSegmentState(value: selectedTabIndex));
// }
void toggleSelectedIndex( ToggleSelectedEvent event, Emitter<ThreeGangState> emit) {
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<ThreeGangState> emit) {
emit(LoadingInitialState());
selectedTabIndex =event.index;
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<ThreeGangState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<ThreeGangState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
int selectedTabIndex = 0;
bool toggleSchedule = true;

View File

@ -135,4 +135,6 @@ class ToggleCreateScheduleEvent extends ThreeGangEvent {
const ToggleCreateScheduleEvent({required this.index});
@override
List<Object> get props => [index];
}
}
class InitialWizardDevises extends ThreeGangEvent {}

View File

@ -0,0 +1,682 @@
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/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_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/group_three_touch_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/three_touch_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
final String threeTouchId;
final String switchCode;
ThreeTouchModel deviceStatus = ThreeTouchModel(
firstSwitch: false,
secondSwitch: false,
thirdSwitch: false,
firstCountDown: 0,
secondCountDown: 0,
thirdCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off,
relay_status_2: status.off,
relay_status_3: status.off,
);
Timer? _timer;
bool threeTouchGroup = false;
List<DeviceModel> devicesList = [];
List<GroupThreeTouchModel> groupThreeTouchList = [];
bool allSwitchesOn = true;
ThreeTouchBloc({required this.threeTouchId, required this.switchCode}) : super(InitialState()) {
on<InitialEvent>(_fetchThreeTouchStatus);
on<ThreeTouchUpdated>(_threeTouchUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
on<ChangeSecondSwitchStatusEvent>(_changeSecondSwitch);
on<ChangeThirdSwitchStatusEvent>(_changeThirdSwitch);
on<AllOffEvent>(_allOff);
on<AllOnEvent>(_allOn);
on<ChangeSlidingSegment>(_changeSliding);
on<SetCounterValue>(_setCounterValue);
on<GetCounterEvent>(_getCounterValue);
on<TickTimer>(_onTickTimer);
on<OnClose>(_onClose);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<ThreeTouchSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleChange);
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<ChangeStatusEvent>(_changeStatus);
}
void _fetchThreeTouchStatus(InitialEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingInitialState());
try {
threeTouchGroup = event.groupScreen;
if (threeTouchGroup) {
devicesList = [];
groupThreeTouchList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '3GT');
for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = ThreeTouchModel.fromJson(statusModelList);
groupThreeTouchList.add(GroupThreeTouchModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
secondSwitch: deviceStatus.secondSwitch,
thirdSwitch: deviceStatus.thirdSwitch));
}
if (groupThreeTouchList.isNotEmpty) {
groupThreeTouchList.firstWhere((element) {
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesOn));
} else {
var response = await DevicesAPI.getDeviceStatus(threeTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = ThreeTouchModel.fromJson(statusModelList);
emit(UpdateState(threeTouchModel: deviceStatus));
// _listenToChanges();
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$threeTouchId');
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: element['value']));
});
deviceStatus = ThreeTouchModel.fromJson(statusList);
if (!isClosed) {
add(ThreeTouchUpdated());
}
});
} catch (_) {}
}
_threeTouchUpdated(ThreeTouchUpdated event, Emitter<ThreeTouchState> emit) {
emit(UpdateState(threeTouchModel: deviceStatus));
}
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
if (threeTouchGroup) {
bool allSwitchesValue = true;
groupThreeTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesValue));
} else {
deviceStatus.firstSwitch = !event.value;
emit(UpdateState(threeTouchModel: deviceStatus));
}
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchGroup ? event.deviceId : threeTouchId,
code: 'switch_1',
value: !event.value),
threeTouchGroup ? event.deviceId : threeTouchId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
}
void _changeSecondSwitch(
ChangeSecondSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
if (threeTouchGroup) {
bool allSwitchesValue = true;
groupThreeTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.secondSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesValue));
} else {
deviceStatus.secondSwitch = !event.value;
emit(UpdateState(threeTouchModel: deviceStatus));
}
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchGroup ? event.deviceId : threeTouchId,
code: 'switch_2',
value: !event.value),
threeTouchGroup ? event.deviceId : threeTouchId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
}
void _changeThirdSwitch(ChangeThirdSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
if (threeTouchGroup) {
bool allSwitchesValue = true;
groupThreeTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.thirdSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesValue));
} else {
deviceStatus.thirdSwitch = !event.value;
emit(UpdateState(threeTouchModel: deviceStatus));
}
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchGroup ? event.deviceId : threeTouchId,
code: 'switch_3',
value: !event.value),
threeTouchGroup ? event.deviceId : threeTouchId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
}
void _allOff(AllOffEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = false;
deviceStatus.secondSwitch = false;
deviceStatus.thirdSwitch = false;
emit(UpdateState(threeTouchModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId, code: 'switch_1', value: deviceStatus.firstSwitch),
threeTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId, code: 'switch_2', value: deviceStatus.secondSwitch),
threeTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId, code: 'switch_3', value: deviceStatus.thirdSwitch),
threeTouchId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
}
void _allOn(AllOnEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = true;
deviceStatus.secondSwitch = true;
deviceStatus.thirdSwitch = true;
emit(UpdateState(threeTouchModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId, code: 'switch_1', value: deviceStatus.firstSwitch),
threeTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId, code: 'switch_2', value: deviceStatus.secondSwitch),
threeTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId, code: 'switch_3', value: deviceStatus.thirdSwitch),
threeTouchId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
}
void _groupAllOn(GroupAllOnEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
for (int i = 0; i < groupThreeTouchList.length; i++) {
groupThreeTouchList[i].firstSwitch = true;
groupThreeTouchList[i].secondSwitch = true;
groupThreeTouchList[i].thirdSwitch = true;
}
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: true));
List<String> allDeviceIds = groupThreeTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: true,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: true,
);
final response3 = await DevicesAPI.deviceBatchController(
code: 'switch_3',
devicesUuid: allDeviceIds,
value: true,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]' ||
response3['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
void _groupAllOff(GroupAllOffEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
for (int i = 0; i < groupThreeTouchList.length; i++) {
groupThreeTouchList[i].firstSwitch = false;
groupThreeTouchList[i].secondSwitch = false;
groupThreeTouchList[i].thirdSwitch = false;
}
List<String> allDeviceIds = groupThreeTouchList.map((device) => device.deviceId).toList();
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: false));
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: false,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: false,
);
final response3 = await DevicesAPI.deviceBatchController(
code: 'switch_3',
devicesUuid: allDeviceIds,
value: false,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]' ||
response3['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
void _changeSliding(ChangeSlidingSegment event, Emitter<ThreeTouchState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(SetCounterValue event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: threeTouchId, code: event.deviceCode, value: seconds),
threeTouchId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown = seconds;
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown = seconds;
} else if (event.deviceCode == 'countdown_3') {
deviceStatus.thirdCountDown = seconds;
}
} else {
emit(const FailedState(error: 'Something went wrong'));
return;
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(GetCounterEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(threeTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = ThreeTouchModel.fromJson(statusModelList);
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown > 0
? _onStartTimer(deviceStatus.firstCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown > 0
? _onStartTimer(deviceStatus.secondCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.secondCountDown));
} else if (event.deviceCode == 'countdown_3') {
deviceStatus.thirdCountDown > 0
? _onStartTimer(deviceStatus.thirdCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.thirdCountDown));
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _onClose(OnClose event, Emitter<ThreeTouchState> 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<ThreeTouchState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
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<ThreeTouchState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(ChangeSlidingSegment(value: 1));
}
Future<void> saveSchedule(
ThreeTouchSave event,
Emitter<ThreeTouchState> emit,
) async {
try {
if (selectedDays.isNotEmpty) {
emit(LoadingInitialState());
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: threeTouchId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(ThreeTouchSaveSchedule());
add(const ToggleCreateScheduleEvent(index: 1));
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(FailedState(error: e.toString()));
}
}
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<ThreeTouchState> emit,
) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: threeTouchId,
);
List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: 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<ThreeTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: threeTouchId, enable: event.toggle);
if (response == true) {
add(GetScheduleEvent());
toggleSchedule = event.toggle;
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
Future deleteSchedule(DeleteScheduleEvent event, Emitter<ThreeTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: threeTouchId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<ThreeTouchState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<ThreeTouchState> emit) {
emit(LoadingInitialState());
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();
String statusSelected = '';
String optionSelected = '';
Future<void> _changeStatus(ChangeStatusEvent event, Emitter<ThreeTouchState> emit) async {
try {
emit(LoadingInitialState());
final Map<String, Map<String, String>> controlMap = {
"relay_status": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"light_mode": {
'Off': 'none',
'On/Off Status': 'relay',
'Switch Position': 'pos',
},
"relay_status_1": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"relay_status_2": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"relay_status_3": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
};
final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) {
await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: threeTouchId, code: optionSelected, value: selectedControl),
threeTouchId,
);
} else {
emit(const FailedState(error: 'Invalid statusSelected or optionSelected'));
}
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
}

View File

@ -0,0 +1,147 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
abstract class ThreeTouchEvent extends Equatable {
const ThreeTouchEvent();
@override
List<Object> get props => [];
}
class LoadingEvent extends ThreeTouchEvent {}
class ThreeTouchUpdated extends ThreeTouchEvent {}
class InitialEvent extends ThreeTouchEvent {
final bool groupScreen;
const InitialEvent({required this.groupScreen});
@override
List<Object> get props => [groupScreen];
}
class ChangeFirstSwitchStatusEvent extends ThreeTouchEvent {
final bool value;
final String deviceId;
const ChangeFirstSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeSecondSwitchStatusEvent extends ThreeTouchEvent {
final bool value;
final String deviceId;
const ChangeSecondSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeThirdSwitchStatusEvent extends ThreeTouchEvent {
final bool value;
final String deviceId;
const ChangeThirdSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class AllOffEvent extends ThreeTouchEvent {}
class AllOnEvent extends ThreeTouchEvent {}
class GroupAllOnEvent extends ThreeTouchEvent {}
class GroupAllOffEvent extends ThreeTouchEvent {}
class ChangeSlidingSegment extends ThreeTouchEvent {
final int value;
const ChangeSlidingSegment({required this.value});
@override
List<Object> get props => [value];
}
class GetCounterEvent extends ThreeTouchEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class SetCounterValue extends ThreeTouchEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends ThreeTouchEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends ThreeTouchEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends ThreeTouchEvent {}
class OnClose extends ThreeTouchEvent {}
//------------------- Schedule ----------=---------
class GetScheduleEvent extends ThreeTouchEvent {}
class ThreeTouchSave extends ThreeTouchEvent {}
class ToggleScheduleEvent extends ThreeTouchEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle, required this.id});
@override
List<Object> get props => [toggle, id];
}
class ToggleDaySelectionEvent extends ThreeTouchEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
class DeleteScheduleEvent extends ThreeTouchEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@override
List<Object> get props => [id];
}
class ToggleSelectedEvent extends ThreeTouchEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@override
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends ThreeTouchEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@override
List<Object> get props => [index];
}
class InitialWizardDevises extends ThreeTouchEvent {}
class ChangeStatusEvent extends ThreeTouchEvent {
final String deviceId;
final BuildContext context;
const ChangeStatusEvent({this.deviceId = '', required this.context});
}

View File

@ -0,0 +1,96 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/group_three_touch_model.dart';
import 'package:syncrow_app/features/devices/model/three_touch_model.dart';
class ThreeTouchState extends Equatable {
const ThreeTouchState();
@override
List<Object> get props => [];
}
class InitialState extends ThreeTouchState {}
class LoadingInitialState extends ThreeTouchState {}
class UpdateState extends ThreeTouchState {
final ThreeTouchModel threeTouchModel;
const UpdateState({required this.threeTouchModel});
@override
List<Object> get props => [threeTouchModel];
}
class LoadingNewSate extends ThreeTouchState {
final ThreeTouchModel threeTouchModel;
const LoadingNewSate({required this.threeTouchModel});
@override
List<Object> get props => [threeTouchModel];
}
class UpdateGroupState extends ThreeTouchState {
final List<GroupThreeTouchModel> threeTouchList;
final bool allSwitches;
const UpdateGroupState(
{required this.threeTouchList, required this.allSwitches});
@override
List<Object> get props => [threeTouchList, allSwitches];
}
class FailedState extends ThreeTouchState {
final String error;
const FailedState({required this.error});
@override
List<Object> get props => [error];
}
class ChangeSlidingSegmentState extends ThreeTouchState {
final int value;
const ChangeSlidingSegmentState({required this.value});
@override
List<Object> get props => [value];
}
class UpdateTimerState extends ThreeTouchState {
final int seconds;
const UpdateTimerState({required this.seconds});
@override
List<Object> get props => [seconds];
}
class TimerRunInProgress extends ThreeTouchState {
final int remainingTime;
const TimerRunInProgress(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class TimerRunComplete extends ThreeTouchState {}
class ThreeTouchSaveSchedule extends ThreeTouchState {}
class IsToggleState extends ThreeTouchState {
final bool? onOff;
const IsToggleState({this.onOff});
}
class ChangeTimeState extends ThreeTouchState {}
class UpdateCreateScheduleState extends ThreeTouchState {
final bool createSchedule;
UpdateCreateScheduleState(this.createSchedule);
}
class ChangeStateSetting extends ThreeTouchState {
const ChangeStateSetting();
}

View File

@ -35,8 +35,7 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
bool createSchedule = false;
List<ScheduleModel> listSchedule = [];
TwoGangBloc({required this.twoGangId, required this.switchCode})
: super(InitialState()) {
TwoGangBloc({required this.twoGangId, required this.switchCode}) : super(InitialState()) {
on<InitialEvent>(_fetchTwoGangStatus);
on<TwoGangUpdated>(_twoGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -57,36 +56,22 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<InitialWizardEvent>(_fetchTwoGangWizardStatus);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<ChangeSecondWizardSwitchStatusEvent>(_changeSecondWizardSwitch);
}
DateTime? selectedTime = DateTime.now();
// void toggleCreateSchedule() {
// emit(LoadingInitialState());
// createSchedule = !createSchedule;
// selectedDays.clear();
// selectedTime = DateTime.now();
// emit(UpdateCreateScheduleState(createSchedule));
// emit(ChangeSlidingSegmentState(value: 1));
// }
int selectedTabIndex = 0;
// void toggleSelectedIndex(index) {
// emit(LoadingInitialState());
// selectedTabIndex = index;
// emit(ChangeSlidingSegmentState(value: selectedTabIndex));
// }
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<TwoGangState> emit) {
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<TwoGangState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<TwoGangState> emit) {
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<TwoGangState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
@ -94,55 +79,17 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
emit(UpdateCreateScheduleState(createSchedule));
}
void _fetchTwoGangStatus(
InitialEvent event, Emitter<TwoGangState> emit) async {
void _fetchTwoGangStatus(InitialEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState());
try {
twoGangGroup = event.groupScreen;
if (twoGangGroup) {
devicesList = [];
groupTwoGangList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '2G');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoGangModel.fromJson(statusModelList);
groupTwoGangList.add(GroupTwoGangModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
secondSwitch: deviceStatus.secondSwitch,
));
}
if (groupTwoGangList.isNotEmpty) {
groupTwoGangList.firstWhere((element) {
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(
twoGangList: groupTwoGangList, allSwitches: allSwitchesOn));
} else {
var response = await DevicesAPI.getDeviceStatus(twoGangId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoGangModel.fromJson(statusModelList);
emit(UpdateState(twoGangModel: deviceStatus));
_listenToChanges();
var response = await DevicesAPI.getDeviceStatus(twoGangId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoGangModel.fromJson(statusModelList);
emit(UpdateState(twoGangModel: deviceStatus));
// _listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
@ -151,21 +98,18 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$twoGangId');
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$twoGangId');
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>;
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: element['value']));
statusList.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = TwoGangModel.fromJson(statusList);
@ -180,8 +124,7 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
emit(UpdateState(twoGangModel: deviceStatus));
}
void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.value;
@ -190,25 +133,21 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangGroup ? event.deviceId : twoGangId,
code: 'switch_1',
value: !event.value),
twoGangGroup ? event.deviceId : twoGangId);
DeviceControlModel(deviceId: twoGangId, code: 'switch_1', value: !event.value),
twoGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: twoGangGroup));
add(const InitialEvent());
}
});
} catch (_) {
add(InitialEvent(groupScreen: twoGangGroup));
add(const InitialEvent());
}
}
void _changeSecondSwitch(
ChangeSecondSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
deviceStatus.secondSwitch = !event.value;
@ -216,20 +155,17 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangGroup ? event.deviceId : twoGangId,
code: 'switch_2',
value: !event.value),
twoGangGroup ? event.deviceId : twoGangId);
DeviceControlModel(deviceId: twoGangId, code: 'switch_2', value: !event.value),
twoGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: twoGangGroup));
add(const InitialEvent());
}
});
} catch (_) {
add(InitialEvent(groupScreen: twoGangGroup));
add(const InitialEvent());
}
}
@ -244,25 +180,21 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch),
twoGangId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch),
twoGangId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
add(const InitialEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
add(const InitialEvent());
}
}
@ -275,24 +207,20 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch),
twoGangId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch),
twoGangId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
add(const InitialEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
add(const InitialEvent());
}
}
@ -304,32 +232,28 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
groupTwoGangList[i].secondSwitch = true;
}
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: true));
List<String> allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList();
for (int i = 0; i < groupTwoGangList.length; i++) {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupTwoGangList[i].deviceId,
code: 'switch_1',
value: true),
groupTwoGangList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupTwoGangList[i].deviceId,
code: 'switch_2',
value: true),
groupTwoGangList[i].deviceId),
]);
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: true,
);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
break;
}
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: true,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
add(InitialWizardEvent());
}
}
@ -340,50 +264,45 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
groupTwoGangList[i].firstSwitch = false;
groupTwoGangList[i].secondSwitch = false;
}
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: false));
for (int i = 0; i < groupTwoGangList.length; i++) {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupTwoGangList[i].deviceId,
code: 'switch_1',
value: false),
groupTwoGangList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupTwoGangList[i].deviceId,
code: 'switch_2',
value: false),
groupTwoGangList[i].deviceId),
]);
List<String> allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList();
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
break;
}
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: false,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: false,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
add(InitialWizardEvent());
}
}
void _changeSliding(
ChangeSlidingSegment event, Emitter<TwoGangState> emit) async {
void _changeSliding(ChangeSlidingSegment event, Emitter<TwoGangState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(
SetCounterValue event, Emitter<TwoGangState> emit) async {
void _setCounterValue(SetCounterValue event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId, code: event.deviceCode, value: seconds),
DeviceControlModel(deviceId: twoGangId, code: event.deviceCode, value: seconds),
twoGangId);
if (response['success'] ?? false) {
@ -408,8 +327,7 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
}
}
void _getCounterValue(
GetCounterEvent event, Emitter<TwoGangState> emit) async {
void _getCounterValue(GetCounterEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState());
try {
add(GetScheduleEvent());
@ -476,7 +394,7 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(ChangeSlidingSegment(value: 1));
add(const ChangeSlidingSegment(value: 1));
}
Future<void> saveSchedule(
@ -486,7 +404,7 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
try {
if (selectedDays.isNotEmpty) {
emit(LoadingInitialState());
final response = await DevicesAPI.postSchedule(
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: twoGangId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
@ -517,8 +435,7 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
deviceId: twoGangId,
);
List<dynamic> jsonData = response;
listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
@ -529,13 +446,12 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
dateTime.day, dateTime.hour, dateTime.minute);
DateTime dateTimeWithoutSeconds =
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
}
Future toggleRepeat(
ToggleScheduleEvent event, Emitter<TwoGangState> emit) async {
Future toggleRepeat(ToggleScheduleEvent event, Emitter<TwoGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
@ -554,8 +470,7 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<TwoGangState> emit) async {
Future deleteSchedule(DeleteScheduleEvent event, Emitter<TwoGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
@ -574,4 +489,106 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
emit(FailedState(error: errorMessage.toString()));
}
}
void _fetchTwoGangWizardStatus(InitialWizardEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
groupTwoGangList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '2G');
for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoGangModel.fromJson(statusModelList);
groupTwoGangList.add(GroupTwoGangModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
secondSwitch: deviceStatus.secondSwitch,
));
}
if (groupTwoGangList.isNotEmpty) {
groupTwoGangList.firstWhere((element) {
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _changeFirstWizardSwitch(
ChangeFirstWizardSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupTwoGangList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesValue));
List<String> allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
void _changeSecondWizardSwitch(
ChangeSecondWizardSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupTwoGangList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.secondSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesValue = false;
}
});
List<String> allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList();
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
}

View File

@ -10,17 +10,20 @@ abstract class TwoGangEvent extends Equatable {
class LoadingEvent extends TwoGangEvent {}
class TwoGangUpdated extends TwoGangEvent {}
class TwoGangSave extends TwoGangEvent {}
class ToggleScheduleEvent extends TwoGangEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle,required this.id});
const ToggleScheduleEvent({required this.toggle, required this.id});
@override
List<Object> get props => [toggle,id];
List<Object> get props => [toggle, id];
}
class errorMessage extends TwoGangEvent {}
class ToggleDaySelectionEvent extends TwoGangEvent {
class errorMessage extends TwoGangEvent {}
class ToggleDaySelectionEvent extends TwoGangEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@ -29,10 +32,9 @@ class ToggleDaySelectionEvent extends TwoGangEvent {
}
class InitialEvent extends TwoGangEvent {
final bool groupScreen;
const InitialEvent({required this.groupScreen});
const InitialEvent();
@override
List<Object> get props => [groupScreen];
List<Object> get props => [];
}
class ChangeFirstSwitchStatusEvent extends TwoGangEvent {
@ -51,7 +53,6 @@ class ChangeSecondSwitchStatusEvent extends TwoGangEvent {
List<Object> get props => [value, deviceId];
}
class AllOffEvent extends TwoGangEvent {}
class AllOnEvent extends TwoGangEvent {}
@ -60,13 +61,9 @@ class GroupAllOnEvent extends TwoGangEvent {}
class GroupAllOffEvent extends TwoGangEvent {}
// two_gang_event.dart
// class ToggleCreateScheduleEvent extends TwoGangEvent {}
class ChangeSlidingSegment extends TwoGangEvent {
final int value;
const ChangeSlidingSegment({required this.value});
@ -111,20 +108,20 @@ class StopTimer extends TwoGangEvent {}
class OnClose extends TwoGangEvent {}
class GetScheduleEvent extends TwoGangEvent {}
class DeleteScheduleEvent extends TwoGangEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@override
List<Object> get props => [id];
}
class TabChangedEvent extends TwoGangEvent {
final int index;
TabChangedEvent({required this.index});
}
class ToggleSelectedEvent extends TwoGangEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@ -132,7 +129,6 @@ class ToggleSelectedEvent extends TwoGangEvent {
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends TwoGangEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@ -140,5 +136,20 @@ class ToggleCreateScheduleEvent extends TwoGangEvent {
List<Object> get props => [index];
}
class InitialWizardEvent extends TwoGangEvent {}
class ChangeFirstWizardSwitchStatusEvent extends TwoGangEvent {
final bool value;
final String deviceId;
const ChangeFirstWizardSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeSecondWizardSwitchStatusEvent extends TwoGangEvent {
final bool value;
final String deviceId;
const ChangeSecondWizardSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}

View File

@ -0,0 +1,642 @@
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/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_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/group_two_touch_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/two_touch_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
final String twoTouchId;
final String switchCode;
TwoTouchModel deviceStatus = TwoTouchModel(
firstSwitch: false,
secondSwitch: false,
firstCountDown: 0,
secondCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off,
relay_status_2: status.off,
);
Timer? _timer;
bool twoTouchGroup = false;
List<DeviceModel> devicesList = [];
List<GroupTwoTouchModel> groupTwoTouchList = [];
bool allSwitchesOn = true;
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
List<ScheduleModel> listSchedule = [];
TwoTouchBloc({required this.twoTouchId, required this.switchCode}) : super(InitialState()) {
on<InitialEvent>(_fetchTwoTouchStatus);
on<TwoTouchUpdated>(_twoTouchUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
on<ChangeSecondSwitchStatusEvent>(_changeSecondSwitch);
on<AllOffEvent>(_allOff);
on<AllOnEvent>(_allOn);
on<ChangeSlidingSegment>(_changeSliding);
on<SetCounterValue>(_setCounterValue);
on<GetCounterEvent>(_getCounterValue);
on<TickTimer>(_onTickTimer);
on<OnClose>(_onClose);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<TwoTouchSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleRepeat);
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<InitialWizardEvent>(_fetchTwoTouchWizardStatus);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<ChangeSecondWizardSwitchStatusEvent>(_changeSecondWizardSwitch);
on<ChangeStatusEvent>(_changeStatus);
}
DateTime? selectedTime = DateTime.now();
int selectedTabIndex = 0;
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<TwoTouchState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<TwoTouchState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
void _fetchTwoTouchStatus(InitialEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(twoTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoTouchModel.fromJson(statusModelList);
emit(UpdateState(twoTouchModel: deviceStatus));
// _listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$twoTouchId');
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: element['value']));
});
deviceStatus = TwoTouchModel.fromJson(statusList);
if (!isClosed) {
add(TwoTouchUpdated());
}
});
} catch (_) {}
}
_twoTouchUpdated(TwoTouchUpdated event, Emitter<TwoTouchState> emit) {
emit(UpdateState(twoTouchModel: deviceStatus));
}
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.value;
emit(UpdateState(twoTouchModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoTouchId, code: 'switch_1', value: !event.value),
twoTouchId);
if (!response['success']) {
add(const InitialEvent());
}
});
} catch (_) {
add(const InitialEvent());
}
}
void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.secondSwitch = !event.value;
emit(UpdateState(twoTouchModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoTouchId, code: 'switch_2', value: !event.value),
twoTouchId);
if (!response['success']) {
add(const InitialEvent());
}
});
} catch (_) {
add(const InitialEvent());
}
}
void _allOff(AllOffEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = false;
deviceStatus.secondSwitch = false;
emit(UpdateState(twoTouchModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId, code: 'switch_1', value: deviceStatus.firstSwitch),
twoTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId, code: 'switch_2', value: deviceStatus.secondSwitch),
twoTouchId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
}
void _allOn(AllOnEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = true;
deviceStatus.secondSwitch = true;
emit(UpdateState(twoTouchModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId, code: 'switch_1', value: deviceStatus.firstSwitch),
twoTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId, code: 'switch_2', value: deviceStatus.secondSwitch),
twoTouchId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
}
void _groupAllOn(GroupAllOnEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
for (int i = 0; i < groupTwoTouchList.length; i++) {
groupTwoTouchList[i].firstSwitch = true;
groupTwoTouchList[i].secondSwitch = true;
}
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: true));
List<String> allDeviceIds = groupTwoTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: true,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: true,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
void _groupAllOff(GroupAllOffEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
for (int i = 0; i < groupTwoTouchList.length; i++) {
groupTwoTouchList[i].firstSwitch = false;
groupTwoTouchList[i].secondSwitch = false;
}
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: false));
List<String> allDeviceIds = groupTwoTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: false,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: false,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
void _changeSliding(ChangeSlidingSegment event, Emitter<TwoTouchState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(SetCounterValue event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoTouchId, code: event.deviceCode, value: seconds),
twoTouchId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown = seconds;
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown = seconds;
}
} else {
emit(const FailedState(error: 'Something went wrong'));
return;
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(GetCounterEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState());
try {
add(GetScheduleEvent());
var response = await DevicesAPI.getDeviceStatus(twoTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoTouchModel.fromJson(statusModelList);
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown > 0
? _onStartTimer(deviceStatus.firstCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown > 0
? _onStartTimer(deviceStatus.secondCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.secondCountDown));
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _onClose(OnClose event, Emitter<TwoTouchState> 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<TwoTouchState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
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<TwoTouchState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(const ChangeSlidingSegment(value: 1));
}
Future<void> saveSchedule(
TwoTouchSave event,
Emitter<TwoTouchState> emit,
) async {
try {
if (selectedDays.isNotEmpty) {
emit(LoadingInitialState());
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: twoTouchId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(TwoTouchSaveSchedule());
add(const ToggleCreateScheduleEvent(index: 1));
// toggleCreateSchedule();
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(FailedState(error: e.toString()));
}
}
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<TwoTouchState> emit,
) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: twoTouchId,
);
List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: 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 toggleRepeat(ToggleScheduleEvent event, Emitter<TwoTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: twoTouchId, enable: event.toggle);
if (response == true) {
add(GetScheduleEvent());
toggleSchedule = event.toggle;
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
Future deleteSchedule(DeleteScheduleEvent event, Emitter<TwoTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: twoTouchId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
void _fetchTwoTouchWizardStatus(InitialWizardEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
groupTwoTouchList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '2GT');
for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoTouchModel.fromJson(statusModelList);
groupTwoTouchList.add(GroupTwoTouchModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
secondSwitch: deviceStatus.secondSwitch,
));
}
if (groupTwoTouchList.isNotEmpty) {
groupTwoTouchList.firstWhere((element) {
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _changeFirstWizardSwitch(
ChangeFirstWizardSwitchStatusEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupTwoTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: [event.deviceId],
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
void _changeSecondWizardSwitch(
ChangeSecondWizardSwitchStatusEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupTwoTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.secondSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: [event.deviceId],
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
String statusSelected = '';
String optionSelected = '';
Future<void> _changeStatus(ChangeStatusEvent event, Emitter<TwoTouchState> emit) async {
try {
emit(LoadingInitialState());
final Map<String, Map<String, String>> controlMap = {
"relay_status": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"light_mode": {
'Off': 'none',
'On/Off Status': 'relay',
'Switch Position': 'pos',
},
"relay_status_1": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"relay_status_2": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
};
final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) {
await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoTouchId, code: optionSelected, value: selectedControl),
twoTouchId,
);
} else {
emit(const FailedState(error: 'Invalid statusSelected or optionSelected'));
}
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
}

View File

@ -0,0 +1,162 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
abstract class TwoTouchEvent extends Equatable {
const TwoTouchEvent();
@override
List<Object> get props => [];
}
class LoadingEvent extends TwoTouchEvent {}
class TwoTouchUpdated extends TwoTouchEvent {}
class TwoTouchSave extends TwoTouchEvent {}
class ToggleScheduleEvent extends TwoTouchEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle, required this.id});
@override
List<Object> get props => [toggle, id];
}
class errorMessage extends TwoTouchEvent {}
class ToggleDaySelectionEvent extends TwoTouchEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
class InitialEvent extends TwoTouchEvent {
const InitialEvent();
@override
List<Object> get props => [];
}
class ChangeFirstSwitchStatusEvent extends TwoTouchEvent {
final bool value;
final String deviceId;
const ChangeFirstSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeSecondSwitchStatusEvent extends TwoTouchEvent {
final bool value;
final String deviceId;
const ChangeSecondSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class AllOffEvent extends TwoTouchEvent {}
class AllOnEvent extends TwoTouchEvent {}
class GroupAllOnEvent extends TwoTouchEvent {}
class GroupAllOffEvent extends TwoTouchEvent {}
class ChangeSlidingSegment extends TwoTouchEvent {
final int value;
const ChangeSlidingSegment({required this.value});
@override
List<Object> get props => [value];
}
class GetCounterEvent extends TwoTouchEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class SetCounterValue extends TwoTouchEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends TwoTouchEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends TwoTouchEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends TwoTouchEvent {}
class OnClose extends TwoTouchEvent {}
class GetScheduleEvent extends TwoTouchEvent {}
class DeleteScheduleEvent extends TwoTouchEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@override
List<Object> get props => [id];
}
class TabChangedEvent extends TwoTouchEvent {
final int index;
TabChangedEvent({required this.index});
}
class ToggleSelectedEvent extends TwoTouchEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@override
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends TwoTouchEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@override
List<Object> get props => [index];
}
class InitialWizardEvent extends TwoTouchEvent {}
class ChangeFirstWizardSwitchStatusEvent extends TwoTouchEvent {
final bool value;
final String deviceId;
const ChangeFirstWizardSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeSecondWizardSwitchStatusEvent extends TwoTouchEvent {
final bool value;
final String deviceId;
const ChangeSecondWizardSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeStatusEvent extends TwoTouchEvent {
final String deviceId;
final BuildContext context;
const ChangeStatusEvent({this.deviceId = '',required this.context});
}

View File

@ -0,0 +1,91 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/group_two_touch_model.dart';
import 'package:syncrow_app/features/devices/model/two_touch_model.dart';
class TwoTouchState extends Equatable {
const TwoTouchState();
@override
List<Object> get props => [];
}
class InitialState extends TwoTouchState {}
class TwoTouchSaveSchedule extends TwoTouchState {}
class ChangeTimeState extends TwoTouchState {}
class LoadingInitialState extends TwoTouchState {}
class UpdateState extends TwoTouchState {
final TwoTouchModel twoTouchModel;
const UpdateState({required this.twoTouchModel});
@override
List<Object> get props => [TwoTouchModel];
}
class LoadingNewSate extends TwoTouchState {
final TwoTouchModel twoTouchModel;
const LoadingNewSate({required this.twoTouchModel});
@override
List<Object> get props => [TwoTouchModel];
}
class UpdateGroupState extends TwoTouchState {
final List<GroupTwoTouchModel> twoTouchList;
final bool allSwitches;
const UpdateGroupState({required this.twoTouchList, required this.allSwitches});
@override
List<Object> get props => [twoTouchList, allSwitches];
}
class FailedState extends TwoTouchState {
final String error;
const FailedState({required this.error});
@override
List<Object> get props => [error];
}
class ChangeSlidingSegmentState extends TwoTouchState {
final int value;
const ChangeSlidingSegmentState({required this.value});
@override
List<Object> get props => [value];
}
class UpdateTimerState extends TwoTouchState {
final int seconds;
const UpdateTimerState({required this.seconds});
@override
List<Object> get props => [seconds];
}
class TimerRunInProgress extends TwoTouchState {
final int remainingTime;
const TimerRunInProgress(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class TimerRunComplete extends TwoTouchState {}
class IsToggleState extends TwoTouchState {
final bool? onOff;
const IsToggleState({this.onOff});
}
class UpdateCreateScheduleState extends TwoTouchState {
final bool createSchedule;
UpdateCreateScheduleState(this.createSchedule);
}

View File

@ -20,7 +20,9 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
on<WallSensorUpdatedEvent>(_wallSensorUpdated);
}
void _fetchCeilingSensorStatus(InitialEvent event, Emitter<WallSensorState> emit) async {
void _fetchCeilingSensorStatus(
InitialEvent event,
Emitter<WallSensorState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(deviceId);
@ -30,7 +32,7 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
}
deviceStatus = WallSensorModel.fromJson(statusModelList);
emit(UpdateState(wallSensorModel: deviceStatus));
_listenToChanges();
// _listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
@ -39,15 +41,18 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) {
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 = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value']));
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = WallSensorModel.fromJson(statusList);
@ -56,15 +61,19 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
} catch (_) {}
}
_wallSensorUpdated(WallSensorUpdatedEvent event, Emitter<WallSensorState> emit) {
_wallSensorUpdated(
WallSensorUpdatedEvent event, Emitter<WallSensorState> emit) {
emit(UpdateState(wallSensorModel: deviceStatus));
}
void _changeIndicator(ChangeIndicatorEvent event, Emitter<WallSensorState> emit) async {
void _changeIndicator(
ChangeIndicatorEvent event, Emitter<WallSensorState> emit) async {
emit(LoadingNewSate(wallSensorModel: deviceStatus));
try {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: deviceId, code: 'indicator', value: !event.value), deviceId);
DeviceControlModel(
deviceId: deviceId, code: 'indicator', value: !event.value),
deviceId);
if (response['success'] ?? false) {
deviceStatus.indicator = !event.value;
@ -73,11 +82,14 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
emit(UpdateState(wallSensorModel: deviceStatus));
}
void _changeValue(ChangeValueEvent event, Emitter<WallSensorState> emit) async {
void _changeValue(
ChangeValueEvent event, Emitter<WallSensorState> emit) async {
emit(LoadingNewSate(wallSensorModel: deviceStatus));
try {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: deviceId, code: event.code, value: event.value), deviceId);
DeviceControlModel(
deviceId: deviceId, code: event.code, value: event.value),
deviceId);
if (response['success'] ?? false) {
if (event.code == 'far_detection') {

View File

@ -1,9 +1,12 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.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/GroupWHModel.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';
@ -16,9 +19,7 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
final String whId;
final String switchCode;
WHModel deviceStatus = WHModel(
firstSwitch: false,firstCountDown: 0
);
WHModel deviceStatus = WHModel(firstSwitch: false, firstCountDown: 0);
List<WHModel> deviceStatusList = [];
List<DeviceModel> devicesList = [];
bool allAcsPage = false;
@ -27,15 +28,15 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
int globalTemp = 25;
Timer? _timer;
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
bool createCirculate = false;
List<ScheduleModel> listSchedule = [];
DateTime? selectedTime=DateTime.now();
DateTime? selectedTime = DateTime.now();
WaterHeaterBloc({required this.whId,required this.switchCode}) : super(WHInitialState()) {
WaterHeaterBloc({required this.whId, required this.switchCode})
: super(WHInitialState()) {
on<WaterHeaterInitial>(_fetchWaterHeaterStatus);
on<WaterHeaterSwitch>(_changeFirstSwitch);
on<SetCounterValue>(_setCounterValue);
@ -49,11 +50,19 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
on<OnClose>(_onClose);
on<SelectTimeEvent>(showTime);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<InitialWizardEvent>(_fetchWHWizardStatus);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ToggleCreateCirculate>(_toggleCreateCirculate);
on<WaterHeaterUpdated>(_waterHeaterUpdated);
}
void _fetchWaterHeaterStatus(WaterHeaterInitial event, Emitter<WaterHeaterState> emit) async {
void _fetchWaterHeaterStatus(
WaterHeaterInitial event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(whId);
@ -61,9 +70,10 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = WHModel.fromJson(statusModelList, );
deviceStatus = WHModel.fromJson(
statusModelList,
);
emit(UpdateState(whModel: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges();
} catch (e) {
emit(WHFailedState(errorMessage: e.toString()));
@ -71,8 +81,41 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
}
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$whId');
Stream<DatabaseEvent> stream = ref.onValue;
void _changeFirstSwitch(WaterHeaterSwitch event, Emitter<WaterHeaterState> emit) async {
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: element['value']));
});
deviceStatus = WHModel.fromJson(statusList);
if (!isClosed) {
add(WaterHeaterUpdated());
}
});
} catch (_) {}
}
_waterHeaterUpdated(
WaterHeaterUpdated event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
emit(UpdateState(whModel: deviceStatus));
}
void _changeFirstSwitch(
WaterHeaterSwitch event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.whSwitch;
@ -83,13 +126,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: whId,
deviceId: whId,
code: 'switch_1',
value: deviceStatus.firstSwitch ),
value: deviceStatus.firstSwitch),
whId);
if (!response['success']) {
// add(InitialEvent(groupScreen: oneGangGroup));
// add(InitialEvent(groupScreen: oneGangGroup));
}
});
} catch (_) {
@ -97,19 +140,17 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
}
//=====================---------- timer ----------------------------------------
void _setCounterValue(SetCounterValue event, Emitter<WaterHeaterState> emit) async {
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),
DeviceControlModel(
deviceId: whId, code: event.deviceCode, value: seconds),
whId);
if (response['success'] ?? false) {
@ -132,7 +173,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
}
void _getCounterValue(GetCounterEvent event, Emitter<WaterHeaterState> emit) async {
void _getCounterValue(
GetCounterEvent event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(whId);
@ -148,7 +190,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
}
} catch (e) {
WHFailedState(errorMessage: e.toString());
WHFailedState(errorMessage: e.toString());
return;
}
}
@ -173,13 +215,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
}
//=====================---------- Schedule ----------------------------------------
List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"},
{"day": "Mon", "key": "Mon"},
@ -190,11 +227,14 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
{"day": "Sat", "key": "Sat"},
];
Future<void> saveSchedule(ScheduleSave event, Emitter<WaterHeaterState> emit,) async {
Future<void> saveSchedule(
ScheduleSave event,
Emitter<WaterHeaterState> emit,
) async {
try {
if(selectedDays.isNotEmpty) {
if (selectedDays.isNotEmpty) {
emit(WHLoadingState());
final response = await DevicesAPI.postSchedule(
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: whId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
@ -204,24 +244,28 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(SaveSchedule());
add(const ToggleCreateScheduleEvent(index:1 ));
}else{
add(const ToggleCreateScheduleEvent(index: 1));
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(WHFailedState(errorMessage:e.toString()));
emit(WHFailedState(errorMessage: e.toString()));
}
}
Future<void> getSchedule(GetScheduleEvent event, Emitter<WaterHeaterState> emit,) async {
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<WaterHeaterState> emit,
) async {
try {
emit(WHLoadingState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: whId ,
deviceId: whId,
);
List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(WHInitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
@ -252,7 +296,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(WHFailedState(errorMessage: errorMessage.toString()));
emit(WHFailedState(errorMessage: errorMessage.toString()));
}
}
@ -262,7 +306,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
emit(WHLoadingState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: whId, );
deviceUuid: whId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
@ -275,47 +320,35 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
}
// void toggleCreateSchedule() {
// emit(WHLoadingState());
// createSchedule = !createSchedule;
// selectedDays.clear();
// selectedTime=DateTime.now();
// emit(UpdateCreateScheduleState(createSchedule));
// }
void toggleCreateCirculate() {
emit(WHLoadingState());
void _toggleCreateCirculate(
ToggleCreateCirculate event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
createCirculate = !createCirculate;
selectedDays.clear();
selectedTime=DateTime.now();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createCirculate));
}
// void toggleSelectedIndex(index) {
// emit(WHLoadingState());
// selectedTabIndex = index;
// emit(ChangeSlidingSegmentState(value: selectedTabIndex));
// }
void toggleSelectedIndex( ToggleSelectedEvent event, Emitter<WaterHeaterState> emit) {
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
selectedTabIndex =event.index;
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<WaterHeaterState> emit,
) async {
ToggleDaySelectionEvent event,
Emitter<WaterHeaterState> emit,
) async {
emit(WHLoadingState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
@ -327,9 +360,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
int selectedTabIndex = 0;
showTime(SelectTimeEvent event, Emitter<WaterHeaterState> emit) async {
final TimeOfDay? timePicked = await showTimePicker(
await showTimePicker(
context: event.context,
initialTime: TimeOfDay.now(),
builder: (context, child) {
@ -350,4 +382,137 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
},
);
}
List<GroupWHModel> groupWaterHeaterList = [];
bool allSwitchesOn = true;
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupWaterHeaterList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: [event.deviceId],
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
void _fetchWHWizardStatus(
InitialWizardEvent event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
try {
devicesList = [];
groupWaterHeaterList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', 'WH');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = WHModel.fromJson(statusModelList);
groupWaterHeaterList.add(GroupWHModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
));
}
if (groupWaterHeaterList.isNotEmpty) {
groupWaterHeaterList.firstWhere((element) {
if (!element.firstSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: allSwitchesOn));
} catch (e) {
// emit(FailedState(error: e.toString()));
return;
}
}
void _groupAllOn(
GroupAllOnEvent event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
for (int i = 0; i < groupWaterHeaterList.length; i++) {
groupWaterHeaterList[i].firstSwitch = true;
}
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: true));
List<String> allDeviceIds =
groupWaterHeaterList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: true,
);
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
void _groupAllOff(
GroupAllOffEvent event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
for (int i = 0; i < groupWaterHeaterList.length; i++) {
groupWaterHeaterList[i].firstSwitch = false;
}
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: false));
List<String> allDeviceIds =
groupWaterHeaterList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: false,
);
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
}

View File

@ -28,7 +28,6 @@ class WaterHeaterInitial extends WaterHeaterEvent {
class WaterHeaterChangeStatus extends WaterHeaterEvent {}
class GetCounterEvent extends WaterHeaterEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@ -66,25 +65,27 @@ 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});
const ToggleScheduleEvent({required this.toggle, required this.id});
@override
List<Object> get props => [toggle,id];
List<Object> get props => [toggle, id];
}
class ToggleDaySelectionEvent extends WaterHeaterEvent {
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});
@ -100,7 +101,6 @@ class SelectTimeEvent extends WaterHeaterEvent {
List<Object> get props => [context, isEffective];
}
class ToggleSelectedEvent extends WaterHeaterEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@ -108,7 +108,6 @@ class ToggleSelectedEvent extends WaterHeaterEvent {
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends WaterHeaterEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@ -116,10 +115,25 @@ class ToggleCreateScheduleEvent extends WaterHeaterEvent {
List<Object> get props => [index];
}
class ToggleCreateCirculateEvent extends WaterHeaterEvent {
class ToggleCreateCirculateEvent extends WaterHeaterEvent {
final int index;
const ToggleCreateCirculateEvent({required this.index});
@override
List<Object> get props => [index];
}
class InitialWizardEvent extends WaterHeaterEvent {}
class ChangeFirstWizardSwitchStatusEvent extends WaterHeaterEvent {
final bool value;
final String deviceId;
const ChangeFirstWizardSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class GroupAllOnEvent extends WaterHeaterEvent {}
class GroupAllOffEvent extends WaterHeaterEvent {}
class ToggleCreateCirculate extends WaterHeaterEvent {}

View File

@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/GroupWHModel.dart';
import 'package:syncrow_app/features/devices/model/water_heater.dart';
abstract class WaterHeaterState extends Equatable {
@ -13,13 +14,8 @@ 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 {
@ -110,4 +106,17 @@ class ChangeSlidingSegmentState extends WaterHeaterState {
@override
List<Object> get props => [value];
}
}
class UpdateGroupState extends WaterHeaterState {
final List<GroupWHModel> twoGangList;
final bool allSwitches;
const UpdateGroupState({required this.twoGangList, required this.allSwitches});
@override
List<Object> get props => [twoGangList, allSwitches];
}

View File

@ -0,0 +1,165 @@
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/water_leak_bloc/water_leak_event.dart';
import 'package:syncrow_app/features/devices/bloc/water_leak_bloc/water_leak_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/status_model.dart';
import 'package:syncrow_app/features/devices/model/water_leak_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
class WaterLeakBloc extends Bloc<WaterLeakEvent, WaterLeakState> {
final String WLId;
WaterLeakBloc({
required this.WLId,
}) : super(const WaterLeakState()) {
on<WaterLeakInitial>(_fetchStatus);
on<ReportLogsInitial>(fetchLogsForLastMonth);
on<ToggleLowBatteryEvent>(_toggleLowBattery);
on<ToggleClosingReminderEvent>(_toggleClosingReminder);
on<ToggleWaterLeakAlarmEvent>(_toggleWaterLeakAlarm);
}
Timer? _timer;
bool lowBattery = false;
bool closingReminder = false;
bool waterAlarm = false;
WaterLeakModel deviceStatus =
WaterLeakModel(waterContactState: 'normal', batteryPercentage: 0);
void _fetchStatus(
WaterLeakInitial event, Emitter<WaterLeakState> emit) async {
emit(WaterLeakLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(WLId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = WaterLeakModel.fromJson(
statusModelList,
);
emit(UpdateState(waterSensor: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges();
} catch (e) {
emit(WaterLeakFailedState(errorMessage: e.toString()));
return;
}
}
void _toggleLowBattery(
ToggleLowBatteryEvent event, Emitter<WaterLeakState> emit) async {
emit(LoadingNewSate(waterSensor: deviceStatus));
try {
lowBattery = event.isLowBatteryEnabled;
emit(UpdateState(waterSensor: deviceStatus));
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: WLId,
code: 'low_battery',
value: lowBattery,
),
WLId,
);
} catch (e) {
emit(WaterLeakFailedState(errorMessage: e.toString()));
}
}
void _toggleClosingReminder(
ToggleClosingReminderEvent event, Emitter<WaterLeakState> emit) async {
emit(LoadingNewSate(waterSensor: deviceStatus));
try {
closingReminder = event.isClosingReminderEnabled;
emit(UpdateState(waterSensor: deviceStatus));
// API call to update the state, if necessary
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: WLId,
code: 'closing_reminder',
value: closingReminder,
),
WLId,
);
} catch (e) {
emit(WaterLeakFailedState(errorMessage: e.toString()));
}
}
void _toggleWaterLeakAlarm(
ToggleWaterLeakAlarmEvent event, Emitter<WaterLeakState> emit) async {
emit(LoadingNewSate(waterSensor: deviceStatus));
try {
waterAlarm = event.isWaterLeakAlarmEnabled;
emit(UpdateState(waterSensor: deviceStatus));
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: WLId,
code: 'water_alarm',
value: waterAlarm,
),
WLId,
);
} catch (e) {
emit(WaterLeakFailedState(errorMessage: e.toString()));
}
}
DeviceReport recordGroups =
DeviceReport(startTime: '0', endTime: '0', data: []);
Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<WaterLeakState> 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(WaterLeakLoadingState());
var response = await DevicesAPI.getReportLogs(
startTime: startTime.toString(),
endTime: endTime.toString(),
deviceUuid: WLId,
code: 'watersensor_state',
);
recordGroups = response;
emit(UpdateState(waterSensor: deviceStatus));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(WaterLeakFailedState(errorMessage: errorMessage));
}
}
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$WLId');
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 = WaterLeakModel.fromJson(statusList);
if (!isClosed) {
add(
WaterLeakSwitch(switchD: deviceStatus.waterContactState),
);
}
});
} catch (_) {}
}
}

View File

@ -0,0 +1,102 @@
import 'package:equatable/equatable.dart';
abstract class WaterLeakEvent extends Equatable {
const WaterLeakEvent();
@override
List<Object> get props => [];
}
class WaterLeakLoading extends WaterLeakEvent {}
class WaterLeakSwitch extends WaterLeakEvent {
final String switchD;
final String deviceId;
final String productId;
const WaterLeakSwitch({required this.switchD, this.deviceId = '', this.productId = ''});
@override
List<Object> get props => [switchD, deviceId, productId];
}
class WaterLeakUpdated extends WaterLeakEvent {}
class WaterLeakInitial extends WaterLeakEvent {
const WaterLeakInitial();
}
class ReportLogsInitial extends WaterLeakEvent {
const ReportLogsInitial();
}
class WaterLeakChangeStatus extends WaterLeakEvent {}
class GetCounterEvent extends WaterLeakEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class ToggleLowBatteryEvent extends WaterLeakEvent {
final bool isLowBatteryEnabled;
const ToggleLowBatteryEvent(this.isLowBatteryEnabled);
@override
List<Object> get props => [isLowBatteryEnabled];
}
class ToggleClosingReminderEvent extends WaterLeakEvent {
final bool isClosingReminderEnabled;
const ToggleClosingReminderEvent(this.isClosingReminderEnabled);
@override
List<Object> get props => [isClosingReminderEnabled];
}
class ToggleWaterLeakAlarmEvent extends WaterLeakEvent {
final bool isWaterLeakAlarmEnabled;
const ToggleWaterLeakAlarmEvent(this.isWaterLeakAlarmEnabled);
@override
List<Object> get props => [isWaterLeakAlarmEnabled];
}
class SetCounterValue extends WaterLeakEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends WaterLeakEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends WaterLeakEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends WaterLeakEvent {}
class OnClose extends WaterLeakEvent {}

View File

@ -0,0 +1,39 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/water_leak_model.dart';
class WaterLeakState extends Equatable {
const WaterLeakState();
@override
List<Object> get props => [];
}
class WaterLeakInitialState extends WaterLeakState {}
class WaterLeakLoadingState extends WaterLeakState {}
class WaterLeakFailedState extends WaterLeakState {
final String errorMessage;
const WaterLeakFailedState({required this.errorMessage});
@override
List<Object> get props => [errorMessage];
}
class UpdateState extends WaterLeakState {
final WaterLeakModel waterSensor;
const UpdateState({required this.waterSensor});
@override
List<Object> get props => [waterSensor];
}
class LoadingNewSate extends WaterLeakState {
final WaterLeakModel waterSensor;
const LoadingNewSate({required this.waterSensor});
@override
List<Object> get props => [waterSensor];
}

View File

@ -0,0 +1,11 @@
class GroupWHModel {
final String deviceId;
final String deviceName;
bool firstSwitch;
GroupWHModel({
required this.deviceId,
required this.deviceName,
required this.firstSwitch,
});
}

View File

@ -0,0 +1,29 @@
import 'package:syncrow_app/features/devices/model/status_model.dart';
class CurtainModel {
String control;
int percent;
CurtainModel({
required this.control,
required this.percent,
});
factory CurtainModel.fromJson(List<StatusModel> jsonList) {
late String _control;
late int _percent;
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'control') {
_control = jsonList[i].value ?? false;
}
if (jsonList[i].code == 'percent_control') {
_percent = jsonList[i].value ?? 0;
}
}
//percent_control
return CurtainModel(
control: _control,
percent: _percent,
);
}
}

View File

@ -67,4 +67,8 @@ Map<DeviceType, String> deviceTypeIconMap = {
DeviceType.WH: Assets.waterHeaterIcon,
DeviceType.DS: Assets.doorSensorIcon,
DeviceType.Other: Assets.assetsIconsAC,
DeviceType.OneTouch: Assets.gang1touch,
DeviceType.TowTouch: Assets.gang2touch,
DeviceType.ThreeTouch: Assets.gang3touch,
DeviceType.GarageDoor: Assets.garageIcon
};

View File

@ -66,6 +66,16 @@ class DeviceModel {
tempIcon = Assets.waterHeaterIcon;
} else if (type == DeviceType.DS) {
tempIcon = Assets.doorSensorIcon;
} else if (type == DeviceType.OneTouch) {
tempIcon = Assets.gang1touch;
} else if (type == DeviceType.TowTouch) {
tempIcon = Assets.gang2touch;
} else if (type == DeviceType.GarageDoor) {
tempIcon = Assets.garageIcon;
} else if (type == DeviceType.ThreeTouch) {
tempIcon = Assets.gang3touch;
} else if (type == DeviceType.WaterLeak) {
tempIcon = Assets.waterLeakIcon;
} else {
tempIcon = Assets.assetsIconsLogo;
}

View 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);
}
}

View File

@ -0,0 +1,13 @@
class GroupCurtainModel {
final String deviceId;
final String deviceName;
String firstSwitch;
int percentControl;
GroupCurtainModel({
required this.deviceId,
required this.deviceName,
required this.firstSwitch,
required this.percentControl,
});
}

View File

@ -0,0 +1,11 @@
class GroupGarageModel {
final String deviceId;
final String deviceName;
bool firstSwitch;
GroupGarageModel({
required this.deviceId,
required this.deviceName,
required this.firstSwitch,
});
}

View File

@ -0,0 +1,11 @@
class GroupOneTouchModel {
final String deviceId;
final String deviceName;
bool firstSwitch;
GroupOneTouchModel({
required this.deviceId,
required this.deviceName,
required this.firstSwitch,
});
}

View File

@ -0,0 +1,15 @@
class GroupThreeTouchModel {
final String deviceId;
final String deviceName;
bool firstSwitch;
bool secondSwitch;
bool thirdSwitch;
GroupThreeTouchModel({
required this.deviceId,
required this.deviceName,
required this.firstSwitch,
required this.secondSwitch,
required this.thirdSwitch,
});
}

View File

@ -0,0 +1,13 @@
class GroupTwoTouchModel {
final String deviceId;
final String deviceName;
bool firstSwitch;
bool secondSwitch;
GroupTwoTouchModel({
required this.deviceId,
required this.deviceName,
required this.firstSwitch,
required this.secondSwitch,
});
}

View File

@ -0,0 +1,50 @@
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class OneTouchModel {
bool firstSwitch;
int firstCountDown;
status relay;
lightStatus light_mode;
status relay_status_1;
OneTouchModel(
{required this.firstSwitch,
required this.firstCountDown,
required this.light_mode,
required this.relay,
required this.relay_status_1
});
factory OneTouchModel.fromJson(List<StatusModel> jsonList) {
late bool _switch;
late int _count;
late String _relay;
late String _light_mode;
late String relay_status_1;
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;
} else if (jsonList[i].code == 'relay_status') {
_relay = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'light_mode') {
_light_mode = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_1') {
relay_status_1 = jsonList[i].value ?? 0;
}
}
return OneTouchModel(
firstSwitch: _switch,
firstCountDown: _count,
light_mode: lightStatusExtension.fromString(_light_mode) ,
relay: StatusExtension.fromString(_relay ) ,
relay_status_1: StatusExtension.fromString(relay_status_1 )
);
}
}

View File

@ -0,0 +1,81 @@
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class ThreeTouchModel {
bool firstSwitch;
bool secondSwitch;
bool thirdSwitch;
int firstCountDown;
int secondCountDown;
int thirdCountDown;
status relay;
lightStatus light_mode;
status relay_status_1;
status relay_status_2;
status relay_status_3;
ThreeTouchModel(
{required this.firstSwitch,
required this.secondSwitch,
required this.thirdSwitch,
required this.firstCountDown,
required this.secondCountDown,
required this.thirdCountDown,
required this.light_mode,
required this.relay,
required this.relay_status_1,
required this.relay_status_2,
required this.relay_status_3});
factory ThreeTouchModel.fromJson(List<StatusModel> jsonList) {
late bool _firstSwitch;
late bool _secondSwitch;
late bool _thirdSwitch;
late int _firstCount;
late int _secondCount;
late int _thirdCount;
late String _relay;
late String _light_mode;
late String _relay_status_1;
late String _relay_status_2;
late String _relay_status_3;
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch_1') {
_firstSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'switch_2') {
_secondSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'switch_3') {
_thirdSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'countdown_1') {
_firstCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'countdown_2') {
_secondCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'countdown_3') {
_thirdCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status') {
_relay = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'light_mode') {
_light_mode = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_1') {
_relay_status_1 = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_2') {
_relay_status_2 = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_3') {
_relay_status_3 = jsonList[i].value ?? 0;
}
}
return ThreeTouchModel(
firstSwitch: _firstSwitch,
secondSwitch: _secondSwitch,
thirdSwitch: _thirdSwitch,
firstCountDown: _firstCount,
secondCountDown: _secondCount,
thirdCountDown: _thirdCount,
light_mode: lightStatusExtension.fromString(_light_mode),
relay: StatusExtension.fromString(_relay),
relay_status_1: StatusExtension.fromString(_relay_status_1),
relay_status_2: StatusExtension.fromString(_relay_status_2),
relay_status_3: StatusExtension.fromString(_relay_status_3));
}
}

View File

@ -0,0 +1,63 @@
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class TwoTouchModel {
bool firstSwitch;
bool secondSwitch;
int firstCountDown;
int secondCountDown;
status relay;
lightStatus light_mode;
status relay_status_1;
status relay_status_2;
TwoTouchModel(
{required this.firstSwitch,
required this.secondSwitch,
required this.firstCountDown,
required this.secondCountDown,
required this.light_mode,
required this.relay,
required this.relay_status_1,
required this.relay_status_2});
factory TwoTouchModel.fromJson(List<StatusModel> jsonList) {
late bool _firstSwitch;
late bool _secondSwitch;
late int _firstCount;
late int _secondCount;
late String _relay;
late String _light_mode;
late String _relay_status_1;
late String _relay_status_2;
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch_1') {
_firstSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'switch_2') {
_secondSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'countdown_1') {
_firstCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'countdown_2') {
_secondCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status') {
_relay = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'light_mode') {
_light_mode = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_1') {
_relay_status_1 = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_2') {
_relay_status_2 = jsonList[i].value ?? 0;
}
}
return TwoTouchModel(
firstSwitch: _firstSwitch,
secondSwitch: _secondSwitch,
firstCountDown: _firstCount,
secondCountDown: _secondCount,
light_mode: lightStatusExtension.fromString(_light_mode),
relay: StatusExtension.fromString(_relay),
relay_status_1: StatusExtension.fromString(_relay_status_1),
relay_status_2: StatusExtension.fromString(_relay_status_2));
}
}

View File

@ -0,0 +1,28 @@
import 'package:syncrow_app/features/devices/model/status_model.dart';
class WaterLeakModel {
String waterContactState;
int batteryPercentage;
WaterLeakModel({
required this.waterContactState,
required this.batteryPercentage,
});
factory WaterLeakModel.fromJson(List<StatusModel> jsonList) {
late String _waterContactState;
late int _batteryPercentage;
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'watersensor_state') {
_waterContactState = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'battery_percentage') {
_batteryPercentage = jsonList[i].value ?? 0;
}
}
return WaterLeakModel(
waterContactState: _waterContactState,
batteryPercentage: _batteryPercentage,
);
}
}

View File

@ -86,6 +86,8 @@ class ACsList extends StatelessWidget {
),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'OFF',
on: 'ON',
switchValue: devicesStatuesList[index].acSwitch,
action: () {
BlocProvider.of<ACsBloc>(context).add(AcSwitch(

View File

@ -0,0 +1,88 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/model/device_model.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';
class CircularButton extends StatelessWidget {
const CircularButton({
super.key,
required this.device,
required this.label,
required this.onTap,
required this.icons,
});
final DeviceModel? device;
final String label;
final Function()? onTap;
final IconData icons;
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: GestureDetector(
onTap: onTap,
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: label == 'All On'
? BodySmall(
text: "On",
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
)
: label == 'All Off'
? BodySmall(
text: "Off",
style: context.bodyMedium.copyWith(
color:
ColorsManager.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
)
: Icon(
icons,
color: ColorsManager.primaryColorWithOpacity,
size: 25,
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
// text: "Timer",
text: label,
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
);
}
}

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
@ -17,8 +16,8 @@ class CurtainButtons extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildButton(
onTap: () => context.read<CurtainBloc>().add(OpenCurtain(curtain.productType!)),
iconPath: Assets.assetsIconsCurtainsIconOpenCurtain,
onTap: () => context.read<CurtainBloc>().add(CloseCurtain(curtain.productType!)),
iconPath: Assets.assetsIconsCurtainsIconCloseCurtain,
),
_buildButton(
onTap: () => context.read<CurtainBloc>().add(PauseCurtain()),
@ -26,8 +25,8 @@ class CurtainButtons extends StatelessWidget {
isSvg: false,
),
_buildButton(
onTap: () => context.read<CurtainBloc>().add(CloseCurtain(curtain.productType!)),
iconPath: Assets.assetsIconsCurtainsIconCloseCurtain,
onTap: () => context.read<CurtainBloc>().add(OpenCurtain(curtain.productType!)),
iconPath: Assets.assetsIconsCurtainsIconOpenCurtain,
),
],
);

View File

@ -6,6 +6,7 @@ import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dar
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_buttons.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/generated/assets.dart';
@ -19,7 +20,7 @@ class CurtainView extends StatelessWidget {
create: (context) => CurtainBloc(curtain.uuid!)..add(InitCurtain()),
child: BlocBuilder<CurtainBloc, CurtainState>(
builder: (context, state) {
double curtainWidth = 270;
double curtainWidth = MediaQuery.sizeOf(context).width * 0.6;
// double blindHeight = 310;
if (state is CurtainsOpening) {
curtainWidth = state.curtainWidth;
@ -33,66 +34,117 @@ class CurtainView extends StatelessWidget {
}
return DefaultScaffold(
title: curtain.name,
child: Column(
children: [
Stack(
alignment: Alignment.centerLeft,
children: [
Container(
height: 340,
width: 365,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.assetsImagesWindow,
),
child: state is CurtainLoadingState
? const Center(
child:
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<CurtainBloc>(context).add(InitCurtain());
},
child: ListView(
children: [
const SizedBox(
height: 40,
),
),
),
Padding(
padding: const EdgeInsets.all(40),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
height: 310,
width: curtainWidth,
child: Stack(
children: List.generate(
10,
(index) {
double spacing = curtainWidth / 9;
double leftMostPosition = index * spacing;
return AnimatedPositioned(
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
left: leftMostPosition,
child: SizedBox(
height: 320,
width: 32,
child: SvgPicture.asset(
Assets.assetsIconsCurtainsIconVerticalBlade,
fit: BoxFit.fill,
Stack(
alignment: Alignment.center,
children: [
SvgPicture.asset(
Assets.assetsImagesWindow,
width: MediaQuery.sizeOf(context).width * 0.85,
height: MediaQuery.sizeOf(context).height * 0.4,
),
SizedBox(
height: MediaQuery.sizeOf(context).height * 0.4,
child: Column(
children: [
SvgPicture.asset(
Assets.assetsIconsCurtainsIconCurtainHolder,
width: MediaQuery.sizeOf(context).width * 0.75,
),
),
);
},
),
SizedBox(
width: MediaQuery.sizeOf(context).width * 0.75,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: MediaQuery.sizeOf(context).width * 0.025,
),
AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
height: MediaQuery.sizeOf(context).height * 0.35,
width: MediaQuery.sizeOf(context).width * 0.35,
child: Stack(
children: List.generate(
4,
(index) {
double spacing = curtainWidth / 7.5;
double leftMostPosition = index * spacing;
return AnimatedPositioned(
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
left: leftMostPosition,
child: SizedBox(
height:
MediaQuery.sizeOf(context).height * 0.35,
width: MediaQuery.sizeOf(context).width * 0.08,
child: SvgPicture.asset(
Assets.assetsIconsCurtainsIconVerticalBlade,
fit: BoxFit.fill,
),
),
);
},
),
),
),
AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
height: MediaQuery.sizeOf(context).height * 0.35,
width: MediaQuery.sizeOf(context).width * 0.35,
child: Stack(
children: List.generate(
4,
(index) {
double spacing = curtainWidth / 7.5;
double rightMostPosition = index * spacing;
return AnimatedPositioned(
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
right: rightMostPosition,
child: SizedBox(
height: MediaQuery.sizeOf(context).height * 0.35,
width: MediaQuery.sizeOf(context).width * 0.08,
child: SvgPicture.asset(
Assets.rightVerticalBlade,
fit: BoxFit.fill,
),
),
);
},
),
),
),
SizedBox(
width: MediaQuery.sizeOf(context).width * 0.025,
),
],
),
),
],
),
),
],
),
),
const SizedBox(height: 80),
CurtainButtons(curtain: curtain),
],
),
Positioned(
top: 27,
left: 43,
child: SvgPicture.asset(
Assets.assetsIconsCurtainsIconCurtainHolder,
),
),
],
),
const SizedBox(height: 80),
CurtainButtons(curtain: curtain),
],
),
),
);
},
),

View File

@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
import 'package:syncrow_app/features/devices/model/group_curtain_model.dart';
import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class CurtainsList extends StatelessWidget {
const CurtainsList(
{super.key, required this.curtainsList, required this.allSwitches});
final List<GroupCurtainModel> curtainsList;
final bool allSwitches;
@override
Widget build(BuildContext context) {
return BlocBuilder<CurtainBloc, CurtainState>(
builder: (context, state) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 10),
const BodySmall(text: 'All Curtains'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'Close',
on: 'Open',
switchValue: allSwitches,
action: () {
BlocProvider.of<CurtainBloc>(context).add(GroupAllOnEvent());
},
secondAction: () {
BlocProvider.of<CurtainBloc>(context).add(GroupAllOffEvent());
},
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0),
itemCount: curtainsList.length,
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
BodySmall(text: curtainsList[index].deviceName),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'close',
on: 'open',
switchValue: curtainsList[index].percentControl > 1,
action: () {
// Toggle between 'open' and 'close' based on current value
final newValue =
curtainsList[index].percentControl > 1 ? 0 : 100;
BlocProvider.of<CurtainBloc>(context).add(
ChangeFirstWizardSwitchStatusEvent(
value: newValue,
deviceId: curtainsList[index].deviceId,
),
);
},
),
],
);
},
),
],
),
);
},
);
}
}

View File

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_curtain_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtains_list.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
class CurtainsWizard extends StatelessWidget {
const CurtainsWizard({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
List<GroupCurtainModel> groupOneTouchModel = [];
return DefaultScaffold(
title: 'Curtain',
child: BlocProvider(
create: (context) =>
CurtainBloc(device?.uuid ?? '')..add(InitialWizardEvent()),
child: BlocBuilder<CurtainBloc, CurtainState>(
builder: (context, state) {
bool allSwitchesOn = false;
if (state is UpdateGroupState) {
groupOneTouchModel = state.curtainList;
allSwitchesOn = state.allSwitches;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: CurtainsList(
curtainsList: groupOneTouchModel,
allSwitches: allSwitchesOn,
);
},
),
));
}
}

View File

@ -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,
)
],
),
)),
),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,441 @@
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/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/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);
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: 5,
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,
),
)),
],
),
),
),
Expanded(
flex: 3,
child: Column(
children: [
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 Flexible(
child: 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 Flexible(
child: 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 Flexible(
child: 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 Flexible(
child: 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],
),
),
);
}
}

View File

@ -0,0 +1,74 @@
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/devices/model/group_garage_model.dart';
import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class GarageList extends StatelessWidget {
const GarageList(
{super.key, required this.garageList, required this.allSwitches});
final List<GroupGarageModel> garageList;
final bool allSwitches;
@override
Widget build(BuildContext context) {
return BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
builder: (context, state) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 10),
const BodySmall(text: 'All Lights'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'OFF',
on: 'ON',
switchValue: allSwitches,
action: () {
BlocProvider.of<GarageDoorBloc>(context)
.add(GroupAllOnEvent());
},
secondAction: () {
BlocProvider.of<GarageDoorBloc>(context)
.add(GroupAllOffEvent());
},
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0),
itemCount: garageList.length,
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
BodySmall(text: garageList[index].deviceName),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'OFF',
on: 'ON',
switchValue: garageList[index].firstSwitch,
action: () {
BlocProvider.of<GarageDoorBloc>(context).add(
ChangeFirstWizardSwitchStatusEvent(
value: garageList[index].firstSwitch,
deviceId: garageList[index].deviceId));
},
),
],
);
},
),
],
),
);
},
);
}
}

View File

@ -0,0 +1,521 @@
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/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: InkWell(
onTap: () {
showDialog(
context: context,
builder: (context) {
return TimeoutDialog(
duration: Duration(
seconds: garageDoorBloc
.deviceStatus
.countdownAlarm),
title: 'Timeout Alarm',
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: (selectedSecond) {
garageDoorBloc.add(
SetTimeOutValue(
deviceCode:
'countdown_alarm',
duration:
selectedSecond));
Navigator.of(context).pop();
},
);
});
},
child: 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.deviceStatus
.doorState1 !=
'unclosed_time',
onChanged: (value) {
context
.read<GarageDoorBloc>()
.add(
ToggleAlarmEvent(
value
? 'unclosed_time'
: 'close_time_alarm',
),
);
},
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: Container(
padding: EdgeInsets.only(top: 12, bottom: 12),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyMedium(
text: 'Opening and Closing Time',
fontWeight: FontWeight.normal,
),
Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
BodyMedium(
fontColor: ColorsManager.textGray,
text:
'${garageDoorBloc.secondSelected.toString()} Seconds',
fontWeight: FontWeight.normal,
fontSize: 13,
),
const Icon(
Icons.arrow_forward_ios,
size: 15,
color: ColorsManager.textGray,
)
],
),
],
),
),
),
)
],
);
},
),
));
}
}
//Timeout
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 int selectedSecond;
@override
void initState() {
super.initState();
selectedSecond = int.tryParse(widget.initialSelectedLabel ?? '10') ?? 10;
}
@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(
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),
),
),
)),
))
],
)
],
),
);
}
}
class TimeoutDialog extends StatefulWidget {
final String title;
final Function(String)? onTapLabel1;
final Function()? cancelTab;
final Function(Duration timeSelected)? confirmTab;
final Duration? duration;
TimeoutDialog({
required this.title,
this.onTapLabel1,
required this.cancelTab,
required this.confirmTab,
this.duration,
});
@override
_TimeoutDialogState createState() => _TimeoutDialogState();
}
class _TimeoutDialogState extends State<TimeoutDialog> {
late int selectedSecond;
Duration duration = Duration.zero;
int countNum = 0;
@override
void initState() {
super.initState();
duration = widget.duration!;
}
@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: Container(
height: 150,
width: MediaQuery.of(context).size.width * 1,
child: CupertinoTimerPicker(
initialTimerDuration: duration,
mode: CupertinoTimerPickerMode.hm,
onTimerDurationChanged: (Duration newDuration) {
duration = newDuration;
},
),
),
),
],
),
),
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(duration);
},
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Confirm',
style: TextStyle(
color: ColorsManager.primaryColor,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
)),
))
],
)
],
),
);
}
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

@ -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(),
],
),
),
],
);
},
);
}),
),
);
}
}

View File

@ -0,0 +1,49 @@
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/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_garage_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_list.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
class GarageWizard extends StatelessWidget {
const GarageWizard({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
List<GroupGarageModel> groupGarageModel = [];
return DefaultScaffold(
title: 'Garage Door Opener',
child: BlocProvider(
create: (context) => GarageDoorBloc(GDId: device?.uuid ?? '')
..add(InitialWizardEvent()),
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
builder: (context, state) {
bool allSwitchesOn = false;
if (state is UpdateGroupState) {
groupGarageModel = state.garageList;
allSwitchesOn = state.allSwitches;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: GarageList(
garageList: groupGarageModel,
allSwitches: allSwitchesOn,
);
},
),
));
}
}

View 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,
),
);
}
}

View File

@ -0,0 +1,150 @@
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);
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 GarageDoorLoadingState
? 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';
}
}

View 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';
}
}

View File

@ -48,6 +48,8 @@ class LightsList extends StatelessWidget {
),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'OFF',
on: 'ON',
switchValue: false,
action: () {},
),

View File

@ -8,7 +8,8 @@ import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart'
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class OneGangList extends StatelessWidget {
const OneGangList({super.key, required this.oneGangList, required this.allSwitches});
const OneGangList(
{super.key, required this.oneGangList, required this.allSwitches});
final List<GroupOneGangModel> oneGangList;
final bool allSwitches;
@ -25,6 +26,8 @@ class OneGangList extends StatelessWidget {
const BodySmall(text: 'All Lights'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'OFF',
on: 'ON',
switchValue: allSwitches,
action: () {
BlocProvider.of<OneGangBloc>(context).add(GroupAllOnEvent());
@ -46,11 +49,14 @@ class OneGangList extends StatelessWidget {
BodySmall(text: oneGangList[index].deviceName),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'OFF',
on: 'ON',
switchValue: oneGangList[index].firstSwitch,
action: () {
BlocProvider.of<OneGangBloc>(context).add(ChangeFirstSwitchStatusEvent(
value: oneGangList[index].firstSwitch,
deviceId: oneGangList[index].deviceId));
BlocProvider.of<OneGangBloc>(context).add(
ChangeFirstWizardSwitchStatusEvent(
value: oneGangList[index].firstSwitch,
deviceId: oneGangList[index].deviceId));
},
),
],

View File

@ -3,9 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_one_gang_model.dart';
import 'package:syncrow_app/features/devices/model/one_gang_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_list.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
@ -22,9 +20,8 @@ class OneGangScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) =>
OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '')
..add(const InitialEvent(groupScreen: false)),
create: (context) => OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '')
..add(const InitialEvent(groupScreen: false)),
child: BlocBuilder<OneGangBloc, OneGangState>(
builder: (context, state) {
OneGangModel oneGangModel = OneGangModel(
@ -32,164 +29,135 @@ class OneGangScreen extends StatelessWidget {
firstCountDown: 0,
);
List<GroupOneGangModel> groupOneGangModel = [];
bool allSwitchesOn = false;
if (state is LoadingNewSate) {
oneGangModel = state.oneGangModel;
} else if (state is UpdateState) {
oneGangModel = state.oneGangModel;
} else if (state is UpdateGroupState) {
groupOneGangModel = state.oneGangList;
allSwitchesOn = state.allSwitches;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
child:
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),
)
: device == null
? OneGangList(
oneGangList: groupOneGangModel,
allSwitches: allSwitchesOn)
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<OneGangBloc>(context).add(InitialEvent(
groupScreen: device != null ? false : true));
},
child: ListView(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(child: SizedBox.shrink()),
Expanded(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
crossAxisAlignment:
CrossAxisAlignment.center,
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<OneGangBloc>(context)
.add(InitialEvent(groupScreen: device != null ? false : true));
},
child: ListView(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(child: SizedBox.shrink()),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
Column(
children: [
GangSwitch(
threeGangSwitch: device!,
value: oneGangModel.firstSwitch,
action: () {
BlocProvider.of<OneGangBloc>(
context)
.add(
ChangeFirstSwitchStatusEvent(
value: oneGangModel
.firstSwitch));
},
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: " Entrance Light",
fontColor: ColorsManager
.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
GangSwitch(
threeGangSwitch: device!,
value: oneGangModel.firstSwitch,
action: () {
BlocProvider.of<OneGangBloc>(context).add(
ChangeFirstSwitchStatusEvent(
value: oneGangModel.firstSwitch));
},
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: " Entrance Light",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(100),
),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context,
animation1,
animation2) =>
TimerScheduleScreen(
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,
),
),
],
),
],
),
),
Expanded(child: SizedBox())
],
],
),
),
),
],
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder:
(context, animation1, animation2) =>
TimerScheduleScreen(
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,
),
),
],
),
],
),
),
Expanded(child: SizedBox())
],
),
),
);
],
),
);
},
),
);

View File

@ -0,0 +1,50 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_event.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_one_gang_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_list.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
class OneGangWizard extends StatelessWidget {
const OneGangWizard({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
List<GroupOneGangModel> groupOneGangModel = [];
return DefaultScaffold(
title: 'Lights',
child: BlocProvider(
create: (context) =>
OneGangBloc(switchCode: '', oneGangId: device?.uuid ?? '')
..add(InitialWizardEvent()),
child: BlocBuilder<OneGangBloc, OneGangState>(
builder: (context, state) {
bool allSwitchesOn = false;
if (state is UpdateGroupState) {
groupOneGangModel = state.oneGangList;
allSwitchesOn = state.allSwitches;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: OneGangList(
oneGangList: groupOneGangModel,
allSwitches: allSwitchesOn,
);
},
),
));
}
}

View File

@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_state.dart';
import 'package:syncrow_app/features/devices/model/group_one_touch_model.dart';
import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class OneTouchList extends StatelessWidget {
const OneTouchList(
{super.key, required this.oneTouchList, required this.allSwitches});
final List<GroupOneTouchModel> oneTouchList;
final bool allSwitches;
@override
Widget build(BuildContext context) {
return BlocBuilder<OneTouchBloc, OneTouchState>(
builder: (context, state) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 10),
const BodySmall(text: 'All Lights'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'OFF',
on: 'ON',
switchValue: allSwitches,
action: () {
BlocProvider.of<OneTouchBloc>(context).add(GroupAllOnEvent());
},
secondAction: () {
BlocProvider.of<OneTouchBloc>(context)
.add(GroupAllOffEvent());
},
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0),
itemCount: oneTouchList.length,
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
BodySmall(text: oneTouchList[index].deviceName),
const SizedBox(height: 5),
DevicesDefaultSwitch(
off: 'OFF',
on: 'ON',
switchValue: oneTouchList[index].firstSwitch,
action: () {
BlocProvider.of<OneTouchBloc>(context).add(
ChangeFirstWizardSwitchStatusEvent(
value: oneTouchList[index].firstSwitch,
deviceId: oneTouchList[index].deviceId));
},
),
],
);
},
),
],
),
);
},
);
}
}

View File

@ -0,0 +1,203 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/one_touch_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/circular_button.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_touch/one_touch_setting.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_touch/one_touch_timer_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.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/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class OneTouchScreen extends StatelessWidget {
const OneTouchScreen({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: device != null
? DeviceAppbar(
deviceName: device!.name!,
deviceUuid: device!.uuid!,
)
: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
text: device?.name ?? 'Lights',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.assetsImagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: SafeArea(
child: Padding(
padding: EdgeInsets.only(
left: Constants.defaultPadding,
right: Constants.defaultPadding,
bottom: Constants.bottomNavBarHeight,
),
child: BlocProvider(
create: (context) =>
OneTouchBloc(switchCode: 'switch_1', oneTouchId: device?.uuid ?? '')
..add(const InitialEvent(groupScreen: false)),
child: BlocBuilder<OneTouchBloc, OneTouchState>(
builder: (context, state) {
OneTouchModel oneTouchModel = OneTouchModel(
firstSwitch: false,
firstCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off);
// List<GroupOneTouchModel> groupOneTouchModel = [];
// bool allSwitchesOn = false;
if (state is LoadingNewSate) {
oneTouchModel = state.oneTouchModel;
} else if (state is UpdateState) {
oneTouchModel = state.oneTouchModel;
}
// else if (state is UpdateGroupState) {
// groupOneTouchModel = state.oneTouchList;
// allSwitchesOn = state.allSwitches;
// }
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50, height: 50, child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<OneTouchBloc>(context)
.add(InitialEvent(groupScreen: device != null ? false : true));
},
child: ListView(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(child: SizedBox.shrink()),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
GangSwitch(
threeGangSwitch: device!,
value: oneTouchModel.firstSwitch,
action: () {
BlocProvider.of<OneTouchBloc>(context).add(
ChangeFirstSwitchStatusEvent(
value: oneTouchModel.firstSwitch));
},
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: " Entrance Light",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
],
),
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircularButton(
device: device,
icons: Icons.access_time,
label: 'Timer',
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder:
(context, animation1, animation2) =>
TimerScheduleScreen(
switchCode: 'switch_1',
device: device!,
deviceCode: 'countdown_1',
)));
},
),
const SizedBox(
width: 30,
),
CircularButton(
device: device,
icons: Icons.settings,
label: 'Setting',
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder:
(context, animation1, animation2) =>
OneTouchSetting(
device: device,
)));
},
),
],
),
),
const Expanded(child: SizedBox())
],
),
),
],
),
);
},
),
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,310 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/one_touch_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/restart_status_dialog.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/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class OneTouchSetting extends StatelessWidget {
const OneTouchSetting({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Setting',
child: BlocProvider(
create: (context) =>
OneTouchBloc(switchCode: '', oneTouchId: device?.uuid ?? '')
..add(const InitialEvent(groupScreen: false)),
child: BlocBuilder<OneTouchBloc, OneTouchState>(
builder: (context, state) {
final oneTouchBloc = BlocProvider.of<OneTouchBloc>(context);
OneTouchModel? oneTouchModel = OneTouchModel(
firstSwitch: false,
firstCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off);
// if (state is UpdateState) {
// oneTouchModel = state.oneTouchModel;
// }
if (state is UpdateState) {
oneTouchModel = state.oneTouchModel;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: Column(
children: [
Container(
child: DefaultContainer(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () async {
oneTouchBloc.optionSelected =
'relay_status';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel: oneTouchBloc
.deviceStatus.relay.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
oneTouchBloc.add(ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status',
label1: 'Power Off',
label2: 'Power On',
label3: 'Restart Memory',
onTapLabel1: (selected) {
oneTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
oneTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
oneTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
Future.delayed(const Duration(seconds: 2),
() async {
oneTouchBloc.add(const InitialEvent(
groupScreen: false));
});
}
},
child: Container(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Restart Status',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: oneTouchBloc
.deviceStatus.relay.value,
fontColor:
ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
)),
),
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () async {
oneTouchBloc.optionSelected = 'light_mode';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
oneTouchModel!.light_mode.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
oneTouchBloc.add(
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Indicator Status',
label1: 'Off',
label2: 'On/Off Status',
label3: 'Switch Position',
onTapLabel1: (selected) {
oneTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
oneTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
oneTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
Future.delayed(
const Duration(seconds: 2),
() async {
oneTouchBloc.add(const InitialEvent(
groupScreen: false));
});
}
},
child: SizedBox(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Indicator Status',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: oneTouchModel
.light_mode.value,
fontColor: ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
)),
),
),
const Divider(
color: ColorsManager.graysColor,
),
Container(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () async {
oneTouchBloc.optionSelected =
'relay_status_1';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
oneTouchModel!
.relay_status_1.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
oneTouchBloc.add(
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status 1',
label1: 'Power Off',
label2: 'Power On',
label3: 'Restart Memory',
onTapLabel1: (selected) {
oneTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
oneTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
oneTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
Future.delayed(
const Duration(seconds: 2),
() async {
oneTouchBloc.add(const InitialEvent(
groupScreen: false));
});
}
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Restart Status 1',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: oneTouchModel
.relay_status_1.value,
fontColor:
ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
),
)),
],
),
),
),
],
);
},
),
));
}
}

View File

@ -0,0 +1,296 @@
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/one_touch_bloc/one_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.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';
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) =>
OneTouchBloc(switchCode: switchCode, oneTouchId: device.uuid ?? '')
..add(GetCounterEvent(deviceCode: deviceCode))
..add(GetScheduleEvent()),
child: BlocBuilder<OneTouchBloc, OneTouchState>(
builder: (context, state) {
final oneTouchBloc = BlocProvider.of<OneTouchBloc>(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) {
oneTouchBloc.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: [
oneTouchBloc.createSchedule == true
? TextButton(
onPressed: () {
oneTouchBloc.add(ScheduleSave());
},
child: const Text('Save'))
: oneTouchBloc.selectedTabIndex == 1
? IconButton(
onPressed: () {
// oneTouchBloc.toggleCreateSchedule();
oneTouchBloc.add(
const ToggleCreateScheduleEvent(
index: 1));
},
icon: const Icon(Icons.add),
)
: const SizedBox(),
],
),
child: state is LoadingInitialState
? 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(
onTap: (value) {
if (value == 0) {
if (oneTouchBloc.createSchedule ==
true) {
// oneTouchBloc.toggleCreateSchedule();
oneTouchBloc.add(
const ToggleCreateScheduleEvent(
index: 0));
}
oneTouchBloc.add(
const ToggleSelectedEvent(
index: 0));
} else {
oneTouchBloc.add(
const ToggleSelectedEvent(
index: 1));
}
},
indicatorColor:
Colors.white, // Customize the indicator
dividerHeight: 0,
indicatorSize: TabBarIndicatorSize.tab,
indicator: const ShapeDecoration(
color: ColorsManager.slidingBlueColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(20)),
),
),
tabs: [
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: BodySmall(
text: 'Countdown',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: Text(
'Schedule',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
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) {
oneTouchBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration: Duration
.zero));
} else if (duration !=
Duration.zero) {
oneTouchBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration:
duration));
}
},
child: SvgPicture.asset(
countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
),
),
),
SizedBox(
child: oneTouchBloc.createSchedule ==
true
? CreateSchedule(
onToggleChanged: (bool isOn) {
oneTouchBloc.toggleSchedule =
isOn;
},
onDateTimeChanged:
(DateTime dateTime) {
oneTouchBloc.selectedTime =
dateTime;
},
days: oneTouchBloc.days,
selectDays: (List<String>
selectedDays) {
oneTouchBloc.selectedDays =
selectedDays;
},
)
: Padding(
padding: const EdgeInsets.only(
top: 10),
child: ScheduleListView(
listSchedule: oneTouchBloc
.listSchedule, // Pass the schedule list here
onDismissed: (scheduleId) {
oneTouchBloc.listSchedule
.removeWhere((schedule) =>
schedule
.scheduleId ==
scheduleId);
oneTouchBloc.add(
DeleteScheduleEvent(
id: scheduleId));
},
onToggleSchedule:
(scheduleId, isEnabled) {
oneTouchBloc.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';
}
}

Some files were not shown because too many files have changed in this diff Show More