Compare commits
208 Commits
hide_widge
...
connect_re
Author | SHA1 | Date | |
---|---|---|---|
dcfbe5282e | |||
6f2e2e2d4a | |||
fe52726f6e | |||
ba44d1d359 | |||
a623f1c723 | |||
c5f5992c18 | |||
98ad7090d8 | |||
ea08024b82 | |||
f6d66185b3 | |||
ead5297ba1 | |||
9a6bf5cbaf | |||
51fbe64209 | |||
49fa80e7d8 | |||
1aa15e5dd6 | |||
962f2d6861 | |||
bd6219f915 | |||
132cafcaa2 | |||
8862ad95f3 | |||
af4c0f84cb | |||
c2b77ad1fc | |||
95cee89b4c | |||
d5fcbe2601 | |||
1fa33a271f | |||
09e2564183 | |||
5dee6c2842 | |||
c5c5088724 | |||
d1d570b40f | |||
a43ff3c07d | |||
572520eed5 | |||
5e5f127a4b | |||
6f51c2d2b6 | |||
a18e8443d0 | |||
72241cba6c | |||
506531e16a | |||
ab3edbaf57 | |||
64e3fb7f34 | |||
e6e46be9b4 | |||
91dfd53477 | |||
5ab9664318 | |||
d3bf4de0ca | |||
5ae07688cb | |||
e6fa9c2391 | |||
916b606cb1 | |||
29c444eede | |||
9dd6c9e1e7 | |||
b070884bd9 | |||
bf5b39e742 | |||
7d05a33c52 | |||
6e546a4831 | |||
b098202fd8 | |||
a294988558 | |||
43c17d1c18 | |||
09c1a785e5 | |||
e70b9ea9e2 | |||
c173df934d | |||
e4262d08a5 | |||
4bae7bb9fb | |||
073916d4ac | |||
8870467fe4 | |||
9331193e90 | |||
45b0b67fe0 | |||
9e0184f19d | |||
9091af2661 | |||
4b7f4d4279 | |||
e61cfd7e49 | |||
788fb75a68 | |||
ea5b6597f5 | |||
c72297e0c8 | |||
d0c6b13072 | |||
812dc4792b | |||
4907eebc42 | |||
2221d9ae7b | |||
9167c8da29 | |||
4258ccdfbd | |||
cb71b51565 | |||
d4ed4efcd8 | |||
dac045146e | |||
5563197e9d | |||
7268253e35 | |||
921d352207 | |||
c5871be990 | |||
24f7ab6af8 | |||
2fb6f30ccb | |||
508d8bbaa8 | |||
97bdb1bbb7 | |||
7ce0a27af0 | |||
65d00c923a | |||
bc4af6a237 | |||
830725254f | |||
ba7db3a5fb | |||
513175ed1e | |||
f35b699d4c | |||
7ffdc67016 | |||
18afc4f563 | |||
44d95f5701 | |||
e47f3d6d59 | |||
788ea27de1 | |||
5060d2a66d | |||
81e9e58627 | |||
25eae3dfaa | |||
0e912207e5 | |||
eb53671e3a | |||
2f6bd31aa2 | |||
fe680d15f2 | |||
440263e2f9 | |||
ec5b7d4395 | |||
7109421358 | |||
145086b9de | |||
bae5ae17a7 | |||
9706c2655c | |||
8a95f93556 | |||
60028cdf78 | |||
c12c73f20a | |||
a7256c8d5d | |||
5975adb5e2 | |||
0bb24604bc | |||
cf2690123e | |||
a220483310 | |||
12df07e681 | |||
59eafc99a5 | |||
db7eaa53af | |||
20a9f19480 | |||
a4e7f30411 | |||
210fbf7497 | |||
acbb6ca7c0 | |||
eb7eeebf18 | |||
15023e5882 | |||
408c40aa60 | |||
2abe7a6feb | |||
a381fd317d | |||
a588351482 | |||
1be52adcc8 | |||
3c5e0a7778 | |||
6591ef1664 | |||
cfc1b544b7 | |||
15640ff0df | |||
bfbc32d51b | |||
8aa493a15e | |||
e70df16de3 | |||
a7e7554813 | |||
1ab8c8341d | |||
67516817ec | |||
097e70b906 | |||
390f7288bd | |||
625b7b8304 | |||
d0b853b188 | |||
339a242e74 | |||
48c064c711 | |||
17e025b69f | |||
9b3e4a59af | |||
9f5e9af5fa | |||
6b79254a89 | |||
08f322165e | |||
1228e5e737 | |||
e7e0149b3a | |||
f8efc07fdb | |||
81345f7154 | |||
6ee650e9f8 | |||
8c0744054c | |||
8fd1259f9c | |||
d721f6f774 | |||
fe8f8160ec | |||
a31eb27c92 | |||
0fda5457ae | |||
5bd257ee56 | |||
e44c3ae796 | |||
3876909bea | |||
58b469b92a | |||
ae09cbda1e | |||
b59e7e4836 | |||
ed06b0ebd6 | |||
0bed2573a0 | |||
69092823a2 | |||
d2d5e76102 | |||
691beb2e86 | |||
819670867d | |||
1c256cc55c | |||
1d35377137 | |||
67ad986fcc | |||
90e5499f92 | |||
540f569b1f | |||
a98f7e77a3 | |||
944b981ee0 | |||
e0ff139f30 | |||
e12252db96 | |||
80dea5c12d | |||
65ad9c5edf | |||
b264f6042f | |||
fa16eaf82f | |||
7935864208 | |||
edf8bdfdcd | |||
9e5cbc285e | |||
8f7b46be25 | |||
c834ad0670 | |||
ed2187b7ff | |||
0341844ea9 | |||
51d3338497 | |||
c486b9af29 | |||
573852b4b4 | |||
298aab5116 | |||
bd1204c03a | |||
c31f1262a2 | |||
a46f69636d | |||
879bf99b12 | |||
56d4c34321 | |||
dd5fe10a21 | |||
4055265b0a | |||
aff7ceeac4 |
@ -1,5 +1,9 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "com.android.application"
|
id "com.android.application"
|
||||||
|
// START: FlutterFire Configuration
|
||||||
|
id 'com.google.gms.google-services'
|
||||||
|
id 'com.google.firebase.crashlytics'
|
||||||
|
// END: FlutterFire Configuration
|
||||||
id "kotlin-android"
|
id "kotlin-android"
|
||||||
id "dev.flutter.flutter-gradle-plugin"
|
id "dev.flutter.flutter-gradle-plugin"
|
||||||
}
|
}
|
||||||
|
68
android/app/google-services.json
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "427332280600",
|
||||||
|
"firebase_url": "https://test2-8a3d2-default-rtdb.firebaseio.com",
|
||||||
|
"project_id": "test2-8a3d2",
|
||||||
|
"storage_bucket": "test2-8a3d2.firebasestorage.app"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:427332280600:android:550f67441246cb1a0c7e6d",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.example.syncrow.app"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:427332280600:android:bb6047adeeb80fb00c7e6d",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.example.syncrow_application"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:427332280600:android:2bc36fbe82994a3e0c7e6d",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.example.syncrow_web"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
@ -20,6 +20,10 @@ pluginManagement {
|
|||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version "7.3.0" apply false
|
id "com.android.application" version "7.3.0" apply false
|
||||||
|
// START: FlutterFire Configuration
|
||||||
|
id "com.google.gms.google-services" version "4.3.15" apply false
|
||||||
|
id "com.google.firebase.crashlytics" version "2.8.1" apply false
|
||||||
|
// END: FlutterFire Configuration
|
||||||
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
|
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
assets/icons/active_user.svg
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<svg width="40" height="34" viewBox="0 0 40 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect y="2" width="33" height="20" rx="10" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<g filter="url(#filter0_d_5216_2616)">
|
||||||
|
<ellipse cx="22.9389" cy="12" rx="8.45122" ry="8.4" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_5216_2616" x="6.48767" y="0.599976" width="32.9025" height="32.8" 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 dy="5"/>
|
||||||
|
<feGaussianBlur stdDeviation="4"/>
|
||||||
|
<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_5216_2616"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5216_2616" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1011 B |
3
assets/icons/arrow_down.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="8" height="5" viewBox="0 0 8 5" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8 0.740463C8 0.574789 7.93931 0.408979 7.8179 0.282701C7.57528 0.0297901 7.18168 0.0297901 6.93903 0.282701L4 3.34404L1.06095 0.282701C0.818322 0.0297898 0.424717 0.0297898 0.182084 0.282701C-0.0606947 0.535291 -0.0606947 0.945601 0.182084 1.19819L3.56055 4.71746C3.80318 4.97034 4.1968 4.97034 4.43945 4.71746L7.8179 1.19819C7.93932 1.07191 8 0.906104 8 0.740463Z" fill="#999999" fill-opacity="0.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 511 B |
3
assets/icons/arrow_forward.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="5" height="9" viewBox="0 0 5 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0.647445 0.5C0.481771 0.5 0.315961 0.560695 0.189683 0.6821C-0.0632278 0.924716 -0.0632278 1.31832 0.189683 1.56097L3.25102 4.5L0.189683 7.43905C-0.0632278 7.68168 -0.0632278 8.07528 0.189683 8.31792C0.442273 8.56069 0.852583 8.56069 1.10517 8.31792L4.62444 4.93945C4.87732 4.69682 4.87732 4.3032 4.62444 4.06055L1.10517 0.6821C0.978895 0.560678 0.813086 0.5 0.647445 0.5Z" fill="#999999" fill-opacity="0.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 519 B |
BIN
assets/icons/atoz_icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/box_checked.png
Normal file
After Width: | Height: | Size: 754 B |
9
assets/icons/compleate_process_icon.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z" fill="#BBEC6C"/>
|
||||||
|
<path d="M9.9999 0C9.79708 0 9.59588 0.00676056 9.39604 0.018672C14.6376 0.330986 18.5355 4.67996 18.5355 10C18.5355 15.32 14.6376 19.669 9.396 19.9813C9.59588 19.9932 9.79708 20 9.9999 20C15.5228 20 19.9999 15.5229 19.9999 10C19.9999 4.47714 15.5228 0 9.9999 0Z" fill="#A2E62E"/>
|
||||||
|
<path d="M10.0002 18.5355C14.7142 18.5355 18.5357 14.714 18.5357 9.99993C18.5357 5.28586 14.7142 1.46436 10.0002 1.46436C5.28611 1.46436 1.4646 5.28586 1.4646 9.99993C1.4646 14.714 5.28611 18.5355 10.0002 18.5355Z" fill="#4FC123"/>
|
||||||
|
<path d="M9.99986 1.46436C9.7968 1.46436 9.59551 1.47196 9.396 1.48588C13.8282 1.79574 17.3277 5.48894 17.3277 9.99993C17.3277 14.511 13.8282 18.2041 9.396 18.514C9.59551 18.5279 9.7968 18.5355 9.99986 18.5355C14.7139 18.5355 18.5354 14.714 18.5354 9.99993C18.5354 5.28589 14.7139 1.46436 9.99986 1.46436Z" fill="#47A920"/>
|
||||||
|
<path d="M15.1631 8.28358L9.71483 13.7323C9.13696 14.3097 8.20095 14.3097 7.62348 13.7323L4.83717 10.946C4.51684 10.626 4.51684 10.1069 4.83717 9.787L5.64924 8.97493V8.97452L5.92449 8.69927C6.24441 8.37935 6.76352 8.37935 7.08344 8.69927L8.47781 10.0936C8.62751 10.2437 8.87097 10.2437 9.02067 10.0936L12.9969 6.11738C13.3168 5.79746 13.836 5.79746 14.1559 6.11738L15.1631 7.12462C15.4834 7.44495 15.4834 7.96366 15.1631 8.28358Z" fill="#D1F19E"/>
|
||||||
|
<path d="M9.02084 10.0938L8.55927 10.5553C8.37738 10.7376 8.08241 10.7388 7.89851 10.5582L6.48724 9.17265C6.26068 8.94569 5.93432 8.8805 5.64941 8.97507V8.97466L5.92467 8.69941C6.24459 8.37949 6.7637 8.37949 7.08362 8.69941L8.47799 10.0938C8.62768 10.2439 8.87114 10.2439 9.02084 10.0938Z" fill="#BBEC6C"/>
|
||||||
|
<path d="M15.1633 7.1248L14.1559 6.11747C13.8359 5.79743 13.317 5.79743 12.997 6.11747L12.7366 6.37791C12.971 6.35606 13.213 6.43478 13.3925 6.61429L13.9555 7.12484C14.2755 7.44488 14.2755 7.96375 13.9555 8.28379L8.9588 13.3461C8.60206 13.7028 8.10838 13.8389 7.64697 13.7549C8.22609 14.3094 9.14488 14.3022 9.71466 13.7324L15.1633 8.28379C15.4833 7.96375 15.4833 7.44484 15.1633 7.1248Z" fill="#BBEC6C"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
3
assets/icons/current_process_icon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="10" cy="10" r="10" fill="#023DFE"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 151 B |
18
assets/icons/deactive_user.svg
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<svg width="39" height="32" viewBox="0 0 39 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="6" y="1" width="33" height="20" rx="10" fill="#E9E9E9"/>
|
||||||
|
<g filter="url(#filter0_d_5216_2749)">
|
||||||
|
<circle cx="16" cy="11" r="8" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_5216_2749" x="0" y="0" width="32" height="32" 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 dy="5"/>
|
||||||
|
<feGaussianBlur stdDeviation="4"/>
|
||||||
|
<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_5216_2749"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5216_2749" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 956 B |
16
assets/icons/duplicate.svg
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.9807 2.67199L16.6413 0.219727H7.91051C7.43122 0.219727 7.04266 0.608281 7.04266 1.08758V16.605C7.04266 17.0843 7.43122 17.4729 7.91051 17.4729H18.2257C18.705 17.4729 19.0935 17.0843 19.0935 16.605V16.5459H19.7312V3.8127L17.9807 2.67199Z" fill="#60B7FF"/>
|
||||||
|
<path d="M18.1513 6.23445H9.12553C8.95881 6.23445 8.82373 6.09934 8.82373 5.93266C8.82373 5.76598 8.95885 5.63086 9.12553 5.63086H18.1513C18.318 5.63086 18.4531 5.76598 18.4531 5.93266C18.4531 6.09934 18.318 6.23445 18.1513 6.23445Z" fill="#0055A3"/>
|
||||||
|
<path d="M18.1513 8.54891H9.12553C8.95881 8.54891 8.82373 8.41379 8.82373 8.24711C8.82373 8.08043 8.95885 7.94531 9.12553 7.94531H18.1513C18.318 7.94531 18.4531 8.08043 18.4531 8.24711C18.4531 8.41379 18.318 8.54891 18.1513 8.54891Z" fill="#0055A3"/>
|
||||||
|
<path d="M18.1513 10.8634H9.12553C8.95881 10.8634 8.82373 10.7282 8.82373 10.5616C8.82373 10.3949 8.95885 10.2598 9.12553 10.2598H18.1513C18.318 10.2598 18.4531 10.3949 18.4531 10.5616C18.4531 10.7282 18.318 10.8634 18.1513 10.8634Z" fill="#0055A3"/>
|
||||||
|
<path d="M18.1513 13.1778H9.12556C8.95884 13.1778 8.82376 13.0427 8.82376 12.876C8.82376 12.7093 8.95888 12.5742 9.12556 12.5742H18.1513C18.3181 12.5742 18.4531 12.7093 18.4531 12.876C18.4531 13.0427 18.3181 13.1778 18.1513 13.1778Z" fill="#0055A3"/>
|
||||||
|
<path d="M19.0935 3.39648V16.6044C19.0935 17.0837 18.7049 17.4722 18.2256 17.4722H19.3663C19.8456 17.4722 20.2342 17.0837 20.2342 16.6044V3.81203L19.0935 3.39648Z" fill="#26A6FE"/>
|
||||||
|
<path d="M17.5091 3.8127H20.2342L16.6413 0.219727V2.94484C16.6413 3.42414 17.0298 3.8127 17.5091 3.8127Z" fill="#004281"/>
|
||||||
|
<path d="M11.4172 19.7805C11.8965 19.7805 12.2851 19.392 12.2851 18.9127V18.8937H12.8297V6.12031L11.039 4.78906L9.83279 2.52734H1.10204C0.622747 2.52734 0.234192 2.9159 0.234192 3.3952V18.9127C0.234192 19.392 0.622747 19.7805 1.10204 19.7805H11.4172Z" fill="#D5EDFF"/>
|
||||||
|
<path d="M12.285 4.97852V6.11922V18.9116C12.285 19.3909 11.8964 19.7794 11.4171 19.7794H12.5578C13.0371 19.7794 13.4257 19.3909 13.4257 18.9116V6.11922L12.285 4.97852Z" fill="#D8ECFE"/>
|
||||||
|
<path d="M10.7006 6.12031H13.4258L9.83279 2.52734V5.25246C9.83276 5.73176 10.2213 6.12031 10.7006 6.12031Z" fill="#B3DAFE"/>
|
||||||
|
<path d="M11.3429 8.54891H2.31709C2.15037 8.54891 2.01529 8.41379 2.01529 8.24711C2.01529 8.08043 2.15041 7.94531 2.31709 7.94531H11.3429C11.5096 7.94531 11.6447 8.08043 11.6447 8.24711C11.6447 8.41379 11.5096 8.54891 11.3429 8.54891Z" fill="#82AEE3"/>
|
||||||
|
<path d="M11.3428 10.8634H2.31706C2.15034 10.8634 2.01526 10.7282 2.01526 10.5616C2.01526 10.3949 2.15038 10.2598 2.31706 10.2598H11.3428C11.5096 10.2598 11.6446 10.3949 11.6446 10.5616C11.6446 10.7282 11.5096 10.8634 11.3428 10.8634Z" fill="#82AEE3"/>
|
||||||
|
<path d="M11.3428 13.1778H2.31706C2.15034 13.1778 2.01526 13.0427 2.01526 12.876C2.01526 12.7093 2.15038 12.5742 2.31706 12.5742H11.3428C11.5096 12.5742 11.6446 12.7093 11.6446 12.876C11.6446 13.0427 11.5096 13.1778 11.3428 13.1778Z" fill="#82AEE3"/>
|
||||||
|
<path d="M11.3428 15.4923H2.31706C2.15034 15.4923 2.01526 15.3571 2.01526 15.1905C2.01526 15.0238 2.15038 14.8887 2.31706 14.8887H11.3428C11.5096 14.8887 11.6446 15.0238 11.6446 15.1905C11.6447 15.3571 11.5096 15.4923 11.3428 15.4923Z" fill="#82AEE3"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
22
assets/icons/edit_space.svg
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_4618_3290)">
|
||||||
|
<path d="M18.7967 7.35156V19.8515C18.7967 21.0362 17.8329 22 16.6482 22H4.14825C2.9636 22 1.99982 21.0362 1.99982 19.8515V7.35156C1.99982 6.16691 2.9636 5.20312 4.14825 5.20312H16.6482C17.8329 5.20312 18.7967 6.16691 18.7967 7.35156Z" fill="#EDF2F2"/>
|
||||||
|
<path d="M18.7967 19.8515C18.7967 21.0361 17.8329 21.9999 16.6482 21.9999H4.14825C3.55591 21.9999 3.0188 21.7589 2.62978 21.3699L18.1667 5.83301C18.5557 6.22203 18.7967 6.75914 18.7967 7.35148V19.8515Z" fill="#C9DCDC"/>
|
||||||
|
<path d="M9.28417 14.7153C9.12722 14.5583 9.07241 14.3262 9.14265 14.1157L9.97128 11.6297C10 11.5434 10.0485 11.465 10.1128 11.4007L17.8468 3.66674C18.0756 3.43791 18.4466 3.43791 18.6754 3.66674L20.3327 5.324C20.5615 5.55283 20.5615 5.9238 20.3327 6.15263L12.5987 13.8866C12.5344 13.9509 12.456 13.9994 12.3697 14.0281L9.88374 14.8567C9.67323 14.927 9.44109 14.8722 9.28417 14.7153Z" fill="#4998EE"/>
|
||||||
|
<path d="M19.504 4.49512L9.28413 14.715C9.44105 14.8719 9.6732 14.9267 9.88374 14.8565L12.3697 14.0279C12.456 13.9992 12.5344 13.9507 12.5987 13.8864L20.3327 6.15242C20.5615 5.92359 20.5615 5.55261 20.3327 5.32379L19.504 4.49512Z" fill="#176EDE"/>
|
||||||
|
<path d="M20.3327 6.15305L17.8467 3.66711L19.2278 2.28602C19.6092 1.90466 20.2275 1.90466 20.6089 2.28602L21.7137 3.39087C22.0951 3.77223 22.0951 4.39055 21.7137 4.77192L20.3327 6.15305Z" fill="#FFE137"/>
|
||||||
|
<path d="M21.1613 2.83789L19.0897 4.90949L20.3327 6.15245L21.7138 4.77136C22.0951 4.39 22.0951 3.77168 21.7138 3.39031L21.1613 2.83789Z" fill="#FAC814"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_4618_3290" x="-0.000183105" y="0" width="24" height="24" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<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.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4618_3290"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4618_3290" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
BIN
assets/icons/empty_box.png
Normal file
After Width: | Height: | Size: 425 B |
3
assets/icons/filter_table_icon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.0001 0.416701C10.0001 0.647137 9.81341 0.833403 9.58339 0.833403H4.16627C3.93625 0.833403 3.74957 0.647137 3.74957 0.416701C3.74957 0.186266 3.93625 0 4.16627 0H9.58339C9.81341 0 10.0001 0.186266 10.0001 0.416701ZM8.33328 2.08351H4.16627C3.93625 2.08351 3.74957 2.26977 3.74957 2.50021C3.74957 2.73064 3.93625 2.91691 4.16627 2.91691H8.33328C8.5633 2.91691 8.74998 2.73064 8.74998 2.50021C8.74998 2.26977 8.5633 2.08351 8.33328 2.08351ZM7.08318 4.16701H4.16627C3.93625 4.16701 3.74957 4.35328 3.74957 4.58372C3.74957 4.81415 3.93625 5.00042 4.16627 5.00042H7.08318C7.3132 5.00042 7.49988 4.81415 7.49988 4.58372C7.49988 4.35328 7.3132 4.16701 7.08318 4.16701ZM5.83307 6.25052H4.16627C3.93625 6.25052 3.74957 6.43679 3.74957 6.66722C3.74957 6.89766 3.93625 7.08392 4.16627 7.08392H5.83307C6.06309 7.08392 6.24977 6.89766 6.24977 6.66722C6.24977 6.43679 6.06309 6.25052 5.83307 6.25052ZM3.21077 8.03942L2.49946 8.75073V0.416701C2.49946 0.186266 2.31278 0 2.08276 0C1.85274 0 1.66606 0.186266 1.66606 0.416701V8.75073L0.954333 8.039C0.791403 7.87607 0.528048 7.87607 0.365118 8.039C0.202187 8.20193 0.202187 8.46529 0.365118 8.62822L1.49313 9.75623C1.65564 9.91874 1.86899 10 2.08276 10C2.29653 10 2.50946 9.91874 2.67198 9.75623L3.79999 8.62822C3.96292 8.46529 3.96292 8.20193 3.79999 8.039C3.63706 7.87607 3.3737 7.87649 3.21077 8.03942Z" fill="#999999"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
7
assets/icons/invited_icon.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18.4066 14.8703C18.0603 14.6128 17.571 14.6847 17.3134 15.0309C17.1718 15.2212 17.0202 15.408 16.8629 15.5859C16.5772 15.9092 16.6075 16.4029 16.9308 16.6887C17.0794 16.8201 17.264 16.8846 17.4479 16.8846C17.664 16.8846 17.8792 16.7955 18.0335 16.6208C18.2198 16.4101 18.3993 16.1889 18.5671 15.9634C18.8246 15.6173 18.7528 15.1278 18.4066 14.8703Z" fill="#D5D5D5"/>
|
||||||
|
<path d="M19.7131 11.2064C19.2917 11.1146 18.8753 11.382 18.7835 11.8036C18.733 12.0355 18.672 12.2678 18.602 12.4942C18.4747 12.9065 18.7056 13.3439 19.1178 13.4713C19.1947 13.495 19.2723 13.5063 19.3487 13.5063C19.6823 13.5063 19.9912 13.2909 20.0949 12.9555C20.1779 12.6868 20.2504 12.411 20.3103 12.1359C20.402 11.7144 20.1347 11.2982 19.7131 11.2064Z" fill="#D5D5D5"/>
|
||||||
|
<path d="M14.6462 17.3725C14.4387 17.4883 14.224 17.5965 14.0079 17.6941C13.6146 17.8717 13.4398 18.3344 13.6174 18.7277C13.7479 19.0166 14.0322 19.1875 14.3299 19.1875C14.4374 19.1875 14.5466 19.1652 14.651 19.1181C14.9073 19.0023 15.1619 18.874 15.4079 18.7367C15.7846 18.5264 15.9195 18.0505 15.7091 17.6737C15.4988 17.2971 15.0229 17.1622 14.6462 17.3725Z" fill="#D5D5D5"/>
|
||||||
|
<path d="M9.71886 3.75V9.67641L6.85405 12.5412C6.54897 12.8463 6.54897 13.3409 6.85405 13.646C7.00663 13.7986 7.20651 13.8748 7.40651 13.8748C7.60644 13.8748 7.8064 13.7986 7.95898 13.646L11.0526 10.5524C11.1991 10.4059 11.2814 10.2072 11.2814 10V3.75C11.2814 3.31852 10.9316 2.96875 10.5001 2.96875C10.0686 2.96875 9.71886 3.31852 9.71886 3.75Z" fill="#D5D5D5"/>
|
||||||
|
<path d="M19.7188 1.67969C19.2873 1.67969 18.9375 2.02945 18.9375 2.46094V4.63031C17.1191 1.77844 13.9434 0 10.5 0C7.82891 0 5.3177 1.0402 3.42891 2.92891C1.5402 4.8177 0.5 7.32891 0.5 10C0.5 12.6711 1.5402 15.1823 3.42891 17.0711C5.3177 18.9598 7.82891 20 10.5 20C10.5066 20 10.513 19.9992 10.5195 19.999C10.5261 19.9992 10.5325 20 10.5391 20C10.8206 20 11.105 19.9881 11.3843 19.9648C11.8142 19.9287 12.1336 19.551 12.0976 19.1211C12.0616 18.6911 11.6843 18.3716 11.2539 18.4077C11.0178 18.4275 10.7773 18.4375 10.5391 18.4375C10.5325 18.4375 10.5261 18.4383 10.5195 18.4385C10.513 18.4383 10.5066 18.4375 10.5 18.4375C5.84754 18.4375 2.0625 14.6525 2.0625 10C2.0625 5.34754 5.84754 1.5625 10.5 1.5625C13.4984 1.5625 16.2561 3.16066 17.7631 5.70312H15.615C15.1835 5.70312 14.8337 6.05289 14.8337 6.48438C14.8337 6.91586 15.1835 7.26562 15.615 7.26562H18C18.4758 7.26562 18.9209 7.13191 19.2999 6.90027C19.3243 6.88637 19.3477 6.87141 19.37 6.85527C20.05 6.40797 20.5 5.63855 20.5 4.76562V2.46094C20.5 2.02945 20.1502 1.67969 19.7188 1.67969Z" fill="#D5D5D5"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
12
assets/icons/link.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Group 440">
|
||||||
|
<path id="Vector" d="M6.7986 0.892983L4.84001 2.85148C4.48185 3.20973 4.23182 3.63572 4.08964 4.08854C3.62464 4.23503 3.19865 4.49284 2.85148 4.84001L0.892983 6.7986C-0.29757 7.98915 -0.297753 9.91625 0.892983 11.107C2.08354 12.2976 4.01072 12.2977 5.20146 11.107L7.15996 9.14848C7.5182 8.79033 7.76814 8.36433 7.91032 7.91142C8.37541 7.76503 8.80132 7.50713 9.14848 7.15996L11.107 5.20146C12.2976 4.01081 12.2978 2.08372 11.107 0.892983C9.91643 -0.29757 7.98933 -0.297753 6.7986 0.892983ZM4.17735 6.1656C4.32576 6.5276 4.54658 6.86653 4.84001 7.15996C5.1251 7.44496 5.46431 7.67027 5.83418 7.82289L3.87577 9.78139C3.41893 10.2381 2.67552 10.2382 2.21867 9.78139C1.76182 9.32445 1.76182 8.58113 2.21867 8.12428L4.17717 6.16569C4.17726 6.16569 4.17726 6.16569 4.17735 6.1656ZM6.82854 8.81706L4.86995 10.7756C3.86259 11.783 2.23194 11.7831 1.2244 10.7756C0.216957 9.76821 0.216866 8.13747 1.2244 7.13002L3.1829 5.17143C3.41105 4.94328 3.67939 4.76082 3.9719 4.63255C3.92823 4.9897 3.94819 5.34263 4.02427 5.67991C3.96128 5.72697 3.90159 5.77843 3.84574 5.83427L1.88725 7.79277C1.24766 8.43245 1.24766 9.47313 1.88725 10.1127C2.52683 10.7523 3.56752 10.7523 4.2072 10.1127L6.16569 8.15422C6.80592 7.5139 6.80601 6.47459 6.16569 5.83427C5.82365 5.49223 5.74034 4.99492 5.90358 4.57753C6.24891 4.70598 6.56587 4.90876 6.82854 5.17143C7.8336 6.1765 7.83369 7.8119 6.82854 8.81706ZM10.7756 4.86995L8.81706 6.82854C8.58891 7.05669 8.32057 7.23915 8.02806 7.36742C8.07173 7.01027 8.05177 6.65733 7.97578 6.32005C8.03868 6.27299 8.09846 6.22154 8.15422 6.16569L10.1128 4.2072C10.7524 3.56761 10.7524 2.52683 10.1128 1.88725C9.5385 1.31303 8.64028 1.25379 7.99913 1.71229C7.89384 1.78755 7.86958 1.93394 7.94484 2.03922C8.0201 2.14451 8.16649 2.16886 8.27177 2.09352C8.73952 1.75907 9.37434 1.81162 9.78139 2.21867C10.2382 2.67552 10.2382 3.41883 9.78139 3.87577L7.8228 5.83427C7.8228 5.83427 7.8228 5.83427 7.82271 5.83436C7.67421 5.47236 7.45338 5.13344 7.15996 4.84001C6.87495 4.555 6.53566 4.32969 6.16578 4.17707L6.96431 3.37855C7.05577 3.28709 7.05577 3.13868 6.96431 3.04713C6.87276 2.95567 6.72444 2.95567 6.63289 3.04713L5.83427 3.84574C5.19404 4.48597 5.19395 5.52528 5.83427 6.16569C6.17631 6.50764 6.25963 7.00505 6.09639 7.42244C5.75105 7.29399 5.43409 7.0912 5.17143 6.82844C4.16645 5.82347 4.16636 4.18797 5.17143 3.1829L7.13002 1.2244C8.13737 0.216957 9.76811 0.216774 10.7756 1.2244C11.783 2.23176 11.7831 3.8625 10.7756 4.86995Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path id="Vector_2" d="M7.69571 2.55103C7.69571 2.68048 7.59079 2.7854 7.46143 2.7854C7.33197 2.7854 7.22705 2.68048 7.22705 2.55103C7.22705 2.42157 7.33197 2.31665 7.46143 2.31665C7.59079 2.31665 7.69571 2.42157 7.69571 2.55103Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path id="Vector_3" d="M3.18286 3.1831C3.27441 3.09164 3.27441 2.94323 3.18286 2.85168L2.18859 1.85741C2.09704 1.76595 1.94872 1.76595 1.85717 1.85741C1.76571 1.94897 1.76571 2.09737 1.85717 2.18893L2.85143 3.18319C2.94308 3.27465 3.09139 3.27465 3.18286 3.1831Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path id="Vector_4" d="M0.891022 3.9375C0.761658 3.9375 0.656738 4.04242 0.656738 4.17178C0.656738 4.30124 0.761658 4.40616 0.891022 4.40616H2.29718C2.42655 4.40616 2.53147 4.30124 2.53147 4.17178C2.53147 4.04242 2.42655 3.9375 2.29718 3.9375H0.891022Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path id="Vector_5" d="M3.93774 0.821289V2.22736C3.93774 2.35672 4.04266 2.46173 4.17203 2.46173C4.30148 2.46173 4.4064 2.35672 4.4064 2.22736V0.821289C4.4064 0.691834 4.30148 0.586914 4.17203 0.586914C4.04266 0.586914 3.93774 0.691834 3.93774 0.821289Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path id="Vector_6" d="M8.8172 8.81738C8.72565 8.90884 8.72565 9.05724 8.8172 9.1488L9.81146 10.1431C9.85724 10.1888 9.91721 10.2117 9.97717 10.2117C10.184 10.2117 10.291 9.95986 10.1429 9.81164L9.14862 8.81738C9.05707 8.72591 8.90875 8.72591 8.8172 8.81738Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path id="Vector_7" d="M8.03882 11.1785V9.77237C8.03882 9.64301 7.93381 9.53809 7.80444 9.53809C7.67499 9.53809 7.57007 9.64301 7.57007 9.77237V11.1785C7.57007 11.3079 7.67499 11.4128 7.80444 11.4128C7.93381 11.4128 8.03882 11.3079 8.03882 11.1785Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path id="Vector_8" d="M11.1793 8.03906C11.3086 8.03906 11.4135 7.93405 11.4135 7.80469C11.4135 7.67523 11.3086 7.57031 11.1793 7.57031H9.7731C9.64374 7.57031 9.53882 7.67523 9.53882 7.80469C9.53882 7.93405 9.64374 8.03906 9.7731 8.03906H11.1793Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.5 KiB |
BIN
assets/icons/rectangle_check_box.png
Normal file
After Width: | Height: | Size: 523 B |
4
assets/icons/search_icon_user.svg
Normal 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="M1.89852 11.08C-0.632759 8.54864 -0.632708 4.42983 1.89852 1.8985C4.42985 -0.632833 8.54861 -0.632833 11.0799 1.8985C13.2274 4.04599 13.5526 7.23986 12.0565 9.73392C12.0565 9.73392 11.949 9.91422 12.0942 10.0593C12.9222 10.8872 15.4065 13.3716 15.4065 13.3716C16.0658 14.0308 16.2227 14.9527 15.638 15.5374L15.5374 15.638C14.9527 16.2227 14.0308 16.0658 13.3716 15.4065C13.3716 15.4065 10.8926 12.9275 10.0662 12.1012C9.91414 11.9491 9.73389 12.0566 9.73389 12.0566C7.23988 13.5526 4.04601 13.2275 1.89852 11.08ZM9.88131 9.88133C11.7517 8.01094 11.7516 4.96763 9.88125 3.09724C8.01086 1.22689 4.96755 1.22684 3.09721 3.09724C1.22681 4.96758 1.22681 8.01094 3.09721 9.88133C4.9676 11.7516 8.01086 11.7516 9.88131 9.88133Z" fill="black" fill-opacity="0.3"/>
|
||||||
|
<path d="M9.46694 6.10386C9.554 6.10386 9.6425 6.08674 9.7278 6.05072C10.0686 5.9065 10.228 5.51333 10.0838 5.17253C9.17732 3.03045 6.69723 2.0252 4.5552 2.93164C4.21445 3.07586 4.05503 3.46903 4.19924 3.80983C4.34351 4.15063 4.73658 4.30995 5.07749 4.16579C6.53894 3.54737 8.2312 4.23326 8.84956 5.69471C8.95775 5.95031 9.20588 6.10386 9.46694 6.10386Z" fill="black" fill-opacity="0.3"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
9
assets/icons/space_delete.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M11.8069 19.9998H3.50035C2.16411 19.9998 1.08087 18.9165 1.08087 17.5804V4.51562H14.2262V17.5804C14.2262 18.9165 13.1432 19.9998 11.8069 19.9998Z" fill="#D8D8D8"/>
|
||||||
|
<path d="M1.08087 4.51562V5.48335H12.3715C12.8168 5.48335 13.1779 5.84438 13.1779 6.2898V17.3384C13.1779 18.2292 12.4557 18.9513 11.5649 18.9513H2.4519C2.05409 18.9513 1.67887 18.8547 1.34775 18.6844C1.74907 19.4652 2.56207 19.9998 3.50035 19.9998H11.8069C13.1432 19.9998 14.2262 18.9165 14.2262 17.5803V4.51562H1.08087Z" fill="#BABABA"/>
|
||||||
|
<path d="M14.2667 1.77417H10.7439L10.1633 0.612956C9.9742 0.234837 9.5941 0 9.17142 0H6.13594C5.71311 0 5.33316 0.234837 5.1441 0.612956L4.56349 1.77417H1.04063C0.595221 1.77417 0.234192 2.1352 0.234192 2.58061V3.70978C0.234192 4.15504 0.595221 4.51622 1.04063 4.51622H14.2667C14.7121 4.51622 15.0732 4.15504 15.0732 3.70978V2.58077C15.0732 2.1352 14.7121 1.77417 14.2667 1.77417ZM5.68503 0.8835C5.77094 0.71153 5.94368 0.604869 6.13594 0.604869H9.17142C9.36354 0.604869 9.53627 0.71153 9.62218 0.8835L10.0676 1.77417H5.23977L5.68503 0.8835Z" fill="#757575"/>
|
||||||
|
<path d="M14.2668 1.77441H12.9763C13.4217 1.77441 13.7829 2.13544 13.7829 2.58086V3.71003C13.7829 4.15529 13.4217 4.51647 12.9763 4.51647H14.2668C14.7122 4.51647 15.0732 4.15529 15.0732 3.71003V2.58101C15.0732 2.13544 14.7122 1.77441 14.2668 1.77441Z" fill="#595959"/>
|
||||||
|
<path d="M11.3634 17.5C10.918 17.5 10.5569 17.139 10.5569 16.6935V9.15312C10.5569 8.70771 10.918 8.34668 11.3634 8.34668C11.8088 8.34668 12.1698 8.70771 12.1698 9.15312V16.6935C12.1698 17.139 11.8088 17.5 11.3634 17.5Z" fill="#757575"/>
|
||||||
|
<path d="M3.94398 17.5C4.38924 17.5 4.75043 17.139 4.75043 16.6935V9.15312C4.75043 8.70771 4.38924 8.34668 3.94398 8.34668C3.49857 8.34668 3.13739 8.70771 3.13739 9.15312V16.6935C3.13739 17.139 3.49857 17.5 3.94398 17.5Z" fill="#757575"/>
|
||||||
|
<path d="M7.65361 17.5C7.2082 17.5 6.84717 17.139 6.84717 16.6935V9.15312C6.84717 8.70771 7.2082 8.34668 7.65361 8.34668C8.09902 8.34668 8.46005 8.70771 8.46005 9.15312V16.6935C8.46005 17.139 8.09902 17.5 7.65361 17.5Z" fill="#757575"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
3
assets/icons/uncompleate_process_icon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="10" cy="10" r="9" stroke="#D5D5D5" stroke-width="2"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 169 B |
7
assets/icons/user_management.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg width="20" height="18" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.5594 12.881L12.3006 12.1281C12.0363 12.04 11.8587 11.7935 11.8587 11.5148V10.3696C12.6718 9.84207 13.248 8.97922 13.39 7.97848C14.2092 7.32457 14.6768 6.35539 14.6768 5.30305C14.6768 3.83754 13.7513 2.5843 12.4541 2.0966C12.2658 0.898984 11.2171 0 10 0C8.78291 0 7.73424 0.899023 7.54592 2.0966C6.24877 2.5843 5.32323 3.83754 5.32323 5.30305C5.32323 6.35535 5.79088 7.32453 6.61002 7.97844C6.75209 8.97918 7.32826 9.84203 8.14139 10.3696V11.5148C8.14139 11.7935 7.96377 12.0399 7.6994 12.128L5.44061 12.881C4.8085 13.0917 4.38385 13.6809 4.38385 14.3471V17.202C4.38385 17.3638 4.51502 17.4949 4.67682 17.4949C4.83862 17.4949 4.96979 17.3638 4.96979 17.202V14.3471C4.96979 13.9335 5.23346 13.5677 5.62588 13.4368L6.35303 13.1945L6.12049 13.6595C5.99178 13.917 5.99178 14.2243 6.12049 14.4817L7.54612 17.333C7.59744 17.4356 7.70088 17.495 7.80838 17.495C7.8524 17.495 7.89709 17.485 7.93916 17.464C8.08389 17.3916 8.14256 17.2157 8.07018 17.071L6.64455 14.2197C6.59791 14.1264 6.59791 14.015 6.64455 13.9216L7.13842 12.9327L7.8599 12.6922L8.77334 17.2594C8.80119 17.3987 8.9235 17.495 9.06033 17.495C9.07936 17.495 9.09869 17.4931 9.11811 17.4893C9.27678 17.4575 9.37967 17.3032 9.34795 17.1445L8.53889 13.0992L9.7994 14.2841C9.85576 14.3371 9.92791 14.3637 10.0001 14.3637C10.0722 14.3637 10.1443 14.3371 10.2007 14.2841L11.4612 13.0992L10.6522 17.1445C10.6205 17.3032 10.7233 17.4575 10.882 17.4893C10.9014 17.4931 10.9207 17.495 10.9398 17.495C11.0766 17.495 11.1989 17.3987 11.2268 17.2594L12.1402 12.6922L12.8615 12.9326L13.3556 13.9216C13.4022 14.0149 13.4022 14.1264 13.3556 14.2197L11.9299 17.0709C11.8576 17.2157 11.9162 17.3916 12.061 17.464C12.103 17.485 12.1477 17.495 12.1917 17.495C12.2992 17.495 12.4027 17.4356 12.454 17.3329L13.8796 14.4817C14.0083 14.2243 14.0083 13.9169 13.8796 13.6595L13.6471 13.1944L14.3742 13.4368C14.7667 13.5676 15.0303 13.9334 15.0303 14.3471V17.2019C15.0303 17.3637 15.1615 17.4949 15.3233 17.4949C15.4851 17.4949 15.6163 17.3637 15.6163 17.2019V14.3471C15.6162 13.6809 15.1915 13.0917 14.5594 12.881ZM10 0.585938C10.8389 0.585938 11.5729 1.14453 11.8145 1.92516C11.6316 1.8948 11.4439 1.87875 11.2526 1.87875H8.74752C8.55616 1.87875 8.36846 1.8948 8.18557 1.92516C8.42717 1.14453 9.16119 0.585938 10 0.585938ZM7.1617 7.49496V6.81496C7.1617 6.32207 7.35365 5.85871 7.70213 5.5102C7.81655 5.39578 7.81655 5.21027 7.70213 5.0959C7.58772 4.98145 7.40221 4.98148 7.28783 5.0959C6.82865 5.55508 6.57576 6.16559 6.57576 6.815V7.13238C6.1469 6.62625 5.9092 5.98582 5.9092 5.30309C5.9092 4.4041 6.32983 3.60199 6.98401 3.08156C7.25975 3.67977 8.31428 5.55266 10.96 6.26395C10.9855 6.27078 11.011 6.27406 11.0362 6.27406C11.1655 6.27406 11.2838 6.18785 11.319 6.05707C11.361 5.90082 11.2684 5.74012 11.1121 5.69809C9.94037 5.38309 8.97006 4.78422 8.22811 3.91816C7.78147 3.39676 7.55647 2.92973 7.48393 2.76262C7.86475 2.57242 8.29369 2.46477 8.74752 2.46477H11.2526C12.8176 2.46477 14.0909 3.73805 14.0909 5.30313C14.0909 5.9859 13.8531 6.62637 13.4242 7.1325C13.4222 6.49598 12.9466 5.9716 12.3163 5.91195C12.1556 5.8966 12.0123 6.01492 11.9971 6.17602C11.9818 6.33711 12.1001 6.48004 12.2611 6.49527C12.5848 6.5259 12.8383 6.80758 12.8383 7.13656V7.49504C12.8383 9.06008 11.5651 10.3334 10 10.3334C8.43498 10.3334 7.1617 9.06 7.1617 7.49496ZM10 13.6686L8.48682 12.2461C8.63932 12.0393 8.72733 11.7852 8.72733 11.5148V10.6738C9.12096 10.832 9.55049 10.9192 10 10.9192C10.4496 10.9192 10.879 10.832 11.2727 10.6738V11.5148C11.2727 11.7852 11.3607 12.0393 11.5132 12.2461L10 13.6686Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path d="M3.4041 12.9931V12.6998C3.60836 12.7636 3.82551 12.798 4.05051 12.798C5.24801 12.798 6.22227 11.8238 6.22227 10.6263V10.426C6.42496 10.1822 6.53539 9.87822 6.53539 9.55721V9.37377C6.53539 8.34893 5.7016 7.51514 4.67676 7.51514H3.42426C2.39941 7.51514 1.56563 8.34889 1.56563 9.37377V9.55721C1.56563 9.87822 1.67605 10.1822 1.87875 10.426V10.6263C1.87875 11.3664 2.25113 12.0209 2.81812 12.4131V12.9931C2.81812 13.1368 2.72652 13.2638 2.59023 13.3092L1.05672 13.8204C0.424688 14.0311 0 14.6203 0 15.2866V17.202C0 17.3638 0.131172 17.495 0.292969 17.495C0.454766 17.495 0.585938 17.3638 0.585938 17.202V15.2866C0.585938 14.8729 0.849609 14.5071 1.24203 14.3763L2.33719 14.0112L3.26172 14.6276C3.31168 14.6609 3.36812 14.6768 3.42395 14.6768C3.51859 14.6768 3.61152 14.631 3.66797 14.5463C3.75773 14.4117 3.72137 14.2298 3.58672 14.1401L3.00359 13.7513C3.24984 13.5831 3.4041 13.3023 3.4041 12.9931ZM2.1516 9.37373C2.1516 8.67197 2.72254 8.10103 3.4243 8.10103H4.6768C5.37855 8.10103 5.94949 8.67197 5.94949 9.37373V9.55717C5.94949 9.70607 5.90723 9.84822 5.82945 9.971L3.20379 9.0958C3.11805 9.06725 3.02387 9.07982 2.94863 9.12998L2.15863 9.65662C2.15445 9.62385 2.15156 9.59076 2.15156 9.55717L2.1516 9.37373ZM2.46473 10.6263V10.1568L3.15445 9.69697L5.63637 10.5243V10.6262C5.63637 11.5006 4.92496 12.2121 4.05055 12.2121C3.17613 12.2121 2.46473 11.5007 2.46473 10.6263Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path d="M1.85864 15.6565C1.69685 15.6565 1.56567 15.7876 1.56567 15.9495V17.202C1.56567 17.3638 1.69685 17.4949 1.85864 17.4949C2.02044 17.4949 2.15161 17.3638 2.15161 17.202V15.9495C2.15161 15.7877 2.02044 15.6565 1.85864 15.6565Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path d="M18.9431 13.8204L17.4096 13.3092C17.2733 13.2638 17.1817 13.1367 17.1817 12.9931V12.4131C17.7487 12.0209 18.1211 11.3664 18.1211 10.6263V10.426C18.3238 10.1822 18.4342 9.87822 18.4342 9.55721V9.37377C18.4342 8.34893 17.6005 7.51514 16.5756 7.51514H15.3231C14.2983 7.51514 13.4645 8.34889 13.4645 9.37377V9.55721C13.4645 9.87822 13.5749 10.1822 13.7776 10.426V10.6263C13.7776 11.8238 14.7519 12.798 15.9494 12.798C16.1744 12.798 16.3915 12.7636 16.5958 12.6998V12.9931C16.5958 13.3023 16.75 13.5831 16.9962 13.7513L16.4131 14.1401C16.2785 14.2298 16.2421 14.4117 16.3319 14.5463C16.3883 14.631 16.4812 14.6768 16.5759 14.6768C16.6317 14.6768 16.6882 14.6609 16.7381 14.6276L17.6626 14.0112L18.7578 14.3763C19.1503 14.5071 19.414 14.8729 19.414 15.2866V17.202C19.414 17.3638 19.5451 17.495 19.7069 17.495C19.8687 17.495 19.9999 17.3638 19.9999 17.202V15.2866C19.9999 14.6203 19.5752 14.0311 18.9431 13.8204ZM14.0504 9.37373C14.0504 8.67197 14.6214 8.10103 15.3231 8.10103H16.5756C17.2774 8.10103 17.8483 8.67197 17.8483 9.37373V9.55717C17.8483 9.70607 17.806 9.84822 17.7283 9.971L15.1026 9.0958C15.0169 9.06725 14.9227 9.07982 14.8475 9.12998L14.0575 9.65662C14.0533 9.62381 14.0504 9.59072 14.0504 9.55717V9.37373ZM14.3635 10.6263V10.1568L15.0533 9.69697L17.5352 10.5243V10.6262C17.5352 11.5006 16.8238 12.2121 15.9494 12.2121C15.0749 12.2121 14.3635 11.5007 14.3635 10.6263Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path d="M18.1414 15.6565C17.9796 15.6565 17.8484 15.7876 17.8484 15.9495V17.202C17.8484 17.3638 17.9796 17.4949 18.1414 17.4949C18.3032 17.4949 18.4343 17.3638 18.4343 17.202V15.9495C18.4343 15.7877 18.3032 15.6565 18.1414 15.6565Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.9 KiB |
10
assets/icons/wrong_process_icon.svg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z" fill="#FFB09E"/>
|
||||||
|
<path d="M9.9999 0C9.79708 0 9.59588 0.00676056 9.39604 0.018672C14.6376 0.330986 18.5355 4.67996 18.5355 10C18.5355 15.32 14.6376 19.669 9.396 19.9813C9.59588 19.9932 9.79708 20 9.9999 20C15.5228 20 19.9999 15.5229 19.9999 10C19.9999 4.47714 15.5228 0 9.9999 0Z" fill="#FFA78F"/>
|
||||||
|
<path d="M10.0002 18.5355C14.7142 18.5355 18.5357 14.714 18.5357 9.99993C18.5357 5.28586 14.7142 1.46436 10.0002 1.46436C5.28611 1.46436 1.4646 5.28586 1.4646 9.99993C1.4646 14.714 5.28611 18.5355 10.0002 18.5355Z" fill="#F07281"/>
|
||||||
|
<path d="M10.0006 1.46436C9.79753 1.46436 9.59625 1.47196 9.39673 1.48588C13.829 1.79574 17.3284 5.48894 17.3284 9.99993C17.3284 14.511 13.829 18.2041 9.39673 18.514C9.59625 18.5279 9.79753 18.5355 10.0006 18.5355C14.7147 18.5355 18.5362 14.714 18.5362 9.99993C18.5362 5.28589 14.7147 1.46436 10.0006 1.46436Z" fill="#EB5569"/>
|
||||||
|
<path d="M14.074 12.1165L12.4961 10.5386C12.336 10.3786 12.336 10.119 12.4961 9.95887L14.074 8.38097C14.3867 8.06825 14.3867 7.56121 14.074 7.24849L13.0007 6.17521C12.688 5.86249 12.181 5.86249 11.8682 6.17521L10.2903 7.75312C10.1303 7.9132 9.8707 7.9132 9.71058 7.75312L8.13267 6.17521C7.81996 5.86249 7.31292 5.86249 7.0002 6.17521L5.92692 7.24849C5.6142 7.56121 5.6142 8.06825 5.92692 8.38097L7.50483 9.95887C7.66491 10.119 7.66491 10.3785 7.50483 10.5386L5.92692 12.1165C5.6142 12.4293 5.6142 12.9363 5.92692 13.249L7.0002 14.3223C7.31292 14.635 7.81996 14.635 8.13267 14.3223L9.71058 12.7444C9.87066 12.5843 10.1302 12.5843 10.2903 12.7444L11.8682 14.3223C12.181 14.635 12.688 14.635 13.0007 14.3223L14.074 13.249C14.3867 12.9363 14.3867 12.4293 14.074 12.1165Z" fill="#FFEEE6"/>
|
||||||
|
<path d="M7.36483 6.63131L9.01368 8.35767C9.17377 8.51775 9.43332 8.51775 9.59344 8.35767L10.0004 7.8732C9.89546 7.8732 9.79055 7.83316 9.71051 7.75312L8.1326 6.17521C7.81988 5.86249 7.31284 5.86249 7.00012 6.17521L6.77759 6.39775C6.98946 6.39223 7.2031 6.46958 7.36483 6.63131Z" fill="#FFDFCF"/>
|
||||||
|
<path d="M8.96663 12.2028L7.28639 13.9606C7.16578 14.0812 7.0162 14.1547 6.86011 14.1823L7.00011 14.3223C7.31282 14.6351 7.81987 14.6351 8.13258 14.3223L9.71049 12.7444C9.79053 12.6644 9.89544 12.6244 10.0003 12.6244L9.54635 12.2028C9.38627 12.0427 9.12671 12.0427 8.96663 12.2028Z" fill="#FFDFCF"/>
|
||||||
|
<path d="M12.496 10.5386C12.3359 10.3785 12.3359 10.119 12.496 9.95887L14.0739 8.38097C14.3866 8.06825 14.3866 7.56121 14.0739 7.24849L13.0006 6.17521C12.6879 5.86249 12.1809 5.86249 11.8682 6.17521L11.5521 6.49131C11.8061 6.44008 12.0802 6.51272 12.2772 6.70974L12.8662 7.24845C13.1789 7.56117 13.1789 8.06821 12.8662 8.38093L11.2883 9.95883C11.1282 10.1189 11.1282 10.3785 11.2883 10.5386L12.8662 12.1165C13.1789 12.4292 13.1789 12.9362 12.8662 13.2489L12.3243 13.7721C12.105 13.9914 11.7904 14.0563 11.514 13.968L11.8682 14.3222C12.1809 14.6349 12.6879 14.6349 13.0006 14.3222L14.0739 13.2489C14.3866 12.9362 14.3866 12.4292 14.0739 12.1165L12.496 10.5386Z" fill="#FFDFCF"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
BIN
assets/icons/ztoa_icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
1
firebase.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"flutter":{"platforms":{"android":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:android:2bc36fbe82994a3e0c7e6d","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:14346b200780dc760c7e6d","uploadDebugSymbols":true,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"macos":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:14346b200780dc760c7e6d","uploadDebugSymbols":true,"fileOutput":"macos/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"test2-8a3d2","configurations":{"android":"1:427332280600:android:2bc36fbe82994a3e0c7e6d","ios":"1:427332280600:ios:14346b200780dc760c7e6d","macos":"1:427332280600:ios:14346b200780dc760c7e6d","web":"1:427332280600:web:ad50516a87a35a1a0c7e6d","windows":"1:427332280600:web:f7a25537ccd5a7bd0c7e6d"}}}}}}
|
@ -15,6 +15,7 @@
|
|||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
E44A9405B1EB1B638DD05A58 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7ABF0EC746A2D686A0ED574F /* Pods_RunnerTests.framework */; };
|
E44A9405B1EB1B638DD05A58 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7ABF0EC746A2D686A0ED574F /* Pods_RunnerTests.framework */; };
|
||||||
|
F2A3345EC3021060731668D3 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B14AB50E8716720E10D074BD /* GoogleService-Info.plist */; };
|
||||||
FF49F60EC38658783D8D66DA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AFAE479A87ECDEBD5D6EB30 /* Pods_Runner.framework */; };
|
FF49F60EC38658783D8D66DA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AFAE479A87ECDEBD5D6EB30 /* Pods_Runner.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@ -64,6 +65,7 @@
|
|||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
B14AB50E8716720E10D074BD /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||||
D3AD250AADBF93406007C9EB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
D3AD250AADBF93406007C9EB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@ -138,6 +140,7 @@
|
|||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
1454C118FFCECEEDF59152D2 /* Pods */,
|
1454C118FFCECEEDF59152D2 /* Pods */,
|
||||||
20A3C64D2B1CFED5A81C3251 /* Frameworks */,
|
20A3C64D2B1CFED5A81C3251 /* Frameworks */,
|
||||||
|
B14AB50E8716720E10D074BD /* GoogleService-Info.plist */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -199,6 +202,7 @@
|
|||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
33590C9CD073D3D5EBA02CDE /* [CP] Embed Pods Frameworks */,
|
33590C9CD073D3D5EBA02CDE /* [CP] Embed Pods Frameworks */,
|
||||||
|
7A77858F6F15CB76D2D3A872 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -264,6 +268,7 @@
|
|||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||||
|
F2A3345EC3021060731668D3 /* GoogleService-Info.plist in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -303,6 +308,24 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
};
|
};
|
||||||
|
7A77858F6F15CB76D2D3A872 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "FlutterFire: \"flutterfire upload-crashlytics-symbols\"";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\n#!/bin/bash\nPATH=\"${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin\"\nflutterfire upload-crashlytics-symbols --upload-symbols-script-path=\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --platform=ios --apple-project-path=\"${SRCROOT}\" --env-platform-name=\"${PLATFORM_NAME}\" --env-configuration=\"${CONFIGURATION}\" --env-project-dir=\"${PROJECT_DIR}\" --env-built-products-dir=\"${BUILT_PRODUCTS_DIR}\" --env-dwarf-dsym-folder-path=\"${DWARF_DSYM_FOLDER_PATH}\" --env-dwarf-dsym-file-name=\"${DWARF_DSYM_FILE_NAME}\" --env-infoplist-path=\"${INFOPLIST_PATH}\" --default-config=default\n";
|
||||||
|
};
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
|
32
ios/Runner/GoogleService-Info.plist
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>API_KEY</key>
|
||||||
|
<string>AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw</string>
|
||||||
|
<key>GCM_SENDER_ID</key>
|
||||||
|
<string>427332280600</string>
|
||||||
|
<key>PLIST_VERSION</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>BUNDLE_ID</key>
|
||||||
|
<string>com.example.syncrowWeb</string>
|
||||||
|
<key>PROJECT_ID</key>
|
||||||
|
<string>test2-8a3d2</string>
|
||||||
|
<key>STORAGE_BUCKET</key>
|
||||||
|
<string>test2-8a3d2.firebasestorage.app</string>
|
||||||
|
<key>IS_ADS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_ANALYTICS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_APPINVITE_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_GCM_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_SIGNIN_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>GOOGLE_APP_ID</key>
|
||||||
|
<string>1:427332280600:ios:14346b200780dc760c7e6d</string>
|
||||||
|
<key>DATABASE_URL</key>
|
||||||
|
<string>https://test2-8a3d2-default-rtdb.firebaseio.com</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
138
lib/common/dialog_dropdown.dart
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class DialogDropdown extends StatefulWidget {
|
||||||
|
final List<String> items;
|
||||||
|
final ValueChanged<String> onSelected;
|
||||||
|
final String? selectedValue;
|
||||||
|
|
||||||
|
const DialogDropdown({
|
||||||
|
Key? key,
|
||||||
|
required this.items,
|
||||||
|
required this.onSelected,
|
||||||
|
this.selectedValue,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_DialogDropdownState createState() => _DialogDropdownState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DialogDropdownState extends State<DialogDropdown> {
|
||||||
|
bool _isOpen = false;
|
||||||
|
late OverlayEntry _overlayEntry;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _toggleDropdown() {
|
||||||
|
if (_isOpen) {
|
||||||
|
_closeDropdown();
|
||||||
|
} else {
|
||||||
|
_openDropdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _openDropdown() {
|
||||||
|
_overlayEntry = _createOverlayEntry();
|
||||||
|
Overlay.of(context).insert(_overlayEntry);
|
||||||
|
_isOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _closeDropdown() {
|
||||||
|
_overlayEntry.remove();
|
||||||
|
_isOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayEntry _createOverlayEntry() {
|
||||||
|
final renderBox = context.findRenderObject() as RenderBox;
|
||||||
|
final size = renderBox.size;
|
||||||
|
final offset = renderBox.localToGlobal(Offset.zero);
|
||||||
|
|
||||||
|
return OverlayEntry(
|
||||||
|
builder: (context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
_closeDropdown();
|
||||||
|
},
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
left: offset.dx,
|
||||||
|
top: offset.dy + size.height,
|
||||||
|
width: size.width,
|
||||||
|
child: Material(
|
||||||
|
elevation: 4.0,
|
||||||
|
child: Container(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxHeight: 200.0, // Set max height for dropdown
|
||||||
|
),
|
||||||
|
child: ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: widget.items.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final item = widget.items[index];
|
||||||
|
return Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: ColorsManager.lightGrayBorderColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(
|
||||||
|
item,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(
|
||||||
|
color: ColorsManager.textPrimaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
widget.onSelected(item);
|
||||||
|
_closeDropdown();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: _toggleDropdown,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: ColorsManager.transparentColor),
|
||||||
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.selectedValue ?? 'Select an item',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
const Icon(Icons.arrow_drop_down),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
160
lib/common/dialog_textfield_dropdown.dart
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class DialogTextfieldDropdown extends StatefulWidget {
|
||||||
|
final List<String> items;
|
||||||
|
final ValueChanged<String> onSelected;
|
||||||
|
final String? initialValue;
|
||||||
|
|
||||||
|
const DialogTextfieldDropdown({
|
||||||
|
Key? key,
|
||||||
|
required this.items,
|
||||||
|
required this.onSelected,
|
||||||
|
this.initialValue,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_DialogTextfieldDropdownState createState() =>
|
||||||
|
_DialogTextfieldDropdownState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||||
|
bool _isOpen = false;
|
||||||
|
late OverlayEntry _overlayEntry;
|
||||||
|
final TextEditingController _controller = TextEditingController();
|
||||||
|
late List<String> _filteredItems; // Filtered items list
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller.text = widget.initialValue ?? 'Select Tag';
|
||||||
|
_filteredItems = List.from(widget.items); // Initialize filtered items
|
||||||
|
}
|
||||||
|
|
||||||
|
void _toggleDropdown() {
|
||||||
|
if (_isOpen) {
|
||||||
|
_closeDropdown();
|
||||||
|
} else {
|
||||||
|
_openDropdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _openDropdown() {
|
||||||
|
_overlayEntry = _createOverlayEntry();
|
||||||
|
Overlay.of(context).insert(_overlayEntry);
|
||||||
|
_isOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _closeDropdown() {
|
||||||
|
_overlayEntry.remove();
|
||||||
|
_isOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayEntry _createOverlayEntry() {
|
||||||
|
final renderBox = context.findRenderObject() as RenderBox;
|
||||||
|
final size = renderBox.size;
|
||||||
|
final offset = renderBox.localToGlobal(Offset.zero);
|
||||||
|
|
||||||
|
return OverlayEntry(
|
||||||
|
builder: (context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
_closeDropdown();
|
||||||
|
},
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
left: offset.dx,
|
||||||
|
top: offset.dy + size.height,
|
||||||
|
width: size.width,
|
||||||
|
child: Material(
|
||||||
|
elevation: 4.0,
|
||||||
|
child: Container(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxHeight: 200.0,
|
||||||
|
),
|
||||||
|
child: ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: _filteredItems.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final item = _filteredItems[index];
|
||||||
|
return Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: ColorsManager.lightGrayBorderColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(item,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(
|
||||||
|
color: ColorsManager.textPrimaryColor)),
|
||||||
|
onTap: () {
|
||||||
|
_controller.text = item;
|
||||||
|
widget.onSelected(item);
|
||||||
|
setState(() {
|
||||||
|
_filteredItems
|
||||||
|
.remove(item); // Remove selected item
|
||||||
|
});
|
||||||
|
_closeDropdown();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: _toggleDropdown,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: ColorsManager.transparentColor),
|
||||||
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextFormField(
|
||||||
|
controller: _controller,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_filteredItems = widget.items
|
||||||
|
.where((item) =>
|
||||||
|
item.toLowerCase().contains(value.toLowerCase()))
|
||||||
|
.toList(); // Filter items dynamically
|
||||||
|
});
|
||||||
|
widget.onSelected(value);
|
||||||
|
},
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: 'Enter or Select tag',
|
||||||
|
border: InputBorder.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Icon(Icons.arrow_drop_down),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
39
lib/common/edit_chip.dart
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class EditChip extends StatelessWidget {
|
||||||
|
final String label;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final Color labelColor;
|
||||||
|
final Color backgroundColor;
|
||||||
|
final Color borderColor;
|
||||||
|
final double borderRadius;
|
||||||
|
|
||||||
|
const EditChip({
|
||||||
|
Key? key,
|
||||||
|
this.label = 'Edit',
|
||||||
|
required this.onTap,
|
||||||
|
this.labelColor = ColorsManager.spaceColor,
|
||||||
|
this.backgroundColor = ColorsManager.whiteColors,
|
||||||
|
this.borderColor = ColorsManager.spaceColor,
|
||||||
|
this.borderRadius = 16.0,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Chip(
|
||||||
|
label: Text(
|
||||||
|
label,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: labelColor)
|
||||||
|
),
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(borderRadius),
|
||||||
|
side: BorderSide(color: borderColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -46,10 +46,9 @@ class CustomSearchBar extends StatelessWidget {
|
|||||||
filled: true,
|
filled: true,
|
||||||
fillColor: ColorsManager.textFieldGreyColor,
|
fillColor: ColorsManager.textFieldGreyColor,
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
hintStyle: TextStyle(
|
hintStyle: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||||
color: Color(0xB2999999),
|
color: ColorsManager.lightGrayColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontFamily: 'Aftika',
|
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
height: 0,
|
height: 0,
|
||||||
letterSpacing: -0.24,
|
letterSpacing: -0.24,
|
25
lib/common/widgets/spaces_side_tree.dart
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||||
|
|
||||||
|
class SpacesSideTree extends StatefulWidget {
|
||||||
|
final List<CommunityModel> communities;
|
||||||
|
final String? selectedSpaceUuid;
|
||||||
|
const SpacesSideTree({
|
||||||
|
super.key,
|
||||||
|
required this.communities,
|
||||||
|
this.selectedSpaceUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SpacesSideTree> createState() => _SpacesSideTreeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SpacesSideTreeState extends State<SpacesSideTree> {
|
||||||
|
String _searchQuery = '';
|
||||||
|
String? _selectedSpaceUuid;
|
||||||
|
String? _selectedId;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const Placeholder();
|
||||||
|
}
|
||||||
|
}
|
93
lib/firebase_options_dev.dart
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// File generated by FlutterFire CLI.
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||||
|
import 'package:flutter/foundation.dart'
|
||||||
|
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||||
|
|
||||||
|
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// import 'firebase_options.dart';
|
||||||
|
/// // ...
|
||||||
|
/// await Firebase.initializeApp(
|
||||||
|
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
class DefaultFirebaseOptionsDev {
|
||||||
|
static FirebaseOptions get currentPlatform {
|
||||||
|
if (kIsWeb) {
|
||||||
|
return web;
|
||||||
|
}
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
return android;
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
return ios;
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
return macos;
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
return windows;
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions have not been configured for linux - '
|
||||||
|
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions are not supported for this platform.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const FirebaseOptions web = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyCVEvKsJYzhWDFM-9Od68FE0nPpP933st0',
|
||||||
|
appId: '1:427332280600:web:ad50516a87a35a1a0c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
authDomain: 'test2-8a3d2.firebaseapp.com',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
measurementId: 'G-Z1RTTTV5H9',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions android = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0',
|
||||||
|
appId: '1:427332280600:android:2bc36fbe82994a3e0c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions ios = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw',
|
||||||
|
appId: '1:427332280600:ios:14346b200780dc760c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
iosBundleId: 'com.example.syncrowWeb',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions macos = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw',
|
||||||
|
appId: '1:427332280600:ios:14346b200780dc760c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
iosBundleId: 'com.example.syncrowWeb',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions windows = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyDizKjPC5rdkEjDxwXjM-RU5unB0Ziq3iw',
|
||||||
|
appId: '1:427332280600:web:f7a25537ccd5a7bd0c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
authDomain: 'test2-8a3d2.firebaseapp.com',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
measurementId: 'G-4LFVXEXWKY',
|
||||||
|
);
|
||||||
|
}
|
77
lib/firebase_options_prod.dart
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// File generated by FlutterFire CLI.
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||||
|
import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||||
|
|
||||||
|
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// import 'firebase_options.dart';
|
||||||
|
/// // ...
|
||||||
|
/// await Firebase.initializeApp(
|
||||||
|
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
class DefaultFirebaseOptionsStaging {
|
||||||
|
static FirebaseOptions get currentPlatform {
|
||||||
|
if (kIsWeb) {
|
||||||
|
return web;
|
||||||
|
}
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
return android;
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
return ios;
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions have not been configured for macos - '
|
||||||
|
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||||
|
);
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions have not been configured for windows - '
|
||||||
|
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||||
|
);
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions have not been configured for linux - '
|
||||||
|
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions are not supported for this platform.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const FirebaseOptions android = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyDP9GpYfLE8gHTj3kZ1hW8fx_FkJqOqSQk',
|
||||||
|
appId: '1:786692570726:android:0ef7079c2b978d4417b7a7',
|
||||||
|
messagingSenderId: '786692570726',
|
||||||
|
projectId: 'syncrow-staging',
|
||||||
|
databaseURL: 'https://syncrow-staging-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'syncrow-staging.appspot.com',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions ios = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyAWlRiuJ75FMlf2_UDdri1voWKvkaSHtRg',
|
||||||
|
appId: '1:786692570726:ios:455a6fcff77e130f17b7a7',
|
||||||
|
messagingSenderId: '786692570726',
|
||||||
|
projectId: 'syncrow-staging',
|
||||||
|
databaseURL: 'https://syncrow-staging-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'syncrow-staging.appspot.com',
|
||||||
|
iosBundleId: 'com.example.syncrow.app',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions web = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyDyGaQ3sZhb4meaY6sGke-YglhdhJ2is8Q',
|
||||||
|
appId: '1:786692570726:web:93c931e6701797b317b7a7',
|
||||||
|
messagingSenderId: '786692570726',
|
||||||
|
projectId: 'syncrow-staging',
|
||||||
|
authDomain: 'syncrow-staging.firebaseapp.com',
|
||||||
|
databaseURL: 'https://syncrow-staging-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'syncrow-staging.appspot.com',
|
||||||
|
measurementId: 'G-CZ3J3G6LMQ',
|
||||||
|
);
|
||||||
|
}
|
@ -1,12 +1,17 @@
|
|||||||
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:syncrow_web/firebase_options_dev.dart';
|
||||||
|
import 'package:syncrow_web/firebase_options_prod.dart';
|
||||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
||||||
import 'package:syncrow_web/services/locator.dart';
|
import 'package:syncrow_web/services/locator.dart';
|
||||||
import 'package:syncrow_web/utils/app_routes.dart';
|
import 'package:syncrow_web/utils/app_routes.dart';
|
||||||
@ -16,9 +21,12 @@ import 'package:syncrow_web/utils/theme/theme.dart';
|
|||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
try {
|
try {
|
||||||
const environment =
|
const environment =
|
||||||
String.fromEnvironment('FLAVOR', defaultValue: 'development');
|
String.fromEnvironment('FLAVOR', defaultValue: 'production');
|
||||||
await dotenv.load(fileName: '.env.$environment');
|
await dotenv.load(fileName: '.env.$environment');
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await Firebase.initializeApp(
|
||||||
|
options: DefaultFirebaseOptionsStaging.currentPlatform,
|
||||||
|
);
|
||||||
initialSetup();
|
initialSetup();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
runApp(MyApp());
|
runApp(MyApp());
|
||||||
@ -56,6 +64,9 @@ class MyApp extends StatelessWidget {
|
|||||||
BlocProvider<RoutineBloc>(
|
BlocProvider<RoutineBloc>(
|
||||||
create: (context) => RoutineBloc(),
|
create: (context) => RoutineBloc(),
|
||||||
),
|
),
|
||||||
|
BlocProvider<SpaceTreeBloc>(
|
||||||
|
create: (context) => SpaceTreeBloc()..add(InitialEvent()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
child: MaterialApp.router(
|
child: MaterialApp.router(
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
|
84
lib/main_dev.dart
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:syncrow_web/firebase_options_dev.dart';
|
||||||
|
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
||||||
|
import 'package:syncrow_web/services/locator.dart';
|
||||||
|
import 'package:syncrow_web/utils/app_routes.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||||
|
import 'package:syncrow_web/utils/theme/theme.dart';
|
||||||
|
|
||||||
|
Future<void> main() async {
|
||||||
|
try {
|
||||||
|
const environment =
|
||||||
|
String.fromEnvironment('FLAVOR', defaultValue: 'development');
|
||||||
|
await dotenv.load(fileName: '.env.$environment');
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await Firebase.initializeApp(
|
||||||
|
options: DefaultFirebaseOptionsDev.currentPlatform,
|
||||||
|
);
|
||||||
|
initialSetup();
|
||||||
|
} catch (_) {}
|
||||||
|
runApp(MyApp());
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
|
MyApp({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final GoRouter _router = GoRouter(
|
||||||
|
initialLocation: RoutesConst.auth,
|
||||||
|
routes: AppRoutes.getRoutes(),
|
||||||
|
redirect: (context, state) async {
|
||||||
|
String checkToken = await AuthBloc.getTokenAndValidate();
|
||||||
|
final loggedIn = checkToken == 'Success';
|
||||||
|
final goingToLogin = state.uri.toString() == RoutesConst.auth;
|
||||||
|
|
||||||
|
if (!loggedIn && !goingToLogin) return RoutesConst.auth;
|
||||||
|
if (loggedIn && goingToLogin) return RoutesConst.home;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MultiBlocProvider(
|
||||||
|
providers: [
|
||||||
|
BlocProvider(
|
||||||
|
create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
||||||
|
BlocProvider<VisitorPasswordBloc>(
|
||||||
|
create: (context) => VisitorPasswordBloc(),
|
||||||
|
),
|
||||||
|
BlocProvider<RoutineBloc>(
|
||||||
|
create: (context) => RoutineBloc(),
|
||||||
|
),
|
||||||
|
BlocProvider<SpaceTreeBloc>(
|
||||||
|
create: (context) => SpaceTreeBloc()..add(InitialEvent()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: MaterialApp.router(
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
scrollBehavior: const MaterialScrollBehavior().copyWith(
|
||||||
|
dragDevices: {
|
||||||
|
PointerDeviceKind.mouse,
|
||||||
|
PointerDeviceKind.touch,
|
||||||
|
PointerDeviceKind.stylus,
|
||||||
|
PointerDeviceKind.unknown,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
theme: myTheme,
|
||||||
|
routerConfig: _router,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ import 'package:syncrow_web/utils/constants/assets.dart';
|
|||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||||
@ -27,19 +28,19 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
final isLargeScreen = isLargeScreenSize(context);
|
final isLargeScreen = isLargeScreenSize(context);
|
||||||
final isSmallScreen = isSmallScreenSize(context);
|
final isSmallScreen = isSmallScreenSize(context);
|
||||||
final isHalfMediumScreen = isHafMediumScreenSize(context);
|
final isHalfMediumScreen = isHafMediumScreenSize(context);
|
||||||
final padding = isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
final padding =
|
||||||
|
isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
||||||
|
|
||||||
return WebScaffold(
|
return WebScaffold(
|
||||||
enableMenuSidebar: false,
|
enableMenuSidebar: false,
|
||||||
appBarTitle: FittedBox(
|
appBarTitle: Text(
|
||||||
child: Text(
|
|
||||||
'Access Management',
|
'Access Management',
|
||||||
style: Theme.of(context).textTheme.headlineLarge,
|
style: ResponsiveTextTheme.of(context).deviceManagementTitle,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
rightBody: const NavigateHomeGridView(),
|
rightBody: const NavigateHomeGridView(),
|
||||||
scaffoldBody: BlocProvider(
|
scaffoldBody: BlocProvider(
|
||||||
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
|
create: (BuildContext context) =>
|
||||||
|
AccessBloc()..add(FetchTableData()),
|
||||||
child: BlocConsumer<AccessBloc, AccessState>(
|
child: BlocConsumer<AccessBloc, AccessState>(
|
||||||
listener: (context, state) {},
|
listener: (context, state) {},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
@ -93,11 +94,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
return [
|
return [
|
||||||
item.passwordName,
|
item.passwordName,
|
||||||
item.passwordType.value,
|
item.passwordType.value,
|
||||||
accessBloc.timestampToDate(item.effectiveTime),
|
accessBloc
|
||||||
accessBloc.timestampToDate(item.invalidTime),
|
.timestampToDate(item.effectiveTime),
|
||||||
|
accessBloc
|
||||||
|
.timestampToDate(item.invalidTime),
|
||||||
item.deviceName.toString(),
|
item.deviceName.toString(),
|
||||||
item.authorizerEmail.toString(),
|
item.authorizerEmail.toString(),
|
||||||
accessBloc.timestampToDate(item.invalidTime),
|
accessBloc
|
||||||
|
.timestampToDate(item.invalidTime),
|
||||||
item.passwordStatus.value,
|
item.passwordStatus.value,
|
||||||
];
|
];
|
||||||
}).toList(),
|
}).toList(),
|
||||||
@ -108,7 +112,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
Wrap _buildVisitorAdminPasswords(BuildContext context, AccessBloc accessBloc) {
|
Wrap _buildVisitorAdminPasswords(
|
||||||
|
BuildContext context, AccessBloc accessBloc) {
|
||||||
return Wrap(
|
return Wrap(
|
||||||
spacing: 10,
|
spacing: 10,
|
||||||
runSpacing: 10,
|
runSpacing: 10,
|
||||||
@ -134,7 +139,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Create Visitor Password ',
|
'Create Visitor Password ',
|
||||||
style: context.textTheme.titleSmall!.copyWith(color: Colors.white, fontSize: 12),
|
style: context.textTheme.titleSmall!
|
||||||
|
.copyWith(color: Colors.white, fontSize: 12),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
// Container(
|
// Container(
|
||||||
@ -172,8 +178,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
description: '',
|
description: '',
|
||||||
onSubmitted: (value) {
|
onSubmitted: (value) {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer:
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
@ -191,8 +199,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
description: '',
|
description: '',
|
||||||
onSubmitted: (value) {
|
onSubmitted: (value) {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer:
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
@ -221,7 +231,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
onSearch: () {
|
onSearch: () {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
@ -249,8 +260,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
description: '',
|
description: '',
|
||||||
onSubmitted: (value) {
|
onSubmitted: (value) {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer:
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
@ -274,7 +287,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
onSearch: () {
|
onSearch: () {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
|
@ -31,7 +31,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
|
|
||||||
////////////////////////////// forget password //////////////////////////////////
|
////////////////////////////// forget password //////////////////////////////////
|
||||||
final TextEditingController forgetEmailController = TextEditingController();
|
final TextEditingController forgetEmailController = TextEditingController();
|
||||||
final TextEditingController forgetPasswordController = TextEditingController();
|
final TextEditingController forgetPasswordController =
|
||||||
|
TextEditingController();
|
||||||
final TextEditingController forgetOtp = TextEditingController();
|
final TextEditingController forgetOtp = TextEditingController();
|
||||||
final forgetFormKey = GlobalKey<FormState>();
|
final forgetFormKey = GlobalKey<FormState>();
|
||||||
final forgetEmailKey = GlobalKey<FormState>();
|
final forgetEmailKey = GlobalKey<FormState>();
|
||||||
@ -48,7 +49,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_remainingTime = 1;
|
_remainingTime = 1;
|
||||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
add(UpdateTimerEvent(
|
||||||
|
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||||
try {
|
try {
|
||||||
forgetEmailValidate = '';
|
forgetEmailValidate = '';
|
||||||
_remainingTime = (await AuthenticationAPI.sendOtp(
|
_remainingTime = (await AuthenticationAPI.sendOtp(
|
||||||
@ -85,7 +87,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
|
add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
|
||||||
} else {
|
} else {
|
||||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
add(UpdateTimerEvent(
|
||||||
|
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -95,7 +98,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
|
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> changePassword(ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
Future<void> changePassword(
|
||||||
|
ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
||||||
emit(LoadingForgetState());
|
emit(LoadingForgetState());
|
||||||
try {
|
try {
|
||||||
var response = await AuthenticationAPI.verifyOtp(
|
var response = await AuthenticationAPI.verifyOtp(
|
||||||
@ -111,7 +115,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
}
|
}
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
final errorData = e.response!.data;
|
final errorData = e.response!.data;
|
||||||
String errorMessage = errorData['error']['message'] ?? 'something went wrong';
|
String errorMessage =
|
||||||
|
errorData['error']['message'] ?? 'something went wrong';
|
||||||
validate = errorMessage;
|
validate = errorMessage;
|
||||||
emit(AuthInitialState());
|
emit(AuthInitialState());
|
||||||
}
|
}
|
||||||
@ -125,7 +130,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onUpdateTimer(UpdateTimerEvent event, Emitter<AuthState> emit) {
|
void _onUpdateTimer(UpdateTimerEvent event, Emitter<AuthState> emit) {
|
||||||
emit(TimerState(isButtonEnabled: event.isButtonEnabled, remainingTime: event.remainingTime));
|
emit(TimerState(
|
||||||
|
isButtonEnabled: event.isButtonEnabled,
|
||||||
|
remainingTime: event.remainingTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////// login /////////////////////////////////////
|
///////////////////////////////////// login /////////////////////////////////////
|
||||||
@ -161,15 +168,23 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
password: event.password,
|
password: event.password,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (failure) {
|
} on DioException catch (e) {
|
||||||
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage = errorData['error']['message'];
|
||||||
|
if (errorMessage == "Access denied for web platform") {
|
||||||
|
validate = errorMessage;
|
||||||
|
} else {
|
||||||
validate = 'Invalid Credentials!';
|
validate = 'Invalid Credentials!';
|
||||||
|
}
|
||||||
emit(LoginInitial());
|
emit(LoginInitial());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (token.accessTokenIsNotEmpty) {
|
if (token.accessTokenIsNotEmpty) {
|
||||||
FlutterSecureStorage storage = const FlutterSecureStorage();
|
FlutterSecureStorage storage = const FlutterSecureStorage();
|
||||||
await storage.write(key: Token.loginAccessTokenKey, value: token.accessToken);
|
await storage.write(
|
||||||
|
key: Token.loginAccessTokenKey, value: token.accessToken);
|
||||||
const FlutterSecureStorage().write(
|
const FlutterSecureStorage().write(
|
||||||
key: UserModel.userUuidKey,
|
key: UserModel.userUuidKey,
|
||||||
value: Token.decodeToken(token.accessToken)['uuid'].toString());
|
value: Token.decodeToken(token.accessToken)['uuid'].toString());
|
||||||
@ -327,12 +342,14 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
static Future<String> getTokenAndValidate() async {
|
static Future<String> getTokenAndValidate() async {
|
||||||
try {
|
try {
|
||||||
const storage = FlutterSecureStorage();
|
const storage = FlutterSecureStorage();
|
||||||
final firstLaunch =
|
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
|
||||||
await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true;
|
StringsManager.firstLaunch) ??
|
||||||
|
true;
|
||||||
if (firstLaunch) {
|
if (firstLaunch) {
|
||||||
storage.deleteAll();
|
storage.deleteAll();
|
||||||
}
|
}
|
||||||
await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false);
|
await SharedPreferencesHelper.saveBoolToSP(
|
||||||
|
StringsManager.firstLaunch, false);
|
||||||
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
|
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
|
||||||
if (value.isEmpty) {
|
if (value.isEmpty) {
|
||||||
return 'Token not found';
|
return 'Token not found';
|
||||||
@ -385,7 +402,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
final String formattedTime = [
|
final String formattedTime = [
|
||||||
if (days > 0) '${days}d', // Append 'd' for days
|
if (days > 0) '${days}d', // Append 'd' for days
|
||||||
if (days > 0 || hours > 0)
|
if (days > 0 || hours > 0)
|
||||||
hours.toString().padLeft(2, '0'), // Show hours if there are days or hours
|
hours
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, '0'), // Show hours if there are days or hours
|
||||||
minutes.toString().padLeft(2, '0'),
|
minutes.toString().padLeft(2, '0'),
|
||||||
seconds.toString().padLeft(2, '0'),
|
seconds.toString().padLeft(2, '0'),
|
||||||
].join(':');
|
].join(':');
|
||||||
|
@ -21,7 +21,9 @@ class LoginWithEmailModel {
|
|||||||
return {
|
return {
|
||||||
'email': email,
|
'email': email,
|
||||||
'password': password,
|
'password': password,
|
||||||
|
"platform": "web"
|
||||||
// 'regionUuid': regionUuid,
|
// 'regionUuid': regionUuid,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//tst@tst.com
|
@ -10,6 +10,10 @@ class UserModel {
|
|||||||
final String? phoneNumber;
|
final String? phoneNumber;
|
||||||
final bool? isEmailVerified;
|
final bool? isEmailVerified;
|
||||||
final bool? isAgreementAccepted;
|
final bool? isAgreementAccepted;
|
||||||
|
final bool? hasAcceptedWebAgreement;
|
||||||
|
final DateTime? webAgreementAcceptedAt;
|
||||||
|
final UserRole? role;
|
||||||
|
|
||||||
UserModel({
|
UserModel({
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
required this.email,
|
required this.email,
|
||||||
@ -19,6 +23,9 @@ class UserModel {
|
|||||||
required this.phoneNumber,
|
required this.phoneNumber,
|
||||||
required this.isEmailVerified,
|
required this.isEmailVerified,
|
||||||
required this.isAgreementAccepted,
|
required this.isAgreementAccepted,
|
||||||
|
required this.hasAcceptedWebAgreement,
|
||||||
|
required this.webAgreementAcceptedAt,
|
||||||
|
required this.role,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory UserModel.fromJson(Map<String, dynamic> json) {
|
factory UserModel.fromJson(Map<String, dynamic> json) {
|
||||||
@ -31,6 +38,11 @@ class UserModel {
|
|||||||
phoneNumber: json['phoneNumber'],
|
phoneNumber: json['phoneNumber'],
|
||||||
isEmailVerified: json['isEmailVerified'],
|
isEmailVerified: json['isEmailVerified'],
|
||||||
isAgreementAccepted: json['isAgreementAccepted'],
|
isAgreementAccepted: json['isAgreementAccepted'],
|
||||||
|
hasAcceptedWebAgreement: json['hasAcceptedWebAgreement'],
|
||||||
|
webAgreementAcceptedAt: json['webAgreementAcceptedAt'] != null
|
||||||
|
? DateTime.parse(json['webAgreementAcceptedAt'])
|
||||||
|
: null,
|
||||||
|
role: json['role'] != null ? UserRole.fromJson(json['role']) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +53,9 @@ class UserModel {
|
|||||||
Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken);
|
Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken);
|
||||||
|
|
||||||
return UserModel(
|
return UserModel(
|
||||||
|
hasAcceptedWebAgreement: null,
|
||||||
|
role: null,
|
||||||
|
webAgreementAcceptedAt: null,
|
||||||
uuid: tempJson['uuid'].toString(),
|
uuid: tempJson['uuid'].toString(),
|
||||||
email: tempJson['email'],
|
email: tempJson['email'],
|
||||||
firstName: null,
|
firstName: null,
|
||||||
@ -65,3 +80,26 @@ class UserModel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UserRole {
|
||||||
|
final String uuid;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final String type;
|
||||||
|
|
||||||
|
UserRole({
|
||||||
|
required this.uuid,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.type,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory UserRole.fromJson(Map<String, dynamic> json) {
|
||||||
|
return UserRole(
|
||||||
|
uuid: json['uuid'],
|
||||||
|
createdAt: DateTime.parse(json['createdAt']),
|
||||||
|
updatedAt: DateTime.parse(json['updatedAt']),
|
||||||
|
type: json['type'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,6 +8,8 @@ class ForgetPasswordPage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const ResponsiveLayout(
|
return const ResponsiveLayout(
|
||||||
desktopBody: ForgetPasswordWebPage(), mobileBody: ForgetPasswordWebPage());
|
tablet: ForgetPasswordWebPage(),
|
||||||
|
desktopBody: ForgetPasswordWebPage(),
|
||||||
|
mobileBody: ForgetPasswordWebPage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ class LoginPage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const ResponsiveLayout(
|
return const ResponsiveLayout(
|
||||||
desktopBody: LoginWebPage(), mobileBody: LoginWebPage());
|
tablet: LoginWebPage(),
|
||||||
|
desktopBody: LoginWebPage(),
|
||||||
|
mobileBody: LoginWebPage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,14 @@ class DefaultButton extends StatelessWidget {
|
|||||||
this.padding,
|
this.padding,
|
||||||
this.borderColor,
|
this.borderColor,
|
||||||
this.elevation,
|
this.elevation,
|
||||||
|
this.borderWidth = 1.0,
|
||||||
});
|
});
|
||||||
final void Function()? onPressed;
|
final void Function()? onPressed;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final double? height;
|
final double? height;
|
||||||
final bool isSecondary;
|
final bool isSecondary;
|
||||||
final double? borderRadius;
|
final double? borderRadius;
|
||||||
|
final double borderWidth;
|
||||||
final bool enabled;
|
final bool enabled;
|
||||||
final double? padding;
|
final double? padding;
|
||||||
final bool isDone;
|
final bool isDone;
|
||||||
@ -66,7 +68,10 @@ class DefaultButton extends StatelessWidget {
|
|||||||
}),
|
}),
|
||||||
shape: WidgetStateProperty.all(
|
shape: WidgetStateProperty.all(
|
||||||
RoundedRectangleBorder(
|
RoundedRectangleBorder(
|
||||||
side: BorderSide(color: borderColor ?? Colors.transparent),
|
side: BorderSide(
|
||||||
|
color: borderColor ?? Colors.transparent,
|
||||||
|
width: borderWidth,
|
||||||
|
),
|
||||||
borderRadius: BorderRadius.circular(borderRadius ?? 20),
|
borderRadius: BorderRadius.circular(borderRadius ?? 20),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -12,7 +12,7 @@ Future<void> showCustomDialog({
|
|||||||
double? iconWidth,
|
double? iconWidth,
|
||||||
VoidCallback? onOkPressed,
|
VoidCallback? onOkPressed,
|
||||||
bool barrierDismissible = false,
|
bool barrierDismissible = false,
|
||||||
required List<Widget> actions,
|
List<Widget>? actions,
|
||||||
}) {
|
}) {
|
||||||
return showDialog(
|
return showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
@ -19,6 +20,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
on<AcControlEvent>(_onAcControl);
|
on<AcControlEvent>(_onAcControl);
|
||||||
on<AcBatchControlEvent>(_onAcBatchControl);
|
on<AcBatchControlEvent>(_onAcBatchControl);
|
||||||
on<AcFactoryResetEvent>(_onFactoryReset);
|
on<AcFactoryResetEvent>(_onFactoryReset);
|
||||||
|
on<AcStatusUpdated>(_onAcStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFetchAcStatus(
|
FutureOr<void> _onFetchAcStatus(
|
||||||
@ -28,12 +30,64 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
final status =
|
final status =
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
|
deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
emit(ACStatusLoaded(deviceStatus));
|
emit(ACStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(AcsFailedState(error: e.toString()));
|
emit(AcsFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
DatabaseReference ref =
|
||||||
|
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
|
Stream<DatabaseEvent> stream = ref.onValue;
|
||||||
|
|
||||||
|
stream.listen((DatabaseEvent event) async {
|
||||||
|
if (event.snapshot.value == null) return;
|
||||||
|
|
||||||
|
if (_timer != null) {
|
||||||
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
|
}
|
||||||
|
Map<dynamic, dynamic> usersMap =
|
||||||
|
event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus =
|
||||||
|
AcStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(AcStatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onAcStatusUpdated(AcStatusUpdated event, Emitter<AcsState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(ACStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Future<void> testFirebaseConnection() async {
|
||||||
|
// // Reference to a test node in your database
|
||||||
|
// final testRef = FirebaseDatabase.instance.ref("test");
|
||||||
|
|
||||||
|
// // Write a test value
|
||||||
|
// await testRef.set("Hello, Firebase!");
|
||||||
|
|
||||||
|
// // Listen for changes on the test node
|
||||||
|
// testRef.onValue.listen((DatabaseEvent event) {
|
||||||
|
// final data = event.snapshot.value;
|
||||||
|
// print("Data from Firebase: $data");
|
||||||
|
// // If you see "Hello, Firebase!" printed in your console, it means the connection works.
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
FutureOr<void> _onAcControl(
|
FutureOr<void> _onAcControl(
|
||||||
AcControlEvent event, Emitter<AcsState> emit) async {
|
AcControlEvent event, Emitter<AcsState> emit) async {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final oldValue = _getValueByCode(event.code);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
|
|
||||||
sealed class AcsEvent extends Equatable {
|
sealed class AcsEvent extends Equatable {
|
||||||
@ -7,6 +8,7 @@ sealed class AcsEvent extends Equatable {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
class AcUpdated extends AcsEvent {}
|
||||||
|
|
||||||
class AcFetchDeviceStatusEvent extends AcsEvent {
|
class AcFetchDeviceStatusEvent extends AcsEvent {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
@ -16,7 +18,10 @@ class AcFetchDeviceStatusEvent extends AcsEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceId];
|
List<Object> get props => [deviceId];
|
||||||
}
|
}
|
||||||
|
class AcStatusUpdated extends AcsEvent {
|
||||||
|
final AcStatusModel deviceStatus;
|
||||||
|
AcStatusUpdated(this.deviceStatus);
|
||||||
|
}
|
||||||
class AcFetchBatchStatusEvent extends AcsEvent {
|
class AcFetchBatchStatusEvent extends AcsEvent {
|
||||||
final List<String> devicesIds;
|
final List<String> devicesIds;
|
||||||
|
|
||||||
|
@ -24,7 +24,8 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
final isLarge = isLargeScreenSize(context);
|
final isLarge = isLargeScreenSize(context);
|
||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => AcBloc(deviceId: device.uuid!)..add(AcFetchDeviceStatusEvent(device.uuid!)),
|
create: (context) => AcBloc(deviceId: device.uuid!)
|
||||||
|
..add(AcFetchDeviceStatusEvent(device.uuid!)),
|
||||||
child: BlocBuilder<AcBloc, AcsState>(
|
child: BlocBuilder<AcBloc, AcsState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is ACStatusLoaded) {
|
if (state is ACStatusLoaded) {
|
||||||
@ -98,7 +99,8 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'h',
|
'h',
|
||||||
style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor),
|
style: context.textTheme.bodySmall!
|
||||||
|
.copyWith(color: ColorsManager.blackColor),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'30',
|
'30',
|
||||||
@ -107,7 +109,9 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text('m', style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor)),
|
Text('m',
|
||||||
|
style: context.textTheme.bodySmall!
|
||||||
|
.copyWith(color: ColorsManager.blackColor)),
|
||||||
IconButton(
|
IconButton(
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
part 'device_managment_event.dart';
|
part 'device_managment_event.dart';
|
||||||
part 'device_managment_state.dart';
|
part 'device_managment_state.dart';
|
||||||
|
|
||||||
class DeviceManagementBloc
|
class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
||||||
extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
|
||||||
int _selectedIndex = 0;
|
int _selectedIndex = 0;
|
||||||
List<AllDevicesModel> _devices = [];
|
List<AllDevicesModel> _devices = [];
|
||||||
int _onlineCount = 0;
|
int _onlineCount = 0;
|
||||||
@ -30,11 +31,23 @@ class DeviceManagementBloc
|
|||||||
on<UpdateSelection>(_onUpdateSelection);
|
on<UpdateSelection>(_onUpdateSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDevices(
|
Future<void> _onFetchDevices(FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||||
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
|
||||||
emit(DeviceManagementLoading());
|
emit(DeviceManagementLoading());
|
||||||
try {
|
try {
|
||||||
final devices = await DevicesManagementApi().fetchDevices();
|
List<AllDevicesModel> devices = [];
|
||||||
|
_devices.clear();
|
||||||
|
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||||
|
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
||||||
|
devices = await DevicesManagementApi().fetchDevices('', '');
|
||||||
|
} else {
|
||||||
|
for (var community in spaceBloc.state.selectedCommunities) {
|
||||||
|
List<String> spacesList = spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
|
||||||
|
for (var space in spacesList) {
|
||||||
|
devices.addAll(await DevicesManagementApi().fetchDevices(community, space));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_selectedDevices.clear();
|
_selectedDevices.clear();
|
||||||
_devices = devices;
|
_devices = devices;
|
||||||
_filteredDevices = devices;
|
_filteredDevices = devices;
|
||||||
@ -53,8 +66,7 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onFilterDevices(
|
void _onFilterDevices(FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
||||||
FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
|
||||||
if (_devices.isNotEmpty) {
|
if (_devices.isNotEmpty) {
|
||||||
_filteredDevices = List.from(_devices.where((device) {
|
_filteredDevices = List.from(_devices.where((device) {
|
||||||
switch (event.filter) {
|
switch (event.filter) {
|
||||||
@ -85,8 +97,7 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onResetFilters(
|
Future<void> _onResetFilters(ResetFilters event, Emitter<DeviceManagementState> emit) async {
|
||||||
ResetFilters event, Emitter<DeviceManagementState> emit) async {
|
|
||||||
currentProductName = '';
|
currentProductName = '';
|
||||||
_selectedDevices.clear();
|
_selectedDevices.clear();
|
||||||
_filteredDevices = List.from(_devices);
|
_filteredDevices = List.from(_devices);
|
||||||
@ -102,8 +113,7 @@ class DeviceManagementBloc
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onResetSelectedDevices(
|
void _onResetSelectedDevices(ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
|
||||||
ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
|
|
||||||
_selectedDevices.clear();
|
_selectedDevices.clear();
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
if (state is DeviceManagementLoaded) {
|
||||||
@ -129,14 +139,12 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSelectedFilterChanged(
|
void _onSelectedFilterChanged(SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
|
||||||
SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
|
|
||||||
_selectedIndex = event.selectedIndex;
|
_selectedIndex = event.selectedIndex;
|
||||||
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSelectDevice(
|
void _onSelectDevice(SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||||
SelectDevice event, Emitter<DeviceManagementState> emit) {
|
|
||||||
final selectedUuid = event.selectedDevice.uuid;
|
final selectedUuid = event.selectedDevice.uuid;
|
||||||
|
|
||||||
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
||||||
@ -147,8 +155,7 @@ class DeviceManagementBloc
|
|||||||
|
|
||||||
List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices);
|
List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices);
|
||||||
|
|
||||||
bool isControlButtonEnabled =
|
bool isControlButtonEnabled = _checkIfControlButtonEnabled(clonedSelectedDevices);
|
||||||
_checkIfControlButtonEnabled(clonedSelectedDevices);
|
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
if (state is DeviceManagementLoaded) {
|
||||||
emit(DeviceManagementLoaded(
|
emit(DeviceManagementLoaded(
|
||||||
@ -157,8 +164,7 @@ class DeviceManagementBloc
|
|||||||
onlineCount: _onlineCount,
|
onlineCount: _onlineCount,
|
||||||
offlineCount: _offlineCount,
|
offlineCount: _offlineCount,
|
||||||
lowBatteryCount: _lowBatteryCount,
|
lowBatteryCount: _lowBatteryCount,
|
||||||
selectedDevice:
|
selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||||
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
|
||||||
isControlButtonEnabled: isControlButtonEnabled,
|
isControlButtonEnabled: isControlButtonEnabled,
|
||||||
));
|
));
|
||||||
} else if (state is DeviceManagementFiltered) {
|
} else if (state is DeviceManagementFiltered) {
|
||||||
@ -168,15 +174,13 @@ class DeviceManagementBloc
|
|||||||
onlineCount: _onlineCount,
|
onlineCount: _onlineCount,
|
||||||
offlineCount: _offlineCount,
|
offlineCount: _offlineCount,
|
||||||
lowBatteryCount: _lowBatteryCount,
|
lowBatteryCount: _lowBatteryCount,
|
||||||
selectedDevice:
|
selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||||
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
|
||||||
isControlButtonEnabled: isControlButtonEnabled,
|
isControlButtonEnabled: isControlButtonEnabled,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onUpdateSelection(
|
void _onUpdateSelection(UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
||||||
UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
|
||||||
List<AllDevicesModel> selectedDevices = [];
|
List<AllDevicesModel> selectedDevices = [];
|
||||||
List<AllDevicesModel> devicesToSelectFrom = [];
|
List<AllDevicesModel> devicesToSelectFrom = [];
|
||||||
|
|
||||||
@ -219,8 +223,7 @@ class DeviceManagementBloc
|
|||||||
|
|
||||||
bool _checkIfControlButtonEnabled(List<AllDevicesModel> selectedDevices) {
|
bool _checkIfControlButtonEnabled(List<AllDevicesModel> selectedDevices) {
|
||||||
if (selectedDevices.length > 1) {
|
if (selectedDevices.length > 1) {
|
||||||
final productTypes =
|
final productTypes = selectedDevices.map((device) => device.productType).toSet();
|
||||||
selectedDevices.map((device) => device.productType).toSet();
|
|
||||||
return productTypes.length == 1;
|
return productTypes.length == 1;
|
||||||
} else if (selectedDevices.length == 1) {
|
} else if (selectedDevices.length == 1) {
|
||||||
return true;
|
return true;
|
||||||
@ -231,10 +234,8 @@ class DeviceManagementBloc
|
|||||||
void _calculateDeviceCounts() {
|
void _calculateDeviceCounts() {
|
||||||
_onlineCount = _devices.where((device) => device.online == true).length;
|
_onlineCount = _devices.where((device) => device.online == true).length;
|
||||||
_offlineCount = _devices.where((device) => device.online == false).length;
|
_offlineCount = _devices.where((device) => device.online == false).length;
|
||||||
_lowBatteryCount = _devices
|
_lowBatteryCount =
|
||||||
.where((device) =>
|
_devices.where((device) => device.batteryLevel != null && device.batteryLevel! < 20).length;
|
||||||
device.batteryLevel != null && device.batteryLevel! < 20)
|
|
||||||
.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getFilterFromIndex(int index) {
|
String _getFilterFromIndex(int index) {
|
||||||
@ -250,8 +251,7 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSearchDevices(
|
void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||||
SearchDevices event, Emitter<DeviceManagementState> emit) {
|
|
||||||
if ((event.community == null || event.community!.isEmpty) &&
|
if ((event.community == null || event.community!.isEmpty) &&
|
||||||
(event.unitName == null || event.unitName!.isEmpty) &&
|
(event.unitName == null || event.unitName!.isEmpty) &&
|
||||||
(event.productName == null || event.productName!.isEmpty)) {
|
(event.productName == null || event.productName!.isEmpty)) {
|
||||||
@ -280,33 +280,22 @@ class DeviceManagementBloc
|
|||||||
final filteredDevices = devicesToSearch.where((device) {
|
final filteredDevices = devicesToSearch.where((device) {
|
||||||
final matchesCommunity = event.community == null ||
|
final matchesCommunity = event.community == null ||
|
||||||
event.community!.isEmpty ||
|
event.community!.isEmpty ||
|
||||||
(device.community?.name
|
(device.community?.name?.toLowerCase().contains(event.community!.toLowerCase()) ??
|
||||||
?.toLowerCase()
|
|
||||||
.contains(event.community!.toLowerCase()) ??
|
|
||||||
false);
|
false);
|
||||||
final matchesUnit = event.unitName == null ||
|
final matchesUnit = event.unitName == null ||
|
||||||
event.unitName!.isEmpty ||
|
event.unitName!.isEmpty ||
|
||||||
(device.spaces != null &&
|
(device.spaces != null &&
|
||||||
device.spaces!.isNotEmpty &&
|
device.spaces!.isNotEmpty &&
|
||||||
device.spaces![0].spaceName
|
device.spaces![0].spaceName!.toLowerCase().contains(event.unitName!.toLowerCase()));
|
||||||
!.toLowerCase()
|
|
||||||
.contains(event.unitName!.toLowerCase()));
|
|
||||||
final matchesProductName = event.productName == null ||
|
final matchesProductName = event.productName == null ||
|
||||||
event.productName!.isEmpty ||
|
event.productName!.isEmpty ||
|
||||||
(device.name
|
(device.name?.toLowerCase().contains(event.productName!.toLowerCase()) ?? false);
|
||||||
?.toLowerCase()
|
|
||||||
.contains(event.productName!.toLowerCase()) ??
|
|
||||||
false);
|
|
||||||
final matchesDeviceName = event.productName == null ||
|
final matchesDeviceName = event.productName == null ||
|
||||||
event.productName!.isEmpty ||
|
event.productName!.isEmpty ||
|
||||||
(device.categoryName
|
(device.categoryName?.toLowerCase().contains(event.productName!.toLowerCase()) ??
|
||||||
?.toLowerCase()
|
|
||||||
.contains(event.productName!.toLowerCase()) ??
|
|
||||||
false);
|
false);
|
||||||
|
|
||||||
return matchesCommunity &&
|
return matchesCommunity && matchesUnit && (matchesProductName || matchesDeviceName);
|
||||||
matchesUnit &&
|
|
||||||
(matchesProductName || matchesDeviceName);
|
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
emit(DeviceManagementFiltered(
|
emit(DeviceManagementFiltered(
|
||||||
|
@ -7,7 +7,15 @@ abstract class DeviceManagementEvent extends Equatable {
|
|||||||
List<Object?> get props => [];
|
List<Object?> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class FetchDevices extends DeviceManagementEvent {}
|
class FetchDevices extends DeviceManagementEvent {
|
||||||
|
// final Map<String, List<String>> selectedCommunitiesSpaces;
|
||||||
|
// final String spaceId;
|
||||||
|
final BuildContext context;
|
||||||
|
|
||||||
|
const FetchDevices(this.context);
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [context];
|
||||||
|
}
|
||||||
|
|
||||||
class FilterDevices extends DeviceManagementEvent {
|
class FilterDevices extends DeviceManagementEvent {
|
||||||
final String filter;
|
final String filter;
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
class DeviceSubspace {
|
||||||
|
final String uuid;
|
||||||
|
final DateTime? createdAt;
|
||||||
|
final DateTime? updatedAt;
|
||||||
|
final String subspaceName;
|
||||||
|
final bool disabled;
|
||||||
|
|
||||||
|
DeviceSubspace({
|
||||||
|
required this.uuid,
|
||||||
|
this.createdAt,
|
||||||
|
this.updatedAt,
|
||||||
|
required this.subspaceName,
|
||||||
|
required this.disabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory DeviceSubspace.fromJson(Map<String, dynamic> json) {
|
||||||
|
return DeviceSubspace(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
createdAt: json['createdAt'] != null
|
||||||
|
? DateTime.tryParse(json['createdAt'].toString())
|
||||||
|
: null,
|
||||||
|
updatedAt: json['updatedAt'] != null
|
||||||
|
? DateTime.tryParse(json['updatedAt'].toString())
|
||||||
|
: null,
|
||||||
|
subspaceName: json['subspaceName'] as String,
|
||||||
|
disabled: json['disabled'] as bool,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'createdAt': createdAt?.toIso8601String(),
|
||||||
|
'updatedAt': updatedAt?.toIso8601String(),
|
||||||
|
'subspaceName': subspaceName,
|
||||||
|
'disabled': disabled,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<DeviceSubspace> listFromJson(List<dynamic> jsonList) {
|
||||||
|
return jsonList.map((json) => DeviceSubspace.fromJson(json)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Map<String, dynamic>> listToJson(List<DeviceSubspace> subspaces) {
|
||||||
|
return subspaces.map((subspace) => subspace.toJson()).toList();
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,13 @@
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_community.model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_community.model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_space_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_subspace.model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_function.dart';
|
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/three_gang_switch/three_gang_switch.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/three_gang_switch/three_gang_switch.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/two_gang_switch/two_gang_switch.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/two_gang_switch/two_gang_switch.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/enum/device_types.dart';
|
import 'package:syncrow_web/utils/enum/device_types.dart';
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ class AllDevicesModel {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
DevicesModelRoom? room;
|
DevicesModelRoom? room;
|
||||||
|
DeviceSubspace? subspace;
|
||||||
DevicesModelUnit? unit;
|
DevicesModelUnit? unit;
|
||||||
DeviceCommunityModel? community;
|
DeviceCommunityModel? community;
|
||||||
String? productUuid;
|
String? productUuid;
|
||||||
@ -77,6 +79,7 @@ class AllDevicesModel {
|
|||||||
|
|
||||||
AllDevicesModel({
|
AllDevicesModel({
|
||||||
this.room,
|
this.room,
|
||||||
|
this.subspace,
|
||||||
this.unit,
|
this.unit,
|
||||||
this.community,
|
this.community,
|
||||||
this.productUuid,
|
this.productUuid,
|
||||||
@ -110,6 +113,9 @@ class AllDevicesModel {
|
|||||||
room = (json['room'] != null && (json['room'] is Map))
|
room = (json['room'] != null && (json['room'] is Map))
|
||||||
? DevicesModelRoom.fromJson(json['room'])
|
? DevicesModelRoom.fromJson(json['room'])
|
||||||
: null;
|
: null;
|
||||||
|
subspace = (json['subspace'] != null && (json['subspace'] is Map))
|
||||||
|
? DeviceSubspace.fromJson(json['subspace'])
|
||||||
|
: null;
|
||||||
unit = (json['unit'] != null && (json['unit'] is Map))
|
unit = (json['unit'] != null && (json['unit'] is Map))
|
||||||
? DevicesModelUnit.fromJson(json['unit'])
|
? DevicesModelUnit.fromJson(json['unit'])
|
||||||
: null;
|
: null;
|
||||||
@ -142,9 +148,7 @@ class AllDevicesModel {
|
|||||||
|
|
||||||
productName = json['productName']?.toString();
|
productName = json['productName']?.toString();
|
||||||
if (json['spaces'] != null && json['spaces'] is List) {
|
if (json['spaces'] != null && json['spaces'] is List) {
|
||||||
spaces = (json['spaces'] as List)
|
spaces = (json['spaces'] as List).map((space) => DeviceSpaceModel.fromJson(space)).toList();
|
||||||
.map((space) => DeviceSpaceModel.fromJson(space))
|
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,8 +196,7 @@ SOS
|
|||||||
String tempIcon = '';
|
String tempIcon = '';
|
||||||
if (type == DeviceType.LightBulb) {
|
if (type == DeviceType.LightBulb) {
|
||||||
tempIcon = Assets.lightBulb;
|
tempIcon = Assets.lightBulb;
|
||||||
} else if (type == DeviceType.CeilingSensor ||
|
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
|
||||||
type == DeviceType.WallSensor) {
|
|
||||||
tempIcon = Assets.sensors;
|
tempIcon = Assets.sensors;
|
||||||
} else if (type == DeviceType.AC) {
|
} else if (type == DeviceType.AC) {
|
||||||
tempIcon = Assets.ac;
|
tempIcon = Assets.ac;
|
||||||
@ -248,34 +251,25 @@ SOS
|
|||||||
case '1G':
|
case '1G':
|
||||||
return [
|
return [
|
||||||
OneGangSwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
OneGangSwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
OneGangCountdownFunction(
|
OneGangCountdownFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
case '2G':
|
case '2G':
|
||||||
return [
|
return [
|
||||||
TwoGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
TwoGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
TwoGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
TwoGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
TwoGangCountdown1Function(
|
TwoGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
TwoGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
TwoGangCountdown2Function(
|
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
case '3G':
|
case '3G':
|
||||||
return [
|
return [
|
||||||
ThreeGangSwitch1Function(
|
ThreeGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
ThreeGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
ThreeGangSwitch2Function(
|
ThreeGangSwitch3Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
ThreeGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
ThreeGangSwitch3Function(
|
ThreeGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
ThreeGangCountdown3Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
ThreeGangCountdown1Function(
|
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
ThreeGangCountdown2Function(
|
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
ThreeGangCountdown3Function(
|
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -288,6 +282,9 @@ SOS
|
|||||||
if (room != null) {
|
if (room != null) {
|
||||||
data['room'] = room!.toJson();
|
data['room'] = room!.toJson();
|
||||||
}
|
}
|
||||||
|
if (subspace != null) {
|
||||||
|
data['subspace'] = subspace!.toJson();
|
||||||
|
}
|
||||||
if (unit != null) {
|
if (unit != null) {
|
||||||
data['unit'] = unit!.toJson();
|
data['unit'] = unit!.toJson();
|
||||||
}
|
}
|
||||||
@ -330,6 +327,7 @@ SOS
|
|||||||
|
|
||||||
return other is AllDevicesModel &&
|
return other is AllDevicesModel &&
|
||||||
other.room == room &&
|
other.room == room &&
|
||||||
|
other.subspace == subspace &&
|
||||||
other.unit == unit &&
|
other.unit == unit &&
|
||||||
other.productUuid == productUuid &&
|
other.productUuid == productUuid &&
|
||||||
other.productType == productType &&
|
other.productType == productType &&
|
||||||
@ -360,6 +358,7 @@ SOS
|
|||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
return room.hashCode ^
|
return room.hashCode ^
|
||||||
|
subspace.hashCode ^
|
||||||
unit.hashCode ^
|
unit.hashCode ^
|
||||||
productUuid.hashCode ^
|
productUuid.hashCode ^
|
||||||
productType.hashCode ^
|
productType.hashCode ^
|
||||||
|
@ -3,12 +3,13 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
|
import 'package:syncrow_web/pages/routines/view/create_new_routine_view.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/view/routines_view.dart';
|
import 'package:syncrow_web/pages/routines/view/routines_view.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||||
@ -19,17 +20,17 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => DeviceManagementBloc()..add(FetchDevices()),
|
create: (context) =>
|
||||||
|
DeviceManagementBloc()..add(FetchDevices(context)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: WebScaffold(
|
child: WebScaffold(
|
||||||
appBarTitle: FittedBox(
|
appBarTitle: Text(
|
||||||
child: Text(
|
|
||||||
'Device Management',
|
'Device Management',
|
||||||
style: Theme.of(context).textTheme.headlineLarge,
|
style: ResponsiveTextTheme.of(context).deviceManagementTitle,
|
||||||
),
|
),
|
||||||
),
|
centerBody:
|
||||||
centerBody: BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
|
BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@ -45,8 +46,11 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
child: Text(
|
child: Text(
|
||||||
'Devices',
|
'Devices',
|
||||||
style: context.textTheme.titleMedium?.copyWith(
|
style: context.textTheme.titleMedium?.copyWith(
|
||||||
color: !state.routineTab ? ColorsManager.whiteColors : ColorsManager.grayColor,
|
color: !state.routineTab
|
||||||
fontWeight: !state.routineTab ? FontWeight.w700 : FontWeight.w400,
|
? ColorsManager.whiteColors
|
||||||
|
: ColorsManager.grayColor,
|
||||||
|
fontWeight:
|
||||||
|
!state.routineTab ? FontWeight.w700 : FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -55,13 +59,18 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
backgroundColor: null,
|
backgroundColor: null,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<RoutineBloc>().add(const TriggerSwitchTabsEvent(isRoutineTab: true));
|
context
|
||||||
|
.read<RoutineBloc>()
|
||||||
|
.add(const TriggerSwitchTabsEvent(isRoutineTab: true));
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Routines',
|
'Routines',
|
||||||
style: context.textTheme.titleMedium?.copyWith(
|
style: context.textTheme.titleMedium?.copyWith(
|
||||||
color: state.routineTab ? ColorsManager.whiteColors : ColorsManager.grayColor,
|
color: state.routineTab
|
||||||
fontWeight: state.routineTab ? FontWeight.w700 : FontWeight.w400,
|
? ColorsManager.whiteColors
|
||||||
|
: ColorsManager.grayColor,
|
||||||
|
fontWeight:
|
||||||
|
state.routineTab ? FontWeight.w700 : FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -69,7 +78,8 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
rightBody: const NavigateHomeGridView(),
|
rightBody: const NavigateHomeGridView(),
|
||||||
scaffoldBody: BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
|
scaffoldBody:
|
||||||
|
BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
|
||||||
if (state.routineTab) {
|
if (state.routineTab) {
|
||||||
return const RoutinesView();
|
return const RoutinesView();
|
||||||
}
|
}
|
||||||
@ -80,11 +90,12 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||||
builder: (context, deviceState) {
|
builder: (context, deviceState) {
|
||||||
if (deviceState is DeviceManagementLoading) {
|
if (deviceState is DeviceManagementLoading) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const DeviceManagementBody(devices: []);
|
||||||
} else if (deviceState is DeviceManagementLoaded) {
|
} else if (deviceState is DeviceManagementLoaded) {
|
||||||
return DeviceManagementBody(devices: deviceState.devices);
|
return DeviceManagementBody(devices: deviceState.devices);
|
||||||
} else if (deviceState is DeviceManagementFiltered) {
|
} else if (deviceState is DeviceManagementFiltered) {
|
||||||
return DeviceManagementBody(devices: deviceState.filteredDevices);
|
return DeviceManagementBody(
|
||||||
|
devices: deviceState.filteredDevices);
|
||||||
} else {
|
} else {
|
||||||
return const Center(child: Text('Error fetching Devices'));
|
return const Center(child: Text('Error fetching Devices'));
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||||
import 'package:syncrow_web/utils/format_date_time.dart';
|
import 'package:syncrow_web/utils/format_date_time.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
@ -59,10 +60,23 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
|
|
||||||
final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control';
|
final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control';
|
||||||
|
|
||||||
return Column(
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: SpaceTreeView(
|
||||||
|
onSelect: () {
|
||||||
|
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: state is DeviceManagementLoading
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
|
padding: isLargeScreenSize(context)
|
||||||
|
? const EdgeInsets.all(30)
|
||||||
|
: const EdgeInsets.all(15),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -71,14 +85,16 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
tabs: tabs,
|
tabs: tabs,
|
||||||
selectedIndex: selectedIndex,
|
selectedIndex: selectedIndex,
|
||||||
onTabChanged: (index) {
|
onTabChanged: (index) {
|
||||||
context.read<DeviceManagementBloc>().add(SelectedFilterChanged(index));
|
context
|
||||||
|
.read<DeviceManagementBloc>()
|
||||||
|
.add(SelectedFilterChanged(index));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const DeviceSearchFilters(),
|
const DeviceSearchFilters(),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Container(
|
Container(
|
||||||
height: 45,
|
// height: 45,
|
||||||
width: 125,
|
width: 125,
|
||||||
decoration: containerDecoration,
|
decoration: containerDecoration,
|
||||||
child: Center(
|
child: Center(
|
||||||
@ -93,7 +109,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (selectedDevices.length > 1) {
|
} else if (selectedDevices.length > 1) {
|
||||||
final productTypes = selectedDevices.map((device) => device.productType).toSet();
|
final productTypes = selectedDevices
|
||||||
|
.map((device) => device.productType)
|
||||||
|
.toSet();
|
||||||
if (productTypes.length == 1) {
|
if (productTypes.length == 1) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -122,13 +140,17 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
|
padding: isLargeScreenSize(context)
|
||||||
|
? const EdgeInsets.all(30)
|
||||||
|
: const EdgeInsets.all(15),
|
||||||
child: DynamicTable(
|
child: DynamicTable(
|
||||||
withSelectAll: true,
|
withSelectAll: true,
|
||||||
cellDecoration: containerDecoration,
|
cellDecoration: containerDecoration,
|
||||||
onRowSelected: (index, isSelected, row) {
|
onRowSelected: (index, isSelected, row) {
|
||||||
final selectedDevice = devicesToShow[index];
|
final selectedDevice = devicesToShow[index];
|
||||||
context.read<DeviceManagementBloc>().add(SelectDevice(selectedDevice));
|
context
|
||||||
|
.read<DeviceManagementBloc>()
|
||||||
|
.add(SelectDevice(selectedDevice));
|
||||||
},
|
},
|
||||||
withCheckBox: true,
|
withCheckBox: true,
|
||||||
size: MediaQuery.of(context).size,
|
size: MediaQuery.of(context).size,
|
||||||
@ -147,31 +169,45 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
data: devicesToShow.map((device) {
|
data: devicesToShow.map((device) {
|
||||||
final combinedSpaceNames = device.spaces != null
|
final combinedSpaceNames = device.spaces != null
|
||||||
? device.spaces!.map((space) => space.spaceName).join(' > ') +
|
? device.spaces!.map((space) => space.spaceName).join(' > ') +
|
||||||
(device.community != null ? ' > ${device.community!.name}' : '')
|
(device.community != null
|
||||||
|
? ' > ${device.community!.name}'
|
||||||
|
: '')
|
||||||
: (device.community != null ? device.community!.name : '');
|
: (device.community != null ? device.community!.name : '');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
device.name ?? '',
|
device.name ?? '',
|
||||||
device.productName ?? '',
|
device.productName ?? '',
|
||||||
device.uuid ?? '',
|
device.uuid ?? '',
|
||||||
(device.spaces != null && device.spaces!.isNotEmpty) ? device.spaces![0].spaceName : '',
|
(device.spaces != null && device.spaces!.isNotEmpty)
|
||||||
|
? device.spaces![0].spaceName
|
||||||
|
: '',
|
||||||
combinedSpaceNames,
|
combinedSpaceNames,
|
||||||
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
|
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
|
||||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)),
|
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(device.createTime ?? 0) * 1000)),
|
||||||
device.online == true ? 'Online' : 'Offline',
|
device.online == true ? 'Online' : 'Offline',
|
||||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)),
|
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(device.updateTime ?? 0) * 1000)),
|
||||||
];
|
];
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onSelectionChanged: (selectedRows) {
|
onSelectionChanged: (selectedRows) {
|
||||||
context.read<DeviceManagementBloc>().add(UpdateSelection(selectedRows));
|
context
|
||||||
|
.read<DeviceManagementBloc>()
|
||||||
|
.add(UpdateSelection(selectedRows));
|
||||||
},
|
},
|
||||||
initialSelectedIds:
|
initialSelectedIds: context
|
||||||
context.read<DeviceManagementBloc>().selectedDevices.map((device) => device.uuid!).toList(),
|
.read<DeviceManagementBloc>()
|
||||||
|
.selectedDevices
|
||||||
|
.map((device) => device.uuid!)
|
||||||
|
.toList(),
|
||||||
isEmpty: devicesToShow.isEmpty,
|
isEmpty: devicesToShow.isEmpty,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -12,8 +12,7 @@ class DeviceSearchFilters extends StatefulWidget {
|
|||||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
|
||||||
with HelperResponsiveLayout {
|
|
||||||
final TextEditingController communityController = TextEditingController();
|
final TextEditingController communityController = TextEditingController();
|
||||||
final TextEditingController unitNameController = TextEditingController();
|
final TextEditingController unitNameController = TextEditingController();
|
||||||
final TextEditingController productNameController = TextEditingController();
|
final TextEditingController productNameController = TextEditingController();
|
||||||
@ -27,8 +26,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
|||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
_buildSearchField("Space Name", unitNameController, 200),
|
_buildSearchField("Space Name", unitNameController, 200),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
_buildSearchField(
|
_buildSearchField("Device Name / Product Name", productNameController, 300),
|
||||||
"Device Name / Product Name", productNameController, 300),
|
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
_buildSearchResetButtons(),
|
_buildSearchResetButtons(),
|
||||||
],
|
],
|
||||||
@ -53,8 +51,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSearchField(
|
Widget _buildSearchField(String title, TextEditingController controller, double width) {
|
||||||
String title, TextEditingController controller, double width) {
|
|
||||||
return Container(
|
return Container(
|
||||||
child: StatefulTextField(
|
child: StatefulTextField(
|
||||||
title: title,
|
title: title,
|
||||||
@ -88,7 +85,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
|||||||
productNameController.clear();
|
productNameController.clear();
|
||||||
context.read<DeviceManagementBloc>()
|
context.read<DeviceManagementBloc>()
|
||||||
..add(ResetFilters())
|
..add(ResetFilters())
|
||||||
..add(FetchDevices());
|
..add(FetchDevices(context));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
|
||||||
@ -22,42 +23,55 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
|||||||
on<ShowCeilingDescriptionEvent>(_showDescription);
|
on<ShowCeilingDescriptionEvent>(_showDescription);
|
||||||
on<BackToCeilingGridViewEvent>(_backToGridView);
|
on<BackToCeilingGridViewEvent>(_backToGridView);
|
||||||
on<CeilingFactoryResetEvent>(_onFactoryReset);
|
on<CeilingFactoryResetEvent>(_onFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _fetchCeilingSensorStatus(
|
void _fetchCeilingSensorStatus(
|
||||||
CeilingInitialEvent event, Emitter<CeilingSensorState> emit) async {
|
CeilingInitialEvent event, Emitter<CeilingSensorState> emit) async {
|
||||||
emit(CeilingLoadingInitialState());
|
emit(CeilingLoadingInitialState());
|
||||||
try {
|
try {
|
||||||
var response = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
var response =
|
||||||
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
||||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
// _listenToChanges();
|
_listenToChanges(event.deviceId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(CeilingFailedState(error: e.toString()));
|
emit(CeilingFailedState(error: e.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _listenToChanges() {
|
_listenToChanges(deviceId) {
|
||||||
// try {
|
try {
|
||||||
// DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
DatabaseReference ref =
|
||||||
// Stream<DatabaseEvent> stream = ref.onValue;
|
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
|
Stream<DatabaseEvent> stream = ref.onValue;
|
||||||
|
|
||||||
// stream.listen((DatabaseEvent event) {
|
stream.listen((DatabaseEvent event) {
|
||||||
// Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
|
Map<dynamic, dynamic> usersMap =
|
||||||
// List<StatusModel> statusList = [];
|
event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
|
||||||
// usersMap['status'].forEach((element) {
|
List<Status> statusList = [];
|
||||||
// statusList.add(StatusModel(code: element['code'], value: element['value']));
|
usersMap['status'].forEach((element) {
|
||||||
// });
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
// deviceStatus = WallSensorModel.fromJson(statusList);
|
deviceStatus = CeilingSensorModel.fromJson(statusList);
|
||||||
// add(WallSensorUpdatedEvent());
|
if (!isClosed) {
|
||||||
// });
|
add(StatusUpdated(deviceStatus));
|
||||||
// } catch (_) {}
|
}
|
||||||
// }
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
void _changeValue(CeilingChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
|
void _onStatusUpdated(StatusUpdated event, Emitter<CeilingSensorState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _changeValue(
|
||||||
|
CeilingChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
|
||||||
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
|
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
|
||||||
if (event.code == 'sensitivity') {
|
if (event.code == 'sensitivity') {
|
||||||
deviceStatus.sensitivity = event.value;
|
deviceStatus.sensitivity = event.value;
|
||||||
@ -122,7 +136,8 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
|||||||
try {
|
try {
|
||||||
late bool response;
|
late bool response;
|
||||||
if (isBatch) {
|
if (isBatch) {
|
||||||
response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
response = await DevicesManagementApi()
|
||||||
|
.deviceBatchControl(deviceId, code, value);
|
||||||
} else {
|
} else {
|
||||||
response = await DevicesManagementApi()
|
response = await DevicesManagementApi()
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
.deviceControl(deviceId, Status(code: code, value: value));
|
||||||
@ -143,8 +158,8 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _getDeviceReports(
|
FutureOr<void> _getDeviceReports(GetCeilingDeviceReportsEvent event,
|
||||||
GetCeilingDeviceReportsEvent event, Emitter<CeilingSensorState> emit) async {
|
Emitter<CeilingSensorState> emit) async {
|
||||||
if (event.code.isEmpty) {
|
if (event.code.isEmpty) {
|
||||||
emit(ShowCeilingDescriptionState(description: reportString));
|
emit(ShowCeilingDescriptionState(description: reportString));
|
||||||
return;
|
return;
|
||||||
@ -155,7 +170,8 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// await DevicesManagementApi.getDeviceReportsByDate(deviceId, event.code, from.toString(), to.toString())
|
// await DevicesManagementApi.getDeviceReportsByDate(deviceId, event.code, from.toString(), to.toString())
|
||||||
await DevicesManagementApi.getDeviceReports(deviceId, event.code).then((value) {
|
await DevicesManagementApi.getDeviceReports(deviceId, event.code)
|
||||||
|
.then((value) {
|
||||||
emit(CeilingReportsState(deviceReport: value));
|
emit(CeilingReportsState(deviceReport: value));
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -165,19 +181,23 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showDescription(ShowCeilingDescriptionEvent event, Emitter<CeilingSensorState> emit) {
|
void _showDescription(
|
||||||
|
ShowCeilingDescriptionEvent event, Emitter<CeilingSensorState> emit) {
|
||||||
emit(ShowCeilingDescriptionState(description: event.description));
|
emit(ShowCeilingDescriptionState(description: event.description));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _backToGridView(BackToCeilingGridViewEvent event, Emitter<CeilingSensorState> emit) {
|
void _backToGridView(
|
||||||
|
BackToCeilingGridViewEvent event, Emitter<CeilingSensorState> emit) {
|
||||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _fetchCeilingSensorBatchControl(
|
FutureOr<void> _fetchCeilingSensorBatchControl(
|
||||||
CeilingFetchDeviceStatusEvent event, Emitter<CeilingSensorState> emit) async {
|
CeilingFetchDeviceStatusEvent event,
|
||||||
|
Emitter<CeilingSensorState> emit) async {
|
||||||
emit(CeilingLoadingInitialState());
|
emit(CeilingLoadingInitialState());
|
||||||
try {
|
try {
|
||||||
var response = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
var response =
|
||||||
|
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
||||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
|
||||||
|
|
||||||
abstract class CeilingSensorEvent extends Equatable {
|
abstract class CeilingSensorEvent extends Equatable {
|
||||||
const CeilingSensorEvent();
|
const CeilingSensorEvent();
|
||||||
@ -83,3 +84,12 @@ class CeilingFactoryResetEvent extends CeilingSensorEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [devicesId, factoryResetModel];
|
List<Object> get props => [devicesId, factoryResetModel];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class StatusUpdated extends CeilingSensorEvent {
|
||||||
|
final CeilingSensorModel deviceStatus;
|
||||||
|
const StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart';
|
||||||
@ -16,6 +17,7 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
|||||||
on<CurtainControl>(_onCurtainControl);
|
on<CurtainControl>(_onCurtainControl);
|
||||||
on<CurtainBatchControl>(_onCurtainBatchControl);
|
on<CurtainBatchControl>(_onCurtainBatchControl);
|
||||||
on<CurtainFactoryReset>(_onFactoryReset);
|
on<CurtainFactoryReset>(_onFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFetchDeviceStatus(
|
FutureOr<void> _onFetchDeviceStatus(
|
||||||
@ -24,7 +26,7 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
|||||||
try {
|
try {
|
||||||
final status =
|
final status =
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
deviceStatus = _checkStatus(status.status[0].value);
|
deviceStatus = _checkStatus(status.status[0].value);
|
||||||
|
|
||||||
emit(CurtainStatusLoaded(deviceStatus));
|
emit(CurtainStatusLoaded(deviceStatus));
|
||||||
@ -33,6 +35,48 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _listenToChanges(String deviceId) {
|
||||||
|
try {
|
||||||
|
DatabaseReference ref =
|
||||||
|
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
|
Stream<DatabaseEvent> stream = ref.onValue;
|
||||||
|
|
||||||
|
stream.listen((DatabaseEvent event) {
|
||||||
|
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
if (data['status'] != null) {
|
||||||
|
for (var element in data['status']) {
|
||||||
|
statusList.add(
|
||||||
|
Status(
|
||||||
|
code: element['code'].toString(),
|
||||||
|
value: element['value'].toString(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (statusList.isNotEmpty) {
|
||||||
|
bool newStatus = _checkStatus(statusList[0].value);
|
||||||
|
if (newStatus != deviceStatus) {
|
||||||
|
deviceStatus = newStatus;
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
emit(CurtainError('Failed to listen to changes: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(StatusUpdated event, Emitter<CurtainState> emit) {
|
||||||
|
emit(CurtainStatusLoading());
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(CurtainStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
FutureOr<void> _onCurtainControl(
|
FutureOr<void> _onCurtainControl(
|
||||||
CurtainControl event, Emitter<CurtainState> emit) async {
|
CurtainControl event, Emitter<CurtainState> emit) async {
|
||||||
final oldValue = deviceStatus;
|
final oldValue = deviceStatus;
|
||||||
|
@ -60,3 +60,7 @@ class CurtainFactoryReset extends CurtainEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceId, factoryReset];
|
List<Object> get props => [deviceId, factoryReset];
|
||||||
}
|
}
|
||||||
|
class StatusUpdated extends CurtainEvent {
|
||||||
|
final bool deviceStatus;
|
||||||
|
const StatusUpdated(this.deviceStatus);
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_event.dart';
|
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_event.dart';
|
||||||
@ -18,6 +19,39 @@ class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
|||||||
//on<DoorLockControl>(_onDoorLockControl);
|
//on<DoorLockControl>(_onDoorLockControl);
|
||||||
on<UpdateLockEvent>(_updateLock);
|
on<UpdateLockEvent>(_updateLock);
|
||||||
on<DoorLockFactoryReset>(_onFactoryReset);
|
on<DoorLockFactoryReset>(_onFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
|
}
|
||||||
|
|
||||||
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus =
|
||||||
|
DoorLockStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(StatusUpdated event, Emitter<DoorLockState> emit) {
|
||||||
|
emit(DoorLockStatusLoading());
|
||||||
|
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(DoorLockStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFetchDeviceStatus(
|
FutureOr<void> _onFetchDeviceStatus(
|
||||||
@ -28,6 +62,8 @@ class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
|||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
DoorLockStatusModel.fromJson(event.deviceId, status.status);
|
DoorLockStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
|
|
||||||
emit(DoorLockStatusLoaded(deviceStatus));
|
emit(DoorLockStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(DoorLockControlError(e.toString()));
|
emit(DoorLockControlError(e.toString()));
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/door_lock/models/door_lock_status_model.dart';
|
||||||
|
|
||||||
sealed class DoorLockEvent extends Equatable {
|
sealed class DoorLockEvent extends Equatable {
|
||||||
const DoorLockEvent();
|
const DoorLockEvent();
|
||||||
@ -51,3 +52,10 @@ class DoorLockFactoryReset extends DoorLockEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceId, factoryReset];
|
List<Object> get props => [deviceId, factoryReset];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends DoorLockEvent {
|
||||||
|
final DoorLockStatusModel deviceStatus;
|
||||||
|
const StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/garage_door/bloc/garage_door_event.dart';
|
import 'package:syncrow_web/pages/device_managment/garage_door/bloc/garage_door_event.dart';
|
||||||
@ -39,31 +40,68 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
on<GarageDoorFetchBatchStatusEvent>(_onFetchBatchStatus);
|
on<GarageDoorFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||||
on<GarageDoorFactoryResetEvent>(_onFactoryReset);
|
on<GarageDoorFactoryResetEvent>(_onFactoryReset);
|
||||||
on<EditGarageDoorScheduleEvent>(_onEditSchedule);
|
on<EditGarageDoorScheduleEvent>(_onEditSchedule);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
|
}
|
||||||
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus =
|
||||||
|
GarageDoorStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _fetchGarageDoorStatus(GarageDoorInitialEvent event, Emitter<GarageDoorState> emit) async {
|
void _onStatusUpdated(StatusUpdated event, Emitter<GarageDoorState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _fetchGarageDoorStatus(
|
||||||
|
GarageDoorInitialEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
emit(GarageDoorLoadingState());
|
emit(GarageDoorLoadingState());
|
||||||
try {
|
try {
|
||||||
var response = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
var response =
|
||||||
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
deviceStatus = GarageDoorStatusModel.fromJson(deviceId, response.status);
|
deviceStatus = GarageDoorStatusModel.fromJson(deviceId, response.status);
|
||||||
|
_listenToChanges(deviceId);
|
||||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(GarageDoorErrorState(message: e.toString()));
|
emit(GarageDoorErrorState(message: e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event,
|
||||||
|
Emitter<GarageDoorState> emit) async {
|
||||||
emit(GarageDoorLoadingState());
|
emit(GarageDoorLoadingState());
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
final status =
|
||||||
deviceStatus = GarageDoorStatusModel.fromJson(event.deviceIds.first, status.status);
|
await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||||
|
deviceStatus =
|
||||||
|
GarageDoorStatusModel.fromJson(event.deviceIds.first, status.status);
|
||||||
emit(GarageDoorBatchStatusLoaded(deviceStatus));
|
emit(GarageDoorBatchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(GarageDoorBatchControlError(e.toString()));
|
emit(GarageDoorBatchControlError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addSchedule(AddGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _addSchedule(
|
||||||
|
AddGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
try {
|
try {
|
||||||
ScheduleEntry newSchedule = ScheduleEntry(
|
ScheduleEntry newSchedule = ScheduleEntry(
|
||||||
category: event.category,
|
category: event.category,
|
||||||
@ -71,9 +109,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
function: Status(code: 'switch_1', value: event.functionOn),
|
function: Status(code: 'switch_1', value: event.functionOn),
|
||||||
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
||||||
);
|
);
|
||||||
bool success = await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId);
|
bool success =
|
||||||
|
await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId);
|
||||||
if (success) {
|
if (success) {
|
||||||
add(FetchGarageDoorSchedulesEvent(deviceId: deviceId, category: 'switch_1'));
|
add(FetchGarageDoorSchedulesEvent(
|
||||||
|
deviceId: deviceId, category: 'switch_1'));
|
||||||
} else {
|
} else {
|
||||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
}
|
}
|
||||||
@ -82,16 +122,19 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onUpdateCountdownAlarm(UpdateCountdownAlarmEvent event, Emitter<GarageDoorState> emit) {
|
void _onUpdateCountdownAlarm(
|
||||||
|
UpdateCountdownAlarmEvent event, Emitter<GarageDoorState> emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is GarageDoorLoadedState) {
|
if (currentState is GarageDoorLoadedState) {
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
status: currentState.status.copyWith(countdownAlarm: event.countdownAlarm),
|
status:
|
||||||
|
currentState.status.copyWith(countdownAlarm: event.countdownAlarm),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onUpdateTrTimeCon(UpdateTrTimeConEvent event, Emitter<GarageDoorState> emit) {
|
void _onUpdateTrTimeCon(
|
||||||
|
UpdateTrTimeConEvent event, Emitter<GarageDoorState> emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is GarageDoorLoadedState) {
|
if (currentState is GarageDoorLoadedState) {
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
@ -100,7 +143,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateSchedule(UpdateGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _updateSchedule(UpdateGarageDoorScheduleEvent event,
|
||||||
|
Emitter<GarageDoorState> emit) async {
|
||||||
try {
|
try {
|
||||||
final updatedSchedules = deviceStatus.schedules?.map((schedule) {
|
final updatedSchedules = deviceStatus.schedules?.map((schedule) {
|
||||||
if (schedule.scheduleId == event.scheduleId) {
|
if (schedule.scheduleId == event.scheduleId) {
|
||||||
@ -127,12 +171,15 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _deleteSchedule(DeleteGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _deleteSchedule(DeleteGarageDoorScheduleEvent event,
|
||||||
|
Emitter<GarageDoorState> emit) async {
|
||||||
try {
|
try {
|
||||||
bool success = await DevicesManagementApi().deleteScheduleRecord(deviceStatus.uuid, event.scheduleId);
|
bool success = await DevicesManagementApi()
|
||||||
|
.deleteScheduleRecord(deviceStatus.uuid, event.scheduleId);
|
||||||
if (success) {
|
if (success) {
|
||||||
final updatedSchedules =
|
final updatedSchedules = deviceStatus.schedules
|
||||||
deviceStatus.schedules?.where((schedule) => schedule.scheduleId != event.scheduleId).toList();
|
?.where((schedule) => schedule.scheduleId != event.scheduleId)
|
||||||
|
.toList();
|
||||||
deviceStatus = deviceStatus.copyWith(schedules: updatedSchedules);
|
deviceStatus = deviceStatus.copyWith(schedules: updatedSchedules);
|
||||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
} else {
|
} else {
|
||||||
@ -143,11 +190,12 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _fetchSchedules(FetchGarageDoorSchedulesEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _fetchSchedules(FetchGarageDoorSchedulesEvent event,
|
||||||
|
Emitter<GarageDoorState> emit) async {
|
||||||
emit(ScheduleGarageLoadingState());
|
emit(ScheduleGarageLoadingState());
|
||||||
try {
|
try {
|
||||||
List<ScheduleModel> schedules =
|
List<ScheduleModel> schedules = await DevicesManagementApi()
|
||||||
await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category);
|
.getDeviceSchedules(deviceStatus.uuid, event.category);
|
||||||
deviceStatus = deviceStatus.copyWith(schedules: schedules);
|
deviceStatus = deviceStatus.copyWith(schedules: schedules);
|
||||||
emit(
|
emit(
|
||||||
GarageDoorLoadedState(
|
GarageDoorLoadedState(
|
||||||
@ -165,30 +213,37 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateSelectedTime(UpdateSelectedTimeEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _updateSelectedTime(
|
||||||
|
UpdateSelectedTimeEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is GarageDoorLoadedState) {
|
if (currentState is GarageDoorLoadedState) {
|
||||||
emit(currentState.copyWith(selectedTime: event.selectedTime));
|
emit(currentState.copyWith(selectedTime: event.selectedTime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateSelectedDay(UpdateSelectedDayEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _updateSelectedDay(
|
||||||
|
UpdateSelectedDayEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is GarageDoorLoadedState) {
|
if (currentState is GarageDoorLoadedState) {
|
||||||
List<bool> updatedDays = List.from(currentState.selectedDays);
|
List<bool> updatedDays = List.from(currentState.selectedDays);
|
||||||
updatedDays[event.dayIndex] = event.isSelected;
|
updatedDays[event.dayIndex] = event.isSelected;
|
||||||
emit(currentState.copyWith(selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
emit(currentState.copyWith(
|
||||||
|
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateFunctionOn(UpdateFunctionOnEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _updateFunctionOn(
|
||||||
|
UpdateFunctionOnEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is GarageDoorLoadedState) {
|
if (currentState is GarageDoorLoadedState) {
|
||||||
emit(currentState.copyWith(functionOn: event.functionOn, selectedTime: currentState.selectedTime));
|
emit(currentState.copyWith(
|
||||||
|
functionOn: event.functionOn,
|
||||||
|
selectedTime: currentState.selectedTime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initializeAddSchedule(InitializeAddScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _initializeAddSchedule(
|
||||||
|
InitializeAddScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is GarageDoorLoadedState) {
|
if (currentState is GarageDoorLoadedState) {
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
@ -200,20 +255,25 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _fetchRecords(FetchGarageDoorRecordsEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _fetchRecords(
|
||||||
|
FetchGarageDoorRecordsEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
emit(GarageDoorReportsLoadingState());
|
emit(GarageDoorReportsLoadingState());
|
||||||
try {
|
try {
|
||||||
final from = DateTime.now().subtract(const Duration(days: 30)).millisecondsSinceEpoch;
|
final from = DateTime.now()
|
||||||
|
.subtract(const Duration(days: 30))
|
||||||
|
.millisecondsSinceEpoch;
|
||||||
final to = DateTime.now().millisecondsSinceEpoch;
|
final to = DateTime.now().millisecondsSinceEpoch;
|
||||||
final DeviceReport records =
|
final DeviceReport records =
|
||||||
await DevicesManagementApi.getDeviceReportsByDate(event.deviceId, 'switch_1', from.toString(), to.toString());
|
await DevicesManagementApi.getDeviceReportsByDate(
|
||||||
|
event.deviceId, 'switch_1', from.toString(), to.toString());
|
||||||
emit(GarageDoorReportsState(deviceReport: records));
|
emit(GarageDoorReportsState(deviceReport: records));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(GarageDoorReportsFailedState(error: e.toString()));
|
emit(GarageDoorReportsFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBatchControl(GarageDoorBatchControlEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _onBatchControl(
|
||||||
|
GarageDoorBatchControlEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
final oldValue = event.code == 'switch_1' ? deviceStatus.switch1 : false;
|
final oldValue = event.code == 'switch_1' ? deviceStatus.switch1 : false;
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
@ -233,11 +293,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _backToGridView(BackToGarageDoorGridViewEvent event, Emitter<GarageDoorState> emit) {
|
void _backToGridView(
|
||||||
|
BackToGarageDoorGridViewEvent event, Emitter<GarageDoorState> emit) {
|
||||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleUpdate(GarageDoorUpdatedEvent event, Emitter<GarageDoorState> emit) {
|
void _handleUpdate(
|
||||||
|
GarageDoorUpdatedEvent event, Emitter<GarageDoorState> emit) {
|
||||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,9 +315,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
late bool status;
|
late bool status;
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
if (isBatch) {
|
if (isBatch) {
|
||||||
status = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
status = await DevicesManagementApi()
|
||||||
|
.deviceBatchControl(deviceId, code, value);
|
||||||
} else {
|
} else {
|
||||||
status = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
|
status = await DevicesManagementApi()
|
||||||
|
.deviceControl(deviceId, Status(code: code, value: value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
@ -270,10 +334,12 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFactoryReset(GarageDoorFactoryResetEvent event, Emitter<GarageDoorState> emit) async {
|
Future<void> _onFactoryReset(
|
||||||
|
GarageDoorFactoryResetEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
emit(GarageDoorLoadingState());
|
emit(GarageDoorLoadingState());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
|
final response = await DevicesManagementApi()
|
||||||
|
.factoryReset(event.factoryReset, event.deviceId);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
emit(const GarageDoorErrorState(message: 'Failed to reset device'));
|
emit(const GarageDoorErrorState(message: 'Failed to reset device'));
|
||||||
} else {
|
} else {
|
||||||
@ -284,34 +350,47 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _increaseDelay(IncreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
|
void _increaseDelay(
|
||||||
|
IncreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
// if (deviceStatus.countdown1 != 0) {
|
// if (deviceStatus.countdown1 != 0) {
|
||||||
try {
|
try {
|
||||||
deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay + Duration(minutes: 10));
|
deviceStatus = deviceStatus.copyWith(
|
||||||
|
delay: deviceStatus.delay + Duration(minutes: 10));
|
||||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1'));
|
add(GarageDoorControlEvent(
|
||||||
|
deviceId: event.deviceId,
|
||||||
|
value: deviceStatus.delay.inSeconds,
|
||||||
|
code: 'countdown_1'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(GarageDoorErrorState(message: e.toString()));
|
emit(GarageDoorErrorState(message: e.toString()));
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void _decreaseDelay(DecreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
|
void _decreaseDelay(
|
||||||
|
DecreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
// if (deviceStatus.countdown1 != 0) {
|
// if (deviceStatus.countdown1 != 0) {
|
||||||
try {
|
try {
|
||||||
if (deviceStatus.delay.inMinutes > 10) {
|
if (deviceStatus.delay.inMinutes > 10) {
|
||||||
deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay - Duration(minutes: 10));
|
deviceStatus = deviceStatus.copyWith(
|
||||||
|
delay: deviceStatus.delay - Duration(minutes: 10));
|
||||||
}
|
}
|
||||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1'));
|
add(GarageDoorControlEvent(
|
||||||
|
deviceId: event.deviceId,
|
||||||
|
value: deviceStatus.delay.inSeconds,
|
||||||
|
code: 'countdown_1'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(GarageDoorErrorState(message: e.toString()));
|
emit(GarageDoorErrorState(message: e.toString()));
|
||||||
}
|
}
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _garageDoorControlEvent(GarageDoorControlEvent event, Emitter<GarageDoorState> emit) async {
|
void _garageDoorControlEvent(
|
||||||
final oldValue = event.code == 'countdown_1' ? deviceStatus.countdown1 : deviceStatus.switch1;
|
GarageDoorControlEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
|
final oldValue = event.code == 'countdown_1'
|
||||||
|
? deviceStatus.countdown1
|
||||||
|
: deviceStatus.switch1;
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
final success = await _runDeBouncer(
|
final success = await _runDeBouncer(
|
||||||
@ -327,7 +406,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _revertValue(String code, dynamic oldValue, Emitter<GarageDoorState> emit) {
|
void _revertValue(
|
||||||
|
String code, dynamic oldValue, Emitter<GarageDoorState> emit) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 'switch_1':
|
case 'switch_1':
|
||||||
if (oldValue is bool) {
|
if (oldValue is bool) {
|
||||||
@ -336,7 +416,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
break;
|
break;
|
||||||
case 'countdown_1':
|
case 'countdown_1':
|
||||||
if (oldValue is int) {
|
if (oldValue is int) {
|
||||||
deviceStatus = deviceStatus.copyWith(countdown1: oldValue, delay: Duration(seconds: oldValue));
|
deviceStatus = deviceStatus.copyWith(
|
||||||
|
countdown1: oldValue, delay: Duration(seconds: oldValue));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// Add other cases if needed
|
// Add other cases if needed
|
||||||
@ -358,7 +439,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
break;
|
break;
|
||||||
case 'countdown_1':
|
case 'countdown_1':
|
||||||
if (value is int) {
|
if (value is int) {
|
||||||
deviceStatus = deviceStatus.copyWith(countdown1: value, delay: Duration(seconds: value));
|
deviceStatus = deviceStatus.copyWith(
|
||||||
|
countdown1: value, delay: Duration(seconds: value));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'countdown_alarm':
|
case 'countdown_alarm':
|
||||||
@ -401,7 +483,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onEditSchedule(EditGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
FutureOr<void> _onEditSchedule(
|
||||||
|
EditGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||||
try {
|
try {
|
||||||
ScheduleEntry newSchedule = ScheduleEntry(
|
ScheduleEntry newSchedule = ScheduleEntry(
|
||||||
scheduleId: event.scheduleId,
|
scheduleId: event.scheduleId,
|
||||||
@ -410,9 +493,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
|||||||
function: Status(code: 'switch_1', value: event.functionOn),
|
function: Status(code: 'switch_1', value: event.functionOn),
|
||||||
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
||||||
);
|
);
|
||||||
bool success = await DevicesManagementApi().editScheduleRecord(deviceId, newSchedule);
|
bool success = await DevicesManagementApi()
|
||||||
|
.editScheduleRecord(deviceId, newSchedule);
|
||||||
if (success) {
|
if (success) {
|
||||||
add(FetchGarageDoorSchedulesEvent(deviceId: deviceId, category: 'switch_1'));
|
add(FetchGarageDoorSchedulesEvent(
|
||||||
|
deviceId: deviceId, category: 'switch_1'));
|
||||||
} else {
|
} else {
|
||||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/garage_door/models/garage_door_model.dart';
|
||||||
|
|
||||||
abstract class GarageDoorEvent extends Equatable {
|
abstract class GarageDoorEvent extends Equatable {
|
||||||
const GarageDoorEvent();
|
const GarageDoorEvent();
|
||||||
@ -25,7 +26,8 @@ class GarageDoorControlEvent extends GarageDoorEvent {
|
|||||||
final dynamic value;
|
final dynamic value;
|
||||||
final String code;
|
final String code;
|
||||||
|
|
||||||
const GarageDoorControlEvent({required this.deviceId, required this.value, required this.code});
|
const GarageDoorControlEvent(
|
||||||
|
{required this.deviceId, required this.value, required this.code});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [deviceId, value];
|
List<Object?> get props => [deviceId, value];
|
||||||
@ -121,7 +123,8 @@ class FetchGarageDoorRecordsEvent extends GarageDoorEvent {
|
|||||||
final String deviceId;
|
final String deviceId;
|
||||||
final String code;
|
final String code;
|
||||||
|
|
||||||
const FetchGarageDoorRecordsEvent({required this.deviceId, required this.code});
|
const FetchGarageDoorRecordsEvent(
|
||||||
|
{required this.deviceId, required this.code});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [deviceId, code];
|
List<Object?> get props => [deviceId, code];
|
||||||
@ -232,3 +235,10 @@ class GarageDoorFactoryResetEvent extends GarageDoorEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => [factoryReset, deviceId];
|
List<Object?> get props => [factoryReset, deviceId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends GarageDoorEvent {
|
||||||
|
final GarageDoorStatusModel deviceStatus;
|
||||||
|
const StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
@ -16,6 +17,7 @@ class MainDoorSensorBloc
|
|||||||
on<MainDoorSensorFetchBatchEvent>(_onFetchBatchStatus);
|
on<MainDoorSensorFetchBatchEvent>(_onFetchBatchStatus);
|
||||||
on<MainDoorSensorReportsEvent>(_fetchReports);
|
on<MainDoorSensorReportsEvent>(_fetchReports);
|
||||||
on<MainDoorSensorFactoryReset>(_factoryReset);
|
on<MainDoorSensorFactoryReset>(_factoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
late MainDoorSensorStatusModel deviceStatus;
|
late MainDoorSensorStatusModel deviceStatus;
|
||||||
@ -28,7 +30,7 @@ class MainDoorSensorBloc
|
|||||||
final status = await DevicesManagementApi()
|
final status = await DevicesManagementApi()
|
||||||
.getDeviceStatus(event.deviceId)
|
.getDeviceStatus(event.deviceId)
|
||||||
.then((value) => value.status);
|
.then((value) => value.status);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
deviceStatus = MainDoorSensorStatusModel.fromJson(event.deviceId, status);
|
deviceStatus = MainDoorSensorStatusModel.fromJson(event.deviceId, status);
|
||||||
emit(MainDoorSensorDeviceStatusLoaded(deviceStatus));
|
emit(MainDoorSensorDeviceStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -156,4 +158,35 @@ class MainDoorSensorBloc
|
|||||||
emit(MainDoorSensorFailedState(error: e.toString()));
|
emit(MainDoorSensorFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus = MainDoorSensorStatusModel.fromJson(
|
||||||
|
usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event, Emitter<MainDoorSensorState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(MainDoorSensorDeviceStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/main_door_sensor/models/main_door_status_model.dart';
|
||||||
|
|
||||||
import '../../all_devices/models/factory_reset_model.dart';
|
import '../../all_devices/models/factory_reset_model.dart';
|
||||||
|
|
||||||
@ -71,3 +72,10 @@ class MainDoorSensorFactoryReset extends MainDoorSensorEvent {
|
|||||||
MainDoorSensorFactoryReset(
|
MainDoorSensorFactoryReset(
|
||||||
{required this.deviceId, required this.factoryReset});
|
{required this.deviceId, required this.factoryReset});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends MainDoorSensorEvent {
|
||||||
|
final MainDoorSensorStatusModel deviceStatus;
|
||||||
|
StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
@ -10,33 +11,71 @@ import 'package:syncrow_web/services/devices_mang_api.dart';
|
|||||||
part 'one_gang_glass_switch_event.dart';
|
part 'one_gang_glass_switch_event.dart';
|
||||||
part 'one_gang_glass_switch_state.dart';
|
part 'one_gang_glass_switch_state.dart';
|
||||||
|
|
||||||
class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
|
class OneGangGlassSwitchBloc
|
||||||
|
extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
|
||||||
OneGangGlassStatusModel deviceStatus;
|
OneGangGlassStatusModel deviceStatus;
|
||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
|
|
||||||
OneGangGlassSwitchBloc({required String deviceId})
|
OneGangGlassSwitchBloc({required String deviceId})
|
||||||
: deviceStatus = OneGangGlassStatusModel(uuid: deviceId, switch1: false, countDown: 0),
|
: deviceStatus = OneGangGlassStatusModel(
|
||||||
|
uuid: deviceId, switch1: false, countDown: 0),
|
||||||
super(OneGangGlassSwitchInitial()) {
|
super(OneGangGlassSwitchInitial()) {
|
||||||
on<OneGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
on<OneGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||||
on<OneGangGlassSwitchControl>(_onControl);
|
on<OneGangGlassSwitchControl>(_onControl);
|
||||||
on<OneGangGlassSwitchBatchControl>(_onBatchControl);
|
on<OneGangGlassSwitchBatchControl>(_onBatchControl);
|
||||||
on<OneGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
on<OneGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||||
on<OneGangGlassFactoryResetEvent>(_onFactoryReset);
|
on<OneGangGlassFactoryResetEvent>(_onFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDeviceStatus(
|
Future<void> _onFetchDeviceStatus(OneGangGlassSwitchFetchDeviceEvent event,
|
||||||
OneGangGlassSwitchFetchDeviceEvent event, Emitter<OneGangGlassSwitchState> emit) async {
|
Emitter<OneGangGlassSwitchState> emit) async {
|
||||||
emit(OneGangGlassSwitchLoading());
|
emit(OneGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
final status =
|
||||||
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
|
deviceStatus =
|
||||||
|
OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(OneGangGlassSwitchError(e.toString()));
|
emit(OneGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onControl(OneGangGlassSwitchControl event, Emitter<OneGangGlassSwitchState> emit) async {
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus = OneGangGlassStatusModel.fromJson(
|
||||||
|
usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event, Emitter<OneGangGlassSwitchState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onControl(OneGangGlassSwitchControl event,
|
||||||
|
Emitter<OneGangGlassSwitchState> emit) async {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final oldValue = _getValueByCode(event.code);
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
@ -52,10 +91,12 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFactoryReset(OneGangGlassFactoryResetEvent event, Emitter<OneGangGlassSwitchState> emit) async {
|
Future<void> _onFactoryReset(OneGangGlassFactoryResetEvent event,
|
||||||
|
Emitter<OneGangGlassSwitchState> emit) async {
|
||||||
emit(OneGangGlassSwitchLoading());
|
emit(OneGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
|
final response = await DevicesManagementApi()
|
||||||
|
.factoryReset(event.factoryReset, event.deviceId);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
emit(OneGangGlassSwitchError('Failed to reset device'));
|
emit(OneGangGlassSwitchError('Failed to reset device'));
|
||||||
} else {
|
} else {
|
||||||
@ -66,7 +107,8 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBatchControl(OneGangGlassSwitchBatchControl event, Emitter<OneGangGlassSwitchState> emit) async {
|
Future<void> _onBatchControl(OneGangGlassSwitchBatchControl event,
|
||||||
|
Emitter<OneGangGlassSwitchState> emit) async {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final oldValue = _getValueByCode(event.code);
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
@ -83,11 +125,14 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(
|
Future<void> _onFetchBatchStatus(
|
||||||
OneGangGlassSwitchFetchBatchStatusEvent event, Emitter<OneGangGlassSwitchState> emit) async {
|
OneGangGlassSwitchFetchBatchStatusEvent event,
|
||||||
|
Emitter<OneGangGlassSwitchState> emit) async {
|
||||||
emit(OneGangGlassSwitchLoading());
|
emit(OneGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
final status =
|
||||||
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceIds.first, status.status);
|
await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||||
|
deviceStatus = OneGangGlassStatusModel.fromJson(
|
||||||
|
event.deviceIds.first, status.status);
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(OneGangGlassSwitchError(e.toString()));
|
emit(OneGangGlassSwitchError(e.toString()));
|
||||||
@ -117,9 +162,11 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
|||||||
try {
|
try {
|
||||||
late bool response;
|
late bool response;
|
||||||
if (isBatch) {
|
if (isBatch) {
|
||||||
response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
response = await DevicesManagementApi()
|
||||||
|
.deviceBatchControl(deviceId, code, value);
|
||||||
} else {
|
} else {
|
||||||
response = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
|
response = await DevicesManagementApi()
|
||||||
|
.deviceControl(deviceId, Status(code: code, value: value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@ -131,7 +178,8 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue, Emitter<OneGangGlassSwitchState> emit) {
|
void _revertValueAndEmit(String deviceId, String code, bool oldValue,
|
||||||
|
Emitter<OneGangGlassSwitchState> emit) {
|
||||||
_updateLocalValue(code, oldValue);
|
_updateLocalValue(code, oldValue);
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,11 @@ class OneGangGlassSwitchFetchBatchStatusEvent extends OneGangGlassSwitchEvent {
|
|||||||
OneGangGlassSwitchFetchBatchStatusEvent(this.deviceIds);
|
OneGangGlassSwitchFetchBatchStatusEvent(this.deviceIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends OneGangGlassSwitchEvent {
|
||||||
|
final OneGangGlassStatusModel deviceStatus;
|
||||||
|
StatusUpdated(this.deviceStatus);
|
||||||
|
}
|
||||||
|
|
||||||
class OneGangGlassFactoryResetEvent extends OneGangGlassSwitchEvent {
|
class OneGangGlassFactoryResetEvent extends OneGangGlassSwitchEvent {
|
||||||
final FactoryResetModel factoryReset;
|
final FactoryResetModel factoryReset;
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart';
|
||||||
@ -16,6 +17,7 @@ class WallLightSwitchBloc
|
|||||||
on<WallLightSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
on<WallLightSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
||||||
on<WallLightSwitchBatchControl>(_onBatchControl);
|
on<WallLightSwitchBatchControl>(_onBatchControl);
|
||||||
on<WallLightFactoryReset>(_onFactoryReset);
|
on<WallLightFactoryReset>(_onFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
late WallLightStatusModel deviceStatus;
|
late WallLightStatusModel deviceStatus;
|
||||||
@ -31,12 +33,44 @@ class WallLightSwitchBloc
|
|||||||
|
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
WallLightStatusModel.fromJson(event.deviceId, status.status);
|
WallLightStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(WallLightSwitchError(e.toString()));
|
emit(WallLightSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus =
|
||||||
|
WallLightStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event, Emitter<WallLightSwitchState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
FutureOr<void> _onControl(
|
FutureOr<void> _onControl(
|
||||||
WallLightSwitchControl event, Emitter<WallLightSwitchState> emit) async {
|
WallLightSwitchControl event, Emitter<WallLightSwitchState> emit) async {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final oldValue = _getValueByCode(event.code);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart';
|
||||||
|
|
||||||
class WallLightSwitchEvent extends Equatable {
|
class WallLightSwitchEvent extends Equatable {
|
||||||
@override
|
@override
|
||||||
@ -57,3 +58,10 @@ class WallLightFactoryReset extends WallLightSwitchEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceId, factoryReset];
|
List<Object> get props => [deviceId, factoryReset];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends WallLightSwitchEvent {
|
||||||
|
final WallLightStatusModel deviceStatus;
|
||||||
|
StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
@ -95,8 +95,9 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
|||||||
]),
|
]),
|
||||||
TableRow(
|
TableRow(
|
||||||
children: [
|
children: [
|
||||||
_buildInfoRow('Space Name:', device.unit?.name ?? 'N/A'),
|
_buildInfoRow('Space Name:',
|
||||||
_buildInfoRow('Room:', device.room?.name ?? 'N/A'),
|
device.spaces?.firstOrNull?.spaceName ?? 'N/A'),
|
||||||
|
_buildInfoRow('Room:', device.subspace?.subspaceName ?? 'N/A'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
TableRow(
|
TableRow(
|
||||||
@ -111,9 +112,13 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
|||||||
),
|
),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
'Battery Level:',
|
'Battery Level:',
|
||||||
device.batteryLevel != null ? '${device.batteryLevel ?? 0}%' : "-",
|
device.batteryLevel != null
|
||||||
|
? '${device.batteryLevel ?? 0}%'
|
||||||
|
: "-",
|
||||||
statusColor: device.batteryLevel != null
|
statusColor: device.batteryLevel != null
|
||||||
? (device.batteryLevel! < 20 ? ColorsManager.red : ColorsManager.green)
|
? (device.batteryLevel! < 20
|
||||||
|
? ColorsManager.red
|
||||||
|
: ColorsManager.green)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/sos/bloc/sos_device_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/sos/bloc/sos_device_bloc.dart';
|
||||||
|
|
||||||
class SOSBatchControlView extends StatelessWidget {
|
class SOSBatchControlView extends StatelessWidget {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
@ -10,7 +11,8 @@ import 'package:syncrow_web/services/devices_mang_api.dart';
|
|||||||
part 'three_gang_glass_switch_event.dart';
|
part 'three_gang_glass_switch_event.dart';
|
||||||
part 'three_gang_glass_switch_state.dart';
|
part 'three_gang_glass_switch_state.dart';
|
||||||
|
|
||||||
class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGangGlassSwitchState> {
|
class ThreeGangGlassSwitchBloc
|
||||||
|
extends Bloc<ThreeGangGlassSwitchEvent, ThreeGangGlassSwitchState> {
|
||||||
ThreeGangGlassStatusModel deviceStatus;
|
ThreeGangGlassStatusModel deviceStatus;
|
||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
|
|
||||||
@ -29,21 +31,57 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
|||||||
on<ThreeGangGlassSwitchBatchControl>(_onBatchControl);
|
on<ThreeGangGlassSwitchBatchControl>(_onBatchControl);
|
||||||
on<ThreeGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
on<ThreeGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||||
on<ThreeGangGlassFactoryReset>(_onFactoryReset);
|
on<ThreeGangGlassFactoryReset>(_onFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDeviceStatus(
|
Future<void> _onFetchDeviceStatus(ThreeGangGlassSwitchFetchDeviceEvent event,
|
||||||
ThreeGangGlassSwitchFetchDeviceEvent event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||||
emit(ThreeGangGlassSwitchLoading());
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
final status =
|
||||||
deviceStatus = ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
|
deviceStatus =
|
||||||
|
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ThreeGangGlassSwitchError(e.toString()));
|
emit(ThreeGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onControl(ThreeGangGlassSwitchControl event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus = ThreeGangGlassStatusModel.fromJson(
|
||||||
|
usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event, Emitter<ThreeGangGlassSwitchState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onControl(ThreeGangGlassSwitchControl event,
|
||||||
|
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final oldValue = _getValueByCode(event.code);
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
@ -59,7 +97,8 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBatchControl(ThreeGangGlassSwitchBatchControl event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
Future<void> _onBatchControl(ThreeGangGlassSwitchBatchControl event,
|
||||||
|
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final oldValue = _getValueByCode(event.code);
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
@ -76,21 +115,26 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(
|
Future<void> _onFetchBatchStatus(
|
||||||
ThreeGangGlassSwitchFetchBatchStatusEvent event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
ThreeGangGlassSwitchFetchBatchStatusEvent event,
|
||||||
|
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||||
emit(ThreeGangGlassSwitchLoading());
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
final status =
|
||||||
deviceStatus = ThreeGangGlassStatusModel.fromJson(event.deviceIds.first, status.status);
|
await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||||
|
deviceStatus = ThreeGangGlassStatusModel.fromJson(
|
||||||
|
event.deviceIds.first, status.status);
|
||||||
emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ThreeGangGlassSwitchError(e.toString()));
|
emit(ThreeGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFactoryReset(ThreeGangGlassFactoryReset event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
Future<void> _onFactoryReset(ThreeGangGlassFactoryReset event,
|
||||||
|
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||||
emit(ThreeGangGlassSwitchLoading());
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
|
final response = await DevicesManagementApi()
|
||||||
|
.factoryReset(event.factoryReset, event.deviceId);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
emit(ThreeGangGlassSwitchError('Failed'));
|
emit(ThreeGangGlassSwitchError('Failed'));
|
||||||
} else {
|
} else {
|
||||||
@ -124,9 +168,11 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
|||||||
try {
|
try {
|
||||||
late bool response;
|
late bool response;
|
||||||
if (isBatch) {
|
if (isBatch) {
|
||||||
response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
response = await DevicesManagementApi()
|
||||||
|
.deviceBatchControl(deviceId, code, value);
|
||||||
} else {
|
} else {
|
||||||
response = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
|
response = await DevicesManagementApi()
|
||||||
|
.deviceControl(deviceId, Status(code: code, value: value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@ -138,7 +184,8 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue, Emitter<ThreeGangGlassSwitchState> emit) {
|
void _revertValueAndEmit(String deviceId, String code, bool oldValue,
|
||||||
|
Emitter<ThreeGangGlassSwitchState> emit) {
|
||||||
_updateLocalValue(code, oldValue);
|
_updateLocalValue(code, oldValue);
|
||||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
@ -49,3 +49,10 @@ class ThreeGangGlassFactoryReset extends ThreeGangGlassSwitchEvent {
|
|||||||
required this.factoryReset,
|
required this.factoryReset,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends ThreeGangGlassSwitchEvent {
|
||||||
|
final ThreeGangGlassStatusModel deviceStatus;
|
||||||
|
StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart';
|
import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart';
|
||||||
@ -22,6 +23,7 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
|||||||
on<LivingRoomBatchControl>(_livingRoomBatchControl);
|
on<LivingRoomBatchControl>(_livingRoomBatchControl);
|
||||||
on<LivingRoomFetchBatchEvent>(_livingRoomFetchBatchControl);
|
on<LivingRoomFetchBatchEvent>(_livingRoomFetchBatchControl);
|
||||||
on<LivingRoomFactoryResetEvent>(_livingRoomFactoryReset);
|
on<LivingRoomFactoryResetEvent>(_livingRoomFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFetchDeviceStatus(LivingRoomFetchDeviceStatusEvent event,
|
FutureOr<void> _onFetchDeviceStatus(LivingRoomFetchDeviceStatusEvent event,
|
||||||
@ -32,6 +34,7 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
|||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
LivingRoomStatusModel.fromJson(event.deviceId, status.status);
|
LivingRoomStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
_listenToChanges(deviceId);
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(LivingRoomDeviceManagementError(e.toString()));
|
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||||
@ -144,6 +147,9 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
|||||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
LivingRoomStatusModel.fromJson(event.devicesIds.first, status.status);
|
LivingRoomStatusModel.fromJson(event.devicesIds.first, status.status);
|
||||||
|
// for (var deviceId in event.devicesIds) {
|
||||||
|
// _listenToChanges(deviceId);
|
||||||
|
// }
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(LivingRoomDeviceManagementError(e.toString()));
|
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||||
@ -185,4 +191,34 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
|||||||
emit(LivingRoomDeviceManagementError(e.toString()));
|
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus =
|
||||||
|
LivingRoomStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(StatusUpdated event, Emitter<LivingRoomState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,3 +58,10 @@ class LivingRoomFactoryResetEvent extends LivingRoomEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [uuid, factoryReset];
|
List<Object> get props => [uuid, factoryReset];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends LivingRoomEvent {
|
||||||
|
final LivingRoomStatusModel deviceStatus;
|
||||||
|
const StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two_gang_glass_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two_gang_glass_status_model.dart';
|
||||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
part 'two_gang_glass_switch_event.dart';
|
part 'two_gang_glass_switch_event.dart';
|
||||||
part 'two_gang_glass_switch_state.dart';
|
part 'two_gang_glass_switch_state.dart';
|
||||||
|
|
||||||
@ -14,7 +13,6 @@ class TwoGangGlassSwitchBloc
|
|||||||
extends Bloc<TwoGangGlassSwitchEvent, TwoGangGlassSwitchState> {
|
extends Bloc<TwoGangGlassSwitchEvent, TwoGangGlassSwitchState> {
|
||||||
TwoGangGlassStatusModel deviceStatus;
|
TwoGangGlassStatusModel deviceStatus;
|
||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
|
|
||||||
TwoGangGlassSwitchBloc({required String deviceId})
|
TwoGangGlassSwitchBloc({required String deviceId})
|
||||||
: deviceStatus = TwoGangGlassStatusModel(
|
: deviceStatus = TwoGangGlassStatusModel(
|
||||||
uuid: deviceId,
|
uuid: deviceId,
|
||||||
@ -28,6 +26,7 @@ class TwoGangGlassSwitchBloc
|
|||||||
on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
|
on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
|
||||||
on<TwoGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
on<TwoGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||||
on<TwoGangGlassFactoryReset>(_onFactoryReset);
|
on<TwoGangGlassFactoryReset>(_onFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDeviceStatus(TwoGangGlassSwitchFetchDeviceEvent event,
|
Future<void> _onFetchDeviceStatus(TwoGangGlassSwitchFetchDeviceEvent event,
|
||||||
@ -38,12 +37,44 @@ class TwoGangGlassSwitchBloc
|
|||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _listenToChanges(String deviceId) {
|
||||||
|
try {
|
||||||
|
DatabaseReference ref =
|
||||||
|
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
|
ref.onValue.listen((DatabaseEvent event) {
|
||||||
|
if (event.snapshot.value == null) return;
|
||||||
|
|
||||||
|
Map<dynamic, dynamic> data =
|
||||||
|
event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
List<Status> statusList = [];
|
||||||
|
|
||||||
|
data['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Parse the new status and add the event
|
||||||
|
final updatedStatus =
|
||||||
|
TwoGangGlassStatusModel.fromJson(data['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(updatedStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// Handle errors and emit an error state if necessary
|
||||||
|
if (!isClosed) {
|
||||||
|
// add(TwoGangGlassSwitchError('Error listening to updates: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onControl(TwoGangGlassSwitchControl event,
|
Future<void> _onControl(TwoGangGlassSwitchControl event,
|
||||||
Emitter<TwoGangGlassSwitchState> emit) async {
|
Emitter<TwoGangGlassSwitchState> emit) async {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final oldValue = _getValueByCode(event.code);
|
||||||
@ -178,4 +209,37 @@ class TwoGangGlassSwitchBloc
|
|||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _listenToChanges(deviceId) {
|
||||||
|
// try {
|
||||||
|
// 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>;
|
||||||
|
|
||||||
|
// List<Status> statusList = [];
|
||||||
|
// usersMap['status'].forEach((element) {
|
||||||
|
// statusList
|
||||||
|
// .add(Status(code: element['code'], value: element['value']));
|
||||||
|
// });
|
||||||
|
|
||||||
|
// deviceStatus = TwoGangGlassStatusModel.fromJson(
|
||||||
|
// usersMap['productUuid'], statusList);
|
||||||
|
// if (!isClosed) {
|
||||||
|
// add(StatusUpdated(deviceStatus));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// } catch (_) {}
|
||||||
|
// }
|
||||||
|
|
||||||
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event, Emitter<TwoGangGlassSwitchState> emit) {
|
||||||
|
// Update the local deviceStatus with the new status from the event
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
// Emit the new state with the updated status
|
||||||
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,3 +48,11 @@ class TwoGangGlassFactoryReset extends TwoGangGlassSwitchEvent {
|
|||||||
required this.factoryReset,
|
required this.factoryReset,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends TwoGangGlassSwitchEvent {
|
||||||
|
final TwoGangGlassStatusModel deviceStatus;
|
||||||
|
StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two
|
|||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class TwoGangGlassSwitchControlView extends StatelessWidget with HelperResponsiveLayout {
|
class TwoGangGlassSwitchControlView extends StatelessWidget
|
||||||
|
with HelperResponsiveLayout {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
|
|
||||||
const TwoGangGlassSwitchControlView({required this.deviceId, super.key});
|
const TwoGangGlassSwitchControlView({required this.deviceId, super.key});
|
||||||
@ -14,8 +15,8 @@ class TwoGangGlassSwitchControlView extends StatelessWidget with HelperResponsiv
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) => TwoGangGlassSwitchBloc(deviceId: deviceId)
|
||||||
TwoGangGlassSwitchBloc(deviceId: deviceId)..add(TwoGangGlassSwitchFetchDeviceEvent(deviceId)),
|
..add(TwoGangGlassSwitchFetchDeviceEvent(deviceId)),
|
||||||
child: BlocBuilder<TwoGangGlassSwitchBloc, TwoGangGlassSwitchState>(
|
child: BlocBuilder<TwoGangGlassSwitchBloc, TwoGangGlassSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is TwoGangGlassSwitchLoading) {
|
if (state is TwoGangGlassSwitchLoading) {
|
||||||
@ -23,16 +24,16 @@ class TwoGangGlassSwitchControlView extends StatelessWidget with HelperResponsiv
|
|||||||
} else if (state is TwoGangGlassSwitchStatusLoaded) {
|
} else if (state is TwoGangGlassSwitchStatusLoaded) {
|
||||||
return _buildStatusControls(context, state.status);
|
return _buildStatusControls(context, state.status);
|
||||||
} else if (state is TwoGangGlassSwitchError) {
|
} else if (state is TwoGangGlassSwitchError) {
|
||||||
return const Center(child: Text('Error fetching status'));
|
return Center(child: Text(state.message));
|
||||||
} else {
|
} else {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStatusControls(BuildContext context, TwoGangGlassStatusModel status) {
|
Widget _buildStatusControls(
|
||||||
|
BuildContext context, TwoGangGlassStatusModel status) {
|
||||||
final isExtraLarge = isExtraLargeScreenSize(context);
|
final isExtraLarge = isExtraLargeScreenSize(context);
|
||||||
final isLarge = isLargeScreenSize(context);
|
final isLarge = isLargeScreenSize(context);
|
||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart';
|
||||||
@ -14,6 +15,7 @@ class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
|||||||
on<TwoGangSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
on<TwoGangSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
||||||
on<TwoGangSwitchBatchControl>(_onBatchControl);
|
on<TwoGangSwitchBatchControl>(_onBatchControl);
|
||||||
on<TwoGangFactoryReset>(_onFactoryReset);
|
on<TwoGangFactoryReset>(_onFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
late TwoGangStatusModel deviceStatus;
|
late TwoGangStatusModel deviceStatus;
|
||||||
@ -26,8 +28,8 @@ class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
|||||||
try {
|
try {
|
||||||
final status =
|
final status =
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
|
|
||||||
deviceStatus = TwoGangStatusModel.fromJson(event.deviceId, status.status);
|
deviceStatus = TwoGangStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
_listenToChanges(emit);
|
||||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(TwoGangSwitchError(e.toString()));
|
emit(TwoGangSwitchError(e.toString()));
|
||||||
@ -174,4 +176,34 @@ class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
|||||||
emit(TwoGangSwitchError(e.toString()));
|
emit(TwoGangSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus =
|
||||||
|
TwoGangStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(StatusUpdated event, Emitter<TwoGangSwitchState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/models/two_gang_status_model.dart';
|
||||||
|
|
||||||
class TwoGangSwitchEvent extends Equatable {
|
class TwoGangSwitchEvent extends Equatable {
|
||||||
@override
|
@override
|
||||||
@ -57,3 +58,10 @@ class TwoGangFactoryReset extends TwoGangSwitchEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceId, factoryReset];
|
List<Object> get props => [deviceId, factoryReset];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends TwoGangSwitchEvent {
|
||||||
|
final TwoGangStatusModel deviceStatus;
|
||||||
|
StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_event.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_event.dart';
|
||||||
@ -29,7 +30,7 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
var response = await DevicesManagementApi().getDeviceStatus(deviceId);
|
var response = await DevicesManagementApi().getDeviceStatus(deviceId);
|
||||||
deviceStatus = WallSensorModel.fromJson(response.status);
|
deviceStatus = WallSensorModel.fromJson(response.status);
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
// _listenToChanges();
|
_listenToChanges(emit);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(WallSensorFailedState(error: e.toString()));
|
emit(WallSensorFailedState(error: e.toString()));
|
||||||
return;
|
return;
|
||||||
@ -38,10 +39,12 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
|
|
||||||
// Fetch batch status
|
// Fetch batch status
|
||||||
FutureOr<void> _fetchWallSensorBatchControl(
|
FutureOr<void> _fetchWallSensorBatchControl(
|
||||||
WallSensorFetchBatchStatusEvent event, Emitter<WallSensorState> emit) async {
|
WallSensorFetchBatchStatusEvent event,
|
||||||
|
Emitter<WallSensorState> emit) async {
|
||||||
emit(WallSensorLoadingInitialState());
|
emit(WallSensorLoadingInitialState());
|
||||||
try {
|
try {
|
||||||
var response = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
var response =
|
||||||
|
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
deviceStatus = WallSensorModel.fromJson(response.status);
|
deviceStatus = WallSensorModel.fromJson(response.status);
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -49,26 +52,30 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _listenToChanges() {
|
_listenToChanges(Emitter<WallSensorState> emit) {
|
||||||
// try {
|
try {
|
||||||
// DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
DatabaseReference ref =
|
||||||
// Stream<DatabaseEvent> stream = ref.onValue;
|
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
|
Stream<DatabaseEvent> stream = ref.onValue;
|
||||||
|
|
||||||
// stream.listen((DatabaseEvent event) {
|
stream.listen((DatabaseEvent event) {
|
||||||
// Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
|
Map<dynamic, dynamic> usersMap =
|
||||||
// List<StatusModel> statusList = [];
|
event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
List<Status> statusList = [];
|
||||||
|
|
||||||
// usersMap['status'].forEach((element) {
|
usersMap['status'].forEach((element) {
|
||||||
// statusList.add(StatusModel(code: element['code'], value: element['value']));
|
statusList
|
||||||
// });
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
// deviceStatus = WallSensorModel.fromJson(statusList);
|
deviceStatus = WallSensorModel.fromJson(statusList);
|
||||||
// add(WallSensorUpdatedEvent());
|
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
||||||
// });
|
});
|
||||||
// } catch (_) {}
|
} catch (_) {}
|
||||||
// }
|
}
|
||||||
|
|
||||||
void _changeValue(WallSensorChangeValueEvent event, Emitter<WallSensorState> emit) async {
|
void _changeValue(
|
||||||
|
WallSensorChangeValueEvent event, Emitter<WallSensorState> emit) async {
|
||||||
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
||||||
if (event.code == 'far_detection') {
|
if (event.code == 'far_detection') {
|
||||||
deviceStatus.farDetection = event.value;
|
deviceStatus.farDetection = event.value;
|
||||||
@ -125,7 +132,8 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
try {
|
try {
|
||||||
late bool response;
|
late bool response;
|
||||||
if (isBatch) {
|
if (isBatch) {
|
||||||
response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
response = await DevicesManagementApi()
|
||||||
|
.deviceBatchControl(deviceId, code, value);
|
||||||
} else {
|
} else {
|
||||||
response = await DevicesManagementApi()
|
response = await DevicesManagementApi()
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
.deviceControl(deviceId, Status(code: code, value: value));
|
||||||
@ -150,7 +158,8 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
try {
|
try {
|
||||||
// await DevicesManagementApi.getDeviceReportsByDate(
|
// await DevicesManagementApi.getDeviceReportsByDate(
|
||||||
// deviceId, event.code, from.toString(), to.toString())
|
// deviceId, event.code, from.toString(), to.toString())
|
||||||
await DevicesManagementApi.getDeviceReports(deviceId, event.code).then((value) {
|
await DevicesManagementApi.getDeviceReports(deviceId, event.code)
|
||||||
|
.then((value) {
|
||||||
emit(DeviceReportsState(deviceReport: value, code: event.code));
|
emit(DeviceReportsState(deviceReport: value, code: event.code));
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -159,11 +168,13 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showDescription(ShowDescriptionEvent event, Emitter<WallSensorState> emit) {
|
void _showDescription(
|
||||||
|
ShowDescriptionEvent event, Emitter<WallSensorState> emit) {
|
||||||
emit(WallSensorShowDescriptionState(description: event.description));
|
emit(WallSensorShowDescriptionState(description: event.description));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _backToGridView(BackToGridViewEvent event, Emitter<WallSensorState> emit) {
|
void _backToGridView(
|
||||||
|
BackToGridViewEvent event, Emitter<WallSensorState> emit) {
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_entry.dart';
|
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_entry.dart';
|
||||||
@ -34,6 +35,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
on<EditWaterHeaterScheduleEvent>(_onEditSchedule);
|
on<EditWaterHeaterScheduleEvent>(_onEditSchedule);
|
||||||
on<DeleteScheduleEvent>(_onDeleteSchedule);
|
on<DeleteScheduleEvent>(_onDeleteSchedule);
|
||||||
on<UpdateScheduleEntryEvent>(_onUpdateSchedule);
|
on<UpdateScheduleEntryEvent>(_onUpdateSchedule);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
late WaterHeaterStatusModel deviceStatus;
|
late WaterHeaterStatusModel deviceStatus;
|
||||||
@ -78,7 +80,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
final updatedDays = List<bool>.from(currentState.selectedDays);
|
final updatedDays = List<bool>.from(currentState.selectedDays);
|
||||||
updatedDays[event.index] = event.value;
|
updatedDays[event.index] = event.value;
|
||||||
emit(currentState.copyWith(selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
emit(currentState.copyWith(
|
||||||
|
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _updateFunctionOn(
|
FutureOr<void> _updateFunctionOn(
|
||||||
@ -86,7 +89,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) {
|
) {
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
emit(currentState.copyWith(functionOn: event.isOn, selectedTime: currentState.selectedTime));
|
emit(currentState.copyWith(
|
||||||
|
functionOn: event.isOn, selectedTime: currentState.selectedTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _updateScheduleEvent(
|
FutureOr<void> _updateScheduleEvent(
|
||||||
@ -101,7 +105,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (event.scheduleMode == ScheduleModes.countdown) {
|
if (event.scheduleMode == ScheduleModes.countdown) {
|
||||||
final countdownRemaining = Duration(hours: event.hours, minutes: event.minutes);
|
final countdownRemaining =
|
||||||
|
Duration(hours: event.hours, minutes: event.minutes);
|
||||||
|
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
scheduleMode: ScheduleModes.countdown,
|
scheduleMode: ScheduleModes.countdown,
|
||||||
@ -111,11 +116,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
countdownRemaining: countdownRemaining,
|
countdownRemaining: countdownRemaining,
|
||||||
));
|
));
|
||||||
|
|
||||||
if (!currentState.isCountdownActive! && countdownRemaining > Duration.zero) {
|
if (!currentState.isCountdownActive! &&
|
||||||
|
countdownRemaining > Duration.zero) {
|
||||||
_startCountdownTimer(emit, countdownRemaining);
|
_startCountdownTimer(emit, countdownRemaining);
|
||||||
}
|
}
|
||||||
} else if (event.scheduleMode == ScheduleModes.inching) {
|
} else if (event.scheduleMode == ScheduleModes.inching) {
|
||||||
final inchingDuration = Duration(hours: event.hours, minutes: event.minutes);
|
final inchingDuration =
|
||||||
|
Duration(hours: event.hours, minutes: event.minutes);
|
||||||
|
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
scheduleMode: ScheduleModes.inching,
|
scheduleMode: ScheduleModes.inching,
|
||||||
@ -217,7 +224,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().deviceControl(
|
final status = await DevicesManagementApi().deviceControl(
|
||||||
event.deviceId,
|
event.deviceId,
|
||||||
Status(code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
|
Status(
|
||||||
|
code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
|
||||||
);
|
);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.'));
|
emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.'));
|
||||||
@ -235,8 +243,10 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
emit(WaterHeaterLoadingState());
|
emit(WaterHeaterLoadingState());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
final status =
|
||||||
deviceStatus = WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
|
deviceStatus =
|
||||||
|
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
|
||||||
if (deviceStatus.scheduleMode == ScheduleModes.countdown) {
|
if (deviceStatus.scheduleMode == ScheduleModes.countdown) {
|
||||||
final countdownRemaining = Duration(
|
final countdownRemaining = Duration(
|
||||||
@ -300,11 +310,42 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
isInchingActive: false,
|
isInchingActive: false,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(WaterHeaterFailedState(error: e.toString()));
|
emit(WaterHeaterFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_listenToChanges(deviceId) {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus = WaterHeaterStatusModel.fromJson(
|
||||||
|
usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(StatusUpdated event, Emitter<WaterHeaterState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
void _startCountdownTimer(
|
void _startCountdownTimer(
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
Duration countdownRemaining,
|
Duration countdownRemaining,
|
||||||
@ -334,8 +375,10 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
|
|
||||||
if (currentState.countdownRemaining != null && currentState.countdownRemaining! > Duration.zero) {
|
if (currentState.countdownRemaining != null &&
|
||||||
final newRemaining = currentState.countdownRemaining! - const Duration(minutes: 1);
|
currentState.countdownRemaining! > Duration.zero) {
|
||||||
|
final newRemaining =
|
||||||
|
currentState.countdownRemaining! - const Duration(minutes: 1);
|
||||||
|
|
||||||
if (newRemaining <= Duration.zero) {
|
if (newRemaining <= Duration.zero) {
|
||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
@ -430,7 +473,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _revertValue(String code, dynamic oldValue, void Function(WaterHeaterState state) emit) {
|
void _revertValue(String code, dynamic oldValue,
|
||||||
|
void Function(WaterHeaterState state) emit) {
|
||||||
_updateLocalValue(code, oldValue);
|
_updateLocalValue(code, oldValue);
|
||||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
@ -477,12 +521,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _getSchedule(GetSchedulesEvent event, Emitter<WaterHeaterState> emit) async {
|
FutureOr<void> _getSchedule(
|
||||||
|
GetSchedulesEvent event, Emitter<WaterHeaterState> emit) async {
|
||||||
emit(ScheduleLoadingState());
|
emit(ScheduleLoadingState());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<ScheduleModel> schedules =
|
List<ScheduleModel> schedules = await DevicesManagementApi()
|
||||||
await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category);
|
.getDeviceSchedules(deviceStatus.uuid, event.category);
|
||||||
|
|
||||||
emit(WaterHeaterDeviceStatusLoaded(
|
emit(WaterHeaterDeviceStatusLoaded(
|
||||||
deviceStatus,
|
deviceStatus,
|
||||||
@ -514,7 +559,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
|
|
||||||
// emit(ScheduleLoadingState());
|
// emit(ScheduleLoadingState());
|
||||||
|
|
||||||
bool success = await DevicesManagementApi().addScheduleRecord(newSchedule, currentState.status.uuid);
|
bool success = await DevicesManagementApi()
|
||||||
|
.addScheduleRecord(newSchedule, currentState.status.uuid);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
|
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
|
||||||
@ -525,7 +571,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onEditSchedule(EditWaterHeaterScheduleEvent event, Emitter<WaterHeaterState> emit) async {
|
FutureOr<void> _onEditSchedule(EditWaterHeaterScheduleEvent event,
|
||||||
|
Emitter<WaterHeaterState> emit) async {
|
||||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
|
|
||||||
@ -594,11 +641,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
|
|
||||||
// emit(ScheduleLoadingState());
|
// emit(ScheduleLoadingState());
|
||||||
|
|
||||||
bool success = await DevicesManagementApi().deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
|
bool success = await DevicesManagementApi()
|
||||||
|
.deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
final updatedSchedules =
|
final updatedSchedules = currentState.schedules
|
||||||
currentState.schedules.where((schedule) => schedule.scheduleId != event.scheduleId).toList();
|
.where((schedule) => schedule.scheduleId != event.scheduleId)
|
||||||
|
.toList();
|
||||||
|
|
||||||
emit(currentState.copyWith(schedules: updatedSchedules));
|
emit(currentState.copyWith(schedules: updatedSchedules));
|
||||||
} else {
|
} else {
|
||||||
@ -608,12 +657,15 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event, Emitter<WaterHeaterState> emit) async {
|
FutureOr<void> _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event,
|
||||||
|
Emitter<WaterHeaterState> emit) async {
|
||||||
emit(WaterHeaterLoadingState());
|
emit(WaterHeaterLoadingState());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getBatchStatus(event.devicesUuid);
|
final status =
|
||||||
deviceStatus = WaterHeaterStatusModel.fromJson(event.devicesUuid.first, status.status);
|
await DevicesManagementApi().getBatchStatus(event.devicesUuid);
|
||||||
|
deviceStatus = WaterHeaterStatusModel.fromJson(
|
||||||
|
event.devicesUuid.first, status.status);
|
||||||
|
|
||||||
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -621,7 +673,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _batchControlWaterHeater(ControlWaterHeaterBatchEvent event, Emitter<WaterHeaterState> emit) async {
|
FutureOr<void> _batchControlWaterHeater(ControlWaterHeaterBatchEvent event,
|
||||||
|
Emitter<WaterHeaterState> emit) async {
|
||||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
|
|
||||||
|
@ -54,6 +54,15 @@ final class WaterHeaterFetchStatusEvent extends WaterHeaterEvent {
|
|||||||
|
|
||||||
final class DecrementCountdownEvent extends WaterHeaterEvent {}
|
final class DecrementCountdownEvent extends WaterHeaterEvent {}
|
||||||
|
|
||||||
|
|
||||||
|
class StatusUpdated extends WaterHeaterEvent {
|
||||||
|
final WaterHeaterStatusModel deviceStatus;
|
||||||
|
const StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
final class AddScheduleEvent extends WaterHeaterEvent {
|
final class AddScheduleEvent extends WaterHeaterEvent {
|
||||||
final List<bool> selectedDays;
|
final List<bool> selectedDays;
|
||||||
final TimeOfDay time;
|
final TimeOfDay time;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/water_leak/bloc/water_leak_event.dart';
|
import 'package:syncrow_web/pages/device_managment/water_leak/bloc/water_leak_event.dart';
|
||||||
@ -21,6 +22,7 @@ class WaterLeakBloc extends Bloc<WaterLeakEvent, WaterLeakState> {
|
|||||||
on<FetchWaterLeakBatchStatusEvent>(_onFetchBatchStatus);
|
on<FetchWaterLeakBatchStatusEvent>(_onFetchBatchStatus);
|
||||||
on<FetchWaterLeakReportsEvent>(_onFetchWaterLeakReports);
|
on<FetchWaterLeakReportsEvent>(_onFetchWaterLeakReports);
|
||||||
on<WaterLeakFactoryResetEvent>(_onFactoryReset);
|
on<WaterLeakFactoryResetEvent>(_onFactoryReset);
|
||||||
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchWaterLeakStatus(
|
Future<void> _onFetchWaterLeakStatus(
|
||||||
@ -30,12 +32,43 @@ class WaterLeakBloc extends Bloc<WaterLeakEvent, WaterLeakState> {
|
|||||||
final response =
|
final response =
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
deviceStatus = WaterLeakStatusModel.fromJson(deviceId, response.status);
|
deviceStatus = WaterLeakStatusModel.fromJson(deviceId, response.status);
|
||||||
|
_listenToChanges();
|
||||||
emit(WaterLeakLoadedState(deviceStatus!));
|
emit(WaterLeakLoadedState(deviceStatus!));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(WaterLeakErrorState(e.toString()));
|
emit(WaterLeakErrorState(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_listenToChanges() {
|
||||||
|
try {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList
|
||||||
|
.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus =
|
||||||
|
WaterLeakStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus!));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(StatusUpdated event, Emitter<WaterLeakState> emit) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(WaterLeakLoadedState(deviceStatus!));
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onControl(
|
Future<void> _onControl(
|
||||||
WaterLeakControlEvent event, Emitter<WaterLeakState> emit) async {
|
WaterLeakControlEvent event, Emitter<WaterLeakState> emit) async {
|
||||||
final oldValue = deviceStatus!.watersensorState;
|
final oldValue = deviceStatus!.watersensorState;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/water_leak/model/water_leak_status_model.dart';
|
||||||
|
|
||||||
abstract class WaterLeakEvent extends Equatable {
|
abstract class WaterLeakEvent extends Equatable {
|
||||||
const WaterLeakEvent();
|
const WaterLeakEvent();
|
||||||
@ -17,6 +18,13 @@ class FetchWaterLeakStatusEvent extends WaterLeakEvent {
|
|||||||
List<Object> get props => [deviceId];
|
List<Object> get props => [deviceId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatusUpdated extends WaterLeakEvent {
|
||||||
|
final WaterLeakStatusModel deviceStatus;
|
||||||
|
const StatusUpdated(this.deviceStatus);
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceStatus];
|
||||||
|
}
|
||||||
|
|
||||||
class WaterLeakControlEvent extends WaterLeakEvent {
|
class WaterLeakControlEvent extends WaterLeakEvent {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
final String code;
|
final String code;
|
||||||
|
@ -1,55 +1,99 @@
|
|||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:graphview/GraphView.dart';
|
// import 'package:graphview/GraphView.dart';
|
||||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||||
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
|
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/services/home_api.dart';
|
import 'package:syncrow_web/services/home_api.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||||
|
|
||||||
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||||
final Graph graph = Graph()..isTree = true;
|
// final Graph graph = Graph()..isTree = true;
|
||||||
final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
// final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
||||||
List<Node> sourcesList = [];
|
// List<Node> sourcesList = [];
|
||||||
List<Node> destinationsList = [];
|
// List<Node> destinationsList = [];
|
||||||
UserModel? user;
|
UserModel? user;
|
||||||
|
String terms = '';
|
||||||
|
String policy = '';
|
||||||
|
|
||||||
HomeBloc() : super((HomeInitial())) {
|
HomeBloc() : super((HomeInitial())) {
|
||||||
on<CreateNewNode>(_createNode);
|
// on<CreateNewNode>(_createNode);
|
||||||
on<FetchUserInfo>(_fetchUserInfo);
|
on<FetchUserInfo>(_fetchUserInfo);
|
||||||
|
on<FetchTermEvent>(_fetchTerms);
|
||||||
|
on<FetchPolicyEvent>(_fetchPolicy);
|
||||||
|
on<ConfirmUserAgreementEvent>(_confirmUserAgreement);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
// void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
||||||
emit(HomeInitial());
|
// emit(HomeInitial());
|
||||||
sourcesList.add(event.sourceNode);
|
// sourcesList.add(event.sourceNode);
|
||||||
destinationsList.add(event.destinationNode);
|
// destinationsList.add(event.destinationNode);
|
||||||
for (int i = 0; i < sourcesList.length; i++) {
|
// for (int i = 0; i < sourcesList.length; i++) {
|
||||||
graph.addEdge(sourcesList[i], destinationsList[i]);
|
// graph.addEdge(sourcesList[i], destinationsList[i]);
|
||||||
}
|
// }
|
||||||
|
|
||||||
builder
|
// builder
|
||||||
..siblingSeparation = (100)
|
// ..siblingSeparation = (100)
|
||||||
..levelSeparation = (150)
|
// ..levelSeparation = (150)
|
||||||
..subtreeSeparation = (150)
|
// ..subtreeSeparation = (150)
|
||||||
..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
|
// ..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
|
||||||
emit(HomeUpdateTree(graph: graph, builder: builder));
|
// emit(HomeUpdateTree(graph: graph, builder: builder));
|
||||||
}
|
// }
|
||||||
|
|
||||||
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
||||||
try {
|
try {
|
||||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
var uuid =
|
||||||
|
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
user = await HomeApi().fetchUserInfo(uuid);
|
user = await HomeApi().fetchUserInfo(uuid);
|
||||||
|
add(FetchTermEvent());
|
||||||
|
add(FetchPolicyEvent());
|
||||||
|
|
||||||
emit(HomeInitial());
|
emit(HomeInitial());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future _fetchTerms(FetchTermEvent event, Emitter<HomeState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(LoadingHome());
|
||||||
|
terms = await HomeApi().fetchTerms();
|
||||||
|
emit(HomeInitial());
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _fetchPolicy(FetchPolicyEvent event, Emitter<HomeState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(LoadingHome());
|
||||||
|
policy = await HomeApi().fetchPolicy();
|
||||||
|
emit(HomeInitial());
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint("Error fetching policy: $e");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _confirmUserAgreement(
|
||||||
|
ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(LoadingHome());
|
||||||
|
var uuid =
|
||||||
|
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
|
policy = await HomeApi().confirmUserAgreements(uuid);
|
||||||
|
emit(PolicyAgreement());
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// static Future fetchUserInfo() async {
|
// static Future fetchUserInfo() async {
|
||||||
// try {
|
// try {
|
||||||
// var uuid =
|
// var uuid =
|
||||||
@ -62,7 +106,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
|
|
||||||
List<HomeItemModel> homeItems = [
|
List<HomeItemModel> homeItems = [
|
||||||
HomeItemModel(
|
HomeItemModel(
|
||||||
title: 'Access',
|
title: 'Access Management',
|
||||||
icon: Assets.accessIcon,
|
icon: Assets.accessIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
@ -80,7 +124,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
color: ColorsManager.primaryColor,
|
color: ColorsManager.primaryColor,
|
||||||
),
|
),
|
||||||
HomeItemModel(
|
HomeItemModel(
|
||||||
title: 'Devices',
|
title: 'Devices Management',
|
||||||
icon: Assets.devicesIcon,
|
icon: Assets.devicesIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
@ -90,6 +134,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
},
|
},
|
||||||
color: ColorsManager.primaryColor,
|
color: ColorsManager.primaryColor,
|
||||||
),
|
),
|
||||||
|
|
||||||
// HomeItemModel(
|
// HomeItemModel(
|
||||||
// title: 'Move in',
|
// title: 'Move in',
|
||||||
// icon: Assets.moveinIcon,
|
// icon: Assets.moveinIcon,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:graphview/GraphView.dart';
|
// import 'package:graphview/GraphView.dart';
|
||||||
|
|
||||||
abstract class HomeEvent extends Equatable {
|
abstract class HomeEvent extends Equatable {
|
||||||
const HomeEvent();
|
const HomeEvent();
|
||||||
@ -8,16 +8,22 @@ abstract class HomeEvent extends Equatable {
|
|||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateNewNode extends HomeEvent {
|
// class CreateNewNode extends HomeEvent {
|
||||||
final Node sourceNode;
|
// final Node sourceNode;
|
||||||
final Node destinationNode;
|
// final Node destinationNode;
|
||||||
const CreateNewNode(
|
// const CreateNewNode(
|
||||||
{required this.sourceNode, required this.destinationNode});
|
// {required this.sourceNode, required this.destinationNode});
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
List<Object> get props => [sourceNode, destinationNode];
|
// List<Object> get props => [sourceNode, destinationNode];
|
||||||
}
|
// }
|
||||||
|
|
||||||
class FetchUserInfo extends HomeEvent {
|
class FetchUserInfo extends HomeEvent {
|
||||||
const FetchUserInfo();
|
const FetchUserInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FetchTermEvent extends HomeEvent {}
|
||||||
|
|
||||||
|
class FetchPolicyEvent extends HomeEvent {}
|
||||||
|
|
||||||
|
class ConfirmUserAgreementEvent extends HomeEvent {}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:graphview/GraphView.dart';
|
// import 'package:graphview/GraphView.dart';
|
||||||
|
|
||||||
abstract class HomeState extends Equatable {
|
abstract class HomeState extends Equatable {
|
||||||
const HomeState();
|
const HomeState();
|
||||||
@ -8,19 +8,25 @@ abstract class HomeState extends Equatable {
|
|||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LoadingHome extends HomeState {}
|
||||||
|
|
||||||
class HomeInitial extends HomeState {}
|
class HomeInitial extends HomeState {}
|
||||||
|
|
||||||
class HomeCounterState extends HomeState {
|
class TermsAgreement extends HomeState {}
|
||||||
final int counter;
|
|
||||||
const HomeCounterState(this.counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
class HomeUpdateTree extends HomeState {
|
class PolicyAgreement extends HomeState {}
|
||||||
final Graph graph;
|
|
||||||
final BuchheimWalkerConfiguration builder;
|
|
||||||
|
|
||||||
const HomeUpdateTree({required this.graph, required this.builder});
|
// class HomeCounterState extends HomeState {
|
||||||
|
// final int counter;
|
||||||
|
// const HomeCounterState(this.counter);
|
||||||
|
// }
|
||||||
|
|
||||||
@override
|
// class HomeUpdateTree extends HomeState {
|
||||||
List<Object> get props => [graph, builder];
|
// final Graph graph;
|
||||||
}
|
// final BuchheimWalkerConfiguration builder;
|
||||||
|
|
||||||
|
// const HomeUpdateTree({required this.graph, required this.builder});
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// List<Object> get props => [graph, builder];
|
||||||
|
// }
|
||||||
|
178
lib/pages/home/view/agreement_and_privacy_dialog.dart
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class AgreementAndPrivacyDialog extends StatefulWidget {
|
||||||
|
final String terms;
|
||||||
|
final String policy;
|
||||||
|
|
||||||
|
const AgreementAndPrivacyDialog({
|
||||||
|
super.key,
|
||||||
|
required this.terms,
|
||||||
|
required this.policy,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_AgreementAndPrivacyDialogState createState() =>
|
||||||
|
_AgreementAndPrivacyDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AgreementAndPrivacyDialogState extends State<AgreementAndPrivacyDialog> {
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
bool _isAtEnd = false;
|
||||||
|
int _currentPage = 1;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_scrollController.addListener(_onScroll);
|
||||||
|
WidgetsBinding.instance
|
||||||
|
.addPostFrameCallback((_) => _checkScrollRequirement());
|
||||||
|
}
|
||||||
|
|
||||||
|
void _checkScrollRequirement() {
|
||||||
|
final scrollPosition = _scrollController.position;
|
||||||
|
if (scrollPosition.maxScrollExtent <= 0) {
|
||||||
|
setState(() {
|
||||||
|
_isAtEnd = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.removeListener(_onScroll);
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onScroll() {
|
||||||
|
if (_scrollController.position.atEdge) {
|
||||||
|
final isAtBottom = _scrollController.position.pixels ==
|
||||||
|
_scrollController.position.maxScrollExtent;
|
||||||
|
if (isAtBottom && !_isAtEnd) {
|
||||||
|
setState(() {
|
||||||
|
_isAtEnd = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String get _dialogTitle =>
|
||||||
|
_currentPage == 1 ? 'User Agreement' : 'Privacy Policy';
|
||||||
|
|
||||||
|
String get _dialogContent => _currentPage == 1 ? widget.terms : widget.policy;
|
||||||
|
final String staticText =
|
||||||
|
'<h5 style="color: #FF5722;">If you cancel you will be logged out.</h5>';
|
||||||
|
|
||||||
|
Widget _buildScrollableContent() {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(40),
|
||||||
|
width: MediaQuery.of(context).size.width * 0.8,
|
||||||
|
height: MediaQuery.of(context).size.height * 0.75,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[200],
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||||
|
),
|
||||||
|
child: Scrollbar(
|
||||||
|
thumbVisibility: true,
|
||||||
|
trackVisibility: true,
|
||||||
|
interactive: true,
|
||||||
|
controller: _scrollController,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
controller: _scrollController,
|
||||||
|
padding: const EdgeInsets.all(25),
|
||||||
|
child: Html(
|
||||||
|
data: "$_dialogContent $staticText",
|
||||||
|
onLinkTap: (url, attributes, element) async {
|
||||||
|
if (url != null) {
|
||||||
|
final uri = Uri.parse(url);
|
||||||
|
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
"body": Style(
|
||||||
|
fontSize: FontSize(14),
|
||||||
|
color: Colors.black87,
|
||||||
|
lineHeight: LineHeight(1.5),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildActionButton() {
|
||||||
|
final String buttonText = _currentPage == 2 ? "I Agree" : "Next";
|
||||||
|
|
||||||
|
return InkWell(
|
||||||
|
onTap: _isAtEnd
|
||||||
|
? () {
|
||||||
|
if (_currentPage == 1) {
|
||||||
|
setState(() {
|
||||||
|
_currentPage = 2;
|
||||||
|
_isAtEnd = false;
|
||||||
|
_scrollController.jumpTo(0);
|
||||||
|
WidgetsBinding.instance
|
||||||
|
.addPostFrameCallback((_) => _checkScrollRequirement());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: Text(
|
||||||
|
buttonText,
|
||||||
|
style: TextStyle(
|
||||||
|
color: _isAtEnd ? ColorsManager.secondaryColor : Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Dialog(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Text(
|
||||||
|
_dialogTitle,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: ColorsManager.secondaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
_buildScrollableContent(),
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
AuthBloc.logout();
|
||||||
|
context.go(RoutesConst.auth);
|
||||||
|
},
|
||||||
|
child: const Text("Cancel"),
|
||||||
|
),
|
||||||
|
_buildActionButton(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -41,8 +41,7 @@ class HomeMobilePage extends StatelessWidget {
|
|||||||
SizedBox(height: size.height * 0.05),
|
SizedBox(height: size.height * 0.05),
|
||||||
const Text(
|
const Text(
|
||||||
'ACCESS YOUR APPS',
|
'ACCESS YOUR APPS',
|
||||||
style:
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700),
|
||||||
TextStyle(fontSize: 20, fontWeight: FontWeight.w700),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -51,9 +50,8 @@ class HomeMobilePage extends StatelessWidget {
|
|||||||
height: size.height * 0.6,
|
height: size.height * 0.6,
|
||||||
width: size.width * 0.68,
|
width: size.width * 0.68,
|
||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
itemCount: 8,
|
itemCount: 3,
|
||||||
gridDelegate:
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: 2,
|
crossAxisCount: 2,
|
||||||
crossAxisSpacing: 20.0,
|
crossAxisSpacing: 20.0,
|
||||||
mainAxisSpacing: 20.0,
|
mainAxisSpacing: 20.0,
|
||||||
@ -65,8 +63,7 @@ class HomeMobilePage extends StatelessWidget {
|
|||||||
active: homeItems[index]['active'],
|
active: homeItems[index]['active'],
|
||||||
name: homeItems[index]['title'],
|
name: homeItems[index]['title'],
|
||||||
img: homeItems[index]['icon'],
|
img: homeItems[index]['icon'],
|
||||||
onTap: () =>
|
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||||
homeBloc.homeItems[index].onPress(context),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -97,33 +94,33 @@ class HomeMobilePage extends StatelessWidget {
|
|||||||
'icon': Assets.devicesIcon,
|
'icon': Assets.devicesIcon,
|
||||||
'active': true,
|
'active': true,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
'title': 'Move in',
|
// 'title': 'Move in',
|
||||||
'icon': Assets.moveinIcon,
|
// 'icon': Assets.moveinIcon,
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
'title': 'Construction',
|
// 'title': 'Construction',
|
||||||
'icon': Assets.constructionIcon,
|
// 'icon': Assets.constructionIcon,
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
'title': 'Energy',
|
// 'title': 'Energy',
|
||||||
'icon': Assets.energyIcon,
|
// 'icon': Assets.energyIcon,
|
||||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
'title': 'Integrations',
|
// 'title': 'Integrations',
|
||||||
'icon': Assets.integrationsIcon,
|
// 'icon': Assets.integrationsIcon,
|
||||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
'title': 'Asset',
|
// 'title': 'Asset',
|
||||||
'icon': Assets.assetIcon,
|
// 'icon': Assets.assetIcon,
|
||||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,67 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/home/view/agreement_and_privacy_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||||
import 'package:syncrow_web/pages/home/view/home_card.dart';
|
import 'package:syncrow_web/pages/home/view/home_card.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
class HomeWebPage extends StatelessWidget {
|
class HomeWebPage extends StatefulWidget {
|
||||||
const HomeWebPage({super.key});
|
const HomeWebPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomeWebPage> createState() => _HomeWebPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomeWebPageState extends State<HomeWebPage> {
|
||||||
|
// Flag to track whether the dialog is already shown.
|
||||||
|
bool _dialogShown = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||||
|
homeBloc.add(FetchUserInfo());
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Size size = MediaQuery.of(context).size;
|
Size size = MediaQuery.of(context).size;
|
||||||
|
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||||
|
|
||||||
return PopScope(
|
return PopScope(
|
||||||
canPop: false,
|
canPop: false,
|
||||||
onPopInvoked: (didPop) => false,
|
onPopInvoked: (didPop) => false,
|
||||||
child: BlocConsumer<HomeBloc, HomeState>(
|
child: BlocConsumer<HomeBloc, HomeState>(
|
||||||
listener: (BuildContext context, state) {},
|
listener: (BuildContext context, state) {
|
||||||
|
if (state is HomeInitial) {
|
||||||
|
if (homeBloc.user!.hasAcceptedWebAgreement == false && !_dialogShown) {
|
||||||
|
_dialogShown = true; // Set the flag to true to indicate the dialog is showing.
|
||||||
|
Future.delayed(const Duration(seconds: 1), () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AgreementAndPrivacyDialog(
|
||||||
|
terms: homeBloc.terms,
|
||||||
|
policy: homeBloc.policy,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).then((v) {
|
||||||
|
_dialogShown = false;
|
||||||
|
if (v != null) {
|
||||||
|
homeBloc.add(ConfirmUserAgreementEvent());
|
||||||
|
homeBloc.add(const FetchUserInfo());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
|
||||||
return WebScaffold(
|
return WebScaffold(
|
||||||
enableMenuSidebar: false,
|
enableMenuSidebar: false,
|
||||||
appBarTitle: Row(
|
appBarTitle: Row(
|
||||||
@ -32,7 +75,10 @@ class HomeWebPage extends StatelessWidget {
|
|||||||
scaffoldBody: SizedBox(
|
scaffoldBody: SizedBox(
|
||||||
height: size.height,
|
height: size.height,
|
||||||
width: size.width,
|
width: size.width,
|
||||||
child: Column(
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -51,9 +97,9 @@ class HomeWebPage extends StatelessWidget {
|
|||||||
height: size.height * 0.6,
|
height: size.height * 0.6,
|
||||||
width: size.width * 0.68,
|
width: size.width * 0.68,
|
||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
itemCount: 3, //8
|
itemCount: 3, // Change this count if needed.
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 4,
|
crossAxisCount: 3, // Adjust as needed.
|
||||||
crossAxisSpacing: 20.0,
|
crossAxisSpacing: 20.0,
|
||||||
mainAxisSpacing: 20.0,
|
mainAxisSpacing: 20.0,
|
||||||
childAspectRatio: 1.5,
|
childAspectRatio: 1.5,
|
||||||
@ -72,9 +118,12 @@ class HomeWebPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
));
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,185 +1,185 @@
|
|||||||
import 'package:flutter/material.dart';
|
// import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
// import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:graphview/GraphView.dart';
|
// import 'package:graphview/GraphView.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
// import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
// import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
// import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||||
|
|
||||||
class TreeWidget extends StatelessWidget {
|
// class TreeWidget extends StatelessWidget {
|
||||||
const TreeWidget({super.key});
|
// const TreeWidget({super.key});
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Widget build(BuildContext context) {
|
// Widget build(BuildContext context) {
|
||||||
// final HomeBloc homeBloc = BlocProvider.of<HomeBloc>(context);
|
// // final HomeBloc homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||||
String firstNodeName = '';
|
// String firstNodeName = '';
|
||||||
String secondNodeName = '';
|
// String secondNodeName = '';
|
||||||
|
|
||||||
return SafeArea(
|
// return SafeArea(
|
||||||
child: Container(
|
// child: Container(
|
||||||
padding: const EdgeInsets.all(24),
|
// padding: const EdgeInsets.all(24),
|
||||||
width: MediaQuery.sizeOf(context).width,
|
// width: MediaQuery.sizeOf(context).width,
|
||||||
height: MediaQuery.sizeOf(context).height,
|
// height: MediaQuery.sizeOf(context).height,
|
||||||
alignment: AlignmentDirectional.center,
|
// alignment: AlignmentDirectional.center,
|
||||||
child: Column(
|
// child: Column(
|
||||||
mainAxisSize: MainAxisSize.max,
|
// mainAxisSize: MainAxisSize.max,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
// children: [
|
||||||
BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
// BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
||||||
if (state is HomeInitial) {
|
// if (state is HomeInitial) {
|
||||||
return Wrap(
|
// return Wrap(
|
||||||
children: [
|
// children: [
|
||||||
SizedBox(
|
// SizedBox(
|
||||||
width: 100,
|
// width: 100,
|
||||||
child: TextFormField(
|
// child: TextFormField(
|
||||||
decoration: const InputDecoration(
|
// decoration: const InputDecoration(
|
||||||
labelText: "Subtree separation"),
|
// labelText: "Subtree separation"),
|
||||||
onChanged: (text) {
|
// onChanged: (text) {
|
||||||
firstNodeName = text;
|
// firstNodeName = text;
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
const SizedBox(
|
// const SizedBox(
|
||||||
width: 8,
|
// width: 8,
|
||||||
),
|
// ),
|
||||||
Container(
|
// Container(
|
||||||
width: 100,
|
// width: 100,
|
||||||
child: TextFormField(
|
// child: TextFormField(
|
||||||
decoration: InputDecoration(labelText: "Node Name"),
|
// decoration: InputDecoration(labelText: "Node Name"),
|
||||||
onChanged: (text) {
|
// onChanged: (text) {
|
||||||
secondNodeName = text;
|
// secondNodeName = text;
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
ElevatedButton(
|
// ElevatedButton(
|
||||||
onPressed: () {
|
// onPressed: () {
|
||||||
final node1 = Node.Id(firstNodeName);
|
// final node1 = Node.Id(firstNodeName);
|
||||||
final node2 = Node.Id(secondNodeName);
|
// final node2 = Node.Id(secondNodeName);
|
||||||
context.read<HomeBloc>().add(CreateNewNode(
|
// context.read<HomeBloc>().add(CreateNewNode(
|
||||||
sourceNode: node1, destinationNode: node2));
|
// sourceNode: node1, destinationNode: node2));
|
||||||
},
|
// },
|
||||||
child: Text("Add"),
|
// child: Text("Add"),
|
||||||
)
|
// )
|
||||||
],
|
// ],
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
if (state is HomeUpdateTree) {
|
// if (state is HomeUpdateTree) {
|
||||||
return Expanded(
|
// return Expanded(
|
||||||
child: InteractiveViewer(
|
// child: InteractiveViewer(
|
||||||
constrained: false,
|
// constrained: false,
|
||||||
boundaryMargin: const EdgeInsets.all(100),
|
// boundaryMargin: const EdgeInsets.all(100),
|
||||||
minScale: 0.01,
|
// minScale: 0.01,
|
||||||
maxScale: 5.6,
|
// maxScale: 5.6,
|
||||||
child: GraphView(
|
// child: GraphView(
|
||||||
graph: state.graph,
|
// graph: state.graph,
|
||||||
algorithm: BuchheimWalkerAlgorithm(
|
// algorithm: BuchheimWalkerAlgorithm(
|
||||||
state.builder, TreeEdgeRenderer(state.builder)),
|
// state.builder, TreeEdgeRenderer(state.builder)),
|
||||||
paint: Paint()
|
// paint: Paint()
|
||||||
..color = Colors.green
|
// ..color = Colors.green
|
||||||
..strokeWidth = 1
|
// ..strokeWidth = 1
|
||||||
..style = PaintingStyle.stroke,
|
// ..style = PaintingStyle.stroke,
|
||||||
builder: (Node node) {
|
// builder: (Node node) {
|
||||||
// I can decide what widget should be shown here based on the id
|
// // I can decide what widget should be shown here based on the id
|
||||||
var nodeName = node.key!.value;
|
// var nodeName = node.key!.value;
|
||||||
return rectangleWidget(nodeName, node, context);
|
// return rectangleWidget(nodeName, node, context);
|
||||||
},
|
// },
|
||||||
)),
|
// )),
|
||||||
);
|
// );
|
||||||
} else {
|
// } else {
|
||||||
return Container();
|
// return Container();
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
Widget rectangleWidget(String text, Node node, BuildContext blocContext) {
|
// Widget rectangleWidget(String text, Node node, BuildContext blocContext) {
|
||||||
String nodeName = '';
|
// String nodeName = '';
|
||||||
return InkWell(
|
// return InkWell(
|
||||||
onTap: () {
|
// onTap: () {
|
||||||
showDialog(
|
// showDialog(
|
||||||
context: blocContext,
|
// context: blocContext,
|
||||||
builder: (BuildContext context) {
|
// builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
// return AlertDialog(
|
||||||
title: const Text('Add a child'),
|
// title: const Text('Add a child'),
|
||||||
content: TextField(
|
// content: TextField(
|
||||||
decoration:
|
// decoration:
|
||||||
const InputDecoration(hintText: 'Enter your text here'),
|
// const InputDecoration(hintText: 'Enter your text here'),
|
||||||
onChanged: (value) {
|
// onChanged: (value) {
|
||||||
nodeName = value;
|
// nodeName = value;
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
actions: <Widget>[
|
// actions: <Widget>[
|
||||||
TextButton(
|
// TextButton(
|
||||||
onPressed: () {
|
// onPressed: () {
|
||||||
Navigator.of(context).pop();
|
// Navigator.of(context).pop();
|
||||||
},
|
// },
|
||||||
child: Text('Close'),
|
// child: Text('Close'),
|
||||||
),
|
// ),
|
||||||
TextButton(
|
// TextButton(
|
||||||
onPressed: () {
|
// onPressed: () {
|
||||||
if (nodeName.isNotEmpty) {
|
// if (nodeName.isNotEmpty) {
|
||||||
final newNode = Node.Id(nodeName);
|
// final newNode = Node.Id(nodeName);
|
||||||
blocContext.read<HomeBloc>().add(CreateNewNode(
|
// blocContext.read<HomeBloc>().add(CreateNewNode(
|
||||||
sourceNode: node, destinationNode: newNode));
|
// sourceNode: node, destinationNode: newNode));
|
||||||
}
|
// }
|
||||||
Navigator.of(context).pop();
|
// Navigator.of(context).pop();
|
||||||
},
|
// },
|
||||||
child: Text('Add'),
|
// child: Text('Add'),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
child: Container(
|
// child: Container(
|
||||||
width: MediaQuery.of(blocContext).size.width * 0.2,
|
// width: MediaQuery.of(blocContext).size.width * 0.2,
|
||||||
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
// margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||||
padding: EdgeInsets.all(20.0),
|
// padding: EdgeInsets.all(20.0),
|
||||||
decoration: BoxDecoration(
|
// decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
// color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
// borderRadius: BorderRadius.circular(10.0),
|
||||||
boxShadow: [
|
// boxShadow: [
|
||||||
BoxShadow(
|
// BoxShadow(
|
||||||
color: Colors.grey.withOpacity(0.5),
|
// color: Colors.grey.withOpacity(0.5),
|
||||||
spreadRadius: 2,
|
// spreadRadius: 2,
|
||||||
blurRadius: 5,
|
// blurRadius: 5,
|
||||||
offset: Offset(0, 3), // changes position of shadow
|
// offset: Offset(0, 3), // changes position of shadow
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
child: Row(
|
// child: Row(
|
||||||
children: [
|
// children: [
|
||||||
const SizedBox(
|
// const SizedBox(
|
||||||
child: Icon(
|
// child: Icon(
|
||||||
Icons.location_on,
|
// Icons.location_on,
|
||||||
color: Colors.blue,
|
// color: Colors.blue,
|
||||||
size: 40.0,
|
// size: 40.0,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
const SizedBox(width: 10.0),
|
// const SizedBox(width: 10.0),
|
||||||
SizedBox(
|
// SizedBox(
|
||||||
child: Text(
|
// child: Text(
|
||||||
text,
|
// text,
|
||||||
style: const TextStyle(
|
// style: const TextStyle(
|
||||||
fontSize: 24.0,
|
// fontSize: 24.0,
|
||||||
fontWeight: FontWeight.bold,
|
// fontWeight: FontWeight.bold,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
const Spacer(),
|
// const Spacer(),
|
||||||
Container(
|
// Container(
|
||||||
child: const Icon(
|
// child: const Icon(
|
||||||
Icons.add_circle_outline,
|
// Icons.add_circle_outline,
|
||||||
color: Colors.grey,
|
// color: Colors.grey,
|
||||||
size: 24.0,
|
// size: 24.0,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/model/role_model.dart';
|
||||||
|
|
||||||
|
class RolesPermissionBloc
|
||||||
|
extends Bloc<RolesPermissionEvent, RolesPermissionState> {
|
||||||
|
RolesPermissionBloc() : super(RolesInitial()) {
|
||||||
|
on<GetRoles>(_getRoles);
|
||||||
|
on<ChangeTapSelected>(changeTapSelected);
|
||||||
|
}
|
||||||
|
List<RoleModel> roleModel = [];
|
||||||
|
|
||||||
|
FutureOr<void> _getRoles(
|
||||||
|
GetRoles event, Emitter<RolesPermissionState> emit) async {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
try {
|
||||||
|
roleModel = [
|
||||||
|
RoleModel(roleId: '1', roleImage: '', roleName: 'Admin'),
|
||||||
|
RoleModel(roleId: '2', roleImage: '', roleName: 'Security'),
|
||||||
|
RoleModel(roleId: '2', roleImage: '', roleName: 'Reception'),
|
||||||
|
];
|
||||||
|
emit(UsersLoadedState());
|
||||||
|
} catch (e) {
|
||||||
|
emit(ErrorState(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tapSelect = true;
|
||||||
|
|
||||||
|
changeTapSelected(
|
||||||
|
ChangeTapSelected event, Emitter<RolesPermissionState> emit) {
|
||||||
|
try {
|
||||||
|
emit(RolesLoadingState());
|
||||||
|
tapSelect = event.selected;
|
||||||
|
emit(ChangeTapStatus(select: !tapSelect));
|
||||||
|
} catch (e) {
|
||||||
|
emit(ErrorState(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
sealed class RolesPermissionEvent extends Equatable {
|
||||||
|
const RolesPermissionEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetRoles extends RolesPermissionEvent {
|
||||||
|
const GetRoles();
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetBatchStatus extends RolesPermissionEvent {
|
||||||
|
final List<String> uuids;
|
||||||
|
const GetBatchStatus(this.uuids);
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [uuids];
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetDeviceRecords extends RolesPermissionEvent {
|
||||||
|
final String uuid;
|
||||||
|
|
||||||
|
const GetDeviceRecords(this.uuid);
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [uuid];
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetDeviceAutomationRecords extends RolesPermissionEvent {
|
||||||
|
final String uuid;
|
||||||
|
const GetDeviceAutomationRecords(this.uuid);
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [uuid];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChangeTapSelected extends RolesPermissionEvent {
|
||||||
|
final bool selected;
|
||||||
|
const ChangeTapSelected(this.selected);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [selected];
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
sealed class RolesPermissionState extends Equatable {
|
||||||
|
const RolesPermissionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
final class RolesInitial extends RolesPermissionState {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class RolesLoadingState extends RolesPermissionState {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class UsersLoadingState extends RolesPermissionState {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class RolesLoadedState extends RolesPermissionState {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class UsersLoadedState extends RolesPermissionState {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ErrorState extends RolesPermissionState {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const ErrorState(this.message);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [message];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// report state
|
||||||
|
final class SosReportLoadingState extends RolesPermissionState {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class RolesErrorState extends RolesPermissionState {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const RolesErrorState(this.message);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [message];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// automation reports
|
||||||
|
|
||||||
|
final class SosAutomationReportLoadingState extends RolesPermissionState {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class SosAutomationReportErrorState extends RolesPermissionState {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const SosAutomationReportErrorState(this.message);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [message];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ChangeTapStatus extends RolesPermissionState {
|
||||||
|
final bool select;
|
||||||
|
|
||||||
|
const ChangeTapStatus({required this.select});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [select];
|
||||||
|
}
|
267
lib/pages/roles_and_permission/model/edit_user_model.dart
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
// import 'dart:convert';
|
||||||
|
|
||||||
|
// // Model for Space
|
||||||
|
// class UserSpaceModel {
|
||||||
|
// final String uuid;
|
||||||
|
// final DateTime createdAt;
|
||||||
|
// final DateTime updatedAt;
|
||||||
|
|
||||||
|
// UserSpaceModel({
|
||||||
|
// required this.uuid,
|
||||||
|
// required this.createdAt,
|
||||||
|
// required this.updatedAt,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// factory UserSpaceModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
// return UserSpaceModel(
|
||||||
|
// uuid: json['uuid'],
|
||||||
|
// createdAt: DateTime.parse(json['createdAt']),
|
||||||
|
// updatedAt: DateTime.parse(json['updatedAt']),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Map<String, dynamic> toJson() {
|
||||||
|
// return {
|
||||||
|
// 'uuid': uuid,
|
||||||
|
// 'createdAt': createdAt.toIso8601String(),
|
||||||
|
// 'updatedAt': updatedAt.toIso8601String(),
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Model for User
|
||||||
|
// class EditUserModel {
|
||||||
|
// final String uuid;
|
||||||
|
// final DateTime createdAt;
|
||||||
|
// final dynamic email;
|
||||||
|
// final dynamic? jobTitle;
|
||||||
|
// final dynamic status;
|
||||||
|
// final String firstName;
|
||||||
|
// final String lastName;
|
||||||
|
// final String? phoneNumber;
|
||||||
|
// final bool isEnabled;
|
||||||
|
// final dynamic invitedBy;
|
||||||
|
// final dynamic roleType;
|
||||||
|
// final List<UserSpaceModel> spaces;
|
||||||
|
// final String createdDate;
|
||||||
|
// final String createdTime;
|
||||||
|
|
||||||
|
// EditUserModel({
|
||||||
|
// required this.uuid,
|
||||||
|
// required this.createdAt,
|
||||||
|
// required this.email,
|
||||||
|
// this.jobTitle,
|
||||||
|
// required this.status,
|
||||||
|
// required this.firstName,
|
||||||
|
// required this.lastName,
|
||||||
|
// this.phoneNumber,
|
||||||
|
// required this.isEnabled,
|
||||||
|
// required this.invitedBy,
|
||||||
|
// required this.roleType,
|
||||||
|
// required this.spaces,
|
||||||
|
// required this.createdDate,
|
||||||
|
// required this.createdTime,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// factory EditUserModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
// var spacesList = (json['spaces'] as List)
|
||||||
|
// .map((spaceJson) => UserSpaceModel.fromJson(spaceJson))
|
||||||
|
// .toList();
|
||||||
|
|
||||||
|
// return EditUserModel(
|
||||||
|
// uuid: json['uuid'],
|
||||||
|
// createdAt: DateTime.parse(json['createdAt']),
|
||||||
|
// email: json['email'],
|
||||||
|
// jobTitle: json['jobTitle'],
|
||||||
|
// status: json['status'],
|
||||||
|
// firstName: json['firstName'],
|
||||||
|
// lastName: json['lastName'],
|
||||||
|
// phoneNumber: json['phoneNumber'],
|
||||||
|
// isEnabled: json['isEnabled'],
|
||||||
|
// invitedBy: json['invitedBy'],
|
||||||
|
// roleType: json['roleType'],
|
||||||
|
// spaces: spacesList,
|
||||||
|
// createdDate: json['createdDate'],
|
||||||
|
// createdTime: json['createdTime'],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Map<String, dynamic> toJson() {
|
||||||
|
// return {
|
||||||
|
// 'uuid': uuid,
|
||||||
|
// 'createdAt': createdAt.toIso8601String(),
|
||||||
|
// 'email': email,
|
||||||
|
// 'jobTitle': jobTitle,
|
||||||
|
// 'status': status,
|
||||||
|
// 'firstName': firstName,
|
||||||
|
// 'lastName': lastName,
|
||||||
|
// 'phoneNumber': phoneNumber,
|
||||||
|
// 'isEnabled': isEnabled,
|
||||||
|
// 'invitedBy': invitedBy,
|
||||||
|
// 'roleType': roleType,
|
||||||
|
// 'spaces': spaces.map((space) => space.toJson()).toList(),
|
||||||
|
// 'createdDate': createdDate,
|
||||||
|
// 'createdTime': createdTime,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
class UserProjectResponse {
|
||||||
|
final int statusCode;
|
||||||
|
final String message;
|
||||||
|
final EditUserModel data;
|
||||||
|
final bool success;
|
||||||
|
|
||||||
|
UserProjectResponse({
|
||||||
|
required this.statusCode,
|
||||||
|
required this.message,
|
||||||
|
required this.data,
|
||||||
|
required this.success,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Create a [UserProjectResponse] from JSON data
|
||||||
|
factory UserProjectResponse.fromJson(Map<String, dynamic> json) {
|
||||||
|
return UserProjectResponse(
|
||||||
|
statusCode: json['statusCode'] as int,
|
||||||
|
message: json['message'] as String,
|
||||||
|
data: EditUserModel.fromJson(json['data'] as Map<String, dynamic>),
|
||||||
|
success: json['success'] as bool,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the [UserProjectResponse] to JSON
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'statusCode': statusCode,
|
||||||
|
'message': message,
|
||||||
|
'data': data.toJson(),
|
||||||
|
'success': success,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EditUserModel {
|
||||||
|
final String uuid;
|
||||||
|
final String firstName;
|
||||||
|
final String lastName;
|
||||||
|
final String email;
|
||||||
|
final String createdDate; // e.g. "1/3/2025"
|
||||||
|
final String createdTime; // e.g. "8:41:43 AM"
|
||||||
|
final String status; // e.g. "invited"
|
||||||
|
final String invitedBy; // e.g. "SUPER_ADMIN"
|
||||||
|
final String? phoneNumber; // can be empty
|
||||||
|
final String? jobTitle; // can be empty
|
||||||
|
final String roleType; // e.g. "ADMIN"
|
||||||
|
final List<UserSpaceModel> spaces;
|
||||||
|
|
||||||
|
EditUserModel({
|
||||||
|
required this.uuid,
|
||||||
|
required this.firstName,
|
||||||
|
required this.lastName,
|
||||||
|
required this.email,
|
||||||
|
required this.createdDate,
|
||||||
|
required this.createdTime,
|
||||||
|
required this.status,
|
||||||
|
required this.invitedBy,
|
||||||
|
required this.phoneNumber,
|
||||||
|
required this.jobTitle,
|
||||||
|
required this.roleType,
|
||||||
|
required this.spaces,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Create a [UserData] from JSON data
|
||||||
|
factory EditUserModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return EditUserModel(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
firstName: json['firstName'] as String,
|
||||||
|
lastName: json['lastName'] as String,
|
||||||
|
email: json['email'] as String,
|
||||||
|
createdDate: json['createdDate'] as String,
|
||||||
|
createdTime: json['createdTime'] as String,
|
||||||
|
status: json['status'] as String,
|
||||||
|
invitedBy: json['invitedBy'] as String,
|
||||||
|
phoneNumber: json['phoneNumber'] ?? '',
|
||||||
|
jobTitle: json['jobTitle'] ?? '',
|
||||||
|
roleType: json['roleType'] as String,
|
||||||
|
spaces: (json['spaces'] as List<dynamic>)
|
||||||
|
.map((e) => UserSpaceModel.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the [UserData] to JSON
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'firstName': firstName,
|
||||||
|
'lastName': lastName,
|
||||||
|
'email': email,
|
||||||
|
'createdDate': createdDate,
|
||||||
|
'createdTime': createdTime,
|
||||||
|
'status': status,
|
||||||
|
'invitedBy': invitedBy,
|
||||||
|
'phoneNumber': phoneNumber,
|
||||||
|
'jobTitle': jobTitle,
|
||||||
|
'roleType': roleType,
|
||||||
|
'spaces': spaces.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserSpaceModel {
|
||||||
|
final String uuid;
|
||||||
|
final String createdAt; // e.g. "2024-11-04T07:20:35.940Z"
|
||||||
|
final String updatedAt; // e.g. "2024-11-28T18:47:29.736Z"
|
||||||
|
final dynamic spaceTuyaUuid;
|
||||||
|
final dynamic spaceName;
|
||||||
|
final dynamic invitationCode;
|
||||||
|
final bool disabled;
|
||||||
|
final double x;
|
||||||
|
final double y;
|
||||||
|
final String icon;
|
||||||
|
|
||||||
|
UserSpaceModel({
|
||||||
|
required this.uuid,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.spaceTuyaUuid,
|
||||||
|
required this.spaceName,
|
||||||
|
required this.invitationCode,
|
||||||
|
required this.disabled,
|
||||||
|
required this.x,
|
||||||
|
required this.y,
|
||||||
|
required this.icon,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Create a [UserSpaceModel] from JSON data
|
||||||
|
factory UserSpaceModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return UserSpaceModel(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
createdAt: json['createdAt'] as String,
|
||||||
|
updatedAt: json['updatedAt'] as String,
|
||||||
|
spaceTuyaUuid: json['spaceTuyaUuid'] as String?,
|
||||||
|
spaceName: json['spaceName'] as String,
|
||||||
|
invitationCode: json['invitationCode'] as String?,
|
||||||
|
disabled: json['disabled'] as bool,
|
||||||
|
x: (json['x'] as num).toDouble(),
|
||||||
|
y: (json['y'] as num).toDouble(),
|
||||||
|
icon: json['icon'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the [UserSpaceModel] to JSON
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'createdAt': createdAt,
|
||||||
|
'updatedAt': updatedAt,
|
||||||
|
'spaceTuyaUuid': spaceTuyaUuid,
|
||||||
|
'spaceName': spaceName,
|
||||||
|
'invitationCode': invitationCode,
|
||||||
|
'disabled': disabled,
|
||||||
|
'x': x,
|
||||||
|
'y': y,
|
||||||
|
'icon': icon,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
6
lib/pages/roles_and_permission/model/role_model.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class RoleModel {
|
||||||
|
String? roleId;
|
||||||
|
String? roleName;
|
||||||
|
String? roleImage;
|
||||||
|
RoleModel({this.roleId, this.roleName, this.roleImage});
|
||||||
|
}
|
22
lib/pages/roles_and_permission/model/role_type_model.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
class RoleTypeModel {
|
||||||
|
final String uuid;
|
||||||
|
final String createdAt;
|
||||||
|
final String updatedAt;
|
||||||
|
final String type;
|
||||||
|
|
||||||
|
RoleTypeModel({
|
||||||
|
required this.uuid,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.type,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory RoleTypeModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return RoleTypeModel(
|
||||||
|
uuid: json['uuid'],
|
||||||
|
createdAt: json['createdAt'],
|
||||||
|
updatedAt: json['updatedAt'],
|
||||||
|
type: json['type'].toString().toLowerCase().replaceAll("_", " "),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
52
lib/pages/roles_and_permission/model/roles_user_model.dart
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
class RolesUserModel {
|
||||||
|
final String uuid;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final String email;
|
||||||
|
final dynamic firstName;
|
||||||
|
final dynamic lastName;
|
||||||
|
final dynamic roleType;
|
||||||
|
final dynamic status;
|
||||||
|
final bool isEnabled;
|
||||||
|
final String invitedBy;
|
||||||
|
final dynamic phoneNumber;
|
||||||
|
final dynamic jobTitle;
|
||||||
|
final dynamic createdDate;
|
||||||
|
final dynamic createdTime;
|
||||||
|
|
||||||
|
RolesUserModel({
|
||||||
|
required this.uuid,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.email,
|
||||||
|
required this.firstName,
|
||||||
|
required this.lastName,
|
||||||
|
required this.roleType,
|
||||||
|
required this.status,
|
||||||
|
required this.isEnabled,
|
||||||
|
required this.invitedBy,
|
||||||
|
this.phoneNumber,
|
||||||
|
this.jobTitle,
|
||||||
|
required this.createdDate,
|
||||||
|
required this.createdTime,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory RolesUserModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return RolesUserModel(
|
||||||
|
uuid: json['uuid'],
|
||||||
|
createdAt: DateTime.parse(json['createdAt']),
|
||||||
|
email: json['email'],
|
||||||
|
firstName: json['firstName'],
|
||||||
|
lastName: json['lastName'],
|
||||||
|
roleType: json['roleType'].toString().toLowerCase().replaceAll("_", " "),
|
||||||
|
status: json['status'],
|
||||||
|
isEnabled: json['isEnabled'],
|
||||||
|
invitedBy:
|
||||||
|
json['invitedBy'].toString().toLowerCase().replaceAll("_", " "),
|
||||||
|
phoneNumber: json['phoneNumber'],
|
||||||
|
jobTitle: json['jobTitle'] == null || json['jobTitle'] == " "
|
||||||
|
? "_"
|
||||||
|
: json['jobTitle'],
|
||||||
|
createdDate: json['createdDate'],
|
||||||
|
createdTime: json['createdTime'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,603 @@
|
|||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/custom_dialog.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/model/edit_user_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/model/role_type_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/permission_option_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/tree_node_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
|
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||||
|
import 'package:syncrow_web/services/user_permission.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
|
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||||
|
UsersBloc() : super(UsersInitial()) {
|
||||||
|
on<CheckStepStatus>(isCompleteBasicsFun);
|
||||||
|
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
|
||||||
|
on<SearchAnode>(searchTreeNode);
|
||||||
|
on<CheckSpacesStepStatus>(isCompleteSpacesFun);
|
||||||
|
on<RoleEvent>(_getRolePermission);
|
||||||
|
on<PermissionEvent>(_getPermissions);
|
||||||
|
on<SearchPermission>(searchRolePermission);
|
||||||
|
on<SendInviteUsers>(_sendInvitUser);
|
||||||
|
on<ValidateBasicsStep>(_validateBasicsStep);
|
||||||
|
on<CheckRoleStepStatus>(isCompleteRoleFun);
|
||||||
|
on<CheckEmailEvent>(checkEmail);
|
||||||
|
on<GetUserByIdEvent>(getUserById);
|
||||||
|
on<ToggleNodeExpansion>(_onToggleNodeExpansion);
|
||||||
|
on<ToggleNodeCheck>(_onToggleNodeCheck);
|
||||||
|
on<EditInviteUsers>(_editInviteUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _validateBasicsStep(ValidateBasicsStep event, Emitter<UsersState> emit) {
|
||||||
|
if (formKey.currentState?.validate() ?? false) {
|
||||||
|
emit(const BasicsStepValidState());
|
||||||
|
} else {
|
||||||
|
emit(const BasicsStepInvalidState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String roleSelected = '';
|
||||||
|
|
||||||
|
final formKey = GlobalKey<FormState>();
|
||||||
|
final TextEditingController firstNameController = TextEditingController();
|
||||||
|
final TextEditingController lastNameController = TextEditingController();
|
||||||
|
final TextEditingController emailController = TextEditingController();
|
||||||
|
final TextEditingController phoneController = TextEditingController();
|
||||||
|
final TextEditingController jobTitleController = TextEditingController();
|
||||||
|
final TextEditingController roleSearchController = TextEditingController();
|
||||||
|
|
||||||
|
bool? isCompleteBasics;
|
||||||
|
bool? isCompleteRolePermissions;
|
||||||
|
bool? isCompleteSpaces;
|
||||||
|
|
||||||
|
int numberBasics = 0;
|
||||||
|
int numberSpaces = 0;
|
||||||
|
int numberRole = 0;
|
||||||
|
|
||||||
|
void isCompleteSpacesFun(
|
||||||
|
CheckSpacesStepStatus event, Emitter<UsersState> emit) {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||||
|
isCompleteSpaces = selectedIds.isNotEmpty;
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
}
|
||||||
|
|
||||||
|
void isCompleteRoleFun(CheckRoleStepStatus event, Emitter<UsersState> emit) {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
isCompleteRolePermissions = roleSelected != '';
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
||||||
|
String communityUuid) async {
|
||||||
|
return await CommunitySpaceManagementApi().getSpaceHierarchy(communityUuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TreeNode> updatedCommunities = [];
|
||||||
|
List<TreeNode> spacesNodes = [];
|
||||||
|
List<String> communityIds = [];
|
||||||
|
_onLoadCommunityAndSpaces(
|
||||||
|
LoadCommunityAndSpacesEvent event, Emitter<UsersState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
List<CommunityModel> communities =
|
||||||
|
await CommunitySpaceManagementApi().fetchCommunities();
|
||||||
|
communityIds = communities.map((community) => community.uuid).toList();
|
||||||
|
updatedCommunities = await Future.wait(
|
||||||
|
communities.map((community) async {
|
||||||
|
List<SpaceModel> spaces =
|
||||||
|
await _fetchSpacesForCommunity(community.uuid);
|
||||||
|
spacesNodes = _buildTreeNodes(spaces);
|
||||||
|
return TreeNode(
|
||||||
|
uuid: community.uuid,
|
||||||
|
title: community.name,
|
||||||
|
children: spacesNodes,
|
||||||
|
isChecked: false,
|
||||||
|
isHighlighted: false,
|
||||||
|
isExpanded: true,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
originalCommunities = updatedCommunities;
|
||||||
|
emit(const SpacesLoadedState());
|
||||||
|
} catch (e) {
|
||||||
|
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This variable holds the full original list.
|
||||||
|
List<TreeNode> originalCommunities = [];
|
||||||
|
|
||||||
|
// This variable holds the working list that may be filtered.
|
||||||
|
|
||||||
|
// Build tree nodes from your data model.
|
||||||
|
List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
|
||||||
|
return spaces.map((space) {
|
||||||
|
List<TreeNode> childNodes =
|
||||||
|
space.children.isNotEmpty ? _buildTreeNodes(space.children) : [];
|
||||||
|
return TreeNode(
|
||||||
|
uuid: space.uuid!,
|
||||||
|
title: space.name,
|
||||||
|
isChecked: false,
|
||||||
|
isHighlighted: false,
|
||||||
|
isExpanded: childNodes.isNotEmpty,
|
||||||
|
children: childNodes,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional helper method to deep clone a TreeNode.
|
||||||
|
TreeNode _cloneNode(TreeNode node) {
|
||||||
|
return TreeNode(
|
||||||
|
uuid: node.uuid,
|
||||||
|
title: node.title,
|
||||||
|
isChecked: node.isChecked,
|
||||||
|
isHighlighted: node.isHighlighted,
|
||||||
|
isExpanded: node.isExpanded,
|
||||||
|
children: node.children.map(_cloneNode).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone an entire list of tree nodes.
|
||||||
|
List<TreeNode> _cloneNodes(List<TreeNode> nodes) {
|
||||||
|
return nodes.map(_cloneNode).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Your search event handler.
|
||||||
|
void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
|
||||||
|
// If the search term is empty, restore the original list.
|
||||||
|
if (event.searchTerm!.isEmpty) {
|
||||||
|
// Clear any highlights on the restored copy.
|
||||||
|
updatedCommunities = _cloneNodes(originalCommunities);
|
||||||
|
_clearHighlights(updatedCommunities);
|
||||||
|
} else {
|
||||||
|
// Start with a fresh clone of the original tree.
|
||||||
|
List<TreeNode> freshClone = _cloneNodes(originalCommunities);
|
||||||
|
|
||||||
|
_searchAndHighlightNodes(freshClone, event.searchTerm!);
|
||||||
|
|
||||||
|
updatedCommunities = _filterNodes(freshClone, event.searchTerm!);
|
||||||
|
}
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearHighlights(List<TreeNode> nodes) {
|
||||||
|
for (var node in nodes) {
|
||||||
|
node.isHighlighted = false;
|
||||||
|
if (node.children.isNotEmpty) {
|
||||||
|
_clearHighlights(node.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _searchAndHighlightNodes(List<TreeNode> nodes, String searchTerm) {
|
||||||
|
bool anyMatch = false;
|
||||||
|
for (var node in nodes) {
|
||||||
|
bool isMatch =
|
||||||
|
node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||||
|
bool childMatch = _searchAndHighlightNodes(node.children, searchTerm);
|
||||||
|
node.isHighlighted = isMatch || childMatch;
|
||||||
|
|
||||||
|
anyMatch = anyMatch || node.isHighlighted;
|
||||||
|
}
|
||||||
|
return anyMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TreeNode> _filterNodes(List<TreeNode> nodes, String searchTerm) {
|
||||||
|
List<TreeNode> filteredNodes = [];
|
||||||
|
for (var node in nodes) {
|
||||||
|
bool isMatch =
|
||||||
|
node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||||
|
List<TreeNode> filteredChildren = _filterNodes(node.children, searchTerm);
|
||||||
|
if (isMatch || filteredChildren.isNotEmpty) {
|
||||||
|
node.isHighlighted = isMatch;
|
||||||
|
node.children = filteredChildren;
|
||||||
|
filteredNodes.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
|
||||||
|
// return spaces.map((space) {
|
||||||
|
// List<TreeNode> childNodes =
|
||||||
|
// space.children.isNotEmpty ? _buildTreeNodes(space.children) : [];
|
||||||
|
// return TreeNode(
|
||||||
|
// uuid: space.uuid!,
|
||||||
|
// title: space.name,
|
||||||
|
// isChecked: false,
|
||||||
|
// isHighlighted: false,
|
||||||
|
// isExpanded: childNodes.isNotEmpty,
|
||||||
|
// children: childNodes,
|
||||||
|
// );
|
||||||
|
// }).toList();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
|
||||||
|
// emit(UsersLoadingState());
|
||||||
|
// if (event.searchTerm!.isEmpty) {
|
||||||
|
// _clearHighlights(updatedCommunities);
|
||||||
|
// } else {
|
||||||
|
// _searchAndHighlightNodes(updatedCommunities, event.searchTerm!);
|
||||||
|
// updatedCommunities = _filterNodes(updatedCommunities, event.searchTerm!);
|
||||||
|
// }
|
||||||
|
// emit(ChangeStatusSteps());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void _clearHighlights(List<TreeNode> nodes) {
|
||||||
|
// for (var node in nodes) {
|
||||||
|
// node.isHighlighted = false;
|
||||||
|
// if (node.children.isNotEmpty) {
|
||||||
|
// _clearHighlights(node.children);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bool _searchAndHighlightNodes(List<TreeNode> nodes, String searchTerm) {
|
||||||
|
// bool anyMatch = false;
|
||||||
|
// for (var node in nodes) {
|
||||||
|
// bool isMatch =
|
||||||
|
// node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||||
|
// bool childMatch = _searchAndHighlightNodes(node.children, searchTerm);
|
||||||
|
// node.isHighlighted = isMatch || childMatch;
|
||||||
|
|
||||||
|
// anyMatch = anyMatch || node.isHighlighted;
|
||||||
|
// }
|
||||||
|
// return anyMatch;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// List<TreeNode> _filterNodes(List<TreeNode> nodes, String searchTerm) {
|
||||||
|
// List<TreeNode> filteredNodes = [];
|
||||||
|
// for (var node in nodes) {
|
||||||
|
// // Check if the current node's title contains the search term.
|
||||||
|
// bool isMatch =
|
||||||
|
// node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||||
|
|
||||||
|
// // Recursively filter the children.
|
||||||
|
// List<TreeNode> filteredChildren = _filterNodes(node.children, searchTerm);
|
||||||
|
|
||||||
|
// // If the current node is a match or any of its children are, include it.
|
||||||
|
// if (isMatch || filteredChildren.isNotEmpty) {
|
||||||
|
// // Optionally, update any properties (like isHighlighted) if you still need them.
|
||||||
|
// node.isHighlighted = isMatch;
|
||||||
|
// // Replace the children with the filtered ones.
|
||||||
|
// node.children = filteredChildren;
|
||||||
|
// filteredNodes.add(node);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return filteredNodes;
|
||||||
|
// }
|
||||||
|
|
||||||
|
List<String> selectedIds = [];
|
||||||
|
|
||||||
|
List<String> getSelectedIds(List<TreeNode> nodes) {
|
||||||
|
List<String> selectedIds = [];
|
||||||
|
for (var node in nodes) {
|
||||||
|
if (node.isChecked) {
|
||||||
|
selectedIds.add(node.uuid);
|
||||||
|
}
|
||||||
|
if (node.children.isNotEmpty) {
|
||||||
|
selectedIds.addAll(getSelectedIds(node.children));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selectedIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<RoleTypeModel> roles = [];
|
||||||
|
List<PermissionOption> permissions = [];
|
||||||
|
|
||||||
|
_getRolePermission(RoleEvent event, Emitter<UsersState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
roles = await UserPermissionApi().fetchRoles();
|
||||||
|
emit(RolePermissionInitial());
|
||||||
|
} catch (e) {
|
||||||
|
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_getPermissions(PermissionEvent event, Emitter<UsersState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
permissions = await UserPermissionApi().fetchPermission(
|
||||||
|
event.roleUuid == "" ? roles.first.uuid : event.roleUuid);
|
||||||
|
roleSelected = event.roleUuid!;
|
||||||
|
emit(RolePermissionInitial());
|
||||||
|
} catch (e) {
|
||||||
|
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _searchRolePermission(List<PermissionOption> nodes, String searchTerm) {
|
||||||
|
bool anyMatch = false;
|
||||||
|
for (var node in nodes) {
|
||||||
|
bool isMatch =
|
||||||
|
node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||||
|
bool childMatch = _searchRolePermission(node.subOptions, searchTerm);
|
||||||
|
node.isHighlighted = isMatch || childMatch;
|
||||||
|
anyMatch = anyMatch || node.isHighlighted;
|
||||||
|
}
|
||||||
|
return anyMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||||
|
.where((id) => !communityIds.contains(id))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
bool res = await UserPermissionApi().sendInviteUser(
|
||||||
|
email: emailController.text,
|
||||||
|
firstName: firstNameController.text,
|
||||||
|
jobTitle: jobTitleController.text,
|
||||||
|
lastName: lastNameController.text,
|
||||||
|
phoneNumber: phoneController.text,
|
||||||
|
roleUuid: roleSelected,
|
||||||
|
spaceUuids: selectedIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
showCustomDialog(
|
||||||
|
barrierDismissible: false,
|
||||||
|
context: event.context,
|
||||||
|
message: "The invite was sent successfully.",
|
||||||
|
iconPath: Assets.deviceNoteIcon,
|
||||||
|
title: "Invite Success",
|
||||||
|
dialogHeight: MediaQuery.of(event.context).size.height * 0.3,
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(event.context).pop(true);
|
||||||
|
Navigator.of(event.context).pop(true);
|
||||||
|
},
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
emit(const ErrorState('Failed to send invite.'));
|
||||||
|
}
|
||||||
|
emit(SaveState());
|
||||||
|
} catch (e) {
|
||||||
|
emit(ErrorState('Failed to send invite: ${e.toString()}'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_editInviteUser(EditInviteUsers event, Emitter<UsersState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||||
|
.where((id) => !communityIds.contains(id))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
bool res = await UserPermissionApi().editInviteUser(
|
||||||
|
userId: event.userId,
|
||||||
|
firstName: firstNameController.text,
|
||||||
|
jobTitle: jobTitleController.text,
|
||||||
|
lastName: lastNameController.text,
|
||||||
|
phoneNumber: phoneController.text,
|
||||||
|
roleUuid: roleSelected,
|
||||||
|
spaceUuids: selectedIds,
|
||||||
|
);
|
||||||
|
if (res == true) {
|
||||||
|
showCustomDialog(
|
||||||
|
barrierDismissible: false,
|
||||||
|
context: event.context,
|
||||||
|
message: "The invite was sent successfully.",
|
||||||
|
iconPath: Assets.deviceNoteIcon,
|
||||||
|
title: "Invite Success",
|
||||||
|
dialogHeight: MediaQuery.of(event.context).size.height * 0.3,
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(event.context).pop(true);
|
||||||
|
Navigator.of(event.context).pop(true);
|
||||||
|
},
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).then(
|
||||||
|
(value) {},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
emit(const ErrorState('Failed to send invite.'));
|
||||||
|
}
|
||||||
|
emit(SaveState());
|
||||||
|
} catch (e) {
|
||||||
|
emit(ErrorState('Failed to send invite: ${e.toString()}'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void searchRolePermission(SearchPermission event, Emitter<UsersState> emit) {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
if (event.searchTerm!.isEmpty) {
|
||||||
|
_clearHighlightsRolePermission(permissions);
|
||||||
|
} else {
|
||||||
|
_searchRolePermission(permissions, event.searchTerm!);
|
||||||
|
}
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
}
|
||||||
|
|
||||||
|
String checkEmailValid = '';
|
||||||
|
|
||||||
|
Future<void> checkEmail(
|
||||||
|
CheckEmailEvent event, Emitter<UsersState> emit) async {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
String? res = await UserPermissionApi().checkEmail(
|
||||||
|
emailController.text,
|
||||||
|
);
|
||||||
|
checkEmailValid = res!;
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isCompleteBasicsFun(CheckStepStatus event, Emitter<UsersState> emit) {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
if (event.isEditUser == false) {
|
||||||
|
add(const CheckEmailEvent());
|
||||||
|
final emailRegex = RegExp(
|
||||||
|
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
|
||||||
|
);
|
||||||
|
bool isEmailValid = emailRegex.hasMatch(emailController.text);
|
||||||
|
bool isEmailServerValid = checkEmailValid == 'Valid email';
|
||||||
|
isCompleteBasics = firstNameController.text.isNotEmpty &&
|
||||||
|
lastNameController.text.isNotEmpty &&
|
||||||
|
emailController.text.isNotEmpty &&
|
||||||
|
isEmailValid &&
|
||||||
|
isEmailServerValid;
|
||||||
|
} else {
|
||||||
|
isCompleteBasics = firstNameController.text.isNotEmpty &&
|
||||||
|
lastNameController.text.isNotEmpty;
|
||||||
|
}
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
emit(ValidateBasics());
|
||||||
|
return isCompleteBasics!;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearHighlightsRolePermission(List<PermissionOption> nodes) {
|
||||||
|
for (var node in nodes) {
|
||||||
|
node.isHighlighted = false;
|
||||||
|
if (node.subOptions.isNotEmpty) {
|
||||||
|
_clearHighlightsRolePermission(node.subOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditUserModel? res = EditUserModel(
|
||||||
|
spaces: [],
|
||||||
|
jobTitle: '',
|
||||||
|
phoneNumber: '',
|
||||||
|
uuid: '',
|
||||||
|
email: '',
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
roleType: '',
|
||||||
|
status: '',
|
||||||
|
invitedBy: '',
|
||||||
|
createdDate: '',
|
||||||
|
createdTime: '');
|
||||||
|
|
||||||
|
Future<void> getUserById(
|
||||||
|
GetUserByIdEvent event,
|
||||||
|
Emitter<UsersState> emit,
|
||||||
|
) async {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (event.uuid?.isNotEmpty ?? false) {
|
||||||
|
final res = await UserPermissionApi().fetchUserById(event.uuid);
|
||||||
|
|
||||||
|
if (res != null) {
|
||||||
|
// Populate the text controllers
|
||||||
|
firstNameController.text = res.firstName;
|
||||||
|
lastNameController.text = res.lastName;
|
||||||
|
emailController.text = res.email;
|
||||||
|
phoneController.text = res.phoneNumber ?? '';
|
||||||
|
jobTitleController.text = res.jobTitle ?? '';
|
||||||
|
res.roleType;
|
||||||
|
if (updatedCommunities.isNotEmpty) {
|
||||||
|
// Create a list of UUIDs to mark
|
||||||
|
final uuidsToMark = res.spaces.map((space) => space.uuid).toList();
|
||||||
|
// Print all IDs and mark nodes in updatedCommunities
|
||||||
|
debugPrint('Printing and marking nodes in updatedCommunities:');
|
||||||
|
_printAndMarkNodes(updatedCommunities, uuidsToMark);
|
||||||
|
}
|
||||||
|
final roleId = roles
|
||||||
|
.firstWhere((element) =>
|
||||||
|
element.type ==
|
||||||
|
res.roleType.toString().toLowerCase().replaceAll("_", " "))
|
||||||
|
.uuid;
|
||||||
|
debugPrint('Role ID: $roleId');
|
||||||
|
roleSelected = roleId;
|
||||||
|
add(PermissionEvent(roleUuid: roleSelected));
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
} else {}
|
||||||
|
} else {}
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _printAndMarkNodes(List<TreeNode> nodes, List<String> uuidsToMark,
|
||||||
|
[int level = 0]) {
|
||||||
|
for (final node in nodes) {
|
||||||
|
if (uuidsToMark.contains(node.uuid)) {
|
||||||
|
node.isChecked = true;
|
||||||
|
debugPrint(
|
||||||
|
'${' ' * level}MATCH FOUND: Node ID: ${node.uuid}, Title: ${node.title} is marked as checked.');
|
||||||
|
} else {
|
||||||
|
debugPrint(
|
||||||
|
'${' ' * level}Node ID: ${node.uuid}, Title: ${node.title}');
|
||||||
|
}
|
||||||
|
if (node.children.isNotEmpty) {
|
||||||
|
_printAndMarkNodes(node.children, uuidsToMark, level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onToggleNodeExpansion(
|
||||||
|
ToggleNodeExpansion event,
|
||||||
|
Emitter<UsersState> emit,
|
||||||
|
) {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
event.node.isExpanded = !event.node.isExpanded;
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onToggleNodeCheck(
|
||||||
|
ToggleNodeCheck event,
|
||||||
|
Emitter<UsersState> emit,
|
||||||
|
) {
|
||||||
|
emit(UsersLoadingState());
|
||||||
|
//Toggle node's checked state
|
||||||
|
event.node.isChecked = !event.node.isChecked;
|
||||||
|
debugPrint(
|
||||||
|
'Node toggled. ID: ${event.node.uuid}, isChecked: ${event.node.isChecked}',
|
||||||
|
);
|
||||||
|
// Update children and parent
|
||||||
|
_updateChildrenCheckStatus(event.node, event.node.isChecked);
|
||||||
|
_updateParentCheckStatus(event.node);
|
||||||
|
|
||||||
|
// Finally, emit a new state
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateChildrenCheckStatus(TreeNode node, bool isChecked) {
|
||||||
|
for (var child in node.children) {
|
||||||
|
child.isChecked = isChecked;
|
||||||
|
_updateChildrenCheckStatus(child, isChecked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateParentCheckStatus(TreeNode node) {
|
||||||
|
TreeNode? parent = _findParent(updatedCommunities, node);
|
||||||
|
if (parent != null) {
|
||||||
|
parent.isChecked = _areAllChildrenChecked(parent);
|
||||||
|
_updateParentCheckStatus(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _areAllChildrenChecked(TreeNode node) {
|
||||||
|
return node.children.isNotEmpty &&
|
||||||
|
node.children.every((child) =>
|
||||||
|
child.isChecked &&
|
||||||
|
(child.children.isEmpty || _areAllChildrenChecked(child)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode? _findParent(List<TreeNode> nodes, TreeNode target) {
|
||||||
|
for (var node in nodes) {
|
||||||
|
if (node.children.contains(target)) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
final parent = _findParent(node.children, target);
|
||||||
|
if (parent != null) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|