Compare commits

..

63 Commits

Author SHA1 Message Date
3082148e8c Bug fixes 2 2024-09-29 12:03:58 +03:00
2fb18965f4 Bug fixes 2024-09-29 01:52:17 +03:00
8d784f1e95 fixes 2024-09-27 16:58:09 +03:00
bc1b92cd5c fixes 2024-09-26 16:47:19 +03:00
6e32f30970 fixes 2024-09-26 16:36:54 +03:00
781522d4b6 fixes 2024-09-26 16:36:23 +03:00
4e345db842 one gang wizard &two Gang wizard & wh wizard 2024-09-26 16:26:39 +03:00
8508995108 Merge pull request #53 from SyncrowIOT/491
491
2024-09-24 11:51:09 +03:00
e3a6579819 fixes bugs 5 2024-09-24 11:15:29 +03:00
9d8c40e44e bugs fixes 4 2024-09-24 10:35:56 +03:00
a811baca70 Fixed design issues 2024-09-24 00:28:46 +03:00
04e8131fb2 Bug fixes 3 2024-09-23 16:33:39 +03:00
dfae04076f Bug fixes 3 2024-09-23 16:33:02 +03:00
429009aefa bug fixes 2 2024-09-23 14:37:07 +03:00
62e80c89a2 Bug fixes 2024-09-23 00:35:07 +03:00
d97efe229d door sensor 2024-09-22 17:27:29 +03:00
58e13da887 door sensor 2024-09-22 15:32:47 +03:00
7279215cdc Added flavers env and prod for android and ios including Google services 2024-09-21 17:17:54 +03:00
e23210777a Merge pull request #52 from SyncrowIOT/sp_484
Sp 484
2024-09-21 16:40:44 +03:00
45ebd10980 Merge pull request #51 from SyncrowIOT/bugfix/SP-286
Two line error message
2024-09-21 15:49:47 +03:00
0b3f9de162 water heater and timer and schedule ui and api ,
Circulate ui and Inching ui
2024-09-21 13:20:10 +03:00
a46cec9dc5 water heater and timer and schedule ui and api ,
Circulate ui and Inching ui
2024-09-21 09:20:17 +03:00
09d1ce5ccb water heater and timer and schedule ui and api ,
Circulate ui and Inching ui
2024-09-21 08:56:30 +03:00
c3273c729d water heater and timer and schedule ui and api ,
Circulate ui and Inching ui
2024-09-21 08:53:43 +03:00
42e76f1c6e water heater and timer and schedule ui and api ,
Circulate ui and Inching ui
2024-09-21 08:45:55 +03:00
64e2ba2fd9 water heater and timer and schedule ui and api ,
Circulate ui and Inching ui
2024-09-21 08:28:29 +03:00
54cce48b89 water heater and timer and schedule ui and api ,
Circulate ui and Inching ui
2024-09-20 14:06:24 +03:00
f0feb4021f water heater and timer and schedule ui and api ,
Circulate ui and Inching ui
2024-09-20 11:50:39 +03:00
340ac35b3e display multiple error 2024-09-19 13:25:21 +04:00
af31d33778 display long error message in two line 2024-09-19 13:11:04 +04:00
26833cf215 Merge pull request #50 from SyncrowIOT/SP-465
Sp 465
2024-09-18 14:21:12 +03:00
6165c2ceee Merge remote-tracking branch 'origin/dev' into SP-465
# Conflicts:
#	lib/generated/assets.dart
2024-09-18 14:16:56 +03:00
65bb388daf schedule for one gang and two gang and three gange 2024-09-18 14:04:18 +03:00
b7f59902cd schedule for one gang and two gang and three gange 2024-09-18 13:19:43 +03:00
740ca4e4ba schedule for one gang and two gang and three gange 2024-09-18 13:01:15 +03:00
d9cd24e7f0 schedule for one gang and two gang and three gange 2024-09-18 13:00:46 +03:00
42b5ff105f schedule for one gang and two gang and three gange 2024-09-18 12:59:28 +03:00
ddaf36797d two gang schedule 2024-09-15 16:48:16 +03:00
ad47e34fa2 Implement Two-Gang & One-Gang 2024-09-15 11:05:06 +03:00
46662b5bac Implement Two-Gang & One-Gang 2024-09-15 10:15:37 +03:00
b5842194ff Implement Two-Gang & One-Gang 2024-09-12 16:59:03 +03:00
ba4ebd07e1 Merge pull request #49 from SyncrowIOT/bugfix/SP-292
Bugfix/SP-292
2024-09-09 12:22:30 +04:00
21c336360c revert 2024-09-06 10:40:45 +04:00
fee34703bd revert back 2024-09-06 10:33:39 +04:00
a92676d6a4 revert back to dev 2024-09-06 10:32:02 +04:00
8c5cf2c04e dialog 2024-09-06 10:25:54 +04:00
1f02f66916 changed stack to column 2024-09-06 10:20:52 +04:00
3ea089425c revert back change 2024-09-06 10:07:14 +04:00
76be98354b Bug fixes in the doorlock real time 2024-09-03 00:34:43 +03:00
3418fbe7b4 Merge pull request #48 from SyncrowIOT/sp-231
Sp 231
2024-09-02 15:05:31 +03:00
ea3bc4b5e1 curtain changes 2024-09-02 15:04:16 +03:00
77d2f54352 revert back dev 2024-09-02 13:38:49 +04:00
cff66bb653 revert back to dev 2024-09-02 13:35:25 +04:00
022ba53f5d Revert back to dev 2024-09-02 13:34:16 +04:00
bf69399af2 Merge remote-tracking branch 'origin/dev' into bugfix/SP-292 2024-09-02 13:27:08 +04:00
a72fc0b466 Added dialogue for success message 2024-09-02 13:25:58 +04:00
df13840a65 asset added of success icon 2024-09-02 13:25:33 +04:00
e63bf2a2c2 Merge pull request #47 from SyncrowIOT/bugfix/SP-286
fix: Shows only one error at a time for password validation error
2024-09-02 09:05:03 +04:00
bf944a6121 curtain changes 2024-09-01 10:21:04 +03:00
eb5aa56536 curtain changes 2024-08-29 16:57:15 +03:00
1e35bb8736 curtain changes 2024-08-29 16:56:19 +03:00
9c23ab1399 curtain changes 2024-08-29 16:54:43 +03:00
b3bb0b9eea fix: Correct error message and improve consistency in passwordValidator 2024-08-29 16:37:49 +04:00
135 changed files with 10639 additions and 2130 deletions

25
.vscode/launch.json vendored
View File

