Compare commits

..

50 Commits

Author SHA1 Message Date
48327fbbe5 sos 2024-11-14 10:23:00 +03:00
6920d9129e sos 2024-11-14 10:14:28 +03:00
44965d8928 SOS 2024-11-14 09:34:33 +03:00
93f6489d22 sos 2024-11-13 14:54:05 +03:00
69de4b4c00 sos_device 2024-11-13 14:19:50 +03:00
b547a126ed Bug fixes 2024-11-12 00:15:26 +03:00
faf294bb10 Merge pull request #63 from SyncrowIOT/feat/refactor
Feat/refactor
2024-11-11 22:40:06 +03:00
391d6349cc Fixed the assets order 2024-11-05 15:54:48 +04:00
9c873fb0c5 fixed icon assets issue 2024-11-05 15:53:31 +04:00
e9615cd351 Fixed show in device bug 2024-11-05 12:52:11 +04:00
52f6be3db0 updated add to room, and verify to space 2024-11-05 12:27:27 +04:00
34536e6584 updated invitation code api 2024-11-05 11:01:49 +04:00
7d51ca1f12 Fixed bugs in automation 2024-11-05 00:52:38 +04:00
ff31c54e7b reformat 2024-11-04 17:59:55 +04:00
944de7b373 reformat 2024-11-04 17:45:29 +04:00
ab4f8c593d revert 2024-11-04 10:32:13 +04:00
977fd12721 podfile revert 2024-11-04 10:30:50 +04:00
e4a3d4c50b delete scene 2024-11-04 10:28:16 +04:00
29f82945a6 revert back 2024-11-04 10:19:36 +04:00
87a4a88417 fixed automation 2024-11-02 23:10:24 +04:00
dcccc4db3a create subspace 2024-10-31 11:30:35 +04:00
36e5df38ee Merge branch 'dev' of https://github.com/SyncrowIOT/syncrow-app into feat/refactor 2024-10-31 10:45:08 +04:00
7571e35a70 revert 2024-10-31 10:40:29 +04:00
995fd8d0a6 revert 2024-10-31 10:40:05 +04:00
b7b48006af revert config 2024-10-31 10:38:15 +04:00
ea202812cd revert back 2024-10-31 10:35:26 +04:00
79f224f481 revert back env 2024-10-31 10:34:39 +04:00
80d2651370 scene and automation has been updated 2024-10-31 10:19:38 +04:00
7071f50d49 auth_change 2024-10-31 08:35:32 +03:00
13a4bf25b3 added unit devices 2024-10-30 19:16:10 +04:00
f6a12f2e92 Merge pull request #62 from SyncrowIOT/password_changes
password_changes&_routine_changes
2024-10-30 14:23:11 +03:00
5d32fc1213 Resend 2024-10-30 12:18:16 +03:00
bfd9c557ce remove_real_time 2024-10-30 11:56:12 +03:00
5c65bac076 removed logs 2024-10-30 12:27:31 +04:00
489789da0a fixed issues in space 2024-10-30 11:04:36 +04:00
d025da6daf fixed space 2024-10-30 09:56:57 +04:00
5a7ed3ec7c subspace model added 2024-10-29 18:44:41 +04:00
1558996891 models 2024-10-29 18:41:59 +04:00
ef232e9cd5 password_changes&_routine_changes 2024-10-29 17:21:31 +03:00
a1b8c79ce4 Merge pull request #61 from SyncrowIOT/power_clamp_issue
power_clamp_issue&search_issue
2024-10-29 11:10:44 +03:00
70d8bae19d change_size 2024-10-29 11:08:29 +03:00
021f40b8b3 Merged with dev 2024-10-29 10:58:02 +03:00
13f244ff19 power_clamp_issue&search_issue 2024-10-28 17:08:49 +03:00
bcc31d53a1 Enabled real time data 2024-10-28 17:03:05 +03:00
3adb84125a Merge pull request #60 from SyncrowIOT/icon_settings
Icon settings
2024-10-28 16:52:22 +03:00
3d56f33ec3 Implemented tab to run setting 2024-10-28 16:45:59 +03:00
20fdfdde87 icon_settings 2024-10-27 17:21:35 +03:00
7fed2f17af icon_settings 2024-10-27 17:21:13 +03:00
769be41855 con setting 2024-10-27 17:16:37 +03:00
d4d7ced585 Merge pull request #59 from SyncrowIOT/power_clamp
Power clamp
2024-10-27 14:03:24 +03:00
122 changed files with 6004 additions and 1380 deletions

View File

@ -0,0 +1,23 @@
<svg width="35" height="36" viewBox="0 0 35 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.66933 30.6933C5.53419 30.6933 5.39898 30.6418 5.29581 30.5386C5.08955 30.3323 5.08955 29.9979 5.29581 29.7917L13.1989 21.8886C13.4052 21.6823 13.7396 21.6823 13.9459 21.8886C14.1521 22.0949 14.1521 22.4293 13.9459 22.6355L6.04286 30.5386C5.93969 30.6418 5.80448 30.6933 5.66933 30.6933Z" fill="#E9EDF1"/>
<path d="M20.7589 15.6035C20.6238 15.6035 20.4886 15.552 20.3854 15.4488C20.1791 15.2425 20.1791 14.9081 20.3854 14.7019L28.9575 6.1298C29.1639 5.92353 29.4982 5.92353 29.7045 6.1298C29.9108 6.33607 29.9108 6.6705 29.7045 6.8767L21.1325 15.4488C21.0293 15.5519 20.8941 15.6035 20.7589 15.6035Z" fill="#E9EDF1"/>
<path d="M29.3309 30.6232C29.1958 30.6232 29.0605 30.5716 28.9574 30.4684L23.4486 24.9597C23.2424 24.7534 23.2424 24.419 23.4486 24.2128C23.655 24.0065 23.9894 24.0065 24.1956 24.2128L29.7043 29.7215C29.9106 29.9278 29.9106 30.2622 29.7043 30.4684C29.6013 30.5716 29.466 30.6232 29.3309 30.6232Z" fill="#E9EDF1"/>
<path d="M11.2132 12.5055C11.0781 12.5055 10.9429 12.4539 10.8397 12.3508L5.33097 6.84203C5.1247 6.63576 5.1247 6.30133 5.33097 6.09513C5.53731 5.88886 5.87167 5.88886 6.07794 6.09513L11.5867 11.6039C11.7929 11.8101 11.7929 12.1446 11.5867 12.3508C11.4835 12.4539 11.3484 12.5055 11.2132 12.5055Z" fill="#E9EDF1"/>
<path d="M29.1335 15.7045H27.1526C27.0645 15.7045 26.9878 15.6461 26.9631 15.5616C26.7624 14.8743 26.4885 14.2186 26.1511 13.6024C26.1089 13.525 26.1216 13.4299 26.1835 13.3672L27.585 11.9658C27.6624 11.8891 27.6624 11.7644 27.585 11.6869L24.1462 8.24822C24.0688 8.17075 23.9441 8.17075 23.8673 8.24822L22.4659 9.64962C22.4033 9.71159 22.3082 9.72427 22.2307 9.68202C21.6145 9.34469 20.9589 9.07075 20.2716 8.87005C20.1871 8.8454 20.1286 8.76864 20.1286 8.68061V6.69962C20.1286 6.59047 20.0406 6.50244 19.9314 6.50244H15.0681C14.9589 6.50244 14.8709 6.59047 14.8709 6.69962V8.68061C14.8709 8.76864 14.8124 8.8454 14.7279 8.87005C14.0406 9.07075 13.385 9.34469 12.7688 9.68202C12.6913 9.72427 12.5962 9.71159 12.5335 9.64962L11.1321 8.24822C11.0554 8.17075 10.9307 8.17075 10.8533 8.24822L7.41454 11.6869C7.33707 11.7644 7.33707 11.8891 7.41454 11.9658L8.81595 13.3672C8.87792 13.4299 8.89059 13.525 8.84834 13.6024C8.5258 14.1919 8.26102 14.8165 8.06313 15.4714C8.05397 15.501 8.06454 15.5651 8.05538 15.5954C8.03073 15.6799 7.95397 15.7384 7.86595 15.7384L6.03214 15.8306C5.92299 15.8306 5.83496 15.9186 5.83496 16.0278L5.86524 20.5644C5.86524 20.6736 5.95327 20.7616 6.06243 20.7616L7.93848 20.7679C8.02651 20.7679 8.10327 20.8264 8.12792 20.9109C8.32862 21.5982 8.71242 22.4461 9.04975 23.0623C9.092 23.1398 9.07933 23.2348 9.01735 23.2975L7.62721 24.7038C7.54975 24.7806 7.54975 24.9052 7.62721 24.9827L10.8575 28.0503C10.935 28.1278 11.0596 28.1278 11.1364 28.0503L12.4399 26.8398C12.5026 26.7778 12.5976 26.7651 12.6751 26.8074C13.2913 27.1447 14.2645 27.4503 14.9519 27.651C15.0364 27.6757 15.0948 27.7524 15.0948 27.8405L15.0413 29.7524C15.0413 29.8616 15.1293 29.9496 15.2385 29.9496L19.7159 29.9081C19.8251 29.9081 19.9131 29.82 19.9131 29.7109L19.9645 27.8764C19.9645 27.7883 20.023 27.7116 20.1075 27.6869C20.5575 27.556 21.1371 27.4771 21.5575 27.2855C21.6258 27.2545 21.7814 27.2158 21.7814 27.2158C21.9335 27.1426 22.0835 27.0658 22.2307 26.9848C22.3082 26.9426 22.4033 26.9552 22.4659 27.0172L23.8673 28.4186C23.9441 28.4961 24.0688 28.4961 24.1462 28.4186L27.585 24.9799C27.6624 24.9024 27.6624 24.7778 27.585 24.701L26.1835 23.2996C26.1216 23.2369 26.1089 23.1419 26.1511 23.0644C26.4885 22.4482 26.7624 21.7926 26.9631 21.1052C26.9878 21.0207 27.0645 20.9623 27.1526 20.9623H29.1335C29.2427 20.9623 29.3307 20.8743 29.3307 20.7651V15.9017C29.3307 15.7926 29.2427 15.7045 29.1335 15.7045ZM17.5399 21.2693C15.8962 21.2693 14.5638 19.9369 14.5638 18.2933C14.5638 16.6496 15.8962 15.3172 17.5399 15.3172C19.1835 15.3172 20.5159 16.6496 20.5159 18.2933C20.5159 19.9369 19.1835 21.2693 17.5399 21.2693Z" fill="#C3C1C9"/>
<path d="M21.7816 27.2158C21.2992 27.4489 20.7943 27.6439 20.2718 27.7967C20.1872 27.8214 20.1288 27.8982 20.1288 27.9862V29.9672C20.1288 30.0763 20.0408 30.1644 19.9316 30.1644H15.0682C14.9591 30.1644 14.8711 30.0763 14.8711 29.9672V27.9862C14.8711 27.8982 14.8126 27.8214 14.7281 27.7967C14.0408 27.596 13.3851 27.3221 12.7689 26.9848C12.6915 26.9425 12.5964 26.9552 12.5337 27.0172L11.1323 28.4186C11.0556 28.496 10.9309 28.496 10.8534 28.4186L7.41472 24.9798C7.33725 24.9024 7.33725 24.7777 7.41472 24.701L8.81613 23.2996C8.8781 23.2369 8.89078 23.1418 8.84852 23.0644C8.5112 22.4482 8.23725 21.7925 8.03655 21.1052C8.0119 21.0207 7.93514 20.9622 7.84711 20.9622H5.86613C5.75697 20.9622 5.66895 20.8742 5.66895 20.7651V15.9017C5.66895 15.7925 5.75697 15.7045 5.86613 15.7045H7.84711C7.93514 15.7045 8.0119 15.6461 8.03655 15.5615C8.045 15.5313 8.05352 15.5008 8.06338 15.4712C8.12747 22.0367 13.4704 27.3397 20.0513 27.3397C20.6387 27.3397 21.2168 27.2975 21.7816 27.2158Z" fill="#ADACB5"/>
<path d="M17.5401 12.272C14.2148 12.272 11.5183 14.9677 11.5183 18.2938C11.5183 21.6192 14.2148 24.3156 17.5401 24.3156C20.8662 24.3156 23.562 21.6192 23.562 18.2938C23.562 14.9677 20.8662 12.272 17.5401 12.272ZM17.5401 20.653C16.2373 20.653 15.181 19.5966 15.181 18.2938C15.181 16.991 16.2373 15.9346 17.5401 15.9346C18.843 15.9346 19.8993 16.991 19.8993 18.2938C19.8993 19.5966 18.843 20.653 17.5401 20.653Z" fill="#ADACB5"/>
<path d="M34.9999 4.53117C34.9999 2.48926 33.3446 0.833984 31.3027 0.833984C30.589 0.833984 29.9225 1.03624 29.3574 1.38652C29.3574 1.38652 29.164 1.54589 29.0626 1.62441C28.1892 2.30067 27.7471 3.3411 27.7471 4.53124C27.7471 6.57314 29.2607 8.01637 31.3026 8.01637C32.404 8.01637 33.3538 7.71511 34.0312 6.95102C34.114 6.85757 34.3045 6.68997 34.3045 6.68997C34.7421 6.0825 34.9999 5.33694 34.9999 4.53117Z" fill="#73C2FB"/>
<path d="M34.3045 6.69058C33.6334 7.62227 32.5386 8.22903 31.3026 8.22903C29.2611 8.22903 27.6055 6.5734 27.6055 4.53185C27.6055 3.20368 28.306 2.03862 29.3574 1.38721C28.9193 1.99425 28.6618 2.7403 28.6618 3.54594C28.6618 5.58749 30.3174 7.24312 32.359 7.24312C33.0731 7.24312 33.7397 7.04129 34.3045 6.69058Z" fill="#4B9CD3"/>
<path d="M31.3028 6.11652C32.1779 6.11652 32.8873 5.40711 32.8873 4.53202C32.8873 3.65692 32.1779 2.94751 31.3028 2.94751C30.4277 2.94751 29.7183 3.65692 29.7183 4.53202C29.7183 5.40711 30.4277 6.11652 31.3028 6.11652Z" fill="#4B9CD3"/>
<path d="M7.39434 4.53117C7.39434 2.48926 5.73906 0.833984 3.69716 0.833984C2.98343 0.833984 2.31695 1.03624 1.75188 1.38652C1.75188 1.38652 1.55843 1.54589 1.45709 1.62441C0.583714 2.3006 0.141602 3.3411 0.141602 4.53117C0.141602 6.57307 1.65526 8.0163 3.69716 8.0163C4.79857 8.0163 5.74836 7.71504 6.42568 6.95095C6.50857 6.8575 6.69899 6.6899 6.69899 6.6899C7.1366 6.0825 7.39434 5.33694 7.39434 4.53117Z" fill="#7CB9E8"/>
<path d="M6.69901 6.69058C6.02788 7.62227 4.9331 8.22903 3.69718 8.22903C1.65563 8.22903 0 6.5734 0 4.53185C0 3.20368 0.700493 2.03862 1.7519 1.38721C1.31387 1.99425 1.05634 2.7403 1.05634 3.54594C1.05634 5.58749 2.71197 7.24312 4.75352 7.24312C5.4676 7.24312 6.13422 7.04129 6.69901 6.69058Z" fill="#6699CC"/>
<path d="M3.69705 6.11652C4.57215 6.11652 5.28156 5.40711 5.28156 4.53202C5.28156 3.65692 4.57215 2.94751 3.69705 2.94751C2.82196 2.94751 2.11255 3.65692 2.11255 4.53202C2.11255 5.40711 2.82196 6.11652 3.69705 6.11652Z" fill="#6699CC"/>
<path d="M35.0001 32.1376C35.0001 30.0957 33.3448 28.4404 31.3029 28.4404C30.5892 28.4404 29.9227 28.6427 29.3577 28.993C29.3577 28.993 29.1642 29.1523 29.0629 29.2309C28.1894 29.9071 27.7473 30.9475 27.7473 32.1377C27.7473 34.1796 29.261 35.6228 31.3029 35.6228C32.4043 35.6228 33.3541 35.3216 34.0314 34.5575C34.1143 34.464 34.3047 34.2964 34.3047 34.2964C34.7424 33.6889 35.0001 32.9434 35.0001 32.1376Z" fill="#6086FF"/>
<path d="M34.305 34.2956C33.6338 35.2273 32.5391 35.834 31.3031 35.834C29.2616 35.834 27.606 34.1784 27.606 32.1368C27.606 30.8087 28.3065 29.6436 29.3579 28.9922C28.9198 29.5992 28.6623 30.3453 28.6623 31.1509C28.6623 33.1925 30.3179 34.8481 32.3595 34.8481C33.0736 34.8481 33.7402 34.6463 34.305 34.2956Z" fill="#023DFE"/>
<path d="M31.3033 33.7217C32.1784 33.7217 32.8878 33.0123 32.8878 32.1372C32.8878 31.2621 32.1784 30.5527 31.3033 30.5527C30.4282 30.5527 29.7188 31.2621 29.7188 32.1372C29.7188 33.0123 30.4282 33.7217 31.3033 33.7217Z" fill="#023DFE"/>
<path d="M7.39434 32.1376C7.39434 30.0957 5.73906 28.4404 3.69716 28.4404C2.98343 28.4404 2.31695 28.6427 1.75188 28.993C1.75188 28.993 1.55843 29.1523 1.45709 29.2309C0.583714 29.907 0.141602 30.9475 0.141602 32.1376C0.141602 34.1795 1.65526 35.6228 3.69716 35.6228C4.79857 35.6228 5.74836 35.3215 6.42568 34.5574C6.50857 34.4639 6.69899 34.2963 6.69899 34.2963C7.1366 33.6889 7.39434 32.9434 7.39434 32.1376Z" fill="#76ABDF"/>
<path d="M6.69901 34.2956C6.02788 35.2273 4.9331 35.834 3.69718 35.834C1.65563 35.834 0 34.1784 0 32.1368C0 30.8087 0.700493 29.6436 1.7519 28.9922C1.31387 29.5992 1.05634 30.3453 1.05634 31.1509C1.05634 33.1925 2.71197 34.8481 4.75352 34.8481C5.4676 34.8481 6.13422 34.6463 6.69901 34.2956Z" fill="#4682B4"/>
<path d="M3.69705 33.7217C4.57215 33.7217 5.28156 33.0123 5.28156 32.1372C5.28156 31.2621 4.57215 30.5527 3.69705 30.5527C2.82196 30.5527 2.11255 31.2621 2.11255 32.1372C2.11255 33.0123 2.82196 33.7217 3.69705 33.7217Z" fill="#4682B4"/>
<path d="M11.5185 18.8222C11.6454 18.8222 11.7693 18.7765 11.8664 18.6915L13.8114 16.9891C14.0309 16.797 14.0532 16.4634 13.861 16.2439C13.669 16.0243 13.3352 16.0022 13.1157 16.1943L12.2055 16.9909C12.7957 14.5928 14.9731 12.8005 17.54 12.8005C19.8371 12.8005 21.9109 14.2491 22.7002 16.4051C22.8006 16.6791 23.1037 16.8198 23.3778 16.7195C23.6517 16.6192 23.7925 16.3158 23.6922 16.0419C22.751 13.4713 20.2786 11.7441 17.54 11.7441C15.8053 11.7441 14.1704 12.4155 12.9366 13.6347C12.1095 14.452 11.5277 15.4527 11.2267 16.5455L10.8242 15.7489C10.6926 15.4885 10.3748 15.384 10.1146 15.5156C9.85425 15.6472 9.74974 15.9648 9.88136 16.2252L11.0471 18.5322C11.1207 18.6779 11.2575 18.7814 11.4178 18.8125C11.4513 18.819 11.485 18.8222 11.5185 18.8222Z" fill="#F7F9FA"/>
<path d="M25.1992 20.368L24.0335 18.061C23.9598 17.9153 23.823 17.8118 23.6627 17.7807C23.5027 17.7496 23.337 17.7942 23.2142 17.9018L21.2691 19.6042C21.0496 19.7963 21.0273 20.1299 21.2195 20.3494C21.4116 20.5689 21.7452 20.5911 21.9648 20.399L22.8727 19.6044C22.2802 21.999 20.1049 23.7877 17.5399 23.7877C15.2331 23.7877 13.1564 22.3309 12.3722 20.1627C12.273 19.8883 11.9701 19.7463 11.6959 19.8456C11.4215 19.9449 11.2796 20.2476 11.3788 20.522C12.3137 23.1071 14.7897 24.844 17.5399 24.844C19.2753 24.844 20.9105 24.1721 22.1446 22.9522C22.9704 22.1357 23.5515 21.1364 23.8524 20.0451L24.2563 20.8444C24.3492 21.0284 24.5351 21.1345 24.7281 21.1345C24.8082 21.1345 24.8895 21.1162 24.9659 21.0776C25.2263 20.9461 25.3308 20.6284 25.1992 20.368Z" fill="#F7F9FA"/>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
<desc>Created with Fabric.js 5.2.4</desc>
<defs>
</defs>
<g transform="matrix(1 0 0 1 540 540)" id="08fc7ff7-a606-462d-8969-ede27d8e77f9" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(1 0 0 1 540 540)" id="6aac87eb-d0cb-4bcd-affa-b5008406fb16" >
</g>
<g transform="matrix(56.84 0 0 56.84 540 540)" >
<g style="" >
<g transform="matrix(1 0 0 1 3 -6)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12.5, -4.5)" d="M 10.1364 7.1194 L 7.03409 4.29851 L 6 5.23881 L 10.1364 9 L 19 0.940299 L 17.9659 0 L 10.1364 7.1194 Z" stroke-linecap="round" />
</g>
<g transform="matrix(1 0 0 1 -2.63 1.24)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: evenodd; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-6.87, -11.74)" d="M 2.29002 7.87775 C 2.29002 11.6677 5.3701 14.7478 9.16009 14.7478 L 9.16009 11.3128 L 13.7401 15.8928 L 9.16009 20.4729 L 9.16009 17.0378 C 4.09914 17.0378 0 12.9387 0 7.87775 C 0 6.08008 0.526705 4.40836 1.41981 3 L 3.09153 4.67172 C 2.57628 5.62208 2.29002 6.72129 2.29002 7.87775 Z" stroke-linecap="round" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.3258 4.08383C15.0587 3.35098 15.0585 2.16495 14.3258 1.43217L13.4419 0.548297C12.7108 -0.182766 11.5213 -0.182766 10.7902 0.548297L2.54069 8.79789C2.06572 9.27286 1.75181 9.90067 1.65681 10.5656L1.21484 13.6592L4.30847 13.2173C4.97341 13.1223 5.60122 12.8084 6.07619 12.3334L14.3258 4.08383ZM4.16112 8.9452L9.46444 3.64189L11.2322 5.40964L5.92891 10.713L4.16112 8.9452ZM2.688 12.1861L2.89425 10.7425C2.94141 10.4125 3.07863 10.0979 3.28581 9.83764L5.0365 11.5883C4.77628 11.7955 4.46172 11.9327 4.13172 11.9799L2.688 12.1861ZM13.4419 3.19992L12.1161 4.52577L10.3483 2.75802L11.6742 1.4322C11.9178 1.18852 12.3143 1.18852 12.558 1.4322L13.4419 2.31608C13.6862 2.56039 13.6861 2.95577 13.4419 3.19992Z" fill="#D5D5D5"/>
<path d="M0 14.749H16V15.999H0V14.749Z" fill="#D5D5D5"/>
</svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.3258 4.08383C15.0587 3.35098 15.0585 2.16495 14.3258 1.43217L13.4419 0.548297C12.7108 -0.182766 11.5213 -0.182766 10.7902 0.548297L2.54069 8.79789C2.06572 9.27286 1.75181 9.90067 1.65681 10.5656L1.21484 13.6592L4.30847 13.2173C4.97341 13.1223 5.60122 12.8084 6.07619 12.3334L14.3258 4.08383ZM4.16112 8.9452L9.46444 3.64189L11.2322 5.40964L5.92891 10.713L4.16112 8.9452ZM2.688 12.1861L2.89425 10.7425C2.94141 10.4125 3.07863 10.0979 3.28581 9.83764L5.0365 11.5883C4.77628 11.7955 4.46172 11.9327 4.13172 11.9799L2.688 12.1861ZM13.4419 3.19992L12.1161 4.52577L10.3483 2.75802L11.6742 1.4322C11.9178 1.18852 12.3143 1.18852 12.558 1.4322L13.4419 2.31608C13.6862 2.56039 13.6861 2.95577 13.4419 3.19992Z" fill="#D5D5D5"/>
<path d="M0 14.749H16V15.999H0V14.749Z" fill="#D5D5D5"/>
</svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -0,0 +1,16 @@
<svg width="100" height="139" viewBox="0 0 100 139" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.5419 20.2425C11.1182 19.3486 10.0545 18.9679 9.16647 19.3936L1.38334 23.1269C0.591819 23.3099 0 24.0198 0 24.8727V33.8466C0 34.8381 0.797668 35.6414 1.78229 35.6414C2.76668 35.6414 3.56412 34.8381 3.56412 33.8466V27.6645L9.16647 30.3517C9.41376 30.4705 9.67449 30.5264 9.93112 30.5264C10.5974 30.5264 11.2359 30.1484 11.5419 29.5026C11.9643 28.6076 11.5875 27.5367 10.699 27.1104L6.03295 24.8725L10.699 22.6347C11.5877 22.2085 11.9643 21.1376 11.5419 20.2425Z" fill="#D5D5D5"/>
<path d="M20.6084 17.6894C20.8655 17.6894 21.1257 17.6335 21.3737 17.5147L32.0481 12.3952C32.9366 11.9685 33.3141 10.8974 32.891 10.0025C32.4682 9.10867 31.4052 8.72817 30.5156 9.15363L19.8408 14.2736C18.9522 14.7 18.5754 15.7706 18.998 16.6658C19.3038 17.3112 19.9423 17.6894 20.6084 17.6894Z" fill="#D5D5D5"/>
<path d="M42.7227 7.27445L48.1841 4.65449V10.9114C48.1841 11.9027 48.9818 12.7061 49.9659 12.7061C50.9503 12.7061 51.7478 11.9027 51.7478 10.9114V4.62192L57.2779 7.27445C57.5259 7.39303 57.7862 7.44922 58.0433 7.44922C58.7091 7.44922 59.3478 7.07124 59.6534 6.42537C60.0763 5.53041 59.6994 4.45953 58.8106 4.03316L50.7663 0.174427C50.2813 -0.0581424 49.7189 -0.0581424 49.2338 0.174427L41.19 4.03316C40.3015 4.45953 39.9244 5.53018 40.3472 6.42537C40.771 7.32101 41.8362 7.70198 42.7227 7.27445Z" fill="#D5D5D5"/>
<path d="M67.9533 12.3944L78.6281 17.5146C78.875 17.6334 79.1361 17.6894 79.3932 17.6894C80.059 17.6894 80.6978 17.3114 81.0034 16.6655C81.426 15.7705 81.0494 14.6997 80.1606 14.2733L69.4856 9.15287C68.5982 8.72718 67.5345 9.10722 67.1105 10.0017C66.6875 10.8967 67.0645 11.9676 67.9533 12.3944Z" fill="#D5D5D5"/>
<path d="M81.539 34.8099C82.4275 34.3838 82.8046 33.3129 82.3815 32.4177C81.9587 31.5232 80.8946 31.1425 80.0065 31.5695L73.167 34.851L51.7477 24.5771V16.5766C51.7477 15.5846 50.9503 14.7819 49.9659 14.7819C48.9817 14.7819 48.1841 15.5848 48.1841 16.5766V24.6096L26.8346 34.85L20.6999 31.9074C19.8093 31.481 18.7482 31.8613 18.3244 32.7565C17.9016 33.6514 18.2787 34.7225 19.1672 35.1489L25.8031 38.3319V61.6685L19.0593 64.9031C18.1707 65.3295 17.7939 66.4002 18.2165 67.2956C18.5221 67.9412 19.1606 68.3192 19.8266 68.3192C20.0837 68.3192 20.3447 68.2632 20.5917 68.1444L26.8349 65.1499L48.1841 75.3903V81.5075C48.1841 82.4993 48.9817 83.3023 49.9659 83.3023C50.9503 83.3023 51.7477 82.4991 51.7477 81.5075V75.4234L73.1657 65.1502L79.6524 68.2616C79.9002 68.3802 80.1607 68.4364 80.4175 68.4364C81.0834 68.4364 81.7221 68.0584 82.0277 67.4125C82.4508 66.5176 82.0735 65.4467 81.1849 65.0201L74.1977 61.6687V38.3319L81.539 34.8099ZM70.634 62.388L51.7479 71.4467V49.0994L70.634 40.0402V62.388ZM29.4788 61.8939C29.4472 61.827 29.4053 61.7692 29.3668 61.7082V40.0404L48.1841 49.0664V71.4142L29.6409 62.5199C29.6239 62.3086 29.5745 62.0965 29.4788 61.8939ZM50.0003 27.7152L69.0207 36.8384L50.0003 45.9611L30.9799 36.8384L50.0003 27.7152Z" fill="#D5D5D5"/>
<path d="M78.6271 82.4859L67.9525 87.6061C67.0639 88.0327 66.6864 89.1036 67.1095 89.9979C67.4153 90.644 68.054 91.0215 68.7199 91.0215C68.9767 91.0215 69.2379 90.9655 69.485 90.8477L80.1598 85.7272C81.0483 85.3009 81.4252 84.2295 81.0025 83.3346C80.579 82.4401 79.5149 82.0616 78.6271 82.4859Z" fill="#D5D5D5"/>
<path d="M57.2782 92.7265L51.748 95.3793V88.227C51.748 87.2357 50.9506 86.4323 49.9662 86.4323C48.982 86.4323 48.1844 87.2357 48.1844 88.227V95.3467L42.723 92.7265C41.8335 92.3022 40.7713 92.6807 40.3475 93.5759C39.9246 94.4708 40.3015 95.5412 41.1903 95.9676L49.2346 99.8259C49.4769 99.9417 49.7387 100 50.0008 100C50.2629 100 50.5248 99.9417 50.7671 99.8259L58.8114 95.9676C59.6999 95.5412 60.077 94.4708 59.6541 93.5759C59.2304 92.6807 58.166 92.3031 57.2782 92.7265Z" fill="#D5D5D5"/>
<path d="M32.0477 87.6061L21.3729 82.4859C20.4864 82.0605 19.4219 82.4394 18.9976 83.3343C18.575 84.2293 18.9519 85.3006 19.8404 85.727L30.5154 90.8474C30.7623 90.9653 31.0235 91.0213 31.2803 91.0213C31.9461 91.0213 32.5849 90.6438 32.8905 89.9977C33.3133 89.1036 32.9362 88.0327 32.0477 87.6061Z" fill="#D5D5D5"/>
<path d="M11.5419 70.4973C11.1182 69.6028 10.0545 69.2239 9.16647 69.6487L3.56412 72.3354V65.6177C3.56412 64.6264 2.76668 63.823 1.78229 63.823C0.797668 63.823 0 64.6264 0 65.6177V74.5918C0 74.8162 0.0457694 75.0283 0.120686 75.2262C0.156892 75.8783 0.53193 76.465 1.12215 76.7485L9.16647 80.6072C9.41376 80.7254 9.67449 80.7818 9.93112 80.7818C10.5974 80.7818 11.2359 80.4038 11.5419 79.7581C11.9643 78.8632 11.5875 77.7923 10.699 77.3655L6.03295 75.1281L10.699 72.8902C11.5877 72.4636 11.9643 71.3923 11.5419 70.4973Z" fill="#D5D5D5"/>
<path d="M1.78229 56.8226C2.76668 56.8226 3.56412 56.0194 3.56412 55.0274V44.4374C3.56412 43.4461 2.76668 42.6427 1.78229 42.6427C0.797668 42.6427 0 43.4461 0 44.4374V55.0274C0.00022771 56.0194 0.797896 56.8226 1.78229 56.8226Z" fill="#D5D5D5"/>
<path d="M98.6173 23.1267L90.8342 19.3935C89.9443 18.9666 88.8825 19.3478 88.4589 20.2423C88.0363 21.1377 88.4132 22.2084 89.3017 22.635L93.9677 24.8729L89.3017 27.1107C88.4132 27.5371 88.0363 28.6077 88.4589 29.5029C88.7645 30.1488 89.4032 30.5268 90.0691 30.5268C90.3262 30.5268 90.5873 30.4708 90.8342 30.352L96.4365 27.6648V33.847C96.4365 34.8385 97.234 35.6417 98.2184 35.6417C99.2027 35.6417 100 34.8385 100 33.847V24.8731C100 24.0196 99.4088 23.3098 98.6173 23.1267Z" fill="#D5D5D5"/>
<path d="M98.2184 42.642C97.2337 42.642 96.4365 43.4454 96.4365 44.4367V55.0266C96.4365 56.0186 97.234 56.8214 98.2184 56.8214C99.2027 56.8214 100 56.0184 100 55.0266V44.4367C100 43.4454 99.203 42.642 98.2184 42.642Z" fill="#D5D5D5"/>
<path d="M98.2184 63.8228C97.2337 63.8228 96.4365 64.6262 96.4365 65.6175V72.3352L90.8342 69.6485C89.9443 69.223 88.8825 69.6021 88.4589 70.4971C88.0363 71.392 88.4132 72.4634 89.3017 72.8898L93.9677 75.1276L89.3017 77.365C88.4132 77.7918 88.0363 78.8627 88.4589 79.7577C88.7645 80.4033 89.4032 80.7813 90.0691 80.7813C90.3262 80.7813 90.5873 80.7249 90.8342 80.6068L98.8785 76.748C99.4687 76.4645 99.8438 75.8778 99.88 75.2258C99.9546 75.0278 100 74.8157 100 74.5914V65.6173C100 64.6262 99.203 63.8228 98.2184 63.8228Z" fill="#D5D5D5"/>
<path d="M28.6625 123.289H30.3578V135H28.7094L22.4906 126.25V135H20.8109V123.289H22.4359L28.6625 132.055V123.289ZM37.4631 135.18V135.188C36.0829 135.188 34.9501 134.729 34.0647 133.812C33.1845 132.901 32.7444 131.776 32.7444 130.438C32.7444 129.115 33.1845 128.005 34.0647 127.109C34.9501 126.208 36.0829 125.758 37.4631 125.758C38.8381 125.758 39.9709 126.208 40.8616 127.109C41.7522 128.005 42.1975 129.115 42.1975 130.438C42.1975 131.771 41.7522 132.896 40.8616 133.812C39.9709 134.724 38.8381 135.18 37.4631 135.18ZM37.4631 127.234V127.242C36.536 127.242 35.7913 127.547 35.2288 128.156C34.6663 128.766 34.385 129.534 34.385 130.461C34.385 131.404 34.6663 132.182 35.2288 132.797C35.7913 133.417 36.536 133.727 37.4631 133.727C38.3902 133.727 39.135 133.417 39.6975 132.797C40.26 132.182 40.5413 131.401 40.5413 130.453C40.5413 129.526 40.26 128.758 39.6975 128.148C39.135 127.539 38.3902 127.234 37.4631 127.234ZM57.2753 133.492V135H49.6816V123.289H51.3612V133.492H57.2753ZM62.9119 135.18V135.188C61.5317 135.188 60.3989 134.729 59.5134 133.812C58.6332 132.901 58.1931 131.776 58.1931 130.438C58.1931 129.115 58.6332 128.005 59.5134 127.109C60.3989 126.208 61.5317 125.758 62.9119 125.758C64.2869 125.758 65.4197 126.208 66.3103 127.109C67.2009 128.005 67.6462 129.115 67.6462 130.438C67.6462 131.771 67.2009 132.896 66.3103 133.812C65.4197 134.724 64.2869 135.18 62.9119 135.18ZM62.9119 127.234V127.242C61.9848 127.242 61.24 127.547 60.6775 128.156C60.115 128.766 59.8337 129.534 59.8337 130.461C59.8337 131.404 60.115 132.182 60.6775 132.797C61.24 133.417 61.9848 133.727 62.9119 133.727C63.839 133.727 64.5837 133.417 65.1462 132.797C65.7087 132.182 65.99 131.401 65.99 130.453C65.99 129.526 65.7087 128.758 65.1462 128.148C64.5837 127.539 63.839 127.234 62.9119 127.234ZM76.7203 125.93H78.3141V134.266C78.3141 137.26 76.7411 138.758 73.5953 138.758C72.0276 138.758 70.7047 138.359 69.6266 137.562L70.3531 136.328C71.3115 136.99 72.3583 137.32 73.4938 137.32C75.6396 137.32 76.7125 136.271 76.7125 134.172V133.641C75.999 134.667 74.9052 135.18 73.4313 135.18C72.2385 135.18 71.2438 134.747 70.4469 133.883C69.65 133.013 69.2516 131.87 69.2516 130.453C69.2516 129.052 69.6474 127.917 70.4391 127.047C71.2255 126.182 72.2255 125.75 73.4391 125.75C74.913 125.75 76.0068 126.263 76.7203 127.289V125.93ZM73.8844 133.688V133.695C74.7698 133.695 75.4625 133.385 75.9625 132.766C76.4625 132.151 76.7125 131.385 76.7125 130.469C76.7125 129.531 76.4625 128.758 75.9625 128.148C75.4625 127.539 74.7698 127.234 73.8844 127.234C72.9781 127.234 72.2516 127.542 71.7047 128.156C71.1578 128.771 70.8844 129.536 70.8844 130.453C70.8844 131.359 71.1578 132.125 71.7047 132.75C72.2516 133.375 72.9781 133.688 73.8844 133.688Z" fill="#D5D5D5"/>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -0,0 +1,9 @@
<svg width="61" height="78" viewBox="0 0 61 78" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.4903 47.9279L16.8438 49.2221C16.8166 49.2741 16.8032 49.3322 16.8049 49.3909C16.8067 49.4496 16.8234 49.5069 16.8537 49.5573C16.8839 49.6076 16.9266 49.6493 16.9776 49.6784C17.0286 49.7075 17.0862 49.723 17.145 49.7234H22.5828L23.7334 44.1986H19.5621C19.4988 44.1983 19.4366 44.2158 19.3827 44.249C19.3287 44.2822 19.2852 44.3298 19.2568 44.3864L18.8425 45.2013L7.5883 30.867C8.6698 18.425 13.1546 7.9471 19.3604 2.1377C13.9907 4.23837 9.33495 7.83301 5.94387 12.4964C2.55279 17.1598 0.568261 22.6969 0.225024 28.4527C0.208229 28.7362 0.28111 29.0177 0.433331 29.2575C0.585552 29.4972 0.809388 29.6829 1.07309 29.7883C2.01199 30.1535 2.97179 30.4626 3.94741 30.7137L17.4903 47.9279Z" fill="#E9E9E9"/>
<path d="M20.5167 32.9022C20.8068 20.3124 22.6162 7.15076 26.054 0.922852C17.8068 4.28197 11.3855 16.5624 10.2639 31.9561C12.9946 32.3497 16.3855 32.6867 20.5167 32.9022Z" fill="#E9E9E9"/>
<path d="M29.2309 33.1492V44.199H26.5555L25.4049 49.7239H35.8207L34.6688 44.199H31.9933V33.1492C34.1163 33.1368 36.0914 33.094 37.9326 33.0277C37.4837 12.2321 33.4201 0.313537 30.695 0H30.6121H30.5334C27.7972 0.330111 23.7406 12.2445 23.2861 33.0111C25.1328 33.0871 27.108 33.1299 29.2309 33.1492Z" fill="#E9E9E9"/>
<path d="M25.0867 60.4366L25.7676 59.7557C26.1351 59.3987 26.6258 59.1965 27.1382 59.1911C27.6506 59.1857 28.1454 59.3775 28.5204 59.7267L30.6115 61.8289L32.6709 59.7571C33.038 59.3989 33.5289 59.1959 34.0417 59.19C34.5545 59.184 35.0498 59.3757 35.4251 59.7253L36.1364 60.4352V52.4863H25.0867V60.4366Z" fill="#E9E9E9"/>
<path d="M38.8993 52.4856V62.3751C38.9008 62.7626 38.7872 63.1417 38.5729 63.4645C38.3586 63.7872 38.0533 64.0391 37.6957 64.1881C37.3381 64.3371 36.9442 64.3765 36.5642 64.3014C36.1841 64.2262 35.8349 64.0399 35.5609 63.766L34.065 62.2715L32.0043 64.3434C31.6256 64.7048 31.123 64.9074 30.5996 64.9097C30.0973 64.9106 29.6138 64.7188 29.2487 64.3738L27.1589 62.2715L25.6645 63.766C25.3905 64.0404 25.0412 64.2271 24.6609 64.3025C24.2806 64.378 23.8865 64.3386 23.5285 64.1896C23.1706 64.0405 22.8651 63.7885 22.6507 63.4654C22.4364 63.1423 22.3229 62.7628 22.3247 62.3751V52.4856H17.1451C17.0292 52.4779 16.9139 52.4631 16.7998 52.4414V75.9663C16.7998 76.3326 16.9453 76.684 17.2044 76.943C17.4634 77.202 17.8147 77.3475 18.181 77.3475H43.043C43.4093 77.3475 43.7606 77.202 44.0196 76.943C44.2787 76.684 44.4242 76.3326 44.4242 75.9663V52.4414C44.3105 52.4631 44.1957 52.4779 44.0802 52.4856H38.8993ZM26.4683 74.5851H20.9435C20.5771 74.5851 20.2258 74.4396 19.9668 74.1806C19.7078 73.9215 19.5622 73.5702 19.5622 73.2039C19.5622 72.8376 19.7078 72.4862 19.9668 72.2272C20.2258 71.9682 20.5771 71.8227 20.9435 71.8227H26.4683C26.8347 71.8227 27.186 71.9682 27.445 72.2272C27.704 72.4862 27.8496 72.8376 27.8496 73.2039C27.8496 73.5702 27.704 73.9215 27.445 74.1806C27.186 74.4396 26.8347 74.5851 26.4683 74.5851Z" fill="#E9E9E9"/>
<path d="M41.8629 2.14062C48.0674 7.94174 52.5522 18.4238 53.6364 30.87L42.3726 45.2015L41.9665 44.388C41.9383 44.3311 41.8947 44.2833 41.8408 44.2499C41.7869 44.2165 41.7247 44.1988 41.6613 44.1987H37.49L38.6419 49.7236H44.0812C44.1396 49.7251 44.1973 49.7109 44.2483 49.6825C44.2993 49.6541 44.3418 49.6124 44.3712 49.562C44.4032 49.5126 44.4214 49.4557 44.4241 49.3969C44.4268 49.3382 44.4138 49.2798 44.3864 49.2277L43.74 47.9349L57.2759 30.7084C58.2509 30.4566 59.2102 30.1476 60.1489 29.7829C60.4117 29.6777 60.6349 29.4929 60.7872 29.2543C60.9396 29.0158 61.0134 28.7355 60.9983 28.4528C60.6542 22.6976 58.6694 17.1613 55.2784 12.4985C51.8873 7.83568 47.2321 4.24139 41.8629 2.14062Z" fill="#E9E9E9"/>
<path d="M50.96 31.9552C49.8385 16.5739 43.4283 4.30181 35.1907 0.931641C38.6092 7.15955 40.4186 20.3157 40.7073 32.9013C44.8454 32.6859 48.2294 32.3488 50.96 31.9552Z" fill="#E9E9E9"/>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.16663 14.0003H9.83329V12.3337H8.16663V14.0003ZM8.99996 0.666992C4.39996 0.666992 0.666626 4.40033 0.666626 9.00033C0.666626 13.6003 4.39996 17.3337 8.99996 17.3337C13.6 17.3337 17.3333 13.6003 17.3333 9.00033C17.3333 4.40033 13.6 0.666992 8.99996 0.666992ZM8.99996 15.667C5.32496 15.667 2.33329 12.6753 2.33329 9.00033C2.33329 5.32533 5.32496 2.33366 8.99996 2.33366C12.675 2.33366 15.6666 5.32533 15.6666 9.00033C15.6666 12.6753 12.675 15.667 8.99996 15.667ZM8.99996 4.00033C7.15829 4.00033 5.66663 5.49199 5.66663 7.33366H7.33329C7.33329 6.41699 8.08329 5.66699 8.99996 5.66699C9.91663 5.66699 10.6666 6.41699 10.6666 7.33366C10.6666 9.00033 8.16663 8.79199 8.16663 11.5003H9.83329C9.83329 9.62533 12.3333 9.41699 12.3333 7.33366C12.3333 5.49199 10.8416 4.00033 8.99996 4.00033Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 912 B

