Compare commits
194 Commits
bugfix/fix
...
SP-1271-re
Author | SHA1 | Date | |
---|---|---|---|
22935f7007 | |||
5bf5120883 | |||
f307aaff9d | |||
aea18fb293 | |||
835dfe8785 | |||
f670ae78aa | |||
d3128a9c9c | |||
b65f172f9d | |||
dad18b77de | |||
77a9aa2f19 | |||
b77dc860cb | |||
6045158432 | |||
7e06dd76cf | |||
7e1c2ba712 | |||
80c43b8046 | |||
2d3345c1d9 | |||
c0d53fdf5c | |||
5e05b20f68 | |||
95730cc2ba | |||
a5a37f3841 | |||
e0486deecb | |||
bc64efa557 | |||
2a065efc0e | |||
7ae3e4a933 | |||
2a0f6a4596 | |||
5b2822f973 | |||
70d31f5351 | |||
c39c693755 | |||
8ed6980264 | |||
16df75eb49 | |||
80c294f09c | |||
c806b5f59d | |||
dd01a7fddb | |||
b563cc378e | |||
2140b7eee3 | |||
7de9e25ed5 | |||
123949aa86 | |||
6d554c5953 | |||
5ed87a5794 | |||
168c997240 | |||
de65f79ccf | |||
eb0490fb16 | |||
a73fc04712 | |||
dee07ebb06 | |||
5237f3ae5b | |||
e017633b9b | |||
e8e5e9bcb7 | |||
a1d15c9cea | |||
16c006e7a9 | |||
24280549ec | |||
8359642a1a | |||
ada19a5992 | |||
c6702d4d5f | |||
f78e2e2d36 | |||
83b9555920 | |||
8af24e575c | |||
4301d7f62f | |||
788d36541b | |||
44cf1cec69 | |||
acb7ed5192 | |||
1b8a87e942 | |||
fa39182386 | |||
54a250ea2f | |||
efccac4d19 | |||
096317fce8 | |||
254485235d | |||
d624dd767b | |||
add34b327f | |||
d75ac416eb | |||
048a7c0e8f | |||
c8aab320df | |||
9795517a3f | |||
60bf58d5fd | |||
8d072ee6bb | |||
de614d40a5 | |||
45f6599c40 | |||
fecab17cbe | |||
d2ff909bf2 | |||
5cea8eddb3 | |||
213ec329c0 | |||
c9427b35be | |||
a7995bb2b8 | |||
20474835dd | |||
5233c1b38e | |||
ec502214f4 | |||
215dd9cfa4 | |||
dcfbe5282e | |||
d88ae9ea15 | |||
64adf516f6 | |||
ef777cfce9 | |||
6e90f81760 | |||
51cfa8d5ae | |||
4469efe465 | |||
c7c8e9a519 | |||
6f2e2e2d4a | |||
692b05a600 | |||
7607e5f80d | |||
b84513c09d | |||
41605bef6b | |||
fd24d6bd27 | |||
fe52726f6e | |||
5ea29efaf5 | |||
70cb12236b | |||
9f75ce817e | |||
aa23daa0b4 | |||
61f0c3ad2b | |||
553c77d1e3 | |||
27fef7ddaa | |||
010176cc25 | |||
d08a1d1037 | |||
e634154fb3 | |||
c0f59aba61 | |||
7ee7681e09 | |||
57c5f4752c | |||
ad4f2ae382 | |||
eafb811d2e | |||
2d0dcc41df | |||
d89e3fac8e | |||
25acd67351 | |||
b134823551 | |||
1054970a63 | |||
7cab299a51 | |||
a3c5670fee | |||
009ede7d08 | |||
0c2a092f4d | |||
b968b5a6eb | |||
05edc7641a | |||
b8204f1015 | |||
d87fec796b | |||
b00b0c82dc | |||
0aa029a2fc | |||
dec3a25639 | |||
581dcf7016 | |||
e1609309cf | |||
da445e11aa | |||
55de7fab0f | |||
ba44d1d359 | |||
00a9cb1188 | |||
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 | |||
5ab9664318 | |||
d3bf4de0ca | |||
5ae07688cb | |||
e6fa9c2391 | |||
b070884bd9 | |||
7d05a33c52 | |||
6e546a4831 | |||
b098202fd8 | |||
43c17d1c18 | |||
e70b9ea9e2 | |||
9e0184f19d | |||
ea5b6597f5 | |||
2221d9ae7b | |||
921d352207 | |||
c5871be990 | |||
2fb6f30ccb | |||
508d8bbaa8 | |||
97bdb1bbb7 | |||
7ce0a27af0 | |||
bc4af6a237 | |||
513175ed1e | |||
5060d2a66d | |||
540f569b1f | |||
a98f7e77a3 | |||
0341844ea9 |
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
assets/icons/delete_space_link_icon.svg
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_6702_36698)">
|
||||||
|
<circle cx="20" cy="20" r="15" fill="#F4F4F4"/>
|
||||||
|
<path d="M26.4 13.1094H23.7333V12.582C23.7333 11.7097 23.0156 11 22.1333 11H17.8667C16.9844 11 16.2667 11.7097 16.2667 12.582V13.1094H13.6C12.7178 13.1094 12 13.8191 12 14.6914C12 15.392 12.4631 15.9873 13.1024 16.1947L14.0537 27.5493C14.1222 28.3628 14.8226 29 15.6481 29H24.3519C25.1775 29 25.8778 28.3628 25.9464 27.5491L26.8976 16.1947C27.5369 15.9873 28 15.392 28 14.6914C28 13.8191 27.2822 13.1094 26.4 13.1094ZM17.3333 12.582C17.3333 12.2913 17.5726 12.0547 17.8667 12.0547H22.1333C22.4274 12.0547 22.6667 12.2913 22.6667 12.582V13.1094H17.3333V12.582ZM24.8833 27.4618C24.8605 27.7329 24.6271 27.9453 24.3519 27.9453H15.6481C15.373 27.9453 15.1395 27.7329 15.1167 27.462L14.1793 16.2734H25.8207L24.8833 27.4618ZM26.4 15.2188H13.6C13.3059 15.2188 13.0667 14.9822 13.0667 14.6914C13.0667 14.4006 13.3059 14.1641 13.6 14.1641H26.4C26.6941 14.1641 26.9333 14.4006 26.9333 14.6914C26.9333 14.9822 26.6941 15.2188 26.4 15.2188Z" fill="#999999"/>
|
||||||
|
<path d="M17.8656 26.3307L17.3323 17.8229C17.314 17.5322 17.0596 17.3111 16.767 17.3292C16.473 17.3472 16.2494 17.5974 16.2676 17.8881L16.801 26.396C16.8185 26.6756 17.0533 26.8907 17.3328 26.8907C17.6416 26.8907 17.8846 26.6335 17.8656 26.3307Z" fill="#999999"/>
|
||||||
|
<path d="M20.0001 17.3281C19.7056 17.3281 19.4668 17.5642 19.4668 17.8555V26.3633C19.4668 26.6545 19.7056 26.8906 20.0001 26.8906C20.2947 26.8906 20.5335 26.6545 20.5335 26.3633V17.8555C20.5335 17.5642 20.2947 17.3281 20.0001 17.3281Z" fill="#999999"/>
|
||||||
|
<path d="M23.233 17.3292C22.9396 17.3111 22.6859 17.5321 22.6677 17.8229L22.1343 26.3307C22.1162 26.6213 22.3397 26.8716 22.6337 26.8896C22.9278 26.9076 23.1808 26.6865 23.199 26.3959L23.7323 17.8881C23.7505 17.5974 23.527 17.3472 23.233 17.3292Z" fill="#999999"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_6702_36698" x="0" y="0" width="40" height="40" 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="2.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6702_36698"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6702_36698" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
6
assets/icons/delete_space_model.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.4 2.10938H11.7333V1.58203C11.7333 0.709699 11.0156 0 10.1333 0H5.86667C4.98443 0 4.26667 0.709699 4.26667 1.58203V2.10938H1.6C0.71776 2.10938 0 2.81907 0 3.69141C0 4.392 0.463111 4.9873 1.1024 5.19472L2.05369 16.5493C2.1222 17.3628 2.82258 18 3.64814 18H12.3519C13.1775 18 13.8778 17.3628 13.9464 16.5491L14.8976 5.19469C15.5369 4.9873 16 4.392 16 3.69141C16 2.81907 15.2822 2.10938 14.4 2.10938ZM5.33333 1.58203C5.33333 1.29125 5.57259 1.05469 5.86667 1.05469H10.1333C10.4274 1.05469 10.6667 1.29125 10.6667 1.58203V2.10938H5.33333V1.58203ZM12.8833 16.4618C12.8605 16.7329 12.6271 16.9453 12.3519 16.9453H3.64814C3.37298 16.9453 3.13952 16.7329 3.11673 16.462L2.17934 5.27344H13.8207L12.8833 16.4618ZM14.4 4.21875H1.6C1.30592 4.21875 1.06667 3.98218 1.06667 3.69141C1.06667 3.40063 1.30592 3.16406 1.6 3.16406H14.4C14.6941 3.16406 14.9333 3.40063 14.9333 3.69141C14.9333 3.98218 14.6941 4.21875 14.4 4.21875Z" fill="#999999"/>
|
||||||
|
<path d="M5.86561 15.3307L5.33228 6.82286C5.31404 6.53215 5.05957 6.31106 4.76698 6.32916C4.47297 6.3472 4.24943 6.59744 4.26764 6.88811L4.80097 15.396C4.8185 15.6756 5.05331 15.8907 5.33278 15.8907C5.64165 15.8907 5.88456 15.6335 5.86561 15.3307Z" fill="#999999"/>
|
||||||
|
<path d="M7.99989 6.32812C7.70534 6.32812 7.46655 6.56423 7.46655 6.85547V15.3633C7.46655 15.6545 7.70534 15.8906 7.99989 15.8906C8.29443 15.8906 8.53322 15.6545 8.53322 15.3633V6.85547C8.53322 6.56423 8.29443 6.32812 7.99989 6.32812Z" fill="#999999"/>
|
||||||
|
<path d="M11.233 6.32915C10.9396 6.31112 10.6859 6.53215 10.6677 6.82285L10.1343 15.3307C10.1162 15.6213 10.3397 15.8716 10.6337 15.8896C10.9278 15.9076 11.1808 15.6865 11.199 15.3959L11.7323 6.8881C11.7505 6.5974 11.527 6.34715 11.233 6.32915Z" fill="#999999"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
17
assets/icons/scenesPlayIcon.svg
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_6675_32326)">
|
||||||
|
<path d="M18 3C9.71584 3 3 9.71572 3 18C3 26.2843 9.71584 33 18 33C26.2842 33 33 26.2843 33 18C33 9.71572 26.2842 3 18 3ZM23.1844 18.7951L15.6844 23.4826C15.5326 23.5774 15.3601 23.625 15.1875 23.625C15.0312 23.625 14.8746 23.5861 14.7329 23.5073C14.4349 23.3421 14.25 23.0285 14.25 22.6875V13.3125C14.25 12.9715 14.4349 12.6579 14.7329 12.4927C15.0309 12.3265 15.3953 12.3366 15.6844 12.5174L23.1844 17.2049C23.4584 17.3766 23.625 17.6769 23.625 18C23.625 18.3231 23.4584 18.6235 23.1844 18.7951Z" fill="#F4F4F4"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_6675_32326" x="0" y="0" width="36" height="36" 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.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6675_32326"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6675_32326" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
30
assets/icons/scenesPlayIconCheck.svg
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_7280_5211)">
|
||||||
|
<circle cx="18" cy="18" r="15" fill="#F4F4F4"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter1_i_7280_5211)">
|
||||||
|
<path d="M25.1663 13.187C24.8231 12.8439 24.2666 12.8439 23.9234 13.1871L16.1621 20.9484L12.0766 16.8628C11.7334 16.5196 11.1768 16.5196 10.8336 16.8628C10.4904 17.206 10.4904 17.7625 10.8336 18.1057L15.5406 22.8127C15.7122 22.9844 15.9372 23.0701 16.1621 23.0701C16.3869 23.0701 16.6119 22.9843 16.7835 22.8127L25.1663 14.43C25.5095 14.0868 25.5095 13.5303 25.1663 13.187Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_7280_5211" x="0" y="0" width="36" height="36" 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.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_7280_5211"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_7280_5211" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter1_i_7280_5211" x="10.5762" y="12.9297" width="14.8475" height="10.1406" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="1.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_7280_5211"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
25
assets/icons/space_link_icon.svg
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_6702_36714)">
|
||||||
|
<circle cx="20" cy="20" r="15" fill="#F4F4F4"/>
|
||||||
|
<path d="M21.1979 12.3395L18.26 15.2772C17.7228 15.8146 17.3477 16.4536 17.1345 17.1328C16.437 17.3525 15.798 17.7393 15.2772 18.26L12.3395 21.1979C10.5536 22.9837 10.5534 25.8744 12.3395 27.6605C14.1253 29.4464 17.0161 29.4466 18.8022 27.6605L21.7399 24.7227C22.2773 24.1855 22.6522 23.5465 22.8655 22.8671C23.5631 22.6475 24.202 22.2607 24.7227 21.7399L27.6605 18.8022C29.4464 17.0162 29.4467 14.1256 27.6605 12.3395C25.8746 10.5536 22.984 10.5534 21.1979 12.3395ZM17.266 20.2484C17.4886 20.7914 17.8199 21.2998 18.26 21.7399C18.6877 22.1674 19.1965 22.5054 19.7513 22.7343L16.8137 25.6721C16.1284 26.3572 15.0133 26.3574 14.328 25.6721C13.6427 24.9867 13.6427 23.8717 14.328 23.1864L17.2657 20.2485C17.2659 20.2485 17.2659 20.2485 17.266 20.2484ZM21.2428 24.2256L18.3049 27.1633C16.7939 28.6745 14.3479 28.6747 12.8366 27.1633C11.3254 25.6523 11.3253 23.2062 12.8366 21.695L15.7744 18.7571C16.1166 18.4149 16.5191 18.1412 16.9579 17.9488C16.8924 18.4845 16.9223 19.014 17.0364 19.5199C16.9419 19.5905 16.8524 19.6676 16.7686 19.7514L13.8309 22.6892C12.8715 23.6487 12.8715 25.2097 13.8309 26.1691C14.7903 27.1285 16.3513 27.1285 17.3108 26.1691L20.2485 23.2313C21.2089 22.2709 21.209 20.7119 20.2485 19.7514C19.7355 19.2383 19.6105 18.4924 19.8554 17.8663C20.3734 18.059 20.8488 18.3631 21.2428 18.7571C22.7504 20.2647 22.7505 22.7179 21.2428 24.2256ZM27.1633 18.3049L24.2256 21.2428C23.8834 21.585 23.4809 21.8587 23.0421 22.0511C23.1076 21.5154 23.0777 20.986 22.9637 20.4801C23.058 20.4095 23.1477 20.3323 23.2313 20.2485L26.1692 17.3108C27.1286 16.3514 27.1286 14.7903 26.1692 13.8309C25.3077 12.9695 23.9604 12.8807 22.9987 13.5684C22.8408 13.6813 22.8044 13.9009 22.9173 14.0588C23.0301 14.2168 23.2497 14.2533 23.4077 14.1403C24.1093 13.6386 25.0615 13.7174 25.6721 14.328C26.3574 15.0133 26.3574 16.1283 25.6721 16.8137L22.7342 19.7514C22.7342 19.7514 22.7342 19.7514 22.7341 19.7515C22.5113 19.2085 22.1801 18.7002 21.7399 18.26C21.3124 17.8325 20.8035 17.4945 20.2487 17.2656L21.4465 16.0678C21.5837 15.9306 21.5837 15.708 21.4465 15.5707C21.3091 15.4335 21.0867 15.4335 20.9493 15.5707L19.7514 16.7686C18.7911 17.729 18.7909 19.2879 19.7514 20.2485C20.2645 20.7615 20.3894 21.5076 20.1446 22.1337C19.6266 21.941 19.1511 21.6368 18.7571 21.2427C17.2497 19.7352 17.2495 17.282 18.7571 15.7744L21.695 12.8366C23.2061 11.3254 25.6522 11.3252 27.1633 12.8366C28.6745 14.3476 28.6747 16.7937 27.1633 18.3049Z" fill="#999999"/>
|
||||||
|
<path d="M22.5443 14.8262C22.5443 15.0204 22.3869 15.1777 22.1929 15.1777C21.9987 15.1777 21.8413 15.0204 21.8413 14.8262C21.8413 14.632 21.9987 14.4746 22.1929 14.4746C22.3869 14.4746 22.5443 14.632 22.5443 14.8262Z" fill="#999999"/>
|
||||||
|
<path d="M15.7755 15.774C15.9128 15.6368 15.9128 15.4142 15.7755 15.2769L14.2841 13.7855C14.1468 13.6483 13.9243 13.6483 13.787 13.7855C13.6498 13.9228 13.6498 14.1455 13.787 14.2828L15.2784 15.7742C15.4158 15.9114 15.6383 15.9114 15.7755 15.774Z" fill="#999999"/>
|
||||||
|
<path d="M12.3378 16.9062C12.1437 16.9062 11.9863 17.0636 11.9863 17.2577C11.9863 17.4519 12.1437 17.6092 12.3378 17.6092H14.447C14.641 17.6092 14.7984 17.4519 14.7984 17.2577C14.7984 17.0636 14.641 16.9062 14.447 16.9062H12.3378Z" fill="#999999"/>
|
||||||
|
<path d="M16.9062 12.2314V14.3405C16.9062 14.5346 17.0636 14.6921 17.2577 14.6921C17.4519 14.6921 17.6092 14.5346 17.6092 14.3405V12.2314C17.6092 12.0373 17.4519 11.8799 17.2577 11.8799C17.0636 11.8799 16.9062 12.0373 16.9062 12.2314Z" fill="#999999"/>
|
||||||
|
<path d="M24.227 24.2259C24.0897 24.3631 24.0897 24.5857 24.227 24.7231L25.7184 26.2145C25.7871 26.2831 25.877 26.3175 25.967 26.3175C26.2772 26.3175 26.4377 25.9397 26.2155 25.7173L24.7242 24.2259C24.5868 24.0887 24.3643 24.0887 24.227 24.2259Z" fill="#999999"/>
|
||||||
|
<path d="M23.0605 27.7673V25.6581C23.0605 25.464 22.903 25.3066 22.709 25.3066C22.5148 25.3066 22.3574 25.464 22.3574 25.6581V27.7673C22.3574 27.9614 22.5148 28.1187 22.709 28.1187C22.903 28.1187 23.0605 27.9614 23.0605 27.7673Z" fill="#999999"/>
|
||||||
|
<path d="M27.7693 23.0586C27.9633 23.0586 28.1207 22.9011 28.1207 22.707C28.1207 22.5128 27.9633 22.3555 27.7693 22.3555H25.66C25.466 22.3555 25.3086 22.5128 25.3086 22.707C25.3086 22.9011 25.466 23.0586 25.66 23.0586H27.7693Z" fill="#999999"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_6702_36714" x="0" y="0" width="40" height="40" 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="2.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6702_36714"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6702_36714" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
4
assets/icons/spaseLocationIcon.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="15" height="14" viewBox="0 0 15 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.13597 13.8173C7.21711 13.9314 7.35373 14 7.5 14C7.64627 14 7.78289 13.9315 7.86403 13.8173C8.89942 12.3614 10.4245 10.5632 11.4872 8.73444C12.3369 7.27221 12.75 6.02509 12.75 4.92188C12.75 2.20795 10.3948 0 7.5 0C4.60515 0 2.25 2.20795 2.25 4.92188C2.25 6.02509 2.66309 7.27221 3.51283 8.73444C4.57476 10.5618 6.10271 12.3644 7.13597 13.8173ZM7.5 0.820312C9.91237 0.820312 11.875 2.66027 11.875 4.92188C11.875 5.88448 11.4968 7.00323 10.7188 8.342C9.80277 9.91834 8.49557 11.5174 7.5 12.8617C6.50457 11.5176 5.19729 9.91843 4.2812 8.342C3.5032 7.00323 3.125 5.88448 3.125 4.92188C3.125 2.66027 5.08763 0.820312 7.5 0.820312Z" fill="#999999"/>
|
||||||
|
<path d="M7.5 7.38281C8.94742 7.38281 10.125 6.27884 10.125 4.92188C10.125 3.56491 8.94742 2.46094 7.5 2.46094C6.05257 2.46094 4.875 3.56491 4.875 4.92188C4.875 6.27884 6.05257 7.38281 7.5 7.38281ZM7.5 3.28125C8.46495 3.28125 9.25 4.01723 9.25 4.92188C9.25 5.82652 8.46495 6.5625 7.5 6.5625C6.53505 6.5625 5.75 5.82652 5.75 4.92188C5.75 4.01723 6.53505 3.28125 7.5 3.28125Z" fill="#999999"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
3
assets/icons/success_icon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M43.2614 20.4808C44.1769 21.3963 44.1769 22.8804 43.2614 23.7955L27.5381 39.5192C26.6226 40.4343 25.139 40.4343 24.2235 39.5192L16.7386 32.0338C15.8231 31.1188 15.8231 29.6347 16.7386 28.7196C17.6537 27.8041 19.1377 27.8041 20.0528 28.7196L25.8806 34.5474L39.9467 20.4808C40.8623 19.5657 42.3463 19.5657 43.2614 20.4808ZM60 30C60 46.5825 46.5802 60 30 60C13.4175 60 0 46.5802 0 30C0 13.4175 13.4198 0 30 0C46.5825 0 60 13.4198 60 30ZM55.3125 30C55.3125 16.0085 43.9897 4.6875 30 4.6875C16.0085 4.6875 4.6875 16.0103 4.6875 30C4.6875 43.9915 16.0103 55.3125 30 55.3125C43.9915 55.3125 55.3125 43.9897 55.3125 30Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 761 B |
21
assets/images/delete_space_link_icon.svg
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_6702_36698)">
|
||||||
|
<circle cx="20" cy="20" r="15" fill="#F4F4F4"/>
|
||||||
|
<path d="M26.4 13.1094H23.7333V12.582C23.7333 11.7097 23.0156 11 22.1333 11H17.8667C16.9844 11 16.2667 11.7097 16.2667 12.582V13.1094H13.6C12.7178 13.1094 12 13.8191 12 14.6914C12 15.392 12.4631 15.9873 13.1024 16.1947L14.0537 27.5493C14.1222 28.3628 14.8226 29 15.6481 29H24.3519C25.1775 29 25.8778 28.3628 25.9464 27.5491L26.8976 16.1947C27.5369 15.9873 28 15.392 28 14.6914C28 13.8191 27.2822 13.1094 26.4 13.1094ZM17.3333 12.582C17.3333 12.2913 17.5726 12.0547 17.8667 12.0547H22.1333C22.4274 12.0547 22.6667 12.2913 22.6667 12.582V13.1094H17.3333V12.582ZM24.8833 27.4618C24.8605 27.7329 24.6271 27.9453 24.3519 27.9453H15.6481C15.373 27.9453 15.1395 27.7329 15.1167 27.462L14.1793 16.2734H25.8207L24.8833 27.4618ZM26.4 15.2188H13.6C13.3059 15.2188 13.0667 14.9822 13.0667 14.6914C13.0667 14.4006 13.3059 14.1641 13.6 14.1641H26.4C26.6941 14.1641 26.9333 14.4006 26.9333 14.6914C26.9333 14.9822 26.6941 15.2188 26.4 15.2188Z" fill="#999999"/>
|
||||||
|
<path d="M17.8656 26.3307L17.3323 17.8229C17.314 17.5322 17.0596 17.3111 16.767 17.3292C16.473 17.3472 16.2494 17.5974 16.2676 17.8881L16.801 26.396C16.8185 26.6756 17.0533 26.8907 17.3328 26.8907C17.6416 26.8907 17.8846 26.6335 17.8656 26.3307Z" fill="#999999"/>
|
||||||
|
<path d="M20.0001 17.3281C19.7056 17.3281 19.4668 17.5642 19.4668 17.8555V26.3633C19.4668 26.6545 19.7056 26.8906 20.0001 26.8906C20.2947 26.8906 20.5335 26.6545 20.5335 26.3633V17.8555C20.5335 17.5642 20.2947 17.3281 20.0001 17.3281Z" fill="#999999"/>
|
||||||
|
<path d="M23.233 17.3292C22.9396 17.3111 22.6859 17.5321 22.6677 17.8229L22.1343 26.3307C22.1162 26.6213 22.3397 26.8716 22.6337 26.8896C22.9278 26.9076 23.1808 26.6865 23.199 26.3959L23.7323 17.8881C23.7505 17.5974 23.527 17.3472 23.233 17.3292Z" fill="#999999"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_6702_36698" x="0" y="0" width="40" height="40" 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="2.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6702_36698"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6702_36698" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
25
assets/images/space_link_icon.svg
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_6702_36714)">
|
||||||
|
<circle cx="20" cy="20" r="15" fill="#F4F4F4"/>
|
||||||
|
<path d="M21.1979 12.3395L18.26 15.2772C17.7228 15.8146 17.3477 16.4536 17.1345 17.1328C16.437 17.3525 15.798 17.7393 15.2772 18.26L12.3395 21.1979C10.5536 22.9837 10.5534 25.8744 12.3395 27.6605C14.1253 29.4464 17.0161 29.4466 18.8022 27.6605L21.7399 24.7227C22.2773 24.1855 22.6522 23.5465 22.8655 22.8671C23.5631 22.6475 24.202 22.2607 24.7227 21.7399L27.6605 18.8022C29.4464 17.0162 29.4467 14.1256 27.6605 12.3395C25.8746 10.5536 22.984 10.5534 21.1979 12.3395ZM17.266 20.2484C17.4886 20.7914 17.8199 21.2998 18.26 21.7399C18.6877 22.1674 19.1965 22.5054 19.7513 22.7343L16.8137 25.6721C16.1284 26.3572 15.0133 26.3574 14.328 25.6721C13.6427 24.9867 13.6427 23.8717 14.328 23.1864L17.2657 20.2485C17.2659 20.2485 17.2659 20.2485 17.266 20.2484ZM21.2428 24.2256L18.3049 27.1633C16.7939 28.6745 14.3479 28.6747 12.8366 27.1633C11.3254 25.6523 11.3253 23.2062 12.8366 21.695L15.7744 18.7571C16.1166 18.4149 16.5191 18.1412 16.9579 17.9488C16.8924 18.4845 16.9223 19.014 17.0364 19.5199C16.9419 19.5905 16.8524 19.6676 16.7686 19.7514L13.8309 22.6892C12.8715 23.6487 12.8715 25.2097 13.8309 26.1691C14.7903 27.1285 16.3513 27.1285 17.3108 26.1691L20.2485 23.2313C21.2089 22.2709 21.209 20.7119 20.2485 19.7514C19.7355 19.2383 19.6105 18.4924 19.8554 17.8663C20.3734 18.059 20.8488 18.3631 21.2428 18.7571C22.7504 20.2647 22.7505 22.7179 21.2428 24.2256ZM27.1633 18.3049L24.2256 21.2428C23.8834 21.585 23.4809 21.8587 23.0421 22.0511C23.1076 21.5154 23.0777 20.986 22.9637 20.4801C23.058 20.4095 23.1477 20.3323 23.2313 20.2485L26.1692 17.3108C27.1286 16.3514 27.1286 14.7903 26.1692 13.8309C25.3077 12.9695 23.9604 12.8807 22.9987 13.5684C22.8408 13.6813 22.8044 13.9009 22.9173 14.0588C23.0301 14.2168 23.2497 14.2533 23.4077 14.1403C24.1093 13.6386 25.0615 13.7174 25.6721 14.328C26.3574 15.0133 26.3574 16.1283 25.6721 16.8137L22.7342 19.7514C22.7342 19.7514 22.7342 19.7514 22.7341 19.7515C22.5113 19.2085 22.1801 18.7002 21.7399 18.26C21.3124 17.8325 20.8035 17.4945 20.2487 17.2656L21.4465 16.0678C21.5837 15.9306 21.5837 15.708 21.4465 15.5707C21.3091 15.4335 21.0867 15.4335 20.9493 15.5707L19.7514 16.7686C18.7911 17.729 18.7909 19.2879 19.7514 20.2485C20.2645 20.7615 20.3894 21.5076 20.1446 22.1337C19.6266 21.941 19.1511 21.6368 18.7571 21.2427C17.2497 19.7352 17.2495 17.282 18.7571 15.7744L21.695 12.8366C23.2061 11.3254 25.6522 11.3252 27.1633 12.8366C28.6745 14.3476 28.6747 16.7937 27.1633 18.3049Z" fill="#999999"/>
|
||||||
|
<path d="M22.5443 14.8262C22.5443 15.0204 22.3869 15.1777 22.1929 15.1777C21.9987 15.1777 21.8413 15.0204 21.8413 14.8262C21.8413 14.632 21.9987 14.4746 22.1929 14.4746C22.3869 14.4746 22.5443 14.632 22.5443 14.8262Z" fill="#999999"/>
|
||||||
|
<path d="M15.7755 15.774C15.9128 15.6368 15.9128 15.4142 15.7755 15.2769L14.2841 13.7855C14.1468 13.6483 13.9243 13.6483 13.787 13.7855C13.6498 13.9228 13.6498 14.1455 13.787 14.2828L15.2784 15.7742C15.4158 15.9114 15.6383 15.9114 15.7755 15.774Z" fill="#999999"/>
|
||||||
|
<path d="M12.3378 16.9062C12.1437 16.9062 11.9863 17.0636 11.9863 17.2577C11.9863 17.4519 12.1437 17.6092 12.3378 17.6092H14.447C14.641 17.6092 14.7984 17.4519 14.7984 17.2577C14.7984 17.0636 14.641 16.9062 14.447 16.9062H12.3378Z" fill="#999999"/>
|
||||||
|
<path d="M16.9062 12.2314V14.3405C16.9062 14.5346 17.0636 14.6921 17.2577 14.6921C17.4519 14.6921 17.6092 14.5346 17.6092 14.3405V12.2314C17.6092 12.0373 17.4519 11.8799 17.2577 11.8799C17.0636 11.8799 16.9062 12.0373 16.9062 12.2314Z" fill="#999999"/>
|
||||||
|
<path d="M24.227 24.2259C24.0897 24.3631 24.0897 24.5857 24.227 24.7231L25.7184 26.2145C25.7871 26.2831 25.877 26.3175 25.967 26.3175C26.2772 26.3175 26.4377 25.9397 26.2155 25.7173L24.7242 24.2259C24.5868 24.0887 24.3643 24.0887 24.227 24.2259Z" fill="#999999"/>
|
||||||
|
<path d="M23.0605 27.7673V25.6581C23.0605 25.464 22.903 25.3066 22.709 25.3066C22.5148 25.3066 22.3574 25.464 22.3574 25.6581V27.7673C22.3574 27.9614 22.5148 28.1187 22.709 28.1187C22.903 28.1187 23.0605 27.9614 23.0605 27.7673Z" fill="#999999"/>
|
||||||
|
<path d="M27.7693 23.0586C27.9633 23.0586 28.1207 22.9011 28.1207 22.707C28.1207 22.5128 27.9633 22.3555 27.7693 22.3555H25.66C25.466 22.3555 25.3086 22.5128 25.3086 22.707C25.3086 22.9011 25.466 23.0586 25.66 23.0586H27.7693Z" fill="#999999"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_6702_36714" x="0" y="0" width="40" height="40" 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="2.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6702_36714"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6702_36714" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
3
assets/images/success_icon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M43.2614 20.4808C44.1769 21.3963 44.1769 22.8804 43.2614 23.7955L27.5381 39.5192C26.6226 40.4343 25.139 40.4343 24.2235 39.5192L16.7386 32.0338C15.8231 31.1188 15.8231 29.6347 16.7386 28.7196C17.6537 27.8041 19.1377 27.8041 20.0528 28.7196L25.8806 34.5474L39.9467 20.4808C40.8623 19.5657 42.3463 19.5657 43.2614 20.4808ZM60 30C60 46.5825 46.5802 60 30 60C13.4175 60 0 46.5802 0 30C0 13.4175 13.4198 0 30 0C46.5825 0 60 13.4198 60 30ZM55.3125 30C55.3125 16.0085 43.9897 4.6875 30 4.6875C16.0085 4.6875 4.6875 16.0103 4.6875 30C4.6875 43.9915 16.0103 55.3125 30 55.3125C43.9915 55.3125 55.3125 43.9897 55.3125 30Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 761 B |
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>
|
@ -1,160 +0,0 @@
|
|||||||
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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
185
lib/common/tag_dialog_textfield_dropdown.dart
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class TagDialogTextfieldDropdown extends StatefulWidget {
|
||||||
|
final List<Tag> items;
|
||||||
|
final ValueChanged<Tag> onSelected;
|
||||||
|
final Tag? initialValue;
|
||||||
|
final String product;
|
||||||
|
|
||||||
|
const TagDialogTextfieldDropdown({
|
||||||
|
Key? key,
|
||||||
|
required this.items,
|
||||||
|
required this.onSelected,
|
||||||
|
this.initialValue,
|
||||||
|
required this.product,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_DialogTextfieldDropdownState createState() => _DialogTextfieldDropdownState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DialogTextfieldDropdownState extends State<TagDialogTextfieldDropdown> {
|
||||||
|
bool _isOpen = false;
|
||||||
|
OverlayEntry? _overlayEntry;
|
||||||
|
final TextEditingController _controller = TextEditingController();
|
||||||
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
List<Tag> _filteredItems = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller.text = widget.initialValue?.tag ?? '';
|
||||||
|
|
||||||
|
_filterItems();
|
||||||
|
|
||||||
|
_focusNode.addListener(() {
|
||||||
|
if (!_focusNode.hasFocus) {
|
||||||
|
_closeDropdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _filterItems() {
|
||||||
|
setState(() {
|
||||||
|
_filteredItems = widget.items.where((tag) => tag.product?.uuid == widget.product).toList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _toggleDropdown() {
|
||||||
|
if (_isOpen) {
|
||||||
|
_closeDropdown();
|
||||||
|
} else {
|
||||||
|
_openDropdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _openDropdown() {
|
||||||
|
_overlayEntry = _createOverlayEntry();
|
||||||
|
Overlay.of(context).insert(_overlayEntry!);
|
||||||
|
_isOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _closeDropdown() {
|
||||||
|
if (_isOpen && _overlayEntry != null) {
|
||||||
|
_overlayEntry!.remove();
|
||||||
|
_overlayEntry = null;
|
||||||
|
_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: StatefulBuilder(
|
||||||
|
builder: (context, setStateDropdown) {
|
||||||
|
return ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: _filteredItems.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final tag = _filteredItems[index];
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: ColorsManager.lightGrayBorderColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(tag.tag ?? '',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(color: ColorsManager.textPrimaryColor)),
|
||||||
|
onTap: () {
|
||||||
|
_controller.text = tag.tag ?? '';
|
||||||
|
widget.onSelected(tag);
|
||||||
|
setState(() {
|
||||||
|
_filteredItems.remove(tag);
|
||||||
|
});
|
||||||
|
_closeDropdown();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
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,
|
||||||
|
focusNode: _focusNode,
|
||||||
|
onFieldSubmitted: (value) {
|
||||||
|
final selectedTag = _filteredItems.firstWhere((tag) => tag.tag == value,
|
||||||
|
orElse: () => Tag(tag: value));
|
||||||
|
widget.onSelected(selectedTag);
|
||||||
|
_closeDropdown();
|
||||||
|
},
|
||||||
|
onTapOutside: (event) {
|
||||||
|
widget.onSelected(_filteredItems.firstWhere((tag) => tag.tag == _controller.text,
|
||||||
|
orElse: () => Tag(tag: _controller.text)));
|
||||||
|
_closeDropdown();
|
||||||
|
},
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: 'Enter or Select a tag',
|
||||||
|
border: InputBorder.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: _toggleDropdown,
|
||||||
|
child: const Icon(Icons.arrow_drop_down),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -56,24 +56,6 @@ class CustomExpansionTileState extends State<CustomExpansionTile> {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
// Checkbox with independent state management
|
|
||||||
Checkbox(
|
|
||||||
value: false,
|
|
||||||
onChanged: (bool? value) {
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
side: WidgetStateBorderSide.resolveWith((states) {
|
|
||||||
return const BorderSide(color: ColorsManager.grayBorder);
|
|
||||||
}),
|
|
||||||
fillColor: WidgetStateProperty.resolveWith((states) {
|
|
||||||
if (states.contains(WidgetState.selected)) {
|
|
||||||
return ColorsManager.grayBorder;
|
|
||||||
} else {
|
|
||||||
return ColorsManager.checkBoxFillColor;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
checkColor: ColorsManager.whiteColors,
|
|
||||||
),
|
|
||||||
// Expand/collapse icon, now wrapped in a GestureDetector for specific onTap
|
// Expand/collapse icon, now wrapped in a GestureDetector for specific onTap
|
||||||
if (widget.children != null && widget.children!.isNotEmpty)
|
if (widget.children != null && widget.children!.isNotEmpty)
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
@ -84,7 +66,9 @@ class CustomExpansionTileState extends State<CustomExpansionTile> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
_isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right,
|
_isExpanded
|
||||||
|
? Icons.keyboard_arrow_down
|
||||||
|
: Icons.keyboard_arrow_right,
|
||||||
color: ColorsManager.lightGrayColor,
|
color: ColorsManager.lightGrayColor,
|
||||||
size: 16.0, // Adjusted size for better alignment
|
size: 16.0, // Adjusted size for better alignment
|
||||||
),
|
),
|
||||||
@ -101,8 +85,10 @@ class CustomExpansionTileState extends State<CustomExpansionTile> {
|
|||||||
_capitalizeFirstLetter(widget.title),
|
_capitalizeFirstLetter(widget.title),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: widget.isSelected
|
color: widget.isSelected
|
||||||
? ColorsManager.blackColor // Change color to black when selected
|
? ColorsManager
|
||||||
: ColorsManager.lightGrayColor, // Gray when not selected
|
.blackColor // Change color to black when selected
|
||||||
|
: ColorsManager
|
||||||
|
.lightGrayColor, // Gray when not selected
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -111,9 +97,11 @@ class CustomExpansionTileState extends State<CustomExpansionTile> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
// The expanded section (children) that shows when the tile is expanded
|
// The expanded section (children) that shows when the tile is expanded
|
||||||
if (_isExpanded && widget.children != null && widget.children!.isNotEmpty)
|
if (_isExpanded &&
|
||||||
|
widget.children != null &&
|
||||||
|
widget.children!.isNotEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 48.0), // Indented children
|
padding: const EdgeInsets.only(left: 24.0), // Indented children
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: widget.children!,
|
children: widget.children!,
|
@ -3,18 +3,33 @@ import 'package:flutter_svg/svg.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';
|
||||||
|
|
||||||
class CustomSearchBar extends StatelessWidget {
|
class CustomSearchBar extends StatefulWidget {
|
||||||
final TextEditingController? controller;
|
final TextEditingController? controller;
|
||||||
final String hintText;
|
final String hintText;
|
||||||
|
final String? searchQuery;
|
||||||
final Function(String)? onSearchChanged; // Callback for search input changes
|
final Function(String)? onSearchChanged; // Callback for search input changes
|
||||||
|
|
||||||
const CustomSearchBar({
|
const CustomSearchBar({
|
||||||
super.key,
|
super.key,
|
||||||
this.controller,
|
this.controller,
|
||||||
|
this.searchQuery = '',
|
||||||
this.hintText = 'Search',
|
this.hintText = 'Search',
|
||||||
this.onSearchChanged,
|
this.onSearchChanged,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CustomSearchBar> createState() => _CustomSearchBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomSearchBarState extends State<CustomSearchBar> {
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
if (widget.controller != null) {
|
||||||
|
widget.controller!.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -36,20 +51,20 @@ class CustomSearchBar extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: TextField(
|
child: TextFormField(
|
||||||
controller: controller,
|
controller: widget.controller,
|
||||||
|
initialValue: widget.searchQuery,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
onChanged: onSearchChanged, // Call the callback on text change
|
onChanged: widget.onSearchChanged, // Call the callback on text change
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: ColorsManager.textFieldGreyColor,
|
fillColor: ColorsManager.textFieldGreyColor,
|
||||||
hintText: hintText,
|
hintText: widget.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,
|
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,33 +1,40 @@
|
|||||||
|
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_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/create_routine_bloc/create_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';
|
||||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||||
|
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||||
import 'package:syncrow_web/utils/theme/theme.dart';
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
MyApp({
|
MyApp({super.key});
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final GoRouter _router = GoRouter(
|
final GoRouter _router = GoRouter(
|
||||||
initialLocation: RoutesConst.auth,
|
initialLocation: RoutesConst.auth,
|
||||||
@ -48,6 +55,9 @@ class MyApp extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
BlocProvider<CreateRoutineBloc>(
|
||||||
|
create: (context) => CreateRoutineBloc(),
|
||||||
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
||||||
BlocProvider<VisitorPasswordBloc>(
|
BlocProvider<VisitorPasswordBloc>(
|
||||||
@ -56,6 +66,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,
|
||||||
@ -67,6 +80,8 @@ class MyApp extends StatelessWidget {
|
|||||||
PointerDeviceKind.unknown,
|
PointerDeviceKind.unknown,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
key: NavigationService.navigatorKey,
|
||||||
|
// scaffoldMessengerKey: NavigationService.snackbarKey,
|
||||||
theme: myTheme,
|
theme: myTheme,
|
||||||
routerConfig: _router,
|
routerConfig: _router,
|
||||||
));
|
));
|
||||||
|
88
lib/main_dev.dart
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
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/create_routine_bloc/create_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/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<CreateRoutineBloc>(
|
||||||
|
create: (context) => CreateRoutineBloc(),
|
||||||
|
),
|
||||||
|
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,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
|
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
|
import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
|
||||||
import 'package:syncrow_web/services/access_mang_api.dart';
|
import 'package:syncrow_web/services/access_mang_api.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
@ -30,8 +31,9 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
|||||||
Future<void> _onFetchTableData(
|
Future<void> _onFetchTableData(
|
||||||
FetchTableData event, Emitter<AccessState> emit) async {
|
FetchTableData event, Emitter<AccessState> emit) async {
|
||||||
try {
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
emit(AccessLoaded());
|
emit(AccessLoaded());
|
||||||
data = await AccessMangApi().fetchVisitorPassword();
|
data = await AccessMangApi().fetchVisitorPassword(projectUuid);
|
||||||
filteredData = data;
|
filteredData = data;
|
||||||
updateTabsCount();
|
updateTabsCount();
|
||||||
emit(TableLoaded(data));
|
emit(TableLoaded(data));
|
||||||
|
@ -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));
|
||||||
|
@ -9,6 +9,9 @@ import 'package:syncrow_web/pages/auth/model/login_with_email_model.dart';
|
|||||||
import 'package:syncrow_web/pages/auth/model/region_model.dart';
|
import 'package:syncrow_web/pages/auth/model/region_model.dart';
|
||||||
import 'package:syncrow_web/pages/auth/model/token.dart';
|
import 'package:syncrow_web/pages/auth/model/token.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/common/bloc/project_manager.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/services/auth_api.dart';
|
import 'package:syncrow_web/services/auth_api.dart';
|
||||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
@ -161,8 +164,14 @@ 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;
|
||||||
}
|
}
|
||||||
@ -176,7 +185,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
user = UserModel.fromToken(token);
|
user = UserModel.fromToken(token);
|
||||||
loginEmailController.clear();
|
loginEmailController.clear();
|
||||||
loginPasswordController.clear();
|
loginPasswordController.clear();
|
||||||
debugPrint("token " + token.accessToken);
|
|
||||||
emit(LoginSuccess());
|
emit(LoginSuccess());
|
||||||
} else {
|
} else {
|
||||||
emit(const LoginFailure(error: 'Something went wrong'));
|
emit(const LoginFailure(error: 'Something went wrong'));
|
||||||
@ -423,8 +431,10 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
emit(LoginInitial());
|
emit(LoginInitial());
|
||||||
}
|
}
|
||||||
|
|
||||||
static logout() {
|
static Future<void> logout(BuildContext context) async {
|
||||||
const storage = FlutterSecureStorage();
|
final storage = FlutterSecureStorage();
|
||||||
|
ProjectManager.clearProjectUUID();
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearAllData());
|
||||||
storage.deleteAll();
|
storage.deleteAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
27
lib/pages/auth/model/project_model.dart
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
class Project {
|
||||||
|
final String uuid;
|
||||||
|
final String name;
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
const Project({
|
||||||
|
required this.uuid,
|
||||||
|
required this.name,
|
||||||
|
required this.description,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Project.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Project(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
name: json['name'] as String,
|
||||||
|
description: json['description'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'name': name,
|
||||||
|
'description': description,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:syncrow_web/pages/auth/model/project_model.dart';
|
||||||
import 'package:syncrow_web/pages/auth/model/token.dart';
|
import 'package:syncrow_web/pages/auth/model/token.dart';
|
||||||
|
|
||||||
class UserModel {
|
class UserModel {
|
||||||
@ -10,6 +11,11 @@ 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;
|
||||||
|
final Project? project;
|
||||||
|
|
||||||
UserModel({
|
UserModel({
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
required this.email,
|
required this.email,
|
||||||
@ -19,6 +25,10 @@ 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,
|
||||||
|
required this.project,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory UserModel.fromJson(Map<String, dynamic> json) {
|
factory UserModel.fromJson(Map<String, dynamic> json) {
|
||||||
@ -31,6 +41,13 @@ 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,
|
||||||
|
project:
|
||||||
|
json['project'] != null ? Project.fromJson(json['project']) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +58,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,
|
||||||
@ -49,6 +69,7 @@ class UserModel {
|
|||||||
phoneNumber: null,
|
phoneNumber: null,
|
||||||
isEmailVerified: null,
|
isEmailVerified: null,
|
||||||
isAgreementAccepted: null,
|
isAgreementAccepted: null,
|
||||||
|
project: null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,3 +86,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
lib/pages/common/bloc/project_manager.dart
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
|
|
||||||
|
class ProjectManager {
|
||||||
|
static Future<String?> getProjectUUID() async {
|
||||||
|
final projectUuid = await SharedPreferencesHelper.readStringFromSP(
|
||||||
|
StringsManager.projectKey);
|
||||||
|
return projectUuid.isNotEmpty ? projectUuid : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> setProjectUUID(String newUUID) async {
|
||||||
|
await SharedPreferencesHelper.saveStringToSP(
|
||||||
|
StringsManager.projectKey, newUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> clearProjectUUID() async {
|
||||||
|
await SharedPreferencesHelper.removeValueFromSP(StringsManager.projectKey);
|
||||||
|
}
|
||||||
|
}
|
@ -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,6 +1,9 @@
|
|||||||
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/common/bloc/project_manager.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';
|
||||||
@ -34,7 +37,24 @@ class DeviceManagementBloc
|
|||||||
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>();
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
|
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
||||||
|
devices = await DevicesManagementApi().fetchDevices('', '', projectUuid);
|
||||||
|
} 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, projectUuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_selectedDevices.clear();
|
_selectedDevices.clear();
|
||||||
_devices = devices;
|
_devices = devices;
|
||||||
_filteredDevices = devices;
|
_filteredDevices = devices;
|
||||||
@ -288,8 +308,8 @@ class DeviceManagementBloc
|
|||||||
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()
|
.toLowerCase()
|
||||||
.contains(event.unitName!.toLowerCase()));
|
.contains(event.unitName!.toLowerCase()));
|
||||||
final matchesProductName = event.productName == null ||
|
final matchesProductName = event.productName == null ||
|
||||||
event.productName!.isEmpty ||
|
event.productName!.isEmpty ||
|
||||||
|
@ -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;
|
||||||
|
@ -3,11 +3,11 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_spa
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_subspace.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';
|
||||||
|
|
||||||
@ -148,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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,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;
|
||||||
@ -247,6 +244,7 @@ SOS
|
|||||||
SwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
SwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
ModeFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
ModeFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
TempSetFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
TempSetFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
|
CurrentTempFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
LevelFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
LevelFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
ChildLockFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
ChildLockFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
];
|
];
|
||||||
@ -254,34 +252,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:
|
||||||
|
@ -3,12 +3,15 @@ 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/create_routine_bloc/create_routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
|
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_event.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/view/routines_view.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/view/create_new_routine_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 +22,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: [
|
||||||
@ -38,15 +41,24 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
backgroundColor: null,
|
backgroundColor: null,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
BlocProvider.of<CreateRoutineBloc>(context)
|
||||||
|
.add(const ResetSelectedEvent());
|
||||||
|
|
||||||
context
|
context
|
||||||
.read<RoutineBloc>()
|
.read<RoutineBloc>()
|
||||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
||||||
|
context
|
||||||
|
.read<DeviceManagementBloc>()
|
||||||
|
.add(FetchDevices(context));
|
||||||
},
|
},
|
||||||
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 +67,21 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
backgroundColor: null,
|
backgroundColor: null,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<RoutineBloc>().add(const TriggerSwitchTabsEvent(isRoutineTab: true));
|
BlocProvider.of<CreateRoutineBloc>(context)
|
||||||
|
.add(const ResetSelectedEvent());
|
||||||
|
|
||||||
|
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 +89,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 +101,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,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -14,81 +14,69 @@ class DeviceSearchFilters extends StatefulWidget {
|
|||||||
|
|
||||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||||
with HelperResponsiveLayout {
|
with HelperResponsiveLayout {
|
||||||
final TextEditingController communityController = TextEditingController();
|
final _unitNameController = TextEditingController();
|
||||||
final TextEditingController unitNameController = TextEditingController();
|
final _productNameController = TextEditingController();
|
||||||
final TextEditingController productNameController = TextEditingController();
|
|
||||||
|
List<Widget> get _widgets => [
|
||||||
|
_buildSearchField("Space Name", _unitNameController, 200),
|
||||||
|
_buildSearchField("Device Name / Product Name", _productNameController, 300),
|
||||||
|
_buildSearchResetButtons(),
|
||||||
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return isExtraLargeScreenSize(context)
|
if (isExtraLargeScreenSize(context)) {
|
||||||
? Row(
|
return Row(
|
||||||
children: [
|
children: _widgets
|
||||||
_buildSearchField("Community", communityController, 200),
|
.map((e) => Padding(padding: const EdgeInsets.all(10), child: e))
|
||||||
const SizedBox(width: 20),
|
.toList(),
|
||||||
_buildSearchField("Space Name", unitNameController, 200),
|
);
|
||||||
const SizedBox(width: 20),
|
}
|
||||||
_buildSearchField(
|
|
||||||
"Device Name / Product Name", productNameController, 300),
|
return Wrap(
|
||||||
const SizedBox(width: 20),
|
|
||||||
_buildSearchResetButtons(),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: Wrap(
|
|
||||||
spacing: 20,
|
spacing: 20,
|
||||||
runSpacing: 10,
|
runSpacing: 10,
|
||||||
children: [
|
children: _widgets,
|
||||||
_buildSearchField(
|
|
||||||
"Community",
|
|
||||||
communityController,
|
|
||||||
200,
|
|
||||||
),
|
|
||||||
_buildSearchField("Space Name", unitNameController, 200),
|
|
||||||
_buildSearchField(
|
|
||||||
"Device Name / Product Name",
|
|
||||||
productNameController,
|
|
||||||
300,
|
|
||||||
),
|
|
||||||
_buildSearchResetButtons(),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSearchField(
|
Widget _buildSearchField(
|
||||||
String title, TextEditingController controller, double width) {
|
String title,
|
||||||
return Container(
|
TextEditingController controller,
|
||||||
child: StatefulTextField(
|
double width,
|
||||||
|
) {
|
||||||
|
return StatefulTextField(
|
||||||
title: title,
|
title: title,
|
||||||
width: width,
|
width: width,
|
||||||
elevation: 2,
|
elevation: 2,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
onSubmitted: () {
|
onSubmitted: () {
|
||||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
final searchDevicesEvent = SearchDevices(
|
||||||
productName: productNameController.text,
|
productName: _productNameController.text,
|
||||||
unitName: unitNameController.text,
|
unitName: _unitNameController.text,
|
||||||
community: communityController.text,
|
searchField: true,
|
||||||
searchField: true));
|
);
|
||||||
|
context.read<DeviceManagementBloc>().add(searchDevicesEvent);
|
||||||
},
|
},
|
||||||
onChanged: (p0) {},
|
onChanged: (p0) {},
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSearchResetButtons() {
|
Widget _buildSearchResetButtons() {
|
||||||
return SearchResetButtons(
|
return SearchResetButtons(
|
||||||
onSearch: () {
|
onSearch: () => context.read<DeviceManagementBloc>().add(
|
||||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
SearchDevices(
|
||||||
community: communityController.text,
|
unitName: _unitNameController.text,
|
||||||
unitName: unitNameController.text,
|
productName: _productNameController.text,
|
||||||
productName: productNameController.text,
|
searchField: true,
|
||||||
searchField: true));
|
),
|
||||||
},
|
),
|
||||||
onReset: () {
|
onReset: () {
|
||||||
communityController.clear();
|
_unitNameController.clear();
|
||||||
unitNameController.clear();
|
_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];
|
||||||
|
}
|
||||||
|
@ -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(event.deviceId);
|
||||||
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, deviceId);
|
||||||
} 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, 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>;
|
||||||
|
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,56 +1,104 @@
|
|||||||
|
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:syncrow_web/pages/auth/model/user_model.dart';
|
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.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/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.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';
|
||||||
|
import 'package:syncrow_web/utils/navigation_service.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 =
|
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
|
||||||
user = await HomeApi().fetchUserInfo(uuid);
|
user = await HomeApi().fetchUserInfo(uuid);
|
||||||
|
|
||||||
|
if (user != null && user!.project != null) {
|
||||||
|
await ProjectManager.setProjectUUID(user!.project!.uuid);
|
||||||
|
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>().add(InitialEvent());
|
||||||
|
}
|
||||||
|
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 =
|
||||||
@ -63,10 +111,11 @@ 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) {
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||||
context.go(RoutesConst.accessManagementPage);
|
context.go(RoutesConst.accessManagementPage);
|
||||||
},
|
},
|
||||||
color: null,
|
color: null,
|
||||||
@ -76,21 +125,24 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
icon: Assets.spaseManagementIcon,
|
icon: Assets.spaseManagementIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||||
context.go(RoutesConst.spacesManagementPage);
|
context.go(RoutesConst.spacesManagementPage);
|
||||||
},
|
},
|
||||||
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) {
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||||
BlocProvider.of<RoutineBloc>(context)
|
BlocProvider.of<RoutineBloc>(context)
|
||||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
||||||
context.go(RoutesConst.deviceManagementPage);
|
context.go(RoutesConst.deviceManagementPage);
|
||||||
},
|
},
|
||||||
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];
|
||||||
|
// }
|
||||||
|
180
lib/pages/home/view/agreement_and_privacy_dialog.dart
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.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/pages/common/bloc/project_manager.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);
|
||||||
|
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,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
@ -219,6 +219,9 @@ class UserSpaceModel {
|
|||||||
final double x;
|
final double x;
|
||||||
final double y;
|
final double y;
|
||||||
final String icon;
|
final String icon;
|
||||||
|
final String communityUuid;
|
||||||
|
|
||||||
|
//communityUuid
|
||||||
|
|
||||||
UserSpaceModel({
|
UserSpaceModel({
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
@ -231,6 +234,7 @@ class UserSpaceModel {
|
|||||||
required this.x,
|
required this.x,
|
||||||
required this.y,
|
required this.y,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
|
required this.communityUuid,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Create a [UserSpaceModel] from JSON data
|
/// Create a [UserSpaceModel] from JSON data
|
||||||
@ -246,7 +250,7 @@ class UserSpaceModel {
|
|||||||
x: (json['x'] as num).toDouble(),
|
x: (json['x'] as num).toDouble(),
|
||||||
y: (json['y'] as num).toDouble(),
|
y: (json['y'] as num).toDouble(),
|
||||||
icon: json['icon'] as String,
|
icon: json['icon'] as String,
|
||||||
);
|
communityUuid: json['communityUuid'] as String);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the [UserSpaceModel] to JSON
|
/// Convert the [UserSpaceModel] to JSON
|
||||||
@ -262,6 +266,7 @@ class UserSpaceModel {
|
|||||||
'x': x,
|
'x': x,
|
||||||
'y': y,
|
'y': y,
|
||||||
'icon': icon,
|
'icon': icon,
|
||||||
|
'communityUuid': communityUuid
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,9 @@ class RolesUserModel {
|
|||||||
invitedBy:
|
invitedBy:
|
||||||
json['invitedBy'].toString().toLowerCase().replaceAll("_", " "),
|
json['invitedBy'].toString().toLowerCase().replaceAll("_", " "),
|
||||||
phoneNumber: json['phoneNumber'],
|
phoneNumber: json['phoneNumber'],
|
||||||
jobTitle: json['jobTitle'] ?? "-",
|
jobTitle: json['jobTitle'] == null || json['jobTitle'] == " "
|
||||||
|
? "_"
|
||||||
|
: json['jobTitle'],
|
||||||
createdDate: json['createdDate'],
|
createdDate: json['createdDate'],
|
||||||
createdTime: json['createdTime'],
|
createdTime: json['createdTime'],
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/common/custom_dialog.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/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/model/role_type_model.dart';
|
||||||
@ -7,11 +9,14 @@ import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialo
|
|||||||
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/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/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/roles_and_permission/users_page/add_user_dialog/model/tree_node_model.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/spaces_management/all_spaces/model/community_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/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
import 'package:syncrow_web/services/space_mana_api.dart';
|
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||||
import 'package:syncrow_web/services/user_permission.dart';
|
import 'package:syncrow_web/services/user_permission.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||||
|
|
||||||
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||||
UsersBloc() : super(UsersInitial()) {
|
UsersBloc() : super(UsersInitial()) {
|
||||||
@ -61,8 +66,10 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
void isCompleteSpacesFun(
|
void isCompleteSpacesFun(
|
||||||
CheckSpacesStepStatus event, Emitter<UsersState> emit) {
|
CheckSpacesStepStatus event, Emitter<UsersState> emit) {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
var spaceBloc =
|
||||||
isCompleteSpaces = selectedIds.isNotEmpty;
|
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
|
||||||
|
|
||||||
|
isCompleteSpaces = spaceBloc.state.selectedCommunities.isNotEmpty;
|
||||||
emit(ChangeStatusSteps());
|
emit(ChangeStatusSteps());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,18 +81,24 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
|
|
||||||
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
||||||
String communityUuid) async {
|
String communityUuid) async {
|
||||||
return await CommunitySpaceManagementApi().getSpaceHierarchy(communityUuid);
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
|
return await CommunitySpaceManagementApi()
|
||||||
|
.getSpaceHierarchy(communityUuid, projectUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TreeNode> updatedCommunities = [];
|
List<TreeNode> updatedCommunities = [];
|
||||||
List<TreeNode> spacesNodes = [];
|
List<TreeNode> spacesNodes = [];
|
||||||
|
List<String> communityIds = [];
|
||||||
_onLoadCommunityAndSpaces(
|
_onLoadCommunityAndSpaces(
|
||||||
LoadCommunityAndSpacesEvent event, Emitter<UsersState> emit) async {
|
LoadCommunityAndSpacesEvent event, Emitter<UsersState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
List<CommunityModel> communities =
|
List<CommunityModel> communities =
|
||||||
await CommunitySpaceManagementApi().fetchCommunities();
|
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
|
||||||
|
communityIds = communities.map((community) => community.uuid).toList();
|
||||||
updatedCommunities = await Future.wait(
|
updatedCommunities = await Future.wait(
|
||||||
communities.map((community) async {
|
communities.map((community) async {
|
||||||
List<SpaceModel> spaces =
|
List<SpaceModel> spaces =
|
||||||
@ -101,13 +114,19 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
);
|
);
|
||||||
|
originalCommunities = updatedCommunities;
|
||||||
emit(const SpacesLoadedState());
|
emit(const SpacesLoadedState());
|
||||||
return updatedCommunities;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ErrorState('Error loading communities and spaces: $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) {
|
List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
|
||||||
return spaces.map((space) {
|
return spaces.map((space) {
|
||||||
List<TreeNode> childNodes =
|
List<TreeNode> childNodes =
|
||||||
@ -123,12 +142,39 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
}).toList();
|
}).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) {
|
void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
|
|
||||||
|
// If the search term is empty, restore the original list.
|
||||||
if (event.searchTerm!.isEmpty) {
|
if (event.searchTerm!.isEmpty) {
|
||||||
|
// Clear any highlights on the restored copy.
|
||||||
|
updatedCommunities = _cloneNodes(originalCommunities);
|
||||||
_clearHighlights(updatedCommunities);
|
_clearHighlights(updatedCommunities);
|
||||||
} else {
|
} else {
|
||||||
_searchAndHighlightNodes(updatedCommunities, event.searchTerm!);
|
// 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());
|
emit(ChangeStatusSteps());
|
||||||
}
|
}
|
||||||
@ -155,6 +201,91 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
return anyMatch;
|
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> selectedIds = [];
|
||||||
|
|
||||||
List<String> getSelectedIds(List<TreeNode> nodes) {
|
List<String> getSelectedIds(List<TreeNode> nodes) {
|
||||||
@ -177,7 +308,6 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
try {
|
try {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
roles = await UserPermissionApi().fetchRoles();
|
roles = await UserPermissionApi().fetchRoles();
|
||||||
// add(PermissionEvent(roleUuid: roles.first.uuid));
|
|
||||||
emit(RolePermissionInitial());
|
emit(RolePermissionInitial());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||||
@ -208,10 +338,17 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
return anyMatch;
|
return anyMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
|
void _sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
|
||||||
try {
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
// List<String> selectedIds =
|
||||||
|
// getSelectedIds(updatedCommunities).where((id) => !communityIds.contains(id)).toList();
|
||||||
|
|
||||||
|
List<String> selectedSpacesId = getSelectedSpacesIds();
|
||||||
|
// List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||||
|
|
||||||
bool res = await UserPermissionApi().sendInviteUser(
|
bool res = await UserPermissionApi().sendInviteUser(
|
||||||
email: emailController.text,
|
email: emailController.text,
|
||||||
firstName: firstNameController.text,
|
firstName: firstNameController.text,
|
||||||
@ -219,9 +356,10 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
lastName: lastNameController.text,
|
lastName: lastNameController.text,
|
||||||
phoneNumber: phoneController.text,
|
phoneNumber: phoneController.text,
|
||||||
roleUuid: roleSelected,
|
roleUuid: roleSelected,
|
||||||
spaceUuids: selectedIds,
|
spaceUuids: selectedSpacesId,
|
||||||
);
|
projectUuid: projectUuid);
|
||||||
if (res == true) {
|
|
||||||
|
if (res) {
|
||||||
showCustomDialog(
|
showCustomDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
context: event.context,
|
context: event.context,
|
||||||
@ -248,10 +386,22 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> getSelectedSpacesIds() {
|
||||||
|
List<String> selectedSpacesId = [];
|
||||||
|
var spaceBloc =
|
||||||
|
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
|
||||||
|
for (var community in spaceBloc.state.selectedCommunities) {
|
||||||
|
selectedSpacesId
|
||||||
|
.addAll(spaceBloc.state.selectedCommunityAndSpaces[community] ?? []);
|
||||||
|
}
|
||||||
|
return selectedSpacesId;
|
||||||
|
}
|
||||||
|
|
||||||
_editInviteUser(EditInviteUsers event, Emitter<UsersState> emit) async {
|
_editInviteUser(EditInviteUsers event, Emitter<UsersState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
bool res = await UserPermissionApi().editInviteUser(
|
bool res = await UserPermissionApi().editInviteUser(
|
||||||
userId: event.userId,
|
userId: event.userId,
|
||||||
firstName: firstNameController.text,
|
firstName: firstNameController.text,
|
||||||
@ -259,8 +409,8 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
lastName: lastNameController.text,
|
lastName: lastNameController.text,
|
||||||
phoneNumber: phoneController.text,
|
phoneNumber: phoneController.text,
|
||||||
roleUuid: roleSelected,
|
roleUuid: roleSelected,
|
||||||
spaceUuids: selectedIds,
|
spaceUuids: getSelectedSpacesIds(),
|
||||||
);
|
projectUuid: projectUuid);
|
||||||
if (res == true) {
|
if (res == true) {
|
||||||
showCustomDialog(
|
showCustomDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
@ -365,8 +515,13 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
var spaceBloc =
|
||||||
|
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
if (event.uuid?.isNotEmpty ?? false) {
|
if (event.uuid?.isNotEmpty ?? false) {
|
||||||
final res = await UserPermissionApi().fetchUserById(event.uuid);
|
final res =
|
||||||
|
await UserPermissionApi().fetchUserById(event.uuid, projectUuid);
|
||||||
|
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
// Populate the text controllers
|
// Populate the text controllers
|
||||||
@ -376,13 +531,20 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
phoneController.text = res.phoneNumber ?? '';
|
phoneController.text = res.phoneNumber ?? '';
|
||||||
jobTitleController.text = res.jobTitle ?? '';
|
jobTitleController.text = res.jobTitle ?? '';
|
||||||
res.roleType;
|
res.roleType;
|
||||||
if (updatedCommunities.isNotEmpty) {
|
res.spaces.map((space) {
|
||||||
// Create a list of UUIDs to mark
|
selectedIds.add(space.uuid);
|
||||||
final uuidsToMark = res.spaces.map((space) => space.uuid).toList();
|
CommunityModel community = spaceBloc.state.communityList
|
||||||
// Print all IDs and mark nodes in updatedCommunities
|
.firstWhere((item) => item.uuid == space.communityUuid);
|
||||||
debugPrint('Printing and marking nodes in updatedCommunities:');
|
spaceBloc.add(OnSpaceSelected(community, space.uuid, []));
|
||||||
_printAndMarkNodes(updatedCommunities, uuidsToMark);
|
}).toList();
|
||||||
}
|
|
||||||
|
// 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
|
final roleId = roles
|
||||||
.firstWhere((element) =>
|
.firstWhere((element) =>
|
||||||
element.type ==
|
element.type ==
|
||||||
@ -475,4 +637,16 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
emailController.dispose();
|
||||||
|
firstNameController.dispose();
|
||||||
|
lastNameController.dispose();
|
||||||
|
emailController.dispose();
|
||||||
|
phoneController.dispose();
|
||||||
|
jobTitleController.dispose();
|
||||||
|
roleSearchController.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (BuildContext context) => UsersBloc()
|
create: (BuildContext context) => UsersBloc()
|
||||||
..add(const LoadCommunityAndSpacesEvent())
|
// ..add(const LoadCommunityAndSpacesEvent())
|
||||||
..add(const RoleEvent()),
|
..add(const RoleEvent()),
|
||||||
child: BlocConsumer<UsersBloc, UsersState>(
|
child: BlocConsumer<UsersBloc, UsersState>(
|
||||||
listener: (context, state) {},
|
listener: (context, state) {},
|
||||||
@ -34,8 +34,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
return Dialog(
|
return Dialog(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
|
||||||
width: 900,
|
width: 900,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -64,8 +63,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
children: [
|
children: [
|
||||||
_buildStep1Indicator(1, "Basics", _blocRole),
|
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||||
_buildStep2Indicator(2, "Spaces", _blocRole),
|
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||||
_buildStep3Indicator(
|
_buildStep3Indicator(3, "Role & Permissions", _blocRole),
|
||||||
3, "Role & Permissions", _blocRole),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -113,15 +111,12 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
if (currentStep < 3) {
|
if (currentStep < 3) {
|
||||||
currentStep++;
|
currentStep++;
|
||||||
if (currentStep == 2) {
|
if (currentStep == 2) {
|
||||||
_blocRole.add(
|
_blocRole.add(const CheckStepStatus(isEditUser: false));
|
||||||
const CheckStepStatus(isEditUser: false));
|
|
||||||
} else if (currentStep == 3) {
|
} else if (currentStep == 3) {
|
||||||
_blocRole
|
_blocRole.add(const CheckSpacesStepStatus());
|
||||||
.add(const CheckSpacesStepStatus());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_blocRole
|
_blocRole.add(SendInviteUsers(context: context));
|
||||||
.add(SendInviteUsers(context: context));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -129,11 +124,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
currentStep < 3 ? "Next" : "Save",
|
currentStep < 3 ? "Next" : "Save",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: (_blocRole.isCompleteSpaces == false ||
|
color: (_blocRole.isCompleteSpaces == false ||
|
||||||
_blocRole.isCompleteBasics ==
|
_blocRole.isCompleteBasics == false ||
|
||||||
false ||
|
_blocRole.isCompleteRolePermissions == false) &&
|
||||||
_blocRole
|
|
||||||
.isCompleteRolePermissions ==
|
|
||||||
false) &&
|
|
||||||
currentStep == 3
|
currentStep == 3
|
||||||
? ColorsManager.grayColor
|
? ColorsManager.grayColor
|
||||||
: ColorsManager.secondaryColor),
|
: ColorsManager.secondaryColor),
|
||||||
@ -204,12 +196,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -236,12 +224,16 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
currentStep = step;
|
|
||||||
bloc.add(const CheckStepStatus(isEditUser: false));
|
bloc.add(const CheckStepStatus(isEditUser: false));
|
||||||
|
currentStep = step;
|
||||||
|
Future.delayed(const Duration(milliseconds: 500), () {
|
||||||
|
bloc.add(const CheckStepStatus(isEditUser: false));
|
||||||
|
});
|
||||||
if (step3 == 3) {
|
if (step3 == 3) {
|
||||||
|
Future.delayed(const Duration(seconds: 1), () {
|
||||||
bloc.add(const CheckRoleStepStatus());
|
bloc.add(const CheckRoleStepStatus());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -268,12 +260,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -330,12 +318,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -46,8 +46,9 @@ class BasicsView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
Flexible(
|
||||||
width: MediaQuery.of(context).size.width * 0.18,
|
child: SizedBox(
|
||||||
|
// width: MediaQuery.of(context).size.width * 0.18,
|
||||||
height: MediaQuery.of(context).size.width * 0.08,
|
height: MediaQuery.of(context).size.width * 0.08,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -75,8 +76,8 @@ class BasicsView extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
style:
|
style: const TextStyle(
|
||||||
const TextStyle(color: ColorsManager.blackColor),
|
color: ColorsManager.blackColor),
|
||||||
// onChanged: (value) {
|
// onChanged: (value) {
|
||||||
// Future.delayed(const Duration(milliseconds: 200),
|
// Future.delayed(const Duration(milliseconds: 200),
|
||||||
// () {
|
// () {
|
||||||
@ -103,9 +104,11 @@ class BasicsView extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
SizedBox(
|
Flexible(
|
||||||
width: MediaQuery.of(context).size.width * 0.18,
|
child: SizedBox(
|
||||||
|
// width: MediaQuery.of(context).size.width * 0.18,
|
||||||
height: MediaQuery.of(context).size.width * 0.08,
|
height: MediaQuery.of(context).size.width * 0.08,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -142,8 +145,7 @@ class BasicsView extends StatelessWidget {
|
|||||||
decoration:
|
decoration:
|
||||||
inputTextFormDeco(hintText: "Enter last name")
|
inputTextFormDeco(hintText: "Enter last name")
|
||||||
.copyWith(
|
.copyWith(
|
||||||
hintStyle: context
|
hintStyle: context.textTheme.bodyMedium
|
||||||
.textTheme.bodyMedium
|
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -159,6 +161,7 @@ class BasicsView extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
@ -218,7 +221,7 @@ class BasicsView extends StatelessWidget {
|
|||||||
if (_blocRole.checkEmailValid != "Valid email") {
|
if (_blocRole.checkEmailValid != "Valid email") {
|
||||||
return _blocRole.checkEmailValid;
|
return _blocRole.checkEmailValid;
|
||||||
}
|
}
|
||||||
return null;
|
// return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.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_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/bloc/users_status.dart';
|
||||||
@ -19,7 +20,6 @@ class TreeView extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
||||||
debugPrint('TreeView constructed with userId = $userId');
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => UsersBloc(),
|
create: (_) => UsersBloc(),
|
||||||
// ..add(const LoadCommunityAndSpacesEvent()),
|
// ..add(const LoadCommunityAndSpacesEvent()),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.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_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/bloc/users_status.dart';
|
||||||
@ -25,13 +26,12 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (BuildContext context) => UsersBloc()
|
create: (BuildContext context) => UsersBloc()
|
||||||
..add(const LoadCommunityAndSpacesEvent())
|
// ..add(const LoadCommunityAndSpacesEvent())
|
||||||
..add(const RoleEvent())
|
..add(const RoleEvent())
|
||||||
..add(GetUserByIdEvent(uuid: widget.userId)),
|
..add(GetUserByIdEvent(uuid: widget.userId)),
|
||||||
child: BlocConsumer<UsersBloc, UsersState>(listener: (context, state) {
|
child: BlocConsumer<UsersBloc, UsersState>(listener: (context, state) {
|
||||||
if (state is SpacesLoadedState) {
|
if (state is SpacesLoadedState) {
|
||||||
BlocProvider.of<UsersBloc>(context)
|
BlocProvider.of<UsersBloc>(context).add(GetUserByIdEvent(uuid: widget.userId));
|
||||||
.add(GetUserByIdEvent(uuid: widget.userId));
|
|
||||||
}
|
}
|
||||||
}, builder: (context, state) {
|
}, builder: (context, state) {
|
||||||
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
||||||
@ -39,8 +39,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
return Dialog(
|
return Dialog(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
|
||||||
width: 900,
|
width: 900,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -69,8 +68,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
children: [
|
children: [
|
||||||
_buildStep1Indicator(1, "Basics", _blocRole),
|
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||||
_buildStep2Indicator(2, "Spaces", _blocRole),
|
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||||
_buildStep3Indicator(
|
_buildStep3Indicator(3, "Role & Permissions", _blocRole),
|
||||||
3, "Role & Permissions", _blocRole),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -118,15 +116,13 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
if (currentStep < 3) {
|
if (currentStep < 3) {
|
||||||
currentStep++;
|
currentStep++;
|
||||||
if (currentStep == 2) {
|
if (currentStep == 2) {
|
||||||
_blocRole
|
_blocRole.add(CheckStepStatus(isEditUser: true));
|
||||||
.add(CheckStepStatus(isEditUser: true));
|
|
||||||
} else if (currentStep == 3) {
|
} else if (currentStep == 3) {
|
||||||
_blocRole.add(const CheckSpacesStepStatus());
|
_blocRole.add(const CheckSpacesStepStatus());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_blocRole.add(EditInviteUsers(
|
_blocRole
|
||||||
context: context,
|
.add(EditInviteUsers(context: context, userId: widget.userId!));
|
||||||
userId: widget.userId!));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -135,8 +131,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: (_blocRole.isCompleteSpaces == false ||
|
color: (_blocRole.isCompleteSpaces == false ||
|
||||||
_blocRole.isCompleteBasics == false ||
|
_blocRole.isCompleteBasics == false ||
|
||||||
_blocRole.isCompleteRolePermissions ==
|
_blocRole.isCompleteRolePermissions == false) &&
|
||||||
false) &&
|
|
||||||
currentStep == 3
|
currentStep == 3
|
||||||
? ColorsManager.grayColor
|
? ColorsManager.grayColor
|
||||||
: ColorsManager.secondaryColor),
|
: ColorsManager.secondaryColor),
|
||||||
@ -209,12 +204,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -272,12 +263,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -334,12 +321,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -81,7 +81,7 @@ Future<void> showPopUpFilterMenu({
|
|||||||
),
|
),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const Text(
|
const Text(
|
||||||
"Filter by Status",
|
"Filter by ",
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
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:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.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/bloc/users_status.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/build_tree_view.dart';
|
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
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/style.dart';
|
|
||||||
|
|
||||||
class SpacesAccessView extends StatelessWidget {
|
class SpacesAccessView extends StatelessWidget {
|
||||||
final String? userId;
|
final String? userId;
|
||||||
@ -27,10 +22,8 @@ class SpacesAccessView extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Spaces access',
|
'Spaces access',
|
||||||
style: context.textTheme.bodyLarge?.copyWith(
|
style: context.textTheme.bodyLarge
|
||||||
fontWeight: FontWeight.w700,
|
?.copyWith(fontWeight: FontWeight.w700, fontSize: 20, color: Colors.black),
|
||||||
fontSize: 20,
|
|
||||||
color: Colors.black),
|
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 35,
|
height: 35,
|
||||||
@ -42,77 +35,78 @@ class SpacesAccessView extends StatelessWidget {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 25,
|
height: 25,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(child: SpaceTreeView(onSelect: () {}))
|
||||||
child: SizedBox(
|
// Expanded(
|
||||||
child: Column(
|
// child: SizedBox(
|
||||||
children: [
|
// child: Column(
|
||||||
Expanded(
|
// children: [
|
||||||
flex: 2,
|
// Expanded(
|
||||||
child: Container(
|
// flex: 2,
|
||||||
decoration: const BoxDecoration(
|
// child: Container(
|
||||||
color: ColorsManager.circleRolesBackground,
|
// decoration: const BoxDecoration(
|
||||||
borderRadius: BorderRadius.only(
|
// color: ColorsManager.circleRolesBackground,
|
||||||
topRight: Radius.circular(20),
|
// borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(20)),
|
// topRight: Radius.circular(20),
|
||||||
),
|
// topLeft: Radius.circular(20)),
|
||||||
child: Padding(
|
// ),
|
||||||
padding: const EdgeInsets.all(8.0),
|
// child: Padding(
|
||||||
child: Row(
|
// padding: const EdgeInsets.all(8.0),
|
||||||
children: [
|
// child: Row(
|
||||||
Expanded(
|
// children: [
|
||||||
child: Container(
|
// Expanded(
|
||||||
decoration: BoxDecoration(
|
// child: Container(
|
||||||
borderRadius: const BorderRadius.all(
|
// decoration: BoxDecoration(
|
||||||
Radius.circular(20)),
|
// borderRadius: const BorderRadius.all(
|
||||||
border: Border.all(
|
// Radius.circular(20)),
|
||||||
color: ColorsManager.grayBorder)),
|
// border: Border.all(
|
||||||
child: TextFormField(
|
// color: ColorsManager.grayBorder)),
|
||||||
style:
|
// child: TextFormField(
|
||||||
const TextStyle(color: Colors.black),
|
// style:
|
||||||
// controller: _blocRole.firstNameController,
|
// const TextStyle(color: Colors.black),
|
||||||
onChanged: (value) {
|
// // controller: _blocRole.firstNameController,
|
||||||
_blocRole.add(SearchAnode(
|
// onChanged: (value) {
|
||||||
nodes: _blocRole.updatedCommunities,
|
// _blocRole.add(SearchAnode(
|
||||||
searchTerm: value));
|
// nodes: _blocRole.updatedCommunities,
|
||||||
},
|
// searchTerm: value));
|
||||||
decoration: textBoxDecoration(radios: 20)!
|
// },
|
||||||
.copyWith(
|
// decoration: textBoxDecoration(radios: 20)!
|
||||||
fillColor: Colors.white,
|
// .copyWith(
|
||||||
suffixIcon: Padding(
|
// fillColor: Colors.white,
|
||||||
padding:
|
// suffixIcon: Padding(
|
||||||
const EdgeInsets.only(right: 16),
|
// padding:
|
||||||
child: SvgPicture.asset(
|
// const EdgeInsets.only(right: 16),
|
||||||
Assets.textFieldSearch,
|
// child: SvgPicture.asset(
|
||||||
width: 24,
|
// Assets.textFieldSearch,
|
||||||
height: 24,
|
// width: 24,
|
||||||
),
|
// height: 24,
|
||||||
),
|
// ),
|
||||||
hintStyle: context.textTheme.bodyMedium
|
// ),
|
||||||
?.copyWith(
|
// hintStyle: context.textTheme.bodyMedium
|
||||||
fontWeight: FontWeight.w400,
|
// ?.copyWith(
|
||||||
fontSize: 12,
|
// fontWeight: FontWeight.w400,
|
||||||
color: ColorsManager.textGray),
|
// fontSize: 12,
|
||||||
),
|
// color: ColorsManager.textGray),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ),
|
||||||
),
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
Expanded(
|
// ),
|
||||||
flex: 7,
|
// Expanded(
|
||||||
child: Container(
|
// flex: 7,
|
||||||
color: ColorsManager.circleRolesBackground,
|
// child: Container(
|
||||||
padding: const EdgeInsets.all(8.0),
|
// color: ColorsManager.circleRolesBackground,
|
||||||
child: Container(
|
// padding: const EdgeInsets.all(8.0),
|
||||||
color: ColorsManager.whiteColors,
|
// child: Container(
|
||||||
child: TreeView(userId: userId))))
|
// color: ColorsManager.whiteColors,
|
||||||
],
|
// child: TreeView(userId: userId))))
|
||||||
),
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:bloc/bloc.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_event.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_state.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_state.dart';
|
||||||
import 'package:syncrow_web/services/user_permission.dart';
|
import 'package:syncrow_web/services/user_permission.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
|
|
||||||
class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||||
UserTableBloc() : super(TableInitial()) {
|
UserTableBloc() : super(TableInitial()) {
|
||||||
@ -27,7 +30,16 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
int currentPage = 1;
|
int currentPage = 1;
|
||||||
List<RolesUserModel> users = [];
|
List<RolesUserModel> users = [];
|
||||||
List<RolesUserModel> initialUsers = [];
|
List<RolesUserModel> initialUsers = [];
|
||||||
|
|
||||||
|
List<RolesUserModel> totalUsersCount = [];
|
||||||
String currentSortOrder = '';
|
String currentSortOrder = '';
|
||||||
|
|
||||||
|
String currentSortJopTitle = '';
|
||||||
|
String currentSortRole = '';
|
||||||
|
String currentSortCreatedDate = '';
|
||||||
|
String currentSortStatus = '';
|
||||||
|
String currentSortCreatedBy = '';
|
||||||
|
|
||||||
String currentSortOrderDate = '';
|
String currentSortOrderDate = '';
|
||||||
List<String> roleTypes = [];
|
List<String> roleTypes = [];
|
||||||
List<String> jobTitle = [];
|
List<String> jobTitle = [];
|
||||||
@ -37,12 +49,12 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
Future<void> _getUsers(GetUsers event, Emitter<UserTableState> emit) async {
|
Future<void> _getUsers(GetUsers event, Emitter<UserTableState> emit) async {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
try {
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
roleTypes.clear();
|
roleTypes.clear();
|
||||||
jobTitle.clear();
|
jobTitle.clear();
|
||||||
createdBy.clear();
|
createdBy.clear();
|
||||||
// deActivate.clear();
|
users = await UserPermissionApi().fetchUsers(projectUuid);
|
||||||
users = await UserPermissionApi().fetchUsers();
|
|
||||||
|
|
||||||
users.sort((a, b) {
|
users.sort((a, b) {
|
||||||
final dateA = _parseDateTime(a.createdDate);
|
final dateA = _parseDateTime(a.createdDate);
|
||||||
final dateB = _parseDateTime(b.createdDate);
|
final dateB = _parseDateTime(b.createdDate);
|
||||||
@ -57,15 +69,13 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
for (var user in users) {
|
for (var user in users) {
|
||||||
createdBy.add(user.invitedBy.toString());
|
createdBy.add(user.invitedBy.toString());
|
||||||
}
|
}
|
||||||
// for (var user in users) {
|
|
||||||
// deActivate.add(user.status.toString());
|
|
||||||
// }
|
|
||||||
initialUsers = List.from(users);
|
initialUsers = List.from(users);
|
||||||
roleTypes = roleTypes.toSet().toList();
|
roleTypes = roleTypes.toSet().toList();
|
||||||
jobTitle = jobTitle.toSet().toList();
|
jobTitle = jobTitle.toSet().toList();
|
||||||
createdBy = createdBy.toSet().toList();
|
createdBy = createdBy.toSet().toList();
|
||||||
// deActivate = deActivate.toSet().toList();
|
|
||||||
_handlePageChange(ChangePage(1), emit);
|
_handlePageChange(ChangePage(1), emit);
|
||||||
|
totalUsersCount = initialUsers;
|
||||||
|
add(ChangePage(currentPage));
|
||||||
emit(UsersLoadedState(users: users));
|
emit(UsersLoadedState(users: users));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ErrorState(e.toString()));
|
emit(ErrorState(e.toString()));
|
||||||
@ -91,31 +101,13 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
Future<void> _changeUserStatus(
|
Future<void> _changeUserStatus(
|
||||||
ChangeUserStatus event, Emitter<UserTableState> emit) async {
|
ChangeUserStatus event, Emitter<UserTableState> emit) async {
|
||||||
try {
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
bool res = await UserPermissionApi().changeUserStatusById(
|
bool res = await UserPermissionApi().changeUserStatusById(event.userId,
|
||||||
event.userId, event.newStatus == "disabled" ? false : true);
|
event.newStatus == "disabled" ? false : true, projectUuid);
|
||||||
if (res == true) {
|
if (res == true) {
|
||||||
add(const GetUsers());
|
add(const GetUsers());
|
||||||
// users = users.map((user) {
|
|
||||||
// if (user.uuid == event.userId) {
|
|
||||||
// return RolesUserModel(
|
|
||||||
// uuid: user.uuid,
|
|
||||||
// createdAt: user.createdAt,
|
|
||||||
// email: user.email,
|
|
||||||
// firstName: user.firstName,
|
|
||||||
// lastName: user.lastName,
|
|
||||||
// roleType: user.roleType,
|
|
||||||
// status: event.newStatus,
|
|
||||||
// isEnabled: event.newStatus == "disabled" ? false : true,
|
|
||||||
// invitedBy: user.invitedBy,
|
|
||||||
// phoneNumber: user.phoneNumber,
|
|
||||||
// jobTitle: user.jobTitle,
|
|
||||||
// createdDate: user.createdDate,
|
|
||||||
// createdTime: user.createdTime,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// return user;
|
|
||||||
// }).toList();
|
|
||||||
}
|
}
|
||||||
emit(UsersLoadedState(users: users));
|
emit(UsersLoadedState(users: users));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -125,11 +117,14 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
|
|
||||||
void _toggleSortUsersByNameAsc(
|
void _toggleSortUsersByNameAsc(
|
||||||
SortUsersByNameAsc event, Emitter<UserTableState> emit) {
|
SortUsersByNameAsc event, Emitter<UserTableState> emit) {
|
||||||
|
selectedRoles.clear();
|
||||||
|
selectedJobTitles.clear();
|
||||||
|
selectedCreatedBy.clear();
|
||||||
|
selectedStatuses.clear();
|
||||||
if (currentSortOrder == "Asc") {
|
if (currentSortOrder == "Asc") {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
users = List.from(users);
|
users = List.from(users);
|
||||||
emit(UsersLoadedState(users: users));
|
|
||||||
} else {
|
} else {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "Asc";
|
currentSortOrder = "Asc";
|
||||||
@ -137,28 +132,42 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
.toString()
|
.toString()
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.compareTo(b.firstName.toString().toLowerCase()));
|
.compareTo(b.firstName.toString().toLowerCase()));
|
||||||
emit(UsersLoadedState(users: users));
|
|
||||||
}
|
}
|
||||||
|
currentSortJopTitle = '';
|
||||||
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
emit(UsersLoadedState(users: users));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _toggleSortUsersByNameDesc(
|
void _toggleSortUsersByNameDesc(
|
||||||
SortUsersByNameDesc event, Emitter<UserTableState> emit) {
|
SortUsersByNameDesc event, Emitter<UserTableState> emit) {
|
||||||
|
selectedRoles.clear();
|
||||||
|
selectedJobTitles.clear();
|
||||||
|
selectedCreatedBy.clear();
|
||||||
|
selectedStatuses.clear();
|
||||||
if (currentSortOrder == "Desc") {
|
if (currentSortOrder == "Desc") {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
users = List.from(initialUsers); // Reset to saved initial state
|
users = List.from(initialUsers);
|
||||||
emit(UsersLoadedState(users: users));
|
|
||||||
} else {
|
} else {
|
||||||
// Sort descending
|
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
users.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
users.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
emit(UsersLoadedState(users: users));
|
|
||||||
}
|
}
|
||||||
|
currentSortJopTitle = '';
|
||||||
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
emit(UsersLoadedState(users: users));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _toggleSortUsersByDateNewestToOldest(
|
void _toggleSortUsersByDateNewestToOldest(
|
||||||
DateNewestToOldestEvent event, Emitter<UserTableState> emit) {
|
DateNewestToOldestEvent event, Emitter<UserTableState> emit) {
|
||||||
|
selectedRoles.clear();
|
||||||
|
selectedJobTitles.clear();
|
||||||
|
selectedCreatedBy.clear();
|
||||||
|
selectedStatuses.clear();
|
||||||
if (currentSortOrderDate == "NewestToOldest") {
|
if (currentSortOrderDate == "NewestToOldest") {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
@ -179,6 +188,10 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
|
|
||||||
void _toggleSortUsersByDateOldestToNewest(
|
void _toggleSortUsersByDateOldestToNewest(
|
||||||
DateOldestToNewestEvent event, Emitter<UserTableState> emit) {
|
DateOldestToNewestEvent event, Emitter<UserTableState> emit) {
|
||||||
|
selectedRoles.clear();
|
||||||
|
selectedJobTitles.clear();
|
||||||
|
selectedCreatedBy.clear();
|
||||||
|
selectedStatuses.clear();
|
||||||
if (currentSortOrderDate == "OldestToNewest") {
|
if (currentSortOrderDate == "OldestToNewest") {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
@ -212,6 +225,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
Future<void> _searchUsers(
|
Future<void> _searchUsers(
|
||||||
SearchUsers event, Emitter<UserTableState> emit) async {
|
SearchUsers event, Emitter<UserTableState> emit) async {
|
||||||
try {
|
try {
|
||||||
|
emit(TableSearch());
|
||||||
final query = event.query.toLowerCase();
|
final query = event.query.toLowerCase();
|
||||||
final filteredUsers = initialUsers.where((user) {
|
final filteredUsers = initialUsers.where((user) {
|
||||||
final fullName = "${user.firstName} ${user.lastName}".toLowerCase();
|
final fullName = "${user.firstName} ${user.lastName}".toLowerCase();
|
||||||
@ -240,7 +254,8 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handlePageChange(ChangePage event, Emitter<UserTableState> emit) {
|
void _handlePageChange(ChangePage event, Emitter<UserTableState> emit) {
|
||||||
const itemsPerPage = 10;
|
currentPage = event.pageNumber;
|
||||||
|
const itemsPerPage = 20;
|
||||||
final startIndex = (event.pageNumber - 1) * itemsPerPage;
|
final startIndex = (event.pageNumber - 1) * itemsPerPage;
|
||||||
final endIndex = startIndex + itemsPerPage;
|
final endIndex = startIndex + itemsPerPage;
|
||||||
if (startIndex >= users.length) {
|
if (startIndex >= users.length) {
|
||||||
@ -277,9 +292,15 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
} else if (event.sortOrder == "Desc") {
|
} else if (event.sortOrder == "Desc") {
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
} else {
|
} else {}
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
}
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
currentSortJopTitle = '';
|
||||||
|
currentSortOrderDate = "";
|
||||||
|
|
||||||
|
totalUsersCount = filteredUsers;
|
||||||
|
|
||||||
emit(UsersLoadedState(users: filteredUsers));
|
emit(UsersLoadedState(users: filteredUsers));
|
||||||
}
|
}
|
||||||
@ -301,9 +322,16 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
} else if (event.sortOrder == "Desc") {
|
} else if (event.sortOrder == "Desc") {
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
} else {
|
} else {}
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
}
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
currentSortRole = '';
|
||||||
|
currentSortOrderDate = "";
|
||||||
|
|
||||||
|
totalUsersCount = filteredUsers;
|
||||||
|
|
||||||
emit(UsersLoadedState(users: filteredUsers));
|
emit(UsersLoadedState(users: filteredUsers));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,9 +353,15 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
} else if (event.sortOrder == "Desc") {
|
} else if (event.sortOrder == "Desc") {
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
} else {
|
} else {}
|
||||||
currentSortOrder = "";
|
currentSortOrder = '';
|
||||||
}
|
currentSortRole = '';
|
||||||
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortOrderDate = "";
|
||||||
|
|
||||||
|
totalUsersCount = filteredUsers;
|
||||||
|
|
||||||
emit(UsersLoadedState(users: filteredUsers));
|
emit(UsersLoadedState(users: filteredUsers));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +371,20 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
|
|
||||||
final filteredUsers = initialUsers.where((user) {
|
final filteredUsers = initialUsers.where((user) {
|
||||||
if (selectedStatuses.isEmpty) return true;
|
if (selectedStatuses.isEmpty) return true;
|
||||||
return selectedStatuses.contains(user.status);
|
|
||||||
|
return selectedStatuses.any((status) {
|
||||||
|
final userStatus = user.status?.toLowerCase() ?? '';
|
||||||
|
switch (status.toLowerCase()) {
|
||||||
|
case 'active':
|
||||||
|
return user.isEnabled == true && userStatus != 'invited';
|
||||||
|
case 'disabled':
|
||||||
|
return user.isEnabled == false;
|
||||||
|
case 'invited':
|
||||||
|
return userStatus == 'invited';
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}).toList();
|
}).toList();
|
||||||
if (event.sortOrder == "Asc") {
|
if (event.sortOrder == "Asc") {
|
||||||
currentSortOrder = "Asc";
|
currentSortOrder = "Asc";
|
||||||
@ -348,9 +395,14 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
} else if (event.sortOrder == "Desc") {
|
} else if (event.sortOrder == "Desc") {
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
} else {
|
totalUsersCount = filteredUsers;
|
||||||
currentSortOrder = "";
|
} else {}
|
||||||
}
|
currentSortOrder = '';
|
||||||
|
currentSortRole = '';
|
||||||
|
currentSortCreatedDate = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
currentSortOrderDate = "";
|
||||||
|
|
||||||
emit(UsersLoadedState(users: filteredUsers));
|
emit(UsersLoadedState(users: filteredUsers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,10 @@ final class TableInitial extends UserTableState {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
final class TableSearch extends UserTableState {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
final class RolesLoadingState extends UserTableState {
|
final class RolesLoadingState extends UserTableState {
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
|
@ -12,7 +12,7 @@ Future<void> showDateFilterMenu({
|
|||||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
final RelativeRect position = RelativeRect.fromRect(
|
final RelativeRect position = RelativeRect.fromRect(
|
||||||
Rect.fromLTRB(
|
Rect.fromLTRB(
|
||||||
overlay.size.width / 2,
|
overlay.size.width / 3,
|
||||||
240,
|
240,
|
||||||
0,
|
0,
|
||||||
overlay.size.height,
|
overlay.size.height,
|
||||||
@ -40,7 +40,6 @@ Future<void> showDateFilterMenu({
|
|||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
"Sort from newest to oldest",
|
"Sort from newest to oldest",
|
||||||
// style: context.textTheme.bodyMedium,
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isSelected == "NewestToOldest"
|
color: isSelected == "NewestToOldest"
|
||||||
? Colors.black
|
? Colors.black
|
||||||
@ -65,9 +64,5 @@ Future<void> showDateFilterMenu({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).then((value) {
|
).then((value) {});
|
||||||
// setState(() {
|
|
||||||
// _isDropdownOpen = false;
|
|
||||||
// });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ Future<void> showDeActivateFilterMenu({
|
|||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
"Sort A to Z",
|
"Sort A to Z",
|
||||||
// style: context.textTheme.bodyMedium,
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isSelected == "NewestToOldest"
|
color: isSelected == "NewestToOldest"
|
||||||
? Colors.black
|
? Colors.black
|
||||||
@ -65,9 +64,5 @@ Future<void> showDeActivateFilterMenu({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).then((value) {
|
).then((value) {});
|
||||||
// setState(() {
|
|
||||||
// _isDropdownOpen = false;
|
|
||||||
// });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ Future<void> showNameMenu({
|
|||||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
final RelativeRect position = RelativeRect.fromRect(
|
final RelativeRect position = RelativeRect.fromRect(
|
||||||
Rect.fromLTRB(
|
Rect.fromLTRB(
|
||||||
overlay.size.width / 25,
|
overlay.size.width / 35,
|
||||||
240,
|
240,
|
||||||
0,
|
0,
|
||||||
overlay.size.height,
|
overlay.size.height,
|
||||||
@ -40,7 +40,6 @@ Future<void> showNameMenu({
|
|||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
"Sort A to Z",
|
"Sort A to Z",
|
||||||
// style: context.textTheme.bodyMedium,
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isSelected == "Asc" ? Colors.black : Colors.blueGrey),
|
color: isSelected == "Asc" ? Colors.black : Colors.blueGrey),
|
||||||
),
|
),
|
||||||
@ -61,9 +60,5 @@ Future<void> showNameMenu({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).then((value) {
|
).then((value) {});
|
||||||
// setState(() {
|
|
||||||
// _isDropdownOpen = false;
|
|
||||||
// });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -1,255 +1,58 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/flutter_svg.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/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class DynamicTableScreen extends StatefulWidget {
|
class _HeaderColumn extends StatelessWidget {
|
||||||
final List<String> titles;
|
final String title;
|
||||||
final List<List<Widget>> rows;
|
final double width;
|
||||||
final void Function(int columnIndex)? onFilter;
|
final bool showFilter;
|
||||||
|
final VoidCallback? onFilter;
|
||||||
|
final Function(double) onResize;
|
||||||
|
|
||||||
DynamicTableScreen(
|
const _HeaderColumn({
|
||||||
{required this.titles, required this.rows, required this.onFilter});
|
required this.title,
|
||||||
|
required this.width,
|
||||||
@override
|
required this.showFilter,
|
||||||
_DynamicTableScreenState createState() => _DynamicTableScreenState();
|
required this.onResize,
|
||||||
}
|
this.onFilter,
|
||||||
|
Key? key,
|
||||||
class _DynamicTableScreenState extends State<DynamicTableScreen>
|
}) : super(key: key);
|
||||||
with WidgetsBindingObserver {
|
|
||||||
late List<double> columnWidths;
|
|
||||||
late double totalWidth;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
columnWidths = List<double>.filled(widget.titles.length, 150.0);
|
|
||||||
totalWidth = columnWidths.reduce((a, b) => a + b);
|
|
||||||
WidgetsBinding.instance.addObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeMetrics() {
|
|
||||||
super.didChangeMetrics();
|
|
||||||
final newScreenWidth = MediaQuery.of(context).size.width;
|
|
||||||
setState(() {
|
|
||||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
|
||||||
if (index == 1) {
|
|
||||||
return newScreenWidth *
|
|
||||||
0.12; // 20% of screen width for the second column
|
|
||||||
} else if (index == 9) {
|
|
||||||
return newScreenWidth *
|
|
||||||
0.1; // 25% of screen width for the tenth column
|
|
||||||
}
|
|
||||||
return newScreenWidth *
|
|
||||||
0.09; // Default to 10% of screen width for other columns
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
return MouseRegion(
|
||||||
if (columnWidths.every((width) => width == screenWidth * 7)) {
|
cursor: SystemMouseCursors.resizeColumn,
|
||||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
child: GestureDetector(
|
||||||
if (index == 1) {
|
onHorizontalDragUpdate: (details) => onResize(details.delta.dx),
|
||||||
return screenWidth * 0.11;
|
|
||||||
} else if (index == 9) {
|
|
||||||
return screenWidth * 0.1;
|
|
||||||
}
|
|
||||||
return screenWidth * 0.09;
|
|
||||||
});
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
return SingleChildScrollView(
|
|
||||||
clipBehavior: Clip.none,
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: containerDecoration.copyWith(
|
width: width,
|
||||||
color: ColorsManager.whiteColors,
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(20))),
|
decoration: const BoxDecoration(
|
||||||
child: FittedBox(
|
border: Border(right: BorderSide(color: ColorsManager.boxDivider)),
|
||||||
child: Column(
|
),
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: totalWidth,
|
|
||||||
decoration: containerDecoration.copyWith(
|
|
||||||
color: ColorsManager.circleRolesBackground,
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(15),
|
|
||||||
topRight: Radius.circular(15))),
|
|
||||||
child: Row(
|
|
||||||
children: List.generate(widget.titles.length, (index) {
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
FittedBox(
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.only(left: 5, right: 5),
|
|
||||||
width: columnWidths[index],
|
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.titles[index],
|
title,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
style: const TextStyle(
|
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: ColorsManager.grayColor,
|
color: ColorsManager.grayColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (index != 1 &&
|
if (showFilter)
|
||||||
index != 9 &&
|
IconButton(
|
||||||
index != 8 &&
|
icon: SvgPicture.asset(Assets.filterTableIcon),
|
||||||
index != 5)
|
onPressed: onFilter,
|
||||||
FittedBox(
|
padding: EdgeInsets.zero,
|
||||||
child: IconButton(
|
constraints: const BoxConstraints(),
|
||||||
icon: SvgPicture.asset(
|
|
||||||
Assets.filterTableIcon,
|
|
||||||
fit: BoxFit.none,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
if (widget.onFilter != null) {
|
|
||||||
widget.onFilter!(index);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
onHorizontalDragUpdate: (details) {
|
|
||||||
setState(() {
|
|
||||||
columnWidths[index] =
|
|
||||||
(columnWidths[index] + details.delta.dx)
|
|
||||||
.clamp(150.0, 300.0);
|
|
||||||
totalWidth = columnWidths.reduce((a, b) => a + b);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: MouseRegion(
|
|
||||||
cursor: SystemMouseCursors.resizeColumn,
|
|
||||||
child: Container(
|
|
||||||
color: Colors.green,
|
|
||||||
child: Container(
|
|
||||||
color: ColorsManager.boxDivider,
|
|
||||||
width: 1,
|
|
||||||
height: 50,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
widget.rows.isEmpty
|
|
||||||
? SizedBox(
|
|
||||||
height: MediaQuery.of(context).size.height / 2,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
SvgPicture.asset(Assets.emptyTable),
|
|
||||||
const SizedBox(
|
|
||||||
height: 15,
|
|
||||||
),
|
|
||||||
const Text(
|
|
||||||
'No Users',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w700),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Center(
|
|
||||||
child: Container(
|
|
||||||
width: totalWidth,
|
|
||||||
decoration: containerDecoration.copyWith(
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(15),
|
|
||||||
bottomRight: Radius.circular(15))),
|
|
||||||
child: ListView.builder(
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: widget.rows.length,
|
|
||||||
itemBuilder: (context, rowIndex) {
|
|
||||||
if (columnWidths.every((width) => width == 120.0)) {
|
|
||||||
columnWidths = List<double>.generate(
|
|
||||||
widget.titles.length, (index) {
|
|
||||||
if (index == 1) {
|
|
||||||
return screenWidth * 0.11;
|
|
||||||
} else if (index == 9) {
|
|
||||||
return screenWidth * 0.2;
|
|
||||||
}
|
|
||||||
return screenWidth * 0.11;
|
|
||||||
});
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
final row = widget.rows[rowIndex];
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 5, top: 10, right: 5, bottom: 10),
|
|
||||||
child: Row(
|
|
||||||
children:
|
|
||||||
List.generate(row.length, (index) {
|
|
||||||
return SizedBox(
|
|
||||||
width: columnWidths[index],
|
|
||||||
child: SizedBox(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 15, right: 10),
|
|
||||||
child: row[index],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (rowIndex < widget.rows.length - 1)
|
|
||||||
Row(
|
|
||||||
children: List.generate(
|
|
||||||
widget.titles.length, (index) {
|
|
||||||
return SizedBox(
|
|
||||||
width: columnWidths[index],
|
|
||||||
child: const Divider(
|
|
||||||
color: ColorsManager.boxDivider,
|
|
||||||
thickness: 1,
|
|
||||||
height: 1,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -258,3 +61,204 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _TableRow extends StatelessWidget {
|
||||||
|
final List<Widget> cells;
|
||||||
|
final List<double> columnWidths;
|
||||||
|
final bool isLast;
|
||||||
|
|
||||||
|
const _TableRow({
|
||||||
|
required this.cells,
|
||||||
|
required this.columnWidths,
|
||||||
|
required this.isLast,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
for (int i = 0; i < cells.length; i++)
|
||||||
|
Container(
|
||||||
|
width: columnWidths[i],
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// border: Border(
|
||||||
|
// right: BorderSide(color: ColorsManager.boxDivider),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
child: cells[i],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (!isLast)
|
||||||
|
Divider(
|
||||||
|
height: 1,
|
||||||
|
thickness: 1,
|
||||||
|
color: ColorsManager.boxDivider,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
class DynamicTableScreen extends StatefulWidget {
|
||||||
|
final List<String> titles;
|
||||||
|
final List<List<Widget>> rows;
|
||||||
|
final void Function(int columnIndex)? onFilter;
|
||||||
|
|
||||||
|
const DynamicTableScreen({
|
||||||
|
required this.titles,
|
||||||
|
required this.rows,
|
||||||
|
required this.onFilter,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_DynamicTableScreenState createState() => _DynamicTableScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DynamicTableScreenState extends State<DynamicTableScreen> {
|
||||||
|
late List<double> columnWidths;
|
||||||
|
final double _minColumnWidth = 100.0;
|
||||||
|
final double _maxColumnWidth = 300.0;
|
||||||
|
final double _dividerWidth = 1.0;
|
||||||
|
double _lastAvailableWidth = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
columnWidths = List.filled(widget.titles.length, _minColumnWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleColumnResize(int index, double delta) {
|
||||||
|
setState(() {
|
||||||
|
double newWidth = columnWidths[index] + delta;
|
||||||
|
newWidth = newWidth.clamp(_minColumnWidth, _maxColumnWidth);
|
||||||
|
double actualDelta = newWidth - columnWidths[index];
|
||||||
|
if (actualDelta == 0) return;
|
||||||
|
|
||||||
|
int nextIndex = (index + 1) % columnWidths.length;
|
||||||
|
columnWidths[index] = newWidth;
|
||||||
|
columnWidths[nextIndex] = (columnWidths[nextIndex] - actualDelta)
|
||||||
|
.clamp(_minColumnWidth, _maxColumnWidth);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildHeader() {
|
||||||
|
return Container(
|
||||||
|
decoration: containerDecoration.copyWith(
|
||||||
|
color: ColorsManager.circleRolesBackground,
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(15),
|
||||||
|
topRight: Radius.circular(15),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
for (int i = 0; i < widget.titles.length; i++)
|
||||||
|
_HeaderColumn(
|
||||||
|
title: widget.titles[i],
|
||||||
|
width: columnWidths[i],
|
||||||
|
showFilter: i != 1 && i != 9 && i != 8 && i != 5,
|
||||||
|
onFilter: () => widget.onFilter?.call(i),
|
||||||
|
onResize: (delta) => _handleColumnResize(i, delta),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBody() {
|
||||||
|
if (widget.rows.isEmpty) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 300,
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(Assets.emptyTable),
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
const Text(
|
||||||
|
'No Users',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: containerDecoration.copyWith(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(15),
|
||||||
|
bottomRight: Radius.circular(15),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
for (int rowIndex = 0; rowIndex < widget.rows.length; rowIndex++)
|
||||||
|
_TableRow(
|
||||||
|
cells: widget.rows[rowIndex],
|
||||||
|
columnWidths: columnWidths,
|
||||||
|
isLast: rowIndex == widget.rows.length - 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final availableWidth = constraints.maxWidth;
|
||||||
|
final totalDividersWidth = (widget.titles.length - 1) * _dividerWidth;
|
||||||
|
|
||||||
|
if (_lastAvailableWidth != availableWidth) {
|
||||||
|
final equalWidth =
|
||||||
|
(availableWidth - totalDividersWidth) / widget.titles.length;
|
||||||
|
final clampedWidth =
|
||||||
|
equalWidth.clamp(_minColumnWidth, _maxColumnWidth);
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
setState(() {
|
||||||
|
columnWidths = List.filled(widget.titles.length, clampedWidth);
|
||||||
|
_lastAvailableWidth = availableWidth;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final totalTableWidth =
|
||||||
|
columnWidths.fold(0.0, (sum, w) => sum + w) + totalDividersWidth;
|
||||||
|
return SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Container(
|
||||||
|
width: totalTableWidth,
|
||||||
|
decoration: containerDecoration.copyWith(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildHeader(),
|
||||||
|
_buildBody(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,6 +13,8 @@ import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/vi
|
|||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/de_activate_filter.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/de_activate_filter.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/name_filter.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/name_filter.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/user_table.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/user_table.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/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/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
@ -25,7 +27,7 @@ class UsersPage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final TextEditingController searchController = TextEditingController();
|
final TextEditingController searchController = TextEditingController();
|
||||||
|
|
||||||
Widget actionButton({required String title, required Function()? onTap}) {
|
Widget actionButton({bool isActive = false, required String title, Function()? onTap}) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -33,7 +35,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
color: title == "Delete"
|
color: isActive == false && title != "Delete"
|
||||||
|
? Colors.grey
|
||||||
|
: title == "Delete"
|
||||||
? ColorsManager.red
|
? ColorsManager.red
|
||||||
: ColorsManager.spaceColor,
|
: ColorsManager.spaceColor,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@ -56,8 +60,7 @@ class UsersPage extends StatelessWidget {
|
|||||||
: ColorsManager.disabledPink.withOpacity(0.5),
|
: ColorsManager.disabledPink.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 5, top: 5),
|
||||||
const EdgeInsets.only(left: 10, right: 10, bottom: 5, top: 5),
|
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
@ -81,15 +84,12 @@ class UsersPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget changeIconStatus(
|
Widget changeIconStatus(
|
||||||
{required String userId,
|
{required String userId, required String status, required Function()? onTap}) {
|
||||||
required String status,
|
|
||||||
required Function()? onTap}) {
|
|
||||||
return Center(
|
return Center(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding: const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5),
|
||||||
const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5),
|
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
status == "invited"
|
status == "invited"
|
||||||
? Assets.invitedIcon
|
? Assets.invitedIcon
|
||||||
@ -108,7 +108,6 @@ class UsersPage extends StatelessWidget {
|
|||||||
final screenSize = MediaQuery.of(context).size;
|
final screenSize = MediaQuery.of(context).size;
|
||||||
final _blocRole = BlocProvider.of<UserTableBloc>(context);
|
final _blocRole = BlocProvider.of<UserTableBloc>(context);
|
||||||
if (state is UsersLoadingState) {
|
if (state is UsersLoadingState) {
|
||||||
_blocRole.add(ChangePage(_blocRole.currentPage));
|
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
} else if (state is UsersLoadedState) {
|
} else if (state is UsersLoadedState) {
|
||||||
return Padding(
|
return Padding(
|
||||||
@ -130,9 +129,12 @@ class UsersPage extends StatelessWidget {
|
|||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: searchController,
|
controller: searchController,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context
|
final bloc = context.read<UserTableBloc>();
|
||||||
.read<UserTableBloc>()
|
bloc.add(FilterClearEvent());
|
||||||
.add(SearchUsers(value));
|
bloc.add(SearchUsers(value));
|
||||||
|
if (value == '') {
|
||||||
|
bloc.add(ChangePage(1));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
style: const TextStyle(color: Colors.black),
|
style: const TextStyle(color: Colors.black),
|
||||||
decoration: textBoxDecoration(radios: 15)!.copyWith(
|
decoration: textBoxDecoration(radios: 15)!.copyWith(
|
||||||
@ -155,6 +157,7 @@ class UsersPage extends StatelessWidget {
|
|||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
@ -193,14 +196,10 @@ class UsersPage extends StatelessWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortOrder,
|
||||||
aToZTap: () {
|
aToZTap: () {
|
||||||
context
|
context.read<UserTableBloc>().add(const SortUsersByNameAsc());
|
||||||
.read<UserTableBloc>()
|
|
||||||
.add(const SortUsersByNameAsc());
|
|
||||||
},
|
},
|
||||||
zToaTap: () {
|
zToaTap: () {
|
||||||
context
|
context.read<UserTableBloc>().add(const SortUsersByNameDesc());
|
||||||
.read<UserTableBloc>()
|
|
||||||
.add(const SortUsersByNameDesc());
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -209,13 +208,12 @@ class UsersPage extends StatelessWidget {
|
|||||||
for (var item in _blocRole.jobTitle)
|
for (var item in _blocRole.jobTitle)
|
||||||
item: _blocRole.selectedJobTitles.contains(item),
|
item: _blocRole.selectedJobTitles.contains(item),
|
||||||
};
|
};
|
||||||
final RenderBox overlay = Overlay.of(context)
|
final RenderBox overlay =
|
||||||
.context
|
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
.findRenderObject() as RenderBox;
|
|
||||||
|
|
||||||
showPopUpFilterMenu(
|
showPopUpFilterMenu(
|
||||||
position: RelativeRect.fromLTRB(
|
position: RelativeRect.fromLTRB(
|
||||||
overlay.size.width / 4,
|
overlay.size.width / 5.3,
|
||||||
240,
|
240,
|
||||||
overlay.size.width / 4,
|
overlay.size.width / 4,
|
||||||
0,
|
0,
|
||||||
@ -223,8 +221,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
list: _blocRole.jobTitle,
|
list: _blocRole.jobTitle,
|
||||||
context: context,
|
context: context,
|
||||||
checkboxStates: checkboxStates,
|
checkboxStates: checkboxStates,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortJopTitle,
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
|
searchController.clear();
|
||||||
_blocRole.add(FilterClearEvent());
|
_blocRole.add(FilterClearEvent());
|
||||||
final selectedItems = checkboxStates.entries
|
final selectedItems = checkboxStates.entries
|
||||||
.where((entry) => entry.value)
|
.where((entry) => entry.value)
|
||||||
@ -233,14 +232,14 @@ class UsersPage extends StatelessWidget {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
_blocRole.add(FilterUsersByJobEvent(
|
_blocRole.add(FilterUsersByJobEvent(
|
||||||
selectedJob: selectedItems,
|
selectedJob: selectedItems,
|
||||||
sortOrder: _blocRole.currentSortOrder,
|
sortOrder: _blocRole.currentSortJopTitle,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
onSortAtoZ: (v) {
|
onSortAtoZ: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortJopTitle = v;
|
||||||
},
|
},
|
||||||
onSortZtoA: (v) {
|
onSortZtoA: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortJopTitle = v;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -250,9 +249,8 @@ class UsersPage extends StatelessWidget {
|
|||||||
for (var item in _blocRole.roleTypes)
|
for (var item in _blocRole.roleTypes)
|
||||||
item: _blocRole.selectedRoles.contains(item),
|
item: _blocRole.selectedRoles.contains(item),
|
||||||
};
|
};
|
||||||
final RenderBox overlay = Overlay.of(context)
|
final RenderBox overlay =
|
||||||
.context
|
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
.findRenderObject() as RenderBox;
|
|
||||||
showPopUpFilterMenu(
|
showPopUpFilterMenu(
|
||||||
position: RelativeRect.fromLTRB(
|
position: RelativeRect.fromLTRB(
|
||||||
overlay.size.width / 4,
|
overlay.size.width / 4,
|
||||||
@ -263,24 +261,24 @@ class UsersPage extends StatelessWidget {
|
|||||||
list: _blocRole.roleTypes,
|
list: _blocRole.roleTypes,
|
||||||
context: context,
|
context: context,
|
||||||
checkboxStates: checkboxStates,
|
checkboxStates: checkboxStates,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortRole,
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
|
searchController.clear();
|
||||||
_blocRole.add(FilterClearEvent());
|
_blocRole.add(FilterClearEvent());
|
||||||
final selectedItems = checkboxStates.entries
|
final selectedItems = checkboxStates.entries
|
||||||
.where((entry) => entry.value)
|
.where((entry) => entry.value)
|
||||||
.map((entry) => entry.key)
|
.map((entry) => entry.key)
|
||||||
.toList();
|
.toList();
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
context.read<UserTableBloc>().add(
|
context.read<UserTableBloc>().add(FilterUsersByRoleEvent(
|
||||||
FilterUsersByRoleEvent(
|
|
||||||
selectedRoles: selectedItems,
|
selectedRoles: selectedItems,
|
||||||
sortOrder: _blocRole.currentSortOrder));
|
sortOrder: _blocRole.currentSortRole));
|
||||||
},
|
},
|
||||||
onSortAtoZ: (v) {
|
onSortAtoZ: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortRole = v;
|
||||||
},
|
},
|
||||||
onSortZtoA: (v) {
|
onSortZtoA: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortRole = v;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -289,14 +287,10 @@ class UsersPage extends StatelessWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortOrder,
|
||||||
aToZTap: () {
|
aToZTap: () {
|
||||||
context
|
context.read<UserTableBloc>().add(const DateNewestToOldestEvent());
|
||||||
.read<UserTableBloc>()
|
|
||||||
.add(const DateNewestToOldestEvent());
|
|
||||||
},
|
},
|
||||||
zToaTap: () {
|
zToaTap: () {
|
||||||
context
|
context.read<UserTableBloc>().add(const DateOldestToNewestEvent());
|
||||||
.read<UserTableBloc>()
|
|
||||||
.add(const DateOldestToNewestEvent());
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -305,9 +299,8 @@ class UsersPage extends StatelessWidget {
|
|||||||
for (var item in _blocRole.createdBy)
|
for (var item in _blocRole.createdBy)
|
||||||
item: _blocRole.selectedCreatedBy.contains(item),
|
item: _blocRole.selectedCreatedBy.contains(item),
|
||||||
};
|
};
|
||||||
final RenderBox overlay = Overlay.of(context)
|
final RenderBox overlay =
|
||||||
.context
|
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
.findRenderObject() as RenderBox;
|
|
||||||
showPopUpFilterMenu(
|
showPopUpFilterMenu(
|
||||||
position: RelativeRect.fromLTRB(
|
position: RelativeRect.fromLTRB(
|
||||||
overlay.size.width / 1,
|
overlay.size.width / 1,
|
||||||
@ -318,8 +311,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
list: _blocRole.createdBy,
|
list: _blocRole.createdBy,
|
||||||
context: context,
|
context: context,
|
||||||
checkboxStates: checkboxStates,
|
checkboxStates: checkboxStates,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortCreatedBy,
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
|
searchController.clear();
|
||||||
_blocRole.add(FilterClearEvent());
|
_blocRole.add(FilterClearEvent());
|
||||||
final selectedItems = checkboxStates.entries
|
final selectedItems = checkboxStates.entries
|
||||||
.where((entry) => entry.value)
|
.where((entry) => entry.value)
|
||||||
@ -328,13 +322,13 @@ class UsersPage extends StatelessWidget {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
_blocRole.add(FilterUsersByCreatedEvent(
|
_blocRole.add(FilterUsersByCreatedEvent(
|
||||||
selectedCreatedBy: selectedItems,
|
selectedCreatedBy: selectedItems,
|
||||||
sortOrder: _blocRole.currentSortOrder));
|
sortOrder: _blocRole.currentSortCreatedBy));
|
||||||
},
|
},
|
||||||
onSortAtoZ: (v) {
|
onSortAtoZ: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortCreatedBy = v;
|
||||||
},
|
},
|
||||||
onSortZtoA: (v) {
|
onSortZtoA: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortCreatedBy = v;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -343,23 +337,23 @@ class UsersPage extends StatelessWidget {
|
|||||||
for (var item in _blocRole.status)
|
for (var item in _blocRole.status)
|
||||||
item: _blocRole.selectedStatuses.contains(item),
|
item: _blocRole.selectedStatuses.contains(item),
|
||||||
};
|
};
|
||||||
final RenderBox overlay = Overlay.of(context)
|
|
||||||
.context
|
final RenderBox overlay =
|
||||||
.findRenderObject() as RenderBox;
|
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
showPopUpFilterMenu(
|
showPopUpFilterMenu(
|
||||||
position: RelativeRect.fromLTRB(
|
position: RelativeRect.fromLTRB(
|
||||||
overlay.size.width / 0,
|
overlay.size.width / 0,
|
||||||
240,
|
240,
|
||||||
overlay.size.width / 4,
|
overlay.size.width / 5,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
list: _blocRole.status,
|
list: _blocRole.status,
|
||||||
context: context,
|
context: context,
|
||||||
checkboxStates: checkboxStates,
|
checkboxStates: checkboxStates,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortStatus,
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
|
searchController.clear();
|
||||||
_blocRole.add(FilterClearEvent());
|
_blocRole.add(FilterClearEvent());
|
||||||
|
|
||||||
final selectedItems = checkboxStates.entries
|
final selectedItems = checkboxStates.entries
|
||||||
.where((entry) => entry.value)
|
.where((entry) => entry.value)
|
||||||
.map((entry) => entry.key)
|
.map((entry) => entry.key)
|
||||||
@ -367,13 +361,13 @@ class UsersPage extends StatelessWidget {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
_blocRole.add(FilterUsersByDeActevateEvent(
|
_blocRole.add(FilterUsersByDeActevateEvent(
|
||||||
selectedActivate: selectedItems,
|
selectedActivate: selectedItems,
|
||||||
sortOrder: _blocRole.currentSortOrder));
|
sortOrder: _blocRole.currentSortStatus));
|
||||||
},
|
},
|
||||||
onSortAtoZ: (v) {
|
onSortAtoZ: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortStatus = v;
|
||||||
},
|
},
|
||||||
onSortZtoA: (v) {
|
onSortZtoA: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortStatus = v;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -382,14 +376,10 @@ class UsersPage extends StatelessWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
isSelected: _blocRole.currentSortOrderDate,
|
isSelected: _blocRole.currentSortOrderDate,
|
||||||
aToZTap: () {
|
aToZTap: () {
|
||||||
context
|
context.read<UserTableBloc>().add(const DateNewestToOldestEvent());
|
||||||
.read<UserTableBloc>()
|
|
||||||
.add(const DateNewestToOldestEvent());
|
|
||||||
},
|
},
|
||||||
zToaTap: () {
|
zToaTap: () {
|
||||||
context
|
context.read<UserTableBloc>().add(const DateOldestToNewestEvent());
|
||||||
.read<UserTableBloc>()
|
|
||||||
.add(const DateOldestToNewestEvent());
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -410,46 +400,34 @@ class UsersPage extends StatelessWidget {
|
|||||||
return [
|
return [
|
||||||
Text('${user.firstName} ${user.lastName}'),
|
Text('${user.firstName} ${user.lastName}'),
|
||||||
Text(user.email),
|
Text(user.email),
|
||||||
Text(user.jobTitle ?? '-'),
|
Text(user.jobTitle),
|
||||||
Text(user.roleType ?? ''),
|
Text(user.roleType ?? ''),
|
||||||
Text(user.createdDate ?? ''),
|
Text(user.createdDate ?? ''),
|
||||||
Text(user.createdTime ?? ''),
|
Text(user.createdTime ?? ''),
|
||||||
Text(user.invitedBy),
|
Text(user.invitedBy),
|
||||||
status(
|
status(
|
||||||
status: user.isEnabled == false
|
status: user.isEnabled == false ? 'disabled' : user.status,
|
||||||
? 'disabled'
|
|
||||||
: user.status,
|
|
||||||
),
|
),
|
||||||
changeIconStatus(
|
changeIconStatus(
|
||||||
status: user.isEnabled == false
|
status: user.isEnabled == false ? 'disabled' : user.status,
|
||||||
? 'disabled'
|
|
||||||
: user.status,
|
|
||||||
userId: user.uuid,
|
userId: user.uuid,
|
||||||
onTap: user.status != "invited"
|
onTap: user.status != "invited"
|
||||||
? () {
|
? () {
|
||||||
// final newStatus = user.status == 'active'
|
context.read<UserTableBloc>().add(ChangeUserStatus(
|
||||||
// ? 'disabled'
|
|
||||||
// : user.status == 'disabled'
|
|
||||||
// ? 'invited'
|
|
||||||
// : 'active';
|
|
||||||
context.read<UserTableBloc>().add(
|
|
||||||
ChangeUserStatus(
|
|
||||||
userId: user.uuid,
|
userId: user.uuid,
|
||||||
newStatus: user.isEnabled == false
|
newStatus:
|
||||||
? 'disabled'
|
user.isEnabled == false ? 'disabled' : user.status));
|
||||||
: user.status));
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
// actionButton(
|
user.isEnabled != false
|
||||||
// title: "Activity Log",
|
? actionButton(
|
||||||
// onTap: () {},
|
isActive: true,
|
||||||
// ),
|
|
||||||
actionButton(
|
|
||||||
title: "Edit",
|
title: "Edit",
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
@ -464,6 +442,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
: actionButton(
|
||||||
|
title: "Edit",
|
||||||
),
|
),
|
||||||
actionButton(
|
actionButton(
|
||||||
title: "Delete",
|
title: "Delete",
|
||||||
@ -472,13 +453,10 @@ class UsersPage extends StatelessWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return DeleteUserDialog(
|
return DeleteUserDialog(onTapDelete: () async {
|
||||||
onTapDelete: () async {
|
|
||||||
try {
|
try {
|
||||||
_blocRole.add(DeleteUserEvent(
|
_blocRole.add(DeleteUserEvent(user.uuid, context));
|
||||||
user.uuid, context));
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
await Future.delayed(
|
|
||||||
const Duration(seconds: 2));
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
@ -486,11 +464,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
).then((v) {
|
).then((v) {
|
||||||
if (v != null) {
|
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
_blocRole.add(const GetUsers());
|
_blocRole.add(const GetUsers());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -510,21 +486,14 @@ class UsersPage extends StatelessWidget {
|
|||||||
visiblePagesCount: 4,
|
visiblePagesCount: 4,
|
||||||
buttonRadius: 10,
|
buttonRadius: 10,
|
||||||
selectedButtonColor: ColorsManager.secondaryColor,
|
selectedButtonColor: ColorsManager.secondaryColor,
|
||||||
buttonUnSelectedBorderColor:
|
buttonUnSelectedBorderColor: ColorsManager.grayBorder,
|
||||||
ColorsManager.grayBorder,
|
lastPageIcon: const Icon(Icons.keyboard_double_arrow_right),
|
||||||
lastPageIcon:
|
firstPageIcon: const Icon(Icons.keyboard_double_arrow_left),
|
||||||
const Icon(Icons.keyboard_double_arrow_right),
|
totalPages:
|
||||||
firstPageIcon:
|
(_blocRole.totalUsersCount.length / _blocRole.itemsPerPage).ceil(),
|
||||||
const Icon(Icons.keyboard_double_arrow_left),
|
|
||||||
totalPages: (_blocRole.users.length /
|
|
||||||
_blocRole.itemsPerPage)
|
|
||||||
.ceil(),
|
|
||||||
currentPage: _blocRole.currentPage,
|
currentPage: _blocRole.currentPage,
|
||||||
onPageChanged: (int pageNumber) {
|
onPageChanged: (int pageNumber) {
|
||||||
_blocRole.currentPage = pageNumber;
|
context.read<UserTableBloc>().add(ChangePage(pageNumber));
|
||||||
context
|
|
||||||
.read<UserTableBloc>()
|
|
||||||
.add(ChangePage(pageNumber));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
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/common/bloc/project_manager.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/roles_and_permission/bloc/roles_permission_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_state.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_state.dart';
|
||||||
@ -8,6 +9,7 @@ import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bl
|
|||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/users_page.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/users_page.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/theme/responsive_text_theme.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
class RolesAndPermissionPage extends StatelessWidget {
|
class RolesAndPermissionPage extends StatelessWidget {
|
||||||
@ -26,11 +28,10 @@ class RolesAndPermissionPage extends StatelessWidget {
|
|||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: WebScaffold(
|
: WebScaffold(
|
||||||
enableMenuSidebar: false,
|
enableMenuSidebar: false,
|
||||||
appBarTitle: FittedBox(
|
appBarTitle: Text(
|
||||||
child: Text(
|
|
||||||
'Roles & Permissions',
|
'Roles & Permissions',
|
||||||
style: Theme.of(context).textTheme.headlineLarge,
|
style:
|
||||||
),
|
ResponsiveTextTheme.of(context).deviceManagementTitle,
|
||||||
),
|
),
|
||||||
rightBody: const NavigateHomeGridView(),
|
rightBody: const NavigateHomeGridView(),
|
||||||
centerBody: Row(
|
centerBody: Row(
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/ac_dialog.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/one_gang_switch_dialog.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/three_gang_switch_dialog.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/two_gang_switch_dialog.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
|
||||||
|
|
||||||
class DeviceDialogHelper {
|
|
||||||
static Future<Map<String, dynamic>?> showDeviceDialog(
|
|
||||||
BuildContext context,
|
|
||||||
Map<String, dynamic> data, {
|
|
||||||
required bool removeComparetors,
|
|
||||||
}) async {
|
|
||||||
final functions = data['functions'] as List<DeviceFunction>;
|
|
||||||
|
|
||||||
try {
|
|
||||||
final result = await _getDialogForDeviceType(
|
|
||||||
context,
|
|
||||||
data['productType'],
|
|
||||||
data,
|
|
||||||
functions,
|
|
||||||
removeComparetors: removeComparetors,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Error: $e');
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<Map<String, dynamic>?> _getDialogForDeviceType(
|
|
||||||
BuildContext context,
|
|
||||||
String productType,
|
|
||||||
Map<String, dynamic> data,
|
|
||||||
List<DeviceFunction> functions,
|
|
||||||
{required bool removeComparetors}) async {
|
|
||||||
final routineBloc = context.read<RoutineBloc>();
|
|
||||||
final deviceSelectedFunctions =
|
|
||||||
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
|
|
||||||
|
|
||||||
switch (productType) {
|
|
||||||
case 'AC':
|
|
||||||
return ACHelper.showACFunctionsDialog(
|
|
||||||
context,
|
|
||||||
functions,
|
|
||||||
data['device'],
|
|
||||||
deviceSelectedFunctions,
|
|
||||||
data['uniqueCustomId'],
|
|
||||||
removeComparetors);
|
|
||||||
|
|
||||||
case '1G':
|
|
||||||
return OneGangSwitchHelper.showSwitchFunctionsDialog(
|
|
||||||
context,
|
|
||||||
functions,
|
|
||||||
data['device'],
|
|
||||||
deviceSelectedFunctions,
|
|
||||||
data['uniqueCustomId'],
|
|
||||||
removeComparetors);
|
|
||||||
case '2G':
|
|
||||||
return TwoGangSwitchHelper.showSwitchFunctionsDialog(
|
|
||||||
context,
|
|
||||||
functions,
|
|
||||||
data['device'],
|
|
||||||
deviceSelectedFunctions,
|
|
||||||
data['uniqueCustomId'],
|
|
||||||
removeComparetors);
|
|
||||||
case '3G':
|
|
||||||
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(
|
|
||||||
context,
|
|
||||||
functions,
|
|
||||||
data['device'],
|
|
||||||
deviceSelectedFunctions,
|
|
||||||
data['uniqueCustomId'],
|
|
||||||
removeComparetors);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class RoutinesView extends StatefulWidget {
|
|
||||||
const RoutinesView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<RoutinesView> createState() => _RoutinesViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RoutinesViewState extends State<RoutinesView> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
if (state.createRoutineView) {
|
|
||||||
return const CreateNewRoutineView();
|
|
||||||
}
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Create New Routines",
|
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
RoutineViewCard(
|
|
||||||
onTap: () {
|
|
||||||
context.read<RoutineBloc>().add(
|
|
||||||
(ResetRoutineState()),
|
|
||||||
);
|
|
||||||
BlocProvider.of<RoutineBloc>(context).add(
|
|
||||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: Icons.add,
|
|
||||||
textString: '',
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 15,
|
|
||||||
),
|
|
||||||
const Expanded(child: FetchRoutineScenesAutomation()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
|
||||||
|
|
||||||
class FetchRoutineScenesAutomation extends StatefulWidget {
|
|
||||||
const FetchRoutineScenesAutomation({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<FetchRoutineScenesAutomation> createState() => _FetchRoutineScenesState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
|
|
||||||
with HelperResponsiveLayout {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
context.read<RoutineBloc>()
|
|
||||||
..add(const LoadScenes(spaceId, communityId))
|
|
||||||
..add(const LoadAutomation(spaceId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return state.isLoading
|
|
||||||
? const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
)
|
|
||||||
: SingleChildScrollView(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Scenes (Tab to Run)",
|
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
if (state.scenes.isEmpty)
|
|
||||||
Text(
|
|
||||||
"No scenes found",
|
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (state.scenes.isNotEmpty)
|
|
||||||
ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxHeight: isSmallScreenSize(context) ? 160 : 170,
|
|
||||||
),
|
|
||||||
child: ListView.builder(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
itemCount: state.scenes.length,
|
|
||||||
itemBuilder: (context, index) => Padding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
|
||||||
),
|
|
||||||
child: RoutineViewCard(
|
|
||||||
onTap: () {
|
|
||||||
BlocProvider.of<RoutineBloc>(context).add(
|
|
||||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
|
||||||
);
|
|
||||||
context.read<RoutineBloc>().add(
|
|
||||||
GetSceneDetails(
|
|
||||||
sceneId: state.scenes[index].id,
|
|
||||||
isTabToRun: true,
|
|
||||||
isUpdate: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
textString: state.scenes[index].name,
|
|
||||||
icon: state.scenes[index].icon ?? Assets.logoHorizontal,
|
|
||||||
isFromScenes: true,
|
|
||||||
iconInBytes: state.scenes[index].iconInBytes,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 15),
|
|
||||||
Text(
|
|
||||||
"Automations",
|
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
if (state.automations.isEmpty)
|
|
||||||
Text(
|
|
||||||
"No automations found",
|
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (state.automations.isNotEmpty)
|
|
||||||
ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxHeight: isSmallScreenSize(context) ? 160 : 170,
|
|
||||||
),
|
|
||||||
child: ListView.builder(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
itemCount: state.automations.length,
|
|
||||||
itemBuilder: (context, index) => Padding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
|
||||||
),
|
|
||||||
child: RoutineViewCard(
|
|
||||||
onTap: () {
|
|
||||||
BlocProvider.of<RoutineBloc>(context).add(
|
|
||||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
|
||||||
);
|
|
||||||
context.read<RoutineBloc>().add(
|
|
||||||
GetAutomationDetails(
|
|
||||||
automationId: state.automations[index].id,
|
|
||||||
isAutomation: true,
|
|
||||||
isUpdate: true),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
textString: state.automations[index].name,
|
|
||||||
icon: state.automations[index].icon ?? Assets.automation,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
|
||||||
|
|
||||||
class RoutineViewCard extends StatelessWidget with HelperResponsiveLayout {
|
|
||||||
const RoutineViewCard({
|
|
||||||
super.key,
|
|
||||||
required this.onTap,
|
|
||||||
required this.icon,
|
|
||||||
required this.textString,
|
|
||||||
this.isFromScenes,
|
|
||||||
this.iconInBytes,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Function() onTap;
|
|
||||||
final dynamic icon;
|
|
||||||
final String textString;
|
|
||||||
final bool? isFromScenes;
|
|
||||||
final Uint8List? iconInBytes;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final double cardWidth = isSmallScreenSize(context)
|
|
||||||
? 120
|
|
||||||
: isMediumScreenSize(context)
|
|
||||||
? 135
|
|
||||||
: 150;
|
|
||||||
|
|
||||||
final double cardHeight = isSmallScreenSize(context) ? 160 : 170;
|
|
||||||
|
|
||||||
final double iconSize = isSmallScreenSize(context)
|
|
||||||
? 50
|
|
||||||
: isMediumScreenSize(context)
|
|
||||||
? 60
|
|
||||||
: 70;
|
|
||||||
|
|
||||||
return ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxWidth: cardWidth,
|
|
||||||
maxHeight: cardHeight,
|
|
||||||
),
|
|
||||||
child: Card(
|
|
||||||
elevation: 3,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: onTap,
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
Center(
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.graysColor,
|
|
||||||
borderRadius: BorderRadius.circular(120),
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.greyColor,
|
|
||||||
width: 2.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
height: iconSize,
|
|
||||||
width: iconSize,
|
|
||||||
child: (isFromScenes ?? false)
|
|
||||||
? (iconInBytes != null &&
|
|
||||||
iconInBytes?.isNotEmpty == true)
|
|
||||||
? Image.memory(
|
|
||||||
iconInBytes!,
|
|
||||||
height: iconSize,
|
|
||||||
width: iconSize,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
errorBuilder: (context, error, stackTrace) =>
|
|
||||||
Image.asset(
|
|
||||||
Assets.logo,
|
|
||||||
height: iconSize,
|
|
||||||
width: iconSize,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Image.asset(
|
|
||||||
Assets.logo,
|
|
||||||
height: iconSize,
|
|
||||||
width: iconSize,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
)
|
|
||||||
: (icon is String && icon.endsWith('.svg'))
|
|
||||||
? SvgPicture.asset(
|
|
||||||
icon,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
)
|
|
||||||
: Icon(
|
|
||||||
icon,
|
|
||||||
color: ColorsManager.dialogBlueTitle,
|
|
||||||
size: isSmallScreenSize(context) ? 30 : 40,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 3),
|
|
||||||
child: Text(
|
|
||||||
textString,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
maxLines: 2,
|
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
|
||||||
color: ColorsManager.blackColor,
|
|
||||||
fontSize: isSmallScreenSize(context) ? 10 : 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
class AutomationStatusUpdate {
|
||||||
|
final String spaceUuid;
|
||||||
|
final bool isEnable;
|
||||||
|
|
||||||
|
AutomationStatusUpdate({
|
||||||
|
required this.spaceUuid,
|
||||||
|
required this.isEnable,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory AutomationStatusUpdate.fromRawJson(String str) =>
|
||||||
|
AutomationStatusUpdate.fromJson(json.decode(str));
|
||||||
|
|
||||||
|
String toRawJson() => json.encode(toJson());
|
||||||
|
|
||||||
|
factory AutomationStatusUpdate.fromJson(Map<String, dynamic> json) =>
|
||||||
|
AutomationStatusUpdate(
|
||||||
|
spaceUuid: json["spaceUuid"],
|
||||||
|
isEnable: json["isEnable"],
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
"spaceUuid": spaceUuid,
|
||||||
|
"isEnable": isEnable,
|
||||||
|
};
|
||||||
|
|
||||||
|
factory AutomationStatusUpdate.fromMap(Map<String, dynamic> map) =>
|
||||||
|
AutomationStatusUpdate(
|
||||||
|
spaceUuid: map["spaceUuid"],
|
||||||
|
isEnable: map["isEnable"],
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() => {
|
||||||
|
"spaceUuid": spaceUuid,
|
||||||
|
"isEnable": isEnable,
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
|
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||||
|
|
||||||
|
class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
|
||||||
|
CreateRoutineBloc() : super(const CreateRoutineInitial()) {
|
||||||
|
on<SpaceOnlyWithDevicesEvent>(_fetchSpaceOnlyWithDevices);
|
||||||
|
on<SaveCommunityIdAndSpaceIdEvent>(saveSpaceIdCommunityId);
|
||||||
|
on<ResetSelectedEvent>(resetSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
String selectedSpaceId = '';
|
||||||
|
String selectedCommunityId = '';
|
||||||
|
|
||||||
|
List<SpaceModel> spacesOnlyWithDevices = [];
|
||||||
|
|
||||||
|
Future<void> _fetchSpaceOnlyWithDevices(
|
||||||
|
SpaceOnlyWithDevicesEvent event, Emitter<CreateRoutineState> emit) async {
|
||||||
|
emit(const SpaceWithDeviceLoadingState());
|
||||||
|
|
||||||
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
|
spacesOnlyWithDevices = await CommunitySpaceManagementApi()
|
||||||
|
.getSpaceOnlyWithDevices(
|
||||||
|
communityId: event.communityID, projectId: projectUuid);
|
||||||
|
|
||||||
|
emit(SpaceWithDeviceLoadedState(spacesOnlyWithDevices));
|
||||||
|
} catch (e) {
|
||||||
|
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSpaceIdCommunityId(
|
||||||
|
SaveCommunityIdAndSpaceIdEvent event, Emitter<CreateRoutineState> emit) {
|
||||||
|
emit(const SpaceWithDeviceLoadingState());
|
||||||
|
selectedSpaceId = event.spaceID!;
|
||||||
|
selectedCommunityId = event.communityID!;
|
||||||
|
emit(const SelectedState());
|
||||||
|
}
|
||||||
|
|
||||||
|
resetSelected(ResetSelectedEvent event, Emitter<CreateRoutineState> emit) {
|
||||||
|
emit(const SpaceWithDeviceLoadingState());
|
||||||
|
selectedSpaceId = '';
|
||||||
|
selectedCommunityId = '';
|
||||||
|
emit(const ResetSelectedState());
|
||||||
|
}
|
||||||
|
}
|