@ -1,6 +1,7 @@
{
"configurations": [
{
"name": "DEVELOPMENT",
@ -11,9 +12,13 @@
"args": [
"--dart-define",
"--flavor",
"FLAVOR=development"
"dev",
"-t",
"lib/main_dev.dart"
],
@ -29,9 +34,13 @@
"args": [
"--dart-define",
"--flavor",
"FLAVOR=staging"
"prod",
"-t",
"lib/main.dart"
],
@ -47,9 +56,13 @@
"args": [
"--dart-define",
"--flavor",
"FLAVOR=production"
"prod",
"-t",
"lib/main.dart"
],

View File

@ -43,7 +43,7 @@ Open a pull request on the DEV branch and add a reviewer to it.
To test the app, we use Firebase Distribution to send testing builds of the app to the testers.
- Create an Android build for testing with the command: `flutter build apk --dart-define FLAVOR=staging --build-name={build_version}-qa --build-number={build_number}`.
- Create an Android build for testing with the command: `flutter build apk --flavor prod -t lib/main.dart`.
- Upload the apk file to Firebase distribution
@ -61,7 +61,7 @@ To test the app, we use Firebase Distribution to send testing builds of the app
To test the app, we use Firebase Distribution to send testing builds of the app to the testers.
1- Create an iOS for testing with the command: `flutter build ios --dart-define FLAVOR=staging --build-name=1.0.0-qa --build-number=1`.
1- Create an iOS for testing with the command: `flutter build ios --flavor prod -t lib/main.dart`.
2- Create an archive of your app: Open Xcode and go to the "Product" menu, then select "Archive" to create an archive of your app. Make sure to select the "Generic iOS Device" as the build destination.
@ -79,7 +79,7 @@ To test the app, we use Firebase Distribution to send testing builds of the app
You can also create an archive through these commands lines:
1- Create an iOS for testing with the command: `flutter build ios --dart-define FLAVOR=staging --build-name={build_version}-qa --build-number={build_number}`.
1- Create an iOS for testing with the command: `flutter build ios --flavor prod -t lib/main.dart`.
2- Create an archive with this command: `xcodebuild -workspace Runner.xcworkspace -scheme Runner -archivePath "build/Runner.xcarchive" archive`.

View File

@ -44,6 +44,18 @@ android {
main.java.srcDirs += 'src/main/kotlin'
}
flavorDimensions "env"
productFlavors {
dev {
dimension "env"
applicationId "com.example.syncrow_application"
}
prod {
dimension "env"
applicationId "com.example.syncrow_application"
}
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.syncrow_application"

View File

@ -1,48 +0,0 @@
{
"project_info": {
"project_number": "427332280600",
"project_id": "test2-8a3d2",
"storage_bucket": "test2-8a3d2.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:427332280600:android:550f67441246cb1a0c7e6d",
"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:bb6047adeeb80fb00c7e6d",
"android_client_info": {
"package_name": "com.example.syncrow_application"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View File

@ -0,0 +1,48 @@
{
"project_info": {
"project_number": "427332280600",
"project_id": "test2-8a3d2",
"storage_bucket": "test2-8a3d2.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:427332280600:android:550f67441246cb1a0c7e6d",
"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:bb6047adeeb80fb00c7e6d",
"android_client_info": {
"package_name": "com.example.syncrow_application"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View File

@ -0,0 +1,30 @@
{
"project_info": {
"project_number": "786692570726",
"firebase_url": "https://syncrow-staging-default-rtdb.firebaseio.com",
"project_id": "syncrow-staging",
"storage_bucket": "syncrow-staging.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:786692570726:android:0ef7079c2b978d4417b7a7",
"android_client_info": {
"package_name": "com.example.syncrow_application"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyDP9GpYfLE8gHTj3kZ1hW8fx_FkJqOqSQk"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

5
assets/icons/1gang.svg Normal file
View File

@ -0,0 +1,5 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M38.0142 39.2553L35.3682 40H20.9308H19.9999H19.0691H1.24111C0.555643 40 0 39.4444 0 38.7589V1.24111C0 0.555643 0.555643 0 1.24111 0H19.0682H20.1226H20.9543H35.4255L38.2625 1.24111C38.9479 1.24111 39.5036 1.79675 39.5036 2.48221L39.2553 38.0142C39.2553 38.6997 38.6997 39.2553 38.0142 39.2553Z" fill="#E9E9E9"/>
<path d="M38.7589 0H35.0356C35.721 0 36.2767 0.555643 36.2767 1.24111V38.7589C36.2767 39.4444 35.721 40 35.0356 40H38.7589C39.4444 40 40 39.4444 40 38.7589V1.24111C40 0.555643 39.4444 0 38.7589 0Z" fill="#D1D1D1"/>
<path opacity="0.6" d="M21.375 31.8319V33.3213C21.375 34.0067 20.9553 34.5624 20.4375 34.5624H16.3125C15.7947 34.5624 15.375 34.0067 15.375 33.3213V31.8319C15.375 31.1465 15.7947 30.5908 16.3125 30.5908H20.4375C20.9553 30.5908 21.375 31.1465 21.375 31.8319Z" fill="#023DFE" fill-opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 933 B

7
assets/icons/2gang.svg Normal file
View File

@ -0,0 +1,7 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M38.0142 39.2553L35.3682 40H20.9308H19.9999H19.0691H1.24111C0.555643 40 0 39.4444 0 38.7589V1.24111C0 0.555643 0.555643 0 1.24111 0H19.0682H20.1226H20.9543H35.4255L38.2625 1.24111C38.9479 1.24111 39.5036 1.79675 39.5036 2.48221L39.2553 38.0142C39.2553 38.6997 38.6997 39.2553 38.0142 39.2553Z" fill="#E9E9E9"/>
<path d="M38.7589 0H35.0356C35.721 0 36.2767 0.555643 36.2767 1.24111V38.7589C36.2767 39.4444 35.721 40 35.0356 40H38.7589C39.4444 40 40 39.4444 40 38.7589V1.24111C40 0.555643 39.4444 0 38.7589 0Z" fill="#D1D1D1"/>
<path opacity="0.6" d="M12.0284 31.8319V33.3213C12.0284 34.0067 11.6087 34.5624 11.0909 34.5624H6.96594C6.44816 34.5624 6.02844 34.0067 6.02844 33.3213V31.8319C6.02844 31.1465 6.44816 30.5908 6.96594 30.5908H11.0909C11.6087 30.5908 12.0284 31.1465 12.0284 31.8319Z" fill="#023DFE" fill-opacity="0.5"/>
<path opacity="0.6" d="M26.0285 31.8319V33.3213C26.0285 34.0067 26.4482 34.5624 26.966 34.5624H31.091C31.6088 34.5624 32.0285 34.0067 32.0285 33.3213V31.8319C32.0285 31.1465 31.6088 30.5908 31.091 30.5908H26.966C26.4482 30.5908 26.0285 31.1465 26.0285 31.8319Z" fill="#023DFE" fill-opacity="0.5"/>
<path d="M19.0691 0H20.9308V40H19.0691V0Z" fill="#D1D1D1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,47 @@
<svg width="201" height="260" viewBox="0 0 201 260" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_3851_4852)">
<g filter="url(#filter1_i_3851_4852)">
<path d="M1 32.5794C1 17.65 11.9782 4.87264 26.8261 3.31376C56.9938 0.146434 80.4127 0.288676 110.23 3.38644C125.15 4.93649 136.229 17.743 136.229 32.7433V219.157C136.229 233.932 125.474 246.635 110.8 248.355C80.8281 251.869 57.0283 251.901 26.4597 248.336C11.7726 246.623 1 233.917 1 219.131V32.5794Z" fill="#EAF6FF"/>
</g>
<path d="M116.627 154.669C117.475 154.669 118.323 154.345 118.971 153.698C120.266 152.403 120.266 150.304 118.971 149.009C107.888 137.927 107.888 119.894 118.971 108.812C120.266 107.517 120.266 105.418 118.971 104.123C117.676 102.829 115.577 102.829 114.283 104.123C100.615 117.792 100.615 140.03 114.283 153.698C114.93 154.345 115.778 154.669 116.627 154.669Z" fill="#B3DAFE"/>
<path d="M123.6 141.79C124.312 141.79 125.024 141.518 125.567 140.975C126.653 139.889 126.653 138.127 125.566 137.041C123.395 134.87 122.199 131.982 122.199 128.911C122.199 125.839 123.395 122.952 125.566 120.78C126.653 119.694 126.653 117.933 125.567 116.847C124.48 115.76 122.719 115.76 121.633 116.846C118.411 120.069 116.636 124.353 116.636 128.911C116.636 133.468 118.41 137.753 121.633 140.975C122.176 141.518 122.888 141.79 123.6 141.79Z" fill="#B3DAFE"/>
<path d="M74.4947 201.887L74.4947 214.513C74.4947 217.026 72.4581 219.063 69.9447 219.063C67.4313 219.063 65.3948 217.026 65.3948 214.513L65.3948 201.887C65.3948 199.374 67.4313 197.337 69.9447 197.337C72.4581 197.337 74.4947 199.374 74.4947 201.887Z" fill="#B3DAFE"/>
<g filter="url(#filter2_i_3851_4852)">
<path d="M146.229 60.2459C146.229 53.612 150.555 47.5909 157.072 46.3483C165.305 44.7783 172.168 44.839 180.304 46.382C186.889 47.6306 191.305 53.6871 191.305 60.3888V203.89C191.305 210.378 187.172 216.307 180.833 217.686C172.408 219.518 165.306 219.531 156.73 217.674C150.379 216.299 146.229 210.366 146.229 203.867V60.2459Z" fill="#EAF6FF"/>
</g>
<path d="M162.423 103.153C161.575 103.153 160.727 103.476 160.079 104.124C158.784 105.419 158.784 107.517 160.079 108.812C171.162 119.894 171.162 137.927 160.079 149.009C158.784 150.305 158.784 152.403 160.079 153.698C161.374 154.992 163.473 154.992 164.767 153.698C178.435 140.03 178.435 117.791 164.767 104.123C164.12 103.476 163.272 103.153 162.423 103.153Z" fill="#B3DAFE"/>
<path d="M155.45 116.032C154.738 116.032 154.026 116.303 153.483 116.847C152.397 117.933 152.397 119.694 153.484 120.78C155.655 122.952 156.851 125.839 156.851 128.911C156.851 131.982 155.655 134.869 153.484 137.041C152.397 138.128 152.397 139.889 153.483 140.975C154.57 142.061 156.331 142.061 157.417 140.975C160.639 137.753 162.414 133.468 162.414 128.911C162.414 124.353 160.64 120.069 157.417 116.846C156.874 116.304 156.162 116.032 155.45 116.032Z" fill="#B3DAFE"/>
</g>
<defs>
<filter id="filter0_d_3851_4852" x="0" y="0" width="200.305" height="260" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="4" dy="4"/>
<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.2 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3851_4852"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3851_4852" result="shape"/>
</filter>
<filter id="filter1_i_3851_4852" x="0" y="1" width="136.229" height="250" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-1"/>
<feGaussianBlur stdDeviation="10"/>
<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.3 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_3851_4852"/>
</filter>
<filter id="filter2_i_3851_4852" x="144.229" y="45.1975" width="47.0764" height="173.866" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-2"/>
<feGaussianBlur stdDeviation="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.3 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_3851_4852"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -0,0 +1,10 @@
<svg width="44" height="50" viewBox="0 0 44 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24.9023 9.10478C24.0934 9.10478 23.4375 8.44893 23.4375 7.63994V4.39453C23.4375 3.58682 22.7804 2.92969 21.9727 2.92969C21.1649 2.92969 20.5078 3.58682 20.5078 4.39453V7.63994C20.5078 8.44893 19.852 9.10478 19.043 9.10478C18.234 9.10478 17.5781 8.44893 17.5781 7.63994V4.39453C17.5781 1.97139 19.5495 0 21.9727 0C24.3958 0 26.3672 1.97139 26.3672 4.39453V7.63994C26.3672 8.44893 25.7113 9.10478 24.9023 9.10478Z" fill="#FFB454"/>
<path d="M23.4375 4.39453V7.63994C23.4375 8.44893 24.0934 9.10478 24.9023 9.10478C25.7113 9.10478 26.3672 8.44893 26.3672 7.63994V4.39453C26.3672 1.97139 24.3958 0 21.9727 0V2.92969C22.7805 2.92969 23.4375 3.58682 23.4375 4.39453Z" fill="#FF8E00"/>
<path d="M21.9727 50C17.9341 50 14.6484 46.7144 14.6484 42.6758C14.6484 41.8668 15.3043 41.2109 16.1133 41.2109H27.832C28.641 41.2109 29.2969 41.8668 29.2969 42.6758C29.2969 46.7144 26.0113 50 21.9727 50Z" fill="#FFB454"/>
<path d="M27.832 41.2109H21.9727V50C26.0112 50 29.2969 46.7144 29.2969 42.6758C29.2969 41.8668 28.641 41.2109 27.832 41.2109Z" fill="#FF8E00"/>
<path d="M42.4805 44.1406H1.46486C0.877946 44.1406 0.34777 43.7903 0.117497 43.2505C-0.112777 42.7106 0.00138367 42.0855 0.407634 41.6619C4.55295 37.3389 6.83595 31.6595 6.83595 25.6701V20.9961C6.83595 12.6497 13.6263 5.85938 21.9727 5.85938C30.3191 5.85938 37.1094 12.6497 37.1094 20.9961V25.6701C37.1094 31.6596 39.3924 37.3389 43.5378 41.6619C43.944 42.0855 44.0581 42.7106 43.8279 43.2505C43.5977 43.7903 43.0674 44.1406 42.4805 44.1406Z" fill="#FFE278"/>
<path d="M42.4805 44.1406C43.0674 44.1406 43.5976 43.7903 43.8278 43.2505C44.0581 42.7106 43.9439 42.0855 43.5378 41.6619C39.3924 37.3389 37.1094 31.6595 37.1094 25.6701V20.9961C37.1094 12.6497 30.319 5.85938 21.9727 5.85938V44.1406H42.4805Z" fill="#FFB454"/>
<path d="M42.4803 22.4612C41.6713 22.4612 41.0154 21.8053 41.0154 20.9963C41.0154 15.9097 39.0347 11.1276 35.4379 7.53091C34.8658 6.95884 34.8658 6.0314 35.4379 5.45933C36.0099 4.88726 36.9374 4.88726 37.5095 5.45933C41.6596 9.60933 43.9451 15.1272 43.9451 20.9963C43.9451 21.8053 43.2893 22.4612 42.4803 22.4612Z" fill="#08475E"/>
<path d="M1.46484 22.4612C0.655859 22.4612 0 21.8053 0 20.9963C0 15.1272 2.28555 9.60942 6.43564 5.45933C7.00762 4.88726 7.93516 4.88726 8.50723 5.45933C9.0793 6.0314 9.0793 6.95884 8.50723 7.53091C4.91055 11.1277 2.92969 15.9098 2.92969 20.9963C2.92969 21.8053 2.27383 22.4612 1.46484 22.4612Z" fill="#0A789B"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,18 @@
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.61102 32.55L0.0294905 14.2492C-0.0650406 13.9826 0.0752911 13.6874 0.341795 13.5901C8.9949 10.4779 18.7455 7.58334 27.0805 4.02691C27.453 3.79194 27.7453 4.02407 27.9057 4.46821L38.2465 31.1229L41.0545 38.9321C41.149 39.1986 41.0115 39.4967 40.745 39.5913L20.9575 46.707L13.2441 49.4811C12.9776 49.5786 12.6825 49.4381 12.5851 49.1716L6.61102 32.55Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.098 26.4772L8.81158 7.31083C8.76285 7.02997 8.95201 6.76347 9.22994 6.71474L31.8627 2.83448L37.046 1.98047C37.3297 1.85723 37.791 2.00049 37.8998 2.63389L43.4985 30.5925L44.8997 38.7715C44.9484 39.0495 44.7593 39.3189 44.4813 39.3676L23.7568 42.9212L15.6767 44.3082C15.3988 44.3541 15.1294 44.165 15.0807 43.8869L12.098 26.4772Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.439 20.8256V39.2527C18.439 39.5479 18.6797 39.7914 18.9748 39.7914H27.5276H40.1893H42.0088H49.4642C49.7593 39.7914 50 39.5479 50 39.2527V30.5952V6.68016V6.43085H44.556C44.0317 6.43085 42.9428 6.50536 42.9428 5.3161L42.9313 0H18.9747C18.6796 0 18.4389 0.240722 18.4389 0.535936V5.13554V7.08143V20.8256H18.439Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.35594 10.4889C6.29012 11.5206 3.25292 12.5436 0.341795 13.5896C0.0752911 13.6871 -0.0650406 13.9822 0.0294905 14.2487L6.61102 32.5497L12.5851 49.1712C12.6826 49.4377 12.9777 49.5781 13.2441 49.4807L20.9575 46.7066L38.5331 40.3875L9.35594 10.4889Z" fill="#B5C4CF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.4389 5.13535L9.22994 6.71435C8.95201 6.76308 8.76285 7.02958 8.81158 7.31044L9.35601 10.4886L12.0981 26.4768L15.0808 43.8864C15.1295 44.1645 15.3989 44.3535 15.6768 44.3077L23.7569 42.9207L38.5331 40.3873L42.0087 39.7912H40.1893L18.4389 5.13535Z" fill="#D7E7EC"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.9999 30.5952V6.68016V6.43085V6.34774C49.9999 6.19296 49.934 6.16718 49.6962 5.93505L43.8196 0.329589C43.5417 0.0659178 43.4959 0 43.3325 0H42.9313H18.9747C18.6796 0 18.4389 0.240722 18.4389 0.535936V39.2527C18.4389 39.5479 18.6796 39.7914 18.9747 39.7914H49.4641C49.7592 39.7914 49.9999 39.5479 49.9999 39.2527V30.5952Z" fill="#EDF3F4"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.4389 5.13535L16.2814 5.50507V41.2328C16.2814 41.5309 16.5221 41.7716 16.8172 41.7716H25.37H30.4588L38.5331 40.3874L42.0087 39.7913H40.1893H37.9515H27.5276H18.9747C18.6796 39.7913 18.4389 39.5478 18.4389 39.2526C18.4389 27.881 18.4389 16.5067 18.4389 5.13535Z" fill="#B5C4CF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.098 26.4771L9.35591 10.4889C8.61383 10.7382 7.87457 10.9875 7.13815 11.2368L7.47916 13.2228L10.2212 29.2111L13.2069 46.6207C13.2527 46.8987 13.522 47.0878 13.7999 47.042L21.88 45.655L25.7138 44.9988L37.2608 40.8434L37.1233 40.6285L30.4587 41.7719L23.7569 42.9211L15.6768 44.3081C15.3989 44.354 15.1295 44.1649 15.0808 43.8868L12.098 26.4771Z" fill="#9AAFB7"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.9999 30.5952V6.68016V6.43085C49.9999 6.14139 49.9053 6.13856 49.6962 5.93505L43.8195 0.329589C43.5416 0.0659178 43.4958 0 43.3324 0H42.9312H36.9685C44.255 9.75516 44.6704 27.3396 39.2637 38.3156C39.0143 38.8257 38.7536 39.3157 38.4814 39.7914H40.1891H42.0086H49.464C49.7591 39.7914 49.9999 39.5479 49.9999 39.2527V30.5952Z" fill="#D7E7EC"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M42.9427 5.3161C42.9427 6.50536 44.0315 6.43085 44.5559 6.43085H49.9999V6.34774C49.9999 6.19296 49.934 6.16718 49.6962 5.93505L43.8196 0.329589C43.5416 0.0659178 43.4958 0 43.3325 0H42.9313L42.9427 5.3161Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.6962 5.93505L43.8196 0.329589C43.5416 0.0659178 43.4958 0 43.3325 0H42.9313L42.9427 5.31601C42.9427 6.50526 44.0315 6.43075 44.5559 6.43075H49.9999V6.34764C49.9999 6.19296 49.934 6.16718 49.6962 5.93505Z" fill="#B5C4CF"/>
<path d="M45.1576 11.7192H23.5849C23.1682 11.7192 22.8304 11.3813 22.8304 10.9644C22.8304 10.5475 23.1682 10.2096 23.5849 10.2096H45.1576C45.5742 10.2096 45.912 10.5475 45.912 10.9644C45.912 11.3813 45.5743 11.7192 45.1576 11.7192Z" fill="#9AAFB7"/>
<path d="M45.1576 17.0811H23.5849C23.1682 17.0811 22.8304 16.7432 22.8304 16.3263C22.8304 15.9095 23.1682 15.5716 23.5849 15.5716H45.1576C45.5742 15.5716 45.912 15.9095 45.912 16.3263C45.912 16.7432 45.5743 17.0811 45.1576 17.0811Z" fill="#9AAFB7"/>
<path d="M45.1576 22.4431H23.5849C23.1682 22.4431 22.8304 22.1052 22.8304 21.6883C22.8304 21.2714 23.1682 20.9335 23.5849 20.9335H45.1576C45.5742 20.9335 45.912 21.2714 45.912 21.6883C45.912 22.1052 45.5743 22.4431 45.1576 22.4431Z" fill="#9AAFB7"/>
<path d="M45.1576 27.805H23.5849C23.1682 27.805 22.8304 27.4671 22.8304 27.0502C22.8304 26.6333 23.1682 26.2954 23.5849 26.2954H45.1576C45.5742 26.2954 45.912 26.6333 45.912 27.0502C45.912 27.4671 45.5743 27.805 45.1576 27.805Z" fill="#9AAFB7"/>
<path d="M45.1576 33.1669H23.5849C23.1682 33.1669 22.8304 32.829 22.8304 32.4121C22.8304 31.9952 23.1682 31.6573 23.5849 31.6573H45.1576C45.5742 31.6573 45.912 31.9952 45.912 32.4121C45.912 32.829 45.5743 33.1669 45.1576 33.1669Z" fill="#9AAFB7"/>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -0,0 +1,23 @@
<svg width="29" height="39" viewBox="0 0 29 39" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_i_3851_4689)">
<path d="M0 5.33646C0 2.84823 1.82766 0.716451 4.30322 0.46559C8.74889 0.0150898 12.2724 0.0349553 16.6673 0.476887C19.1549 0.727017 21 2.86372 21 5.36377V33.7227C21 36.1852 19.2096 38.3047 16.7627 38.5821C12.3371 39.0837 8.75437 39.0879 4.2429 38.579C1.794 38.3027 0 36.1827 0 33.7182V5.33646Z" fill="#EAF6FF"/>
</g>
<path d="M17.9558 24C18.0876 24 18.2194 23.9498 18.3199 23.8493C18.521 23.6481 18.521 23.3222 18.3199 23.1212C16.5988 21.4002 16.5988 18.5998 18.3199 16.8788C18.521 16.6777 18.521 16.3518 18.3199 16.1507C18.1188 15.9498 17.7929 15.9498 17.5918 16.1507C15.4693 18.2733 15.4693 21.7268 17.5918 23.8493C17.6923 23.9498 17.8241 24 17.9558 24Z" fill="#8AC9FE"/>
<path d="M19.0387 22C19.1493 22 19.2598 21.9578 19.3442 21.8735C19.5129 21.7048 19.5129 21.4313 19.3441 21.2626C19.0069 20.9254 18.8212 20.477 18.8212 20C18.8212 19.523 19.0069 19.0747 19.3441 18.7374C19.5129 18.5687 19.5129 18.2952 19.3442 18.1265C19.1754 17.9578 18.9019 17.9579 18.7333 18.1265C18.2329 18.6269 17.9573 19.2923 17.9573 20C17.9573 20.7078 18.2329 21.3731 18.7333 21.8735C18.8176 21.9578 18.9282 22 19.0387 22Z" fill="#8AC9FE"/>
<path d="M11.4131 31.3326L11.4131 33.2934C11.4131 33.6836 11.0969 34 10.7066 34C10.3163 34 10 33.6836 10 33.2934L10 31.3326C10 30.9423 10.3163 30.6261 10.7066 30.6261C11.0969 30.6261 11.4131 30.9423 11.4131 31.3326Z" fill="#B3DAFE"/>
<path d="M22 9.09138C22 8.20685 22.5774 7.4095 23.4429 7.22709C24.914 6.91707 26.0828 6.92986 27.5356 7.23253C28.4104 7.41477 29 8.21687 29 9.11042V31.8825C29 32.7476 28.4479 33.5327 27.6064 33.733C26.117 34.0877 24.9156 34.0909 23.3975 33.7314C22.5543 33.5317 22 32.746 22 31.8795V9.09138Z" fill="#EAF6FF"/>
<path d="M24.5149 24C24.3831 24 24.2514 23.9498 24.1508 23.8493C23.9497 23.6481 23.9497 23.3222 24.1508 23.1212C25.8719 21.4002 25.8719 18.5998 24.1508 16.8788C23.9497 16.6777 23.9497 16.3518 24.1508 16.1507C24.3519 15.9498 24.6778 15.9498 24.8789 16.1507C27.0014 18.2733 27.0014 21.7268 24.8789 23.8493C24.7784 23.9498 24.6466 24 24.5149 24Z" fill="#8AC9FE"/>
<path d="M23.432 22C23.3214 22 23.2109 21.9578 23.1265 21.8735C22.9578 21.7048 22.9578 21.4313 23.1266 21.2626C23.4638 20.9254 23.6495 20.477 23.6495 20C23.6495 19.523 23.4638 19.0747 23.1266 18.7374C22.9578 18.5687 22.9578 18.2952 23.1265 18.1265C23.2953 17.9578 23.5688 17.9579 23.7374 18.1265C24.2378 18.6269 24.5134 19.2923 24.5134 20C24.5134 20.7078 24.2379 21.3731 23.7374 21.8735C23.6531 21.9578 23.5425 22 23.432 22Z" fill="#8AC9FE"/>
<defs>
<filter id="filter0_i_3851_4689" x="-1" y="0.136475" width="22" height="38.823" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-1"/>
<feGaussianBlur stdDeviation="1.5"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.538295 0 0 0 0 0.538295 0 0 0 0 0.538295 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_3851_4689"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,15 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.5419 20.2425C11.1182 19.3486 10.0545 18.9679 9.16647 19.3936L1.38334 23.1269C0.591819 23.3099 0 24.0198 0 24.8727V33.8466C0 34.8381 0.797668 35.6414 1.78229 35.6414C2.76668 35.6414 3.56412 34.8381 3.56412 33.8466V27.6645L9.16647 30.3517C9.41376 30.4705 9.67449 30.5264 9.93112 30.5264C10.5974 30.5264 11.2359 30.1484 11.5419 29.5026C11.9643 28.6076 11.5875 27.5367 10.699 27.1104L6.03295 24.8725L10.699 22.6347C11.5877 22.2085 11.9643 21.1376 11.5419 20.2425Z" fill="#D5D5D5"/>
<path d="M20.6084 17.6893C20.8655 17.6893 21.1257 17.6334 21.3737 17.5145L32.0481 12.395C32.9366 11.9684 33.3141 10.8973 32.891 10.0024C32.4682 9.10855 31.4052 8.72804 30.5156 9.1535L19.8408 14.2735C18.9522 14.6999 18.5754 15.7705 18.998 16.6657C19.3038 17.3111 19.9423 17.6893 20.6084 17.6893Z" fill="#D5D5D5"/>
<path d="M42.7227 7.27445L48.1841 4.65449V10.9114C48.1841 11.9027 48.9818 12.7061 49.9659 12.7061C50.9503 12.7061 51.7478 11.9027 51.7478 10.9114V4.62192L57.2779 7.27445C57.5259 7.39303 57.7862 7.44922 58.0433 7.44922C58.7091 7.44922 59.3478 7.07124 59.6534 6.42537C60.0763 5.53041 59.6994 4.45953 58.8106 4.03316L50.7663 0.174427C50.2813 -0.0581424 49.7189 -0.0581424 49.2338 0.174427L41.19 4.03316C40.3015 4.45953 39.9244 5.53018 40.3472 6.42537C40.771 7.32101 41.8362 7.70198 42.7227 7.27445Z" fill="#D5D5D5"/>
<path d="M67.9533 12.3945L78.6281 17.5147C78.875 17.6335 79.1361 17.6895 79.3932 17.6895C80.059 17.6895 80.6978 17.3115 81.0034 16.6656C81.426 15.7707 81.0494 14.6998 80.1606 14.2734L69.4856 9.15299C68.5982 8.7273 67.5345 9.10735 67.1105 10.0018C66.6875 10.8968 67.0645 11.9677 67.9533 12.3945Z" fill="#D5D5D5"/>
<path d="M81.539 34.8098C82.4275 34.3836 82.8046 33.3128 82.3815 32.4176C81.9587 31.5231 80.8946 31.1423 80.0065 31.5694L73.167 34.8508L51.7477 24.577V16.5765C51.7477 15.5845 50.9503 14.7817 49.9659 14.7817C48.9817 14.7817 48.1841 15.5847 48.1841 16.5765V24.6095L26.8346 34.8499L20.6999 31.9073C19.8093 31.4809 18.7482 31.8612 18.3244 32.7563C17.9016 33.6513 18.2787 34.7224 19.1672 35.1488L25.8031 38.3318V61.6684L19.0593 64.903C18.1707 65.3294 17.7939 66.4 18.2165 67.2955C18.5221 67.9411 19.1606 68.3191 19.8266 68.3191C20.0837 68.3191 20.3447 68.2631 20.5917 68.1443L26.8349 65.1498L48.1841 75.3902V81.5074C48.1841 82.4992 48.9817 83.3022 49.9659 83.3022C50.9503 83.3022 51.7477 82.4989 51.7477 81.5074V75.4232L73.1657 65.15L79.6524 68.2615C79.9002 68.3801 80.1607 68.4363 80.4175 68.4363C81.0834 68.4363 81.7221 68.0583 82.0277 67.4124C82.4508 66.5175 82.0735 65.4466 81.1849 65.02L74.1977 61.6686V38.3318L81.539 34.8098ZM70.634 62.3879L51.7479 71.4466V49.0993L70.634 40.0401V62.3879ZM29.4788 61.8938C29.4472 61.8269 29.4053 61.7691 29.3668 61.708V40.0403L48.1841 49.0663V71.414L29.6409 62.5197C29.6239 62.3085 29.5745 62.0963 29.4788 61.8938ZM50.0003 27.715L69.0207 36.8382L50.0003 45.961L30.9799 36.8382L50.0003 27.715Z" fill="#D5D5D5"/>
<path d="M78.6271 82.4859L67.9525 87.6061C67.0639 88.0327 66.6864 89.1036 67.1095 89.9979C67.4153 90.644 68.054 91.0215 68.7199 91.0215C68.9767 91.0215 69.2379 90.9655 69.485 90.8477L80.1598 85.7272C81.0483 85.3009 81.4252 84.2295 81.0025 83.3346C80.579 82.4401 79.5149 82.0616 78.6271 82.4859Z" fill="#D5D5D5"/>
<path d="M57.2782 92.7267L51.748 95.3794V88.2271C51.748 87.2358 50.9506 86.4324 49.9662 86.4324C48.982 86.4324 48.1844 87.2358 48.1844 88.2271V95.3469L42.723 92.7267C41.8335 92.3024 40.7713 92.6808 40.3475 93.576C39.9246 94.4709 40.3015 95.5414 41.1903 95.9677L49.2346 99.826C49.4769 99.9418 49.7387 100 50.0008 100C50.2629 100 50.5248 99.9418 50.7671 99.826L58.8114 95.9677C59.6999 95.5414 60.077 94.4709 59.6541 93.576C59.2304 92.6808 58.166 92.3033 57.2782 92.7267Z" fill="#D5D5D5"/>
<path d="M32.0476 87.6063L21.3728 82.4861C20.4863 82.0606 19.4217 82.4395 18.9975 83.3345C18.5749 84.2294 18.9517 85.3008 19.8403 85.7271L30.5153 90.8476C30.7622 90.9654 31.0233 91.0214 31.2802 91.0214C31.946 91.0214 32.5847 90.6439 32.8903 89.9978C33.3132 89.1037 32.9361 88.0329 32.0476 87.6063Z" fill="#D5D5D5"/>
<path d="M11.5419 70.4973C11.1182 69.6028 10.0545 69.2239 9.16647 69.6487L3.56412 72.3354V65.6177C3.56412 64.6264 2.76668 63.823 1.78229 63.823C0.797668 63.823 0 64.6264 0 65.6177V74.5918C0 74.8162 0.0457694 75.0283 0.120686 75.2262C0.156892 75.8783 0.53193 76.465 1.12215 76.7485L9.16647 80.6072C9.41376 80.7254 9.67449 80.7818 9.93112 80.7818C10.5974 80.7818 11.2359 80.4038 11.5419 79.7581C11.9643 78.8632 11.5875 77.7923 10.699 77.3655L6.03295 75.1281L10.699 72.8902C11.5877 72.4636 11.9643 71.3923 11.5419 70.4973Z" fill="#D5D5D5"/>
<path d="M1.78229 56.8224C2.76668 56.8224 3.56412 56.0192 3.56412 55.0273V44.4373C3.56412 43.446 2.76668 42.6426 1.78229 42.6426C0.797668 42.6426 0 43.446 0 44.4373V55.0273C0.00022771 56.0192 0.797896 56.8224 1.78229 56.8224Z" fill="#D5D5D5"/>
<path d="M98.6173 23.1267L90.8342 19.3935C89.9443 18.9666 88.8825 19.3478 88.4589 20.2423C88.0363 21.1377 88.4132 22.2084 89.3017 22.635L93.9677 24.8729L89.3017 27.1107C88.4132 27.5371 88.0363 28.6077 88.4589 29.5029C88.7645 30.1488 89.4032 30.5268 90.0691 30.5268C90.3262 30.5268 90.5873 30.4708 90.8342 30.352L96.4365 27.6648V33.847C96.4365 34.8385 97.234 35.6417 98.2184 35.6417C99.2027 35.6417 100 34.8385 100 33.847V24.8731C100 24.0196 99.4088 23.3098 98.6173 23.1267Z" fill="#D5D5D5"/>
<path d="M98.2184 42.6421C97.2337 42.6421 96.4365 43.4455 96.4365 44.4368V55.0268C96.4365 56.0187 97.234 56.8215 98.2184 56.8215C99.2027 56.8215 100 56.0185 100 55.0268V44.4368C100 43.4455 99.203 42.6421 98.2184 42.6421Z" fill="#D5D5D5"/>
<path d="M98.2184 63.8228C97.2337 63.8228 96.4365 64.6262 96.4365 65.6175V72.3352L90.8342 69.6485C89.9443 69.223 88.8825 69.6021 88.4589 70.4971C88.0363 71.392 88.4132 72.4634 89.3017 72.8898L93.9677 75.1276L89.3017 77.365C88.4132 77.7918 88.0363 78.8627 88.4589 79.7577C88.7645 80.4033 89.4032 80.7813 90.0691 80.7813C90.3262 80.7813 90.5873 80.7249 90.8342 80.6068L98.8785 76.748C99.4687 76.4645 99.8438 75.8778 99.88 75.2258C99.9546 75.0278 100 74.8157 100 74.5914V65.6173C100 64.6262 99.203 63.8228 98.2184 63.8228Z" fill="#D5D5D5"/>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -0,0 +1,47 @@
<svg width="241" height="260" viewBox="0 0 241 260" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_3851_4840)">
<g filter="url(#filter1_i_3851_4840)">
<path d="M1 32.5794C1 17.65 11.9782 4.87264 26.8261 3.31376C56.9938 0.146434 80.4127 0.288676 110.23 3.38644C125.15 4.93649 136.229 17.743 136.229 32.7433V219.157C136.229 233.932 125.474 246.635 110.8 248.355C80.8281 251.869 57.0283 251.901 26.4597 248.336C11.7726 246.623 1 233.917 1 219.131V32.5794Z" fill="#EAF6FF"/>
</g>
<path d="M113.787 154.669C112.938 154.669 112.09 154.345 111.442 153.698C110.147 152.403 110.147 150.304 111.442 149.009C122.525 137.927 122.525 119.894 111.442 108.812C110.147 107.517 110.147 105.418 111.442 104.123C112.737 102.829 114.836 102.829 116.131 104.123C129.798 117.792 129.798 140.03 116.131 153.698C115.484 154.345 114.635 154.669 113.787 154.669Z" fill="#FF0000" fill-opacity="0.7"/>
<path d="M106.813 141.79C106.101 141.79 105.39 141.518 104.846 140.975C103.76 139.889 103.76 138.127 104.847 137.041C107.018 134.87 108.214 131.982 108.214 128.911C108.214 125.839 107.018 122.952 104.847 120.78C103.76 119.694 103.76 117.933 104.846 116.847C105.933 115.76 107.694 115.76 108.78 116.846C112.002 120.069 113.777 124.353 113.777 128.911C113.777 133.468 112.003 137.753 108.78 140.975C108.237 141.518 107.525 141.79 106.813 141.79Z" fill="#FF0000" fill-opacity="0.7"/>
<path d="M74.4946 201.887L74.4946 214.513C74.4946 217.026 72.4581 219.063 69.9447 219.063C67.4313 219.063 65.3948 217.026 65.3948 214.513L65.3948 201.887C65.3948 199.374 67.4313 197.337 69.9447 197.337C72.4581 197.337 74.4946 199.374 74.4946 201.887Z" fill="#B3DAFE"/>
<g filter="url(#filter2_i_3851_4840)">
<path d="M186.229 60.2459C186.229 53.612 190.555 47.5909 197.072 46.3483C205.305 44.7783 212.168 44.839 220.304 46.382C226.889 47.6306 231.305 53.6871 231.305 60.3888V203.89C231.305 210.378 227.172 216.307 220.833 217.686C212.408 219.518 205.306 219.531 196.73 217.674C190.379 216.299 186.229 210.366 186.229 203.867V60.2459Z" fill="#EAF6FF"/>
</g>
<path d="M205.263 103.153C206.112 103.153 206.96 103.476 207.608 104.124C208.903 105.419 208.903 107.517 207.608 108.812C196.525 119.894 196.525 137.927 207.608 149.009C208.903 150.305 208.903 152.403 207.608 153.698C206.313 154.992 204.214 154.992 202.919 153.698C189.252 140.03 189.252 117.791 202.919 104.123C203.567 103.476 204.415 103.153 205.263 103.153Z" fill="#FF0000" fill-opacity="0.7"/>
<path d="M212.237 116.032C212.949 116.032 213.66 116.303 214.204 116.847C215.29 117.933 215.29 119.694 214.203 120.78C212.032 122.952 210.836 125.839 210.836 128.911C210.836 131.982 212.032 134.869 214.203 137.041C215.29 138.128 215.29 139.889 214.204 140.975C213.117 142.061 211.356 142.061 210.27 140.975C207.048 137.753 205.273 133.468 205.273 128.911C205.273 124.353 207.047 120.069 210.27 116.846C210.813 116.304 211.525 116.032 212.237 116.032Z" fill="#FF0000" fill-opacity="0.7"/>
</g>
<defs>
<filter id="filter0_d_3851_4840" x="0" y="0" width="240.305" height="260" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="4" dy="4"/>
<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.2 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3851_4840"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3851_4840" result="shape"/>
</filter>
<filter id="filter1_i_3851_4840" x="0" y="1" width="136.229" height="250" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-1"/>
<feGaussianBlur stdDeviation="10"/>
<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.3 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_3851_4840"/>
</filter>
<filter id="filter2_i_3851_4840" x="184.229" y="45.1975" width="47.0763" height="173.866" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-2"/>
<feGaussianBlur stdDeviation="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.3 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_3851_4840"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

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

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

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

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

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

After

Width:  |  Height:  |  Size: 965 B

View File

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

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,14 @@
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 284">
<g id="Group">
<g id="Group_2">
<path id="Vector" d="M37.8033 16.3571C37.2313 15.7851 36.3039 15.785 35.7318 16.3572L21.5532 30.5356L14.2681 23.2508C13.6962 22.6788 12.7686 22.6787 12.1966 23.2509C11.6246 23.8229 11.6246 24.7504 12.1966 25.3224L20.5174 33.643C20.8034 33.9291 21.1783 34.072 21.5531 34.072C21.928 34.072 22.3029 33.9291 22.5888 33.6429L37.8033 18.4287C38.3754 17.8567 38.3754 16.9292 37.8033 16.3571Z" fill="white"/>
</g>
</g>
<g id="Group_3">
<g id="Group_4">
<path id="Vector_2" d="M42.6776 7.32236C37.9558 2.60049 31.6776 0 25 0C18.3223 0 12.0442 2.60049 7.32236 7.32236C2.60039 12.0443 0 18.3224 0 25C0 31.6778 2.60039 37.9559 7.32236 42.6777C12.0441 47.3996 18.3223 50 25 50C31.6777 50 37.9558 47.3996 42.6776 42.6777C47.3995 37.9559 50 31.6778 50 25C50 18.3224 47.3995 12.0443 42.6776 7.32236ZM25 47.0703C12.8304 47.0703 2.92969 37.1696 2.92969 25C2.92969 12.8304 12.8304 2.92969 25 2.92969C37.1696 2.92969 47.0703 12.8304 47.0703 25C47.0703 37.1696 37.1696 47.0703 25 47.0703Z" fill="white"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,22 @@
<svg width="27" height="40" viewBox="0 0 27 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.7445 35.1952C10.4209 35.1952 10.1586 35.4576 10.1586 35.7812V37.2605C10.1586 38.1249 9.45534 38.8282 8.59099 38.8282H7.12205C6.79847 38.8282 6.53613 39.0905 6.53613 39.4141C6.53613 39.7377 6.79847 40 7.12205 40H8.59099C10.1015 40 11.3304 38.7711 11.3304 37.2605V35.7812C11.3304 35.4576 11.0681 35.1952 10.7445 35.1952Z" fill="#72BBFF"/>
<path d="M11.7906 32.7314H9.69835C9.37476 32.7314 9.11243 32.9937 9.11243 33.3173V34.7541C9.11243 35.6541 9.84459 36.3862 10.7445 36.3862C11.6444 36.3862 12.3765 35.654 12.3765 34.7541V33.3173C12.3765 32.9937 12.1142 32.7314 11.7906 32.7314Z" fill="#6B717D"/>
<path d="M16.0857 35.1952C16.4093 35.1952 16.6716 35.4576 16.6716 35.7812V37.2605C16.6716 38.1249 17.3749 38.8282 18.2392 38.8282H19.7081C20.0317 38.8282 20.2941 39.0905 20.2941 39.4141C20.2941 39.7377 20.0317 40 19.7081 40H18.2392C16.7287 40 15.4998 38.7711 15.4998 37.2605V35.7812C15.4998 35.4576 15.7621 35.1952 16.0857 35.1952Z" fill="#FF6C6C"/>
<path d="M15.0395 32.7314H17.1318C17.4554 32.7314 17.7177 32.9937 17.7177 33.3173V34.7541C17.7177 35.6541 16.9856 36.3862 16.0857 36.3862C15.1858 36.3862 14.4536 35.654 14.4536 34.7541V33.3173C14.4536 32.9937 14.7159 32.7314 15.0395 32.7314Z" fill="#6B717D"/>
<path d="M2.38438 3.6581H0.585919C0.262336 3.6581 0 3.92043 0 4.24402C0 4.5676 0.262336 4.82993 0.585919 4.82993H2.38438C2.70796 4.82993 2.9703 4.5676 2.9703 4.24402C2.9703 3.92043 2.70796 3.6581 2.38438 3.6581Z" fill="#6B717D"/>
<path d="M2.38438 6.3924H0.585919C0.262336 6.3924 0 6.65473 0 6.97831C0 7.3019 0.262336 7.56423 0.585919 7.56423H2.38438C2.70796 7.56423 2.9703 7.3019 2.9703 6.97831C2.9703 6.65473 2.70796 6.3924 2.38438 6.3924Z" fill="#6B717D"/>
<path d="M26.2441 19.7208H24.4456C24.122 19.7208 23.8597 19.9831 23.8597 20.3067C23.8597 20.6303 24.122 20.8926 24.4456 20.8926H26.2441C26.5676 20.8926 26.83 20.6303 26.83 20.3067C26.83 19.9831 26.5676 19.7208 26.2441 19.7208Z" fill="#6B717D"/>
<path d="M21.766 30.5576V33.2958C21.766 33.6193 21.5035 33.8818 21.1801 33.8818H5.65013C5.3267 33.8818 5.06421 33.6193 5.06421 33.2958V30.5576C5.06421 30.2342 5.3267 29.9717 5.65013 29.9717H21.1801C21.5035 29.9717 21.766 30.2342 21.766 30.5576Z" fill="#D6EAEC"/>
<path d="M21.766 30.5576V33.2958C21.766 33.6193 21.5035 33.8818 21.18 33.8818H18.8364C19.1598 33.8818 19.4223 33.6193 19.4223 33.2958V30.5576C19.4223 30.2342 19.1598 29.9717 18.8364 29.9717H21.18C21.5035 29.9717 21.766 30.2342 21.766 30.5576Z" fill="#B5D9DD"/>
<path d="M25.0315 1.84682V24.8047L22.6878 25.4437L13.4146 27.9741L1.79858 24.8047V1.84682C1.79858 0.828099 2.62668 0 3.6454 0H23.1846C24.2026 0 25.0315 0.828099 25.0315 1.84682Z" fill="#D6EAEC"/>
<path d="M25.0314 1.84682V24.8047L22.6878 25.4437V1.84682C22.6878 0.828099 21.8589 0 20.8409 0H23.1846C24.2026 0 25.0314 0.828099 25.0314 1.84682Z" fill="#B5D9DD"/>
<path d="M25.0315 24.8047V29.2967C25.0315 30.3155 24.2026 31.1436 23.1846 31.1436H3.6454C2.62668 31.1436 1.79858 30.3155 1.79858 29.2967V24.8047H25.0315Z" fill="#6B717D"/>
<path d="M25.0314 24.8047V29.2967C25.0314 30.3155 24.2026 31.1436 23.1846 31.1436H20.8409C21.8589 31.1436 22.6878 30.3155 22.6878 29.2967V24.8047H25.0314Z" fill="#47505E"/>
<path d="M13.8105 15.476C13.5866 15.2712 13.2434 15.2712 13.0195 15.476C12.9301 15.5578 10.8306 17.5023 10.8306 19.5649C10.8306 20.99 11.9899 22.1494 13.415 22.1494C14.8401 22.1494 15.9995 20.99 15.9995 19.5649C15.9994 17.5023 13.8998 15.5578 13.8105 15.476Z" fill="#72BBFF"/>
<path d="M17.952 9.8444C18.9889 7.34275 17.8015 4.47417 15.2999 3.43723C12.7983 2.4003 9.92967 3.58768 8.89274 6.08932C7.8558 8.59096 9.04318 11.4595 11.5448 12.4965C14.0465 13.5334 16.915 12.346 17.952 9.8444Z" fill="#B5D9DD"/>
<path d="M16.3638 7.96677C16.3638 10.0237 15.4716 11.6971 13.4147 11.6971C13.1053 11.6971 12.8045 11.6588 12.5163 11.587C10.8921 11.1846 9.68433 9.71437 9.68433 7.96677C9.68433 6.21917 10.8921 4.7489 12.5163 4.34657C12.8045 4.2747 13.1053 4.23642 13.4147 4.23642C15.4716 4.23642 16.3638 5.9098 16.3638 7.96677Z" fill="white"/>
<path d="M17.1451 7.96677C17.1451 10.0237 15.4717 11.6971 13.4147 11.6971C13.1053 11.6971 12.8046 11.6588 12.5163 11.587C14.1405 11.1846 15.3482 9.71437 15.3482 7.96677C15.3482 6.21917 14.1405 4.7489 12.5163 4.34657C12.8046 4.2747 13.1053 4.23642 13.4147 4.23642C15.4717 4.23642 17.1451 5.9098 17.1451 7.96677Z" fill="#D6EAEC"/>
<path d="M13.8294 7.55251C13.6005 7.3236 13.2295 7.32368 13.0008 7.55251L11.7521 8.80126C11.5233 9.03009 11.5233 9.4011 11.7521 9.62985C11.8665 9.74423 12.0165 9.80149 12.1664 9.80149C12.3163 9.80149 12.4663 9.74431 12.5807 9.62985L13.8294 8.3811C14.0582 8.15228 14.0582 7.78126 13.8294 7.55251Z" fill="#FF6C6C"/>
<path d="M6.17188 28.5601C6.49548 28.5601 6.75781 28.2977 6.75781 27.9741C6.75781 27.6505 6.49548 27.3882 6.17188 27.3882C5.84827 27.3882 5.58594 27.6505 5.58594 27.9741C5.58594 28.2977 5.84827 28.5601 6.17188 28.5601Z" fill="#47505E"/>
<path d="M20.6581 28.5601C20.9817 28.5601 21.2441 28.2977 21.2441 27.9741C21.2441 27.6505 20.9817 27.3882 20.6581 27.3882C20.3345 27.3882 20.0722 27.6505 20.0722 27.9741C20.0722 28.2977 20.3345 28.5601 20.6581 28.5601Z" fill="#47505E"/>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

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

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

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

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -1 +1 @@
{"flutter":{"platforms":{"android":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:android:bb6047adeeb80fb00c7e6d","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:373a65cce55a3af40c7e6d","uploadDebugSymbols":true,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"test2-8a3d2","configurations":{"android":"1:427332280600:android:bb6047adeeb80fb00c7e6d","ios":"1:427332280600:ios:373a65cce55a3af40c7e6d","web":"1:427332280600:web:ad50516a87a35a1a0c7e6d"}}}}}}
{"flutter":{"platforms":{"android":{"default":{"projectId":"syncrow-staging","appId":"1:786692570726:android:0ef7079c2b978d4417b7a7","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"syncrow-staging","appId":"1:786692570726:ios:455a6fcff77e130f17b7a7","uploadDebugSymbols":true,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"syncrow-staging","configurations":{"android":"1:786692570726:android:0ef7079c2b978d4417b7a7","ios":"1:786692570726:ios:455a6fcff77e130f17b7a7","web":"1:786692570726:web:93c931e6701797b317b7a7"}}}}}}

View File

@ -14,14 +14,14 @@ PODS:
- Firebase/Database (10.25.0):
- Firebase/CoreOnly
- FirebaseDatabase (~> 10.25.0)
- firebase_analytics (10.10.7):
- firebase_analytics (10.8.7):
- Firebase/Analytics (= 10.25.0)
- firebase_core
- Flutter
- firebase_core (2.32.0):
- Firebase/CoreOnly (= 10.25.0)
- Flutter
- firebase_crashlytics (3.5.7):
- firebase_crashlytics (3.4.16):
- Firebase/Crashlytics (= 10.25.0)
- firebase_core
- Flutter
@ -88,8 +88,6 @@ PODS:
- PromisesSwift (~> 2.1)
- FirebaseSharedSwift (10.29.0)
- Flutter (1.0.0)
- flutter_localization (0.0.1):
- Flutter
- flutter_secure_storage (6.0.0):
- Flutter
- GoogleAppMeasurement (10.25.0):
@ -152,12 +150,12 @@ PODS:
- nanopb/encode (= 2.30910.0)
- nanopb/decode (2.30910.0)
- nanopb/encode (2.30910.0)
- onesignal_flutter (5.2.3):
- onesignal_flutter (5.2.0):
- Flutter
- OneSignalXCFramework (= 5.2.3)
- OneSignalXCFramework (5.2.3):
- OneSignalXCFramework/OneSignalComplete (= 5.2.3)
- OneSignalXCFramework/OneSignal (5.2.3):
- OneSignalXCFramework (= 5.2.0)
- OneSignalXCFramework (5.2.0):
- OneSignalXCFramework/OneSignalComplete (= 5.2.0)
- OneSignalXCFramework/OneSignal (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalExtension
- OneSignalXCFramework/OneSignalLiveActivities
@ -165,38 +163,38 @@ PODS:
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalComplete (5.2.3):
- OneSignalXCFramework/OneSignalComplete (5.2.0):
- OneSignalXCFramework/OneSignal
- OneSignalXCFramework/OneSignalInAppMessages
- OneSignalXCFramework/OneSignalLocation
- OneSignalXCFramework/OneSignalCore (5.2.3)
- OneSignalXCFramework/OneSignalExtension (5.2.3):
- OneSignalXCFramework/OneSignalCore (5.2.0)
- OneSignalXCFramework/OneSignalExtension (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalInAppMessages (5.2.3):
- OneSignalXCFramework/OneSignalInAppMessages (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalLiveActivities (5.2.3):
- OneSignalXCFramework/OneSignalLiveActivities (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalLocation (5.2.3):
- OneSignalXCFramework/OneSignalLocation (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalNotifications (5.2.3):
- OneSignalXCFramework/OneSignalNotifications (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalExtension
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalOSCore (5.2.3):
- OneSignalXCFramework/OneSignalOSCore (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalOutcomes (5.2.3):
- OneSignalXCFramework/OneSignalOutcomes (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalUser (5.2.3):
- OneSignalXCFramework/OneSignalUser (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
@ -227,7 +225,6 @@ DEPENDENCIES:
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
- firebase_database (from `.symlinks/plugins/firebase_database/ios`)
- Flutter (from `Flutter`)
- flutter_localization (from `.symlinks/plugins/flutter_localization/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- onesignal_flutter (from `.symlinks/plugins/onesignal_flutter/ios`)
@ -274,8 +271,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/firebase_database/ios"
Flutter:
:path: Flutter
flutter_localization:
:path: ".symlinks/plugins/flutter_localization/ios"
flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
image_picker_ios:
@ -298,9 +293,9 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
Firebase: 0312a2352584f782ea56f66d91606891d4607f06
firebase_analytics: cc06e24d6a2343c44f845b3112143db72d10ef78
firebase_analytics: 3a9263fedec72970e6bd30a7132bbdd386de2c14
firebase_core: a626d00494efa398e7c54f25f1454a64c8abf197
firebase_crashlytics: 17e856fabec68d993662abaf2f6fe2413f0abece
firebase_crashlytics: 0b7cb41f5fb3b6889d0fb408cfce3cc7a4247061
firebase_database: 2713033e426b176d4fe5e7195f3d19aa1b549a91
FirebaseAnalytics: ec00fe8b93b41dc6fe4a28784b8e51da0647a248
FirebaseAppCheckInterop: 6a1757cfd4067d8e00fccd14fcc1b8fd78cfac07
@ -314,24 +309,23 @@ SPEC CHECKSUMS:
FirebaseSessions: dbd14adac65ce996228652c1fc3a3f576bdf3ecc
FirebaseSharedSwift: 20530f495084b8d840f78a100d8c5ee613375f6e
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_localization: f43b18844a2b3d2c71fd64f04ffd6b1e64dd54d4
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
GoogleAppMeasurement: 9abf64b682732fed36da827aa2a68f0221fd2356
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
leveldb-library: e8eadf9008a61f9e1dde3978c086d2b6d9b9dc28
nanopb: 438bc412db1928dac798aa6fd75726007be04262
onesignal_flutter: aecb9bab7b87b6b6a0887c103932c9f5488759e5
OneSignalXCFramework: 356e59953e157f6e45a7fdfc863073b3168b2d01
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
onesignal_flutter: 5ce68a29861960168e81101cb1bd685d264361de
OneSignalXCFramework: bdf74fdc06888f9466dc21e826fe1549ed143095
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
PODFILE CHECKSUM: 4243bd7f9184f79552dd731a7c9d5cad03bd2706

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 60;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@ -12,7 +12,6 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
611C662010675536F855E5CA /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 490AAF90B8FBFCC5BA996845 /* Pods_RunnerTests.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
8BB48ED4ACF8DB5A4F5DB78C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 90790D9750E58AEFF7247821 /* GoogleService-Info.plist */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@ -43,18 +42,23 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
01BAAF935356ECBDD35AF0DB /* Pods-RunnerTests.debug-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug-prod.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug-prod.xcconfig"; sourceTree = "<group>"; };
12AD49A621BEBB053FD06115 /* Pods-Runner.release-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-prod.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
1F99043C7AC9BDABD8A4D41A /* Pods-Runner.profile-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-dev.xcconfig"; sourceTree = "<group>"; };
210827A693936E5201C5E75C /* Pods-RunnerTests.profile-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile-dev.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile-dev.xcconfig"; sourceTree = "<group>"; };
238CAAD9FFF9A0C9ED3CFAB2 /* Pods-RunnerTests.profile-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile-prod.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile-prod.xcconfig"; sourceTree = "<group>"; };
25B37F5982CD6994FABA2CC1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
444D77D28A8CDF32047CD0AF /* 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>"; };
490AAF90B8FBFCC5BA996845 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5DE3E6D1EADE3D3859FC1B69 /* Pods-Runner.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-dev.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
90790D9750E58AEFF7247821 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
949637473C534E1F68B19CC0 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
@ -63,9 +67,15 @@
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>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9B82456986D7FA25420A224F /* Pods-Runner.debug-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-prod.xcconfig"; sourceTree = "<group>"; };
A3D4DF5D9888DAC25E2380AA /* Pods-RunnerTests.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release-dev.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release-dev.xcconfig"; sourceTree = "<group>"; };
AAC9129FD50E64509AD1B9AF /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
BFD4DDED98208034B60B5311 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
C41134CD2FDFC1A2BDF49283 /* Pods-Runner.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-dev.xcconfig"; sourceTree = "<group>"; };
C5DBBF9417E4F8A9A08DFF02 /* Pods-RunnerTests.release-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release-prod.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release-prod.xcconfig"; sourceTree = "<group>"; };
D0F6245A5BF345FCC425515C /* Pods-Runner.profile-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-prod.xcconfig"; sourceTree = "<group>"; };
DFB6BB492A265F2BF6FDC8C0 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
EE971EFEA60AEDFDB361D9A3 /* Pods-RunnerTests.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug-dev.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug-dev.xcconfig"; sourceTree = "<group>"; };
F323D632CA976B68DDB0E669 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -98,6 +108,18 @@
DFB6BB492A265F2BF6FDC8C0 /* Pods-RunnerTests.debug.xcconfig */,
F323D632CA976B68DDB0E669 /* Pods-RunnerTests.release.xcconfig */,
AAC9129FD50E64509AD1B9AF /* Pods-RunnerTests.profile.xcconfig */,
9B82456986D7FA25420A224F /* Pods-Runner.debug-prod.xcconfig */,
5DE3E6D1EADE3D3859FC1B69 /* Pods-Runner.debug-dev.xcconfig */,
12AD49A621BEBB053FD06115 /* Pods-Runner.release-prod.xcconfig */,
C41134CD2FDFC1A2BDF49283 /* Pods-Runner.release-dev.xcconfig */,
D0F6245A5BF345FCC425515C /* Pods-Runner.profile-prod.xcconfig */,
1F99043C7AC9BDABD8A4D41A /* Pods-Runner.profile-dev.xcconfig */,
01BAAF935356ECBDD35AF0DB /* Pods-RunnerTests.debug-prod.xcconfig */,
EE971EFEA60AEDFDB361D9A3 /* Pods-RunnerTests.debug-dev.xcconfig */,
C5DBBF9417E4F8A9A08DFF02 /* Pods-RunnerTests.release-prod.xcconfig */,
A3D4DF5D9888DAC25E2380AA /* Pods-RunnerTests.release-dev.xcconfig */,
238CAAD9FFF9A0C9ED3CFAB2 /* Pods-RunnerTests.profile-prod.xcconfig */,
210827A693936E5201C5E75C /* Pods-RunnerTests.profile-dev.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -139,7 +161,6 @@
331C8082294A63A400263BE5 /* RunnerTests */,
2F70EB4341A83C900EB253DC /* Pods */,
876D3217A8BBDAF41961161F /* Frameworks */,
90790D9750E58AEFF7247821 /* GoogleService-Info.plist */,
);
sourceTree = "<group>";
};
@ -195,14 +216,15 @@
buildPhases = (
3DC878D0674AA34AEC9695FB /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
B07E4A152C9B8EA4001F6910 /* copy GoogleService.plist file to the correct location */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
315A05630CF83C532DBBCBF2 /* [CP] Embed Pods Frameworks */,
0D61909C49A20C9AA28568EA /* FlutterFire: "flutterfire upload-crashlytics-symbols" */,
3724F7A126D8469D5B04D144 /* [CP] Copy Pods Resources */,
4768286A3BADB12BBB8C6996 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */,
);
buildRules = (
);
@ -268,31 +290,12 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
8BB48ED4ACF8DB5A4F5DB78C /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
0D61909C49A20C9AA28568EA /* 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";
};
315A05630CF83C532DBBCBF2 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -387,6 +390,24 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
4768286A3BADB12BBB8C6996 /* 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 */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@ -402,6 +423,24 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
B07E4A152C9B8EA4001F6910 /* copy GoogleService.plist file to the correct location */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "copy GoogleService.plist file to the correct location";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Get a reference to the destination location for the GoogleService-Info.plist\n# This is the default location where Firebase init code expects to find GoogleServices-Info.plist file.\nPLIST_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app\n# We have named our Build Configurations as Debug-dev, Debug-prod etc.\n# Here, dev and prod are the scheme names. This kind of naming is required by Flutter for flavors to work.\n# We are using the $CONFIGURATION variable available in the XCode build environment to get the build configuration.\nif [ \"${CONFIGURATION}\" == \"Debug-prod\" ] || [ \"${CONFIGURATION}\" == \"Release-prod\" ] || [ \"${CONFIGURATION}\" == \"Profile-prod\" ] || [ \"${CONFIGURATION}\" == \"Release\" ]; then\ncp \"${PROJECT_DIR}/config/prod/GoogleService-Info.plist\" \"${PLIST_DESTINATION}/GoogleService-Info.plist\"\necho \"Production plist copied\"\nelif [ \"${CONFIGURATION}\" == \"Debug-dev\" ] || [ \"${CONFIGURATION}\" == \"Release-dev\" ] || [ \"${CONFIGURATION}\" == \"Profile-dev\" ] || [ \"${CONFIGURATION}\" == \"Debug\" ]; then\ncp \"${PROJECT_DIR}/config/dev/GoogleService-Info.plist\" \"${PLIST_DESTINATION}/GoogleService-Info.plist\"\necho \"Development plist copied\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -452,7 +491,7 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
249021D3217E4FDB00AE95B9 /* Profile-prod */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
@ -503,9 +542,9 @@
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
name = "Profile-prod";
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
249021D4217E4FDB00AE95B9 /* Profile-prod */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
@ -532,11 +571,11 @@
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
name = "Profile-prod";
};
331C8088294A63A400263BE5 /* Debug */ = {
331C8088294A63A400263BE5 /* Debug-prod */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = DFB6BB492A265F2BF6FDC8C0 /* Pods-RunnerTests.debug.xcconfig */;
baseConfigurationReference = 01BAAF935356ECBDD35AF0DB /* Pods-RunnerTests.debug-prod.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@ -550,11 +589,11 @@
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
name = "Debug-prod";
};
331C8089294A63A400263BE5 /* Release */ = {
331C8089294A63A400263BE5 /* Release-prod */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = F323D632CA976B68DDB0E669 /* Pods-RunnerTests.release.xcconfig */;
baseConfigurationReference = C5DBBF9417E4F8A9A08DFF02 /* Pods-RunnerTests.release-prod.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@ -566,11 +605,11 @@
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
name = "Release-prod";
};
331C808A294A63A400263BE5 /* Profile */ = {
331C808A294A63A400263BE5 /* Profile-prod */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = AAC9129FD50E64509AD1B9AF /* Pods-RunnerTests.profile.xcconfig */;
baseConfigurationReference = 238CAAD9FFF9A0C9ED3CFAB2 /* Pods-RunnerTests.profile-prod.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@ -582,9 +621,9 @@
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
name = "Profile-prod";
};
97C147031CF9000F007C117D /* Debug */ = {
97C147031CF9000F007C117D /* Debug-prod */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
@ -640,9 +679,9 @@
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
name = "Debug-prod";
};
97C147041CF9000F007C117D /* Release */ = {
97C147041CF9000F007C117D /* Release-prod */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
@ -695,9 +734,9 @@
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
name = "Release-prod";
};
97C147061CF9000F007C117D /* Debug */ = {
97C147061CF9000F007C117D /* Debug-prod */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
@ -725,9 +764,9 @@
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
name = "Debug-prod";
};
97C147071CF9000F007C117D /* Release */ = {
97C147071CF9000F007C117D /* Release-prod */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
@ -754,7 +793,311 @@
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
name = "Release-prod";
};
B07E4A0C2C9B8C45001F6910 /* Debug-dev */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = "Debug-dev";
};
B07E4A0D2C9B8C45001F6910 /* Debug-dev */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = "Debug-dev";
};
B07E4A0E2C9B8C45001F6910 /* Debug-dev */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = EE971EFEA60AEDFDB361D9A3 /* Pods-RunnerTests.debug-dev.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrowApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = "Debug-dev";
};
B07E4A0F2C9B8C52001F6910 /* Release-dev */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = "Release-dev";
};
B07E4A102C9B8C52001F6910 /* Release-dev */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = "Release-dev";
};
B07E4A112C9B8C52001F6910 /* Release-dev */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A3D4DF5D9888DAC25E2380AA /* Pods-RunnerTests.release-dev.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrowApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = "Release-dev";
};
B07E4A122C9B8C5C001F6910 /* Profile-dev */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = "Profile-dev";
};
B07E4A132C9B8C5C001F6910 /* Profile-dev */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = "Profile-dev";
};
B07E4A142C9B8C5C001F6910 /* Profile-dev */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 210827A693936E5201C5E75C /* Pods-RunnerTests.profile-dev.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrowApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = "Profile-dev";
};
/* End XCBuildConfiguration section */
@ -762,32 +1105,41 @@
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
331C8088294A63A400263BE5 /* Debug-prod */,
B07E4A0E2C9B8C45001F6910 /* Debug-dev */,
331C8089294A63A400263BE5 /* Release-prod */,
B07E4A112C9B8C52001F6910 /* Release-dev */,
331C808A294A63A400263BE5 /* Profile-prod */,
B07E4A142C9B8C5C001F6910 /* Profile-dev */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = "Release-prod";
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
97C147031CF9000F007C117D /* Debug-prod */,
B07E4A0C2C9B8C45001F6910 /* Debug-dev */,
97C147041CF9000F007C117D /* Release-prod */,
B07E4A0F2C9B8C52001F6910 /* Release-dev */,
249021D3217E4FDB00AE95B9 /* Profile-prod */,
B07E4A122C9B8C5C001F6910 /* Profile-dev */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = "Release-prod";
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
97C147061CF9000F007C117D /* Debug-prod */,
B07E4A0D2C9B8C45001F6910 /* Debug-dev */,
97C147071CF9000F007C117D /* Release-prod */,
B07E4A102C9B8C52001F6910 /* Release-dev */,
249021D4217E4FDB00AE95B9 /* Profile-prod */,
B07E4A132C9B8C5C001F6910 /* Profile-dev */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = "Release-prod";
};
/* End XCConfigurationList section */
};

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug-dev"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug-dev"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release-dev"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug-dev">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release-dev"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -23,7 +23,7 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
buildConfiguration = "Debug-prod"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
@ -51,7 +51,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
buildConfiguration = "Debug-prod"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
@ -72,7 +72,7 @@
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
buildConfiguration = "Profile-prod"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
@ -89,10 +89,10 @@
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
buildConfiguration = "Debug-prod">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
buildConfiguration = "Release-prod"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,7 +1,7 @@
import UIKit
import Flutter
@main
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,

View File

@ -2,6 +2,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>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photo library to allow you to select and upload photos.</string>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
@ -26,8 +28,6 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photo library to allow you to select and upload photos.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>

View 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>AIzaSyAWlRiuJ75FMlf2_UDdri1voWKvkaSHtRg</string>
<key>GCM_SENDER_ID</key>
<string>786692570726</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.example.syncrow.app</string>
<key>PROJECT_ID</key>
<string>syncrow-staging</string>
<key>STORAGE_BUCKET</key>
<string>syncrow-staging.appspot.com</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:786692570726:ios:455a6fcff77e130f17b7a7</string>
<key>DATABASE_URL</key>
<string>https://syncrow-staging-default-rtdb.firebaseio.com</string>
</dict>
</plist>

View File

@ -16,7 +16,6 @@ class AppBarHomeDropdown extends StatelessWidget {
builder: (context, state) {
return Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Center(
child: DropdownButton(
icon: const Icon(
Icons.expand_more,
@ -46,7 +45,6 @@ class AppBarHomeDropdown extends StatelessWidget {
),
const SizedBox(width: 5),
Flexible(
fit: FlexFit.loose,
child: BodyMedium(
text: space.name ?? "??",
style: context.bodyMedium.copyWith(
@ -64,13 +62,10 @@ class AppBarHomeDropdown extends StatelessWidget {
onChanged: (value) {
if (value != null) {
HomeCubit.getInstance().changeSelectedSpace(
HomeCubit.getInstance()
.spaces!
.firstWhere((element) => element.id == value));
HomeCubit.getInstance().spaces!.firstWhere((element) => element.id == value));
}
},
),
),
);
},
);

View File

@ -11,20 +11,18 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
Widget build(BuildContext context) {
return BlocBuilder<HomeCubit, HomeState>(
builder: (context, state) {
return Padding(
return Container(
padding: const EdgeInsets.only(
top: 20,
),
child: AppBar(
backgroundColor: Colors.transparent,
leadingWidth: 150,
leadingWidth: 200,
toolbarHeight: Constants.appBarHeight,
leading: HomeCubit.getInstance().spaces!.isNotEmpty
? HomeCubit.appBarLeading[
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
? HomeCubit.appBarLeading[HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]!
: null,
actions: HomeCubit.appBarActions[
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],
actions: HomeCubit.appBarActions[HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],
));
},
);

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
@ -9,7 +8,6 @@ import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/services/api/authentication_api.dart';
import 'package:syncrow_app/services/api/profile_api.dart';
import 'package:syncrow_app/utils/helpers/shared_preferences_helper.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
@ -59,19 +57,39 @@ class AuthCubit extends Cubit<AuthState> {
/////////////////////////////////////VALIDATORS/////////////////////////////////////
String? passwordValidator(String? value) {
if (value != null) {
if (value.isEmpty) {
return 'Please enter your password';
List<String> errors = [];
if (value == null || value.isEmpty) {
errors.add("Please enter your password");
}
if (value.isNotEmpty) {
if (!RegExp(
r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!"#$%&()*+,-./:;<=>?@[\]^_`{|}~])[A-Za-z\d!"#$%&()*+,-./:;<=>?@[\]^_`{|}~]{8,}$')
.hasMatch(value)) {
return 'Password must contain at least:\n - one uppercase letter.\n - one lowercase letter.\n - one number. \n - special character';
if (value != null && value.length < 8) {
errors.add('Password must be at least 8 characters long');
}
if (value != null && !RegExp(r'[a-z]').hasMatch(value)) {
errors.add('Password must contain at least one lowercase letter');
}
if (value != null && !RegExp(r'[A-Z]').hasMatch(value)) {
errors.add('Password must contain at least one uppercase letter');
}
return null;
if (value != null && !RegExp(r'\d').hasMatch(value)) {
errors.add('Password must contain at least one number');
}
if (value != null &&
!RegExp(r'[!"#$%&()*+,-./:;<=>?@[\]^_`{|}~]').hasMatch(value)) {
errors.add('Password must contain at least one special character');
}
if (errors.isNotEmpty) {
return errors
.join('\n'); // Join the errors with new lines to show all at once
}
return null; // No errors
}
String? fullNameValidator(String? value) {
@ -182,13 +200,10 @@ class AuthCubit extends Cubit<AuthState> {
debugPrint('token: ${token.accessToken}');
FlutterSecureStorage storage = const FlutterSecureStorage();
await storage.write(
key: Token.loginAccessTokenKey,
value: token.accessToken
);
key: Token.loginAccessTokenKey, value: token.accessToken);
const FlutterSecureStorage().write(
key: UserModel.userUuidKey,
value: Token.decodeToken(token.accessToken)['uuid'].toString()
);
value: Token.decodeToken(token.accessToken)['uuid'].toString());
user = UserModel.fromToken(token);
emailController.clear();
passwordController.clear();
@ -225,20 +240,24 @@ class AuthCubit extends Cubit<AuthState> {
sendOtp() async {
try {
emit(AuthLoading());
await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'VERIFICATION'});
await AuthenticationAPI.sendOtp(
body: {'email': email, 'type': 'VERIFICATION'});
emit(AuthSignUpSuccess());
} catch (_) {
emit(AuthLoginError(message: 'Something went wrong'));
}
}
reSendOtp() async {
Future<bool> reSendOtp() async {
try {
emit(AuthLoading());
await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'VERIFICATION'});
await AuthenticationAPI.sendOtp(
body: {'email': email, 'type': 'VERIFICATION'});
emit(ResendOtpSuccess());
return true;
} catch (_) {
emit(AuthLoginError(message: 'Something went wrong'));
return false;
}
}
@ -282,13 +301,16 @@ class AuthCubit extends Cubit<AuthState> {
try {
emit(AuthTokenLoading());
const storage = FlutterSecureStorage();
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true;
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
StringsManager.firstLaunch) ??
true;
if (firstLaunch) {
storage.deleteAll();
}
await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false);
await SharedPreferencesHelper.saveBoolToSP(
StringsManager.firstLaunch, false);
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
if (value.isEmpty) {
@ -315,7 +337,6 @@ class AuthCubit extends Cubit<AuthState> {
}
}
sendToForgetPassword({required String password}) async {
try {
emit(AuthForgetPassLoading());
@ -325,8 +346,4 @@ class AuthCubit extends Cubit<AuthState> {
emit(AuthForgetPassError(message: 'Something went wrong'));
}
}
}

View File

@ -8,6 +8,7 @@ import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
import 'package:syncrow_app/features/auth/view/create_new_password.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/success_dialog.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
@ -40,13 +41,19 @@ class _OtpViewState extends State<OtpView> {
_lifecycleEventHandler = LifecycleEventHandler(
resumeCallBack: () async {
SharedPreferencesHelper.saveBoolToSP('timeStampSaved', false);
String timeStampInBackground = await SharedPreferencesHelper.readStringFromSP('timeStamp');
int savedCounter = await SharedPreferencesHelper.readIntFromSP('savedCounter');
String timeStampInBackground =
await SharedPreferencesHelper.readStringFromSP('timeStamp');
int savedCounter =
await SharedPreferencesHelper.readIntFromSP('savedCounter');
DateTime currentTime = DateTime.now();
int differenceInSeconds = timeStampInBackground.isNotEmpty
? currentTime.difference(DateTime.parse(timeStampInBackground)).inSeconds
? currentTime
.difference(DateTime.parse(timeStampInBackground))
.inSeconds
: 0;
remainingSec = differenceInSeconds > savedCounter ? 0 : savedCounter - differenceInSeconds;
remainingSec = differenceInSeconds > savedCounter
? 0
: savedCounter - differenceInSeconds;
timerStarted = true;
startTimer(remainingSec ?? 0);
return;
@ -75,7 +82,8 @@ class _OtpViewState extends State<OtpView> {
}
handleTimerOnBackground() async {
bool timeStampSaved = await SharedPreferencesHelper.readBoolFromSP('timeStampSaved') ?? false;
bool timeStampSaved =
await SharedPreferencesHelper.readBoolFromSP('timeStampSaved') ?? false;
if (!timeStampSaved) {
final dateInString = DateTime.now().toString();
SharedPreferencesHelper.saveIntToSP('savedCounter', remainingSec ?? 0);
@ -115,7 +123,8 @@ class _OtpViewState extends State<OtpView> {
@override
Widget build(BuildContext context) {
String maskedEmail = AuthCubit.get(context).maskEmail(AuthCubit.get(context).email);
String maskedEmail =
AuthCubit.get(context).maskEmail(AuthCubit.get(context).email);
return BlocConsumer<AuthCubit, AuthState>(
listener: (context, state) {
if (state is AuthOtpSuccess) {
@ -199,7 +208,10 @@ class _OtpViewState extends State<OtpView> {
child: RichText(
text: TextSpan(
text: 'We have sent the verification code to',
style: Theme.of(context).textTheme.titleSmall!.copyWith(
style: Theme.of(context)
.textTheme
.titleSmall!
.copyWith(
color: Colors.white,
fontWeight: FontsManager.regular,
fontSize: 14,
@ -207,7 +219,10 @@ class _OtpViewState extends State<OtpView> {
children: [
TextSpan(
text: ' $maskedEmail',
style: Theme.of(context).textTheme.titleSmall!.copyWith(
style: Theme.of(context)
.textTheme
.titleSmall!
.copyWith(
color: Colors.black,
fontWeight: FontsManager.bold,
fontSize: 14,
@ -215,7 +230,10 @@ class _OtpViewState extends State<OtpView> {
),
TextSpan(
text: ' change email?',
style: Theme.of(context).textTheme.titleSmall!.copyWith(
style: Theme.of(context)
.textTheme
.titleSmall!
.copyWith(
color: const Color(0xFF87C7FF),
fontWeight: FontsManager.regular,
fontSize: 14,
@ -239,7 +257,8 @@ class _OtpViewState extends State<OtpView> {
keyboardType: TextInputType.number,
autoFocus: true,
backgroundColor: Colors.transparent,
animationDuration: const Duration(milliseconds: 30),
animationDuration:
const Duration(milliseconds: 30),
beforeTextPaste: (text) {
// Allow pasting only if all characters are numeric
return int.tryParse(text!) != null;
@ -262,18 +281,27 @@ class _OtpViewState extends State<OtpView> {
errorBorderWidth: 1,
borderWidth: 1,
errorBorderColor: Colors.red,
activeColor: state is AuthLoginError ? Colors.red : Colors.white,
inactiveColor:
state is AuthLoginError ? Colors.red : Colors.white,
activeFillColor:
state is AuthLoginError ? Colors.red : Colors.white,
inactiveFillColor:
state is AuthLoginError ? Colors.red : Colors.white,
selectedFillColor:
state is AuthLoginError ? Colors.red : Colors.white,
activeColor: state is AuthLoginError
? Colors.red
: Colors.white,
inactiveColor: state is AuthLoginError
? Colors.red
: Colors.white,
activeFillColor: state is AuthLoginError
? Colors.red
: Colors.white,
inactiveFillColor: state is AuthLoginError
? Colors.red
: Colors.white,
selectedFillColor: state is AuthLoginError
? Colors.red
: Colors.white,
disabledColor: Colors.white,
fieldHeight: 56,
fieldWidth: MediaQuery.sizeOf(context).width > 340 ? 40 : 20,
fieldWidth:
MediaQuery.sizeOf(context).width > 340
? 40
: 20,
// fieldWidth: 40,
selectedColor: Colors.white,
shape: PinCodeFieldShape.box,
@ -295,10 +323,12 @@ class _OtpViewState extends State<OtpView> {
isDone: state is AuthLoginSuccess,
isLoading: state is AuthLoading,
customButtonStyle: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
backgroundColor:
MaterialStateProperty.all(
Colors.black.withOpacity(.25),
),
foregroundColor: MaterialStateProperty.all(
foregroundColor:
MaterialStateProperty.all(
Colors.white,
),
),
@ -307,7 +337,8 @@ class _OtpViewState extends State<OtpView> {
),
onPressed: () {
if ((state is! AuthLoading)) {
AuthCubit.get(context).verifyOtp(widget.isForgetPage);
AuthCubit.get(context)
.verifyOtp(widget.isForgetPage);
FocusScope.of(context).unfocus();
}
},
@ -321,10 +352,12 @@ class _OtpViewState extends State<OtpView> {
isDone: state is AuthLoginSuccess,
isLoading: state is AuthLoading,
customButtonStyle: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
backgroundColor:
MaterialStateProperty.all(
Colors.black.withOpacity(.25),
),
foregroundColor: MaterialStateProperty.all(
foregroundColor:
MaterialStateProperty.all(
Colors.white,
),
),
@ -341,8 +374,20 @@ class _OtpViewState extends State<OtpView> {
return;
}
if ((state is! AuthLoading)) {
await AuthCubit.get(context).reSendOtp();
bool success = await AuthCubit.get(context)
.reSendOtp();
FocusScope.of(context).unfocus();
if(success){
showDialog(
context: context,
builder: (_) => SuccessDialog(
key: ValueKey('SuccessDialog'),
message: 'New OTP sent!',));
}
Future.delayed(Duration(seconds: 2),
() {
Navigator.of(context).pop();
});
}
},
),

View File

@ -105,8 +105,8 @@ class SignUpView extends StatelessWidget {
autocorrect: false,
autofillHints: const [AutofillHints.name],
// controller: AuthCubit.get(context).fullNameController,
validator: (value) =>
AuthCubit.get(context).fullNameValidator(value),
validator: (value) => AuthCubit.get(context)
.fullNameValidator(value),
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
@ -114,7 +114,11 @@ class SignUpView extends StatelessWidget {
AuthCubit.get(context).fullName = value;
},
onTap: () {},
decoration: defaultInputDecoration(context, hint: "Full Name"),
decoration: defaultInputDecoration(context,
hint: "Full Name")
.copyWith(
errorMaxLines: 2,
),
),
const SizedBox(height: 16),
const BodyMedium(
@ -129,15 +133,16 @@ class SignUpView extends StatelessWidget {
autocorrect: false,
enableSuggestions: false,
autofillHints: const [AutofillHints.email],
validator: AuthCubit.get(context).emailAddressValidator,
validator: AuthCubit.get(context)
.emailAddressValidator,
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
onChanged: (value) {
AuthCubit.get(context).email = value;
},
decoration:
defaultInputDecoration(context, hint: "Example@email.com"),
decoration: defaultInputDecoration(context,
hint: "Example@email.com"),
),
const SizedBox(height: 16),
const BodyMedium(
@ -150,17 +155,25 @@ class SignUpView extends StatelessWidget {
keyboardType: TextInputType.text,
scrollPadding: EdgeInsets.zero,
autocorrect: false,
autofillHints: const [AutofillHints.password],
validator: AuthCubit.get(context).passwordValidator,
autofillHints: const [
AutofillHints.password
],
validator: AuthCubit.get(context)
.passwordValidator,
onChanged: (value) {
AuthCubit.get(context).signUpPassword = value;
AuthCubit.get(context).signUpPassword =
value;
},
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
obscureText: !AuthCubit.get(context).isPasswordVisible,
obscureText: !AuthCubit.get(context)
.isPasswordVisible,
decoration: defaultInputDecoration(context,
hint: "At least 8 characters"),
hint: "At least 8 characters")
.copyWith(
errorMaxLines: 8,
),
),
const SizedBox(height: 16),
const BodyMedium(
@ -174,13 +187,17 @@ class SignUpView extends StatelessWidget {
scrollPadding: EdgeInsets.zero,
autocorrect: false,
enableSuggestions: false,
autofillHints: const [AutofillHints.password],
autofillHints: const [
AutofillHints.password
],
onChanged: (value) {},
validator: AuthCubit.get(context).reEnterPasswordCheck,
validator: AuthCubit.get(context)
.reEnterPasswordCheck,
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
obscureText: !AuthCubit.get(context).isPasswordVisible,
obscureText: !AuthCubit.get(context)
.isPasswordVisible,
decoration: defaultInputDecoration(context,
hint: "At least 8 characters"),
),
@ -193,10 +210,12 @@ class SignUpView extends StatelessWidget {
isDone: state is AuthLoginSuccess,
isLoading: state is AuthLoading,
customButtonStyle: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
backgroundColor:
MaterialStateProperty.all(
Colors.black.withOpacity(.25),
),
foregroundColor: MaterialStateProperty.all(
foregroundColor:
MaterialStateProperty.all(
Colors.white,
),
),
@ -204,11 +223,14 @@ class SignUpView extends StatelessWidget {
'Sign up',
),
onPressed: () {
AuthCubit.get(context).showValidationMessage = true;
if (formKey.currentState!.validate()) {
AuthCubit.get(context)
.showValidationMessage = true;
if (formKey.currentState!
.validate()) {
if ((state is! AuthLoading)) {
AuthCubit.get(context).signUp();
FocusScope.of(context).unfocus();
FocusScope.of(context)
.unfocus();
}
}
},

View File

@ -0,0 +1,184 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
double curtainWidth = 270;
double curtainOpeningSpace = 195;
double blindHeight = 310;
double blindOpeningSpace = 245;
double openPercentage = 0;
bool isMoving = false;
final String curtainId;
CurtainBloc(
this.curtainId,
) : super(CurtainInitial()) {
on<InitCurtain>(_fetchStatus);
on<OpenCurtain>(_onOpenCurtain);
on<CloseCurtain>(_onCloseCurtain);
on<PauseCurtain>(_onPauseCurtain);
}
Future<void> _onOpenCurtain(
OpenCurtain event,
Emitter<CurtainState> emit) async {
isMoving = true;
while (openPercentage < 100.0) {
if (state is CurtainsClosing) {
_pauseCurtain(emit);
break;
}
emit(CurtainsOpening(
curtainWidth: curtainWidth,
blindHeight: blindHeight,
openPercentage: openPercentage,
));
if (isMoving) {
await Future.delayed(const Duration(milliseconds: 200), () async {
openPercentage += 10.0;
event.deviceType == DeviceType.Curtain
? curtainWidth -= curtainOpeningSpace / 10
: blindHeight -= blindOpeningSpace / 10;
if (openPercentage >= 100.0) {
_pauseCurtain(emit);
}
});
if (openPercentage >=100.0) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
code: 'control',
value: 'close',
),
curtainId,
);
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
code: 'percent_control',
value: 100,
),
curtainId,
);
}
} else {
_pauseCurtain(emit);
break;
}
}
}
Future<void> _onCloseCurtain(
CloseCurtain event, Emitter<CurtainState> emit) async {
isMoving = true;
while (openPercentage > 0.0) {
if (state is CurtainsOpening) {
_pauseCurtain(emit);
break;
}
emit(CurtainsClosing(
curtainWidth: curtainWidth,
blindHeight: blindHeight,
openPercentage: openPercentage,
));
if (isMoving) {
await Future.delayed(const Duration(milliseconds: 200), () async {
openPercentage -= 10.0;
event.deviceType == DeviceType.Curtain
? curtainWidth += curtainOpeningSpace / 10
: blindHeight += blindOpeningSpace / 10;
if (openPercentage <= 0.0) {
_pauseCurtain(emit);
}
});
if (openPercentage == 0.0) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
code: 'percent_control',
value: 0,
),
curtainId,
);
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
code: 'control',
value: 'open',
),
curtainId,
);
}
} else {
_pauseCurtain(emit);
break;
}
}
}
Future<void> _onPauseCurtain(
PauseCurtain event, Emitter<CurtainState> emit) async {
_pauseCurtain(emit);
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
code: 'control',
value: 'stop',
),
curtainId,
);
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
code: 'percent_control',
value: openPercentage.ceil(),
),
curtainId,
);
}
Future<void> _pauseCurtain(Emitter<CurtainState> emit) async {
isMoving = false;
emit(CurtainsPaused(
curtainWidth: curtainWidth,
blindHeight: blindHeight,
openPercentage: openPercentage,
));
}
void _fetchStatus(InitCurtain event, Emitter<CurtainState> emit) async {
try {
emit(CurtainLoadingState());
// Fetch the status from the API
var response = await DevicesAPI.getDeviceStatus(curtainId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
// Get the open percentage from the response
openPercentage = double.tryParse(statusModelList[1].value.toString())!;
// Calculate curtain width and blind height based on the open percentage
if (openPercentage != null) {
curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
}
emit(CurtainsOpening(
curtainWidth: curtainWidth,
blindHeight: blindHeight,
openPercentage: openPercentage,
));
} catch (e) {
emit(FailedState());
return;
}
}
}

View File

@ -0,0 +1,34 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
abstract class CurtainEvent extends Equatable {
const CurtainEvent();
@override
List<Object?> get props => [];
}
class OpenCurtain extends CurtainEvent {
final DeviceType deviceType;
const OpenCurtain(this.deviceType);
@override
List<Object?> get props => [deviceType];
}
class CloseCurtain extends CurtainEvent {
final DeviceType deviceType;
const CloseCurtain(this.deviceType);
@override
List<Object?> get props => [deviceType];
}
class InitCurtain extends CurtainEvent {}
class PauseCurtain extends CurtainEvent {}
class useCurtainEvent extends CurtainEvent {}

View File

@ -0,0 +1,76 @@
// curtain_state.dart
import 'package:equatable/equatable.dart';
abstract class CurtainState extends Equatable {
const CurtainState();
@override
List<Object?> get props => [];
}
class CurtainInitial extends CurtainState {}
class UpdateCurtain extends CurtainState {
final double curtainWidth;
final double blindHeight;
final double openPercentage;
const UpdateCurtain({
required this.curtainWidth,
required this.blindHeight,
required this.openPercentage,
});
@override
List<Object?> get props => [curtainWidth, blindHeight, openPercentage];
}
class FailedState extends CurtainState {}
class CurtainLoadingState extends CurtainState {}
class CurtainsOpening extends CurtainState {
final double curtainWidth;
final double blindHeight;
final double openPercentage;
const CurtainsOpening({
required this.curtainWidth,
required this.blindHeight,
required this.openPercentage,
});
@override
List<Object?> get props => [curtainWidth, blindHeight, openPercentage];
}
class CurtainsClosing extends CurtainState {
final double curtainWidth;
final double blindHeight;
final double openPercentage;
const CurtainsClosing({
required this.curtainWidth,
required this.blindHeight,
required this.openPercentage,
});
@override
List<Object?> get props => [curtainWidth, blindHeight, openPercentage];
}
class CurtainsPaused extends CurtainState {
final double curtainWidth;
final double blindHeight;
final double openPercentage;
const CurtainsPaused({
required this.curtainWidth,
required this.blindHeight,
required this.openPercentage,
});
@override
List<Object?> get props => [curtainWidth, blindHeight, openPercentage];
}

View File

@ -397,87 +397,7 @@ class DevicesCubit extends Cubit<DevicesState> {
// }
// }
//////////////////////////////////CURTAINS//////////////////////////////////////
double curtainWidth = 270;
double curtainOpeningSpace = 195;
double blindWindowHight = 310;
double blindOpeningSpace = 245;
double _openPercentage = 0;
bool isMoving = false;
openCurtain(DeviceType type) async {
if (state is CurtainsIsOpening) {
return;
}
isMoving = true;
while (_openPercentage < 100.0) {
if (state is CurtainsIsClosing) {
//listen to interruption by the closing process
pauseCurtain();
break;
}
emit(CurtainsIsOpening());
if (isMoving) {
await Future.delayed(const Duration(milliseconds: 200), () {
_openPercentage += 10.0;
//25.5 is the 10% of the curtain opening space, its used to update the
// animated container of thecurtain
type == DeviceType.Curtain
? curtainWidth -= curtainOpeningSpace / 10
: blindWindowHight -= blindOpeningSpace / 10;
if (_openPercentage >= 100.0) {
pauseCurtain();
}
});
} else {
pauseCurtain();
break;
}
}
}
closeCurtain(DeviceType type) async {
if (state is CurtainsIsClosing) {
return;
}
isMoving = true;
while (_openPercentage > 0.0) {
if (state is CurtainsIsOpening) {
// interrupted by the opening process
pauseCurtain();
break;
}
emit(CurtainsIsClosing());
if (isMoving) {
await Future.delayed(const Duration(milliseconds: 200), () {
_openPercentage -= 10.0;
//25.5 is the 10% of the curtain opening space, its used to update the
type == DeviceType.Curtain
? curtainWidth += curtainOpeningSpace / 10
: blindWindowHight += 24.5;
if (_openPercentage <= 0.0) {
pauseCurtain();
}
});
} else {
pauseCurtain();
break;
}
}
}
pauseCurtain() {
isMoving = false;
emit(CurtainsStopped());
}
}
enum LightMode {

View File

@ -0,0 +1,179 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
import 'package:syncrow_app/features/devices/model/door_sensor_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
final String DSId;
DoorSensorBloc({
required this.DSId,
}) : super(const DoorSensorState()) {
on<DoorSensorInitial>(_fetchStatus);
on<ReportLogsInitial>(fetchLogsForLastMonth);
on<ToggleLowBatteryEvent>(_toggleLowBattery);
on<ToggleClosingReminderEvent>(_toggleClosingReminder);
on<ToggleDoorAlarmEvent>(_toggleDoorAlarm);
}
Timer? _timer;
bool lowBattery = false;
bool closingReminder = false;
bool doorAlarm = false;
DoorSensorModel deviceStatus =
DoorSensorModel(doorContactState: false, batteryPercentage: 0);
void _fetchStatus(
DoorSensorInitial event, Emitter<DoorSensorState> emit) async {
emit(DoorSensorLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(DSId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = DoorSensorModel.fromJson(
statusModelList,
);
emit(UpdateState(doorSensor: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
_listenToChanges();
} catch (e) {
emit(DoorSensorFailedState(errorMessage: e.toString()));
return;
}
}
// Toggle functions for each switch
void _toggleLowBattery(
ToggleLowBatteryEvent event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
lowBattery = event.isLowBatteryEnabled;
emit(UpdateState(doorSensor: deviceStatus));
// API call to update the state, if necessary
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: DSId,
code: 'low_battery',
value: lowBattery,
),
DSId,
);
} catch (e) {
emit(DoorSensorFailedState(errorMessage: e.toString()));
}
}
void _toggleClosingReminder(
ToggleClosingReminderEvent event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
closingReminder = event.isClosingReminderEnabled;
emit(UpdateState(doorSensor: deviceStatus));
// API call to update the state, if necessary
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: DSId,
code: 'closing_reminder',
value: closingReminder,
),
DSId,
);
} catch (e) {
emit(DoorSensorFailedState(errorMessage: e.toString()));
}
}
void _toggleDoorAlarm(
ToggleDoorAlarmEvent event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
doorAlarm = event.isDoorAlarmEnabled;
emit(UpdateState(doorSensor: deviceStatus));
// API call to update the state, if necessary
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: DSId,
code: 'door_alarm',
value: doorAlarm,
),
DSId,
);
} catch (e) {
emit(DoorSensorFailedState(errorMessage: e.toString()));
}
}
DeviceReport recordGroups =
DeviceReport(startTime: '0', endTime: '0', data: []);
Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<DoorSensorState> emit) async {
// Get the current date and time
DateTime now = DateTime.now();
// Calculate the date one month ago
DateTime lastMonth = DateTime(now.year, now.month - 1, now.day);
// Convert the date to milliseconds since epoch (Unix timestamp in milliseconds)
int startTime = lastMonth.millisecondsSinceEpoch;
int endTime = now.millisecondsSinceEpoch;
try {
emit(DoorSensorLoadingState());
var response = await DevicesAPI.getReportLogs(
startTime:
startTime.toString(), // Convert to String if the API expects it
endTime: endTime.toString(), // Convert to String if the API expects it
deviceUuid: DSId,
code: 'doorcontact_state',
);
print('response======${response}');
recordGroups = response;
// Process response here
emit(UpdateState(doorSensor: deviceStatus));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
// Handle error
print('Error fetching logs: ${errorMessage}');
}
}
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$DSId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async {
if (_timer != null) {
await Future.delayed(const Duration(seconds: 2));
}
Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: true));
});
deviceStatus = DoorSensorModel.fromJson(statusList);
if (!isClosed) {
add(
DoorSensorSwitch(switchD: deviceStatus.doorContactState),
);
}
});
} catch (_) {}
}
}

View File

@ -0,0 +1,102 @@
import 'package:equatable/equatable.dart';
abstract class DoorSensorEvent extends Equatable {
const DoorSensorEvent();
@override
List<Object> get props => [];
}
class DoorSensorLoading extends DoorSensorEvent {}
class DoorSensorSwitch extends DoorSensorEvent {
final bool switchD;
final String deviceId;
final String productId;
const DoorSensorSwitch({required this.switchD, this.deviceId = '', this.productId = ''});
@override
List<Object> get props => [switchD, deviceId, productId];
}
class DoorSensorUpdated extends DoorSensorEvent {}
class DoorSensorInitial extends DoorSensorEvent {
const DoorSensorInitial();
}
class ReportLogsInitial extends DoorSensorEvent {
const ReportLogsInitial();
}
class DoorSensorChangeStatus extends DoorSensorEvent {}
class GetCounterEvent extends DoorSensorEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class ToggleLowBatteryEvent extends DoorSensorEvent {
final bool isLowBatteryEnabled;
const ToggleLowBatteryEvent(this.isLowBatteryEnabled);
@override
List<Object> get props => [isLowBatteryEnabled];
}
class ToggleClosingReminderEvent extends DoorSensorEvent {
final bool isClosingReminderEnabled;
const ToggleClosingReminderEvent(this.isClosingReminderEnabled);
@override
List<Object> get props => [isClosingReminderEnabled];
}
class ToggleDoorAlarmEvent extends DoorSensorEvent {
final bool isDoorAlarmEnabled;
const ToggleDoorAlarmEvent(this.isDoorAlarmEnabled);
@override
List<Object> get props => [isDoorAlarmEnabled];
}
class SetCounterValue extends DoorSensorEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends DoorSensorEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends DoorSensorEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends DoorSensorEvent {}
class OnClose extends DoorSensorEvent {}

View File

@ -0,0 +1,128 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/door_sensor_model.dart';
class DoorSensorState extends Equatable {
const DoorSensorState();
@override
List<Object> get props => [];
}
class DoorSensorInitialState extends DoorSensorState {}
class DoorSensorLoadingState extends DoorSensorState {}
class DoorSensorFailedState extends DoorSensorState {
final String errorMessage;
const DoorSensorFailedState({required this.errorMessage});
@override
List<Object> get props => [errorMessage];
}
class UpdateState extends DoorSensorState {
final DoorSensorModel doorSensor;
const UpdateState({required this.doorSensor});
@override
List<Object> get props => [doorSensor];
}
class LoadingNewSate extends DoorSensorState {
final DoorSensorModel doorSensor;
const LoadingNewSate({required this.doorSensor});
@override
List<Object> get props => [doorSensor];
}
// class WHModifyingState extends DoorSensorState {
// final WHModel whStatusModel;
// const WHModifyingState({required this.whStatusModel});
//
// @override
// List<Object> get props => [whStatusModel];
// }
//
// class GetWHStatusState extends DoorSensorState {
// final WHModel whStatusModel;
// const GetWHStatusState({required this.whStatusModel});
//
// @override
// List<Object> get props => [whStatusModel];
// }
//
//
// class WHFailedState extends WaterHeaterState {
// final String errorMessage;
//
// const WHFailedState({required this.errorMessage});
//
// @override
// List<Object> get props => [errorMessage];
// }
// class LoadingNewSate extends WaterHeaterState {
// final WHModel whModel;
// const LoadingNewSate({required this.whModel});
//
// @override
// List<Object> get props => [whModel];
// }
// class TimerRunComplete extends WaterHeaterState {}
// class UpdateTimerState extends WaterHeaterState {
// final int seconds;
// const UpdateTimerState({required this.seconds});
//
// @override
// List<Object> get props => [seconds];
// }
//
// class TimerRunInProgress extends WaterHeaterState {
// final int remainingTime;
//
// const TimerRunInProgress(this.remainingTime);
//
// @override
// List<Object> get props => [remainingTime];
// }
//
// class SaveSchedule extends WaterHeaterState {}
// class ChangeTimeState extends WaterHeaterState {}
// class UpdateCreateScheduleState extends WaterHeaterState {
// final bool createSchedule;
// UpdateCreateScheduleState(this.createSchedule);
// }
// class IsToggleState extends WaterHeaterState {
// final bool? onOff;
// const IsToggleState({this.onOff});
// }
//
//
// class UpdateState extends WaterHeaterState {
// final WHModel whModel;
// const UpdateState({required this.whModel});
//
// @override
// List<Object> get props => [WHModel];
// }
//
// class ChangeSwitchStatusEvent extends WaterHeaterState {
// final bool value;
// final String deviceId;
// const ChangeSwitchStatusEvent({required this.value, this.deviceId = ''});
// @override
// List<Object> get props => [value, deviceId];
// }
//
// class ChangeSlidingSegmentState extends WaterHeaterState {
// final int value;
//
// const ChangeSlidingSegmentState({required this.value});
//
// @override
// List<Object> get props => [value];
// }

View File

@ -0,0 +1,470 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_one_gang_model.dart';
import 'package:syncrow_app/features/devices/model/one_gang_model.dart';
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'one_gang_event.dart';
class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
final String oneGangId;
final String switchCode;
OneGangModel deviceStatus = OneGangModel(
firstSwitch: false,
firstCountDown: 0,
);
Timer? _timer;
bool oneGangGroup = false;
List<DeviceModel> devicesList = [];
OneGangBloc({required this.oneGangId, required this.switchCode}) : super(InitialState()) {
on<InitialEvent>(_fetchOneGangStatus);
on<OneGangUpdated>(_oneGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
on<ChangeSlidingSegment>(_changeSliding);
on<SetCounterValue>(_setCounterValue);
on<GetCounterEvent>(_getCounterValue);
on<TickTimer>(_onTickTimer);
on<OnClose>(_onClose);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<ScheduleSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleChange);
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<InitialWizardEvent>(_fetchOneGangWizardStatus);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
}
void _fetchOneGangStatus(InitialEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(oneGangId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = OneGangModel.fromJson(statusModelList);
emit(UpdateState(oneGangModel: deviceStatus));
_listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$oneGangId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async {
if (_timer != null) {
await Future.delayed(const Duration(seconds: 2));
}
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = OneGangModel.fromJson(statusList);
if (!isClosed) {
add(OneGangUpdated());
}
});
} catch (_) {}
}
_oneGangUpdated(OneGangUpdated event, Emitter<OneGangState> emit) {
emit(UpdateState(oneGangModel: deviceStatus));
}
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.value;
emit(UpdateState(oneGangModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: oneGangGroup ? event.deviceId : oneGangId,
code: 'switch_1',
value: !event.value),
oneGangGroup ? event.deviceId : oneGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: oneGangGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: oneGangGroup));
}
}
void _changeSliding(ChangeSlidingSegment event, Emitter<OneGangState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(SetCounterValue event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: oneGangId, code: event.deviceCode, value: seconds),
oneGangId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown = seconds;
}
} else {
emit(const FailedState(error: 'Something went wrong'));
return;
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(GetCounterEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(oneGangId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = OneGangModel.fromJson(statusModelList);
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown > 0
? _onStartTimer(deviceStatus.firstCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _onClose(OnClose event, Emitter<OneGangState> emit) {
_timer?.cancel();
}
void _onStartTimer(int seconds) {
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
add(TickTimer(seconds - timer.tick));
});
}
void _onTickTimer(TickTimer event, Emitter<OneGangState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"},
{"day": "Mon", "key": "Mon"},
{"day": "Tue", "key": "Tue"},
{"day": "Wed", "key": "Wed"},
{"day": "Thu", "key": "Thu"},
{"day": "Fri", "key": "Fri"},
{"day": "Sat", "key": "Sat"},
];
Future<void> saveSchedule(
ScheduleSave event,
Emitter<OneGangState> emit,
) async {
try {
if (selectedDays.isNotEmpty) {
emit(LoadingInitialState());
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: oneGangId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(SaveSchedule());
add(const ToggleCreateScheduleEvent(index: 1));
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(FailedState(error: e.toString()));
}
}
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<OneGangState> emit,
) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: oneGangId,
);
List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds =
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
}
Future toggleChange(ToggleScheduleEvent event, Emitter<OneGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: oneGangId, enable: event.toggle);
if (response == true) {
add(GetScheduleEvent());
toggleSchedule = event.toggle;
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
Future deleteSchedule(DeleteScheduleEvent event, Emitter<OneGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: oneGangId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<OneGangState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
List<ScheduleModel> listSchedule = [];
DateTime? selectedTime = DateTime.now();
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<OneGangState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(const ChangeSlidingSegment(value: 1));
}
int selectedTabIndex = 0;
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<OneGangState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
List<GroupOneGangModel> groupOneGangList = [];
bool allSwitchesOn = true;
void _fetchOneGangWizardStatus(InitialWizardEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
groupOneGangList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '1G');
for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = OneGangModel.fromJson(statusModelList);
groupOneGangList.add(GroupOneGangModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
));
}
if (groupOneGangList.isNotEmpty) {
groupOneGangList.firstWhere((element) {
if (!element.firstSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _changeFirstWizardSwitch(
ChangeFirstWizardSwitchStatusEvent event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupOneGangList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: [event.deviceId],
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialEvent(groupScreen: oneGangGroup));
}
} catch (_) {
add(InitialEvent(groupScreen: oneGangGroup));
}
}
void _groupAllOn(GroupAllOnEvent event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
for (int i = 0; i < groupOneGangList.length; i++) {
groupOneGangList[i].firstSwitch = true;
}
// Emit the state with updated values
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: true));
// Get a list of all device IDs
List<String> allDeviceIds = groupOneGangList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', // Controls first switch for all devices
devicesUuid: allDeviceIds,
value: true, // true (on) or false (off) depending on the event value
);
// Check if either response is unsuccessful, then reset to initial state
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
// In case of an error, delay and reset the screen to initial state
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
void _groupAllOff(GroupAllOffEvent event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus));
try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
for (int i = 0; i < groupOneGangList.length; i++) {
groupOneGangList[i].firstSwitch = false;
}
// Emit the state with updated values
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: false));
// Get a list of all device IDs
List<String> allDeviceIds = groupOneGangList.map((device) => device.deviceId).toList();
// First call for switch_1
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', // Controls first switch for all devices
devicesUuid: allDeviceIds,
value: false, // true (on) or false (off) depending on the event value
);
// Check if either response is unsuccessful, then reset to initial state
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
} catch (_) {
// In case of an error, delay and reset the screen to initial state
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
}

View File

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

View File

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

View File

@ -54,6 +54,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
bool isStartEndTime = true;
DateTime? startTime;
DateTime? endTime;
int unlockRequest = 0;
List<TemporaryPassword>? temporaryPasswords = [];
List<OfflinePasswordModel>? oneTimePasswords = [];
List<OfflinePasswordModel>? timeLimitPasswords = [];
@ -128,6 +129,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
_doorLockUpdated(DoorLockUpdated event, Emitter<SmartDoorState> emit) {
unlockRequest = deviceStatus.unlockRequest;
emit(UpdateState(smartDoorModel: deviceStatus));
}

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
@ -7,12 +8,15 @@ import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_sta
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_three_gang_model.dart';
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/model/three_gang_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
final String threeGangId;
final String switchCode;
ThreeGangModel deviceStatus = ThreeGangModel(
firstSwitch: false,
secondSwitch: false,
@ -21,16 +25,13 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
secondCountDown: 0,
thirdCountDown: 0);
Timer? _timer;
// Timer? _firstSwitchTimer;
// Timer? _secondSwitchTimer;
// Timer? _thirdSwitchTimer;
bool threeGangGroup = false;
List<DeviceModel> devicesList = [];
List<GroupThreeGangModel> groupThreeGangList = [];
bool allSwitchesOn = true;
ThreeGangBloc({required this.threeGangId}) : super(InitialState()) {
ThreeGangBloc({required this.threeGangId, required this.switchCode}) : super(InitialState()) {
on<InitialEvent>(_fetchThreeGangStatus);
on<ThreeGangUpdated>(_threeGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -45,6 +46,15 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
on<OnClose>(_onClose);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<ThreeGangSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleChange);
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
}
void _fetchThreeGangStatus(InitialEvent event, Emitter<ThreeGangState> emit) async {
@ -190,7 +200,6 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
@ -460,9 +469,6 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
void _onClose(OnClose event, Emitter<ThreeGangState> emit) {
_timer?.cancel();
// _firstSwitchTimer?.cancel();
// _secondSwitchTimer?.cancel();
// _thirdSwitchTimer?.cancel();
}
void _onStartTimer(int seconds) {
@ -480,4 +486,141 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
emit(TimerRunComplete());
}
}
List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"},
{"day": "Mon", "key": "Mon"},
{"day": "Tue", "key": "Tue"},
{"day": "Wed", "key": "Wed"},
{"day": "Thu", "key": "Thu"},
{"day": "Fri", "key": "Fri"},
{"day": "Sat", "key": "Sat"},
];
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<ThreeGangState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(ChangeSlidingSegment(value: 1));
}
Future<void> saveSchedule(
ThreeGangSave event,
Emitter<ThreeGangState> emit,
) async {
try {
if (selectedDays.isNotEmpty) {
emit(LoadingInitialState());
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: threeGangId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(ThreeGangSaveSchedule());
add(const ToggleCreateScheduleEvent(index: 1));
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(FailedState(error: e.toString()));
}
}
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<ThreeGangState> emit,
) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: threeGangId,
);
List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds =
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
}
Future toggleChange(ToggleScheduleEvent event, Emitter<ThreeGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: threeGangId, enable: event.toggle);
if (response == true) {
add(GetScheduleEvent());
toggleSchedule = event.toggle;
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
Future deleteSchedule(DeleteScheduleEvent event, Emitter<ThreeGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: threeGangId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<ThreeGangState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<ThreeGangState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
int selectedTabIndex = 0;
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
List<ScheduleModel> listSchedule = [];
DateTime? selectedTime = DateTime.now();
}

View File

@ -93,3 +93,48 @@ class TickTimer extends ThreeGangEvent {
class StopTimer extends ThreeGangEvent {}
class OnClose extends ThreeGangEvent {}
//------------------- Schedule ----------=---------
class GetScheduleEvent extends ThreeGangEvent {}
class ThreeGangSave extends ThreeGangEvent {}
class ToggleScheduleEvent extends ThreeGangEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle,required this.id});
@override
List<Object> get props => [toggle,id];
}
class ToggleDaySelectionEvent extends ThreeGangEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
class DeleteScheduleEvent extends ThreeGangEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@override
List<Object> get props => [id];
}
class ToggleSelectedEvent extends ThreeGangEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@override
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends ThreeGangEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@override
List<Object> get props => [index];
}
class InitialWizardDevises extends ThreeGangEvent {}

View File

@ -75,3 +75,15 @@ class TimerRunInProgress extends ThreeGangState {
}
class TimerRunComplete extends ThreeGangState {}
class ThreeGangSaveSchedule extends ThreeGangState {}
class IsToggleState extends ThreeGangState {
final bool? onOff;
const IsToggleState({this.onOff});
}
class ChangeTimeState extends ThreeGangState {}
class UpdateCreateScheduleState extends ThreeGangState {
final bool createSchedule;
UpdateCreateScheduleState(this.createSchedule);
}

View File

@ -0,0 +1,629 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_event.dart';
import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_two_gang_model.dart';
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/model/two_gang_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
final String twoGangId;
final String switchCode;
TwoGangModel deviceStatus = TwoGangModel(
firstSwitch: false,
secondSwitch: false,
firstCountDown: 0,
secondCountDown: 0,
);
Timer? _timer;
bool twoGangGroup = false;
List<DeviceModel> devicesList = [];
List<GroupTwoGangModel> groupTwoGangList = [];
bool allSwitchesOn = true;
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
List<ScheduleModel> listSchedule = [];
TwoGangBloc({required this.twoGangId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchTwoGangStatus);
on<TwoGangUpdated>(_twoGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
on<ChangeSecondSwitchStatusEvent>(_changeSecondSwitch);
on<AllOffEvent>(_allOff);
on<AllOnEvent>(_allOn);
on<ChangeSlidingSegment>(_changeSliding);
on<SetCounterValue>(_setCounterValue);
on<GetCounterEvent>(_getCounterValue);
on<TickTimer>(_onTickTimer);
on<OnClose>(_onClose);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<TwoGangSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleRepeat);
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<InitialWizardEvent>(_fetchTwoGangWizardStatus);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<ChangeSecondWizardSwitchStatusEvent>(_changeSecondWizardSwitch);
}
DateTime? selectedTime = DateTime.now();
int selectedTabIndex = 0;
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<TwoGangState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<TwoGangState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
void _fetchTwoGangStatus(
InitialEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(twoGangId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoGangModel.fromJson(statusModelList);
emit(UpdateState(twoGangModel: deviceStatus));
_listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$twoGangId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async {
if (_timer != null) {
await Future.delayed(const Duration(seconds: 2));
}
Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = TwoGangModel.fromJson(statusList);
if (!isClosed) {
add(TwoGangUpdated());
}
});
} catch (_) {}
}
_twoGangUpdated(TwoGangUpdated event, Emitter<TwoGangState> emit) {
emit(UpdateState(twoGangModel: deviceStatus));
}
void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.value;
emit(UpdateState(twoGangModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId, code: 'switch_1', value: !event.value),
twoGangId);
if (!response['success']) {
add(const InitialEvent());
}
});
} catch (_) {
add(const InitialEvent());
}
}
void _changeSecondSwitch(
ChangeSecondSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
deviceStatus.secondSwitch = !event.value;
emit(UpdateState(twoGangModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId, code: 'switch_2', value: !event.value),
twoGangId);
if (!response['success']) {
add(const InitialEvent());
}
});
} catch (_) {
add(const InitialEvent());
}
}
void _allOff(AllOffEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
deviceStatus.firstSwitch = false;
deviceStatus.secondSwitch = false;
emit(UpdateState(twoGangModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
twoGangId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
twoGangId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
}
void _allOn(AllOnEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
deviceStatus.firstSwitch = true;
deviceStatus.secondSwitch = true;
emit(UpdateState(twoGangModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
twoGangId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
twoGangId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
}
void _groupAllOn(GroupAllOnEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
for (int i = 0; i < groupTwoGangList.length; i++) {
groupTwoGangList[i].firstSwitch = true;
groupTwoGangList[i].secondSwitch = true;
}
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: true));
List<String> allDeviceIds =
groupTwoGangList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: true,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: true,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
void _groupAllOff(GroupAllOffEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
for (int i = 0; i < groupTwoGangList.length; i++) {
groupTwoGangList[i].firstSwitch = false;
groupTwoGangList[i].secondSwitch = false;
}
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: false));
List<String> allDeviceIds =
groupTwoGangList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: false,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: false,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
void _changeSliding(
ChangeSlidingSegment event, Emitter<TwoGangState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(
SetCounterValue event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoGangId, code: event.deviceCode, value: seconds),
twoGangId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown = seconds;
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown = seconds;
}
} else {
emit(const FailedState(error: 'Something went wrong'));
return;
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(
GetCounterEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState());
try {
add(GetScheduleEvent());
var response = await DevicesAPI.getDeviceStatus(twoGangId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoGangModel.fromJson(statusModelList);
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown > 0
? _onStartTimer(deviceStatus.firstCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown > 0
? _onStartTimer(deviceStatus.secondCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.secondCountDown));
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _onClose(OnClose event, Emitter<TwoGangState> emit) {
_timer?.cancel();
}
void _onStartTimer(int seconds) {
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
add(TickTimer(seconds - timer.tick));
});
}
void _onTickTimer(TickTimer event, Emitter<TwoGangState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"},
{"day": "Mon", "key": "Mon"},
{"day": "Tue", "key": "Tue"},
{"day": "Wed", "key": "Wed"},
{"day": "Thu", "key": "Thu"},
{"day": "Fri", "key": "Fri"},
{"day": "Sat", "key": "Sat"},
];
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<TwoGangState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(const ChangeSlidingSegment(value: 1));
}
Future<void> saveSchedule(
TwoGangSave event,
Emitter<TwoGangState> emit,
) async {
try {
if (selectedDays.isNotEmpty) {
emit(LoadingInitialState());
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: twoGangId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(TwoGangSaveSchedule());
add(const ToggleCreateScheduleEvent(index: 1));
// toggleCreateSchedule();
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(FailedState(error: e.toString()));
}
}
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<TwoGangState> emit,
) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: twoGangId,
);
List<dynamic> jsonData = response;
listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
}
Future toggleRepeat(
ToggleScheduleEvent event, Emitter<TwoGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: twoGangId, enable: event.toggle);
if (response == true) {
add(GetScheduleEvent());
toggleSchedule = event.toggle;
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<TwoGangState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: twoGangId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
void _fetchTwoGangWizardStatus(
InitialWizardEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
groupTwoGangList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '2G');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoGangModel.fromJson(statusModelList);
groupTwoGangList.add(GroupTwoGangModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
secondSwitch: deviceStatus.secondSwitch,
));
}
if (groupTwoGangList.isNotEmpty) {
groupTwoGangList.firstWhere((element) {
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(
twoGangList: groupTwoGangList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupTwoGangList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
twoGangList: groupTwoGangList, allSwitches: allSwitchesValue));
List<String> allDeviceIds =
groupTwoGangList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
void _changeSecondWizardSwitch(ChangeSecondWizardSwitchStatusEvent event,
Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupTwoGangList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.secondSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesValue = false;
}
});
List<String> allDeviceIds =
groupTwoGangList.map((device) => device.deviceId).toList();
emit(UpdateGroupState(
twoGangList: groupTwoGangList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
}

View File

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

View File

@ -0,0 +1,92 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/group_two_gang_model.dart';
import 'package:syncrow_app/features/devices/model/two_gang_model.dart';
class TwoGangState extends Equatable {
const TwoGangState();
@override
List<Object> get props => [];
}
class InitialState extends TwoGangState {}
class TwoGangSaveSchedule extends TwoGangState {}
class ChangeTimeState extends TwoGangState {}
class LoadingInitialState extends TwoGangState {}
class UpdateState extends TwoGangState {
final TwoGangModel twoGangModel;
const UpdateState({required this.twoGangModel});
@override
List<Object> get props => [TwoGangModel];
}
class LoadingNewSate extends TwoGangState {
final TwoGangModel twoGangModel;
const LoadingNewSate({required this.twoGangModel});
@override
List<Object> get props => [TwoGangModel];
}
class UpdateGroupState extends TwoGangState {
final List<GroupTwoGangModel> twoGangList;
final bool allSwitches;
const UpdateGroupState({required this.twoGangList, required this.allSwitches});
@override
List<Object> get props => [twoGangList, allSwitches];
}
class FailedState extends TwoGangState {
final String error;
const FailedState({required this.error});
@override
List<Object> get props => [error];
}
class ChangeSlidingSegmentState extends TwoGangState {
final int value;
const ChangeSlidingSegmentState({required this.value});
@override
List<Object> get props => [value];
}
class UpdateTimerState extends TwoGangState {
final int seconds;
const UpdateTimerState({required this.seconds});
@override
List<Object> get props => [seconds];
}
class TimerRunInProgress extends TwoGangState {
final int remainingTime;
const TimerRunInProgress(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class TimerRunComplete extends TwoGangState {}
class IsToggleState extends TwoGangState {
final bool? onOff;
const IsToggleState({this.onOff});
}
// two_gang_state.dart
class UpdateCreateScheduleState extends TwoGangState {
final bool createSchedule;
UpdateCreateScheduleState(this.createSchedule);
}

View File

@ -0,0 +1,518 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_event.dart';
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_state.dart';
import 'package:syncrow_app/features/devices/model/GroupWHModel.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/model/water_heater.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
final String whId;
final String switchCode;
WHModel deviceStatus = WHModel(firstSwitch: false, firstCountDown: 0);
List<WHModel> deviceStatusList = [];
List<DeviceModel> devicesList = [];
bool allAcsPage = false;
bool allAcsOn = true;
bool allTempSame = true;
int globalTemp = 25;
Timer? _timer;
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
bool createCirculate = false;
List<ScheduleModel> listSchedule = [];
DateTime? selectedTime = DateTime.now();
WaterHeaterBloc({required this.whId, required this.switchCode})
: super(WHInitialState()) {
on<WaterHeaterInitial>(_fetchWaterHeaterStatus);
on<WaterHeaterSwitch>(_changeFirstSwitch);
on<SetCounterValue>(_setCounterValue);
on<GetCounterEvent>(_getCounterValue);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<ScheduleSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleChange);
on<DeleteScheduleEvent>(deleteSchedule);
on<TickTimer>(_onTickTimer);
on<OnClose>(_onClose);
on<SelectTimeEvent>(showTime);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<InitialWizardEvent>(_fetchWHWizardStatus);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ToggleCreateCirculate>(_toggleCreateCirculate);
on<WaterHeaterUpdated>(_waterHeaterUpdated);
}
void _fetchWaterHeaterStatus(
WaterHeaterInitial event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(whId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = WHModel.fromJson(
statusModelList,
);
emit(UpdateState(whModel: deviceStatus));
_listenToChanges();
} catch (e) {
emit(WHFailedState(errorMessage: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$whId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async {
if (_timer != null) {
await Future.delayed(const Duration(seconds: 2));
}
Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = WHModel.fromJson(statusList);
if (!isClosed) {
add(WaterHeaterUpdated());
}
});
} catch (_) {}
}
_waterHeaterUpdated(
WaterHeaterUpdated event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
emit(UpdateState(whModel: deviceStatus));
}
void _changeFirstSwitch(
WaterHeaterSwitch event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.whSwitch;
emit(UpdateState(whModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: whId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
whId);
if (!response['success']) {
// add(InitialEvent(groupScreen: oneGangGroup));
}
});
} catch (_) {
emit(WHFailedState(errorMessage: _.toString()));
}
}
//=====================---------- timer ----------------------------------------
void _setCounterValue(
SetCounterValue event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: whId, code: event.deviceCode, value: seconds),
whId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown = seconds;
}
} else {
emit(const WHFailedState(errorMessage: 'Something went wrong'));
return;
}
} catch (e) {
emit(const WHFailedState(errorMessage: 'Something went wrong'));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(
GetCounterEvent event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
try {
var response = await DevicesAPI.getDeviceStatus(whId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = WHModel.fromJson(statusModelList);
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown > 0
? _onStartTimer(deviceStatus.firstCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
}
} catch (e) {
WHFailedState(errorMessage: e.toString());
return;
}
}
void _onClose(OnClose event, Emitter<WaterHeaterState> emit) {
_timer?.cancel();
}
void _onStartTimer(int seconds) {
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
add(TickTimer(seconds - timer.tick));
});
}
void _onTickTimer(TickTimer event, Emitter<WaterHeaterState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
//=====================---------- Schedule ----------------------------------------
List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"},
{"day": "Mon", "key": "Mon"},
{"day": "Tue", "key": "Tue"},
{"day": "Wed", "key": "Wed"},
{"day": "Thu", "key": "Thu"},
{"day": "Fri", "key": "Fri"},
{"day": "Sat", "key": "Sat"},
];
Future<void> saveSchedule(
ScheduleSave event,
Emitter<WaterHeaterState> emit,
) async {
try {
if (selectedDays.isNotEmpty) {
emit(WHLoadingState());
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: whId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(SaveSchedule());
add(const ToggleCreateScheduleEvent(index: 1));
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(WHFailedState(errorMessage: e.toString()));
}
}
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<WaterHeaterState> emit,
) async {
try {
emit(WHLoadingState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: whId,
);
List<dynamic> jsonData = response;
listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(WHInitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(WHFailedState(errorMessage: errorMessage.toString()));
}
}
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
}
Future toggleChange(
ToggleScheduleEvent event, Emitter<WaterHeaterState> emit) async {
try {
emit(WHLoadingState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: whId, enable: event.toggle);
if (response == true) {
add(GetScheduleEvent());
toggleSchedule = event.toggle;
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(WHFailedState(errorMessage: errorMessage.toString()));
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<WaterHeaterState> emit) async {
try {
emit(WHLoadingState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: whId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(WHFailedState(errorMessage: errorMessage.toString()));
}
}
void _toggleCreateCirculate(
ToggleCreateCirculate event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
createCirculate = !createCirculate;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createCirculate));
}
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<WaterHeaterState> emit,
) async {
emit(WHLoadingState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
}
int selectedTabIndex = 0;
showTime(SelectTimeEvent event, Emitter<WaterHeaterState> emit) async {
await showTimePicker(
context: event.context,
initialTime: TimeOfDay.now(),
builder: (context, child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: const ColorScheme.light(
primary: ColorsManager.primaryColor,
onSurface: Colors.black,
),
buttonTheme: const ButtonThemeData(
colorScheme: ColorScheme.light(
primary: Colors.green,
),
),
),
child: child!,
);
},
);
}
List<GroupWHModel> groupWaterHeaterList = [];
bool allSwitchesOn = true;
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupWaterHeaterList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: [event.deviceId],
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
void _fetchWHWizardStatus(
InitialWizardEvent event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState());
try {
devicesList = [];
groupWaterHeaterList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', 'WH');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = WHModel.fromJson(statusModelList);
groupWaterHeaterList.add(GroupWHModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
));
}
if (groupWaterHeaterList.isNotEmpty) {
groupWaterHeaterList.firstWhere((element) {
if (!element.firstSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: allSwitchesOn));
} catch (e) {
// emit(FailedState(error: e.toString()));
return;
}
}
void _groupAllOn(
GroupAllOnEvent event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
for (int i = 0; i < groupWaterHeaterList.length; i++) {
groupWaterHeaterList[i].firstSwitch = true;
}
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: true));
List<String> allDeviceIds =
groupWaterHeaterList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: true,
);
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
void _groupAllOff(
GroupAllOffEvent event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus));
try {
for (int i = 0; i < groupWaterHeaterList.length; i++) {
groupWaterHeaterList[i].firstSwitch = false;
}
emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: false));
List<String> allDeviceIds =
groupWaterHeaterList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: false,
);
if (response['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
}

View File

@ -0,0 +1,139 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
abstract class WaterHeaterEvent extends Equatable {
const WaterHeaterEvent();
@override
List<Object> get props => [];
}
class WaterHeaterLoading extends WaterHeaterEvent {}
class WaterHeaterSwitch extends WaterHeaterEvent {
final bool whSwitch;
final String deviceId;
final String productId;
const WaterHeaterSwitch({required this.whSwitch, this.deviceId = '', this.productId = ''});
@override
List<Object> get props => [whSwitch, deviceId, productId];
}
class WaterHeaterUpdated extends WaterHeaterEvent {}
class WaterHeaterInitial extends WaterHeaterEvent {
const WaterHeaterInitial();
}
class WaterHeaterChangeStatus extends WaterHeaterEvent {}
class GetCounterEvent extends WaterHeaterEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class SetCounterValue extends WaterHeaterEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends WaterHeaterEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends WaterHeaterEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends WaterHeaterEvent {}
class OnClose extends WaterHeaterEvent {}
//------------------- Schedule ----------=---------
class GetScheduleEvent extends WaterHeaterEvent {}
class ScheduleSave extends WaterHeaterEvent {}
class ToggleScheduleEvent extends WaterHeaterEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle, required this.id});
@override
List<Object> get props => [toggle, id];
}
class ToggleDaySelectionEvent extends WaterHeaterEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
class DeleteScheduleEvent extends WaterHeaterEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@override
List<Object> get props => [id];
}
class SelectTimeEvent extends WaterHeaterEvent {
final BuildContext context;
final bool isEffective;
const SelectTimeEvent({required this.context, required this.isEffective});
@override
List<Object> get props => [context, isEffective];
}
class ToggleSelectedEvent extends WaterHeaterEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@override
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends WaterHeaterEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@override
List<Object> get props => [index];
}
class ToggleCreateCirculateEvent extends WaterHeaterEvent {
final int index;
const ToggleCreateCirculateEvent({required this.index});
@override
List<Object> get props => [index];
}
class InitialWizardEvent extends WaterHeaterEvent {}
class ChangeFirstWizardSwitchStatusEvent extends WaterHeaterEvent {
final bool value;
final String deviceId;
const ChangeFirstWizardSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class GroupAllOnEvent extends WaterHeaterEvent {}
class GroupAllOffEvent extends WaterHeaterEvent {}
class ToggleCreateCirculate extends WaterHeaterEvent {}

View File

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

View File

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

View File

@ -42,7 +42,9 @@ class DevicesCategoryModel {
: name = json['groupName'],
// id = json['groupId'],
type = devicesTypesMap[json['groupName']] ?? DeviceType.Other,
icon = deviceTypeIconMap[devicesTypesMap[json['groupName']] ?? DeviceType.Other] ?? '',
icon = deviceTypeIconMap[
devicesTypesMap[json['groupName']] ?? DeviceType.Other] ??
'',
devices = [],
isSelected = false;
@ -60,5 +62,9 @@ Map<DeviceType, String> deviceTypeIconMap = {
DeviceType.CeilingSensor: Assets.assetsIconsSensors,
DeviceType.WallSensor: Assets.assetsIconsSensors,
DeviceType.ThreeGang: Assets.assetsIconsGang,
DeviceType.OneGang: Assets.oneGang,
DeviceType.TwoGang: Assets.twoGang,
DeviceType.WH: Assets.waterHeaterIcon,
DeviceType.DS: Assets.doorSensorIcon,
DeviceType.Other: Assets.assetsIconsAC,
};

View File

@ -58,9 +58,18 @@ class DeviceModel {
tempIcon = Assets.assetsIcons3GangSwitch;
} else if (type == DeviceType.Gateway) {
tempIcon = Assets.assetsIconsGateway;
} else if (type == DeviceType.OneGang) {
tempIcon = Assets.oneGang;
} else if (type == DeviceType.TwoGang) {
tempIcon = Assets.twoGang;
} else if (type == DeviceType.WH) {
tempIcon = Assets.waterHeaterIcon;
} else if (type == DeviceType.DS) {
tempIcon = Assets.doorSensorIcon;
} else {
tempIcon = Assets.assetsIconsLogo;
}
return DeviceModel(
icon: tempIcon,
activeTime: json['activeTime'],

View File

@ -0,0 +1,51 @@
class DeviceReport {
final dynamic deviceUuid;
final dynamic startTime;
final dynamic endTime;
final List<DeviceEvent>? data;
DeviceReport({
this.deviceUuid,
this.startTime,
this.endTime,
this.data,
});
DeviceReport.fromJson(Map<String, dynamic> json)
: deviceUuid = json['deviceUuid'] as String?,
startTime = json['startTime'] as String?,
endTime = json['endTime'] as String?,
data = (json['data'] as List<dynamic>?)
?.map((e) => DeviceEvent.fromJson(e as Map<String, dynamic>))
.toList();
Map<String, dynamic> toJson() => {
'deviceUuid': deviceUuid,
'startTime': startTime,
'endTime': endTime,
'data': data?.map((e) => e.toJson()).toList(),
};
}
class DeviceEvent {
final String? code;
final int? eventTime;
final String? value;
DeviceEvent({
this.code,
this.eventTime,
this.value,
});
DeviceEvent.fromJson(Map<String, dynamic> json)
: code = json['code'] as String?,
eventTime = json['eventTime'] as int?,
value = json['value'] as String?;
Map<String, dynamic> toJson() => {
'code': code,
'eventTime': eventTime,
'value': value,
};
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,30 @@
import 'package:syncrow_app/features/devices/model/status_model.dart';
class OneGangModel {
bool firstSwitch;
int firstCountDown;
OneGangModel(
{required this.firstSwitch,
required this.firstCountDown,
});
factory OneGangModel.fromJson(List<StatusModel> jsonList) {
late bool _switch;
late int _count;
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch_1') {
_switch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'countdown_1') {
_count = jsonList[i].value ?? 0;
}
}
return OneGangModel(
firstSwitch: _switch,
firstCountDown: _count,
);
}
}

View File

@ -0,0 +1,23 @@
// Record model
class Record {
final String status;
final String time;
final bool isOpen;
Record({
required this.status,
required this.time,
required this.isOpen,
});
}
// RecordGroup model to group records by date
class RecordGroup {
final DateTime date;
final List<Record> records;
RecordGroup({
required this.date,
required this.records,
});
}

View File

@ -0,0 +1,83 @@
import 'package:intl/intl.dart';
class ScheduleModel {
String category;
bool enable;
ScheduleFunctionData function;
String time;
String scheduleId;
String timezoneId;
List<String> days;
ScheduleModel({
required this.category,
required this.enable,
required this.function,
required this.time,
required this.scheduleId,
required this.timezoneId,
required this.days,
});
// Factory method to create an instance from JSON
factory ScheduleModel.fromJson(Map<String, dynamic> json) {
return ScheduleModel(
category: json['category'],
enable: json['enable'],
function: ScheduleFunctionData.fromJson(json['function']),
time:getTimeIn12HourFormat( json['time']),
scheduleId: json['scheduleId'],
timezoneId: json['timezoneId'],
days: List<String>.from(json['days']),
);
}
// Method to convert an instance into JSON
Map<String, dynamic> toJson() {
return {
'category': category,
'enable': enable,
'function': function.toJson(),
'time': time,
'scheduleId': scheduleId,
'timezoneId': timezoneId,
'days': days,
};
}
}
class ScheduleFunctionData {
String code;
bool value;
ScheduleFunctionData({
required this.code,
required this.value,
});
// Factory method to create an instance from JSON
factory ScheduleFunctionData.fromJson(Map<String, dynamic> json) {
return ScheduleFunctionData(
code: json['code'],
value: json['value'],
);
}
// Method to convert an instance into JSON
Map<String, dynamic> toJson() {
return {
'code': code,
'value': value,
};
}
}
String getTimeIn12HourFormat(time) {
// Parse the time string (in HH:mm format)
final DateFormat inputFormat = DateFormat("HH:mm");
final DateFormat outputFormat = DateFormat("h:mm a"); // 12-hour format with AM/PM
// Convert the time string
DateTime parsedTime = inputFormat.parse(time);
return outputFormat.format(parsedTime);
}

View File

@ -0,0 +1,40 @@
import 'package:syncrow_app/features/devices/model/status_model.dart';
class TwoGangModel {
bool firstSwitch;
bool secondSwitch;
int firstCountDown;
int secondCountDown;
TwoGangModel(
{required this.firstSwitch,
required this.secondSwitch,
required this.firstCountDown,
required this.secondCountDown,
});
factory TwoGangModel.fromJson(List<StatusModel> jsonList) {
late bool _firstSwitch;
late bool _secondSwitch;
late int _firstCount;
late int _secondCount;
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch_1') {
_firstSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'switch_2') {
_secondSwitch = jsonList[i].value ?? false;
}else if (jsonList[i].code == 'countdown_1') {
_firstCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'countdown_2') {
_secondCount = jsonList[i].value ?? 0;
}
}
return TwoGangModel(
firstSwitch: _firstSwitch,
secondSwitch: _secondSwitch,
firstCountDown: _firstCount,
secondCountDown: _secondCount,
);
}
}

