Compare commits

..

1 Commits

Author SHA1 Message Date
4785c6a46e updated team 2024-09-02 13:44:09 +04:00
60 changed files with 946 additions and 4648 deletions

View File

@ -1,5 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 933 B

View File

@ -1,7 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,15 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -1,14 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

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

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */

View File

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

View File

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

View File

@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
@ -58,39 +59,19 @@ class AuthCubit extends Cubit<AuthState> {
/////////////////////////////////////VALIDATORS/////////////////////////////////////
String? passwordValidator(String? value) {
List<String> errors = [];
if (value == null || value.isEmpty) {
errors.add("Please enter your password");
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';
}
}
}
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
return null;
}
String? fullNameValidator(String? value) {
@ -201,10 +182,13 @@ 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();
@ -241,24 +225,20 @@ 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'));
}
}
Future<bool> reSendOtp() async {
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;
}
}
@ -302,16 +282,13 @@ 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) {
@ -338,6 +315,7 @@ class AuthCubit extends Cubit<AuthState> {
}
}
sendToForgetPassword({required String password}) async {
try {
emit(AuthForgetPassLoading());
@ -347,4 +325,8 @@ class AuthCubit extends Cubit<AuthState> {
emit(AuthForgetPassError(message: 'Something went wrong'));
}
}
}

View File

@ -8,7 +8,6 @@ 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';
@ -41,19 +40,13 @@ 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;
@ -82,8 +75,7 @@ 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);
@ -123,8 +115,7 @@ 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) {
@ -208,10 +199,7 @@ 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,
@ -219,10 +207,7 @@ 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,
@ -230,10 +215,7 @@ 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,
@ -257,8 +239,7 @@ 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;
@ -281,27 +262,18 @@ 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,
@ -323,12 +295,10 @@ 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,
),
),
@ -337,8 +307,7 @@ 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();
}
},
@ -352,12 +321,10 @@ 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,
),
),
@ -374,20 +341,8 @@ class _OtpViewState extends State<OtpView> {
return;
}
if ((state is! AuthLoading)) {
bool success = await AuthCubit.get(context)
.reSendOtp();
await AuthCubit.get(context).reSendOtp();
FocusScope.of(context).unfocus();
if(success){
showDialog(
context: context,
builder: (_) => SuccessDialog(
key: ValueKey('SuccessDialog'),
message: 'New OTP sent!',));
}
Future.delayed(Duration(seconds: 2),
() {
Navigator.of(context).pop();
});
}
},
),

View File

@ -105,8 +105,8 @@ class SignUpView extends StatelessWidget {
autocorrect: false,
autofillHints: const [AutofillHints.name],
// controller: AuthCubit.get(context).fullNameController,
validator: (value) => AuthCubit.get(context)
.fullNameValidator(value),
validator: (value) =>
AuthCubit.get(context).fullNameValidator(value),
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
@ -114,11 +114,7 @@ class SignUpView extends StatelessWidget {
AuthCubit.get(context).fullName = value;
},
onTap: () {},
decoration: defaultInputDecoration(context,
hint: "Full Name")
.copyWith(
errorMaxLines: 2,
),
decoration: defaultInputDecoration(context, hint: "Full Name"),
),
const SizedBox(height: 16),
const BodyMedium(
@ -133,16 +129,15 @@ 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(
@ -155,25 +150,17 @@ 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")
.copyWith(
errorMaxLines: 8,
),
hint: "At least 8 characters"),
),
const SizedBox(height: 16),
const BodyMedium(
@ -187,17 +174,13 @@ 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"),
),
@ -210,12 +193,10 @@ 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,
),
),
@ -223,14 +204,11 @@ class SignUpView extends StatelessWidget {
'Sign up',
),
onPressed: () {
AuthCubit.get(context)
.showValidationMessage = true;
if (formKey.currentState!
.validate()) {
AuthCubit.get(context).showValidationMessage = true;
if (formKey.currentState!.validate()) {
if ((state is! AuthLoading)) {
AuthCubit.get(context).signUp();
FocusScope.of(context)
.unfocus();
FocusScope.of(context).unfocus();
}
}
},

View File

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

View File

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

View File

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

View File

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

View File

@ -1,326 +0,0 @@
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/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/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<ThreeGangSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleChange);
on<DeleteScheduleEvent>(deleteSchedule);
}
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(ThreeGangSave event, Emitter<OneGangState> emit,) async {
try {
if(selectedDays.isNotEmpty) {
emit(LoadingInitialState());
final response = await DevicesAPI.postSchedule(
category: switchCode,
deviceId: oneGangId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(ThreeGangSaveSchedule());
toggleCreateSchedule();
}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() {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime=DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
emit(ChangeSlidingSegmentState(value: 1));
}
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(ChangeSlidingSegment(value: 1));
}
int selectedTabIndex = 0;
void toggleSelectedIndex(index) {
emit(LoadingInitialState());
selectedTabIndex = index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
}

View File

@ -1,116 +0,0 @@
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 {}
//------------------- Schedule ----------=---------
class GetScheduleEvent extends OneGangEvent {}
class ThreeGangSave 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];
}

View File

@ -1,89 +0,0 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/groupTwoGangModel.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<GroupTwoGangModel> twoGangList;
final bool allSwitches;
const UpdateGroupState({required this.twoGangList, required this.allSwitches});
@override
List<Object> get props => [twoGangList, 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 ThreeGangSaveSchedule extends OneGangState {}
class IsToggleState extends OneGangState {
final bool? onOff;
const IsToggleState({this.onOff});
}
class ChangeTimeState extends OneGangState {}
class UpdateCreateScheduleState extends OneGangState {
final bool createSchedule;
UpdateCreateScheduleState(this.createSchedule);
}

View File

@ -54,7 +54,6 @@ 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 = [];
@ -129,7 +128,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
_doorLockUpdated(DoorLockUpdated event, Emitter<SmartDoorState> emit) {
unlockRequest = deviceStatus.unlockRequest;
emit(UpdateState(smartDoorModel: deviceStatus));
}

View File

@ -1,5 +1,4 @@
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';
@ -8,16 +7,12 @@ 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,
@ -35,7 +30,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
List<GroupThreeGangModel> groupThreeGangList = [];
bool allSwitchesOn = true;
ThreeGangBloc({required this.threeGangId,required this.switchCode}) : super(InitialState()) {
ThreeGangBloc({required this.threeGangId}) : super(InitialState()) {
on<InitialEvent>(_fetchThreeGangStatus);
on<ThreeGangUpdated>(_threeGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -50,14 +45,6 @@ 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);
}
void _fetchThreeGangStatus(InitialEvent event, Emitter<ThreeGangState> emit) async {
@ -203,6 +190,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
@ -472,6 +460,9 @@ 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) {
@ -489,143 +480,4 @@ 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());
final response = 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());
toggleCreateSchedule();
}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 toggleCreateSchedule() {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime=DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
emit(ChangeSlidingSegmentState(value: 1));
}
int selectedTabIndex = 0;
void toggleSelectedIndex(index) {
emit(LoadingInitialState());
selectedTabIndex = index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
List<ScheduleModel> listSchedule = [];
DateTime? selectedTime=DateTime.now();
}