View File

@ -0,0 +1,38 @@
<svg width="286" height="286" viewBox="0 0 286 286" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_di_4487_3093)">
<path d="M250.999 132.999C250.999 67.8301 198.169 15 132.999 15C67.8301 15 15 67.8301 15 132.999C15 198.169 67.8301 250.999 132.999 250.999C198.169 250.999 250.999 198.169 250.999 132.999Z" fill="#EBECED"/>
</g>
<g filter="url(#filter1_i_4487_3093)">
<path d="M196.919 196.919C232.066 161.772 232.066 104.787 196.919 69.6396C161.772 34.4924 104.787 34.4924 69.6396 69.6396C34.4924 104.787 34.4924 161.772 69.6396 196.919C104.787 232.066 161.772 232.066 196.919 196.919Z" fill="#55E675"/>
</g>
<path d="M199.04 199.04C235.359 162.721 235.359 103.837 199.04 67.5183C162.721 31.1995 103.837 31.1995 67.5183 67.5183C31.1995 103.837 31.1995 162.721 67.5183 199.04C103.837 235.359 162.721 235.359 199.04 199.04Z" stroke="#F1F2F2" stroke-width="6"/>
<path d="M93.8516 139.562L93.8906 139.582C96.9115 141.665 100.154 142.707 103.617 142.707C107.029 142.707 108.734 141.678 108.734 139.621C108.734 138.853 108.298 138.215 107.426 137.707C106.527 137.186 105.434 136.822 104.145 136.613C102.829 136.392 101.404 136.079 99.8672 135.676C98.3698 135.272 96.944 134.79 95.5898 134.23C94.2747 133.684 93.181 132.805 92.3086 131.594C91.4362 130.396 91 128.911 91 127.141C91 124.354 92.1068 122.167 94.3203 120.578C96.5208 119.003 99.2357 118.215 102.465 118.215C106.931 118.215 110.759 119.562 113.949 122.258L110.746 126.73C108.337 124.973 105.486 124.094 102.191 124.094C98.9622 124.094 97.3477 125.083 97.3477 127.062C97.3477 127.792 97.7904 128.404 98.6758 128.898C99.5482 129.393 100.642 129.745 101.957 129.953C103.272 130.161 104.698 130.474 106.234 130.891C107.771 131.307 109.197 131.796 110.512 132.355C111.827 132.928 112.921 133.833 113.793 135.07C114.678 136.333 115.121 137.85 115.121 139.621C115.121 142.473 114.086 144.68 112.016 146.242C109.945 147.805 107.146 148.586 103.617 148.586C101.091 148.586 98.6823 148.176 96.3906 147.355C94.125 146.535 92.1523 145.428 90.4727 144.035L93.8516 139.562ZM133.461 148.527H133.441C128.793 148.527 125.036 147.102 122.172 144.25C119.307 141.398 117.875 137.772 117.875 133.371C117.875 128.983 119.307 125.363 122.172 122.512C125.036 119.66 128.793 118.234 133.441 118.234C138.09 118.234 141.853 119.66 144.73 122.512C147.608 125.363 149.047 128.983 149.047 133.371C149.047 137.772 147.608 141.398 144.73 144.25C141.853 147.102 138.096 148.527 133.461 148.527ZM133.441 124.035V124.074C130.824 124.074 128.637 124.96 126.879 126.73C125.121 128.514 124.242 130.734 124.242 133.391C124.242 136.047 125.121 138.273 126.879 140.07C128.637 141.867 130.824 142.766 133.441 142.766C136.072 142.766 138.259 141.874 140.004 140.09C141.749 138.306 142.621 136.066 142.621 133.371C142.621 130.702 141.749 128.475 140.004 126.691C138.272 124.921 136.085 124.035 133.441 124.035ZM155.336 139.562L155.375 139.582C158.396 141.665 161.638 142.707 165.102 142.707C168.513 142.707 170.219 141.678 170.219 139.621C170.219 138.853 169.783 138.215 168.91 137.707C168.012 137.186 166.918 136.822 165.629 136.613C164.314 136.392 162.888 136.079 161.352 135.676C159.854 135.272 158.428 134.79 157.074 134.23C155.759 133.684 154.665 132.805 153.793 131.594C152.921 130.396 152.484 128.911 152.484 127.141C152.484 124.354 153.591 122.167 155.805 120.578C158.005 119.003 160.72 118.215 163.949 118.215C168.415 118.215 172.243 119.562 175.434 122.258L172.23 126.73C169.822 124.973 166.97 124.094 163.676 124.094C160.447 124.094 158.832 125.083 158.832 127.062C158.832 127.792 159.275 128.404 160.16 128.898C161.033 129.393 162.126 129.745 163.441 129.953C164.757 130.161 166.182 130.474 167.719 130.891C169.255 131.307 170.681 131.796 171.996 132.355C173.311 132.928 174.405 133.833 175.277 135.07C176.163 136.333 176.605 137.85 176.605 139.621C176.605 142.473 175.57 144.68 173.5 146.242C171.43 147.805 168.63 148.586 165.102 148.586C162.576 148.586 160.167 148.176 157.875 147.355C155.609 146.535 153.637 145.428 151.957 144.035L155.336 139.562Z" fill="white"/>
<defs>
<filter id="filter0_di_4487_3093" x="0" y="1.52588e-05" width="285.999" height="285.999" 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 dx="10" dy="10"/>
<feGaussianBlur stdDeviation="12.5"/>
<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.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4487_3093"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4487_3093" result="shape"/>
<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 dx="5" dy="5"/>
<feGaussianBlur stdDeviation="15"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
<feBlend mode="normal" in2="shape" result="effect2_innerShadow_4487_3093"/>
</filter>
<filter id="filter1_i_4487_3093" x="37.2792" y="25.2792" width="193" height="204" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<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 dx="1" dy="-12"/>
<feGaussianBlur stdDeviation="15"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.501961 0 0 0 0 0.0980392 0 0 0 0 0.0980392 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_4487_3093"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

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

@ -0,0 +1,10 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_4487_2199)">
<path d="M11 7H13V9H11V7ZM11 11H13V17H11V11ZM12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 20C7.59 20 4 16.41 4 12C4 7.59 7.59 4 12 4C16.41 4 20 7.59 20 12C20 16.41 16.41 20 12 20Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_4487_2199">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 495 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="19" viewBox="0 0 16 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.34167 16.5083C6.34167 17.425 7.08333 18.1667 8 18.1667C8.91667 18.1667 9.65833 17.425 9.65833 16.5083H6.34167ZM8 4C10.3 4 12.1667 5.86667 12.1667 8.16667V14H3.83333V8.16667C3.83333 5.86667 5.7 4 8 4ZM8 0.25C7.30833 0.25 6.75 0.808333 6.75 1.5V2.475C4.13333 3.04167 2.16667 5.375 2.16667 8.16667V13.1667L0.5 14.8333V15.6667H15.5V14.8333L13.8333 13.1667V8.16667C13.8333 5.375 11.8667 3.04167 9.25 2.475V1.5C9.25 0.808333 8.69167 0.25 8 0.25ZM7.16667 5.66667H8.83333V9H7.16667V5.66667ZM7.16667 10.6667H8.83333V12.3333H7.16667V10.6667Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 663 B

38
assets/icons/red_sos.svg Normal file
View File

@ -0,0 +1,38 @@
<svg width="286" height="286" viewBox="0 0 286 286" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_di_4487_3092)">
<path d="M250.999 132.999C250.999 67.8301 198.169 15 132.999 15C67.8301 15 15 67.8301 15 132.999C15 198.169 67.8301 250.999 132.999 250.999C198.169 250.999 250.999 198.169 250.999 132.999Z" fill="#EBECED"/>
</g>
<g filter="url(#filter1_i_4487_3092)">
<path d="M196.919 196.919C232.066 161.772 232.066 104.787 196.919 69.6396C161.772 34.4924 104.787 34.4924 69.6396 69.6396C34.4924 104.787 34.4924 161.772 69.6396 196.919C104.787 232.066 161.772 232.066 196.919 196.919Z" fill="#FF3232"/>
</g>
<path d="M199.04 199.04C235.359 162.721 235.359 103.837 199.04 67.5183C162.721 31.1995 103.837 31.1995 67.5183 67.5183C31.1995 103.837 31.1995 162.721 67.5183 199.04C103.837 235.359 162.721 235.359 199.04 199.04Z" stroke="#F1F2F2" stroke-width="6"/>
<path d="M93.8516 139.562L93.8906 139.582C96.9115 141.665 100.154 142.707 103.617 142.707C107.029 142.707 108.734 141.678 108.734 139.621C108.734 138.853 108.298 138.215 107.426 137.707C106.527 137.186 105.434 136.822 104.145 136.613C102.829 136.392 101.404 136.079 99.8672 135.676C98.3698 135.272 96.944 134.79 95.5898 134.23C94.2747 133.684 93.181 132.805 92.3086 131.594C91.4362 130.396 91 128.911 91 127.141C91 124.354 92.1068 122.167 94.3203 120.578C96.5208 119.003 99.2357 118.215 102.465 118.215C106.931 118.215 110.759 119.562 113.949 122.258L110.746 126.73C108.337 124.973 105.486 124.094 102.191 124.094C98.9622 124.094 97.3477 125.083 97.3477 127.062C97.3477 127.792 97.7904 128.404 98.6758 128.898C99.5482 129.393 100.642 129.745 101.957 129.953C103.272 130.161 104.698 130.474 106.234 130.891C107.771 131.307 109.197 131.796 110.512 132.355C111.827 132.928 112.921 133.833 113.793 135.07C114.678 136.333 115.121 137.85 115.121 139.621C115.121 142.473 114.086 144.68 112.016 146.242C109.945 147.805 107.146 148.586 103.617 148.586C101.091 148.586 98.6823 148.176 96.3906 147.355C94.125 146.535 92.1523 145.428 90.4727 144.035L93.8516 139.562ZM133.461 148.527H133.441C128.793 148.527 125.036 147.102 122.172 144.25C119.307 141.398 117.875 137.772 117.875 133.371C117.875 128.983 119.307 125.363 122.172 122.512C125.036 119.66 128.793 118.234 133.441 118.234C138.09 118.234 141.853 119.66 144.73 122.512C147.608 125.363 149.047 128.983 149.047 133.371C149.047 137.772 147.608 141.398 144.73 144.25C141.853 147.102 138.096 148.527 133.461 148.527ZM133.441 124.035V124.074C130.824 124.074 128.637 124.96 126.879 126.73C125.121 128.514 124.242 130.734 124.242 133.391C124.242 136.047 125.121 138.273 126.879 140.07C128.637 141.867 130.824 142.766 133.441 142.766C136.072 142.766 138.259 141.874 140.004 140.09C141.749 138.306 142.621 136.066 142.621 133.371C142.621 130.702 141.749 128.475 140.004 126.691C138.272 124.921 136.085 124.035 133.441 124.035ZM155.336 139.562L155.375 139.582C158.396 141.665 161.638 142.707 165.102 142.707C168.513 142.707 170.219 141.678 170.219 139.621C170.219 138.853 169.783 138.215 168.91 137.707C168.012 137.186 166.918 136.822 165.629 136.613C164.314 136.392 162.888 136.079 161.352 135.676C159.854 135.272 158.428 134.79 157.074 134.23C155.759 133.684 154.665 132.805 153.793 131.594C152.921 130.396 152.484 128.911 152.484 127.141C152.484 124.354 153.591 122.167 155.805 120.578C158.005 119.003 160.72 118.215 163.949 118.215C168.415 118.215 172.243 119.562 175.434 122.258L172.23 126.73C169.822 124.973 166.97 124.094 163.676 124.094C160.447 124.094 158.832 125.083 158.832 127.062C158.832 127.792 159.275 128.404 160.16 128.898C161.033 129.393 162.126 129.745 163.441 129.953C164.757 130.161 166.182 130.474 167.719 130.891C169.255 131.307 170.681 131.796 171.996 132.355C173.311 132.928 174.405 133.833 175.277 135.07C176.163 136.333 176.605 137.85 176.605 139.621C176.605 142.473 175.57 144.68 173.5 146.242C171.43 147.805 168.63 148.586 165.102 148.586C162.576 148.586 160.167 148.176 157.875 147.355C155.609 146.535 153.637 145.428 151.957 144.035L155.336 139.562Z" fill="white"/>
<defs>
<filter id="filter0_di_4487_3092" x="0" y="1.52588e-05" width="285.999" height="285.999" 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 dx="10" dy="10"/>
<feGaussianBlur stdDeviation="12.5"/>
<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.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4487_3092"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4487_3092" result="shape"/>
<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 dx="5" dy="5"/>
<feGaussianBlur stdDeviation="15"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
<feBlend mode="normal" in2="shape" result="effect2_innerShadow_4487_3092"/>
</filter>
<filter id="filter1_i_4487_3092" x="37.2792" y="25.2792" width="193" height="204" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<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 dx="1" dy="-12"/>
<feGaussianBlur stdDeviation="15"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.501961 0 0 0 0 0.0980392 0 0 0 0 0.0980392 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_4487_3092"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -0,0 +1,3 @@
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.3333 7.16667V0.5H11.5V3H6.49996V0.5H0.666626V7.16667H6.49996V4.66667H8.16663V13H11.5V15.5H17.3333V8.83333H11.5V11.3333H9.83329V4.66667H11.5V7.16667H17.3333ZM4.83329 5.5H2.33329V2.16667H4.83329V5.5ZM13.1666 10.5H15.6666V13.8333H13.1666V10.5ZM13.1666 2.16667H15.6666V5.5H13.1666V2.16667Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 418 B

View File