View File

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

View File

@ -71,7 +71,9 @@ class ParameterControlDialogState extends State<ParameterControlDialog> {
),
),
),
Row(
SizedBox(
width: MediaQuery.sizeOf(context).width,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
@ -85,7 +87,8 @@ class ParameterControlDialogState extends State<ParameterControlDialog> {
color: Colors.grey,
),
),
Slider(
Flexible(
child: Slider(
value: _value.toDouble(),
onChanged: (value) {
setState(() {
@ -97,6 +100,7 @@ class ParameterControlDialogState extends State<ParameterControlDialog> {
label: _value.toString(),
inactiveColor: ColorsManager.greyColor,
),
),
IconButton(
onPressed: () {
setState(() {
@ -110,6 +114,7 @@ class ParameterControlDialogState extends State<ParameterControlDialog> {
),
],
),
),
Container(
height: 1,
width: double.infinity,

View File

@ -1,163 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class BlindsView extends StatelessWidget {
const BlindsView({
super.key,
this.blind,
});
final DeviceModel? blind;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => DevicesCubit.getInstance(),
child: BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return DefaultScaffold(
title: blind?.name ?? 'Blinds',
child: Column(
children: [
Column(
children: [
Stack(
alignment: Alignment.topCenter,
children: [
Container(
height: 340,
width: 365,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.assetsImagesWindow,
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 15, bottom: 10),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
height: DevicesCubit.get(context).blindWindowHight,
width: 270,
child: Stack(
children: List.generate(
25,
(index) {
double spacing = DevicesCubit.get(context)
.blindWindowHight /
24;
double topPosition = index * spacing;
return AnimatedPositioned(
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
top: topPosition,
child: SizedBox(
height: 10,
width: 270,
child: Image.asset(
Assets.assetsImagesHorizintalBlade,
fit: BoxFit.fill,
),
),
);
},
),
),
),
),
],
),
const SizedBox(height: 80),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
DecoratedBox(
decoration:
BoxDecoration(shape: BoxShape.circle, boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(3, 3),
),
]),
child: InkWell(
overlayColor:
MaterialStateProperty.all(Colors.transparent),
onTap: () {
// DevicesCubit.get(context).setHight(false);
DevicesCubit.get(context).openCurtain(
blind?.productType! ?? DeviceType.Blind);
},
child: Image.asset(
Assets.assetsImagesUp,
width: 60,
height: 60,
),
),
),
DecoratedBox(
decoration:
BoxDecoration(shape: BoxShape.circle, boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(3, 3),
),
]),
child: InkWell(
overlayColor:
MaterialStateProperty.all(Colors.transparent),
onTap: () {
DevicesCubit.get(context).pauseCurtain();
},
child: Image.asset(
Assets.assetsImagesPause,
width: 60,
height: 60,
),
),
),
DecoratedBox(
decoration:
BoxDecoration(shape: BoxShape.circle, boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(3, 3),
),
]),
child: InkWell(
overlayColor:
MaterialStateProperty.all(Colors.transparent),
onTap: () {
DevicesCubit.get(context).closeCurtain(
blind?.productType! ?? DeviceType.Blind);
},
child: Image.asset(
Assets.assetsImagesDown,
width: 60,
height: 60,
),
),
),
],
),
],
),
],
),
);
},
),
);
}
}