View File

@ -93,29 +93,3 @@ 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];
}

View File

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

View File

@ -1,553 +0,0 @@
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/groupTwoGangModel.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);
}
DateTime? selectedTime = DateTime.now();
void toggleCreateSchedule() {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime=DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
emit(ChangeSlidingSegmentState(value: 1));
}
int selectedTabIndex = 0;
void toggleSelectedIndex(index) {
emit(LoadingInitialState());
selectedTabIndex = index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void _fetchTwoGangStatus(InitialEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState());
try {
twoGangGroup = event.groupScreen;
if (twoGangGroup) {
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));
} else {
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: twoGangGroup ? event.deviceId : twoGangId,
code: 'switch_1',
value: !event.value),
twoGangGroup ? event.deviceId : twoGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: twoGangGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: twoGangGroup));
}
}
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: twoGangGroup ? event.deviceId : twoGangId,
code: 'switch_2',
value: !event.value),
twoGangGroup ? event.deviceId : twoGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: twoGangGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: twoGangGroup));
}
}
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(groupScreen: false));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
}
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(groupScreen: false));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
}
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));
for (int i = 0; i < groupTwoGangList.length; i++) {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupTwoGangList[i].deviceId,
code: 'switch_1',
value: true),
groupTwoGangList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupTwoGangList[i].deviceId,
code: 'switch_2',
value: true),
groupTwoGangList[i].deviceId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
break;
}
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
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));
for (int i = 0; i < groupTwoGangList.length; i++) {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupTwoGangList[i].deviceId,
code: 'switch_1',
value: false),
groupTwoGangList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupTwoGangList[i].deviceId,
code: 'switch_2',
value: false),
groupTwoGangList[i].deviceId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
break;
}
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
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(ChangeSlidingSegment(value: 1));
}
Future<void> saveSchedule(TwoGangSave event, Emitter<TwoGangState> emit,) async {
try {
if(selectedDays.isNotEmpty) {
emit(LoadingInitialState());
final response = 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());
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()));
}
}
}

View File

@ -1,130 +0,0 @@
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 {
final bool groupScreen;
const InitialEvent({required this.groupScreen});
@override
List<Object> get props => [groupScreen];
}
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});
}

View File

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

View File

@ -58,10 +58,6 @@ 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 {
tempIcon = Assets.assetsIconsLogo;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,73 +1,114 @@
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';
part of "curtain_view.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: [
_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),
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,
),
),
)
],
),
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: onTap,
child: const SizedBox.square(dimension: 60),
onTap: () {
DevicesCubit.get(context).pauseCurtain();
},
child: Image.asset(
Assets.assetsImagesPause,
width: 60,
height: 60,
),
),
),
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),
),
Stack(
alignment: Alignment.center,
children: [
DecoratedBox(
decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(3, 3),
),
]),
child: const SizedBox.square(
dimension: 60,
),
// InkWell(
// overlayColor: MaterialStateProperty.all(Colors.transparent),
// onTap: () {
// DevicesCubit.get(context).closeCurtain(curtain.productType!);
// },
// child: SvgPicture.asset(
// Assets.assetsIconsCurtainsIconCloseCurtain,
// width: 60,
// height: 60,
// ),
// ),
),
Padding(
padding: const EdgeInsets.only(right: 5, bottom: 5),
child: InkWell(
overlayColor: MaterialStateProperty.all(Colors.transparent),
onTap: () {
DevicesCubit.get(context).closeCurtain(curtain.productType!);
},
child: SvgPicture.asset(
Assets.assetsIconsCurtainsIconCloseCurtain,
width: 110,
height: 110,
),
),
)
],
),
],
);

View File

@ -1,99 +1,86 @@
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/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/bloc/devices_cubit.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) => 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,
),
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,
),
),
),
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,
),
),
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,
),
);
},
),
),
);
},
),
),
),
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,
),
],
),
),
),
);
}

View File

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

View File

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

View File

@ -1,171 +0,0 @@
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: [
const SizedBox(
width: 20,
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen(
switchCode:'switch_1' ,
device: device!,
deviceCode: 'countdown_1',
)));
},
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(100),
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: Icon(
Icons.access_time,
color:
ColorsManager.primaryColorWithOpacity,
size: 25,
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "Timer",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
],
),
),
Expanded(child: SizedBox())
],
),
),
],
),
);
},
),
);
}
}

View File

@ -1,258 +0,0 @@
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(ThreeGangSave());
},
child: const Text('Save')
) :
oneGangBloc.selectedTabIndex==1? IconButton(
onPressed: () {
oneGangBloc.toggleCreateSchedule();
},
icon: const Icon(Icons.add),
):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.toggleSelectedIndex(0);
}else{
oneGangBloc.toggleSelectedIndex(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(
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)),
],
),
),
),
Column(
mainAxisAlignment:oneGangBloc.listSchedule.isNotEmpty?
MainAxisAlignment.start:MainAxisAlignment.center,
children: [
SizedBox(
child: oneGangBloc.createSchedule == true ?
CreateSchedule(
onToggleChanged: (bool isOn) {
oneGangBloc.toggleSchedule = isOn;
},
onDateTimeChanged: (DateTime dateTime) {
oneGangBloc.selectedTime=dateTime;
},
days: oneGangBloc.days,
selectDays: (List<String> selectedDays) {
oneGangBloc.selectedDays = selectedDays;
},
)
:
Padding(
padding: const EdgeInsets.only(top: 10),
child: ScheduleListView(
listSchedule: oneGangBloc.listSchedule, // Pass the schedule list here
onDismissed: (scheduleId) {
oneGangBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId);
oneGangBloc.add(DeleteScheduleEvent(id: scheduleId));
},
onToggleSchedule: (scheduleId, isEnabled) {
oneGangBloc.add(ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
),
),
],
),
],
),
),
],
),
))
);
},
),
),
);
}
String _formatDuration(int seconds) {
final hours = (seconds ~/ 3600).toString().padLeft(2, '0');
final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0');
final secs = (seconds % 60).toString().padLeft(2, '0');
return '$hours:$minutes:$secs';
}
}

View File

@ -8,13 +8,8 @@ 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/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/one_gang/one_gang_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_screen.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';
@ -107,11 +102,6 @@ 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;
@ -130,24 +120,13 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
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);
break;
default:
}

View File

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

View File