@ -0,0 +1,23 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.9985 39.2627C14.8541 39.2627 10.0174 37.2559 6.37968 33.6118C2.74195 29.9678 0.738586 25.1228 0.738586 19.9694C0.738586 14.8159 2.74195 9.97091 6.37976 6.32685C10.0174 2.68278 14.8541 0.675903 19.9985 0.675903C25.143 0.675903 29.9796 2.68278 33.6174 6.32685C37.2552 9.97083 39.2585 14.8159 39.2585 19.9694C39.2585 25.1228 37.2552 29.9678 33.6174 33.6119C29.9797 37.2559 25.1431 39.2627 19.9985 39.2627Z" fill="#CBC4CC"/>
<path d="M19.9983 35.7306C28.688 35.7306 35.7323 28.674 35.7323 19.9692C35.7323 11.2644 28.688 4.20776 19.9983 4.20776C11.3087 4.20776 4.26434 11.2644 4.26434 19.9692C4.26434 28.674 11.3087 35.7306 19.9983 35.7306Z" fill="#F3F0F3"/>
<path d="M19.9986 33.2973C27.3468 33.2973 33.3037 27.3301 33.3037 19.9691C33.3037 12.6081 27.3468 6.64087 19.9986 6.64087C12.6504 6.64087 6.69354 12.6081 6.69354 19.9691C6.69354 27.3301 12.6504 33.2973 19.9986 33.2973Z" fill="#FD4755"/>
<path d="M19.9992 6.64087C19.4706 6.64087 18.9494 6.6729 18.4367 6.73321C25.0395 7.51056 30.1793 13.1494 30.1793 19.969C30.1793 26.7886 25.0395 32.4275 18.4367 33.2049C18.9494 33.2653 19.4706 33.2972 19.9992 33.2972C27.3357 33.2972 33.3043 27.3182 33.3043 19.969C33.3043 12.6198 27.3357 6.64087 19.9992 6.64087Z" fill="#FB2B3A"/>
<path d="M13.2348 12.9076C13.0732 12.9076 12.9123 12.8412 12.7966 12.7109C12.5816 12.469 12.6034 12.0987 12.8453 11.8837C14.8214 10.1277 17.3621 9.16064 19.9996 9.16064C20.3233 9.16064 20.5856 9.42299 20.5856 9.74658C20.5856 10.0702 20.3233 10.3325 19.9996 10.3325C17.6494 10.3325 15.3851 11.1946 13.6238 12.7597C13.5122 12.8588 13.3732 12.9076 13.2348 12.9076Z" fill="#FD8087"/>
<path d="M19.9998 30.777C19.6761 30.777 19.4138 30.5146 19.4138 30.191C19.4138 29.8674 19.6761 29.6051 19.9998 29.6051C22.2935 29.6051 24.5163 28.7794 26.2587 27.2801C26.5041 27.0691 26.8739 27.0967 27.085 27.3421C27.2961 27.5874 27.2684 27.9573 27.023 28.1684C25.0681 29.8506 22.5739 30.777 19.9998 30.777Z" fill="#FD8087"/>
<path d="M14.101 19.467C13.9653 19.4168 13.8165 19.3693 13.659 19.319C13.1803 19.166 12.4569 18.9348 12.2799 18.6045C12.1936 18.4435 12.1857 18.2752 12.2565 18.1045C12.3492 17.8809 12.5605 17.6956 12.808 17.6209C13.7419 17.3392 14.5903 18.0186 14.6085 18.0333C14.856 18.2396 15.224 18.2073 15.4318 17.9605C15.6403 17.713 15.6085 17.3433 15.361 17.1349C15.3073 17.0896 14.0247 16.0298 12.4694 16.499C11.8853 16.6752 11.401 17.1077 11.1739 17.6558C10.9681 18.1525 10.994 18.686 11.247 19.1581C11.6483 19.9067 12.6043 20.2122 13.3024 20.4352C13.4471 20.4815 13.5838 20.5251 13.6949 20.5662C14.3329 20.802 14.6576 21.1673 14.5858 21.5686C14.5138 21.9709 14.0422 22.3871 13.3774 22.3871C12.7361 22.3871 12.1174 22.1263 11.7221 21.6894C11.5051 21.4494 11.1345 21.431 10.8945 21.6479C10.6545 21.8651 10.636 22.2355 10.8531 22.4755C11.4667 23.154 12.4105 23.559 13.3774 23.559C14.542 23.559 15.5574 22.792 15.7393 21.775C15.8774 21.0029 15.5196 19.9911 14.101 19.467Z" fill="white"/>
<path d="M27.6301 19.467C27.4944 19.4169 27.3456 19.3694 27.1881 19.319C26.7093 19.166 25.9859 18.9348 25.8088 18.6045C25.7226 18.4435 25.7147 18.2753 25.7855 18.1045C25.8781 17.8809 26.0895 17.6956 26.337 17.6209C27.2692 17.3395 28.1166 18.0164 28.1374 18.0332C28.3849 18.2396 28.7529 18.2074 28.9607 17.9605C29.1692 17.713 29.1375 17.3434 28.89 17.1349C28.8363 17.0896 27.5537 16.0298 25.9984 16.499C25.4144 16.6752 24.9301 17.1077 24.7029 17.6559C24.497 18.1525 24.523 18.686 24.776 19.1581C25.1773 19.9067 26.1334 20.2122 26.8315 20.4353C26.9762 20.4816 27.1129 20.5252 27.224 20.5663C27.862 20.8021 28.1867 21.1674 28.1149 21.5687C28.0429 21.971 27.5712 22.3872 26.9063 22.3872C26.2652 22.3872 25.6464 22.1264 25.2512 21.6895C25.0341 21.4495 24.6636 21.4311 24.4236 21.648C24.1836 21.8652 24.165 22.2356 24.3822 22.4756C24.9958 23.1541 25.9395 23.5591 26.9063 23.5591C28.071 23.5591 29.0865 22.7921 29.2684 21.7751C29.4064 21.0029 29.0486 19.9912 27.6301 19.467Z" fill="white"/>
<path d="M20 16.3796C18.0236 16.3796 16.4158 17.99 16.4158 19.9693C16.4158 21.9487 18.0236 23.559 20 23.559C21.9763 23.559 23.5841 21.9487 23.5841 19.9693C23.5841 17.99 21.9763 16.3796 20 16.3796ZM20 22.3871C18.6699 22.3871 17.5877 21.3025 17.5877 19.9693C17.5877 18.6361 18.6699 17.5515 20 17.5515C21.3301 17.5515 22.4122 18.6361 22.4122 19.9693C22.4122 21.3025 21.3301 22.3871 20 22.3871Z" fill="white"/>
<path d="M3.84889 35.3784L1.80935 37.4216C1.58076 37.6507 1.58107 38.0216 1.81013 38.2502C1.92459 38.3644 2.07435 38.4215 2.22412 38.4215C2.37428 38.4215 2.52443 38.3641 2.63881 38.2495L4.67834 36.2062C4.90693 35.9772 4.90662 35.6062 4.67756 35.3777C4.44834 35.1491 4.07732 35.1494 3.84889 35.3784Z" fill="#F3F0F3"/>
<path d="M2.24993 32.4788C2.06414 32.2139 1.6986 32.1499 1.43383 32.3356L0.249534 33.1664C-0.0154664 33.3523 -0.079529 33.7177 0.106331 33.9826C0.220315 34.1452 0.401956 34.2321 0.586487 34.2321C0.702659 34.2321 0.820081 34.1976 0.922425 34.1258L2.10672 33.295C2.37172 33.1092 2.43579 32.7438 2.24993 32.4788Z" fill="#F3F0F3"/>
<path d="M7.57032 37.8098C7.30509 37.6245 6.93993 37.6892 6.75439 37.9544L5.96876 39.0784C5.78337 39.3436 5.84814 39.7089 6.11337 39.8943C6.21564 39.9657 6.33267 40 6.44853 40C6.63337 40 6.81532 39.9127 6.92931 39.7497L7.71493 38.6257C7.90032 38.3605 7.83556 37.9952 7.57032 37.8098Z" fill="#F3F0F3"/>
<path d="M36.1472 35.3782C35.9186 35.1492 35.5475 35.1488 35.3186 35.3774C35.0895 35.606 35.0892 35.977 35.3178 36.206L37.3573 38.2492C37.4718 38.3639 37.6218 38.4213 37.772 38.4213C37.9218 38.4213 38.0716 38.3642 38.186 38.25C38.415 38.0214 38.4154 37.6504 38.1868 37.4214L36.1472 35.3782Z" fill="#F3F0F3"/>
<path d="M39.7459 33.1664L38.5616 32.3356C38.2966 32.1499 37.9313 32.2139 37.7456 32.4788C37.5597 32.7438 37.6238 33.1092 37.8888 33.295L39.0731 34.1258C39.1755 34.1976 39.2927 34.2321 39.409 34.2321C39.5935 34.2321 39.7752 34.1451 39.8891 33.9826C40.0749 33.7177 40.0109 33.3523 39.7459 33.1664Z" fill="#F3F0F3"/>
<path d="M33.2416 37.9542C33.0562 37.689 32.691 37.6242 32.4256 37.8096C32.1604 37.9949 32.0956 38.3603 32.281 38.6255L33.0666 39.7495C33.1806 39.9125 33.3625 39.9998 33.5474 39.9998C33.6633 39.9998 33.7803 39.9655 33.8826 39.8941C34.1478 39.7087 34.2126 39.3434 34.0272 39.0782L33.2416 37.9542Z" fill="#F3F0F3"/>
<path d="M35.7325 4.79383C35.8826 4.79383 36.0328 4.73648 36.1472 4.62179L38.1867 2.57859C38.4153 2.34953 38.415 1.97859 38.1859 1.75C37.9567 1.52132 37.5857 1.52171 37.3573 1.75078L35.3178 3.79398C35.0892 4.02304 35.0895 4.39398 35.3186 4.62258C35.4329 4.73679 35.5827 4.79383 35.7325 4.79383Z" fill="#F3F0F3"/>
<path d="M37.7456 7.52093C37.8595 7.68351 38.0412 7.77038 38.2257 7.77038C38.3419 7.77038 38.4593 7.73593 38.5616 7.66413L39.7459 6.83335C40.0109 6.64749 40.075 6.2821 39.8891 6.01718C39.7034 5.75226 39.3378 5.68819 39.0731 5.87398L37.8888 6.70476C37.6238 6.89062 37.5597 7.25601 37.7456 7.52093Z" fill="#F3F0F3"/>
<path d="M33.8826 0.105655C33.6173 -0.0795792 33.2521 -0.0149698 33.0666 0.250265L32.281 1.37417C32.0956 1.63941 32.1604 2.00472 32.4256 2.19011C32.5279 2.26152 32.6449 2.29581 32.7608 2.29581C32.9456 2.29581 33.1276 2.20855 33.2416 2.0455L34.0272 0.921515C34.2125 0.656359 34.1477 0.291046 33.8826 0.105655Z" fill="#F3F0F3"/>
<path d="M2.63873 1.75078C2.41006 1.52171 2.03904 1.52132 1.81013 1.75C1.58107 1.97859 1.58076 2.34961 1.80935 2.57859L3.84889 4.62179C3.96334 4.73648 4.11342 4.79383 4.26357 4.79383C4.41334 4.79383 4.56318 4.73679 4.67756 4.62258C4.90662 4.39398 4.90693 4.02297 4.67834 3.79398L2.63873 1.75078Z" fill="#F3F0F3"/>
<path d="M0.249534 6.83335L1.43383 7.66413C1.53625 7.73593 1.65352 7.77038 1.76977 7.77038C1.9543 7.77038 2.13602 7.68343 2.24993 7.52093C2.43579 7.25601 2.37172 6.89062 2.10672 6.70476L0.922425 5.87398C0.657503 5.68819 0.292112 5.75226 0.106331 6.01718C-0.079529 6.2821 -0.0154664 6.64749 0.249534 6.83335Z" fill="#F3F0F3"/>
<path d="M6.92931 0.250204C6.74392 -0.0148744 6.37876 -0.0796401 6.11337 0.105673C5.84814 0.291063 5.78337 0.656376 5.96876 0.921611L6.75439 2.0456C6.86837 2.20856 7.05025 2.29591 7.23517 2.29591C7.35103 2.29591 7.46806 2.26161 7.57032 2.19021C7.83556 2.00481 7.90032 1.6395 7.71493 1.37427L6.92931 0.250204Z" fill="#F3F0F3"/>
</svg>

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -0,0 +1,6 @@
<svg width="124" height="124" viewBox="0 0 124 124" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M62 122C95.1371 122 122 95.1371 122 62C122 28.8629 95.1371 2 62 2C28.8629 2 2 28.8629 2 62C2 95.1371 28.8629 122 62 122Z" fill="#F6F6F6" stroke="white" stroke-width="3"/>
<circle cx="62" cy="62" r="51" fill="white"/>
<circle cx="62.5" cy="62.5" r="43.5" fill="#FF1D1D"/>
<path d="M50.6152 69.3027L50.5859 69.3223C48.6589 69.3223 47.0736 68.847 45.8301 67.8965L46.6309 66.4805C47.1191 66.8255 47.7148 67.1055 48.418 67.3203C49.1341 67.5352 49.8275 67.6426 50.498 67.6426C52.0866 67.6426 52.8809 67.1413 52.8809 66.1387C52.8809 65.6243 52.6367 65.224 52.1484 64.9375C51.6667 64.6576 51.0807 64.4492 50.3906 64.3125C49.6615 64.1693 48.9779 64.0098 48.3398 63.834C47.6562 63.6452 47.0703 63.3034 46.582 62.8086C46.0938 62.3138 45.8496 61.6497 45.8496 60.8164C45.8496 59.7096 46.2728 58.8796 47.1191 58.3262C47.972 57.7663 48.9779 57.4863 50.1367 57.4863C51.7383 57.4863 53.0729 57.8672 54.1406 58.6289L53.418 60.0938C52.4284 59.4818 51.3249 59.1693 50.1074 59.1562C49.5475 59.1562 49.0332 59.2734 48.5645 59.5078C48.0957 59.7422 47.8613 60.1328 47.8613 60.6797C47.8613 61.0898 48.0339 61.4219 48.3789 61.6758C48.7174 61.9297 49.1471 62.1055 49.668 62.2031C50.1953 62.3008 50.7585 62.4277 51.3574 62.584C51.9954 62.7467 52.5586 62.9258 53.0469 63.1211C53.5742 63.3294 54.0104 63.6745 54.3555 64.1562C54.707 64.6445 54.8828 65.2533 54.8828 65.9824C54.8828 67.0436 54.4922 67.8639 53.7109 68.4434C52.9362 69.0163 51.9043 69.3027 50.6152 69.3027ZM62.6758 69.2246V69.2344C60.9505 69.2344 59.5345 68.6615 58.4277 67.5156C57.3275 66.3763 56.7773 64.9701 56.7773 63.2969C56.7773 61.6432 57.3275 60.2565 58.4277 59.1367C59.5345 58.0104 60.9505 57.4473 62.6758 57.4473C64.3945 57.4473 65.8105 58.0104 66.9238 59.1367C68.0371 60.2565 68.5938 61.6432 68.5938 63.2969C68.5938 64.9635 68.0371 66.3698 66.9238 67.5156C65.8105 68.6549 64.3945 69.2246 62.6758 69.2246ZM62.6758 59.293V59.3027C61.5169 59.3027 60.5859 59.6836 59.8828 60.4453C59.1797 61.207 58.8281 62.1673 58.8281 63.3262C58.8281 64.5046 59.1797 65.4779 59.8828 66.2461C60.5859 67.0208 61.5169 67.4082 62.6758 67.4082C63.8346 67.4082 64.7656 67.0208 65.4688 66.2461C66.1719 65.4779 66.5234 64.5013 66.5234 63.3164C66.5234 62.1576 66.1719 61.1973 65.4688 60.4355C64.7656 59.6738 63.8346 59.293 62.6758 59.293ZM75.1074 69.3027L75.0781 69.3223C73.151 69.3223 71.5658 68.847 70.3223 67.8965L71.123 66.4805C71.6113 66.8255 72.207 67.1055 72.9102 67.3203C73.6263 67.5352 74.3197 67.6426 74.9902 67.6426C76.5788 67.6426 77.373 67.1413 77.373 66.1387C77.373 65.6243 77.1289 65.224 76.6406 64.9375C76.1589 64.6576 75.5729 64.4492 74.8828 64.3125C74.1536 64.1693 73.4701 64.0098 72.832 63.834C72.1484 63.6452 71.5625 63.3034 71.0742 62.8086C70.5859 62.3138 70.3418 61.6497 70.3418 60.8164C70.3418 59.7096 70.765 58.8796 71.6113 58.3262C72.4642 57.7663 73.4701 57.4863 74.6289 57.4863C76.2305 57.4863 77.5651 57.8672 78.6328 58.6289L77.9102 60.0938C76.9206 59.4818 75.8171 59.1693 74.5996 59.1562C74.0397 59.1562 73.5254 59.2734 73.0566 59.5078C72.5879 59.7422 72.3535 60.1328 72.3535 60.6797C72.3535 61.0898 72.526 61.4219 72.8711 61.6758C73.2096 61.9297 73.6393 62.1055 74.1602 62.2031C74.6875 62.3008 75.2507 62.4277 75.8496 62.584C76.4876 62.7467 77.0508 62.9258 77.5391 63.1211C78.0664 63.3294 78.5026 63.6745 78.8477 64.1562C79.1992 64.6445 79.375 65.2533 79.375 65.9824C79.375 67.0436 78.9844 67.8639 78.2031 68.4434C77.4284 69.0163 76.3965 69.3027 75.1074 69.3027Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,10 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_4487_1385)">
<path d="M15 3H6C5.17 3 4.46 3.5 4.16 4.22L1.14 11.27C1.05 11.5 1 11.74 1 12V14C1 15.1 1.9 16 3 16H9.31L8.36 20.57L8.33 20.89C8.33 21.3 8.5 21.68 8.77 21.95L9.83 23L16.42 16.41C16.78 16.05 17 15.55 17 15V5C17 3.9 16.1 3 15 3ZM15 15L10.66 19.34L12 14H3V12L6 5H15V15ZM19 3H23V15H19V3Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_4487_1385">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 548 B

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

@ -0,0 +1,10 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_4487_1378)">
<path d="M9 21H18C18.83 21 19.54 20.5 19.84 19.78L22.86 12.73C22.95 12.5 23 12.26 23 12V10C23 8.9 22.1 8 21 8H14.69L15.64 3.43L15.67 3.11C15.67 2.7 15.5 2.32 15.23 2.05L14.17 1L7.58 7.59C7.22 7.95 7 8.45 7 9V19C7 20.1 7.9 21 9 21ZM9 9L13.34 4.66L12 10H21V12L18 19H9V9ZM1 9H5V21H1V9Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_4487_1378">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 548 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="22" viewBox="0 0 16 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.99996 3.66699V0.916992L4.33329 4.58366L7.99996 8.25033V5.50033C11.0341 5.50033 13.5 7.96616 13.5 11.0003C13.5 11.9262 13.2708 12.8062 12.8583 13.567L14.1966 14.9053C14.9116 13.7778 15.3333 12.4395 15.3333 11.0003C15.3333 6.94866 12.0516 3.66699 7.99996 3.66699ZM7.99996 16.5003C4.96579 16.5003 2.49996 14.0345 2.49996 11.0003C2.49996 10.0745 2.72913 9.19449 3.14163 8.43366L1.80329 7.09532C1.08829 8.22283 0.666626 9.56116 0.666626 11.0003C0.666626 15.052 3.94829 18.3337 7.99996 18.3337V21.0837L11.6666 17.417L7.99996 13.7503V16.5003Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 667 B

View File