View File

@ -1,83 +0,0 @@
// import 'package:flutter/material.dart';
// import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
// import 'package:syncrow_app/generated2/assets.dart';
// class BlindsBottons extends StatelessWidget {
// const BlindsBottons({
// super.key,
// });
// @override
// Widget build(BuildContext context) {
// return Row(
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// children: [
// DecoratedBox(
// decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
// BoxShadow(
// color: Colors.grey.withOpacity(0.5),
// spreadRadius: 1,
// blurRadius: 5,
// offset: const Offset(3, 3),
// ),
// ]),
// child: InkWell(
// overlayColor: MaterialStateProperty.all(Colors.transparent),
// onTap: () {
// // DevicesCubit.get(context).setHight(false);
// DevicesCubit.get(context).closeCurtain();
// },
// child: Image.asset(
// Assets.assetsImagesUp,
// width: 60,
// height: 60,
// ),
// ),
// ),
// DecoratedBox(
// decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
// BoxShadow(
// color: Colors.grey.withOpacity(0.5),
// spreadRadius: 1,
// blurRadius: 5,
// offset: const Offset(3, 3),
// ),
// ]),
// child: InkWell(
// overlayColor: MaterialStateProperty.all(Colors.transparent),
// onTap: () {
// // DevicesCubit.get(context).setHight(false);
// },
// child: Image.asset(
// Assets.assetsImagesPause,
// width: 60,
// height: 60,
// ),
// ),
// ),
// DecoratedBox(
// decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
// BoxShadow(
// color: Colors.grey.withOpacity(0.5),
// spreadRadius: 1,
// blurRadius: 5,
// offset: const Offset(3, 3),
// ),
// ]),
// child: InkWell(
// overlayColor: MaterialStateProperty.all(Colors.transparent),
// onTap: () {
// // DevicesCubit.get(context).setHight(true);
// DevicesCubit.get(context).openCurtain();
// },
// child: Image.asset(
// Assets.assetsImagesDown,
// width: 60,
// height: 60,
// ),
// ),
// ),
// ],
// );
// }
// }