@ -31,36 +31,47 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
value: context.read<SmartDoorBloc>().unlockRequest > 0 ? 1 : 0,
duration: Duration(seconds: context.read<SmartDoorBloc>().unlockRequest),
value: smartDoorModel.unlockRequest > 0 ? 1 : 0,
duration: Duration(seconds: smartDoorModel.unlockRequest),
);
if (context.read<SmartDoorBloc>().unlockRequest > 0) {
if (smartDoorModel.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();
@ -89,7 +100,7 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
// } else if (_animationController.status == AnimationStatus.reverse) {
// _animationController.forward();
// }
if (context.read<SmartDoorBloc>().unlockRequest > 0) {
if (smartDoorModel.unlockRequest > 0) {
BlocProvider.of<SmartDoorBloc>(context)
.add(UpdateLockEvent(value: smartDoorModel.normalOpenSwitch));
}

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
// import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
// import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/two_gang_bloc.dart';
// import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/two_gang_state.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/model/device_model.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';

View File

@ -63,8 +63,7 @@ class ScheduleScreen extends StatelessWidget {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen(
switchCode :"switch_1",
pageBuilder: (context, animation1, animation2) => TimerScreen(
device: device,
deviceCode: 'countdown_1',
)));
@ -100,11 +99,10 @@ class ScheduleScreen extends StatelessWidget {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen(
switchCode :"switch_2",
device: device,
deviceCode: 'countdown_2',
)));
pageBuilder: (context, animation1, animation2) => TimerScreen(
device: device,
deviceCode: 'countdown_2',
)));
},
child: Container(
padding:
@ -137,9 +135,8 @@ class ScheduleScreen extends StatelessWidget {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen(
switchCode :"switch_3",
device: device,
pageBuilder: (context, animation1, animation2) => TimerScreen(
device: device,
deviceCode: 'countdown_3',
)));
},

View File

@ -22,9 +22,7 @@ class ThreeGangScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => ThreeGangBloc(
switchCode: '',
threeGangId: device?.uuid ?? '')
create: (context) => ThreeGangBloc(threeGangId: device?.uuid ?? '')
..add(InitialEvent(groupScreen: device != null ? false : true)),
child: BlocBuilder<ThreeGangBloc, ThreeGangState>(
builder: (context, state) {

View File

@ -7,10 +7,7 @@ import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_blo
import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_event.dart';
import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_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_container.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';
@ -18,17 +15,10 @@ 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 {
class TimerScreen extends StatelessWidget {
final DeviceModel device;
final String deviceCode;
final String switchCode;
const TimerScheduleScreen(
{required this.device,
required this.deviceCode,
required this.switchCode,
super.key});
const TimerScreen({required this.device, required this.deviceCode, super.key});
@override
Widget build(BuildContext context) {
@ -37,217 +27,150 @@ class TimerScheduleScreen extends StatelessWidget {
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: BlocProvider(
create: (context) =>
ThreeGangBloc(switchCode: switchCode, threeGangId: device.uuid ?? '')
..add(GetCounterEvent(deviceCode: deviceCode))
..add(GetScheduleEvent()),
child: BlocBuilder<ThreeGangBloc, ThreeGangState>(
builder: (context, state) {
final threeGangBloc = BlocProvider.of<ThreeGangBloc>(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) {
threeGangBloc.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: [
threeGangBloc.createSchedule == true ?
TextButton(
onPressed: () {
threeGangBloc.add(ThreeGangSave());
},
child: const Text('Save')
) :
threeGangBloc.selectedTabIndex==1? IconButton(
onPressed: () {
threeGangBloc.toggleCreateSchedule();
},
icon: const Icon(Icons.add),
):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(threeGangBloc.createSchedule == true){
threeGangBloc.toggleCreateSchedule();
}
threeGangBloc.toggleSelectedIndex(0);
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Schedule',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: SafeArea(
child: BlocProvider(
create: (context) => ThreeGangBloc(threeGangId: device.uuid ?? '')
..add(GetCounterEvent(deviceCode: deviceCode)),
child: BlocBuilder<ThreeGangBloc, ThreeGangState>(
builder: (context, state) {
Duration duration = Duration.zero;
int countNum = 0;
int tabNum = 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;
}
}else{
threeGangBloc.toggleSelectedIndex(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,
),
),
),
),
],
if (state is ChangeSlidingSegmentState) {
tabNum = state.value;
}
return PopScope(
canPop: false,
onPopInvoked: (didPop) {
if (!didPop) {
BlocProvider.of<ThreeGangBloc>(context).add(OnClose());
Navigator.pop(context);
}
},
child: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
padding: const EdgeInsets.all(24),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.assetsImagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
Expanded(
child: TabBarView(
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;
},
),
child: state is LoadingInitialState || state is LoadingNewSate
? const Center(
child: DefaultContainer(
width: 50, height: 50, child: CircularProgressIndicator()),
)
: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: MediaQuery.sizeOf(context).width,
decoration: const ShapeDecoration(
color: ColorsManager.slidingBlueColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
),
),
child: CupertinoSlidingSegmentedControl<int>(
thumbColor: ColorsManager.slidingBlueColor,
onValueChanged: (value) {
BlocProvider.of<ThreeGangBloc>(context)
.add(ChangeSlidingSegment(value: value ?? 0));
},
groupValue:
state is ChangeSlidingSegmentState ? state.value : 0,
backgroundColor: Colors.white,
children: <int, Widget>{
0: Container(
padding: const EdgeInsets.symmetric(vertical: 10),
child: BodySmall(
text: 'Countdown',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
GestureDetector(
onTap: () {
if (state is LoadingNewSate) {
return;
}
if (countNum > 0) {
threeGangBloc.add(SetCounterValue(
1: Container(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text(
'Schedule',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
},
),
),
if (tabNum == 0)
countNum > 0
? BodyLarge(
text: _formatDuration(countNum),
fontColor: ColorsManager.slidingBlueColor,
fontSize: 40,
)
: CupertinoTimerPicker(
mode: CupertinoTimerPickerMode.hm,
onTimerDurationChanged: (Duration newDuration) {
duration = newDuration;
},
),
if (tabNum == 0)
GestureDetector(
onTap: () {
if (state is LoadingNewSate) {
return;
}
if (countNum > 0) {
BlocProvider.of<ThreeGangBloc>(context).add(
SetCounterValue(
deviceCode: deviceCode,
duration: Duration.zero));
} else if (duration != Duration.zero) {
threeGangBloc.add(SetCounterValue(
deviceCode: deviceCode,
duration: duration));
}
},
child: SvgPicture.asset(countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
),
),
),
Column(
mainAxisAlignment:threeGangBloc.listSchedule.isNotEmpty?
MainAxisAlignment.start:MainAxisAlignment.center,
children: [
SizedBox(
child: threeGangBloc.createSchedule == true ?
CreateSchedule(
onToggleChanged: (bool isOn) {
threeGangBloc.toggleSchedule = isOn;
} else if (duration != Duration.zero) {
BlocProvider.of<ThreeGangBloc>(context).add(
SetCounterValue(
deviceCode: deviceCode, duration: duration));
}
},
onDateTimeChanged: (DateTime dateTime) {
threeGangBloc.selectedTime=dateTime;
},
days: threeGangBloc.days,
selectDays: (List<String> selectedDays) {
threeGangBloc.selectedDays = selectedDays;
},
)
:
Padding(
padding: const EdgeInsets.only(top: 10),
child: ScheduleListView(
listSchedule: threeGangBloc.listSchedule, // Pass the schedule list here
onDismissed: (scheduleId) {
threeGangBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId);
threeGangBloc.add(DeleteScheduleEvent(id: scheduleId));
},
onToggleSchedule: (scheduleId, isEnabled) {
threeGangBloc.add(ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
),
),
],
),
],
),
),
],
),
))
);
},
child: SvgPicture.asset(
countNum > 0 ? Assets.pauseIcon : Assets.playIcon))
],
)));
},
),
),
),
),
);