@ -11,7 +11,7 @@ import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdo
import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
import 'package:syncrow_app/features/menu/view/menu_view.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
@ -88,7 +88,7 @@ class HomeCubit extends Cubit<HomeState> {
SpaceModel? selectedSpace;
RoomModel? selectedRoom;
SubSpaceModel? selectedRoom;
PageController devicesPageController = PageController();
@ -173,7 +173,7 @@ class HomeCubit extends Cubit<HomeState> {
if (index == 0) {
unselectRoom();
} else {
selectedRoom = selectedSpace!.rooms![index - 1];
selectedRoom = selectedSpace!.subspaces[index - 1];
emitSafe(RoomSelected(selectedRoom!));
}
}
@ -188,7 +188,7 @@ class HomeCubit extends Cubit<HomeState> {
if (index <= 0) {
unselectRoom();
} else {
selectedRoom = selectedSpace!.rooms![index - 1];
selectedRoom = selectedSpace!.subspaces[index - 1];
emitSafe(RoomSelected(selectedRoom!));
}
}
@ -211,9 +211,9 @@ class HomeCubit extends Cubit<HomeState> {
}
//////////////////////////////////////// API ////////////////////////////////////////
generateInvitation(String unitId) async {
generateInvitation(SpaceModel unit) async {
try {
final invitationCode = await SpacesAPI.generateInvitationCode(unitId);
final invitationCode = await SpacesAPI.generateInvitationCode(unit.id, unit.community.uuid);
if (invitationCode.isNotEmpty) {
Share.share('The invitation code is $invitationCode');
CustomSnackBar.displaySnackBar(
@ -229,10 +229,10 @@ class HomeCubit extends Cubit<HomeState> {
Future<bool> joinAUnit(String code) async {
try {
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? '';
Map<String, String> body = {'userUuid': uuid, 'inviteCode': code};
var userUuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? '';
Map<String, String> body = {'inviteCode': code};
final success = await SpacesAPI.joinUnit(body);
final success = await SpacesAPI.joinUnit(userUuid, body);
if (success) {
await fetchUnitsByUserId();
CustomSnackBar.displaySnackBar('Done successfully');
@ -247,7 +247,7 @@ class HomeCubit extends Cubit<HomeState> {
fetchUnitsByUserId() async {
emitSafe(GetSpacesLoading());
try {
spaces = await SpacesAPI.getUnitsByUserId();
spaces = await SpacesAPI.getSpacesByUserId();
} catch (failure) {
emitSafe(GetSpacesError("No units found"));
return;
@ -265,13 +265,13 @@ class HomeCubit extends Cubit<HomeState> {
fetchRoomsByUnitId(SpaceModel space) async {
emitSafe(GetSpaceRoomsLoading());
try {
space.rooms = await SpacesAPI.getRoomsBySpaceId(space.id!);
space.subspaces = await SpacesAPI.getSubSpaceBySpaceId(space.community.uuid, space.id);
} catch (failure) {
emitSafe(GetSpaceRoomsError(failure.toString()));
return;
}
if (space.rooms != null && space.rooms!.isNotEmpty) {
emitSafe(GetSpaceRoomsSuccess(space.rooms!));
if (space.subspaces.isNotEmpty) {
emitSafe(GetSpaceRoomsSuccess(space.subspaces));
} else {
emitSafe(GetSpaceRoomsError("No rooms found"));
}
@ -370,6 +370,9 @@ class HomeCubit extends Cubit<HomeState> {
.add(const SmartSceneClearEvent());
BlocProvider.of<EffectPeriodBloc>(NavigationService.navigatorKey.currentState!.context)
.add(ResetEffectivePeriod());
NavigationService.navigatorKey.currentContext!
.read<CreateSceneBloc>()
.add(const ClearTabToRunSetting());
},
),
IconButton(

View File

@ -33,7 +33,7 @@ class GetSpacesError extends HomeError {
class GetSpaceRoomsLoading extends HomeLoading {}
class GetSpaceRoomsSuccess extends HomeSuccess {
final List<RoomModel> rooms;
final List<SubSpaceModel> rooms;
GetSpaceRoomsSuccess(this.rooms);
}
@ -50,7 +50,7 @@ class SpaceSelected extends HomeState {
}
class RoomSelected extends HomeState {
final RoomModel room;
final SubSpaceModel room;
RoomSelected(this.room);
}

View File

@ -0,0 +1,27 @@
class Community {
final String uuid;
final String name;
final String description;
Community({
required this.uuid,
required this.name,
this.description = '',
});
factory Community.fromJson(Map<String, dynamic> json) {
return Community(
uuid: json['uuid'] ?? '',
name: json['name'] ?? 'Unnamed Community',
description: json['description'] ?? '',
);
}
Map<String, dynamic> toJson() {
return {
'uuid': uuid,
'name': name,
'description': description,
};
}
}

View File

@ -1,37 +1,53 @@
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/features/app_layout/model/community_model.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
class SpaceModel {
final String? id;
final String? name;
final SpaceType type;
late List<RoomModel>? rooms;
final String id;
final String name;
final Community community;
late List<SubSpaceModel> subspaces;
SpaceModel({
required this.type,
required this.id,
required this.name,
required this.rooms,
required this.community,
this.subspaces = const [], // Default to an empty list
});
/// Converts the instance into JSON format.
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'rooms': rooms,
'spaceName': name,
'community': community.toJson(),
'subspaces': subspaces.map((room) => room.toJson()).toList(),
};
}
/// Factory constructor to create an instance from JSON.
factory SpaceModel.fromJson(Map<String, dynamic> json) {
// Extract and log each part of space data
final id = json['uuid'] ?? '';
final name = json['spaceName'] ?? 'Unnamed Space';
final communityJson = json['community'] ?? {};
return SpaceModel(
id: json['uuid'],
name: json['name'],
type: spaceTypesMap[json['type']]!,
rooms: [],
id: id,
name: name,
community: Community.fromJson(
communityJson), // Ensure Community is created correctly
subspaces: (json['subspaces'] as List<dynamic>?)
?.map((item) => SubSpaceModel.fromJson(item))
.toList() ??
[],
);
}
/// Helper method to parse a list of SpaceModel from JSON.
static List<SpaceModel> fromJsonList(List<dynamic> jsonList) {
return jsonList.map((item) => SpaceModel.fromJson(item)).toList();
return jsonList.map((item) {
final spaceData = item['space']; // Extract the `space` object
return SpaceModel.fromJson(spaceData); // Pass to SpaceModel.fromJson
}).toList();
}
}

View File

@ -46,7 +46,7 @@ class AppBarHomeDropdown extends StatelessWidget {
const SizedBox(width: 5),
Flexible(
child: BodyMedium(
text: space.name ?? "??",
text: space.name,
style: context.bodyMedium.copyWith(
fontSize: 15,
color: ColorsManager.textPrimaryColor,

View File

@ -237,26 +237,34 @@ class AuthCubit extends Cubit<AuthState> {
}
}
sendOtp() async {
sendOtp({bool? isforget}) async {
try {
emit(AuthLoading());
await AuthenticationAPI.sendOtp(
body: {'email': email, 'type': 'VERIFICATION'});
await AuthenticationAPI.sendOtp(body: {
'email': email,
'type': isforget == true ? 'PASSWORD' : 'VERIFICATION'
});
emit(AuthSignUpSuccess());
} catch (_) {
emit(AuthLoginError(message: 'Something went wrong'));
emit(AuthErrorStatusWithoutMsg());
// emit(AuthLoginError(message: 'Something went wrong'));
}
}
Future<bool> reSendOtp() async {
Future<bool> reSendOtp({bool? forget}) async {
try {
emit(AuthLoading());
await AuthenticationAPI.sendOtp(
body: {'email': email, 'type': 'VERIFICATION'});
await AuthenticationAPI.sendOtp(body: {
'email': email,
'type': forget == true ? 'PASSWORD' : 'VERIFICATION'
});
emit(ResendOtpSuccess());
return true;
} catch (_) {
emit(AuthLoginError(message: 'Something went wrong'));
emit(AuthErrorStatusWithoutMsg());
// emit(AuthLoginError(message: 'Something went wrong'));
return false;
}
}
@ -264,8 +272,11 @@ class AuthCubit extends Cubit<AuthState> {
verifyOtp(bool isForgotPass) async {
emit(AuthLoginLoading());
try {
final response = await AuthenticationAPI.verifyPassCode(
body: {'email': email, 'type': 'VERIFICATION', 'otpCode': otpCode});
final response = await AuthenticationAPI.verifyPassCode(body: {
'email': email,
'type': isForgotPass == true ? 'PASSWORD' : 'VERIFICATION',
'otpCode': otpCode
});
if (response['statusCode'] == 200) {
if (!isForgotPass) {
emailController.text = email;
@ -273,11 +284,13 @@ class AuthCubit extends Cubit<AuthState> {
await login();
}
emit(AuthOtpSuccess());
} else {
emit(AuthLoginError(message: 'Something went wrong'));
}
// else {
// emit(AuthLoginError(message: 'Something went wrong'));
// }
} catch (failure) {
emit(AuthLoginError(message: 'Something went wrong'));
emit(AuthErrorStatusWithoutMsg());
//emit(AuthLoginError(message: 'Something went wrong'));
return;
}
}
@ -292,7 +305,9 @@ class AuthCubit extends Cubit<AuthState> {
(Route route) => false,
);
} catch (failure) {
emit(AuthLogoutError(message: 'Something went wrong'));
emit(AuthErrorStatusWithoutMsg());
// emit(AuthLogoutError(message: 'Something went wrong'));
return;
}
}
@ -333,17 +348,22 @@ class AuthCubit extends Cubit<AuthState> {
emit(AuthTokenError(message: "Something went wrong"));
}
} catch (_) {
emit(AuthTokenError(message: "Something went wrong"));
emit(AuthErrorStatusWithoutMsg());
// emit(AuthTokenError(message: "Something went wrong"));
}
}
sendToForgetPassword({required String password}) async {
try {
emit(AuthForgetPassLoading());
await AuthenticationAPI.forgetPassword(email: email, password: password);
await AuthenticationAPI.forgetPassword(
email: email, password: password, otpCode: otpCode);
emit(AuthForgetPassSuccess());
} catch (_) {
emit(AuthForgetPassError(message: 'Something went wrong'));
emit(AuthErrorStatusWithoutMsg());
// emit(AuthForgetPassError(message: 'Something went wrong'));
}
}
}

View File

@ -52,9 +52,6 @@ class AuthTokenError extends AuthError {
AuthTokenError({required super.message, super.code});
}
//ForgetPassword log states
class AuthForgetPassLoading extends AuthLoading {}
@ -64,3 +61,6 @@ class AuthForgetPassError extends AuthError {
AuthForgetPassError({required super.message, super.code});
}
class AuthErrorStatusWithoutMsg extends AuthState {
AuthErrorStatusWithoutMsg();
}

View File

@ -14,8 +14,9 @@ import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
class checkEmailPage extends StatelessWidget {
const checkEmailPage({super.key});
class CheckEmailPage extends StatelessWidget {
final bool? forget;
const CheckEmailPage({super.key, this.forget});
@override
Widget build(BuildContext context) {
final formKey = AuthCubit.get(context).checkEmailFormKey;
@ -34,8 +35,8 @@ class checkEmailPage extends StatelessWidget {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const OtpView(
isForgetPage: true,
builder: (context) => OtpView(
isForgetPage: forget!,
),
));
}
@ -149,7 +150,7 @@ class checkEmailPage extends StatelessWidget {
AuthCubit.get(context).showValidationMessage = true;
if (formKey.currentState!.validate()) {
if ((state is! AuthLoading)) {
AuthCubit.get(context).sendOtp();
AuthCubit.get(context).sendOtp(isforget: forget);
FocusScope.of(context).unfocus();
}
}

View File

@ -12,6 +12,7 @@ import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
class CreateNewPasswordPage extends StatelessWidget {
const CreateNewPasswordPage({super.key,});

View File

@ -374,20 +374,25 @@ class _OtpViewState extends State<OtpView> {
return;
}
if ((state is! AuthLoading)) {
bool success = await AuthCubit.get(context)
.reSendOtp();
bool success =
await AuthCubit.get(context)
.reSendOtp(
forget:
widget.isForgetPage);
FocusScope.of(context).unfocus();
if(success){
showDialog(
context: context,
builder: (_) => SuccessDialog(
key: ValueKey('SuccessDialog'),
message: 'New OTP sent!',));
if (success) {
showDialog(
context: context,
builder: (_) =>const SuccessDialog(
key: ValueKey(
'SuccessDialog'),
message: 'New OTP sent!',
));
}
Future.delayed(Duration(seconds: 2),
() {
Navigator.of(context).pop();
});
// Future.delayed(Duration(seconds: 2),
// () {
// Navigator.of(context).pop();
// });
}
},
),

View File

@ -10,12 +10,17 @@ class ForgetPassword extends StatelessWidget {
@override
Widget build(BuildContext context) {
bool isforget = true;
return Row(
children: [
const Spacer(),
TextButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const checkEmailPage(),));
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CheckEmailPage(forget: isforget),
));
},
child: BodyMedium(
text: "Forgot Password?",

View File

@ -61,8 +61,7 @@ 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();
@ -75,22 +74,18 @@ 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 (_) {}
@ -107,14 +102,12 @@ 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();
}
@ -136,8 +129,7 @@ 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 {
@ -198,8 +190,7 @@ 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 {
@ -227,8 +218,7 @@ 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 {
@ -256,8 +246,7 @@ 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 {
@ -279,9 +268,7 @@ 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 {
@ -294,23 +281,19 @@ 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) {
@ -355,8 +338,7 @@ 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));
@ -378,10 +360,7 @@ 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']) {
@ -398,8 +377,7 @@ 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,8 +19,7 @@ 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);
@ -39,18 +38,15 @@ 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);
@ -59,19 +55,15 @@ 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

@ -25,12 +25,14 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
static List<DevicesCategoryModel>? allCategories;
Future<void> _onFetchAllDevices(FetchAllDevices event, Emitter<DeviceManagerState> emit) async {
Future<void> _onFetchAllDevices(
FetchAllDevices event, Emitter<DeviceManagerState> emit) async {
emit(state.copyWith(loading: true));
try {
final allDevices = await HomeManagementAPI.fetchDevicesByUnitId();
emit(state.copyWith(devices: allDevices, loading: false));
} catch (e) {
print(e);
emit(state.copyWith(error: e.toString(), loading: false));
}
}
@ -39,21 +41,27 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
FetchDevicesByRoomId event, Emitter<DeviceManagerState> emit) async {
emit(state.copyWith(loading: true));
try {
final devices = await DevicesAPI.getDevicesByRoomId(event.roomId);
final devices = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id,
roomId: event.roomId,
);
emit(state.copyWith(devices: devices, loading: false));
} catch (e) {
emit(state.copyWith(error: e.toString(), loading: false));
}
}
void _onSelectCategory(SelectCategory event, Emitter<DeviceManagerState> emit) {
void _onSelectCategory(
SelectCategory event, Emitter<DeviceManagerState> emit) {
for (var i = 0; i < allCategories!.length; i++) {
allCategories![i].isSelected = i == event.index;
}
emit(state.copyWith(categoryChanged: true));
}
void _onUnselectAllCategories(UnselectAllCategories event, Emitter<DeviceManagerState> emit) {
void _onUnselectAllCategories(
UnselectAllCategories event, Emitter<DeviceManagerState> emit) {
for (var category in allCategories!) {
category.isSelected = false;
}
@ -97,7 +105,8 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
_updateDevicesStatus(category, emit);
}
void _onTurnOnOffDevice(TurnOnOffDevice event, Emitter<DeviceManagerState> emit) {
void _onTurnOnOffDevice(
TurnOnOffDevice event, Emitter<DeviceManagerState> emit) {
var device = event.device;
device.isOnline = !device.isOnline!;
DevicesCategoryModel category = allCategories!.firstWhere((category) {
@ -120,7 +129,8 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
emit(state.copyWith(categoryChanged: true)); // Set category changed state
}
void _updateDevicesStatus(DevicesCategoryModel category, Emitter<DeviceManagerState> emit) {
void _updateDevicesStatus(
DevicesCategoryModel category, Emitter<DeviceManagerState> emit) {
if (category.devices != null && category.devices!.isNotEmpty) {
bool? tempStatus = category.devices![0].isOnline;
for (var device in category.devices!) {
@ -140,7 +150,8 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
try {
final deviceFunctions = await DevicesAPI.deviceFunctions(event.deviceId);
emit(state.copyWith(functionsLoading: false, deviceFunctions: deviceFunctions));
emit(state.copyWith(
functionsLoading: false, deviceFunctions: deviceFunctions));
} catch (e) {
emit(state.copyWith(functionsLoading: false, error: e.toString()));
}

View File

@ -1,5 +1,6 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
@ -15,8 +16,9 @@ class FetchAllDevices extends DeviceManagerEvent {}
class FetchDevicesByRoomId extends DeviceManagerEvent {
final String roomId;
final SpaceModel unit;
const FetchDevicesByRoomId(this.roomId);
const FetchDevicesByRoomId(this.roomId, this.unit);
@override
List<Object> get props => [roomId];

View File

@ -23,14 +23,22 @@ import 'package:syncrow_app/utils/resource_manager/constants.dart';
part 'devices_state.dart';
class DevicesCubit extends Cubit<DevicesState> {
Future<void> _initializeDevices(SpaceModel selectedSpace) async {
// Fetch devices for each room in the selected space
for (var room in selectedSpace.subspaces) {
await fetchDevicesByRoomId(selectedSpace, room.id!);
}
// Fetch groups based on the selected space ID
await fetchGroups(selectedSpace.id);
}
DevicesCubit._() : super(DevicesInitial()) {
if (HomeCubit.getInstance().selectedSpace != null &&
HomeCubit.getInstance().spaces!.isNotEmpty) {
// fetchGroups(HomeCubit.getInstance().selectedSpace!.id!);
for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) {
fetchDevicesByRoomId(room.id!);
}
fetchGroups(HomeCubit.getInstance().selectedSpace?.id ?? '');
final selectedSpace = HomeCubit.getInstance().selectedSpace;
final spaces = HomeCubit.getInstance().spaces;
if (selectedSpace != null && spaces != null && spaces.isNotEmpty) {
_initializeDevices(selectedSpace);
}
}
@ -87,10 +95,10 @@ class DevicesCubit extends Cubit<DevicesState> {
return const DoorsListView();
case DeviceType.Curtain:
return const CurtainListView();
// case DeviceType.ThreeGang:
// return const ThreeGangSwitchesView();
// case DeviceType.Gateway:
// return const GateWayView();
// case DeviceType.ThreeGang:
// return const ThreeGangSwitchesView();
// case DeviceType.Gateway:
// return const GateWayView();
default:
return null;
}
@ -103,9 +111,8 @@ class DevicesCubit extends Cubit<DevicesState> {
// Getter to retrieve all devices from HomeCubit
List<DeviceModel> get allDevices {
List<DeviceModel> devices = [];
if (HomeCubit.getInstance().selectedSpace != null &&
HomeCubit.getInstance().selectedSpace!.rooms != null) {
for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) {
if (HomeCubit.getInstance().selectedSpace != null) {
for (var room in HomeCubit.getInstance().selectedSpace!.subspaces) {
if (room.devices != null) {
devices.addAll(room.devices!);
}
@ -270,15 +277,15 @@ class DevicesCubit extends Cubit<DevicesState> {
if (response['success'] ?? false) {
emitSafe(DeviceControlSuccess(code: control.code));
//this delay is to give tuya server time to update the status
Future.delayed(const Duration(milliseconds: 400), () {
fetchDevicesStatues(
deviceId,
HomeCubit.getInstance()
.selectedSpace!
.rooms!
.indexOf(HomeCubit.getInstance().selectedRoom!),
code: control.code);
});
// Future.delayed(const Duration(milliseconds: 400), () {
fetchDevicesStatues(
deviceId,
HomeCubit.getInstance()
.selectedSpace!
.subspaces
.indexOf(HomeCubit.getInstance().selectedRoom!),
code: control.code);
// });
} else {
emitSafe(DeviceControlError('Failed to control the device'));
}
@ -303,20 +310,23 @@ class DevicesCubit extends Cubit<DevicesState> {
}
}
fetchDevicesByRoomId(String? roomId) async {
fetchDevicesByRoomId(SpaceModel? unit, String? roomId) async {
if (roomId == null) return;
emitSafe(GetDevicesLoading());
int roomIndex =
HomeCubit.getInstance().selectedSpace!.rooms!.indexWhere((element) => element.id == roomId);
int roomIndex = HomeCubit.getInstance()
.selectedSpace!
.subspaces
.indexWhere((element) => element.id == roomId);
try {
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices =
await DevicesAPI.getDevicesByRoomId(roomId);
HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices =
await DevicesAPI.getDevicesByRoomId(
communityUuid: unit!.community.uuid, spaceUuid: unit.id, roomId: roomId);
} catch (e) {
emitSafe(GetDevicesError(e.toString()));
return;
}
final devices = HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices;
final devices = HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices;
emitSafe(GetDevicesSuccess(devices));
//get status for each device
@ -333,7 +343,7 @@ class DevicesCubit extends Cubit<DevicesState> {
emitSafe(GetDeviceStatusLoading(code: code));
int deviceIndex = HomeCubit.getInstance()
.selectedSpace!
.rooms![roomIndex]
.subspaces[roomIndex]
.devices!
.indexWhere((element) => element.uuid == deviceUuid);
List<StatusModel> statuses = [];
@ -346,7 +356,7 @@ class DevicesCubit extends Cubit<DevicesState> {
emitSafe(GetDeviceStatusError(e.toString()));
return;
}
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices![deviceIndex].status =
HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices![deviceIndex].status =
statuses;
emitSafe(GetDeviceStatusSuccess(code: code));
}
@ -396,8 +406,6 @@ class DevicesCubit extends Cubit<DevicesState> {
// emitSafe(LightBrightnessChanged(value));
// }
// }
}
enum LightMode {

View File

@ -25,11 +25,9 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
bool lowBattery = false;
bool closingReminder = false;
bool doorAlarm = false;
DoorSensorModel deviceStatus =
DoorSensorModel(doorContactState: false, batteryPercentage: 0);
DoorSensorModel deviceStatus = DoorSensorModel(doorContactState: false, batteryPercentage: 0);
void _fetchStatus(
DoorSensorInitial event, Emitter<DoorSensorState> emit) async {
void _fetchStatus(DoorSensorInitial event, Emitter<DoorSensorState> emit) async {
emit(DoorSensorLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(DSId);
@ -50,8 +48,7 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
}
// Toggle functions for each switch
void _toggleLowBattery(
ToggleLowBatteryEvent event, Emitter<DoorSensorState> emit) async {
void _toggleLowBattery(ToggleLowBatteryEvent event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
lowBattery = event.isLowBatteryEnabled;
@ -92,8 +89,7 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
}
}
void _toggleDoorAlarm(
ToggleDoorAlarmEvent event, Emitter<DoorSensorState> emit) async {
void _toggleDoorAlarm(ToggleDoorAlarmEvent event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
doorAlarm = event.isDoorAlarmEnabled;
@ -112,11 +108,9 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
}
}
DeviceReport recordGroups =
DeviceReport(startTime: '0', endTime: '0', data: []);
DeviceReport recordGroups = DeviceReport(startTime: '0', endTime: '0', data: []);
Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<DoorSensorState> emit) async {
Future<void> fetchLogsForLastMonth(ReportLogsInitial event, Emitter<DoorSensorState> emit) async {
DateTime now = DateTime.now();
DateTime lastMonth = DateTime(now.year, now.month - 1, now.day);
@ -126,9 +120,8 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
try {
emit(DoorSensorLoadingState());
var response = await DevicesAPI.getReportLogs(
startTime:
startTime.toString(),
endTime: endTime.toString(),
startTime: startTime.toString(),
endTime: endTime.toString(),
deviceUuid: DSId,
code: 'doorcontact_state',
);
@ -142,16 +135,14 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$DSId');
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$DSId');
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) {

View File

@ -65,8 +65,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
batteryPercentage: 0,
);
void _fetchStatus(
GarageDoorInitial event, Emitter<GarageDoorSensorState> emit) async {
void _fetchStatus(GarageDoorInitial event, Emitter<GarageDoorSensorState> emit) async {
emit(GarageDoorLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(GDId);
@ -114,8 +113,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
void _toggleClosingReminder(ToggleClosingReminderEvent event,
Emitter<GarageDoorSensorState> emit) async {
void _toggleClosingReminder(
ToggleClosingReminderEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
closingReminder = event.isClosingReminderEnabled;
@ -133,8 +132,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
void _toggleDoorAlarm(
ToggleDoorAlarmEvent event, Emitter<GarageDoorSensorState> emit) async {
void _toggleDoorAlarm(ToggleDoorAlarmEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
doorAlarm = event.isDoorAlarmEnabled;
@ -152,8 +150,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
DeviceReport recordGroups =
DeviceReport(startTime: '0', endTime: '0', data: []);
DeviceReport recordGroups = DeviceReport(startTime: '0', endTime: '0', data: []);
Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<GarageDoorSensorState> emit) async {
@ -172,8 +169,6 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
);
recordGroups = response;
emit(UpdateState(garageSensor: deviceStatus));
} on DioException catch (e) {
final errorData = e.response!.data;
@ -184,16 +179,14 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$GDId');
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>;
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));
@ -268,8 +261,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
deviceId: GDId,
);
List<dynamic> jsonData = response;
listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(UpdateState(garageSensor: deviceStatus));
} on DioException catch (e) {
final errorData = e.response!.data;
@ -280,13 +272,12 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
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<GarageDoorSensorState> emit) async {
Future toggleChange(ToggleScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
try {
emit(GarageDoorLoadingState());
final response = await DevicesAPI.changeSchedule(
@ -304,8 +295,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
Future deleteSchedule(DeleteScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
try {
emit(GarageDoorLoadingState());
final response = await DevicesAPI.deleteSchedule(
@ -324,15 +314,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<GarageDoorSensorState> emit) {
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<GarageDoorSensorState> emit) {
emit(GarageDoorLoadingState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<GarageDoorSensorState> emit) {
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<GarageDoorSensorState> emit) {
emit(GarageDoorLoadingState());
createSchedule = !createSchedule;
selectedDays.clear();
@ -349,16 +337,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
int secondSelected = 0;
bool toggleDoor = false;
Future<void> selectSeconds(
SelectSecondsEvent event, Emitter<GarageDoorSensorState> emit) async {
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);
DeviceControlModel(deviceId: GDId, code: 'tr_timecon', value: secondSelected), GDId);
emit(UpdateState(garageSensor: deviceStatus));
} on DioException catch (e) {
final errorData = e.response!.data;
@ -367,15 +352,12 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
openCloseGarageDoor(
ToggleDoorEvent event, Emitter<GarageDoorSensorState> emit) async {
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);
DeviceControlModel(deviceId: GDId, code: 'switch_1', value: toggleDoor), GDId);
add(const GarageDoorInitial());
emit(UpdateState(garageSensor: deviceStatus));
} on DioException catch (e) {
@ -385,16 +367,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
void _setCounterValue(
SetCounterValue event, Emitter<GarageDoorSensorState> emit) async {
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);
DeviceControlModel(deviceId: GDId, code: 'countdown_1', value: seconds), GDId);
if (response['success'] ?? false) {
deviceStatus.countdown1 = seconds;
@ -414,8 +393,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
void _getCounterValue(
GetCounterEvent event, Emitter<GarageDoorSensorState> emit) async {
void _getCounterValue(GetCounterEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(GDId);
@ -456,8 +434,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
List<GroupGarageModel> groupList = [];
bool allSwitchesOn = true;
void _fetchWizardStatus(
InitialWizardEvent event, Emitter<GarageDoorSensorState> emit) async {
void _fetchWizardStatus(InitialWizardEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
@ -467,8 +444,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', 'GD');
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));
@ -497,8 +473,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
void _groupAllOn(
GroupAllOnEvent event, Emitter<GarageDoorSensorState> emit) async {
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)
@ -510,8 +485,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
emit(UpdateGroupState(garageList: groupList, allSwitches: true));
// Get a list of all device IDs
List<String> allDeviceIds =
groupList.map((device) => device.deviceId).toList();
List<String> allDeviceIds = groupList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(
@ -531,8 +505,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
void _groupAllOff(
GroupAllOffEvent event, Emitter<GarageDoorSensorState> emit) async {
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)
@ -544,8 +517,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
emit(UpdateGroupState(garageList: groupList, allSwitches: false));
// Get a list of all device IDs
List<String> allDeviceIds =
groupList.map((device) => device.deviceId).toList();
List<String> allDeviceIds = groupList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(
@ -566,8 +538,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<GarageDoorSensorState> emit) async {
void _changeFirstWizardSwitch(
ChangeFirstWizardSwitchStatusEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
bool allSwitchesValue = true;
@ -580,8 +552,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
});
emit(UpdateGroupState(
garageList: groupList, allSwitches: allSwitchesValue));
emit(UpdateGroupState(garageList: groupList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
@ -597,16 +568,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
}
}
void _setTimeOutAlarm(
SetTimeOutValue event, Emitter<GarageDoorSensorState> emit) async {
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);
DeviceControlModel(deviceId: GDId, code: 'countdown_alarm', value: seconds), GDId);
if (response['success'] ?? false) {
deviceStatus.countdownAlarm = seconds;

View File

@ -26,8 +26,7 @@ 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);
@ -50,8 +49,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
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);
@ -70,21 +68,18 @@ 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);
@ -99,8 +94,7 @@ 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;
@ -125,20 +119,17 @@ 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) {
@ -161,8 +152,7 @@ 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);
@ -251,8 +241,7 @@ 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;
@ -263,13 +252,12 @@ 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(
@ -288,8 +276,7 @@ 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(
@ -309,8 +296,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
}
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<OneGangState> emit) {
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<OneGangState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
@ -339,8 +325,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
int selectedTabIndex = 0;
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<OneGangState> emit) {
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<OneGangState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
@ -349,8 +334,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
List<GroupOneGangModel> groupOneGangList = [];
bool allSwitchesOn = true;
void _fetchOneGangWizardStatus(
InitialWizardEvent event, Emitter<OneGangState> emit) async {
void _fetchOneGangWizardStatus(InitialWizardEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
@ -360,8 +344,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', '1G');
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));
@ -382,16 +365,15 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
return true;
});
}
emit(UpdateGroupState(
oneGangList: groupOneGangList, allSwitches: allSwitchesOn));
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<OneGangState> emit) async {
void _changeFirstWizardSwitch(
ChangeFirstWizardSwitchStatusEvent event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
try {
bool allSwitchesValue = true;
@ -404,8 +386,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
}
});
emit(UpdateGroupState(
oneGangList: groupOneGangList, allSwitches: allSwitchesValue));
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
@ -433,8 +414,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: true));
// Get a list of all device IDs
List<String> allDeviceIds =
groupOneGangList.map((device) => device.deviceId).toList();
List<String> allDeviceIds = groupOneGangList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(
@ -466,8 +446,7 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: false));
// Get a list of all device IDs
List<String> allDeviceIds =
groupOneGangList.map((device) => device.deviceId).toList();
List<String> allDeviceIds = groupOneGangList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(

View File

@ -30,8 +30,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
bool oneTouchGroup = false;
List<DeviceModel> devicesList = [];
OneTouchBloc({required this.oneTouchId, required this.switchCode})
: super(InitialState()) {
OneTouchBloc({required this.oneTouchId, required this.switchCode}) : super(InitialState()) {
on<InitialEvent>(_fetchOneTouchStatus);
on<OneTouchUpdated>(_oneTouchUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -54,8 +53,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
on<ChangeStatusEvent>(_changeStatus);
}
void _fetchOneTouchStatus(
InitialEvent event, Emitter<OneTouchState> emit) async {
void _fetchOneTouchStatus(InitialEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(oneTouchId);
@ -74,21 +72,18 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$oneTouchId');
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>;
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 = OneTouchModel.fromJson(statusList);
@ -103,8 +98,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
emit(UpdateState(oneTouchModel: deviceStatus));
}
void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<OneTouchState> emit) async {
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.value;
@ -129,20 +123,17 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
}
}
void _changeSliding(
ChangeSlidingSegment event, Emitter<OneTouchState> emit) async {
void _changeSliding(ChangeSlidingSegment event, Emitter<OneTouchState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(
SetCounterValue event, Emitter<OneTouchState> emit) async {
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),
DeviceControlModel(deviceId: oneTouchId, code: event.deviceCode, value: seconds),
oneTouchId);
if (response['success'] ?? false) {
@ -165,8 +156,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
}
}
void _getCounterValue(
GetCounterEvent event, Emitter<OneTouchState> emit) async {
void _getCounterValue(GetCounterEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(oneTouchId);
@ -255,8 +245,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
deviceId: oneTouchId,
);
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;
@ -267,13 +256,12 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
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<OneTouchState> emit) async {
Future toggleChange(ToggleScheduleEvent event, Emitter<OneTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
@ -292,8 +280,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<OneTouchState> emit) async {
Future deleteSchedule(DeleteScheduleEvent event, Emitter<OneTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
@ -313,8 +300,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
}
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<OneTouchState> emit) {
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<OneTouchState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
@ -343,8 +329,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
int selectedTabIndex = 0;
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<OneTouchState> emit) {
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<OneTouchState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
@ -353,8 +338,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
List<GroupOneTouchModel> groupOneTouchList = [];
bool allSwitchesOn = true;
void _fetchOneTouchWizardStatus(
InitialWizardEvent event, Emitter<OneTouchState> emit) async {
void _fetchOneTouchWizardStatus(InitialWizardEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
@ -364,8 +348,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', '1GT');
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));
@ -386,16 +369,15 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
return true;
});
}
emit(UpdateGroupState(
oneTouchList: groupOneTouchList, allSwitches: allSwitchesOn));
emit(UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<OneTouchState> emit) async {
void _changeFirstWizardSwitch(
ChangeFirstWizardSwitchStatusEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus));
try {
bool allSwitchesValue = true;
@ -413,8 +395,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
value: !event.value,
);
emit(UpdateGroupState(
oneTouchList: groupOneTouchList, allSwitches: allSwitchesValue));
emit(UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: allSwitchesValue));
if (response['success']) {
add(InitialEvent(groupScreen: oneTouchGroup));
}
@ -432,12 +413,10 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
}
// Emit the state with updated values
emit(
UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: true));
emit(UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: true));
// Get a list of all device IDs
List<String> allDeviceIds =
groupOneTouchList.map((device) => device.deviceId).toList();
List<String> allDeviceIds = groupOneTouchList.map((device) => device.deviceId).toList();
// First call for switch_1
final response1 = await DevicesAPI.deviceBatchController(
@ -466,12 +445,10 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
}
// Emit the state with updated values
emit(UpdateGroupState(
oneTouchList: groupOneTouchList, allSwitches: false));
emit(UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: false));
// Get a list of all device IDs
List<String> allDeviceIds =
groupOneTouchList.map((device) => device.deviceId).toList();
List<String> allDeviceIds = groupOneTouchList.map((device) => device.deviceId).toList();
// First call for switch_1
final response1 = await DevicesAPI.deviceBatchController(
@ -495,8 +472,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
String statusSelected = '';
String optionSelected = '';
Future<void> _changeStatus(
ChangeStatusEvent event, Emitter<OneTouchState> emit) async {
Future<void> _changeStatus(ChangeStatusEvent event, Emitter<OneTouchState> emit) async {
try {
emit(LoadingInitialState());
@ -521,10 +497,7 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: oneTouchId,
code: optionSelected,
value: selectedControl),
DeviceControlModel(deviceId: oneTouchId, code: optionSelected, value: selectedControl),
oneTouchId,
);
} else {

View File

@ -22,7 +22,8 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
on<FilterRecordsByDateEvent>(_filterRecordsByDate);
}
DateTime? dateTime = DateTime.now();
String formattedDate = DateFormat('yyyy/MM/dd').format(DateTime.now());
String formattedDate = DateFormat('dd/MM/yyyy').format(DateTime.now());
bool lowBattery = false;
bool closingReminder = false;
bool doorAlarm = false;
@ -305,8 +306,8 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
(newDate) {
if (newDate != null) {
dateTime = newDate;
formattedDate = DateFormat('yyyy/MM/dd').format(dateTime!);
// formattedDate = DateFormat('yyyy/MM/dd').format(dateTime!);
formattedDate = DateFormat('dd/MM/yyyy').format(dateTime!);
add(FilterRecordsByDateEvent(
selectedDate: dateTime!,
viewType: views[currentIndex],
@ -319,8 +320,7 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
(newDate) {
if (newDate != null) {
dateTime = newDate;
formattedDate = DateFormat('yyyy-MM').format(dateTime!);
formattedDate = DateFormat('yyyy/MM').format(dateTime!);
add(FilterRecordsByDateEvent(
selectedDate: dateTime!,
viewType: views[currentIndex],
@ -359,7 +359,7 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
context: context,
builder: (BuildContext context) {
return SizedBox(
height: 300,
height: MediaQuery.of(context).size.height * 0.4,
child: Column(
children: [
const Padding(
@ -463,7 +463,7 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
context: context,
builder: (BuildContext context) {
return SizedBox(
height: 300,
height: MediaQuery.of(context).size.height * 0.4,
child: Column(
children: [
const Padding(
@ -530,13 +530,13 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
Future<DateTime?> dayMonthYearPicker({
required BuildContext context,
}) async {
DateTime selectedDate = DateTime.now(); // Default selected date
DateTime selectedDate = DateTime.now();
return await showModalBottomSheet<DateTime>(
context: context,
builder: (BuildContext context) {
return SizedBox(
height: 350, // Increased height to accommodate the buttons
height: MediaQuery.of(context).size.height * 0.4,
child: Column(
children: [
Expanded(
@ -546,8 +546,7 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
minimumYear: 1900,
maximumYear: DateTime.now().year,
onDateTimeChanged: (DateTime newDateTime) {
selectedDate =
newDateTime; // Update the selected date when changed
selectedDate = newDateTime;
},
),
),
@ -561,15 +560,13 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context)
.pop(); // Dismiss the modal without returning a value
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context)
.pop(selectedDate); // Return the selected date
Navigator.of(context).pop(selectedDate);
},
),
],
@ -591,6 +588,8 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
.where((record) => record.eventTime!.year == event.selectedDate.year)
.toList();
} else if (event.viewType == 'Month') {
formattedDate =
"${getMonthShortName(event.selectedDate.month)} ${event.selectedDate.year.toString()}";
filteredRecords = record
.where((record) =>
record.eventTime!.year == event.selectedDate.year &&
@ -604,10 +603,6 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
record.eventTime!.day == event.selectedDate.day)
.toList();
}
String getMonthShortName(int month) {
final date = DateTime(0, month);
return DateFormat.MMM().format(date);
}
energyDataList = filteredRecords.map((eventDevice) {
return EnergyData(
@ -615,18 +610,32 @@ class PowerClampBloc extends Bloc<PowerClampEvent, PowerClampState> {
? getMonthShortName(
int.tryParse(DateFormat('MM').format(eventDevice.eventTime!))!)
: event.viewType == 'Month'
? DateFormat('yyyy/MM/dd').format(eventDevice.eventTime!)
? DateFormat('dd/MM').format(eventDevice.eventTime!)
: DateFormat('HH:mm:ss').format(eventDevice.eventTime!),
double.parse(eventDevice.value!),
);
}).toList();
selectDateRange();
Future.delayed(const Duration(milliseconds: 500));
emit(FilterRecordsState(filteredRecords: energyDataList));
}
String getMonthShortName(int month) {
final date = DateTime(0, month);
return DateFormat.MMM().format(date);
}
String endChartDate = '';
void selectDateRange() async {
DateTime startDate = dateTime!;
DateTime endDate = DateTime(startDate.year, startDate.month + 1, 1)
.subtract(Duration(days: 1));
String formattedEndDate = DateFormat('dd/MM/yyyy').format(endDate);
endChartDate = ' - $formattedEndDate';
}
}
// Event for filtering records by date
// _listenToChanges() {

View File

@ -14,8 +14,7 @@ class PowerClampSwitch extends PowerClampEvent {
final bool switchD;
final String deviceId;
final String productId;
const PowerClampSwitch(
{required this.switchD, this.deviceId = '', this.productId = ''});
const PowerClampSwitch({required this.switchD, this.deviceId = '', this.productId = ''});
@override
List<Object> get props => [switchD, deviceId, productId];
@ -26,8 +25,8 @@ class PowerClampUpdated extends PowerClampEvent {}
class FetchEnergyData extends PowerClampEvent {}
class SelectDateEvent extends PowerClampEvent {
BuildContext context;
SelectDateEvent({required this.context});
final BuildContext context;
const SelectDateEvent({required this.context});
}
class PowerClampInitial extends PowerClampEvent {
@ -108,12 +107,9 @@ class StopTimer extends PowerClampEvent {}
class OnClose extends PowerClampEvent {}
class FilterRecordsByDateEvent extends PowerClampEvent {
final DateTime selectedDate;
final String viewType; // 'Day', 'Month', 'Year'
const FilterRecordsByDateEvent(
{required this.selectedDate, required this.viewType});
const FilterRecordsByDateEvent({required this.selectedDate, required this.viewType});
}

View File

@ -37,8 +37,7 @@ 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);
@ -60,8 +59,7 @@ 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();
@ -73,8 +71,7 @@ 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;
@ -95,8 +92,7 @@ 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);
@ -115,18 +111,15 @@ 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);
@ -140,14 +133,11 @@ 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));
@ -157,58 +147,46 @@ 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();
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();
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()));
}
@ -229,8 +207,7 @@ 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));
@ -253,8 +230,7 @@ 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,
@ -284,27 +260,20 @@ 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;
}
}
@ -360,27 +329,20 @@ 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;
}
}
@ -389,8 +351,7 @@ 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;
@ -420,8 +381,7 @@ 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;
@ -447,12 +407,10 @@ 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());
});
@ -487,8 +445,7 @@ 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

@ -0,0 +1,259 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_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/question_model.dart';
import 'package:syncrow_app/features/devices/model/sos_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart';
class SosBloc extends Bloc<SosEvent, SosState> {
final String sosId;
SosBloc({
required this.sosId,
}) : super(const SosState()) {
on<SosInitial>(_fetchStatus);
on<ReportLogsInitial>(fetchLogsForLastMonth);
on<ToggleEnableAlarmEvent>(_toggleLowBattery);
on<ToggleClosingReminderEvent>(_toggleClosingReminder);
on<ChangeNameEvent>(_changeName);
on<SearchFaqEvent>(_onSearchFaq);
on<SosInitialQuestion>(_onSosInitial);
on<FetchRoomsEvent>(_fetchRoomsAndDevices);
on<SelectOptionEvent>(_onOptionSelected);
on<SaveSelectionEvent>(_onSaveSelection);
// on<ToggleWaterLeakAlarmEvent>(_toggleWaterLeakAlarm);
}
final TextEditingController nameController =
TextEditingController(text: '${'firstName'}');
bool isSaving = false;
bool editName = false;
final FocusNode focusNode = FocusNode();
Timer? _timer;
bool enableAlarm = false;
bool closingReminder = false;
bool waterAlarm = false;
SosModel deviceStatus =
SosModel(sosContactState: 'normal', batteryPercentage: 0);
void _fetchStatus(SosInitial event, Emitter<SosState> emit) async {
emit(SosLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(sosId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = SosModel.fromJson(
statusModelList,
);
emit(UpdateState(sensor: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges();
} catch (e) {
emit(SosFailedState(errorMessage: e.toString()));
return;
}
}
void _onSearchFaq(SearchFaqEvent event, Emitter<SosState> emit) {
emit(SosLoadingState());
List<QuestionModel> _faqQuestions = faqQuestions.where((question) {
return question.question
.toLowerCase()
.contains(event.query.toLowerCase());
}).toList();
emit(FaqSearchState(filteredFaqQuestions: _faqQuestions));
}
void _changeName(ChangeNameEvent event, Emitter<SosState> emit) {
emit(SosLoadingState());
editName = event.value!;
if (editName) {
Future.delayed(const Duration(milliseconds: 500), () {
focusNode.requestFocus();
});
} else {
focusNode.unfocus();
}
emit(NameEditingState(editName: editName));
}
void _toggleLowBattery(
ToggleEnableAlarmEvent event, Emitter<SosState> emit) async {
emit(LoadingNewSate(sosSensor: deviceStatus));
try {
enableAlarm = event.isLowBatteryEnabled;
emit(UpdateState(sensor: deviceStatus));
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: sosId,
code: 'low_battery',
value: enableAlarm,
),
sosId,
);
} catch (e) {
emit(SosFailedState(errorMessage: e.toString()));
}
}
void _toggleClosingReminder(
ToggleClosingReminderEvent event, Emitter<SosState> emit) async {
emit(LoadingNewSate(sosSensor: deviceStatus));
try {
closingReminder = event.isClosingReminderEnabled;
emit(UpdateState(sensor: deviceStatus));
// API call to update the state, if necessary
// await DevicesAPI.controlDevice(
// DeviceControlModel(
// deviceId: sosId,
// code: 'closing_reminder',
// value: closingReminder,
// ),
// sosId,
// );
} catch (e) {
emit(SosFailedState(errorMessage: e.toString()));
}
}
DeviceReport recordGroups =
DeviceReport(startTime: '0', endTime: '0', data: []);
Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<SosState> 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(SosLoadingState());
var response = await DevicesAPI.getReportLogs(
startTime: startTime.toString(),
endTime: endTime.toString(),
deviceUuid: sosId,
code: 'sossensor_state',
);
recordGroups = response;
emit(UpdateState(sensor: deviceStatus));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(SosFailedState(errorMessage: e.toString()));
}
}
// _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 (_) {}
// }
// Demo list of FAQ questions using the QuestionModel class
final List<QuestionModel> faqQuestions = [
QuestionModel(
id: 1,
question: 'How does an SOS emergency button work?',
answer:
'The SOS emergency button sends an alert to your contacts when pressed.',
),
QuestionModel(
id: 2,
question: 'How long will an SOS alarm persist?',
answer:
'The SOS alarm will persist until it is manually turned off or after a set time.',
),
QuestionModel(
id: 3,
question: 'What should I do if the SOS button is unresponsive?',
answer: 'Try restarting the device. If it persists, contact support.',
),
QuestionModel(
id: 4,
question: 'Can I use the SOS feature without a network connection?',
answer:
'No, a network connection is required to send the alert to your contacts.',
),
QuestionModel(
id: 5,
question: 'How often should I check the SOS battery?',
answer:
'Check the SOS battery at least once a month to ensure it is operational.',
),
];
Future<void> _onSosInitial(
SosInitialQuestion event, Emitter<SosState> emit) async {
emit(SosLoadingState());
// SosModel sosModel = await fetchSosData(sosId); // Define this function as needed
emit(FaqLoadedState(filteredFaqQuestions: faqQuestions));
}
List<DeviceModel> allDevices = [];
List<SubSpaceModel> roomsList = [];
void _fetchRoomsAndDevices(
FetchRoomsEvent event, Emitter<SosState> emit) async {
try {
emit(SosLoadingState());
roomsList = await SpacesAPI.getSubSpaceBySpaceId(
event.unit.community.uuid, event.unit.id);
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
} catch (e) {
emit(const SosFailedState(errorMessage: 'Something went wrong'));
return;
}
}
String _selectedOption = '';
bool _hasSelectionChanged = false;
void _onOptionSelected(SelectOptionEvent event, Emitter<SosState> emit) {
emit(SosLoadingState());
_selectedOption = event.selectedOption;
_hasSelectionChanged = true;
emit(OptionSelectedState(
selectedOption: _selectedOption,
hasSelectionChanged: _hasSelectionChanged));
}
void _onSaveSelection(SaveSelectionEvent event, Emitter<SosState> emit) {
if (_hasSelectionChanged) {
print('Save button clicked with selected option: $_selectedOption');
_hasSelectionChanged = false;
emit(SaveSelectionSuccessState());
}
}
}

View File

@ -0,0 +1,129 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
abstract class SosEvent extends Equatable {
const SosEvent();
@override
List<Object> get props => [];
}
class SosLoading extends SosEvent {}
class SosSwitch extends SosEvent {
final String switchD;
final String deviceId;
final String productId;
const SosSwitch(
{required this.switchD, this.deviceId = '', this.productId = ''});
@override
List<Object> get props => [switchD, deviceId, productId];
}
class SosUpdated extends SosEvent {}
class SosInitial extends SosEvent {
const SosInitial();
}
class ReportLogsInitial extends SosEvent {
const ReportLogsInitial();
}
class SosChangeStatus extends SosEvent {}
class GetCounterEvent extends SosEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class ToggleEnableAlarmEvent extends SosEvent {
final bool isLowBatteryEnabled;
const ToggleEnableAlarmEvent(this.isLowBatteryEnabled);
@override
List<Object> get props => [isLowBatteryEnabled];
}
class ToggleClosingReminderEvent extends SosEvent {
final bool isClosingReminderEnabled;
const ToggleClosingReminderEvent(this.isClosingReminderEnabled);
@override
List<Object> get props => [isClosingReminderEnabled];
}
class ToggleSosAlarmEvent extends SosEvent {
final bool isSosAlarmEnabled;
const ToggleSosAlarmEvent(this.isSosAlarmEnabled);
@override
List<Object> get props => [isSosAlarmEnabled];
}
class SetCounterValue extends SosEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends SosEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends SosEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends SosEvent {}
class OnClose extends SosEvent {}
class ChangeNameEvent extends SosEvent {
final bool? value;
const ChangeNameEvent({this.value});
}
class SearchFaqEvent extends SosEvent {
final String query;
const SearchFaqEvent(this.query);
}
class SosInitialQuestion extends SosEvent {
const SosInitialQuestion();
}
class FetchRoomsEvent extends SosEvent {
final SpaceModel unit;
const FetchRoomsEvent({required this.unit});
@override
List<Object> get props => [unit];
}
class SelectOptionEvent extends SosEvent {
final String selectedOption;
SelectOptionEvent({required this.selectedOption});
}
class SaveSelectionEvent extends SosEvent {}

View File

@ -0,0 +1,87 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/question_model.dart';
import 'package:syncrow_app/features/devices/model/sos_model.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
class SosState extends Equatable {
const SosState();
@override
List<Object> get props => [];
}
class SosInitialState extends SosState {}
class SosLoadingState extends SosState {}
class SosFailedState extends SosState {
final String errorMessage;
const SosFailedState({required this.errorMessage});
@override
List<Object> get props => [errorMessage];
}
class UpdateState extends SosState {
final SosModel sensor;
const UpdateState({required this.sensor});
@override
List<Object> get props => [sensor];
}
class LoadingNewSate extends SosState {
final SosModel sosSensor;
const LoadingNewSate({required this.sosSensor});
@override
List<Object> get props => [sosSensor];
}
class NameEditingState extends SosState {
final bool editName;
NameEditingState({required this.editName});
}
class FaqLoadedState extends SosState {
final List<QuestionModel> filteredFaqQuestions;
FaqLoadedState({this.filteredFaqQuestions = const []});
}
class FaqSearchState extends SosState {
final List<QuestionModel> filteredFaqQuestions;
const FaqSearchState({this.filteredFaqQuestions = const []});
}
class FetchRoomsState extends SosState {
final List<SubSpaceModel> roomsList;
final List<DeviceModel> devicesList;
const FetchRoomsState({required this.devicesList, required this.roomsList});
@override
List<Object> get props => [devicesList];
}
class OptionSelectedState extends SosState {
final String selectedOption;
final bool hasSelectionChanged;
OptionSelectedState({
required this.selectedOption,
required this.hasSelectionChanged,
});
@override
List<Object> get props => [selectedOption, hasSelectionChanged];
}
class SaveSelectionSuccessState extends SosState {
@override
List<Object> get props => [];
}

View File

@ -20,9 +20,7 @@ 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);
@ -41,18 +39,15 @@ 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);
@ -61,19 +56,15 @@ 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;
@ -82,14 +73,11 @@ 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

@ -35,8 +35,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
List<ScheduleModel> listSchedule = [];
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);
@ -61,8 +60,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
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);
@ -83,21 +81,18 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$whId');
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$whId');
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 = WHModel.fromJson(statusList);
@ -108,14 +103,12 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} catch (_) {}
}
_waterHeaterUpdated(
WaterHeaterUpdated event, Emitter<WaterHeaterState> emit) async {
_waterHeaterUpdated(WaterHeaterUpdated event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
emit(UpdateState(whModel: deviceStatus));
}
void _changeFirstSwitch(
WaterHeaterSwitch event, Emitter<WaterHeaterState> emit) async {
void _changeFirstSwitch(WaterHeaterSwitch event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.whSwitch;
@ -125,10 +118,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: whId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
DeviceControlModel(deviceId: whId, code: 'switch_1', value: deviceStatus.firstSwitch),
whId);
if (!response['success']) {
@ -142,16 +132,13 @@ 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),
whId);
DeviceControlModel(deviceId: whId, code: event.deviceCode, value: seconds), whId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
@ -173,8 +160,7 @@ 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);
@ -264,8 +250,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
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;
@ -276,13 +261,12 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
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<WaterHeaterState> emit) async {
Future toggleChange(ToggleScheduleEvent event, Emitter<WaterHeaterState> emit) async {
try {
emit(WHLoadingState());
final response = await DevicesAPI.changeSchedule(
@ -300,8 +284,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<WaterHeaterState> emit) async {
Future deleteSchedule(DeleteScheduleEvent event, Emitter<WaterHeaterState> emit) async {
try {
emit(WHLoadingState());
final response = await DevicesAPI.deleteSchedule(
@ -320,8 +303,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
}
void _toggleCreateCirculate(
ToggleCreateCirculate event, Emitter<WaterHeaterState> emit) {
void _toggleCreateCirculate(ToggleCreateCirculate event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
createCirculate = !createCirculate;
selectedDays.clear();
@ -329,15 +311,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
emit(UpdateCreateScheduleState(createCirculate));
}
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<WaterHeaterState> emit) {
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<WaterHeaterState> emit) {
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
createSchedule = !createSchedule;
selectedDays.clear();
@ -386,8 +366,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
List<GroupWHModel> groupWaterHeaterList = [];
bool allSwitchesOn = true;
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<WaterHeaterState> emit) async {
void _changeFirstWizardSwitch(
ChangeFirstWizardSwitchStatusEvent event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
bool allSwitchesValue = true;
@ -399,8 +379,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: allSwitchesValue));
emit(UpdateGroupState(twoGangList: groupWaterHeaterList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
@ -415,8 +394,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
}
void _fetchWHWizardStatus(
InitialWizardEvent event, Emitter<WaterHeaterState> emit) async {
void _fetchWHWizardStatus(InitialWizardEvent event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
try {
devicesList = [];
@ -426,8 +404,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', 'WH');
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));
@ -449,27 +426,23 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
return true;
});
}
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: allSwitchesOn));
emit(UpdateGroupState(twoGangList: groupWaterHeaterList, allSwitches: allSwitchesOn));
} catch (e) {
// emit(FailedState(error: e.toString()));
return;
}
}
void _groupAllOn(
GroupAllOnEvent event, Emitter<WaterHeaterState> emit) async {
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));
emit(UpdateGroupState(twoGangList: groupWaterHeaterList, allSwitches: true));
List<String> allDeviceIds =
groupWaterHeaterList.map((device) => device.deviceId).toList();
List<String> allDeviceIds = groupWaterHeaterList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
@ -487,18 +460,15 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
}
}
void _groupAllOff(
GroupAllOffEvent event, Emitter<WaterHeaterState> emit) async {
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));
emit(UpdateGroupState(twoGangList: groupWaterHeaterList, allSwitches: false));
List<String> allDeviceIds =
groupWaterHeaterList.map((device) => device.deviceId).toList();
List<String> allDeviceIds = groupWaterHeaterList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',

View File

@ -78,6 +78,8 @@ class DeviceModel {
tempIcon = Assets.waterLeakIcon;
} else if (type == DeviceType.PC) {
tempIcon = Assets.powerClampIcon;
} else if (type == DeviceType.SOS) {
tempIcon = Assets.sosDevice;
} else {
tempIcon = Assets.assetsIconsLogo;
}

View File

@ -0,0 +1,11 @@
class QuestionModel {
final int id;
final String question;
final String answer;
QuestionModel({
required this.id,
required this.question,
required this.answer,
});
}

View File

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

View File

@ -0,0 +1,35 @@
import 'package:syncrow_app/features/devices/model/device_model.dart';
class SubSpaceModel {
final String? id;
final String? name;
List<DeviceModel>? devices;
SubSpaceModel({
required this.id,
required this.name,
required this.devices,
});
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'devices': devices?.map((device) => device.toJson()).toList(),
};
}
factory SubSpaceModel.fromJson(Map<String, dynamic> json) {
List<DeviceModel> devices = [];
if (json['devices'] != null) {
for (var device in json['devices']) {
devices.add(DeviceModel.fromJson(device));
}
}
return SubSpaceModel(
id: json['uuid'],
name: json['subspaceName'],
devices: devices,
);
}
}

View File

@ -22,6 +22,8 @@ class ACsView extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("ACsView deviceModel UUID: ${deviceModel?.uuid}");
return BlocProvider(
create: (context) => ACsBloc(acId: deviceModel?.uuid ?? '')
..add(AcsInitial(allAcs: deviceModel != null ? false : true)),
@ -66,12 +68,14 @@ class ACsView extends StatelessWidget {
child: state is AcsLoadingState
? const Center(
child: DefaultContainer(
width: 50, height: 50, child: CircularProgressIndicator()),
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<ACsBloc>(context)
.add(AcsInitial(allAcs: deviceModel != null ? false : true));
BlocProvider.of<ACsBloc>(context).add(AcsInitial(
allAcs: deviceModel != null ? false : true));
},
child: Container(
padding: const EdgeInsets.only(top: 40),

View File

@ -13,13 +13,14 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class DevicesViewPage extends StatelessWidget {
const DevicesViewPage({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => SceneBloc(), // Initialize your SceneBloc here
create: (context) => SceneBloc(), // Initialize your SceneBloc here
child: DevicesViewBody(),
);
}
@ -42,74 +43,74 @@ class DevicesViewBody extends StatelessWidget {
return HomeCubit.getInstance().spaces?.isEmpty ?? true
? const CreateUnitWidget()
: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
TitleMedium(
text: StringsManager.devices,
style: context.titleMedium.copyWith(
fontSize: 25,
),
),
],
),
SizedBox(
height: MediaQuery.of(context).size.height*0.1,
child: const SceneView(pageType: true,)
),
const SizedBox(
height: 20,
),
const RoomsSlider(),
const SizedBox(
height: 10,
),
Expanded(
child: PageView(
controller: HomeCubit.getInstance().devicesPageController,
onPageChanged: (index) {
HomeCubit.getInstance().devicesPageChanged(index);
},
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
WizardPage(
groupsList: DevicesCubit.getInstance().allCategories ?? [],
Row(
children: [
TitleMedium(
text: StringsManager.devices,
style: context.titleMedium.copyWith(
fontSize: 25,
),
),
],
),
if (HomeCubit.getInstance().selectedSpace != null)
if (HomeCubit.getInstance().selectedSpace!.rooms != null)
...HomeCubit.getInstance().selectedSpace!.rooms!.map((room) {
return RoomPage(
room: room,
);
},
)
SizedBox(
height: MediaQuery.of(context).size.height * 0.1,
child: const SceneView(
pageType: true,
)),
const SizedBox(
height: 20,
),
const RoomsSlider(),
const SizedBox(
height: 10,
),
Expanded(
child: PageView(
controller: HomeCubit.getInstance().devicesPageController,
onPageChanged: (index) {
HomeCubit.getInstance().devicesPageChanged(index);
},
children: [
WizardPage(
groupsList: DevicesCubit.getInstance().allCategories ?? [],
),
if (HomeCubit.getInstance().selectedSpace != null)
...HomeCubit.getInstance().selectedSpace!.subspaces.map(
(room) {
return RoomPage(
room: room,
);
},
)
],
),
),
HomeCubit.getInstance().selectedSpace != null
? Padding(
padding: const EdgeInsets.symmetric(
vertical: 7,
),
child: SmoothPageIndicator(
controller: HomeCubit.getInstance().devicesPageController,
count: HomeCubit.getInstance().selectedSpace!.subspaces.length + 1,
effect: const WormEffect(
paintStyle: PaintingStyle.stroke,
dotHeight: 8,
dotWidth: 8,
),
),
)
: const Center(
child: BodyLarge(text: 'No Home Found'),
),
],
),
),
HomeCubit.getInstance().selectedSpace != null
? Padding(
padding: const EdgeInsets.symmetric(
vertical: 7,
),
child: SmoothPageIndicator(
controller: HomeCubit.getInstance().devicesPageController,
count: HomeCubit.getInstance().selectedSpace!.rooms!.length + 1,
effect: const WormEffect(
paintStyle: PaintingStyle.stroke,
dotHeight: 8,
dotWidth: 8,
),
),
)
: const Center(
child: BodyLarge(text: 'No Home Found'),
),
],
);
);
}
},
);
}
}
}

View File

@ -22,6 +22,8 @@ class PowerClampCard extends StatelessWidget {
final String? totalFactor;
final Widget? dateSwitcher;
final String? formattedDate;
final String? phaseType;
final String? energyConsumption;
final Function()? selectDateEvent;
final List<EnergyData>? chartData;
@ -37,6 +39,7 @@ class PowerClampCard extends StatelessWidget {
this.totalCurrentGeneral,
this.totalFrequencyGeneral,
this.totalVoltage,
this.phaseType,
this.totalActive,
this.totalFrequency,
this.totalFactor,
@ -53,8 +56,7 @@ class PowerClampCard extends StatelessWidget {
Widget build(BuildContext context) {
return DefaultContainer(
child: Padding(
padding:
const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 10),
padding: const EdgeInsets.only(left: 5, right: 5, top: 10, bottom: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
@ -116,7 +118,7 @@ class PowerClampCard extends StatelessWidget {
PowerClampInfoCard(
iconPath: Assets.voltageIcon,
title: 'Voltage',
value: totalVoltage!,
value: '${double.parse(totalVoltage!) / 10}',
unit: ' V',
),
PowerClampInfoCard(
@ -152,13 +154,15 @@ class PowerClampCard extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const BodyMedium(
text: 'Total consumption',
BodyMedium(
text: isGeneral == true
? 'Total consumption'
: phaseType!,
fontSize: 12,
fontWeight: FontWeight.w700,
),
Text(
dateTimeSelected !,
dateTimeSelected!,
style: const TextStyle(
fontSize: 8, fontWeight: FontWeight.w400),
),

View File

@ -55,7 +55,6 @@ class _PowerClampPageState extends State<PowerClampPage> {
child: BlocProvider(
create: (context) => PowerClampBloc(PCId: widget.device?.uuid ?? '')
..add(const PowerClampInitial()),
// ..add(const ReportLogsInitial(code: 'VoltageA')),
child: BlocBuilder<PowerClampBloc, PowerClampState>(
builder: (context, state) {
final blocProvider = context.read<PowerClampBloc>();
@ -88,6 +87,7 @@ class _PowerClampPageState extends State<PowerClampPage> {
},
child: PageView(controller: _pageController, children: [
_buildPowerClampCard(
phaseType: '',
title: 'Total Energy \nConsumption',
phase: model.status.general,
isGeneral: true,
@ -96,18 +96,21 @@ class _PowerClampPageState extends State<PowerClampPage> {
),
_buildPowerClampCard(
title: 'Phase A Energy \nConsumption',
phaseType: 'Phase A consumption',
phase: model.status.phaseA,
chartData: chartData,
blocProvider: blocProvider,
),
_buildPowerClampCard(
title: 'Phase B Energy \nConsumption',
phaseType: 'Phase B consumption',
phase: model.status.phaseB,
chartData: chartData,
blocProvider: blocProvider,
),
_buildPowerClampCard(
title: 'Phase C Energy \nConsumption',
phaseType: 'Phase C consumption',
phase: model.status.phaseC,
chartData: chartData,
blocProvider: blocProvider,
@ -154,6 +157,7 @@ class _PowerClampPageState extends State<PowerClampPage> {
List<EnergyData> chartData, PowerClampBloc blocProvider) {
return [
_buildPowerClampCard(
phaseType: '',
title: 'Total Energy \nConsumption',
phase: model.status.general,
isGeneral: true,
@ -161,18 +165,21 @@ class _PowerClampPageState extends State<PowerClampPage> {
blocProvider: blocProvider,
),
_buildPowerClampCard(
phaseType: 'Phase A consumption',
title: 'Phase A Energy \nConsumption',
phase: model.status.phaseA,
chartData: chartData,
blocProvider: blocProvider,
),
_buildPowerClampCard(
phaseType: 'Phase B consumption',
title: 'Phase B Energy \nConsumption',
phase: model.status.phaseB,
chartData: chartData,
blocProvider: blocProvider,
),
_buildPowerClampCard(
phaseType: 'Phase C consumption',
title: 'Phase C Energy \nConsumption',
phase: model.status.phaseC,
chartData: chartData,
@ -183,15 +190,18 @@ class _PowerClampPageState extends State<PowerClampPage> {
Widget _buildPowerClampCard({
required String title,
required String phaseType,
required Phase phase,
bool isGeneral = false,
required List<EnergyData> chartData,
required PowerClampBloc blocProvider,
}) {
return PowerClampCard(
dateTimeSelected:blocProvider.formattedDate,
dateTimeSelected:
'${blocProvider.dateTime!.day}/${blocProvider.dateTime!.month}/${blocProvider.dateTime!.year} ${blocProvider.endChartDate}',
energyConsumption: _getValueOrNA(phase.dataPoints, isGeneral ? 0 : 5),
title: title,
phaseType: phaseType,
isGeneral: isGeneral,
dateSwitcher: blocProvider.dateSwitcher(),
formattedDate: blocProvider.formattedDate,

View File

@ -21,53 +21,50 @@ class PowerClampInfoCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(5.0),
child: DefaultContainer(
height: 55,
color: ColorsManager.grayBox,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: SvgPicture.asset(
iconPath,
fit: BoxFit.fill,
),
child: DefaultContainer(
height: 55,
color: ColorsManager.grayBox,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: SvgPicture.asset(
iconPath,
fit: BoxFit.contain,
),
Expanded(
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BodyMedium(
fontWeight: FontWeight.w400,
fontSize: 8,
text: title,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BodyMedium(
fontWeight: FontWeight.w700,
fontSize: 15,
text: value,
),
BodyMedium(
fontWeight: FontWeight.w700,
fontSize: 8,
text: unit,
),
],
),
],
),
)
],
),
),
Expanded(
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BodyMedium(
fontWeight: FontWeight.w400,
fontSize: 8,
text: title,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BodyMedium(
fontWeight: FontWeight.w700,
fontSize: 15,
text: value,
),
BodyMedium(
fontWeight: FontWeight.w700,
fontSize: 8,
text: unit,
),
],
),
],
),
)
],
),
),
);

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -8,7 +8,7 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class RoomPage extends StatefulWidget {
const RoomPage({super.key, required this.room});
final RoomModel room;
final SubSpaceModel room;
@override
_RoomPageState createState() => _RoomPageState();
@ -51,9 +51,7 @@ class _RoomPageState extends State<RoomPage> {
decoration: InputDecoration(
hintText: 'Search',
hintStyle: const TextStyle(
color: ColorsManager.textGray,
fontSize: 16,
fontWeight: FontWeight.w400),
color: ColorsManager.textGray, fontSize: 16, fontWeight: FontWeight.w400),
prefixIcon: Container(
padding: const EdgeInsets.all(5.0),
margin: const EdgeInsets.all(10.0),
@ -67,21 +65,40 @@ class _RoomPageState extends State<RoomPage> {
),
),
),
Expanded(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 1.5,
),
padding: const EdgeInsets.only(top: 10),
itemCount: _filteredDevices.length,
itemBuilder: (context, index) {
return RoomPageSwitch(device: _filteredDevices[index]);
},
),
),
_filteredDevices.isNotEmpty
? Expanded(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 1.5,
),
padding: const EdgeInsets.only(top: 10),
itemCount: _filteredDevices.length,
itemBuilder: (context, index) {
return RoomPageSwitch(device: _filteredDevices[index]);
},
),
)
: widget.room.devices!.isNotEmpty
? const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Text(
'No Results Found',
style: TextStyle(
color: ColorsManager.grayColor,
fontSize: 14,
fontWeight: FontWeight.w400),
)),
],
),
)
: const SizedBox(),
],
);
}

View File

@ -16,6 +16,7 @@ import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_touch/one_touch_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/power_clamp/power_clamp_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_touch/three_touch_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_touch_Interface.dart';
@ -211,7 +212,12 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
WaterLeakScreen(device: device)));
case DeviceType.SOS:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
SosScreen(device: device)));
break;
default:
}

View File

@ -22,7 +22,6 @@ class RoomsSlider extends StatelessWidget {
onPageChanged: (index) {
HomeCubit.getInstance().roomSliderPageChanged(index);
},
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
@ -40,24 +39,23 @@ class RoomsSlider extends StatelessWidget {
),
),
if (HomeCubit.getInstance().selectedSpace != null)
if (HomeCubit.getInstance().selectedSpace!.rooms != null)
...HomeCubit.getInstance().selectedSpace!.rooms!.map(
(room) => InkWell(
onTap: () {
HomeCubit.getInstance().roomSliderPageChanged(
HomeCubit.getInstance().selectedSpace!.rooms!.indexOf(room));
},
child: TitleMedium(
text: room.name!,
style: context.titleMedium.copyWith(
fontSize: 25,
color: HomeCubit.getInstance().selectedRoom == room
? ColorsManager.textPrimaryColor
: ColorsManager.textPrimaryColor.withOpacity(.2),
),
...HomeCubit.getInstance().selectedSpace!.subspaces.map(
(room) => InkWell(
onTap: () {
HomeCubit.getInstance().roomSliderPageChanged(
HomeCubit.getInstance().selectedSpace!.subspaces.indexOf(room));
},
child: TitleMedium(
text: room.name!,
style: context.titleMedium.copyWith(
fontSize: 25,
color: HomeCubit.getInstance().selectedRoom == room
? ColorsManager.textPrimaryColor
: ColorsManager.textPrimaryColor.withOpacity(.2),
),
),
)
),
)
],
),
);

View File

@ -40,13 +40,10 @@ class SceneListview extends StatelessWidget {
sceneName: scene.name,
),
);
context
.read<SmartSceneSelectBloc>()
.add(const SmartSceneClearEvent());
context.read<SmartSceneSelectBloc>().add(const SmartSceneClearEvent());
BlocProvider.of<CreateSceneBloc>(context).add(
FetchSceneTasksEvent(
sceneId: scene.id, isAutomation: false));
BlocProvider.of<CreateSceneBloc>(context)
.add(FetchSceneTasksEvent(sceneId: scene.id, isAutomation: false));
/// the state to set the scene type must be after the fetch
BlocProvider.of<CreateSceneBloc>(context)
@ -59,12 +56,25 @@ class SceneListview extends StatelessWidget {
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
height: 32,
width: 32,
Assets.assetsIconsLogo,
fit: BoxFit.fill,
),
child: scene.iconInBytes.isNotEmpty
? Image.memory(
scene.iconInBytes,
height: 32,
width: 32,
fit: BoxFit.fill,
errorBuilder: (context, error, stackTrace) => Image.asset(
Assets.assetsIconsLogo,
height: 32,
width: 32,
fit: BoxFit.fill,
),
)
: Image.asset(
Assets.assetsIconsLogo,
height: 32,
width: 32,
fit: BoxFit.fill,
),
),
Expanded(
child: BodyMedium(

View File

@ -0,0 +1,112 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_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 AlarmManagementPage extends StatelessWidget {
const AlarmManagementPage({super.key});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Alarm Settings',
child: BlocProvider(
create: (context) => SosBloc(sosId: ''),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final _bloc = BlocProvider.of<SosBloc>(context);
return state is LoadingNewSate
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 10,
),
const BodyMedium(
text: 'The Alarm Management',
fontWeight: FontWeight.w700,
fontSize: 12,
fontColor: ColorsManager.grayColor,
),
const SizedBox(
height: 5,
),
DefaultContainer(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 50,
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyMedium(
text: 'SOS Alarm',
fontWeight: FontWeight.w400,
fontSize: 15,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: _bloc.enableAlarm,
onChanged: (value) {
context.read<SosBloc>().add(
ToggleEnableAlarmEvent(value));
},
applyTheme: true,
)),
),
),
const Divider(
color: ColorsManager.graysColor,
),
SizedBox(
height: 50,
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyLarge(
text: 'Low Battery Reminder',
fontWeight: FontWeight.w400,
fontSize: 15,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: _bloc.closingReminder,
onChanged: (value) {
context.read<SosBloc>().add(
ToggleClosingReminderEvent(
value));
},
applyTheme: true,
)),
),
),
],
),
),
),
],
);
},
),
));
}
}

View File

@ -0,0 +1,234 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_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/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';
class SosRecordsScreen extends StatefulWidget {
final String sosId;
const SosRecordsScreen({super.key, required this.sosId});
@override
State<SosRecordsScreen> createState() => _SosRecordsScreenState();
}
class _SosRecordsScreenState extends State<SosRecordsScreen> {
int _selectedIndex = 0;
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Records',
child: BlocProvider(
create: (context) =>
SosBloc(sosId: widget.sosId)..add(const ReportLogsInitial()),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final waterSensorBloc = BlocProvider.of<SosBloc>(context);
final Map<String, List<DeviceEvent>> groupedRecords = {};
if (state is LoadingNewSate) {
return const Center(
child: DefaultContainer(
width: 50, height: 50, child: CircularProgressIndicator()),
);
} else if (state is UpdateState) {
for (var record in waterSensorBloc.recordGroups.data!) {
final DateTime eventDateTime =
DateTime.fromMillisecondsSinceEpoch(record.eventTime!);
final String formattedDate =
DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime);
if (groupedRecords.containsKey(formattedDate)) {
groupedRecords[formattedDate]!.add(record);
} else {
groupedRecords[formattedDate] = [record];
}
}
}
return DefaultTabController(
length: 2,
child: 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) {
setState(() {
_selectedIndex = value;
});
},
indicatorColor: Colors.white,
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: 'Record',
style: context.bodySmall.copyWith(
color: _selectedIndex == 0
? Colors.white
: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text(
'Automation Log',
style: context.bodySmall.copyWith(
color: _selectedIndex == 1
? Colors.white
: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
],
),
),
Expanded(
child: TabBarView(
physics: const NeverScrollableScrollPhysics(),
children: [
groupedRecords.isEmpty
? Center(
child: SvgPicture.asset(
Assets.emptyLog,
fit: BoxFit.fill,
),
)
: 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.all(16.0),
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: [
ListTile(
leading: SvgPicture.asset(
record.value == 'true'
? Assets
.leakDetectedIcon
: Assets
.leakNormalIcon,
height: 25,
width: 25,
),
title: Text(
record.value == 'true'
? "Leak Detected"
: "Normal",
style: const TextStyle(
fontWeight:
FontWeight.bold,
fontSize: 18,
),
),
subtitle:
Text('$formattedTime'),
),
if (idx !=
recordsForDate.length - 1)
const Divider(
color: ColorsManager
.graysColor,
),
],
);
}).toList(),
],
),
),
],
);
},
),
Container(
height: 10,
width: 20,
child: Center(
child: SvgPicture.asset(
Assets.emptyLog,
fit: BoxFit.fill,
),
),
),
],
),
),
],
),
);
},
),
),
);
}
}