View File

@ -1,115 +1,74 @@
part of "curtain_view.dart";
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/generated/assets.dart';
class CurtainButtons extends StatelessWidget {
const CurtainButtons({super.key, required this.curtain});
final DeviceModel curtain;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Stack(
_buildButton(
onTap: () => context.read<CurtainBloc>().add(OpenCurtain(curtain.productType!)),
iconPath: Assets.assetsIconsCurtainsIconOpenCurtain,
),
_buildButton(
onTap: () => context.read<CurtainBloc>().add(PauseCurtain()),
iconPath: Assets.assetsImagesPause,
isSvg: false,
),
_buildButton(
onTap: () => context.read<CurtainBloc>().add(CloseCurtain(curtain.productType!)),
iconPath: Assets.assetsIconsCurtainsIconCloseCurtain,
),
],
);
}
Widget _buildButton({
required VoidCallback onTap,
required String iconPath,
bool isSvg = true,
}) {
return Stack(
alignment: Alignment.center,
children: [
DecoratedBox(
decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(3, 3),
),
]),
],
),
child: InkWell(
overlayColor: MaterialStateProperty.all(Colors.transparent),
onTap: () {
DevicesCubit.get(context).openCurtain(curtain.productType!);
},
child: const SizedBox.square(
dimension: 60,
),
onTap: onTap,
child: const SizedBox.square(dimension: 60),
),
),
Padding(
padding: const EdgeInsets.only(right: 5, bottom: 5),
child: InkWell(
overlayColor: MaterialStateProperty.all(Colors.transparent),
onTap: () {
DevicesCubit.get(context).openCurtain(curtain.productType!);
},
child: SvgPicture.asset(
Assets.assetsIconsCurtainsIconOpenCurtain,
width: 110,
height: 110,
onTap: onTap,
child: isSvg
? SvgPicture.asset(iconPath, width: 110, height: 110)
: Image.asset(iconPath, width: 60, height: 60),
),
),
)
],
),
DecoratedBox(
decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(3, 3),
),
]),
child: InkWell(
overlayColor: MaterialStateProperty.all(Colors.transparent),
onTap: () {
DevicesCubit.get(context).pauseCurtain();
},
child: Image.asset(
Assets.assetsImagesPause,
width: 60,
height: 60,
),
),
),
Stack(
alignment: Alignment.center,
children: [
DecoratedBox(
decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(3, 3),
),
]),
child: const SizedBox.square(
dimension: 60,
),
// InkWell(
// overlayColor: MaterialStateProperty.all(Colors.transparent),
// onTap: () {
// DevicesCubit.get(context).closeCurtain(curtain.productType!);
// },
// child: SvgPicture.asset(
// Assets.assetsIconsCurtainsIconCloseCurtain,
// width: 60,
// height: 60,
// ),
// ),
),
Padding(
padding: const EdgeInsets.only(right: 5, bottom: 5),
child: InkWell(
overlayColor: MaterialStateProperty.all(Colors.transparent),
onTap: () {
DevicesCubit.get(context).closeCurtain(curtain.productType!);
},
child: SvgPicture.asset(
Assets.assetsIconsCurtainsIconCloseCurtain,
width: 110,
height: 110,
),
),
)
],
),
],
);
}