View File

@ -1,67 +0,0 @@
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/two_gang/two_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 TwoGangInterface extends StatelessWidget {
const TwoGangInterface({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: TwoGangScreen(device: gangSwitch),
),
),
),
),
);
}
}

View File

@ -1,81 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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_event.dart';
import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_state.dart';
import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart';
import 'package:syncrow_app/features/devices/model/group_three_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 TwoGangList extends StatelessWidget {
const TwoGangList({super.key, required this.twoGangList, required this.allSwitches});
final List<GroupTwoGangModel> twoGangList;
final bool allSwitches;
@override
Widget build(BuildContext context) {
return BlocBuilder<ThreeGangBloc, ThreeGangState>(
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<ThreeGangBloc>(context).add(GroupAllOnEvent());
},
secondAction: () {
BlocProvider.of<ThreeGangBloc>(context).add(GroupAllOffEvent());
},
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0),
itemCount: twoGangList.length,
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
BodySmall(text: '${twoGangList[index].deviceName} beside light'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
switchValue: twoGangList[index].firstSwitch,
action: () {
BlocProvider.of<ThreeGangBloc>(context).add(ChangeFirstSwitchStatusEvent(
value: twoGangList[index].firstSwitch,
deviceId: twoGangList[index].deviceId));
},
),
const SizedBox(height: 10),
BodySmall(text: '${twoGangList[index].deviceName} ceiling light'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
switchValue: twoGangList[index].secondSwitch,
action: () {
BlocProvider.of<ThreeGangBloc>(context).add(ChangeSecondSwitchStatusEvent(
value: twoGangList[index].secondSwitch,
deviceId: twoGangList[index].deviceId));
},
),
const SizedBox(height: 10),
BodySmall(text: '${twoGangList[index].deviceName} spotlight'),
const SizedBox(height: 5),
],
);
},
),
],
),
);
},
);
}
}

View File

@ -1,339 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_bloc.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_model.dart';
import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart';
import 'package:syncrow_app/features/devices/model/two_gang_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_list.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_schedule_screen.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';
class TwoGangScreen extends StatelessWidget {
const TwoGangScreen({super.key, this.device, this.switchCode});
final DeviceModel? device;
final String? switchCode;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => TwoGangBloc(
switchCode: switchCode??'',
twoGangId: device?.uuid ?? '')
..add(InitialEvent(groupScreen: device != null ? false : true)),
child: BlocBuilder<TwoGangBloc, TwoGangState>(
builder: (context, state) {
TwoGangModel twoGangModel = TwoGangModel(
firstSwitch: false,
secondSwitch: false,
firstCountDown: 0,
secondCountDown: 0,
);
List<GroupTwoGangModel> groupTwoGangModel = [];
bool allSwitchesOn = false;
if (state is LoadingNewSate) {
twoGangModel = state.twoGangModel;
} else if (state is UpdateState) {
twoGangModel = state.twoGangModel;
} else if (state is UpdateGroupState) {
groupTwoGangModel = state.twoGangList;
allSwitchesOn = state.allSwitches;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),)
: device == null
? TwoGangList(
twoGangList: groupTwoGangModel,
allSwitches: allSwitchesOn,
)
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<TwoGangBloc>(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: twoGangModel.firstSwitch,
action: () {
BlocProvider.of<TwoGangBloc>(context).add(
ChangeFirstSwitchStatusEvent(
value: twoGangModel.firstSwitch));
},
),
const SizedBox(height: 20),
const SizedBox(
width: 77,
child: BodySmall(
text: "Cove Light",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
Column(
children: [
GangSwitch(
threeGangSwitch: device!,
value: twoGangModel.secondSwitch,
action: () {
BlocProvider.of<TwoGangBloc>(context).add(
ChangeSecondSwitchStatusEvent(
value: twoGangModel.secondSwitch));
},
),
const SizedBox(height: 20),
const SizedBox(
width: 77,
child: BodySmall(
text: "Chandelier",
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: () {
BlocProvider.of<TwoGangBloc>(context)
.add(AllOnEvent());
},
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: BodySmall(
text: "On",
style: context.bodyMedium.copyWith(
color: ColorsManager
.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "All On",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
const SizedBox(
width: 20,
),
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) =>
TwoGangScheduleScreen(
device: device!,
)));
},
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,
),
),
],
),
const SizedBox(
width: 20,
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: GestureDetector(
onTap: () {
// DevicesCubit.getInstance().deviceControl(
// DeviceControlModel(
// deviceId: device.uuid,
// code: 'switch_1',
// value: false,
// ),
// device.uuid!,
// );
// DevicesCubit.getInstance().deviceControl(
// DeviceControlModel(
// deviceId: device.uuid,
// code: 'switch_2',
// value: false,
// ),
// device.uuid!,
// );
// DevicesCubit.getInstance().deviceControl(
// DeviceControlModel(
// deviceId: device.uuid,
// code: 'switch_3',
// value: false,
// ),
// device.uuid!,
// );
BlocProvider.of<TwoGangBloc>(context)
.add(AllOffEvent());
},
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: BodySmall(
text: "Off",
style: context.bodyMedium.copyWith(
color: ColorsManager
.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "All Off",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
],
),
),
Expanded(child: SizedBox())
],
),
),
],
),
);
},
),
);
}
}

View File

@ -1,141 +0,0 @@
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/two_gang/two_timer_screen.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.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 TwoGangScheduleScreen extends StatelessWidget {
final DeviceModel device;
const TwoGangScheduleScreen({required this.device, super.key});
@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: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Schedule',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: SafeArea(
child: 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: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 48,
),
DefaultContainer(
width: MediaQuery.sizeOf(context).width,
child: Column(
children: [
InkWell(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen(
device: device,
deviceCode: 'countdown_1',
switchCode:'switch_1' ,
)));
},
child: Container(
padding:
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Cove Light",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
fontSize: 15,
fontWeight: FontWeight.w400,
),
),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 18,
)
],
),
),
),
const Divider(
color: ColorsManager.dividerColor,
),
InkWell(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen(
device: device,
deviceCode: 'countdown_2',
switchCode:'switch_2' ,
)));
},
child: Container(
padding:
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Chandelier",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
fontSize: 15,
fontWeight: FontWeight.w400,
),
),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 18,
)
],
),
),
),
],
)),
],
),
),
),
));
}
}

View File

