Compare commits
63 Commits
chore/depe
...
SP-496
Author | SHA1 | Date | |
---|---|---|---|
3082148e8c | |||
2fb18965f4 | |||
8d784f1e95 | |||
bc1b92cd5c | |||
6e32f30970 | |||
781522d4b6 | |||
4e345db842 | |||
8508995108 | |||
e3a6579819 | |||
9d8c40e44e | |||
a811baca70 | |||
04e8131fb2 | |||
dfae04076f | |||
429009aefa | |||
62e80c89a2 | |||
d97efe229d | |||
58e13da887 | |||
7279215cdc | |||
e23210777a | |||
45ebd10980 | |||
0b3f9de162 | |||
a46cec9dc5 | |||
09d1ce5ccb | |||
c3273c729d | |||
42e76f1c6e | |||
64e2ba2fd9 | |||
54cce48b89 | |||
f0feb4021f | |||
340ac35b3e | |||
af31d33778 | |||
26833cf215 | |||
6165c2ceee | |||
65bb388daf | |||
b7f59902cd | |||
740ca4e4ba | |||
d9cd24e7f0 | |||
42b5ff105f | |||
ddaf36797d | |||
ad47e34fa2 | |||
46662b5bac | |||
b5842194ff | |||
ba4ebd07e1 | |||
21c336360c | |||
fee34703bd | |||
a92676d6a4 | |||
8c5cf2c04e | |||
1f02f66916 | |||
3ea089425c | |||
76be98354b | |||
3418fbe7b4 | |||
ea3bc4b5e1 | |||
77d2f54352 | |||
cff66bb653 | |||
022ba53f5d | |||
bf69399af2 | |||
a72fc0b466 | |||
df13840a65 | |||
e63bf2a2c2 | |||
bf944a6121 | |||
eb5aa56536 | |||
1e35bb8736 | |||
9c23ab1399 | |||
b3bb0b9eea |
31
.vscode/launch.json
vendored
@ -1,5 +1,6 @@
|
||||
{
|
||||
"configurations": [
|
||||
|
||||
|
||||
{
|
||||
|
||||
@ -11,9 +12,13 @@
|
||||
|
||||
"args": [
|
||||
|
||||
"--dart-define",
|
||||
|
||||
"FLAVOR=development"
|
||||
"--flavor",
|
||||
|
||||
"dev",
|
||||
|
||||
"-t",
|
||||
|
||||
"lib/main_dev.dart"
|
||||
|
||||
],
|
||||
|
||||
@ -29,9 +34,13 @@
|
||||
|
||||
"args": [
|
||||
|
||||
"--dart-define",
|
||||
|
||||
"FLAVOR=staging"
|
||||
"--flavor",
|
||||
|
||||
"prod",
|
||||
|
||||
"-t",
|
||||
|
||||
"lib/main.dart"
|
||||
|
||||
],
|
||||
|
||||
@ -47,9 +56,13 @@
|
||||
|
||||
"args": [
|
||||
|
||||
"--dart-define",
|
||||
|
||||
"FLAVOR=production"
|
||||
"--flavor",
|
||||
|
||||
"prod",
|
||||
|
||||
"-t",
|
||||
|
||||
"lib/main.dart"
|
||||
|
||||
],
|
||||
|
||||
|
@ -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`.
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
}
|
48
android/app/src/dev/google-services.json
Normal 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"
|
||||
}
|
30
android/app/src/prod/google-services.json
Normal 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
@ -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
@ -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 |
47
assets/icons/closed_door.svg
Normal 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 |
10
assets/icons/door_notification_setting_icon.svg
Normal 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 |
18
assets/icons/door_records_icon.svg
Normal 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 |
23
assets/icons/door_sensor_icon.svg
Normal 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 |
15
assets/icons/emptySchedule.svg
Normal 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 |
47
assets/icons/opened_door.svg
Normal 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 |
10
assets/icons/schedule_Inching_icon.svg
Normal 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 |
12
assets/icons/schedule_celender_icon.svg
Normal 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 |
4
assets/icons/schedule_circulate_icon.svg
Normal 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 |
4
assets/icons/schedule_time_icon.svg
Normal 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 |
14
assets/icons/success-white.svg
Normal 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 |
22
assets/icons/water_heater_icon.svg
Normal 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 |
29
assets/icons/water_heater_off.svg
Normal 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 |
29
assets/icons/water_heater_on.svg
Normal 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 |
@ -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"}}}}}}
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
77
ios/Runner.xcodeproj/xcshareddata/xcschemes/dev.xcscheme
Normal 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>
|
@ -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>
|
@ -1,7 +1,7 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
|
||||
@main
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
|
@ -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>
|
||||
|
32
ios/config/prod/GoogleService-Info.plist
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>API_KEY</key>
|
||||
<string>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>
|
@ -16,60 +16,55 @@ 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,
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
size: 16,
|
||||
),
|
||||
underline: const SizedBox.shrink(),
|
||||
padding: EdgeInsets.zero,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
value: HomeCubit.getInstance().selectedSpace!.id,
|
||||
items: HomeCubit.getInstance().spaces!.map((space) {
|
||||
return DropdownMenuItem(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
value: space.id,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
SvgPicture.asset(
|
||||
Assets.assetsIconsHome,
|
||||
width: 25,
|
||||
height: 25,
|
||||
colorFilter: const ColorFilter.mode(
|
||||
ColorsManager.textPrimaryColor,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Flexible(
|
||||
fit: FlexFit.loose,
|
||||
child: BodyMedium(
|
||||
text: space.name ?? "??",
|
||||
style: context.bodyMedium.copyWith(
|
||||
fontSize: 15,
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
HomeCubit.getInstance().changeSelectedSpace(
|
||||
HomeCubit.getInstance()
|
||||
.spaces!
|
||||
.firstWhere((element) => element.id == value));
|
||||
}
|
||||
},
|
||||
child: DropdownButton(
|
||||
icon: const Icon(
|
||||
Icons.expand_more,
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
size: 16,
|
||||
),
|
||||
underline: const SizedBox.shrink(),
|
||||
padding: EdgeInsets.zero,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
value: HomeCubit.getInstance().selectedSpace!.id,
|
||||
items: HomeCubit.getInstance().spaces!.map((space) {
|
||||
return DropdownMenuItem(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
value: space.id,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
SvgPicture.asset(
|
||||
Assets.assetsIconsHome,
|
||||
width: 25,
|
||||
height: 25,
|
||||
colorFilter: const ColorFilter.mode(
|
||||
ColorsManager.textPrimaryColor,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Flexible(
|
||||
child: BodyMedium(
|
||||
text: space.name ?? "??",
|
||||
style: context.bodyMedium.copyWith(
|
||||
fontSize: 15,
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
HomeCubit.getInstance().changeSelectedSpace(
|
||||
HomeCubit.getInstance().spaces!.firstWhere((element) => element.id == value));
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -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],
|
||||
));
|
||||
},
|
||||
);
|
||||
|
@ -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';
|
||||
}
|
||||
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';
|
||||
}
|
||||
}
|
||||
List<String> errors = [];
|
||||
|
||||
if (value == null || value.isEmpty) {
|
||||
errors.add("Please enter your password");
|
||||
}
|
||||
return null;
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
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'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
184
lib/features/devices/bloc/curtain_bloc/curtain_bloc.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
34
lib/features/devices/bloc/curtain_bloc/curtain_event.dart
Normal 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 {}
|
76
lib/features/devices/bloc/curtain_bloc/curtain_state.dart
Normal 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];
|
||||
}
|
@ -87,10 +87,10 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
return const DoorsListView();
|
||||
case DeviceType.Curtain:
|
||||
return const CurtainListView();
|
||||
// case DeviceType.ThreeGang:
|
||||
// return const ThreeGangSwitchesView();
|
||||
// case DeviceType.Gateway:
|
||||
// return const GateWayView();
|
||||
// case DeviceType.ThreeGang:
|
||||
// return const ThreeGangSwitchesView();
|
||||
// case DeviceType.Gateway:
|
||||
// return const GateWayView();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -308,10 +308,10 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
|
||||
emitSafe(GetDevicesLoading());
|
||||
int roomIndex =
|
||||
HomeCubit.getInstance().selectedSpace!.rooms!.indexWhere((element) => element.id == roomId);
|
||||
HomeCubit.getInstance().selectedSpace!.rooms!.indexWhere((element) => element.id == roomId);
|
||||
try {
|
||||
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices =
|
||||
await DevicesAPI.getDevicesByRoomId(roomId);
|
||||
await DevicesAPI.getDevicesByRoomId(roomId);
|
||||
} catch (e) {
|
||||
emitSafe(GetDevicesError(e.toString()));
|
||||
return;
|
||||
@ -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 {
|
||||
|
179
lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart
Normal 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 (_) {}
|
||||
}
|
||||
}
|
@ -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 {}
|
@ -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];
|
||||
// }
|
470
lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
141
lib/features/devices/bloc/one_gang_bloc/one_gang_event.dart
Normal 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];
|
||||
}
|
92
lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart
Normal 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);
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
@ -104,7 +114,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
|
||||
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$threeGangId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) async {
|
||||
stream.listen((DatabaseEvent event) async {
|
||||
if (_timer != null) {
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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 {}
|
||||
|
@ -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);
|
||||
}
|
||||
|
629
lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
155
lib/features/devices/bloc/two_gang_bloc/two_gang_event.dart
Normal 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];
|
||||
}
|
92
lib/features/devices/bloc/two_gang_bloc/two_gang_state.dart
Normal 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);
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {}
|
@ -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];
|
||||
}
|
11
lib/features/devices/model/GroupWHModel.dart
Normal 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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
};
|
||||
|
@ -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'],
|
||||
|
51
lib/features/devices/model/device_report_model.dart
Normal 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,
|
||||
};
|
||||
}
|
33
lib/features/devices/model/door_sensor_model.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
11
lib/features/devices/model/group_one_gang_model.dart
Normal 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,
|
||||
});
|
||||
}
|
13
lib/features/devices/model/group_two_gang_model.dart
Normal 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,
|
||||
});
|
||||
}
|
30
lib/features/devices/model/one_gang_model.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
23
lib/features/devices/model/report_model.dart
Normal 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,
|
||||
});
|
||||
}
|
83
lib/features/devices/model/schedule_model.dart
Normal 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);
|
||||
}
|
40
lib/features/devices/model/two_gang_model.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
141
lib/features/devices/model/water_heater.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
@ -71,44 +71,49 @@ class ParameterControlDialogState extends State<ParameterControlDialog> {
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_value = (_value - 1).clamp(widget.min, widget.max);
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.remove,
|
||||
color: Colors.grey,
|
||||
SizedBox(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_value = (_value - 1).clamp(widget.min, widget.max);
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.remove,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
Slider(
|
||||
value: _value.toDouble(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_value = value.toInt();
|
||||
});
|
||||
},
|
||||
min: widget.min.toDouble(),
|
||||
max: widget.max.toDouble(),
|
||||
label: _value.toString(),
|
||||
inactiveColor: ColorsManager.greyColor,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_value = (_value + 1).clamp(widget.min, widget.max);
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
color: Colors.grey,
|
||||
Flexible(
|
||||
child: Slider(
|
||||
value: _value.toDouble(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_value = value.toInt();
|
||||
});
|
||||
},
|
||||
min: widget.min.toDouble(),
|
||||
max: widget.max.toDouble(),
|
||||
label: _value.toString(),
|
||||
inactiveColor: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_value = (_value + 1).clamp(widget.min, widget.max);
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 1,
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -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,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
// }
|
@ -1,114 +1,73 @@
|
||||
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(
|
||||
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: InkWell(
|
||||
overlayColor: MaterialStateProperty.all(Colors.transparent),
|
||||
onTap: () {
|
||||
DevicesCubit.get(context).openCurtain(curtain.productType!);
|
||||
},
|
||||
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,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
_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: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 5,
|
||||
offset: const Offset(3, 3),
|
||||
),
|
||||
]),
|
||||
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,
|
||||
),
|
||||
onTap: onTap,
|
||||
child: const SizedBox.square(dimension: 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,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 5, bottom: 5),
|
||||
child: InkWell(
|
||||
overlayColor: MaterialStateProperty.all(Colors.transparent),
|
||||
onTap: onTap,
|
||||
child: isSvg
|
||||
? SvgPicture.asset(iconPath, width: 110, height: 110)
|
||||
: Image.asset(iconPath, width: 60, height: 60),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -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 {
|
||||
|
@ -1,86 +1,100 @@
|
||||
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(
|
||||
title: curtain.name,
|
||||
child: Column(
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
children: [
|
||||
Container(
|
||||
height: 340,
|
||||
width: 365,
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
Assets.assetsImagesWindow,
|
||||
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: [
|
||||
Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
children: [
|
||||
Container(
|
||||
height: 340,
|
||||
width: 365,
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
Assets.assetsImagesWindow,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(40),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.linear,
|
||||
height: 310,
|
||||
width: DevicesCubit.getInstance().curtainWidth,
|
||||
child: Stack(
|
||||
children: List.generate(
|
||||
10,
|
||||
(index) {
|
||||
double spacing =
|
||||
DevicesCubit.getInstance().curtainWidth / 9;
|
||||
double leftMostPosition = index * spacing;
|
||||
return AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.linear,
|
||||
left: leftMostPosition,
|
||||
child: SizedBox(
|
||||
height: 320,
|
||||
width: 32,
|
||||
child: SvgPicture.asset(
|
||||
Assets.assetsIconsCurtainsIconVerticalBlade,
|
||||
fit: BoxFit.fill,
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(40),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.linear,
|
||||
height: 310,
|
||||
width: curtainWidth,
|
||||
child: Stack(
|
||||
children: List.generate(
|
||||
10,
|
||||
(index) {
|
||||
double spacing = curtainWidth / 9;
|
||||
double leftMostPosition = index * spacing;
|
||||
return AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.linear,
|
||||
left: leftMostPosition,
|
||||
child: SizedBox(
|
||||
height: 320,
|
||||
width: 32,
|
||||
child: SvgPicture.asset(
|
||||
Assets.assetsIconsCurtainsIconVerticalBlade,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
Positioned(
|
||||
top: 27,
|
||||
left: 43,
|
||||
child: SvgPicture.asset(
|
||||
Assets.assetsIconsCurtainsIconCurtainHolder)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 80),
|
||||
CurtainButtons(
|
||||
curtain: curtain,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Assets.assetsIconsCurtainsIconCurtainHolder,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 80),
|
||||
CurtainButtons(curtain: curtain),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -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,30 +10,33 @@ 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) {
|
||||
return AppBar(
|
||||
return AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
centerTitle: true,
|
||||
title: BodyLarge(
|
||||
text: deviceName ?? "",
|
||||
text: deviceName,
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
actions: [
|
||||
IconButton(onPressed: () {
|
||||
showPopupMenu(context: context, items: [
|
||||
PopupMenuItem(
|
||||
onTap: () async {
|
||||
HomeCubit.getInstance().updateDevice(deviceUuid);
|
||||
},
|
||||
value: 'Update',
|
||||
child: const Text('Update'),
|
||||
)
|
||||
]);
|
||||
}, icon: Icon(Icons.edit))
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
showPopupMenu(context: context, items: [
|
||||
PopupMenuItem(
|
||||
onTap: () async {
|
||||
HomeCubit.getInstance().updateDevice(deviceUuid);
|
||||
},
|
||||
value: 'Update',
|
||||
child: const Text('Update'),
|
||||
)
|
||||
]);
|
||||
},
|
||||
icon: Icon(Icons.edit))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -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,
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
@ -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.'));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -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;
|
||||
@ -38,9 +36,10 @@ class GateWayView extends StatelessWidget {
|
||||
backgroundColor: ColorsManager.backgroundColor,
|
||||
extendBodyBehindAppBar: true,
|
||||
extendBody: true,
|
||||
appBar:DeviceAppbar(
|
||||
deviceName: 'Gateway',
|
||||
deviceUuid: gatewayObj.uuid!,),
|
||||
appBar: DeviceAppbar(
|
||||
deviceName: 'Gateway',
|
||||
deviceUuid: gatewayObj.uuid!,
|
||||
),
|
||||
body: Container(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
@ -55,11 +54,11 @@ class GateWayView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
child: RefreshIndicator(
|
||||
onRefresh:()async {
|
||||
BlocProvider.of<GatewayBloc>(context).add(GatewayInitial(gatewayId: gatewayObj.uuid ?? ''));
|
||||
},
|
||||
child: ListView(
|
||||
|
||||
onRefresh: () async {
|
||||
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 {
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
));
|
||||
)));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -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';
|
||||
|
@ -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,14 +26,12 @@ 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){
|
||||
if (state is IsRepeatState) {
|
||||
isRepeat = state.repeat;
|
||||
}
|
||||
if (state is GeneratePasswordOneTimestate ){
|
||||
if (state is GeneratePasswordOneTimestate) {
|
||||
generated = state.generated;
|
||||
}
|
||||
}, builder: (context, state) {
|
||||
@ -54,170 +49,173 @@ 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())
|
||||
: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const BodyMedium(
|
||||
text: 'Save the password immediately. The password is not displayed in the app.',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const BodyMedium(
|
||||
text: '7-Digit Password',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children:smartDoorBloc.passwordController.text.isEmpty?
|
||||
List.generate(10, (index) {
|
||||
return const Padding(
|
||||
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(
|
||||
color: ColorsManager.primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 8.0 ,
|
||||
fontSize: 25,
|
||||
wordSpacing: 2),
|
||||
textAlign: TextAlign.center,
|
||||
text: smartDoorBloc.passwordController.text,
|
||||
fontSize: 23,
|
||||
),),
|
||||
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await Clipboard.setData(ClipboardData(
|
||||
text: smartDoorBloc.passwordController.text));
|
||||
},
|
||||
icon: const Icon(Icons.copy)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
|
||||
],
|
||||
const BodyMedium(
|
||||
text:
|
||||
'Save the password immediately. The password is not displayed in the app.',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
if(smartDoorBloc.passwordController.text.isNotEmpty)
|
||||
Column(
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const BodyMedium(
|
||||
text: '7-Digit Password',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
||||
child: Column(
|
||||
children: [
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: const BodyMedium(
|
||||
text: 'Password Name',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: smartDoorBloc.passwordController.text.isEmpty
|
||||
? List.generate(10, (index) {
|
||||
return const Padding(
|
||||
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(
|
||||
color: ColorsManager.primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 8.0,
|
||||
fontSize: 25,
|
||||
wordSpacing: 2),
|
||||
textAlign: TextAlign.center,
|
||||
text: smartDoorBloc.passwordController.text,
|
||||
fontSize: 23,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await Clipboard.setData(ClipboardData(
|
||||
text: smartDoorBloc
|
||||
.passwordController.text));
|
||||
},
|
||||
icon: const Icon(Icons.copy)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width / 2.6,
|
||||
child: TextFormField(
|
||||
controller: BlocProvider.of<SmartDoorBloc>(context).passwordNameController,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Enter The Name',
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 14, color: ColorsManager.textGray)),
|
||||
)),
|
||||
],
|
||||
),
|
||||
|
||||
if (smartDoorBloc.passwordController.text.isNotEmpty)
|
||||
Column(
|
||||
children: [
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: const BodyMedium(
|
||||
text: 'Password Name',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width / 2.6,
|
||||
child: TextFormField(
|
||||
controller: BlocProvider.of<SmartDoorBloc>(context)
|
||||
.passwordNameController,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Enter The Name',
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 14, color: ColorsManager.textGray)),
|
||||
)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const BodyMedium(
|
||||
textAlign: TextAlign.center,
|
||||
text:
|
||||
'Save the password immediately. The password is not displayed in the app.',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
|
||||
// NameTimeWidget(type:type!),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width / 1.5,
|
||||
child: DoorLockButton(
|
||||
isDone: generated,
|
||||
isLoading: smartDoorBloc.isSavingPassword,
|
||||
borderRadius: 30,
|
||||
backgroundColor: ColorsManager.primaryColor,
|
||||
onPressed: () async {
|
||||
if (generated == false) {
|
||||
smartDoorBloc
|
||||
.add(GenerateAndSavePasswordOneTimeEvent(context: context));
|
||||
} else {
|
||||
if (smartDoorBloc.passwordNameController.text.isNotEmpty) {
|
||||
smartDoorBloc.add(RenamePasswordEvent());
|
||||
}
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
},
|
||||
child: const BodyMedium(
|
||||
text: 'Obtain Password',
|
||||
fontWeight: FontWeight.bold,
|
||||
fontColor: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
isRepeat ? const RepeatWidget() : const SizedBox(),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const BodyMedium(
|
||||
textAlign: TextAlign.center,
|
||||
text: 'Save the password immediately. The password is not displayed in the app.',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
|
||||
// NameTimeWidget(type:type!),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width/1.5,
|
||||
child: DoorLockButton(
|
||||
isDone: generated,
|
||||
isLoading: smartDoorBloc.isSavingPassword ,
|
||||
borderRadius: 30,
|
||||
backgroundColor:ColorsManager.primaryColor ,
|
||||
onPressed: () async {
|
||||
if(generated==false){
|
||||
smartDoorBloc.add(GenerateAndSavePasswordOneTimeEvent(context: context));
|
||||
}else{
|
||||
if(smartDoorBloc.passwordNameController.text.isNotEmpty){
|
||||
smartDoorBloc.add(RenamePasswordEvent());
|
||||
}
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
},
|
||||
child: const BodyMedium(
|
||||
text: 'Obtain Password',
|
||||
fontWeight: FontWeight.bold,
|
||||
fontColor: Colors.white,
|
||||
),),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
isRepeat? const RepeatWidget():const SizedBox(),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}));
|
||||
}
|
||||
|
@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -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));
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
165
lib/features/devices/view/widgets/one_gang/one_gang_screen.dart
Normal 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())
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -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';
|
||||
}
|
||||
}
|
@ -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,
|
||||
);
|
||||
},
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
@ -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';
|
||||
|
||||
|
@ -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:
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ class RoomsSlider extends StatelessWidget {
|
||||
onPageChanged: (index) {
|
||||
HomeCubit.getInstance().roomSliderPageChanged(index);
|
||||
},
|
||||
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
|
@ -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) {
|
||||
@ -35,11 +35,11 @@ class CreateTemporaryPassword extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
if (state is IsRepeatState){
|
||||
if (state is IsRepeatState) {
|
||||
isRepeat = state.repeat;
|
||||
}
|
||||
if (state is GeneratePasswordOneTimestate ){
|
||||
generated = state.generated;
|
||||
if (state is GeneratePasswordOneTimestate) {
|
||||
// generated = state.generated;
|
||||
}
|
||||
}, builder: (context, state) {
|
||||
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
|
||||
@ -56,141 +56,142 @@ class CreateTemporaryPassword extends StatelessWidget {
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back)
|
||||
),
|
||||
actions:
|
||||
type == 'Online Password'?[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
smartDoorBloc.add(SavePasswordEvent(context: context));
|
||||
},
|
||||
child: const Text('Save')
|
||||
)
|
||||
]:null,
|
||||
icon: const Icon(Icons.arrow_back)),
|
||||
actions: type == 'Online Password'
|
||||
? [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
smartDoorBloc.add(SavePasswordEvent(context: context));
|
||||
},
|
||||
child: const Text('Save'))
|
||||
]
|
||||
: null,
|
||||
),
|
||||
child: state is LoadingInitialState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const BodyMedium(
|
||||
text: 'Save the password immediately. The password is not displayed in the app.',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const BodyMedium(
|
||||
text: '7-Digit Password',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: type == 'Online Password'?0:25),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: PinCodeTextField(
|
||||
onCompleted: (value) {
|
||||
if (value.split('').every((char) => char == '1')) {
|
||||
smartDoorBloc.passwordController.clear();
|
||||
CustomSnackBar.displaySnackBar('All characters cannot be 1.');
|
||||
}
|
||||
},
|
||||
autoDisposeControllers: false,
|
||||
keyboardType: TextInputType.phone,
|
||||
length: 7,
|
||||
// enabled:type == 'Online Password'? true:false,
|
||||
obscureText: false,
|
||||
animationType: AnimationType.fade,
|
||||
pinTheme: PinTheme(
|
||||
shape: PinCodeFieldShape.underline,
|
||||
fieldHeight: 45,
|
||||
fieldWidth: 20,
|
||||
activeFillColor: Colors.white,
|
||||
disabledColor: Colors.grey,
|
||||
activeColor: Colors.grey,
|
||||
errorBorderColor: Colors.grey,
|
||||
inactiveColor: Colors.grey,
|
||||
inactiveFillColor: Colors.grey,
|
||||
selectedColor: Colors.grey),
|
||||
animationDuration: const Duration(milliseconds: 300),
|
||||
backgroundColor: Colors.white,
|
||||
enableActiveFill: false,
|
||||
controller: smartDoorBloc.passwordController,
|
||||
appContext: context,
|
||||
)),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const BodyMedium(
|
||||
text:
|
||||
'Save the password immediately. The password is not displayed in the app.',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const BodyMedium(
|
||||
text: '7-Digit Password',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: type == 'Online Password' ? 0 : 25),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: PinCodeTextField(
|
||||
onCompleted: (value) {
|
||||
if (value.split('').every((char) => char == '1')) {
|
||||
smartDoorBloc.passwordController.clear();
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'All characters cannot be 1.');
|
||||
}
|
||||
},
|
||||
autoDisposeControllers: false,
|
||||
keyboardType: TextInputType.phone,
|
||||
length: 7,
|
||||
// enabled:type == 'Online Password'? true:false,
|
||||
obscureText: false,
|
||||
animationType: AnimationType.fade,
|
||||
pinTheme: PinTheme(
|
||||
shape: PinCodeFieldShape.underline,
|
||||
fieldHeight: 45,
|
||||
fieldWidth: 20,
|
||||
activeFillColor: Colors.white,
|
||||
disabledColor: Colors.grey,
|
||||
activeColor: Colors.grey,
|
||||
errorBorderColor: Colors.grey,
|
||||
inactiveColor: Colors.grey,
|
||||
inactiveFillColor: Colors.grey,
|
||||
selectedColor: Colors.grey),
|
||||
animationDuration: const Duration(milliseconds: 300),
|
||||
backgroundColor: Colors.white,
|
||||
enableActiveFill: false,
|
||||
controller: smartDoorBloc.passwordController,
|
||||
appContext: context,
|
||||
)),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
if (type == 'Online Password')
|
||||
Flexible(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
smartDoorBloc.add(GeneratePasswordEvent());
|
||||
},
|
||||
child: const BodyMedium(
|
||||
text: 'Generate Randomly',
|
||||
fontWeight: FontWeight.bold,
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
)),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
if(type == 'Online Password')
|
||||
Flexible(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
smartDoorBloc.add(GeneratePasswordEvent());
|
||||
),
|
||||
if (smartDoorBloc.passwordController.text.isNotEmpty)
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await Clipboard.setData(
|
||||
ClipboardData(text: smartDoorBloc.passwordController.text));
|
||||
},
|
||||
child: const Text('Copy')),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
NameTimeWidget(),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const BodyMedium(
|
||||
text: 'Repeat',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
trailing: Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: smartDoorBloc.repeat,
|
||||
onChanged: (value) {
|
||||
smartDoorBloc.add(ToggleRepeatEvent());
|
||||
},
|
||||
child: const BodyMedium(
|
||||
text: 'Generate Randomly',
|
||||
fontWeight: FontWeight.bold,
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
)),
|
||||
)
|
||||
],
|
||||
),
|
||||
applyTheme: true,
|
||||
)),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
isRepeat ? const RepeatWidget() : const SizedBox(),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
if(smartDoorBloc.passwordController.text.isNotEmpty)
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await Clipboard.setData(ClipboardData(
|
||||
text: smartDoorBloc.passwordController.text));
|
||||
},
|
||||
child: const Text('Copy')
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
NameTimeWidget(),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const BodyMedium(
|
||||
text: 'Repeat',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
trailing: Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: smartDoorBloc.repeat,
|
||||
onChanged: (value) {
|
||||
smartDoorBloc.add(ToggleRepeatEvent());
|
||||
},
|
||||
applyTheme: true,
|
||||
)),
|
||||
),
|
||||
) ,
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
isRepeat? const RepeatWidget():const SizedBox(),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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,60 +118,59 @@ class DoorDialogState extends State<DoorDialog> {
|
||||
width: double.infinity,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
widget.temporaryPassword?.effectiveTime!=null?
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Cancel',
|
||||
style: context.bodyMedium.copyWith(color: ColorsManager.greyColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 50,
|
||||
width: 1,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context, 'delete');
|
||||
},
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Delete Password',
|
||||
style: context.bodyMedium.copyWith(color: ColorsManager.primaryColorWithOpacity),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
):
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Container(
|
||||
height: 50,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Cancel',
|
||||
style: context.bodyMedium.copyWith(color: ColorsManager.greyColor),
|
||||
widget.temporaryPassword?.effectiveTime != null
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Cancel',
|
||||
style: context.bodyMedium.copyWith(color: ColorsManager.greyColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
|
||||
],
|
||||
)
|
||||
Container(
|
||||
height: 50,
|
||||
width: 1,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context, 'delete');
|
||||
},
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Delete Password',
|
||||
style: context.bodyMedium
|
||||
.copyWith(color: ColorsManager.primaryColorWithOpacity),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Container(
|
||||
height: 50,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Cancel',
|
||||
style: context.bodyMedium.copyWith(color: ColorsManager.greyColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -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) {
|
||||
@ -67,24 +65,24 @@ class DoorLockGrid extends StatelessWidget {
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> doorLockButtons({val}) => [
|
||||
{
|
||||
'title': 'Unlocking Records',
|
||||
'image': Assets.assetsIconsDoorlockAssetsUnlockingRecords,
|
||||
'page': const UnlockingRecordsView(),
|
||||
},
|
||||
{
|
||||
'title': 'Members Management',
|
||||
'image': Assets.assetsIconsDoorlockAssetsMembersManagement,
|
||||
'page': const MembersManagementView(),
|
||||
},
|
||||
{
|
||||
'title': 'Temporary Password',
|
||||
'image': Assets.assetsIconsDoorlockAssetsTemporaryPassword,
|
||||
'page': TemporaryPasswordPage(deviceId:val) ,
|
||||
},
|
||||
{
|
||||
'title': 'Smart Linkage',
|
||||
'image': Assets.assetsIconsDoorlockAssetsSmartLinkage,
|
||||
'page': const SmartLinkgeView()
|
||||
},
|
||||
];
|
||||
{
|
||||
'title': 'Unlocking Records',
|
||||
'image': Assets.assetsIconsDoorlockAssetsUnlockingRecords,
|
||||
'page': const UnlockingRecordsView(),
|
||||
},
|
||||
{
|
||||
'title': 'Members Management',
|
||||
'image': Assets.assetsIconsDoorlockAssetsMembersManagement,
|
||||
'page': const MembersManagementView(),
|
||||
},
|
||||
{
|
||||
'title': 'Temporary Password',
|
||||
'image': Assets.assetsIconsDoorlockAssetsTemporaryPassword,
|
||||
'page': TemporaryPasswordPage(deviceId: val),
|
||||
},
|
||||
{
|
||||
'title': 'Smart Linkage',
|
||||
'image': Assets.assetsIconsDoorlockAssetsSmartLinkage,
|
||||
'page': const SmartLinkgeView()
|
||||
},
|
||||
];
|
||||
|
@ -14,98 +14,103 @@ 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) {
|
||||
if (state is FailedState) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.errorMessage),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
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) {
|
||||
if(result!=null){
|
||||
smartDoorBloc.add(InitialOneTimePassword());
|
||||
smartDoorBloc.add(InitialOneTimePassword());
|
||||
}
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.add)
|
||||
)
|
||||
],
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return state is LoadingInitialState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Center(
|
||||
child: smartDoorBloc.oneTimePasswords!.isNotEmpty
|
||||
? ListView.builder(
|
||||
itemCount: smartDoorBloc.oneTimePasswords!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: DefaultContainer(
|
||||
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}',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
onTap: () async {
|
||||
final result = await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return DoorDialog(
|
||||
title: 'Password Information',
|
||||
offline: smartDoorBloc.oneTimePasswords![index],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
},
|
||||
trailing: const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
) : Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(Assets.noValidPasswords),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const BodyMedium(text: 'No Valid Passwords')
|
||||
],
|
||||
),
|
||||
);
|
||||
create: (BuildContext context) =>
|
||||
SmartDoorBloc(deviceId: deviceId!)..add(InitialOneTimePassword()),
|
||||
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
|
||||
if (state is FailedState) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.errorMessage),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
}, 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) {
|
||||
if (result != null) {
|
||||
smartDoorBloc.add(InitialOneTimePassword());
|
||||
smartDoorBloc.add(InitialOneTimePassword());
|
||||
}
|
||||
});
|
||||
},
|
||||
));
|
||||
})
|
||||
);
|
||||
icon: const Icon(Icons.add))
|
||||
],
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return state is LoadingInitialState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Center(
|
||||
child: smartDoorBloc.oneTimePasswords!.isNotEmpty
|
||||
? ListView.builder(
|
||||
itemCount: smartDoorBloc.oneTimePasswords!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: DefaultContainer(
|
||||
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}',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
onTap: () async {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return DoorDialog(
|
||||
title: 'Password Information',
|
||||
offline: smartDoorBloc.oneTimePasswords![index],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
trailing: const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(Assets.noValidPasswords),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const BodyMedium(text: 'No Valid Passwords')
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -19,87 +19,88 @@ 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) {
|
||||
if (state is FailedState) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
state.errorMessage
|
||||
);
|
||||
}
|
||||
},
|
||||
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) {
|
||||
smartDoorBloc.add(InitialTimeLimitPassword());
|
||||
smartDoorBloc.add(InitialTimeLimitPassword());
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.add)
|
||||
)
|
||||
],
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return state is LoadingInitialState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Center(
|
||||
child: smartDoorBloc.timeLimitPasswords!.isNotEmpty
|
||||
? ListView.builder(
|
||||
itemCount: smartDoorBloc.timeLimitPasswords!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: DefaultContainer(
|
||||
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}',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
onTap: () async {
|
||||
final result = await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return DoorDialog(
|
||||
title: 'Password Information',
|
||||
offline: smartDoorBloc.timeLimitPasswords![index],
|
||||
);
|
||||
},
|
||||
create: (BuildContext context) =>
|
||||
SmartDoorBloc(deviceId: deviceId!)..add(InitialTimeLimitPassword()),
|
||||
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
|
||||
if (state is FailedState) {
|
||||
CustomSnackBar.displaySnackBar(state.errorMessage);
|
||||
}
|
||||
}, 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) {
|
||||
smartDoorBloc.add(InitialTimeLimitPassword());
|
||||
smartDoorBloc.add(InitialTimeLimitPassword());
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.add))
|
||||
],
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return state is LoadingInitialState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Center(
|
||||
child: smartDoorBloc.timeLimitPasswords!.isNotEmpty
|
||||
? ListView.builder(
|
||||
itemCount: smartDoorBloc.timeLimitPasswords!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: DefaultContainer(
|
||||
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}',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
onTap: () async {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return DoorDialog(
|
||||
title: 'Password Information',
|
||||
offline: smartDoorBloc.timeLimitPasswords![index],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
trailing: const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
trailing: const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(Assets.noValidPasswords),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const BodyMedium(text: 'No Valid Passwords')
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
) : Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(Assets.noValidPasswords),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const BodyMedium(text: 'No Valid Passwords')
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
));
|
||||
})
|
||||
);
|
||||
);
|
||||
},
|
||||
));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -63,16 +63,20 @@ class ScheduleScreen extends StatelessWidget {
|
||||
Navigator.push(
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
pageBuilder: (context, animation1, animation2) => TimerScreen(
|
||||
device: device,
|
||||
deviceCode: 'countdown_1',
|
||||
)));
|
||||
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(
|
||||
device: device,
|
||||
deviceCode: 'countdown_2',
|
||||
)));
|
||||
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(
|
||||
device: device,
|
||||
deviceCode: 'countdown_3',
|
||||
)));
|
||||
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",
|
||||
|