View File

@ -1,9 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/universal_switch.dart';
import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class CurtainList extends StatelessWidget {

View File

@ -1,23 +1,37 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_buttons.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/generated/assets.dart';
part "curtain_buttons.dart";
class CurtainView extends StatelessWidget {
const CurtainView({super.key, required this.curtain});
final DeviceModel curtain;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => DevicesCubit.getInstance(),
child: BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) => DefaultScaffold(
create: (context) => CurtainBloc(curtain.uuid!)..add(InitCurtain()),
child: BlocBuilder<CurtainBloc, CurtainState>(
builder: (context, state) {
double curtainWidth = 270;
// double blindHeight = 310;
if (state is CurtainsOpening) {
curtainWidth = state.curtainWidth;
// blindHeight = state.blindHeight;
} else if (state is CurtainsClosing) {
curtainWidth = state.curtainWidth;
// blindHeight = state.blindHeight;
} else if (state is CurtainsPaused) {
curtainWidth = state.curtainWidth;
// blindHeight = state.blindHeight;
}
return DefaultScaffold(
title: curtain.name,
child: Column(
children: [
@ -41,13 +55,12 @@ class CurtainView extends StatelessWidget {
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
height: 310,
width: DevicesCubit.getInstance().curtainWidth,
width: curtainWidth,
child: Stack(
children: List.generate(
10,
(index) {
double spacing =
DevicesCubit.getInstance().curtainWidth / 9;
double spacing = curtainWidth / 9;
double leftMostPosition = index * spacing;
return AnimatedPositioned(
duration: const Duration(milliseconds: 200),
@ -71,16 +84,17 @@ class CurtainView extends StatelessWidget {
top: 27,
left: 43,
child: SvgPicture.asset(
Assets.assetsIconsCurtainsIconCurtainHolder)),
Assets.assetsIconsCurtainsIconCurtainHolder,
),
),
],
),
const SizedBox(height: 80),
CurtainButtons(
curtain: curtain,
),
CurtainButtons(curtain: curtain),
],
),
),
);
},
),
);
}

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/view/widgets/popup_menu_widget.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
@ -11,7 +10,8 @@ class DeviceAppbar extends StatelessWidget implements PreferredSizeWidget {
final String deviceUuid;
final double appBarHeight = 56.0;
final void Function()? onPressed;
const DeviceAppbar({super.key, required this.deviceName, required this.deviceUuid,this.onPressed});
const DeviceAppbar(
{super.key, required this.deviceName, required this.deviceUuid, this.onPressed});
@override
Widget build(BuildContext context) {
@ -19,12 +19,13 @@ class DeviceAppbar extends StatelessWidget implements PreferredSizeWidget {
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
text: deviceName ?? "",
text: deviceName,
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
actions: [
IconButton(onPressed: () {
IconButton(
onPressed: () {
showPopupMenu(context: context, items: [
PopupMenuItem(
onTap: () async {
@ -34,7 +35,8 @@ class DeviceAppbar extends StatelessWidget implements PreferredSizeWidget {
child: const Text('Update'),
)
]);
}, icon: Icon(Icons.edit))
},
icon: Icon(Icons.edit))
],
);
}

View File

@ -66,6 +66,7 @@ class DevicesViewBody extends StatelessWidget {
const SizedBox(
height: 10,
),
Expanded(
child: PageView(
controller: HomeCubit.getInstance().devicesPageController,
@ -78,8 +79,7 @@ class DevicesViewBody extends StatelessWidget {
),
if (HomeCubit.getInstance().selectedSpace != null)
if (HomeCubit.getInstance().selectedSpace!.rooms != null)
...HomeCubit.getInstance().selectedSpace!.rooms!.map(
(room) {
...HomeCubit.getInstance().selectedSpace!.rooms!.map((room) {
return RoomPage(
room: room,
);

View File

@ -0,0 +1,114 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class NotificationSettingsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Notification Settings',
child: BlocProvider(
create: (context) => DoorSensorBloc(DSId: '')..add(const DoorSensorInitial()),
child: BlocBuilder<DoorSensorBloc, DoorSensorState>(
builder: (context, state) {
final doorSensorBloc = BlocProvider.of<DoorSensorBloc>(context);
return state is DoorSensorLoadingState
? const Center(
child: DefaultContainer(
width: 50, height: 50, child: CircularProgressIndicator()),
)
: Column(
children: [
DefaultContainer(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 50,
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyLarge(
text: 'Low Battery',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: doorSensorBloc.lowBattery,
onChanged: (value) {
context
.read<DoorSensorBloc>()
.add(ToggleLowBatteryEvent(value));
},
applyTheme: true,
)),
),
),
const Divider(
color: ColorsManager.graysColor,
),
SizedBox(
height: 50,
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyLarge(
text: 'Closing Reminder',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: doorSensorBloc.closingReminder,
onChanged: (value) {
context
.read<DoorSensorBloc>()
.add(ToggleClosingReminderEvent(value));
},
applyTheme: true,
)),
),
),
const Divider(
color: ColorsManager.graysColor,
),
SizedBox(
height: 50,
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyLarge(
text: 'Door Alarm',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: doorSensorBloc.closingReminder,
onChanged: (value) {
context
.read<DoorSensorBloc>()
.add(ToggleDoorAlarmEvent(value));
},
applyTheme: true,
)),
),
),
],
),
),
],
);
},
),
));
}
}