@ -1,259 +0,0 @@
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/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_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';
import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_event.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) =>
TwoGangBloc(switchCode: switchCode, twoGangId: device.uuid ?? '')
..add(GetCounterEvent(deviceCode: deviceCode))
..add(GetScheduleEvent()),
child: BlocBuilder<TwoGangBloc, TwoGangState>(
builder: (context, state) {
final twoGangBloc = BlocProvider.of<TwoGangBloc>(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) {
twoGangBloc.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: [
twoGangBloc.createSchedule == true ?
TextButton(
onPressed: () {
twoGangBloc.add(TwoGangSave());
},
child: const Text('Save')
) :
twoGangBloc.selectedTabIndex==1? IconButton(
onPressed: () {
twoGangBloc.toggleCreateSchedule();
},
icon: const Icon(Icons.add),
):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) {
print(value);
if(value==0){
if(twoGangBloc.createSchedule == true){
twoGangBloc.toggleCreateSchedule();
}
twoGangBloc.toggleSelectedIndex(0);
}else{
twoGangBloc.toggleSelectedIndex(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(
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) {
twoGangBloc.add(SetCounterValue(
deviceCode: deviceCode,
duration: Duration.zero));
} else if (duration != Duration.zero) {
twoGangBloc.add(SetCounterValue(
deviceCode: deviceCode,
duration: duration));
}
},
child: SvgPicture.asset(countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
),
),
),
Column(
mainAxisAlignment:twoGangBloc.listSchedule.isNotEmpty?
MainAxisAlignment.start:MainAxisAlignment.center,
children: [
SizedBox(
child: twoGangBloc.createSchedule == true ?
CreateSchedule(
onToggleChanged: (bool isOn) {
twoGangBloc.toggleSchedule = isOn;
},
onDateTimeChanged: (DateTime dateTime) {
twoGangBloc.selectedTime=dateTime;
},
days: twoGangBloc.days,
selectDays: (List<String> selectedDays) {
twoGangBloc.selectedDays = selectedDays;
},
)
:
Padding(
padding: const EdgeInsets.only(top: 10),
child: ScheduleListView(
listSchedule: twoGangBloc.listSchedule, // Pass the schedule list here
onDismissed: (scheduleId) {
twoGangBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId);
twoGangBloc.add(DeleteScheduleEvent(id: scheduleId));
},
onToggleSchedule: (scheduleId, isEnabled) {
twoGangBloc.add(ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
),
),
],
),
],
),
),
],
),
))
);
},
),
),
);
}
String _formatDuration(int seconds) {
final hours = (seconds ~/ 3600).toString().padLeft(2, '0');
final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0');
final secs = (seconds % 60).toString().padLeft(2, '0');
return '$hours:$minutes:$secs';
}
}

View File

@ -1,139 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class CreateSchedule extends StatefulWidget {
final List<Map<String, String>> days;
final void Function(List<String> selectedDays)? selectDays; // Callback for selected days
final Function(DateTime) onDateTimeChanged;
final void Function(bool isOn)? onToggleChanged; // Callback for toggle state
const CreateSchedule({
Key? key,
required this.days,
required this.selectDays,
required this.onDateTimeChanged,
this.onToggleChanged, // Optional callback
}) : super(key: key);
@override
_CreateScheduleState createState() => _CreateScheduleState();
}
class _CreateScheduleState extends State<CreateSchedule> {
List<String> selectedDays = []; // List of selected days
bool isOn = true; // Boolean state for the ON/OFF toggle
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
child: Column(
children: <Widget>[
const Divider(
color: ColorsManager.greyColor,
),
SizedBox(
height: 110,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.time,
initialDateTime: DateTime.now(),
onDateTimeChanged: widget.onDateTimeChanged,
),
),
const Divider(
color: ColorsManager.greyColor,
),
const SizedBox(height: 20),
SizedBox(
height: MediaQuery.of(context).size.height * 0.08,
child: ListView(
scrollDirection: Axis.horizontal,
children: widget.days.map((day) {
bool isSelected = selectedDays.contains(day['day']); // Check if day is selected
return Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () {
setState(() {
if (isSelected) {
selectedDays.remove(day['day']); // Deselect day
} else {
selectedDays.add(day['day']!); // Select day
}
if (widget.selectDays != null) {
widget.selectDays!(selectedDays);
}
});
},
child: Container(
width: 50,
padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 8),
decoration: BoxDecoration(
border: Border.all(
color: isSelected
? Colors.black
: ColorsManager.grayColor,
),
color: Colors.transparent,
borderRadius: BorderRadius.circular(30),
),
child: Center(
child: Text(
day['day']!,
style: TextStyle(
fontSize: 13,
color: isSelected
? Colors.black
: ColorsManager.grayColor,
),
),
),
),
),
);
}).toList(),
),
),
const SizedBox(height: 20),
InkWell(
onTap: () {
setState(() {
isOn = !isOn; // Toggle the state
if (widget.onToggleChanged != null) {
widget.onToggleChanged!(isOn); // Pass the new toggle state
}
});
},
child: DefaultContainer(
height: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
isOn ? 'ON' : 'OFF', // Change text based on state
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
CircleAvatar(
backgroundColor: isOn
? ColorsManager.secondaryColor.withOpacity(0.6)
: Colors.red.withOpacity(0.6), // Change background color based on state
child: const Icon(
Icons.power_settings_new,
color: ColorsManager.onPrimaryColor, // Change icon color
),
),
],
),
),
),
],
),
);
}
}

View File

@ -1,51 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
class EmptySchedule extends StatelessWidget {
const EmptySchedule({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 180,
width: 180,
child: Center(child: Column(
children: [
Center(
child: SvgPicture.asset(
height: 100,
width: 100,
Assets.emptySchedule),
),
Column(
children: [
Center(
child: Text(
'Please add',
style: context.displaySmall
.copyWith(
color: const Color(
0XFFD5D5D5),
),
),
),
Center(
child: Text(
'a new schedule',
style: context.displaySmall
.copyWith(
color: const Color(
0XFFD5D5D5),
),
),
),
],
),
],
),),
);
}
}

View File

@ -1,120 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/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 'empty_schedule.dart'; // for SVG icons
class ScheduleListView extends StatelessWidget {
final List<ScheduleModel> listSchedule;
final Function(String) onDismissed;
final Function(String, bool) onToggleSchedule;
const ScheduleListView({
Key? key,
required this.listSchedule,
required this.onDismissed,
required this.onToggleSchedule,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: listSchedule.isNotEmpty
? SizedBox(
child: ListView.builder(
shrinkWrap: true,
itemCount: listSchedule.length,
itemBuilder: (context, index) {
return Dismissible(
key: Key(listSchedule[index].scheduleId),
background: Container(
padding: const EdgeInsets.only(right: 10),
alignment: AlignmentDirectional.centerEnd,
decoration: const ShapeDecoration(
color: Color(0xFFFF0000),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
),
),
child: Padding(
padding: const EdgeInsets.only(bottom: 10, right: 10),
child: SvgPicture.asset(
Assets.assetsDeleteIcon,
width: 20,
height: 22,
),
),
),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
onDismissed(listSchedule[index].scheduleId);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Schedule removed')),
);
},
child: InkWell(
onTap: () {
},
child: DefaultContainer(
padding: const EdgeInsets.all(20),
height: MediaQuery.of(context).size.height / 6.4,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
BodyLarge(
text: listSchedule[index].time,
fontWeight: FontWeight.w500,
fontColor: Colors.black,
fontSize: 22,
),
Text(listSchedule[index].days.join(' ')),
Text('Function ${listSchedule[index].function.value ? "ON" : "OFF"}'),
],
),
),
Expanded(
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyMedium(
text: '',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: listSchedule[index].enable,
onChanged: (value) {
onToggleSchedule(
listSchedule[index].scheduleId,
value,
);
},
applyTheme: true,
),
),
),
),
],
),
),
),
);
},
),
)
: const EmptySchedule()
);
}
}