View File

@ -0,0 +1,217 @@
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/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/sos_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_alarm_management_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_records_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_settings.dart';
import 'package:syncrow_app/features/shared_widgets/battery_bar.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 SosScreen extends StatelessWidget {
final DeviceModel? device;
const SosScreen({super.key, this.device});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'SOS',
actions: [
InkWell(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SosSettings(device: device!)),
);
},
child: SvgPicture.asset(Assets.assetsIconsSettings)),
const SizedBox(
width: 10,
)
],
child: BlocProvider(
create: (context) =>
SosBloc(sosId: device?.uuid ?? '')..add(const SosInitial()),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final sensor = BlocProvider.of<SosBloc>(context);
SosModel model =
SosModel(batteryPercentage: 0, sosContactState: 'normal');
if (state is LoadingNewSate) {
model = state.sosSensor;
} else if (state is UpdateState) {
model = state.sensor;
}
return state is SosLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
sensor.add(const SosInitial());
},
child: ListView(
children: [
SizedBox(
height: MediaQuery.sizeOf(context).height * 0.8,
child: Column(
children: [
BatteryBar(
batteryPercentage: model.batteryPercentage,
),
Expanded(
flex: 4,
child: InkWell(
overlayColor: WidgetStateProperty.all(
Colors.transparent),
onTap: () {},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(890),
boxShadow: [
BoxShadow(
color:
Colors.white.withOpacity(0.1),
blurRadius: 24,
offset: const Offset(-5, -5),
blurStyle: BlurStyle.outer,
),
BoxShadow(
color: Colors.black
.withOpacity(0.11),
blurRadius: 25,
offset: const Offset(5, 5),
blurStyle: BlurStyle.outer,
),
BoxShadow(
color: Colors.black
.withOpacity(0.13),
blurRadius: 30,
offset: const Offset(5, 5),
blurStyle: BlurStyle.inner,
),
],
),
child: SvgPicture.asset(
model.sosContactState == 'normal'
? Assets.redSos
: Assets.greenSos,
fit: BoxFit.fill,
),
),
],
),
),
),
Flexible(
child: Row(
children: [
Expanded(
child: DefaultContainer(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
SosRecordsScreen(
sosId: device!.uuid!)),
);
},
child: Column(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 46, maxWidth: 50),
child: SvgPicture.asset(
Assets.doorRecordsIcon),
),
const SizedBox(
height: 15,
),
const Flexible(
child: FittedBox(
child: BodySmall(
text: 'Records',
textAlign: TextAlign.center,
),
),
),
],
),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: DefaultContainer(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
const AlarmManagementPage()),
);
},
child: Column(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 46, maxWidth: 50),
child: SvgPicture.asset(Assets
.doorNotificationSetting),
),
const SizedBox(
height: 15,
),
const Flexible(
child: FittedBox(
child: BodySmall(
text: 'Alarm Settings',
textAlign: TextAlign.center,
),
),
),
],
),
),
),
],
),
)
],
),
),
],
),
);
},
),
),
);
}
}