View File

@ -0,0 +1,133 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart';
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class DoorRecordsScreen extends StatelessWidget {
final String DSId;
const DoorRecordsScreen({super.key, required this.DSId});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Records',
child: BlocProvider(
create: (context) =>
DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()),
child: BlocBuilder<DoorSensorBloc, DoorSensorState>(
builder: (context, state) {
final doorSensorBloc = BlocProvider.of<DoorSensorBloc>(context);
if (state is DoorSensorLoadingState) {
return const Center(
child: DefaultContainer(
width: 50, height: 50, child: CircularProgressIndicator()),
);
} else if (state is UpdateState) {
// Group records by formatted date
final Map<String, List<DeviceEvent>> groupedRecords = {};
// Iterate over the data list in DeviceReport
for (var record in doorSensorBloc.recordGroups.data!) {
final DateTime eventDateTime =
DateTime.fromMillisecondsSinceEpoch(record.eventTime!);
final String formattedDate =
DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime);
// Group by formatted date
if (groupedRecords.containsKey(formattedDate)) {
groupedRecords[formattedDate]!.add(record);
} else {
groupedRecords[formattedDate] = [record];
}
}
// Build the ListView with grouped data
return ListView.builder(
itemCount: groupedRecords.length,
itemBuilder: (context, index) {
final String date = groupedRecords.keys.elementAt(index);
final List<DeviceEvent> recordsForDate =
groupedRecords[date]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Date header
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
date,
style: const TextStyle(
color: ColorsManager.grayColor,
fontSize: 13,
fontWeight: FontWeight.w700,
),
),
),
// List of records for the specific date
DefaultContainer(
child: Column(
children: [
...recordsForDate.asMap().entries.map((entry) {
final int idx = entry.key;
final DeviceEvent record = entry.value;
final DateTime eventDateTime =
DateTime.fromMillisecondsSinceEpoch(
record.eventTime!);
final String formattedTime =
DateFormat('HH:mm:ss').format(eventDateTime);
return Column(
children: [
Container(
child: ListTile(
leading: Icon(
record.value == 'true'
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
color: record.value == 'true'
? Colors.blue
: Colors.grey,
),
title: Text(
record.value == 'true'
? "Opened"
: "Closed",
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
subtitle: Text('$formattedTime'),
),
),
// Only add Divider if it's not the last item
if (idx != recordsForDate.length - 1)
const Divider(
color: ColorsManager.graysColor,
),
],
);
}).toList(),
],
),
),
],
);
},
);
}
return const Center(child: Text('No data available.'));
},
),
),
);
}
}

View File

@ -0,0 +1,189 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/door_sensor_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/door_sensor/door_notification_settings.dart';
import 'package:syncrow_app/features/devices/view/widgets/door_sensor/door_records_screen.dart';
import 'package:syncrow_app/features/shared_widgets/battery_bar.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
class DoorSensorScreen extends StatelessWidget {
final DeviceModel? device;
const DoorSensorScreen({super.key, this.device});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Door Sensor',
child: BlocProvider(
create: (context) =>
DoorSensorBloc(DSId: device?.uuid ?? '')..add(const DoorSensorInitial()),
child: BlocBuilder<DoorSensorBloc, DoorSensorState>(
builder: (context, state) {
final doorSensorBloc = BlocProvider.of<DoorSensorBloc>(context);
DoorSensorModel model = DoorSensorModel(batteryPercentage: 0, doorContactState: false);
if (state is LoadingNewSate) {
model = state.doorSensor;
} else if (state is UpdateState) {
model = state.doorSensor;
}
return state is DoorSensorLoadingState
? const Center(
child:
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
doorSensorBloc.add(const DoorSensorInitial());
},
child: ListView(
children: [
SizedBox(
height: MediaQuery.sizeOf(context).height * 0.8,
child: Column(
children: [
BatteryBar(
batteryPercentage: model.batteryPercentage,
),
Expanded(
flex: 4,
child: InkWell(
overlayColor: WidgetStateProperty.all(Colors.transparent),
onTap: () {},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
decoration: BoxDecoration(
// color: Colors.white.withOpacity(0.1),
borderRadius: BorderRadius.circular(890),
boxShadow: [
BoxShadow(
color: Colors.white.withOpacity(0.1),
blurRadius: 24,
offset: const Offset(-5, -5),
blurStyle: BlurStyle.outer,
),
BoxShadow(
color: Colors.black.withOpacity(0.11),
blurRadius: 25,
offset: const Offset(5, 5),
blurStyle: BlurStyle.outer,
),
BoxShadow(
color: Colors.black.withOpacity(0.13),
blurRadius: 30,
offset: const Offset(5, 5),
blurStyle: BlurStyle.inner,
),
],
),
child: SvgPicture.asset(
model.doorContactState
? Assets.doorOpen
: Assets.doorClose,
fit: BoxFit.fill,
),
),
],
),
),
),
Flexible(
child: Row(
children: [
Expanded(
child: DefaultContainer(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
DoorRecordsScreen(DSId: device!.uuid!)),
);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ConstrainedBox(
constraints:
const BoxConstraints(maxHeight: 46, maxWidth: 50),
child: SvgPicture.asset(Assets.doorRecordsIcon),
),
const SizedBox(
height: 15,
),
const Flexible(
child: FittedBox(
child: BodySmall(
text: 'Records',
// doorLockButtons.keys.elementAt(index),
textAlign: TextAlign.center,
),
),
),
],
),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: DefaultContainer(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => NotificationSettingsPage()),
);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ConstrainedBox(
constraints:
const BoxConstraints(maxHeight: 46, maxWidth: 50),
child:
SvgPicture.asset(Assets.doorNotificationSetting),
),
const SizedBox(
height: 15,
),
const Flexible(
child: FittedBox(
child: BodySmall(
text: 'Notification Settings',
// doorLockButtons.keys.elementAt(index),
textAlign: TextAlign.center,
),
),
),
],
),
),
),
],
),
)
],
),
),
],
),
);
},
),
),
);
}
}

View File

@ -8,12 +8,10 @@ import 'package:syncrow_app/features/devices/bloc/gateway_bloc/gateway_state.dar
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class GateWayView extends StatelessWidget {
final DeviceModel gatewayObj;
@ -40,7 +38,8 @@ class GateWayView extends StatelessWidget {
extendBody: true,
appBar: DeviceAppbar(
deviceName: 'Gateway',
deviceUuid: gatewayObj.uuid!,),
deviceUuid: gatewayObj.uuid!,
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
@ -56,10 +55,10 @@ class GateWayView extends StatelessWidget {
),
child: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<GatewayBloc>(context).add(GatewayInitial(gatewayId: gatewayObj.uuid ?? ''));
BlocProvider.of<GatewayBloc>(context)
.add(GatewayInitial(gatewayId: gatewayObj.uuid ?? ''));
},
child: ListView(
children: [
Container(
height: MediaQuery.of(context).size.height,
@ -120,7 +119,8 @@ class GateWayView extends StatelessWidget {
)
: Expanded(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
@ -141,8 +141,7 @@ class GateWayView extends StatelessWidget {
],
),
),
)
));
)));
}));
}
}

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights/lights_list.dart';
import 'package:syncrow_app/features/devices/view/widgets/universal_switch.dart';

View File