View File

@ -1,45 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class SuccessDialog extends StatelessWidget {
final double dialogWidth;
final String message;
const SuccessDialog(
{super.key, this.dialogWidth = 160, required this.message});
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: Container(
width: dialogWidth,
height: 120,
decoration: BoxDecoration(
color: ColorsManager.blackColor.withOpacity(0.7),
borderRadius: BorderRadius.circular(15),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
Assets.assetsSuccessWhite,
width: 50,
height: 50,
),
const SizedBox(height: 20),
BodySmall(
text: message,
fontColor: ColorsManager.onPrimaryColor,
fontSize: FontSize.s16),
],
),
),
);
}
}

View File

@ -733,10 +733,6 @@ class Assets {
static const String playIcon = "assets/icons/play_ic.svg";
static const String gatewayIcon = "assets/icons/gateway_icon.svg";
//assets/icons/success-white.svg
//assets for success white image
static const String assetsSuccessWhite ="assets/icons/success-white.svg";
/// Assets for assetsImagesAutomation
/// assets/images/automation.jpg
static const String assetsImagesAutomation = "assets/images/automation.jpg";
@ -1033,12 +1029,4 @@ class Assets {
static const String assetsPresenceState =
"assets/icons/functions_icons/automation_functions/presence_state.svg";
//assets/icons/functions_icons/automation_functions/presence_state.svg
static const String oneGang = "assets/icons/1gang.svg";
static const String twoGang = "assets/icons/2gang.svg";
static const String emptySchedule = "assets/icons/emptySchedule.svg";
}

View File

@ -7,7 +7,9 @@ import 'package:syncrow_app/firebase_options.dart';
import 'package:syncrow_app/services/locator.dart';
import 'package:syncrow_app/utils/bloc_observer.dart';
import 'package:syncrow_app/utils/helpers/localization_helpers.dart';
import 'my_app.dart';
void main() {
//to observe the state of the blocs in the output console
Bloc.observer = MyBlocObserver();

View File

@ -175,12 +175,4 @@ abstract class ApiEndpoints {
//multiple-time offline
static const String deleteTemporaryPassword =
'/door-lock/temporary-password/online/{doorLockUuid}/{passwordId}';
static const String saveSchedule = '/schedule/{deviceUuid}';
static const String getSchedule = '/schedule/{deviceUuid}?category={category}';
static const String changeSchedule = '/schedule/enable/{deviceUuid}';
static const String deleteSchedule = '/schedule/{deviceUuid}/{scheduleId}';
}

View File

@ -1,11 +1,11 @@
import 'dart:async';
import 'dart:convert';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/function_model.dart';
import 'package:syncrow_app/services/api/api_links_endpoints.dart';
import 'package:syncrow_app/services/api/http_service.dart';
import '../../features/devices/model/create_temporary_password_model.dart';
class DevicesAPI {
@ -32,7 +32,6 @@ class DevicesAPI {
static Future<Map<String, dynamic>> controlDevice(
DeviceControlModel controlModel, String deviceId) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.controlDevice.replaceAll('{deviceUuid}', deviceId),
body: controlModel.toJson(),
@ -214,6 +213,7 @@ class DevicesAPI {
"effectiveTime": effectiveTime,
"invalidTime": invalidTime,
};
print('createPassword =$body');
if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
}
@ -270,87 +270,4 @@ class DevicesAPI {
);
return response;
}
static Future<Map<String, dynamic>> postSchedule({
required String category,
required String deviceId,
required String time,
required String code,
required bool value,
required List<String> days,
}) async {
print( {
"category": category,
"time": time,
"function":{
"code": code,
"value":value,
},
"days": days
});
final response = await _httpService.post(
path: ApiEndpoints.saveSchedule.replaceAll('{deviceUuid}', deviceId),
showServerMessage: false,
body:
jsonEncode({
"category": category,
"time": time,
"function":{
"code": code,
"value":value,
},
"days": days
},),
expectedResponseModel: (json) {
return json;
},
);
return response;
}
static Future getSchedule({
required String category,
required String deviceId,
}) async {
final response = await _httpService.get(
path: ApiEndpoints.getSchedule.replaceAll('{deviceUuid}', deviceId).replaceAll('{category}', category),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
}
static Future<bool> changeSchedule({
required String deviceUuid,
required String scheduleId,
required bool enable,
}) async {
final response = await _httpService.put(
path: ApiEndpoints.changeSchedule.replaceAll('{deviceUuid}', deviceUuid),
body: {
"scheduleId": scheduleId,
"enable": enable
},
expectedResponseModel: (json) {
return json['success'];
},
);
return response;
}
static Future deleteSchedule({
required String deviceUuid,
required String scheduleId,
}) async {
final response = await _httpService.delete(
path: ApiEndpoints.deleteSchedule.replaceAll('{deviceUuid}', deviceUuid).replaceAll('{scheduleId}', scheduleId),
expectedResponseModel: (json) {
return json;
},
);
return response;
}
}

View File

@ -43,8 +43,6 @@ enum DeviceType {
DoorLock,
Curtain,
Blind,
OneGang,
TwoGang,
ThreeGang,
Gateway,
CeilingSensor,
@ -70,9 +68,6 @@ Map<String, DeviceType> devicesTypesMap = {
"DL": DeviceType.DoorLock,
"WPS": DeviceType.WallSensor,
"3G": DeviceType.ThreeGang,
"2G": DeviceType.TwoGang,
"1G": DeviceType.OneGang,
"CUR": DeviceType.Curtain,
};
Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
DeviceType.AC: [
@ -159,33 +154,6 @@ Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
FunctionModel(
code: 'indicator', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})),
],
DeviceType.OneGang:[
FunctionModel(
code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})),
FunctionModel(
code: 'countdown_1',
type: functionTypesMap['Integer'],
values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
],
DeviceType.TwoGang:[
FunctionModel(
code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})
),
FunctionModel(
code: 'switch_2', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})
),
FunctionModel(
code: 'countdown_1',
type: functionTypesMap['Integer'],
values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})
),
FunctionModel(
code: 'countdown_2',
type: functionTypesMap['Integer'],
values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})
),
],
DeviceType.ThreeGang: [
FunctionModel(
code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})),
@ -206,21 +174,6 @@ Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
type: functionTypesMap['Integer'],
values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
],
DeviceType.Curtain: [
FunctionModel(
code: 'control',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson(
{"range": ["open","stop","close"]}
)
),
FunctionModel(
code: 'percent_control',
type: functionTypesMap['Integer'],
values: ValueModel.fromJson(
{"unit": "%", "min": 0, "max": 100, "scale": 0, "step": 1})
),
],
};
enum TempModes { hot, cold, wind }

View File