View File

@ -0,0 +1,227 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class DisconnectDeviceDialog extends StatelessWidget {
final Function()? cancelTab;
final Function()? confirmTab;
const DisconnectDeviceDialog({
super.key,
required this.cancelTab,
required this.confirmTab,
});
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 10,
),
const BodyLarge(
text: 'Disconnect Device',
fontWeight: FontWeight.w700,
fontColor: ColorsManager.red,
fontSize: 16,
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 15),
child: Divider(
color: ColorsManager.textGray,
),
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 20),
child: Column(
children: [
Center(
child: Text(
'This will disconnect your device from this Application')),
],
),
),
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: 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: confirmTab,
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Disconnect',
style: TextStyle(
color: ColorsManager.red,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
)),
))
],
)
],
),
);
}
}
class DisconnectWipeData extends StatelessWidget {
final Function()? cancelTab;
final Function()? confirmTab;
const DisconnectWipeData({
super.key,
required this.cancelTab,
required this.confirmTab,
});
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 10,
),
const BodyLarge(
text: 'Disconnect and Wipe Data',
fontWeight: FontWeight.w700,
fontColor: ColorsManager.red,
fontSize: 16,
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 15),
child: Divider(
color: ColorsManager.textGray,
),
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 20),
child: Column(
children: [
Center(
child: Text(
'This will disconnect your device from this Application and wipe all the data')),
],
),
),
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: 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: confirmTab,
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Disconnect',
style: TextStyle(
color: ColorsManager.red,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
)),
))
],
)
],
),
);
}
}

View File

@ -0,0 +1,151 @@
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/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/question_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/question_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_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class FaqSosPage extends StatelessWidget {
final DeviceModel? device;
const FaqSosPage({super.key, this.device});
@override
Widget build(BuildContext context) {
TextEditingController _searchController = TextEditingController();
return DefaultScaffold(
title: 'FAQ',
child: BlocProvider(
create: (context) =>
SosBloc(sosId: device?.uuid ?? '')..add(const SosInitialQuestion()),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final sensor = BlocProvider.of<SosBloc>(context);
List<QuestionModel> displayedQuestions = [];
if (state is FaqSearchState) {
displayedQuestions = state.filteredFaqQuestions;
} else if (state is FaqLoadedState) {
displayedQuestions = state.filteredFaqQuestions;
}
return state is SosLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
sensor.add(const SosInitial());
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
DefaultContainer(
padding: const EdgeInsets.all(5),
child: TextFormField(
controller: _searchController,
onChanged: (value) {
sensor.add(SearchFaqEvent(value));
},
decoration: InputDecoration(
hintText: 'Enter your questions',
hintStyle: const TextStyle(
color: ColorsManager.textGray,
fontSize: 16,
fontWeight: FontWeight.w400),
suffixIcon: Container(
padding: const EdgeInsets.all(5.0),
margin: const EdgeInsets.all(10.0),
child: SvgPicture.asset(
Assets.searchIcon,
fit: BoxFit.contain,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.04,
),
BodyMedium(
text: _searchController.text.isEmpty
? 'Device Related FAQs'
: '${displayedQuestions.length} Help Topics',
fontWeight: FontWeight.w700,
fontSize: 12,
fontColor: ColorsManager.grayColor,
),
Expanded(
child: DefaultContainer(
child: ListView.builder(
shrinkWrap: true,
itemCount: displayedQuestions.length,
itemBuilder: (context, index) {
final faq = displayedQuestions[index];
return InkWell(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => QuestionPage(
questionModel: faq,
)),
);
},
child: SizedBox(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: BodyMedium(
fontSize: 14,
fontWeight: FontWeight.w400,
text: faq.question,
),
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
),
),
const Divider(
color: ColorsManager.dividerColor,
),
],
),
),
);
},
)),
),
],
),
);
},
),
),
);
}
}

View File

@ -0,0 +1,195 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/model/sos_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/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class LocationSosPage extends StatelessWidget {
final SpaceModel? space;
LocationSosPage({super.key, this.space});
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider(
create: (context) =>
SosBloc(sosId: '')..add(FetchRoomsEvent(unit: space!)),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final sensor = BlocProvider.of<SosBloc>(context);
SosModel model =
SosModel(batteryPercentage: 0, sosContactState: 'normal');
return state is SosLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
)
: DefaultScaffold(
actions: [
BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final bool canSave = state is OptionSelectedState &&
state.hasSelectionChanged;
return InkWell(
onTap: canSave
? () {
context
.read<SosBloc>()
.add(SaveSelectionEvent());
}
: null,
child: BodyMedium(
text: 'Save',
fontWeight: FontWeight.w700,
fontSize: 16,
fontColor: canSave
? ColorsManager.slidingBlueColor
: ColorsManager.primaryTextColor,
),
);
},
),
const SizedBox(width: 20),
],
child: RefreshIndicator(
onRefresh: () async {
sensor.add(const SosInitial());
},
child: ListView(
shrinkWrap: true,
padding: const EdgeInsets.symmetric(vertical: 20),
children: [
const BodyMedium(
text: 'Smart Device Location',
fontWeight: FontWeight.w700,
fontSize: 12,
fontColor: ColorsManager.grayColor,
),
const SizedBox(height: 5),
DefaultContainer(
padding: const EdgeInsets.all(20),
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: sensor.roomsList.length,
itemBuilder: (context, index) {
final room = sensor.roomsList![index];
return Column(
children: [
_buildCheckboxOption(
label: room.name!,
isSelected:
state is OptionSelectedState &&
state.selectedOption == room.name,
onTap: (v) {
context.read<SosBloc>().add(
SelectOptionEvent(
selectedOption: v));
},
),
if (index <
sensor.roomsList.length - 1) ...[
const SizedBox(height: 10),
const Divider(
color: ColorsManager.dividerColor,
),
const SizedBox(height: 10),
],
],
);
},
),
),
],
),
),
);
},
),
),
);
}
Widget _buildCheckboxOption({
required String label,
required bool isSelected,
required 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: isSelected,
onChanged: (bool? value) {
if (value == true) {
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,143 @@
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/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/model/question_model.dart';
import 'package:syncrow_app/features/devices/model/sos_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.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/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class QuestionPage extends StatelessWidget {
final QuestionModel? questionModel;
const QuestionPage({super.key, this.questionModel});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'FAQ',
child: BlocProvider(
create: (context) => SosBloc(sosId: '')..add(const SosInitial()),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final sensor = BlocProvider.of<SosBloc>(context);
SosModel model =
SosModel(batteryPercentage: 0, sosContactState: 'normal');
if (state is LoadingNewSate) {
model = state.sosSensor;
} else if (state is UpdateState) {
model = state.sensor;
}
return state is SosLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
sensor.add(const SosInitial());
},
child: Column(
children: [
DefaultContainer(
padding: EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
BodyLarge(
text: questionModel!.question,
fontSize: 22,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.blackColor,
),
SizedBox(
height: 15,
),
BodyMedium(
text: questionModel!.answer,
fontSize: 14,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.secondaryTextColor,
),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.15,
),
Center(
child: SizedBox(
width: 180,
child: DefaultButton(
backgroundColor: ColorsManager.grayButtonColors,
borderRadius: 50,
onPressed: () {},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
Assets.thumbUp,
fit: BoxFit.fill,
),
SizedBox(
width: 10,
),
BodyMedium(
text: 'Helpful',
fontSize: 12,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.blackColor,
),
],
)),
),
),
SizedBox(
height: 15,
),
Center(
child: SizedBox(
width: 180,
child: DefaultButton(
backgroundColor: ColorsManager.grayButtonColors,
borderRadius: 50,
onPressed: () {},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
Assets.thumbDown,
fit: BoxFit.fill,
),
SizedBox(
width: 10,
),
BodyMedium(
text: 'Not Helpful',
fontSize: 12,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.blackColor,
),
],
)),
),
),
],
));
},
),
),
);
}
}

View File

@ -0,0 +1,100 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/sos_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.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 ShareSosPage extends StatelessWidget {
final DeviceModel? device;
const ShareSosPage({super.key, this.device});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Share Device',
child: BlocProvider(
create: (context) =>
SosBloc(sosId: device?.uuid ?? '')..add(const SosInitial()),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final sensor = BlocProvider.of<SosBloc>(context);
SosModel model =
SosModel(batteryPercentage: 0, sosContactState: 'normal');
if (state is LoadingNewSate) {
model = state.sosSensor;
} else if (state is UpdateState) {
model = state.sensor;
}
return state is SosLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
sensor.add(const SosInitial());
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const BodyLarge(
text: 'Sharing Method Not Supported',
fontSize: 15,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.blackColor,
),
const BodyMedium(
text:
'Currently, you cannot use the specified method to share Bluetooth mesh devices Zigbee devices, infrared devices, Bluetooth Beacon Devices, and certain Bluetooth LE devices with other users.',
fontSize: 14,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.secondaryTextColor,
),
const SizedBox(
height: 10,
),
const BodyLarge(
text: 'Recommended Sharing Method',
fontSize: 15,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.blackColor,
),
const BodyMedium(
text:
'If the recipient is a home member or a reliable user, tap Me > Home Management > Add Member and add the recipient to your home. Then, devices in the home can be shared with the recipient in bulk.',
fontSize: 14,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.secondaryTextColor,
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.15,
),
Center(
child: SizedBox(
width: 250,
child: DefaultButton(
backgroundColor: ColorsManager.blueColor1,
borderRadius: 50,
onPressed: () {},
child: Text('Add Home Member')),
),
)
],
));
},
),
),
);
}
}

View File

@ -0,0 +1,131 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/sos_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/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SosInfoPge extends StatelessWidget {
final DeviceModel? device;
const SosInfoPge({super.key, this.device});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Device Information',
child: BlocProvider(
create: (context) =>
SosBloc(sosId: device?.uuid ?? '')..add(const SosInitial()),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final sensor = BlocProvider.of<SosBloc>(context);
SosModel model =
SosModel(batteryPercentage: 0, sosContactState: 'normal');
if (state is LoadingNewSate) {
model = state.sosSensor;
} else if (state is UpdateState) {
model = state.sensor;
}
return state is SosLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
sensor.add(const SosInitial());
},
child: DefaultContainer(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const BodyLarge(
text: 'Virtual ID',
fontSize: 15,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.blackColor,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BodySmall(
text: 'bf3575d0e0c8b6e0a6hybl',
fontColor: ColorsManager.primaryTextColor,
),
InkWell(
onTap: () {},
child: const Row(
children: [
Icon(
Icons.copy,
color: ColorsManager.blueColor,
),
BodyMedium(
text: 'Copy',
fontColor: ColorsManager.blueColor,
),
],
),
)
],
),
const Divider(
color: ColorsManager.dividerColor,
),
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyLarge(
text: 'MAC',
fontSize: 15,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.blackColor,
),
BodySmall(
text: 'bf3575d0e0c8b6e0a6hybl',
fontColor: ColorsManager.primaryTextColor,
),
],
),
const Divider(
color: ColorsManager.dividerColor,
),
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyLarge(
text: 'Time Zone',
fontSize: 15,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.blackColor,
),
BodySmall(
text: 'Asia/Dubai',
fontColor: ColorsManager.primaryTextColor,
),
],
),
]),
)));
},
),
),
);
}
}

View File

@ -0,0 +1,174 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/sos_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/location_setting.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_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SosProfilePage extends StatelessWidget {
final DeviceModel? device;
const SosProfilePage({super.key, this.device});
@override
Widget build(BuildContext context) {
var spaces = HomeCubit.getInstance().spaces;
return DefaultScaffold(
title: 'Device Settings',
child: BlocProvider(
create: (context) =>
SosBloc(sosId: device?.uuid ?? '')..add(const SosInitial()),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final sensor = BlocProvider.of<SosBloc>(context);
SosModel model =
SosModel(batteryPercentage: 0, sosContactState: 'normal');
if (state is LoadingNewSate) {
model = state.sosSensor;
} else if (state is UpdateState) {
model = state.sensor;
}
return state is SosLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
sensor.add(const SosInitial());
},
child: ListView(
children: [
CircleAvatar(
radius: 60,
backgroundColor: Colors.white,
child: CircleAvatar(
radius: 55,
backgroundColor: Colors.grey,
child: ClipOval(
child: SvgPicture.asset(
Assets.sosProfileIcon,
fit: BoxFit.fill,
),
),
),
),
const SizedBox(
height: 10,
),
SizedBox(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IntrinsicWidth(
child: ConstrainedBox(
constraints:
const BoxConstraints(maxWidth: 200),
child: TextFormField(
maxLength: 30,
style: const TextStyle(
color: ColorsManager.textPrimaryColor,
),
textAlign: TextAlign.center,
focusNode: sensor.focusNode,
controller: sensor.nameController,
enabled: sensor.editName,
onEditingComplete: () {
// sensor.add(SaveNameEvent(context: context));
},
decoration: const InputDecoration(
hintText: "Your Name",
border: InputBorder.none,
fillColor: Colors.white10,
counterText: '',
),
),
),
),
const SizedBox(width: 5),
//editNameSosIcon
InkWell(
onTap: () {
sensor
.add(const ChangeNameEvent(value: true));
},
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 5),
child: SvgPicture.asset(
height: 18,
width: 18,
Assets.editNameSosIcon,
fit: BoxFit.contain,
color: ColorsManager.grayButtonColors,
),
),
),
],
),
),
const SizedBox(height: 20),
const BodyMedium(
text: 'Smart Device Information',
fontWeight: FontWeight.w700,
fontSize: 12,
fontColor: ColorsManager.grayColor,
),
DefaultContainer(
padding: const EdgeInsets.all(20),
child: InkWell(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => LocationSosPage(
space: spaces!.first,
)),
);
},
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
child: Text('Location'),
),
Row(
children: [
SizedBox(
child: BodyMedium(
text: 'Syncroom',
fontColor: ColorsManager.textGray,
),
),
Icon(
Icons.arrow_forward_ios,
size: 15,
color: ColorsManager.textGray,
),
],
)
],
),
),
)
],
),
);
},
),
),
);
}
}

View File

@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SosUpdateNote extends StatelessWidget {
final Function()? cancelTab;
final Function()? confirmTab;
const SosUpdateNote({
super.key,
required this.cancelTab,
required this.confirmTab,
});
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 10,
),
BodyLarge(
text: 'Update Note',
fontWeight: FontWeight.w700,
fontColor: ColorsManager.switchButton.withOpacity(0.6),
fontSize: 16,
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 15),
child: Divider(
color: ColorsManager.textGray,
),
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 20),
child: Column(
children: [
Center(
child: Text(
'This update may take a long time. Make sure that the device is fully charged. The device will be unavailable during the update.',
textAlign: TextAlign.center,
)),
],
),
),
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: cancelTab,
child: const Padding(
padding: const EdgeInsets.only(top: 15, bottom: 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: confirmTab,
child: Padding(
padding: const EdgeInsets.only(top: 15, bottom: 15),
child: Center(
child: Text(
'Start Update',
style: TextStyle(
color:
ColorsManager.switchButton.withOpacity(0.6),
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
)),
))
],
)
],
),
);
}
}

View File

@ -0,0 +1,344 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/sos_update_note.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.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_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SosUpdatePage extends StatelessWidget {
const SosUpdatePage({super.key});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Device Update',
child: BlocProvider(
create: (context) => SosBloc(sosId: '')..add(const SosInitial()),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
return state is SosLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {},
child: Column(
children: [
// SizedBox(
// height: MediaQuery.of(context).size.height * 0.15,
// ),
DefaultContainer(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 50,
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: SizedBox(
width: 200,
child: Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: const BoxDecoration(
color:
ColorsManager.primaryColor,
borderRadius: BorderRadius.all(
Radius.circular(50))),
child: SvgPicture.asset(
Assets.checkUpdateIcon,
fit: BoxFit.fill,
height: 25,
),
),
const SizedBox(
width: 10,
),
InkWell(
onTap: () {},
child: const BodyMedium(
text: 'Automatic Update',
fontWeight: FontWeight.normal,
),
),
],
),
),
trailing: Container(
width: 100,
child: Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
const BodyMedium(
text: 'Off',
fontColor: ColorsManager.textGray,
),
Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: true,
onChanged: (value) {},
applyTheme: true,
),
),
],
),
)),
),
],
),
),
const SizedBox(
height: 10,
),
UpdateSosContainerWithProgressBar(
sosDescription:
'Connectivity Issue Resolved Fixed a bug that caused the SOS button to disconnect from the app intermittently.',
sosVersion: 'SOS v2.0.5',
),
// const UpdatedContainer(
// sosVersion: 'SOS v1.0.13',
// sosDescription: 'SOS is up to date',
// ),
// const NewUpdateContainer(
// sosVersion: 'SOS v2.0.5',
// sosDescription:
// 'Connectivity Issue Resolved Fixed a bug that caused the SOS button to disconnect from the app intermittently.',
// ),
const SizedBox(
height: 15,
),
],
));
},
),
),
);
}
}
class UpdatedContainer extends StatelessWidget {
final String? sosVersion;
final String? sosDescription;
const UpdatedContainer({
this.sosVersion,
this.sosDescription,
super.key,
});
@override
Widget build(BuildContext context) {
return DefaultContainer(
height: MediaQuery.of(context).size.height * 0.35,
child: Padding(
padding: const EdgeInsets.all(25),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SvgPicture.asset(
Assets.emptyUpdateIcon,
fit: BoxFit.fill,
),
BodyMedium(
text: sosVersion!,
fontColor: ColorsManager.primaryTextColor,
),
BodyMedium(
text: sosDescription!,
fontColor: ColorsManager.blackColor,
),
],
),
],
),
),
);
}
}
class NewUpdateContainer extends StatelessWidget {
final String? sosVersion;
final String? sosDescription;
const NewUpdateContainer({
this.sosVersion,
this.sosDescription,
super.key,
});
@override
Widget build(BuildContext context) {
return DefaultContainer(
height: MediaQuery.of(context).size.height * 0.50,
child: Padding(
padding: const EdgeInsets.all(25),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SvgPicture.asset(
Assets.emptyUpdateIcon,
fit: BoxFit.fill,
),
const BodyMedium(
text: 'New Update Available Now!',
fontColor: ColorsManager.blueColor,
),
BodyMedium(
text: sosVersion!,
fontColor: ColorsManager.primaryTextColor,
),
Container(
width: MediaQuery.of(context).size.width * 0.7,
child: BodyMedium(
text: sosDescription!,
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.6,
child: DefaultButton(
borderRadius: 25,
backgroundColor: ColorsManager.blueColor1,
height: 150,
onPressed: () {
showDialog(
context: context,
builder: (context) {
return SosUpdateNote(
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
Navigator.of(context).pop();
},
);
},
);
},
child: const BodyMedium(
text: 'Update Now',
fontColor: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w700,
textAlign: TextAlign.center,
),
),
)
],
),
],
),
),
);
}
}
class UpdateSosContainerWithProgressBar extends StatelessWidget {
final String? sosVersion;
final String? sosDescription;
const UpdateSosContainerWithProgressBar({
this.sosVersion,
this.sosDescription,
super.key,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
DefaultContainer(
height: MediaQuery.of(context).size.height * 0.50,
child: Padding(
padding: const EdgeInsets.all(25),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SvgPicture.asset(
Assets.emptyUpdateIcon,
fit: BoxFit.fill,
),
const BodyMedium(
text: 'New Update Available Now!',
fontColor: ColorsManager.blueColor,
),
BodyMedium(
text: sosVersion!,
fontColor: ColorsManager.primaryTextColor,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.7,
child: BodyMedium(
text: sosDescription!,
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
LinearPercentIndicator(
barRadius: Radius.circular(10),
width: 170.0,
animation: true,
animationDuration: 1000,
lineHeight: 5.0,
percent: 0.2,
linearStrokeCap: LinearStrokeCap.butt,
progressColor: ColorsManager.blueColor1,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.7,
child: const BodyMedium(
text: 'Downloading Update please be patient',
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
],
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.7,
child: const BodyMedium(
text:
'Please keep the power of the device connected during the upgrade process.',
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
);
}
}

View File

@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class UpdateInfoDialog extends StatelessWidget {
final Function()? cancelTab;
final Function()? confirmTab;
const UpdateInfoDialog({
super.key,
required this.cancelTab,
required this.confirmTab,
});
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 10,
),
BodyLarge(
text: 'Update Available',
fontWeight: FontWeight.w700,
fontColor: ColorsManager.switchButton.withOpacity(0.6),
fontSize: 16,
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 15),
child: Divider(
color: ColorsManager.textGray,
),
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 20),
child: Column(
children: [
Center(
child: Text(
'An update is available for your device. Version 2.1.0 includes new features and important fixes to enhance performance and security.',
textAlign: TextAlign.center,
)),
],
),
),
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: cancelTab,
child: const Padding(
padding: const EdgeInsets.only(top: 15, bottom: 15),
child: Center(
child: Text(
'Remind me later',
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: confirmTab,
child: Padding(
padding: const EdgeInsets.only(top: 15, bottom: 15),
child: Center(
child: Text(
'Update Now',
style: TextStyle(
color:
ColorsManager.switchButton.withOpacity(0.6),
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
)),
))
],
)
],
),
);
}
}

View File

@ -0,0 +1,484 @@
import 'package:flutter/cupertino.dart';
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/sos_bloc/sos_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/sos_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/delete_dialog.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/sos_profile_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/faq_sos_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/share_sos_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/sos_info_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/sos_update_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/update_dialog_sos.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_medium.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';
class SosSettings extends StatelessWidget {
final DeviceModel? device;
const SosSettings({super.key, this.device});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Device Settings',
child: BlocProvider(
create: (context) =>
SosBloc(sosId: device?.uuid ?? '')..add(const SosInitial()),
child: BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
final sensor = BlocProvider.of<SosBloc>(context);
SosModel model =
SosModel(batteryPercentage: 0, sosContactState: 'normal');
if (state is LoadingNewSate) {
model = state.sosSensor;
} else if (state is UpdateState) {
model = state.sensor;
}
return state is SosLoadingState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
sensor.add(const SosInitial());
},
child: ListView(
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 10,
),
child: InkWell(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const SosProfilePage(),
),
);
},
child: Stack(
children: [
const Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
SizedBox(height: 20),
DefaultContainer(
borderRadius:
BorderRadius.all(Radius.circular(30)),
child: Padding(
padding: EdgeInsets.all(10.0),
child: Padding(
padding: EdgeInsets.only(left: 90),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
BodyMedium(
text: 'SOS',
fontWeight: FontWeight.bold,
),
SizedBox(
height: 5,
),
BodySmall(
text: "Room: Syncrow"),
],
),
Icon(
Icons.edit_outlined,
color: ColorsManager.grayColor,
),
],
),
),
),
),
],
),
Positioned(
top: 0,
left: 20,
child: CircleAvatar(
radius: 40,
backgroundColor: Colors.white,
child: CircleAvatar(
radius: 40,
backgroundColor: Colors.grey,
child: ClipOval(
child: SvgPicture.asset(
Assets.sosProfileIcon,
fit: BoxFit.fill,
),
),
),
),
),
],
),
),
),
const SizedBox(height: 20),
const BodyMedium(
text: 'Device Management',
fontWeight: FontWeight.w700,
fontSize: 12,
fontColor: ColorsManager.grayColor,
),
DefaultContainer(
child: SettingWidget(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const SosInfoPge()),
);
},
text: 'Device Information',
icon: Assets.infoIcon,
),
),
const SizedBox(height: 20),
const BodyMedium(
text: 'Device Offline Notification',
fontWeight: FontWeight.w700,
fontSize: 12,
fontColor: ColorsManager.grayColor,
),
DefaultContainer(
child: Column(
children: [
SettingWidget(
onChanged: (p0) {},
isNotification: true,
onTap: () {},
text: 'Offline Notification',
icon: Assets.notificationIcon,
),
],
),
),
const SizedBox(height: 20),
const BodyMedium(
text: 'Others',
fontWeight: FontWeight.w700,
fontSize: 12,
fontColor: ColorsManager.grayColor,
),
const SizedBox(height: 5),
DefaultContainer(
child: Column(
children: [
SettingWidget(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
ShareSosPage(device: device!)),
);
},
text: 'Share Device',
icon: Assets.shareIcon,
),
const Divider(
color: ColorsManager.dividerColor,
),
SettingWidget(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
FaqSosPage(device: device!)),
);
},
text: 'Device FAQ',
icon: Assets.faqIcon,
),
const Divider(
color: ColorsManager.dividerColor,
),
SettingWidget(
onTapUpdate: () {
showDialog(
context: context,
builder: (context) {
return UpdateInfoDialog(
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
// context
// .read<
// CreateSceneBloc>()
// .add(DeleteSceneEvent(
// sceneId: sceneId,
// unitUuid: HomeCubit
// .getInstance()
// .selectedSpace!
// .id!,
// ));
Navigator.of(context).pop();
},
);
},
);
},
isUpdate: true,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
const SosUpdatePage()),
);
},
text: 'Device Update',
icon: Assets.updateIcon,
),
],
),
),
const SizedBox(height: 20),
InkWell(
onTap: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const BodyMedium(
text: 'Remove Device',
fontWeight: FontWeight.w700,
fontSize: 16,
fontColor: ColorsManager.red,
),
const SizedBox(height: 10),
const SizedBox(
width: 250,
child: Divider(
color: ColorsManager.dividerColor,
),
),
const SizedBox(height: 10),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
showDialog(
context: context,
builder: (context) {
return DisconnectDeviceDialog(
cancelTab: () {
Navigator.of(context)
.pop();
},
confirmTab: () {
// context
// .read<
// CreateSceneBloc>()
// .add(DeleteSceneEvent(
// sceneId: sceneId,
// unitUuid: HomeCubit
// .getInstance()
// .selectedSpace!
// .id!,
// ));
Navigator.of(context)
.pop();
},
);
},
);
},
child: const BodyMedium(
text: 'Disconnect Device',
fontWeight: FontWeight.w400,
fontSize: 15,
fontColor: ColorsManager
.textPrimaryColor,
),
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
)
],
),
const SizedBox(height: 20),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
showDialog(
context: context,
builder: (context) {
return DisconnectWipeData(
cancelTab: () {
Navigator.of(context)
.pop();
},
confirmTab: () {
// context
// .read<
// CreateSceneBloc>()
// .add(DeleteSceneEvent(
// sceneId: sceneId,
// unitUuid: HomeCubit
// .getInstance()
// .selectedSpace!
// .id!,
// ));
Navigator.of(context)
.pop();
},
);
},
);
},
child: const BodyMedium(
text:
'Disconnect Device and Wipe Data',
fontWeight: FontWeight.w400,
fontSize: 15,
fontColor: ColorsManager
.textPrimaryColor,
),
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
)
],
),
],
),
);
},
);
},
child: const Center(
child: BodyMedium(
text: 'Remove Device',
fontWeight: FontWeight.w400,
fontSize: 15,
fontColor: ColorsManager.red,
),
),
),
],
),
);
},
),
),
);
}
}
class SettingWidget extends StatelessWidget {
final String? text;
final bool? isUpdate;
final bool? isNotification;
final String? icon;
final Function()? onTap;
final Function()? onTapUpdate;
final Function(bool)? onChanged;
const SettingWidget(
{super.key,
this.text,
this.icon,
this.onTap,
this.isUpdate,
this.onChanged,
this.isNotification = false,
this.onTapUpdate});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.all(8),
decoration: const BoxDecoration(
color: ColorsManager.primaryColor,
borderRadius: BorderRadius.all(Radius.circular(20))),
child: SvgPicture.asset(
icon!,
fit: BoxFit.none,
height: 30,
),
),
),
const SizedBox(
width: 8,
),
Expanded(
flex: isUpdate == true ? 5 : 10,
child: BodyMedium(
text: text!,
fontSize: 15,
fontWeight: FontWeight.w400,
)),
],
),
),
isUpdate == true
? InkWell(
onTap: onTapUpdate,
child: const BodyMedium(
text: '1 Update Available',
fontSize: 13,
fontWeight: FontWeight.w400,
fontColor: ColorsManager.blueColor,
),
)
: SizedBox(),
isNotification == false
? const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.graysColor,
size: 20,
)
: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: true,
onChanged: onChanged,
applyTheme: true,
),
),
],
),
);
}
}