@ -1,5 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -7,7 +5,6 @@ import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_blo
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/repeat_widget.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/door_lock_button.dart';
@ -29,9 +26,7 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
if (state is FailedState) {
CustomSnackBar.displaySnackBar(
state.errorMessage
);
CustomSnackBar.displaySnackBar(state.errorMessage);
}
if (state is IsRepeatState) {
isRepeat = state.repeat;
@ -54,8 +49,7 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
onPressed: () {
Navigator.of(context).pop(true);
},
icon: const Icon(Icons.arrow_back)
),
icon: const Icon(Icons.arrow_back)),
),
child: state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
@ -65,7 +59,8 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const BodyMedium(
text: 'Save the password immediately. The password is not displayed in the app.',
text:
'Save the password immediately. The password is not displayed in the app.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
@ -88,21 +83,22 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
Flexible(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:smartDoorBloc.passwordController.text.isEmpty?
List.generate(10, (index) {
children: smartDoorBloc.passwordController.text.isEmpty
? List.generate(10, (index) {
return const Padding(
padding: EdgeInsets.symmetric(horizontal: 4.0,vertical: 15),
padding: EdgeInsets.symmetric(
horizontal: 4.0, vertical: 15),
child: Icon(
Icons.circle,
size: 20.0,
color: Colors.black,
),
);
}) :[
})
: [
Expanded(
child: Row(
children: [
Expanded(
child: BodyLarge(
style: const TextStyle(
@ -114,15 +110,15 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
textAlign: TextAlign.center,
text: smartDoorBloc.passwordController.text,
fontSize: 23,
),),
),
),
IconButton(
onPressed: () async {
await Clipboard.setData(ClipboardData(
text: smartDoorBloc.passwordController.text));
text: smartDoorBloc
.passwordController.text));
},
icon: const Icon(Icons.copy)
),
icon: const Icon(Icons.copy)),
],
),
),
@ -131,7 +127,6 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
const SizedBox(
width: 10,
),
],
),
if (smartDoorBloc.passwordController.text.isNotEmpty)
@ -155,7 +150,8 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
SizedBox(
width: MediaQuery.of(context).size.width / 2.6,
child: TextFormField(
controller: BlocProvider.of<SmartDoorBloc>(context).passwordNameController,
controller: BlocProvider.of<SmartDoorBloc>(context)
.passwordNameController,
decoration: const InputDecoration(
hintText: 'Enter The Name',
hintStyle: TextStyle(
@ -163,7 +159,6 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
)),
],
),
],
),
],
@ -174,7 +169,8 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
),
const BodyMedium(
textAlign: TextAlign.center,
text: 'Save the password immediately. The password is not displayed in the app.',
text:
'Save the password immediately. The password is not displayed in the app.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
@ -193,7 +189,8 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
backgroundColor: ColorsManager.primaryColor,
onPressed: () async {
if (generated == false) {
smartDoorBloc.add(GenerateAndSavePasswordOneTimeEvent(context: context));
smartDoorBloc
.add(GenerateAndSavePasswordOneTimeEvent(context: context));
} else {
if (smartDoorBloc.passwordNameController.text.isNotEmpty) {
smartDoorBloc.add(RenamePasswordEvent());
@ -205,7 +202,8 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
text: 'Obtain Password',
fontWeight: FontWeight.bold,
fontColor: Colors.white,
),),
),
),
),
),
const SizedBox(

View File

@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_screen.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class OneGangInterface extends StatelessWidget {
const OneGangInterface({super.key, this.gangSwitch});
final DeviceModel? gangSwitch;
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: gangSwitch != null
? DeviceAppbar(
deviceName: gangSwitch!.name!,
deviceUuid: gangSwitch!.uuid!,
)
: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
text: gangSwitch?.name ?? 'Lights',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.assetsImagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: SafeArea(
child: Padding(
padding: EdgeInsets.only(
left: Constants.defaultPadding,
right: Constants.defaultPadding,
bottom: Constants.bottomNavBarHeight,
),
child: OneGangScreen(device: gangSwitch),
),
),
),
),
);
}
}

View File

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

View File

@ -0,0 +1,165 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/one_gang_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import '../../../bloc/one_gang_bloc/one_gang_event.dart';
class OneGangScreen extends StatelessWidget {
const OneGangScreen({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '')
..add(const InitialEvent(groupScreen: false)),
child: BlocBuilder<OneGangBloc, OneGangState>(
builder: (context, state) {
OneGangModel oneGangModel = OneGangModel(
firstSwitch: false,
firstCountDown: 0,
);
if (state is LoadingNewSate) {
oneGangModel = state.oneGangModel;
} else if (state is UpdateState) {
oneGangModel = state.oneGangModel;
}
return state is LoadingInitialState
? const Center(
child:
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<OneGangBloc>(context)
.add(InitialEvent(groupScreen: device != null ? false : true));
},
child: ListView(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(child: SizedBox.shrink()),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
GangSwitch(
threeGangSwitch: device!,
value: oneGangModel.firstSwitch,
action: () {
BlocProvider.of<OneGangBloc>(context).add(
ChangeFirstSwitchStatusEvent(
value: oneGangModel.firstSwitch));
},
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: " Entrance Light",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
],
),
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder:
(context, animation1, animation2) =>
TimerScheduleScreen(
switchCode: 'switch_1',
device: device!,
deviceCode: 'countdown_1',
)));
},
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(100),
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: Icon(
Icons.access_time,
color: ColorsManager.primaryColorWithOpacity,
size: 25,
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "Timer",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
],
),
),
Expanded(child: SizedBox())
],
),
),
],
),
);
},
),
);
}
}

View File

@ -0,0 +1,295 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_event.dart';
import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/shared_widgets/create_schedule.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/schedule_list.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class TimerScheduleScreen extends StatelessWidget {
final DeviceModel device;
final String deviceCode;
final String switchCode;
const TimerScheduleScreen(
{required this.device,
required this.deviceCode,
required this.switchCode,
super.key});
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: BlocProvider(
create: (context) =>
OneGangBloc(switchCode: switchCode, oneGangId: device.uuid ?? '')
..add(GetCounterEvent(deviceCode: deviceCode))
..add(GetScheduleEvent()),
child: BlocBuilder<OneGangBloc, OneGangState>(
builder: (context, state) {
final oneGangBloc = BlocProvider.of<OneGangBloc>(context);
Duration duration = Duration.zero;
int countNum = 0;
if (state is UpdateTimerState) {
countNum = state.seconds;
} else if (state is TimerRunInProgress) {
countNum = state.remainingTime;
} else if (state is TimerRunComplete) {
countNum = 0;
} else if (state is LoadingNewSate) {
countNum = 0;
}
return PopScope(
canPop: false,
onPopInvoked: (didPop) {
if (!didPop) {
oneGangBloc.add(OnClose());
Navigator.pop(context);
}
},
child: DefaultTabController(
length: 2,
child: DefaultScaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Schedule',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
actions: [
oneGangBloc.createSchedule == true
? TextButton(
onPressed: () {
oneGangBloc.add(ScheduleSave());
},
child: const Text('Save'))
: oneGangBloc.selectedTabIndex == 1
? IconButton(
onPressed: () {
// oneGangBloc.toggleCreateSchedule();
oneGangBloc.add(
const ToggleCreateScheduleEvent(
index: 1));
},
icon: const Icon(Icons.add),
)
: const SizedBox(),
],
),
child: state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
decoration: const ShapeDecoration(
color: ColorsManager.onPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(30)),
),
),
child: TabBar(
onTap: (value) {
if (value == 0) {
if (oneGangBloc.createSchedule ==
true) {
// oneGangBloc.toggleCreateSchedule();
oneGangBloc.add(
const ToggleCreateScheduleEvent(
index: 0));
}
oneGangBloc.add(
const ToggleSelectedEvent(
index: 0));
} else {
oneGangBloc.add(
const ToggleSelectedEvent(
index: 1));
}
},
indicatorColor:
Colors.white, // Customize the indicator
dividerHeight: 0,
indicatorSize: TabBarIndicatorSize.tab,
indicator: const ShapeDecoration(
color: ColorsManager.slidingBlueColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(20)),
),
),
tabs: [
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: BodySmall(
text: 'Countdown',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: Text(
'Schedule',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
],
),
),
Expanded(
child: TabBarView(
physics: const NeverScrollableScrollPhysics(), // Disable swiping
children: [
Center(
child: Container(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
countNum > 0
? BodyLarge(
text: _formatDuration(
countNum),
fontColor: ColorsManager
.slidingBlueColor,
fontSize: 40,
)
: CupertinoTimerPicker(
mode:
CupertinoTimerPickerMode
.hm,
onTimerDurationChanged:
(Duration
newDuration) {
duration = newDuration;
},
),
GestureDetector(
onTap: () {
if (state
is LoadingNewSate) {
return;
}
if (countNum > 0) {
oneGangBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration: Duration
.zero));
} else if (duration !=
Duration.zero) {
oneGangBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration:
duration));
}
},
child: SvgPicture.asset(
countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
),
),
),
SizedBox(
child: oneGangBloc.createSchedule ==
true
? CreateSchedule(
onToggleChanged: (bool isOn) {
oneGangBloc.toggleSchedule =
isOn;
},
onDateTimeChanged:
(DateTime dateTime) {
oneGangBloc.selectedTime =
dateTime;
},
days: oneGangBloc.days,
selectDays: (List<String>
selectedDays) {
oneGangBloc.selectedDays =
selectedDays;
},
)
: Padding(
padding: const EdgeInsets.only(
top: 10),
child: ScheduleListView(
listSchedule: oneGangBloc
.listSchedule, // Pass the schedule list here
onDismissed: (scheduleId) {
oneGangBloc.listSchedule
.removeWhere((schedule) =>
schedule
.scheduleId ==
scheduleId);
oneGangBloc.add(
DeleteScheduleEvent(
id: scheduleId));
},
onToggleSchedule:
(scheduleId, isEnabled) {
oneGangBloc.add(
ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
),
),
],
),
),
],
),
)));
},
),
),
);
}
String _formatDuration(int seconds) {
final hours = (seconds ~/ 3600).toString().padLeft(2, '0');
final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0');
final secs = (seconds % 60).toString().padLeft(2, '0');
return '$hours:$minutes:$secs';
}
}

View File

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

View File

@ -1,6 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart';

View File

@ -8,12 +8,17 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/door_sensor/door_sensor_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/wall_sensor/wall_sensor_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_heater/water_heater_page.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
@ -26,7 +31,6 @@ class RoomPageSwitch extends StatelessWidget {
});
final DeviceModel device;
@override
Widget build(BuildContext context) {
return GestureDetector(
@ -82,7 +86,8 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => ACsView(deviceModel: device)));
pageBuilder: (context, animation1, animation2) =>
ACsView(deviceModel: device)));
// navigateToInterface(ACsView(deviceModel: device), context);
break;
case DeviceType.WallSensor:
@ -102,6 +107,12 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
// navigateToInterface(CeilingSensorInterface(ceilingSensor: device), context);
break;
case DeviceType.Curtain:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => CurtainView(
curtain: device,
)));
break;
case DeviceType.Blind:
break;
@ -109,24 +120,50 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => DoorInterface(doorLock: device)));
pageBuilder: (context, animation1, animation2) =>
DoorInterface(doorLock: device)));
// navigateToInterface(DoorInterface(doorlock: device), context);
break;
case DeviceType.Gateway:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => GateWayView(gatewayObj: device)));
pageBuilder: (context, animation1, animation2) =>
GateWayView(gatewayObj: device)));
break;
case DeviceType.LightBulb:
navigateToInterface(LightInterface(light: device), context);
case DeviceType.OneGang:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
OneGangInterface(gangSwitch: device)));
case DeviceType.TwoGang:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
TwoGangInterface(gangSwitch: device)));
case DeviceType.ThreeGang:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
ThreeGangInterface(gangSwitch: device)));
// navigateToInterface(ThreeGangInterface(gangSwitch: device), context);
case DeviceType.WH:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
WaterHeaterPage(device: device)));
case DeviceType.DS:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
DoorSensorScreen(device: device)));
break;
default:
}

View File

@ -22,6 +22,7 @@ class RoomsSlider extends StatelessWidget {
onPageChanged: (index) {
HomeCubit.getInstance().roomSliderPageChanged(index);
},
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),

View File

@ -23,7 +23,7 @@ class CreateTemporaryPassword extends StatelessWidget {
@override
Widget build(BuildContext context) {
bool isRepeat = false;
bool generated = false;
// bool generated = false;
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
@ -39,7 +39,7 @@ class CreateTemporaryPassword extends StatelessWidget {
isRepeat = state.repeat;
}
if (state is GeneratePasswordOneTimestate) {
generated = state.generated;
// generated = state.generated;
}
}, builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
@ -56,17 +56,16 @@ class CreateTemporaryPassword extends StatelessWidget {
onPressed: () {
Navigator.of(context).pop(true);
},
icon: const Icon(Icons.arrow_back)
),
actions:
type == 'Online Password'?[
icon: const Icon(Icons.arrow_back)),
actions: type == 'Online Password'
? [
TextButton(
onPressed: () {
smartDoorBloc.add(SavePasswordEvent(context: context));
},
child: const Text('Save')
)
]:null,
child: const Text('Save'))
]
: null,
),
child: state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
@ -76,7 +75,8 @@ class CreateTemporaryPassword extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const BodyMedium(
text: 'Save the password immediately. The password is not displayed in the app.',
text:
'Save the password immediately. The password is not displayed in the app.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
@ -91,7 +91,8 @@ class CreateTemporaryPassword extends StatelessWidget {
DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: type == 'Online Password'?0:25),
padding: EdgeInsets.symmetric(
horizontal: type == 'Online Password' ? 0 : 25),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
@ -102,7 +103,8 @@ class CreateTemporaryPassword extends StatelessWidget {
onCompleted: (value) {
if (value.split('').every((char) => char == '1')) {
smartDoorBloc.passwordController.clear();
CustomSnackBar.displaySnackBar('All characters cannot be 1.');
CustomSnackBar.displaySnackBar(
'All characters cannot be 1.');
}
},
autoDisposeControllers: false,
@ -150,11 +152,10 @@ class CreateTemporaryPassword extends StatelessWidget {
if (smartDoorBloc.passwordController.text.isNotEmpty)
TextButton(
onPressed: () async {
await Clipboard.setData(ClipboardData(
text: smartDoorBloc.passwordController.text));
await Clipboard.setData(
ClipboardData(text: smartDoorBloc.passwordController.text));
},
child: const Text('Copy')
),
child: const Text('Copy')),
const SizedBox(
height: 20,
),

View File

@ -31,47 +31,36 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
value: smartDoorModel.unlockRequest > 0 ? 1 : 0,
duration: Duration(seconds: smartDoorModel.unlockRequest),
value: context.read<SmartDoorBloc>().unlockRequest > 0 ? 1 : 0,
duration: Duration(seconds: context.read<SmartDoorBloc>().unlockRequest),
);
if (smartDoorModel.unlockRequest > 0) {
if (context.read<SmartDoorBloc>().unlockRequest > 0) {
_animationController.reverse();
}
_animation = Tween<double>(begin: 0, end: 1).animate(_animationController)
..addListener(() {
// if (_animation.status == AnimationStatus.completed) {
// if (widget.doorLock.status
// .firstWhere((element) => element.code == 'normal_open_switch')
// .value !=
// true) {
// DevicesCubit.getInstance().deviceControl(
// DeviceControlModel(
// deviceId: widget.doorLock.uuid, code: 'normal_open_switch', value: true),
// widget.doorLock.uuid ?? "");
// }
// BlocProvider.of<SmartDoorBloc>(context)
// .add(UpdateLockEvent(value: smartDoorModel.normalOpenSwitch));
// _animationController.reverse();
// }
// } else if (_animation.status == AnimationStatus.dismissed) {
// // if (widget.doorLock.status
// // .firstWhere((element) => element.code == 'normal_open_switch')
// // .value !=
// // false) {
// DevicesCubit.getInstance().deviceControl(
// DeviceControlModel(
// deviceId: widget.doorLock.uuid, code: 'normal_open_switch', value: false),
// widget.doorLock.uuid ?? "");
// // }
// _animationController.forward();
// }
setState(() {});
});
}
@override
void didUpdateWidget(DoorLockButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (_animationController.status == AnimationStatus.dismissed) {
if (context.read<SmartDoorBloc>().unlockRequest > 0) {
_animationController.value = 1;
_animationController.duration =
Duration(seconds: context.read<SmartDoorBloc>().unlockRequest);
_animationController.reverse();
}
}
}
@override
void dispose() {
_animationController.dispose();
@ -100,7 +89,7 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
// } else if (_animationController.status == AnimationStatus.reverse) {
// _animationController.forward();
// }
if (smartDoorModel.unlockRequest > 0) {
if (context.read<SmartDoorBloc>().unlockRequest > 0) {
BlocProvider.of<SmartDoorBloc>(context)
.add(UpdateLockEvent(value: smartDoorModel.normalOpenSwitch));
}

View File

@ -31,16 +31,18 @@ class DoorDialogState extends State<DoorDialog> {
@override
Widget build(BuildContext context) {
final effectiveTime = widget.temporaryPassword?.effectiveTime ??int.parse( widget.offline?.gmtStart);
final invalidTime = widget.temporaryPassword?.invalidTime ?? int.parse(widget.offline?.gmtExpired);
final effectiveTime =
widget.temporaryPassword?.effectiveTime ?? int.parse(widget.offline?.gmtStart);
final invalidTime =
widget.temporaryPassword?.invalidTime ?? int.parse(widget.offline?.gmtExpired);
final DateTime effectiveDateTime =
DateTime.fromMillisecondsSinceEpoch(effectiveTime! * 1000, isUtc: false);
DateTime.fromMillisecondsSinceEpoch(effectiveTime * 1000, isUtc: false);
String formattedDateEffectiveTime = DateFormat('yyyy-MM-dd').format(effectiveDateTime);
String formattedTimeEffectiveTime = DateFormat('hh:mm a').format(effectiveDateTime);
final DateTime expiredDateTime =
DateTime.fromMillisecondsSinceEpoch(invalidTime! * 1000, isUtc: false);
DateTime.fromMillisecondsSinceEpoch(invalidTime * 1000, isUtc: false);
String formattedDateExpiredDateTime = DateFormat('yyyy-MM-dd').format(expiredDateTime);
String formattedTimeExpiredDateTime = DateFormat('hh:mm a').format(expiredDateTime);
return Dialog(
@ -116,8 +118,8 @@ class DoorDialogState extends State<DoorDialog> {
width: double.infinity,
color: ColorsManager.greyColor,
),
widget.temporaryPassword?.effectiveTime!=null?
Row(
widget.temporaryPassword?.effectiveTime != null
? Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
InkWell(
@ -143,13 +145,14 @@ class DoorDialogState extends State<DoorDialog> {
child: Center(
child: BodyMedium(
text: 'Delete Password',
style: context.bodyMedium.copyWith(color: ColorsManager.primaryColorWithOpacity),
style: context.bodyMedium
.copyWith(color: ColorsManager.primaryColorWithOpacity),
),
),
),
],
):
Row(
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
@ -165,9 +168,7 @@ class DoorDialogState extends State<DoorDialog> {
),
),
),
),
],
)
],

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/members_management_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/smart_linkage_view.dart';
@ -10,9 +9,8 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart
import 'package:syncrow_app/generated/assets.dart';
class DoorLockGrid extends StatelessWidget {
String uuid;
DoorLockGrid({
super.key,required this.uuid});
final String uuid;
const DoorLockGrid({super.key, required this.uuid});
@override
Widget build(BuildContext context) {

View File

@ -14,14 +14,17 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class OnetimePasswordPage extends StatelessWidget {
final String? deviceId;
const OnetimePasswordPage({super.key, this.deviceId,});
const OnetimePasswordPage({
super.key,
this.deviceId,
});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialOneTimePassword( )),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
create: (BuildContext context) =>
SmartDoorBloc(deviceId: deviceId!)..add(InitialOneTimePassword()),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
@ -30,25 +33,26 @@ class OnetimePasswordPage extends StatelessWidget {
),
);
}
},
builder: (context, state) {
}, builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
title: 'Passwords',
actions: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => OfflineOneTimePasswordPage(deviceId: deviceId, )
)).then((result) {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => OfflineOneTimePasswordPage(
deviceId: deviceId,
)))
.then((result) {
if (result != null) {
smartDoorBloc.add(InitialOneTimePassword());
smartDoorBloc.add(InitialOneTimePassword());
}
});
},
icon: const Icon(Icons.add)
)
icon: const Icon(Icons.add))
],
child: Builder(
builder: (context) {
@ -62,16 +66,18 @@ class OnetimePasswordPage extends StatelessWidget {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
padding: const EdgeInsets.symmetric(
horizontal: 15, vertical: 10),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon),
title: BodyMedium(
text: 'Password Name: ${smartDoorBloc.oneTimePasswords![index].pwdName}',
text:
'Password Name: ${smartDoorBloc.oneTimePasswords![index].pwdName}',
fontWeight: FontWeight.normal,
),
onTap: () async {
final result = await showDialog(
await showDialog(
context: context,
builder: (context) {
return DoorDialog(
@ -80,7 +86,6 @@ class OnetimePasswordPage extends StatelessWidget {
);
},
);
},
trailing: const Icon(
Icons.arrow_forward_ios,
@ -91,7 +96,8 @@ class OnetimePasswordPage extends StatelessWidget {
),
);
},
) : Column(
)
: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -105,7 +111,6 @@ class OnetimePasswordPage extends StatelessWidget {
);
},
));
})
);
}));
}
}

View File

@ -19,31 +19,30 @@ class TimeLimitedPasswordPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialTimeLimitPassword()),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
create: (BuildContext context) =>
SmartDoorBloc(deviceId: deviceId!)..add(InitialTimeLimitPassword()),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
if (state is FailedState) {
CustomSnackBar.displaySnackBar(
state.errorMessage
);
CustomSnackBar.displaySnackBar(state.errorMessage);
}
},
builder: (context, state) {
}, builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
title: 'Passwords',
actions: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => CreateOfflineTimeLimitPasswordPage(deviceId: deviceId,)
)).then((result) {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => CreateOfflineTimeLimitPasswordPage(
deviceId: deviceId,
)))
.then((result) {
smartDoorBloc.add(InitialTimeLimitPassword());
smartDoorBloc.add(InitialTimeLimitPassword());
});
},
icon: const Icon(Icons.add)
)
icon: const Icon(Icons.add))
],
child: Builder(
builder: (context) {
@ -57,16 +56,18 @@ class TimeLimitedPasswordPage extends StatelessWidget {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
padding: const EdgeInsets.symmetric(
horizontal: 15, vertical: 10),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon),
title: BodyMedium(
text: 'Password Name: ${smartDoorBloc.timeLimitPasswords![index].pwdName}',
text:
'Password Name: ${smartDoorBloc.timeLimitPasswords![index].pwdName}',
fontWeight: FontWeight.normal,
),
onTap: () async {
final result = await showDialog(
await showDialog(
context: context,
builder: (context) {
return DoorDialog(
@ -85,7 +86,8 @@ class TimeLimitedPasswordPage extends StatelessWidget {
),
);
},
) : Column(
)
: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -99,7 +101,6 @@ class TimeLimitedPasswordPage extends StatelessWidget {
);
},
));
})
);
}));
}
}

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
// import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
// import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart';
// import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_state.dart';
// import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/two_gang_bloc.dart';
// import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/two_gang_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -18,7 +18,7 @@ class GangSwitch extends StatelessWidget {
@override
Widget build(BuildContext context) {
return InkWell(
overlayColor: MaterialStateProperty.all(Colors.transparent),
overlayColor: WidgetStateProperty.all(Colors.transparent),
onTap: () {
action();
// var tempControl = DeviceControlModel(

View File

@ -63,16 +63,20 @@ class ScheduleScreen extends StatelessWidget {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScreen(
pageBuilder:
(context, animation1, animation2) =>
TimerScheduleScreen(
switchCode: "switch_1",
device: device,
deviceCode: 'countdown_1',
)));
},
child: Container(
padding:
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20),
padding: const EdgeInsets.only(
left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Bedside Light",
@ -99,16 +103,20 @@ class ScheduleScreen extends StatelessWidget {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScreen(
pageBuilder:
(context, animation1, animation2) =>
TimerScheduleScreen(
switchCode: "switch_2",
device: device,
deviceCode: 'countdown_2',
)));
},
child: Container(
padding:
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20),
padding: const EdgeInsets.only(
left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Ceiling Light",
@ -135,16 +143,20 @@ class ScheduleScreen extends StatelessWidget {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScreen(
pageBuilder:
(context, animation1, animation2) =>
TimerScheduleScreen(
switchCode: "switch_3",
device: device,
deviceCode: 'countdown_3',
)));
},
child: Container(
padding:
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20),
padding: const EdgeInsets.only(
left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Spotlight",

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