@ -13,10 +13,10 @@ packages:
dependency: transitive
description:
name: args
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.5.0"
async:
dependency: transitive
description:
@ -29,10 +29,10 @@ packages:
dependency: transitive
description:
name: bloc
sha256: f53a110e3b48dcd78136c10daa5d51512443cea5e1348c9d80a320095fa2db9e
sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
url: "https://pub.dev"
source: hosted
version: "8.1.3"
version: "8.1.4"
boolean_selector:
dependency: transitive
description:
@ -45,26 +45,26 @@ packages:
dependency: "direct main"
description:
name: cached_network_image
sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f"
sha256: "4a5d8d2c728b0f3d0245f69f921d7be90cae4c2fd5288f773088672c0893f819"
url: "https://pub.dev"
source: hosted
version: "3.3.1"
version: "3.4.0"
cached_network_image_platform_interface:
dependency: transitive
description:
name: cached_network_image_platform_interface
sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f"
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
version: "4.1.1"
cached_network_image_web:
dependency: transitive
description:
name: cached_network_image_web
sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316"
sha256: "6322dde7a5ad92202e64df659241104a43db20ed594c41ca18de1014598d7996"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.3.0"
characters:
dependency: transitive
description:
@ -93,18 +93,18 @@ packages:
dependency: transitive
description:
name: cross_file
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
url: "https://pub.dev"
source: hosted
version: "0.3.4+1"
version: "0.3.4+2"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
url: "https://pub.dev"
source: hosted
version: "3.0.3"
version: "3.0.5"
csslib:
dependency: transitive
description:
@ -117,10 +117,10 @@ packages:
dependency: "direct main"
description:
name: cupertino_icons
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev"
source: hosted
version: "1.0.6"
version: "1.0.8"
day_picker:
dependency: "direct main"
description:
@ -133,26 +133,34 @@ packages:
dependency: "direct main"
description:
name: device_info_plus
sha256: eead12d1a1ed83d8283ab4c2f3fca23ac4082f29f25f29dff0f758f57d06ec91
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
url: "https://pub.dev"
source: hosted
version: "10.1.0"
version: "10.1.2"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
version: "7.0.1"
dio:
dependency: "direct main"
description:
name: dio
sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8"
sha256: "0dfb6b6a1979dac1c1245e17cef824d7b452ea29bd33d3467269f9bef3715fb0"
url: "https://pub.dev"
source: hosted
version: "5.4.1"
version: "5.6.0"
dio_web_adapter:
dependency: transitive
description:
name: dio_web_adapter
sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
equatable:
dependency: "direct main"
description:
@ -173,10 +181,10 @@ packages:
dependency: transitive
description:
name: ffi
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.3"
file:
dependency: transitive
description:
@ -213,34 +221,34 @@ packages:
dependency: transitive
description:
name: file_selector_windows
sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0
sha256: "2ad726953f6e8affbc4df8dc78b77c3b4a060967a291e528ef72ae846c60fb69"
url: "https://pub.dev"
source: hosted
version: "0.9.3+1"
version: "0.9.3+2"
firebase_analytics:
dependency: "direct main"
description:
name: firebase_analytics
sha256: c6220b23397f9302a42617227ee8fb1c5d718097a5351fcce53561d73fc10339
sha256: dbf1e7ab22cfb1f4a4adb103b46a26276b4edc593d4a78ef6fb942bafc92e035
url: "https://pub.dev"
source: hosted
version: "10.8.7"
version: "10.10.7"
firebase_analytics_platform_interface:
dependency: transitive
description:
name: firebase_analytics_platform_interface
sha256: "7f1c02cdd93a5e0a561af2f551465ffb6abdd541dbd0c8a9b8628d9ae0a5d024"
sha256: "3729b74f8cf1d974a27ba70332ecb55ff5ff560edc8164a6469f4a055b429c37"
url: "https://pub.dev"
source: hosted
version: "3.9.7"
version: "3.10.8"
firebase_analytics_web:
dependency: transitive
description:
name: firebase_analytics_web
sha256: ebb857c23f35fed52220b6c3271c12eeb6137de3930845223e3d0590b6fd0649
sha256: "019cd7eee74254d33fbd2e29229367ce33063516bf6b3258a341d89e3b0f1655"
url: "https://pub.dev"
source: hosted
version: "0.5.5+19"
version: "0.5.7+7"
firebase_core:
dependency: "direct main"
description:
@ -253,34 +261,34 @@ packages:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63
sha256: f7d7180c7f99babd4b4c517754d41a09a4943a0f7a69b65c894ca5c68ba66315
url: "https://pub.dev"
source: hosted
version: "5.0.0"
version: "5.2.1"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: "22fcb352744908224fc7be3caae254836099786acfe5df6e9fe901e9c2575a41"
sha256: "362e52457ed2b7b180964769c1e04d1e0ea0259fdf7025fdfedd019d4ae2bd88"
url: "https://pub.dev"
source: hosted
version: "2.17.1"
version: "2.17.5"
firebase_crashlytics:
dependency: "direct main"
description:
name: firebase_crashlytics
sha256: "0126fa101b74fb981796b3e6f47ccf7fc40237ec918327aaec7c0a06fd1bb4c1"
sha256: "9897c01efaa950d2f6da8317d12452749a74dc45f33b46390a14cfe28067f271"
url: "https://pub.dev"
source: hosted
version: "3.4.16"
version: "3.5.7"
firebase_crashlytics_platform_interface:
dependency: transitive
description:
name: firebase_crashlytics_platform_interface
sha256: cdfa0a20d66e1b32de542883c0ddf651ee9b66b12cebf73067e4d2cdc0865d17
sha256: "16a71e08fbf6e00382816e1b13397898c29a54fa0ad969c2c2a3b82a704877f0"
url: "https://pub.dev"
source: hosted
version: "3.6.23"
version: "3.6.35"
firebase_database:
dependency: "direct main"
description:
@ -338,18 +346,18 @@ packages:
dependency: "direct main"
description:
name: flutter_bloc
sha256: "87325da1ac757fcc4813e6b34ed5dd61169973871fdf181d6c2109dd6935ece1"
sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
url: "https://pub.dev"
source: hosted
version: "8.1.4"
version: "8.1.6"
flutter_cache_manager:
dependency: transitive
description:
name: flutter_cache_manager
sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba"
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
url: "https://pub.dev"
source: hosted
version: "3.3.1"
version: "3.4.1"
flutter_dotenv:
dependency: "direct main"
description:
@ -362,18 +370,18 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
flutter_localization:
dependency: "direct main"
description:
name: flutter_localization
sha256: faaeb1eba307473032e2c2af737f36ced61fc98735608410d0a6d9c231b50912
sha256: c2918388c56fe2d555074215dba44bc47bd5c1036e6b237f72f210b7136cfe61
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.2.1"
flutter_localizations:
dependency: transitive
description: flutter
@ -383,58 +391,58 @@ packages:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e
sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda"
url: "https://pub.dev"
source: hosted
version: "2.0.20"
version: "2.0.22"
flutter_secure_storage:
dependency: "direct main"
description:
name: flutter_secure_storage
sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685
sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
url: "https://pub.dev"
source: hosted
version: "9.0.0"
version: "9.2.2"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
sha256: "3d5032e314774ee0e1a7d0a9f5e2793486f0dff2dd9ef5a23f4e3fb2a0ae6a9e"
sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.2.1"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c
sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.1.2"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e"
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.2"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20"
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.2.1"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108"
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
url: "https://pub.dev"
source: hosted
version: "3.0.0"
version: "3.1.2"
flutter_svg:
dependency: "direct main"
description:
@ -457,10 +465,10 @@ packages:
dependency: "direct main"
description:
name: get_it
sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7
sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1
url: "https://pub.dev"
source: hosted
version: "7.6.7"
version: "7.7.0"
html:
dependency: "direct main"
description:
@ -473,10 +481,10 @@ packages:
dependency: transitive
description:
name: http
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.2.2"
http_parser:
dependency: transitive
description:
@ -497,18 +505,18 @@ packages:
dependency: transitive
description:
name: image_picker_android
sha256: "4161e1f843d8480d2e9025ee22411778c3c9eb7e40076dcf2da23d8242b7b51c"
sha256: c0a6763d50b354793d0192afd0a12560b823147d3ded7c6b77daf658fa05cc85
url: "https://pub.dev"
source: hosted
version: "0.8.12+3"
version: "0.8.12+13"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3"
sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50"
url: "https://pub.dev"
source: hosted
version: "3.0.4"
version: "3.0.5"
image_picker_ios:
dependency: transitive
description:
@ -569,18 +577,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "10.0.4"
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
@ -609,26 +617,26 @@ packages:
dependency: transitive
description:
name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.8.0"
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.15.0"
mime:
dependency: transitive
description:
name: mime
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
url: "https://pub.dev"
source: hosted
version: "1.0.5"
version: "1.0.6"
nested:
dependency: transitive
description:
@ -641,18 +649,18 @@ packages:
dependency: transitive
description:
name: octo_image
sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d"
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.1.0"
onesignal_flutter:
dependency: "direct main"
description:
name: onesignal_flutter
sha256: f3940387d6c7033a9c341aa0548f24d98217fce9182f9ad80bf2554b9dd3dc1a
sha256: e733de4494edb651f768600c00481753a9015dc23518eadce72f339154454531
url: "https://pub.dev"
source: hosted
version: "5.2.0"
version: "5.2.3"
path:
dependency: transitive
description:
@ -673,26 +681,26 @@ packages:
dependency: transitive
description:
name: path_provider
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.4"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
version: "2.2.10"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.4.0"
path_provider_linux:
dependency: transitive
description:
@ -713,10 +721,10 @@ packages:
dependency: transitive
description:
name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev"
source: hosted
version: "2.2.1"
version: "2.3.0"
permission_handler:
dependency: "direct main"
description:
@ -729,34 +737,34 @@ packages:
dependency: transitive
description:
name: permission_handler_android
sha256: "8bb852cd759488893805c3161d0b2b5db55db52f773dbb014420b304055ba2c5"
sha256: "76e4ab092c1b240d31177bb64d2b0bea43f43d0e23541ec866151b9f7b2490fa"
url: "https://pub.dev"
source: hosted
version: "12.0.6"
version: "12.0.12"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662
sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0
url: "https://pub.dev"
source: hosted
version: "9.4.4"
version: "9.4.5"
permission_handler_html:
dependency: transitive
description:
name: permission_handler_html
sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d"
sha256: af26edbbb1f2674af65a8f4b56e1a6f526156bc273d0e65dd8075fab51c78851
url: "https://pub.dev"
source: hosted
version: "0.1.1"
version: "0.1.3+2"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20"
sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea
url: "https://pub.dev"
source: hosted
version: "4.2.1"
version: "4.2.2"
permission_handler_windows:
dependency: transitive
description:
@ -785,10 +793,10 @@ packages:
dependency: transitive
description:
name: platform
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
version: "3.1.5"
plugin_platform_interface:
dependency: transitive
description:
@ -801,18 +809,18 @@ packages:
dependency: transitive
description:
name: provider
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev"
source: hosted
version: "6.1.1"
version: "6.1.2"
rxdart:
dependency: transitive
description:
name: rxdart
sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb"
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
url: "https://pub.dev"
source: hosted
version: "0.27.7"
version: "0.28.0"
share_plus:
dependency: "direct main"
description:
@ -833,58 +841,58 @@ packages:
dependency: "direct main"
description:
name: shared_preferences
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
version: "2.3.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
version: "2.3.2"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
url: "https://pub.dev"
source: hosted
version: "2.3.5"
version: "2.5.2"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.4.2"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.4.1"
sky_engine:
dependency: transitive
description: flutter
@ -902,10 +910,10 @@ packages:
dependency: "direct main"
description:
name: smooth_page_indicator
sha256: "725bc638d5e79df0c84658e1291449996943f93bacbc2cec49963dbbab48d8ae"
sha256: "3b28b0c545fa67ed9e5997d9f9720d486f54c0c607e056a1094544e36934dff3"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.2.0+3"
source_span:
dependency: transitive
description:
@ -926,18 +934,18 @@ packages:
dependency: transitive
description:
name: sqflite
sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6
sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.3.3+1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5"
sha256: "7b41b6c3507854a159e24ae90a8e3e9cc01eb26a477c118d6dca065b5f55453e"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
version: "2.5.4+2"
stack_trace:
dependency: transitive
description:
@ -966,10 +974,10 @@ packages:
dependency: transitive
description:
name: synchronized
sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
sha256: a824e842b8a054f91a728b783c177c1e4731f6b124f9192468457a8913371255
url: "https://pub.dev"
source: hosted
version: "3.1.0+1"
version: "3.2.0"
term_glyph:
dependency: transitive
description:
@ -982,10 +990,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
version: "0.7.0"
version: "0.7.2"
time_picker_spinner:
dependency: "direct main"
description:
@ -1006,74 +1014,74 @@ packages:
dependency: "direct main"
description:
name: url_launcher
sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e"
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
url: "https://pub.dev"
source: hosted
version: "6.2.5"
version: "6.3.0"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745
sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab
url: "https://pub.dev"
source: hosted
version: "6.3.0"
version: "6.3.10"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03"
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
url: "https://pub.dev"
source: hosted
version: "6.2.4"
version: "6.3.1"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
url: "https://pub.dev"
source: hosted
version: "3.1.1"
version: "3.2.0"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.2.0"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
url: "https://pub.dev"
source: hosted
version: "2.3.1"
version: "2.3.2"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
url: "https://pub.dev"
source: hosted
version: "2.3.1"
version: "2.3.3"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
version: "3.1.2"
uuid:
dependency: "direct main"
description:
name: uuid
sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
url: "https://pub.dev"
source: hosted
version: "4.4.0"
version: "4.4.2"
vector_graphics:
dependency: transitive
description:
@ -1110,10 +1118,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
url: "https://pub.dev"
source: hosted
version: "14.2.1"
version: "14.2.4"
web:
dependency: transitive
description:
@ -1126,18 +1134,18 @@ packages:
dependency: transitive
description:
name: win32
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
url: "https://pub.dev"
source: hosted
version: "5.2.0"
version: "5.5.4"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a"
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.1.4"
xdg_directories:
dependency: transitive
description:
@ -1155,5 +1163,5 @@ packages:
source: hosted
version: "6.5.0"
sdks:
dart: ">=3.4.0 <4.0.0"
flutter: ">=3.22.0"
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"