View File

@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/devices/model/smart_door_model.dart';
import 'package:syncrow_app/generated/assets.dart';
class SosStatusBar extends StatelessWidget {
const SosStatusBar({
required this.smartDoorModel,
super.key,
});
final SmartDoorModel smartDoorModel;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(Assets.assetsIconsWifi),
Transform.rotate(
angle: 1.5708, // 90 degrees in radians (π/2 or 1.5708)
child: Icon(
_getBatteryIcon(smartDoorModel.residualElectricity),
color: _getBatteryColor(smartDoorModel.residualElectricity),
size: 30,
),
),
],
);
}
IconData _getBatteryIcon(int batteryLevel) {
// if (batteryState == BatteryState.charging) {
// return Icons.battery_charging_full;
// } else
if (batteryLevel >= 80) {
return Icons.battery_full;
} else if (batteryLevel >= 60) {
return Icons.battery_4_bar;
} else if (batteryLevel >= 40) {
return Icons.battery_3_bar;
} else if (batteryLevel >= 20) {
return Icons.battery_2_bar;
} else {
return Icons.battery_alert;
}
}
Color _getBatteryColor(int batteryLevel) {
if (batteryLevel >= 80) {
return Colors.green;
} else if (batteryLevel >= 40) {
return Colors.yellowAccent;
} else {
return Colors.red;
}
}
}

View File

@ -35,7 +35,7 @@ class WizardPage extends StatelessWidget {
return StatefulBuilder(
builder: (context, setState) {
return ListView(
return Column(
children: [
if (groupsList.isNotEmpty)
TextFormField(
@ -64,129 +64,170 @@ class WizardPage extends StatelessWidget {
),
),
),
GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 1.5,
),
padding: const EdgeInsets.only(top: 10),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: _filteredGroups.length,
itemBuilder: (_, index) {
return GestureDetector(
onTap: () {
if (_filteredGroups[index].name == 'AC') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const ACsView()));
}
if (_filteredGroups[index].name == '3G') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const ThreeGangWizard()));
}
if (_filteredGroups[index].name == '2G') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const TwoGangWizard()));
}
if (_filteredGroups[index].name == '1G') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const OneGangWizard()));
}
if (_filteredGroups[index].name == 'WH') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const WHWizard()));
}
if (_filteredGroups[index].name == '1GT') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const OneTouchWizard()));
}
if (_filteredGroups[index].name == '2GT') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const TwoTouchWizard()));
}
if (_filteredGroups[index].name == '3GT') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const ThreeTouchWizard()));
}
if (_filteredGroups[index].name == 'GD') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const GarageWizard()));
}
if (_filteredGroups[index].name == 'CUR') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const CurtainsWizard()));
}
},
child: DefaultContainer(
padding: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
const SizedBox(
height: 10,
),
_filteredGroups.isNotEmpty
? Expanded(
child: ListView(
shrinkWrap: true,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(
_filteredGroups[index].icon!,
fit: BoxFit.contain,
),
],
),
FittedBox(
fit: BoxFit.scaleDown,
child: BodyLarge(
text: _filteredGroups[index].name!,
style: context.bodyLarge.copyWith(
fontWeight: FontWeight.bold,
height: 0,
fontSize: 20,
color: Colors.grey,
),
GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 1.5,
),
),
padding: const EdgeInsets.only(top: 10),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: _filteredGroups.length,
itemBuilder: (_, index) {
return GestureDetector(
onTap: () {
if (_filteredGroups[index].name == 'AC') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const ACsView()));
}
if (_filteredGroups[index].name == '3G') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const ThreeGangWizard()));
}
if (_filteredGroups[index].name == '2G') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const TwoGangWizard()));
}
if (_filteredGroups[index].name == '1G') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const OneGangWizard()));
}
if (_filteredGroups[index].name == 'WH') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const WHWizard()));
}
if (_filteredGroups[index].name == '1GT') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const OneTouchWizard()));
}
if (_filteredGroups[index].name == '2GT') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const TwoTouchWizard()));
}
if (_filteredGroups[index].name == '3GT') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const ThreeTouchWizard()));
}
if (_filteredGroups[index].name == 'GD') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const GarageWizard()));
}
if (_filteredGroups[index].name == 'CUR') {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
const CurtainsWizard()));
}
},
child: DefaultContainer(
padding: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(
_filteredGroups[index].icon!,
fit: BoxFit.contain,
),
],
),
FittedBox(
fit: BoxFit.scaleDown,
child: BodyLarge(
text: _filteredGroups[index].name!,
style: context.bodyLarge.copyWith(
fontWeight: FontWeight.bold,
height: 0,
fontSize: 20,
color: Colors.grey,
),
),
),
],
),
),
);
},
)
],
),
)
: const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Text(
'No Results Found',
style: TextStyle(
color: ColorsManager.grayColor,
fontSize: 14,
fontWeight: FontWeight.w400),
)),
],
),
),
);
},
),
],
);
},

View File

@ -61,7 +61,9 @@ class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
var storage = const FlutterSecureStorage();
var userId = await storage.read(key: UserModel.userUuidKey) ?? '';
Map<String, String> communityBody = {'communityName': event.communityName};
Map<String, String> communityBody = {
'communityName': event.communityName
};
final response = await HomeCreation.createCommunity(communityBody);
if (response['data']['uuid'] != '') {
// final result =
@ -75,15 +77,22 @@ class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
if (buildingId.isNotEmpty) {
final floorId = await _createFloor(
floorName: event.floorName, buildingId: buildingId, userId: userId);
floorName: event.floorName,
buildingId: buildingId,
userId: userId);
if (floorId.isNotEmpty) {
final unitId =
await _createUnit(unitName: event.unitName, floorId: floorId, userId: userId);
final unitId = await _createUnit(
unitName: event.unitName, floorId: floorId, userId: userId);
if (unitId.isNotEmpty && rooms.isNotEmpty) {
rooms.forEach((room) async {
await _createNewRoom(roomName: room, unitId: unitId, userId: userId);
await _createNewRoom(
roomName: room,
unitId: unitId,
userId: userId,
communityId: response['data']['uuid'],
);
});
}
}
@ -99,7 +108,8 @@ class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
}
}
Future<bool> _assignToCommunity({required String communityId, required String userId}) async {
Future<bool> _assignToCommunity(
{required String communityId, required String userId}) async {
try {
Map<String, String> body = {
'communityUuid': communityId,
@ -114,9 +124,14 @@ Future<bool> _assignToCommunity({required String communityId, required String us
}
Future<String> _createBuilding(
{required String buildingName, required String communityId, required String userId}) async {
{required String buildingName,
required String communityId,
required String userId}) async {
try {
Map<String, String> body = {'buildingName': buildingName, 'communityUuid': communityId};
Map<String, String> body = {
'buildingName': buildingName,
'communityUuid': communityId
};
final response = await HomeCreation.createBuilding(body);
// if (response['data']['uuid'] != '') {
// final result = await _assignToBuilding(buildingId: response['data']['uuid'], userId: userId);
@ -130,7 +145,8 @@ Future<String> _createBuilding(
}
}
Future<bool> _assignToBuilding({required String buildingId, required String userId}) async {
Future<bool> _assignToBuilding(
{required String buildingId, required String userId}) async {
try {
Map<String, String> body = {
'buildingUuid': buildingId,
@ -145,9 +161,14 @@ Future<bool> _assignToBuilding({required String buildingId, required String user
}
Future<String> _createFloor(
{required String floorName, required String buildingId, required String userId}) async {
{required String floorName,
required String buildingId,
required String userId}) async {
try {
Map<String, String> body = {'floorName': floorName, 'buildingUuid': buildingId};
Map<String, String> body = {
'floorName': floorName,
'buildingUuid': buildingId
};
final response = await HomeCreation.createFloor(body);
// if (response['data']['uuid'] != '') {
// final result = await _assignToFloor(buildingId: response['data']['uuid'], userId: userId);
@ -161,7 +182,8 @@ Future<String> _createFloor(
}
}
Future<bool> _assignToFloor({required String buildingId, required String userId}) async {
Future<bool> _assignToFloor(
{required String buildingId, required String userId}) async {
try {
Map<String, String> body = {
'floorUuid': buildingId,
@ -176,12 +198,15 @@ Future<bool> _assignToFloor({required String buildingId, required String userId}
}
Future<String> _createUnit(
{required String unitName, required String floorId, required String userId}) async {
{required String unitName,
required String floorId,
required String userId}) async {
try {
Map<String, String> body = {'unitName': unitName, 'floorUuid': floorId};
final response = await HomeCreation.createUnit(body);
if (response['data']['uuid'] != '') {
final result = await _assignToUnit(unitId: response['data']['uuid'], userId: userId);
final result =
await _assignToUnit(unitId: response['data']['uuid'], userId: userId);
return result ? response['data']['uuid'] : '';
} else {
@ -192,7 +217,8 @@ Future<String> _createUnit(
}
}
Future<bool> _assignToUnit({required String unitId, required String userId}) async {
Future<bool> _assignToUnit(
{required String unitId, required String userId}) async {
try {
Map<String, String> body = {
'unitUuid': unitId,
@ -207,10 +233,14 @@ Future<bool> _assignToUnit({required String unitId, required String userId}) asy
}
Future<String> _createNewRoom(
{required String roomName, required String unitId, required String userId}) async {
{required String roomName,
required String unitId,
required String userId,
required String communityId}) async {
try {
Map<String, String> body = {'roomName': roomName, 'unitUuid': unitId};
final response = await HomeCreation.createRoom(body);
Map<String, String> body = {'subspaceName': roomName};
final response = await HomeCreation.createRoom(
communityId: communityId, spaceId: unitId, body: body);
// if (response['data']['uuid'] != '') {
// final result = await _assignToRoom(roomId: response['data']['uuid'], userId: userId);
@ -223,7 +253,8 @@ Future<String> _createNewRoom(
}
}
Future<bool> _assignToRoom({required String roomId, required String userId}) async {
Future<bool> _assignToRoom(
{required String roomId, required String userId}) async {
try {
Map<String, String> body = {
'roomUuid': roomId,

View File

@ -17,12 +17,15 @@ class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
on<FetchDevicesByRoomIdEvent>(_fetchDevicesByRoomId);
on<AssignRoomEvent>(_assignDevice);
on<AddNewRoom>(_addNewRoom);
on<UnassignRoomEvent>(_unassignDevice);
}
void _fetchRoomsAndDevices(FetchRoomsEvent event, Emitter<ManageUnitState> emit) async {
void _fetchRoomsAndDevices(
FetchRoomsEvent event, Emitter<ManageUnitState> emit) async {
try {
emit(LoadingState());
final roomsList = await SpacesAPI.getRoomsBySpaceId(event.unitId);
final roomsList = await SpacesAPI.getSubSpaceBySpaceId(
event.unit.community.uuid, event.unit.id);
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
} catch (e) {
emit(const ErrorState(message: 'Something went wrong'));
@ -30,11 +33,15 @@ class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
}
}
void _fetchDevicesByRoomId(FetchDevicesByRoomIdEvent event, Emitter<ManageUnitState> emit) async {
void _fetchDevicesByRoomId(
FetchDevicesByRoomIdEvent event, Emitter<ManageUnitState> emit) async {
try {
Map<String, bool> roomDevicesId = {};
emit(LoadingState());
final devicesList = await DevicesAPI.getDevicesByRoomId(event.roomId);
final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id,
roomId: event.roomId);
allDevices = await HomeManagementAPI.fetchDevicesByUserId();
List<String> allDevicesIds = [];
@ -61,13 +68,18 @@ class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
}
}
void _assignDevice(AssignRoomEvent event, Emitter<ManageUnitState> emit) async {
void _assignDevice(
AssignRoomEvent event, Emitter<ManageUnitState> emit) async {
try {
Map<String, bool> roomDevicesId = {};
emit(LoadingState());
Map<String, String> body = {"deviceUuid": event.deviceId, "roomUuid": event.roomId};
await HomeManagementAPI.assignDeviceToRoom(body);
final devicesList = await DevicesAPI.getDevicesByRoomId(event.roomId);
await HomeManagementAPI.assignDeviceToRoom(
event.unit.community.uuid, event.unit.id, event.roomId, event.deviceId);
final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id,
roomId: event.roomId);
List<String> allDevicesIds = [];
@ -93,13 +105,56 @@ class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
}
}
void _unassignDevice(
UnassignRoomEvent event, Emitter<ManageUnitState> emit) async {
try {
Map<String, bool> roomDevicesId = {};
emit(LoadingState());
await HomeManagementAPI.unAssignDeviceToRoom(
event.unit.community.uuid, event.unit.id, event.roomId, event.deviceId);
final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id,
roomId: event.roomId);
List<String> allDevicesIds = [];
allDevices.forEach((element) {
allDevicesIds.add(element.uuid!);
});
devicesList.forEach((e) {
if (allDevicesIds.contains(e.uuid!)) {
roomDevicesId[e.uuid!] = true;
} else {
roomDevicesId[e.uuid!] = false;
}
});
emit(FetchDeviceByRoomIdState(
roomDevices: devicesList,
allDevices: allDevices,
roomDevicesId: roomDevicesId,
roomId: event.roomId));
} catch (e) {
emit(const ErrorState(message: 'Something went wrong'));
return;
}
}
_addNewRoom(AddNewRoom event, Emitter<ManageUnitState> emit) async {
Map<String, String> body = {'roomName': event.roomName, 'unitUuid': event.unitId};
Map<String, String> body = {'subspaceName': event.roomName};
try {
emit(LoadingState());
final response = await HomeCreation.createRoom(body);
final response = await HomeCreation.createRoom(
communityId: event.unit.community.uuid,
spaceId: event.unit.id,
body: body);
if (response['data']['uuid'] != '') {
final roomsList = await SpacesAPI.getRoomsBySpaceId(event.unitId);
final roomsList = await SpacesAPI.getSubSpaceBySpaceId(
event.unit.community.uuid, event.unit.id);
allDevices = await HomeManagementAPI.fetchDevicesByUserId();
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
await HomeCubit.getInstance().fetchUnitsByUserId();

View File

@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
abstract class ManageUnitEvent extends Equatable {
const ManageUnitEvent();
@ -12,39 +13,54 @@ class InitialEvent extends ManageUnitEvent {}
class LoadingEvent extends ManageUnitEvent {}
class FetchRoomsEvent extends ManageUnitEvent {
final String unitId;
final SpaceModel unit;
const FetchRoomsEvent({required this.unitId});
const FetchRoomsEvent({required this.unit});
@override
List<Object> get props => [unitId];
List<Object> get props => [unit];
}
class FetchDevicesByRoomIdEvent extends ManageUnitEvent {
final String roomId;
final SpaceModel unit;
const FetchDevicesByRoomIdEvent({required this.roomId});
const FetchDevicesByRoomIdEvent({required this.roomId, required this.unit});
@override
List<Object> get props => [roomId];
List<Object> get props => [roomId, unit];
}
class AddNewRoom extends ManageUnitEvent {
final String roomName;
final String unitId;
final SpaceModel unit;
const AddNewRoom({required this.roomName, required this.unitId});
const AddNewRoom({required this.roomName, required this.unit});
@override
List<Object> get props => [roomName, unitId];
List<Object> get props => [roomName, unit];
}
class AssignRoomEvent extends ManageUnitEvent {
final String roomId;
final String deviceId;
final SpaceModel unit;
const AssignRoomEvent({required this.roomId, required this.deviceId});
const AssignRoomEvent(
{required this.roomId, required this.deviceId, required this.unit});
@override
List<Object> get props => [roomId];
List<Object> get props => [roomId, unit];
}
class UnassignRoomEvent extends ManageUnitEvent {
final String roomId;
final String deviceId;
final SpaceModel unit;
const UnassignRoomEvent(
{required this.roomId, required this.deviceId, required this.unit});
@override
List<Object> get props => [roomId, unit];
}

View File

@ -1,6 +1,6 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
abstract class ManageUnitState extends Equatable {
const ManageUnitState();
@ -14,7 +14,7 @@ class InitialState extends ManageUnitState {}
class LoadingState extends ManageUnitState {}
class FetchRoomsState extends ManageUnitState {
final List<RoomModel> roomsList;
final List<SubSpaceModel> roomsList;
final List<DeviceModel> devicesList;
const FetchRoomsState({required this.devicesList, required this.roomsList});

View File

@ -44,7 +44,8 @@ class JoinHomeView extends StatelessWidget {
controller: textEditingController,
decoration: InputDecoration(
hintText: 'Invitatoin code',
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
hintStyle:
context.bodyMedium.copyWith(color: Colors.grey),
border: InputBorder.none,
),
),
@ -52,10 +53,12 @@ class JoinHomeView extends StatelessWidget {
IconButton(
onPressed: () async {
if (textEditingController.text.isEmpty) {
CustomSnackBar.displaySnackBar('Please enter the invitation code');
CustomSnackBar.displaySnackBar(
'Please enter the invitation code');
return;
}
if (await HomeCubit.getInstance().joinAUnit(textEditingController.text)) {
if (await HomeCubit.getInstance()
.joinAUnit(textEditingController.text)) {
CustomSnackBar.displaySnackBar('Done successfully');
Navigator.of(context).pop();
} else {

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_bloc.dart';
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_event.dart';
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_state.dart';
@ -11,16 +12,24 @@ import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class AssignDeviceView extends StatelessWidget {
final String unitId;
final String roomId;
const AssignDeviceView({super.key, required this.unitId, required this.roomId});
final SpaceModel unit;
const AssignDeviceView(
{super.key,
required this.unitId,
required this.roomId,
required this.unit});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => ManageUnitBloc()..add(FetchDevicesByRoomIdEvent(roomId: roomId)),
child: BlocConsumer<ManageUnitBloc, ManageUnitState>(listener: (context, state) {
create: (context) => ManageUnitBloc()
..add(FetchDevicesByRoomIdEvent(roomId: roomId, unit: unit)),
child: BlocConsumer<ManageUnitBloc, ManageUnitState>(
listener: (context, state) {
if (state is FetchDeviceByRoomIdState) {
if (state.allDevices.isEmpty) {
CustomSnackBar.displaySnackBar('You do not have the permission to assign devices');
CustomSnackBar.displaySnackBar(
'You do not have the permission to assign devices');
Navigator.of(context).pop();
}
}
@ -34,7 +43,8 @@ class AssignDeviceView extends StatelessWidget {
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
@ -52,11 +62,14 @@ class AssignDeviceView extends StatelessWidget {
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(
state.allDevices[index].icon!,
@ -64,19 +77,42 @@ class AssignDeviceView extends StatelessWidget {
),
GestureDetector(
onTap: () {
if (state.roomDevicesId[
state.allDevices[index].uuid!] ??
false == false) {
BlocProvider.of<ManageUnitBloc>(context).add(
AssignRoomEvent(
deviceId:
state.allDevices[index].uuid ?? '',
bool isAssigned =
state.roomDevicesId[state
.allDevices[index]
.uuid!] ??
false;
if (isAssigned) {
BlocProvider.of<
ManageUnitBloc>(
context)
.add(UnassignRoomEvent(
deviceId: state
.allDevices[
index]
.uuid ??
'',
unit: unit,
roomId: roomId));
} else {
// Tick (assign) the device
BlocProvider.of<
ManageUnitBloc>(
context)
.add(AssignRoomEvent(
deviceId: state
.allDevices[
index]
.uuid ??
'',
unit: unit,
roomId: roomId));
}
},
child: SvgPicture.asset(
state.roomDevicesId[
state.allDevices[index].uuid!] ??
state.roomDevicesId[state
.allDevices[index]
.uuid!] ??
false
? Assets.blueCheckboxIcon
: Assets.emptyCheckboxIcon,

View File

@ -60,7 +60,7 @@ class HomeSettingsView extends StatelessWidget {
onTap: () {
Navigator.of(context).push(CustomPageRoute(
builder: (context) => RoomsView(
unitId: space?.id ?? '',
unit: space!,
)));
},
child: Container(
@ -112,7 +112,7 @@ class HomeSettingsView extends StatelessWidget {
padding: const EdgeInsets.only(bottom: 10),
child: GestureDetector(
onTap: () async {
await HomeCubit.getInstance().generateInvitation(space?.id ?? '');
await HomeCubit.getInstance().generateInvitation(space!);
},
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,

View File

@ -44,8 +44,7 @@ class ManageHomeView extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyMedium(
text: StringHelpers.toTitleCase(spaces[index].name ?? "")),
BodyMedium(text: StringHelpers.toTitleCase(spaces[index].name)),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
@ -75,8 +74,7 @@ class ManageHomeView extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyMedium(
text: HomeCubit.getInstance().spaces![index].name ?? ""),
BodyMedium(text: HomeCubit.getInstance().spaces![index].name),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_bloc.dart';
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_event.dart';
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_state.dart';
@ -11,14 +12,14 @@ import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class RoomsView extends StatelessWidget {
final String unitId;
const RoomsView({super.key, required this.unitId});
final SpaceModel unit;
const RoomsView({super.key, required this.unit});
@override
Widget build(BuildContext context) {
TextEditingController textEditingController = TextEditingController();
return BlocProvider(
create: (context) => ManageUnitBloc()..add(FetchRoomsEvent(unitId: unitId)),
create: (context) => ManageUnitBloc()..add(FetchRoomsEvent(unit:unit )),
child: BlocConsumer<ManageUnitBloc, ManageUnitState>(
listener: (context, state) {},
builder: (context, state) {
@ -62,7 +63,8 @@ class RoomsView extends StatelessWidget {
MaterialPageRoute(
builder: (context) => AssignDeviceView(
roomId: state.roomsList[index].id ?? '',
unitId: unitId,
unitId: unit.id,
unit: unit,
)),
);
},
@ -100,14 +102,14 @@ class RoomsView extends StatelessWidget {
BlocProvider.of<ManageUnitBloc>(context).add(
AddNewRoom(
roomName: textEditingController.text,
unitId: unitId));
unit: unit));
textEditingController.clear();
},
child: const Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
BodyMedium(
text: 'Add Space',
text: 'Add Room',
fontColor: ColorsManager.primaryColor,
),
],

View File

@ -1,5 +1,4 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
@ -10,6 +9,7 @@ import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/helper/scene_operations_data_helper.dart';
import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/icon_model.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/services/api/scene_api.dart';
@ -36,6 +36,10 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
on<SelectConditionEvent>(_selectConditionRule);
on<SceneTypeEvent>(_sceneTypeEvent);
on<EffectiveTimePeriodEvent>(_onEffectiveTimeEvent);
on<SceneIconEvent>(_fetchIconScene);
on<IconSelected>(_iconSelected);
on<ShowOnDeviceClicked>(_showInDeviceClicked);
on<ClearTabToRunSetting>(_clearTabToRunSetting);
}
CreateSceneEnum sceneType = CreateSceneEnum.none;
@ -52,8 +56,12 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
final Map<String, String> automationComparatorValues = {};
String conditionRule = 'or';
EffectiveTime? effectiveTime;
List<IconModel> iconModelList = [];
String selectedIcon = '';
bool showInDeviceScreen = false;
FutureOr<void> _onAddSceneTask(AddTaskEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _onAddSceneTask(
AddTaskEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
if (event.isAutomation == true) {
final copyList = List<SceneStaticFunction>.from(automationTempTasksList);
@ -88,7 +96,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
void addToTempTaskList(TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
void addToTempTaskList(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
bool updated = false;
@ -173,7 +182,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
void addToTempAutomationTaskList(TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
void addToTempAutomationTaskList(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
bool updated = false;
for (var element in automationTempTasksList) {
@ -195,8 +205,10 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
],
comparator: automationComparatorValues[element.code],
);
automationTempTasksList[automationTempTasksList.indexOf(element)] = updatedElement;
automationSelectedValues[updatedElement.code] = event.deviceControlModel.value;
automationTempTasksList[automationTempTasksList.indexOf(element)] =
updatedElement;
automationSelectedValues[updatedElement.code] =
event.deviceControlModel.value;
updated = true;
break;
}
@ -216,10 +228,12 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
icon: '',
),
],
comparator: automationComparatorValues[event.deviceControlModel.code] ?? '==',
comparator:
automationComparatorValues[event.deviceControlModel.code] ?? '==',
);
automationTempTasksList.add(newElement);
automationSelectedValues[newElement.code] = event.deviceControlModel.value;
automationSelectedValues[newElement.code] =
event.deviceControlModel.value;
}
emit(AddSceneTask(
tasksList: tasksList,
@ -228,7 +242,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
FutureOr<void> _selectedValue(SelectedValueEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _selectedValue(
SelectedValueEvent event, Emitter<CreateSceneState> emit) {
if (event.isAutomation == true) {
automationSelectedValues[event.code] = event.value;
automationComparatorValues[event.code] = event.comparator ?? '==';
@ -265,7 +280,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
FutureOr<void> _removeTaskById(RemoveTaskByIdEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _removeTaskById(
RemoveTaskByIdEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
if (event.isAutomation == true) {
for (var element in automationTasksList) {
@ -338,7 +354,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
: await SceneApi.createScene(event.createSceneModel!);
} else if (event.createAutomationModel != null) {
response = event.updateScene
? await SceneApi.updateAutomation(event.createAutomationModel!, event.sceneId)
? await SceneApi.updateAutomation(
event.createAutomationModel!, event.sceneId)
: await SceneApi.createAutomation(event.createAutomationModel!);
}
@ -350,12 +367,16 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
automationTempTasksList.clear();
automationSelectedValues.clear();
automationComparatorValues.clear();
effectiveTime = EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
selectedIcon = '';
showInDeviceScreen = false;
effectiveTime =
EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
sceneType = CreateSceneEnum.none;
conditionRule = 'or';
emit(const CreateSceneWithTasks(success: true));
CustomSnackBar.greenSnackBar(
event.updateScene ? 'Scene updated successfully' : 'Scene created successfully');
CustomSnackBar.greenSnackBar(event.updateScene
? 'Scene updated successfully'
: 'Scene created successfully');
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
}
@ -369,7 +390,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
FutureOr<void> _clearTaskList(ClearTaskListEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _clearTaskList(
ClearTaskListEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
automationTasksList.clear();
tasksList.clear();
@ -380,6 +402,20 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
FutureOr<void> _clearTabToRunSetting(
ClearTabToRunSetting event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
selectedIcon = '';
showInDeviceScreen = false;
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
showInDevice: showInDeviceScreen,
selectedIcon: selectedIcon,
iconModels: iconModelList));
}
FutureOr<void> _fetchSceneTasks(
FetchSceneTasksEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading());
@ -392,7 +428,10 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
automationTempTasksList.clear();
automationSelectedValues.clear();
automationComparatorValues.clear();
effectiveTime = EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
selectedIcon = '';
showInDeviceScreen = false;
effectiveTime =
EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
sceneType = CreateSceneEnum.none;
conditionRule = 'or';
@ -401,10 +440,14 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
: await SceneApi.getSceneDetails(event.sceneId);
if (response.id.isNotEmpty) {
if (event.isAutomation) {
automationTasksList = List<SceneStaticFunction>.from(getTaskListFunctionsFromApi(
actions: [], isAutomation: true, conditions: response.conditions));
automationTasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: [],
isAutomation: true,
conditions: response.conditions));
tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(actions: response.actions, isAutomation: false));
getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
conditionRule = response.decisionExpr ?? conditionRule;
@ -417,25 +460,34 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
: EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
// Set the days directly from the API response
BlocProvider.of<EffectPeriodBloc>(NavigationService.navigatorKey.currentContext!)
BlocProvider.of<EffectPeriodBloc>(
NavigationService.navigatorKey.currentContext!)
.add(SetDays(response.effectiveTime?.loops ?? '1111111'));
// Set Custom Time and reset days first
BlocProvider.of<EffectPeriodBloc>(NavigationService.navigatorKey.currentContext!)
BlocProvider.of<EffectPeriodBloc>(
NavigationService.navigatorKey.currentContext!)
.add(SetCustomTime(effectiveTime!.start, effectiveTime!.end));
emit(AddSceneTask(
automationTasksList: automationTasksList,
tasksList: tasksList,
condition: conditionRule,
));
automationTasksList: automationTasksList,
tasksList: tasksList,
condition: conditionRule,
iconModels: iconModelList,
selectedIcon: selectedIcon,
showInDevice: showInDeviceScreen));
} else {
tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(actions: response.actions, isAutomation: false));
getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
selectedIcon = response.icon!;
showInDeviceScreen = response.showInDevice!;
emit(AddSceneTask(
tasksList: tasksList,
condition: conditionRule,
));
tasksList: tasksList,
condition: conditionRule,
iconModels: iconModelList,
selectedIcon: selectedIcon,
showInDevice: showInDeviceScreen));
}
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
@ -445,12 +497,66 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
FutureOr<void> _fetchIconScene(
SceneIconEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading());
try {
iconModelList = await SceneApi.getIcon();
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
showInDevice: showInDeviceScreen,
selectedIcon: selectedIcon,
iconModels: iconModelList));
} catch (e) {
emit(const CreateSceneError(message: 'Something went wrong'));
}
}
FutureOr<void> _iconSelected(
IconSelected event, Emitter<CreateSceneState> emit) async {
try {
if (event.confirmSelection) {
selectedIcon = event.iconId;
}
emit(CreateSceneLoading());
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
showInDevice: showInDeviceScreen,
condition: conditionRule,
selectedIcon: event.iconId,
iconModels: iconModelList));
} catch (e) {
emit(const CreateSceneError(message: 'Something went wrong'));
}
}
FutureOr<void> _showInDeviceClicked(
ShowOnDeviceClicked event, Emitter<CreateSceneState> emit) async {
try {
emit(CreateSceneLoading());
showInDeviceScreen = event.value;
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
selectedIcon: selectedIcon,
iconModels: iconModelList,
showInDevice: showInDeviceScreen));
} catch (e) {
emit(const CreateSceneError(message: 'Something went wrong'));
}
}
String _getDayFromIndex(int index) {
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
return days[index];
}
FutureOr<void> _clearTempTaskList(ClearTempTaskListEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _clearTempTaskList(
ClearTempTaskListEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
if (event.isAutomation == true) {
automationTempTasksList.clear();
@ -494,13 +600,18 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
FutureOr<void> _deleteScene(DeleteSceneEvent event, Emitter<CreateSceneState> emit) async {
FutureOr<void> _deleteScene(
DeleteSceneEvent event, Emitter<CreateSceneState> emit) async {
emit(DeleteSceneLoading());
try {
final response = sceneType.name == CreateSceneEnum.deviceStatusChanges.name
? await SceneApi.deleteAutomation(automationId: event.sceneId, unitUuid: event.unitUuid)
: await SceneApi.deleteScene(sceneId: event.sceneId, unitUuid: event.unitUuid);
final response =
sceneType.name == CreateSceneEnum.deviceStatusChanges.name
? await SceneApi.deleteAutomation(
automationId: event.sceneId, unitUuid: event.unitUuid)
: await SceneApi.deleteScene(
sceneId: event.sceneId,
);
if (response == true) {
emit(const DeleteSceneSuccess(true));
} else {
@ -511,7 +622,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
FutureOr<void> _updateTaskValue(UpdateTaskEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _updateTaskValue(
UpdateTaskEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
if (event.isAutomation == true) {
for (var i = 0; i < automationTasksList.length; i++) {
@ -547,7 +659,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
FutureOr<void> _selectConditionRule(SelectConditionEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _selectConditionRule(
SelectConditionEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneInitial());
if (event.condition.contains('any')) {
conditionRule = 'or';
@ -562,7 +675,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
FutureOr<void> _sceneTypeEvent(SceneTypeEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _sceneTypeEvent(
SceneTypeEvent event, Emitter<CreateSceneState> emit) {
// emit(CreateSceneInitial());
if (event.type == CreateSceneEnum.tabToRun) {

View File

@ -149,8 +149,7 @@ class FetchSceneTasksEvent extends CreateSceneEvent {
final String sceneId;
final bool isAutomation;
const FetchSceneTasksEvent(
{this.isAutomation = false, required this.sceneId});
const FetchSceneTasksEvent({this.isAutomation = false, required this.sceneId});
@override
List<Object> get props => [sceneId, isAutomation];
@ -183,3 +182,33 @@ class EffectiveTimePeriodEvent extends CreateSceneEvent {
final EffectiveTime period;
const EffectiveTimePeriodEvent(this.period);
}
class SceneIconEvent extends CreateSceneEvent {}
class IconSelected extends CreateSceneEvent {
final String iconId;
final bool confirmSelection;
const IconSelected({required this.iconId, required this.confirmSelection});
@override
List<Object> get props => [iconId];
}
class ShowOnDeviceClicked extends CreateSceneEvent {
final bool value;
const ShowOnDeviceClicked({
required this.value,
});
@override
List<Object> get props => [value];
}
class ClearTabToRunSetting extends CreateSceneEvent {
const ClearTabToRunSetting();
@override
List<Object> get props => [];
}

View File

@ -23,8 +23,16 @@ class AddSceneTask extends CreateSceneState {
final List<SceneStaticFunction> tasksList;
final List<SceneStaticFunction>? automationTasksList;
final String? condition;
final String? selectedIcon;
final List<IconModel>? iconModels;
final bool? showInDevice;
const AddSceneTask(
{required this.tasksList, this.automationTasksList, this.condition});
{required this.tasksList,
this.automationTasksList,
this.condition,
this.iconModels,
this.selectedIcon,
this.showInDevice});
@override
List<Object> get props => [tasksList];
@ -33,8 +41,7 @@ class AddSceneTask extends CreateSceneState {
class TempHoldSceneTask extends CreateSceneState {
final List<SceneStaticFunction> tempTasksList;
final List<SceneStaticFunction>? automationTempTasksList;
const TempHoldSceneTask(
{required this.tempTasksList, this.automationTempTasksList});
const TempHoldSceneTask({required this.tempTasksList, this.automationTempTasksList});
@override
List<Object> get props => [tempTasksList];

View File

@ -24,7 +24,9 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
try {
if (event.unitId.isNotEmpty) {
scenes = await SceneApi.getScenesByUnitId(event.unitId);
scenes = await SceneApi.getScenesByUnitId(
event.unitId, event.unit.community.uuid,
showInDevice: event.showInDevice);
emit(SceneLoaded(scenes, automationList));
} else {
emit(const SceneError(message: 'Unit ID is empty'));
@ -93,7 +95,7 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
event.automationId, event.automationStatusUpdate);
if (success) {
automationList = await SceneApi.getAutomationByUnitId(
event.automationStatusUpdate.unitUuid);
event.automationStatusUpdate.spaceUuid);
newLoadingStates[event.automationId] = false;
emit(SceneLoaded(
currentState.scenes,

View File

@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/scene/model/update_automation.dart';
abstract class SceneEvent extends Equatable {
@ -10,11 +11,13 @@ abstract class SceneEvent extends Equatable {
class LoadScenes extends SceneEvent {
final String unitId;
final bool showInDevice;
final SpaceModel unit;
const LoadScenes(this.unitId);
const LoadScenes(this.unitId, this.unit, {this.showInDevice = false});
@override
List<Object> get props => [unitId];
List<Object> get props => [unitId, showInDevice];
}
class LoadAutomation extends SceneEvent {
@ -41,8 +44,7 @@ class UpdateAutomationStatus extends SceneEvent {
final String automationId;
final AutomationStatusUpdate automationStatusUpdate;
const UpdateAutomationStatus(
{required this.automationStatusUpdate, required this.automationId});
const UpdateAutomationStatus({required this.automationStatusUpdate, required this.automationId});
@override
List<Object> get props => [automationStatusUpdate];

View File

@ -17,7 +17,7 @@ class TabBarBloc extends Bloc<TabBarEvent, TabBarState> {
if (event.roomId == "-1") {
deviceManagerBloc.add(FetchAllDevices());
} else {
deviceManagerBloc.add(FetchDevicesByRoomId(event.roomId));
deviceManagerBloc.add(FetchDevicesByRoomId(event.roomId,event.unit));
}
emit(TabSelected(
roomId: event.roomId, selectedTabIndex: event.selectedIndex));

View File

@ -1,3 +1,5 @@
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
abstract class TabBarEvent {
const TabBarEvent();
}
@ -5,5 +7,7 @@ abstract class TabBarEvent {
class TabChanged extends TabBarEvent {
final int selectedIndex;
final String roomId;
const TabChanged({required this.selectedIndex, required this.roomId});
final SpaceModel unit;
const TabChanged(
{required this.selectedIndex, required this.roomId, required this.unit});
}

View File

@ -60,7 +60,7 @@ mixin SceneLogicHelper {
if (isAutomation) {
final createAutomationModel = CreateAutomationModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
unitUuid: HomeCubit.getInstance().selectedSpace?.id ?? '',
automationName: sceneName.text,
decisionExpr: sceneBloc.conditionRule,
effectiveTime: sceneBloc.effectiveTime ??
@ -124,7 +124,9 @@ mixin SceneLogicHelper {
));
} else {
final createSceneModel = CreateSceneModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
spaceUuid: HomeCubit.getInstance().selectedSpace?.id ?? '',
iconId: sceneBloc.selectedIcon,
showInDevice: sceneBloc.showInDeviceScreen,
sceneName: sceneName.text,
decisionExpr: 'and',
actions: [
@ -171,24 +173,21 @@ mixin SceneLogicHelper {
}
}
Widget getTheCorrectDialogBody(
SceneStaticFunction taskItem, dynamic functionValue,
Widget getTheCorrectDialogBody(SceneStaticFunction taskItem, dynamic functionValue,
{required bool isAutomation}) {
if (taskItem.operationDialogType == OperationDialogType.temperature) {
return AlertDialogTemperatureBody(
taskItem: taskItem,
functionValue: functionValue ?? taskItem.functionValue,
);
} else if ((taskItem.operationDialogType ==
OperationDialogType.countdown) ||
} else if ((taskItem.operationDialogType == OperationDialogType.countdown) ||
(taskItem.operationDialogType == OperationDialogType.delay)) {
return AlertDialogCountdown(
durationValue: taskItem.functionValue ?? 0,
functionValue: functionValue ?? taskItem.functionValue,
function: taskItem,
);
} else if (taskItem.operationDialogType ==
OperationDialogType.integerSteps) {
} else if (taskItem.operationDialogType == OperationDialogType.integerSteps) {
return AlertDialogSliderSteps(
taskItem: taskItem,
functionValue: functionValue ?? taskItem.functionValue,

View File

@ -39,7 +39,7 @@ class CreateAutomationModel {
Map<String, dynamic> toMap([String? automationId]) {
return {
if (automationId == null) 'unitUuid': unitUuid,
if (automationId == null) 'spaceUuid': unitUuid,
'automationName': automationName,
'decisionExpr': decisionExpr,
'effectiveTime': effectiveTime.toMap(),
@ -50,7 +50,7 @@ class CreateAutomationModel {
factory CreateAutomationModel.fromMap(Map<String, dynamic> map) {
return CreateAutomationModel(
unitUuid: map['unitUuid'] ?? '',
unitUuid: map['spaceUuid'] ?? '',
automationName: map['automationName'] ?? '',
decisionExpr: map['decisionExpr'] ?? '',
effectiveTime: EffectiveTime.fromMap(map['effectiveTime']),

View File

@ -3,26 +3,35 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
class CreateSceneModel {
String unitUuid;
String spaceUuid;
String iconId;
bool showInDevice;
String sceneName;
String decisionExpr;
List<CreateSceneAction> actions;
CreateSceneModel({
required this.unitUuid,
required this.spaceUuid,
required this.iconId,
required this.showInDevice,
required this.sceneName,
required this.decisionExpr,
required this.actions,
});
CreateSceneModel copyWith({
String? unitUuid,
String? spaceUuid,
String? iconId,
bool? showInDevice,
String? sceneName,
String? decisionExpr,
List<CreateSceneAction>? actions,
bool? showInHomePage,
}) {
return CreateSceneModel(
unitUuid: unitUuid ?? this.unitUuid,
spaceUuid: spaceUuid ?? this.spaceUuid,
iconId: iconId ?? this.iconId,
showInDevice: showInDevice ?? this.showInDevice,
sceneName: sceneName ?? this.sceneName,
decisionExpr: decisionExpr ?? this.decisionExpr,
actions: actions ?? this.actions,
@ -31,7 +40,9 @@ class CreateSceneModel {
Map<String, dynamic> toMap([String? sceneId]) {
return {
if (sceneId == null) 'unitUuid': unitUuid,
if (sceneId == null) 'spaceUuid': spaceUuid,
if (iconId.isNotEmpty) 'iconUuid': iconId,
'showInHomePage': showInDevice,
'sceneName': sceneName,
'decisionExpr': decisionExpr,
'actions': actions.map((x) => x.toMap()).toList(),
@ -40,7 +51,9 @@ class CreateSceneModel {
factory CreateSceneModel.fromMap(Map<String, dynamic> map) {
return CreateSceneModel(
unitUuid: map['unitUuid'] ?? '',
spaceUuid: map['spaceUuid'] ?? '',
showInDevice: map['showInHomePage'] ?? false,
iconId: map['iconUuid'] ?? '',
sceneName: map['sceneName'] ?? '',
decisionExpr: map['decisionExpr'] ?? '',
actions: List<CreateSceneAction>.from(
@ -55,7 +68,7 @@ class CreateSceneModel {
@override
String toString() {
return 'CreateSceneModel(unitUuid: $unitUuid, sceneName: $sceneName, decisionExpr: $decisionExpr, actions: $actions)';
return 'CreateSceneModel(unitUuid: $spaceUuid, sceneName: $sceneName, decisionExpr: $decisionExpr, actions: $actions)';
}
@override
@ -63,7 +76,9 @@ class CreateSceneModel {
if (identical(this, other)) return true;
return other is CreateSceneModel &&
other.unitUuid == unitUuid &&
other.spaceUuid == spaceUuid &&
other.iconId == iconId &&
other.showInDevice == showInDevice &&
other.sceneName == sceneName &&
other.decisionExpr == decisionExpr &&
listEquals(other.actions, actions);
@ -71,7 +86,7 @@ class CreateSceneModel {
@override
int get hashCode {
return unitUuid.hashCode ^
return spaceUuid.hashCode ^
sceneName.hashCode ^
decisionExpr.hashCode ^
actions.hashCode;

View File

@ -0,0 +1,39 @@
import 'dart:convert';
import 'dart:typed_data';
class IconModel {
final String uuid;
final DateTime createdAt;
final DateTime updatedAt;
final String iconBase64;
IconModel({
required this.uuid,
required this.createdAt,
required this.updatedAt,
required this.iconBase64,
});
// Method to decode the icon from Base64 and return as Uint8List
Uint8List get iconBytes => base64Decode(iconBase64);
// Factory constructor to create an instance from JSON
factory IconModel.fromJson(Map<String, dynamic> json) {
return IconModel(
uuid: json['uuid'] as String,
createdAt: DateTime.parse(json['createdAt'] as String),
updatedAt: DateTime.parse(json['updatedAt'] as String),
iconBase64: json['icon'] as String,
);
}
// Method to convert an instance back to JSON
Map<String, dynamic> toJson() {
return {
'uuid': uuid,
'createdAt': createdAt.toIso8601String(),
'updatedAt': updatedAt.toIso8601String(),
'icon': iconBase64,
};
}
}

View File

@ -4,6 +4,8 @@ class SceneDetailsModel {
final String id;
final String name;
final String status;
final String? icon;
final bool? showInDevice;
final String type;
final List<Action> actions;
final List<Condition>? conditions;
@ -16,6 +18,8 @@ class SceneDetailsModel {
required this.status,
required this.type,
required this.actions,
this.icon,
this.showInDevice,
this.conditions,
this.decisionExpr,
this.effectiveTime,
@ -28,25 +32,27 @@ class SceneDetailsModel {
factory SceneDetailsModel.fromJson(Map<String, dynamic> json) =>
SceneDetailsModel(
id: json["id"],
name: json["name"],
status: json["status"],
type: json["type"],
actions: (json["actions"] as List)
.map((x) => Action.fromJson(x))
.where((x) => x != null)
.toList()
.cast<Action>(),
conditions: json["conditions"] != null
? (json["conditions"] as List)
.map((x) => Condition.fromJson(x))
.toList()
: null,
decisionExpr: json["decisionExpr"],
effectiveTime: json["effectiveTime"] != null
? EffectiveTime.fromJson(json["effectiveTime"])
: null,
);
id: json["uuid"] ?? json["id"],
name: json["name"],
status: json["status"],
type: json["type"],
actions: (json["actions"] as List)
.map((x) => Action.fromJson(x))
.where((x) => x != null)
.toList()
.cast<Action>(),
conditions: json["conditions"] != null
? (json["conditions"] as List)
.map((x) => Condition.fromJson(x))
.toList()
: null,
decisionExpr: json["decisionExpr"],
effectiveTime: json["effectiveTime"] != null
? EffectiveTime.fromJson(json["effectiveTime"])
: null,
icon: json["iconUuid"] != null ? json["iconUuid"] ?? '' : '',
showInDevice:
json['showInHome'] != null ? json['showInHome'] ?? false : false);
Map<String, dynamic> toJson() => {
"id": id,
@ -89,7 +95,7 @@ class Action {
);
}
if (json["executorProperty"] == null) {
return null;
return null;
}
return Action(

View File

@ -1,32 +1,42 @@
import 'dart:convert';
import 'dart:typed_data';
class ScenesModel {
final String id;
final String? sceneTuyaId;
final String name;
final String status;
final String type;
final String? icon;
ScenesModel({
required this.id,
required this.name,
required this.status,
required this.type,
});
ScenesModel(
{required this.id,
this.sceneTuyaId,
required this.name,
required this.status,
required this.type,
this.icon});
factory ScenesModel.fromRawJson(String str) =>
ScenesModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
Uint8List get iconInBytes => base64Decode(icon ?? '');
factory ScenesModel.fromJson(Map<String, dynamic> json) => ScenesModel(
id: json["id"],
name: json["name"] ?? '',
status: json["status"] ?? '',
type: json["type"] ?? '',
);
factory ScenesModel.fromJson(Map<String, dynamic> json) {
return ScenesModel(
id: json["id"] ?? json["uuid"] ?? '', // Fallback to empty string if id is null
sceneTuyaId: json["sceneTuyaId"] as String?, // Nullable
name: json["name"] ?? '', // Fallback to empty string if name is null
status:
json["status"] ?? '', // Fallback to empty string if status is null
type: json["type"] ?? '', // Fallback to empty string if type is null
icon: json["icon"] as String?, // Nullable
);
}
Map<String, dynamic> toJson() => {
"id": id,
"sceneTuyaId": sceneTuyaId ?? '',
"name": name,
"status": status,
"type": type,

View File

@ -1,11 +1,11 @@
import 'dart:convert';
class AutomationStatusUpdate {
final String unitUuid;
final String spaceUuid;
final bool isEnable;
AutomationStatusUpdate({
required this.unitUuid,
required this.spaceUuid,
required this.isEnable,
});
@ -16,23 +16,23 @@ class AutomationStatusUpdate {
factory AutomationStatusUpdate.fromJson(Map<String, dynamic> json) =>
AutomationStatusUpdate(
unitUuid: json["unitUuid"],
spaceUuid: json["spaceUuid"],
isEnable: json["isEnable"],
);
Map<String, dynamic> toJson() => {
"unitUuid": unitUuid,
"spaceUuid": spaceUuid,
"isEnable": isEnable,
};
factory AutomationStatusUpdate.fromMap(Map<String, dynamic> map) =>
AutomationStatusUpdate(
unitUuid: map["unitUuid"],
spaceUuid: map["spaceUuid"],
isEnable: map["isEnable"],
);
Map<String, dynamic> toMap() => {
"unitUuid": unitUuid,
"spaceUuid": spaceUuid,
"isEnable": isEnable,
};
}

View File

@ -1,12 +1,15 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/icons_dialog.dart';
import 'package:syncrow_app/features/scene/widgets/delete_routine_b.dart';
import 'package:syncrow_app/features/scene/widgets/effective_period_setting/effective_period_bottom_sheet.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.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_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -22,72 +25,265 @@ class SceneAutoSettings extends StatelessWidget {
final isAutomation = context.read<CreateSceneBloc>().sceneType ==
CreateSceneEnum.deviceStatusChanges;
final sceneName = sceneSettings['sceneName'] as String? ?? '';
bool showInDevice = context.read<CreateSceneBloc>().showInDeviceScreen;
String selectedIcon = '';
return DefaultScaffold(
title: 'Settings',
padding: EdgeInsets.zero,
leading: IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: const Icon(
Icons.arrow_back_ios,
)),
child: SizedBox(
height: MediaQuery.sizeOf(context).height,
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: DefaultContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
title: 'Settings',
padding: EdgeInsets.zero,
leading: IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: const Icon(
Icons.arrow_back_ios,
)),
child: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
if (state is AddSceneTask) {
showInDevice = state.showInDevice ?? false;
}
return SizedBox(
height: MediaQuery.sizeOf(context).height,
child: Column(
children: [
if (!isAutomation)
DefaultContainer(
child: Padding(
padding: const EdgeInsets.only(
top: 10, left: 10, right: 10, bottom: 10),
child: Column(
children: [
InkWell(
onTap: () {
showDialog(
context: context,
builder: (context) {
BlocProvider.of<CreateSceneBloc>(context)
.add(SceneIconEvent());
return IconsDialog(
widgetList: Container(
height:
MediaQuery.sizeOf(context).height * 0.4,
width: MediaQuery.sizeOf(context).width,
padding: const EdgeInsets.all(24),
child: BlocBuilder<CreateSceneBloc,
CreateSceneState>(
builder: (context, state) {
if (state is CreateSceneLoading) {
return const Center(
child: SizedBox(
height: 50,
width: 50,
child:
CircularProgressIndicator()),
);
} else if (state is AddSceneTask) {
return GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemCount:
state.iconModels?.length ?? 0,
itemBuilder: (context, index) {
final iconModel =
state.iconModels![index];
return InkWell(
onTap: () {
BlocProvider.of<
CreateSceneBloc>(
context)
.add(IconSelected(
iconId:
iconModel.uuid,
confirmSelection:
false));
selectedIcon = iconModel.uuid;
},
child: ClipOval(
child: Container(
padding:
const EdgeInsets.all(1),
decoration: BoxDecoration(
border: Border.all(
color: state.selectedIcon ==
iconModel.uuid
? ColorsManager
.primaryColorWithOpacity
: Colors
.transparent,
width: 2,
),
shape: BoxShape.circle,
),
child: Image.memory(
iconModel.iconBytes,
width: 35,
height: 35,
),
),
),
);
},
);
} else if (state is CreateSceneError) {
return Text(state.message);
} else {
return Container();
}
},
),
),
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
BlocProvider.of<CreateSceneBloc>(context)
.add(IconSelected(
iconId: selectedIcon,
confirmSelection: true));
Navigator.of(context).pop();
},
title: 'Icons',
);
},
);
},
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyMedium(text: 'Icons'),
Icon(
Icons.arrow_forward_ios_outlined,
color: ColorsManager.textGray,
size: 15,
)
],
),
),
const SizedBox(
height: 5,
),
const Divider(
color: ColorsManager.graysColor,
),
const SizedBox(
height: 5,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BodyMedium(text: 'Show on devices page'),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 30,
width: 1,
color: ColorsManager.graysColor,
),
Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: showInDevice,
onChanged: (value) {
BlocProvider.of<CreateSceneBloc>(context)
.add(ShowOnDeviceClicked(
value: value));
},
applyTheme: true,
),
),
],
)
],
),
const SizedBox(
height: 5,
),
const Divider(
color: ColorsManager.graysColor,
),
const SizedBox(
height: 5,
),
const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//Cloud
BodyMedium(text: 'Executed by'),
Text('Cloud',
style: TextStyle(
color: ColorsManager.textGray,
)),
],
),
],
),
)),
if (isAutomation)
DefaultContainer(
padding: const EdgeInsets.symmetric(
horizontal: 8,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(
height: 8,
),
Visibility(
visible: isAutomation,
child: SceneListTile(
titleString: "Effective Period",
trailingWidget:
const Icon(Icons.arrow_forward_ios_rounded),
onPressed: () {
context.customBottomSheet(
child: const EffectPeriodBottomSheetContent(),
);
},
),
),
Visibility(
visible: sceneName.isNotEmpty && isAutomation,
child: SizedBox(
width: context.width * 0.9,
child: const Divider(
color: ColorsManager.greyColor,
),
),
),
],
),
),
const SizedBox(
height: 15,
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 8,
),
Visibility(
visible: isAutomation,
child: SceneListTile(
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 8),
titleString: "Effective Period",
trailingWidget:
const Icon(Icons.arrow_forward_ios_rounded),
onPressed: () {
context.customBottomSheet(
child: const EffectPeriodBottomSheetContent(),
);
},
),
),
Visibility(
visible: sceneName.isNotEmpty && isAutomation,
child: SizedBox(
width: context.width * 0.9,
child: const Divider(
color: ColorsManager.greyColor,
SizedBox(
child: Center(
child: Visibility(
visible: sceneName.isNotEmpty,
child: DeleteRoutineButton(
isAutomation: isAutomation,
sceneId: sceneId,
),
),
),
),
Visibility(
visible: sceneName.isNotEmpty,
child: DeleteBottomSheetContent(
isAutomation: isAutomation,
sceneId: sceneId,
),
),
const SizedBox(
height: 16,
),
],
),
),
],
),
],
),
),
);
);
}));
}
}

View File

@ -1,52 +1,48 @@
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/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart';
import 'package:syncrow_app/features/scene/widgets/scene_devices/scene_devices_body.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class SceneRoomsTabBarDevicesView extends StatefulWidget {
const SceneRoomsTabBarDevicesView({super.key});
@override
State<SceneRoomsTabBarDevicesView> createState() =>
_SceneRoomsTabBarDevicesViewState();
State<SceneRoomsTabBarDevicesView> createState() => _SceneRoomsTabBarDevicesViewState();
}
class _SceneRoomsTabBarDevicesViewState
extends State<SceneRoomsTabBarDevicesView>
class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesView>
with SingleTickerProviderStateMixin {
late final TabController _tabController;
List<RoomModel>? rooms = [];
List<SubSpaceModel>? rooms = [];
late final SpaceModel selectedSpace;
@override
void initState() {
rooms = List.from(HomeCubit.getInstance().selectedSpace?.rooms ?? []);
selectedSpace = HomeCubit.getInstance().selectedSpace!;
rooms = List.from(HomeCubit.getInstance().selectedSpace?.subspaces ?? []);
if (rooms != null) {
if (rooms![0].id != '-1') {
rooms?.insert(
0,
RoomModel(
SubSpaceModel(
name: 'All Devices',
devices: DevicesCubit.getInstance().allDevices,
id: '-1',
type: SpaceType.Room,
),
);
}
}
_tabController =
TabController(length: rooms!.length, vsync: this, initialIndex: 0);
_tabController = TabController(length: rooms!.length, vsync: this, initialIndex: 0);
_tabController.addListener(_handleTabSwitched);
super.initState();
}
@ -57,7 +53,7 @@ class _SceneRoomsTabBarDevicesViewState
/// select tab
context.read<TabBarBloc>().add(
TabChanged(selectedIndex: value, roomId: rooms?[value].id ?? ''));
TabChanged(selectedIndex: value, roomId: rooms?[value].id ?? '', unit: selectedSpace));
return;
}
}

View File

@ -1,16 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/widgets/create_scene_save_button.dart';
import 'package:syncrow_app/features/scene/widgets/if_then_containers/if_container.dart';
import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_container.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
@ -24,19 +20,16 @@ class SceneTasksView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final sceneSettings = ModalRoute.of(context)!.settings.arguments
as SceneSettingsRouteArguments;
final sceneSettings = ModalRoute.of(context)!.settings.arguments as SceneSettingsRouteArguments;
final isAutomation =
sceneSettings.sceneType == CreateSceneEnum.deviceStatusChanges.name;
final isAutomation = sceneSettings.sceneType == CreateSceneEnum.deviceStatusChanges.name;
// context.read<CreateSceneBloc>().add(SceneTypeEvent(isAutomation
// ? CreateSceneEnum.deviceStatusChanges
// : CreateSceneEnum.tabToRun));
return DefaultScaffold(
title: sceneSettings.sceneName.isNotEmpty
? sceneSettings.sceneName
: StringsManager.createScene,
title:
sceneSettings.sceneName.isNotEmpty ? sceneSettings.sceneName : StringsManager.createScene,
padding: EdgeInsets.zero,
leading: IconButton(
onPressed: () {
@ -117,49 +110,3 @@ class SceneTasksView extends StatelessWidget {
);
}
}
class DeleteBottomSheetContent extends StatelessWidget {
const DeleteBottomSheetContent(
{super.key, required this.sceneId, required this.isAutomation});
final String sceneId;
final bool isAutomation;
@override
Widget build(BuildContext context) {
return BlocConsumer<CreateSceneBloc, CreateSceneState>(
listener: (context, state) {
if (state is DeleteSceneSuccess) {
if (state.success) {
navigateToRoute(context, Routes.homeRoute);
BlocProvider.of<SceneBloc>(context)
.add(LoadScenes(HomeCubit.getInstance().selectedSpace!.id!));
BlocProvider.of<SceneBloc>(context).add(
LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
}
}
},
builder: (context, state) {
return SceneListTile(
onPressed: () {
context.read<CreateSceneBloc>().add(DeleteSceneEvent(
sceneId: sceneId,
unitUuid: HomeCubit.getInstance().selectedSpace!.id!,
));
},
padding: const EdgeInsets.symmetric(horizontal: 8),
titleString: isAutomation
? StringsManager.deleteAutomation
: StringsManager.deleteScene,
leadingWidget: (state is DeleteSceneLoading)
? const SizedBox(
height: 24, width: 24, child: CircularProgressIndicator())
: SvgPicture.asset(
Assets.assetsDeleteIcon,
color: ColorsManager.red,
),
);
},
);
}
}

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